2011-08-06 10:43:05 +00:00
using System ;
using System.Linq ;
using System.IO ;
2013-11-03 23:45:44 +00:00
namespace BizHawk.Emulation.DiscSystem
2011-08-06 10:43:05 +00:00
{
partial class Disc
{
2014-12-04 05:40:10 +00:00
/// <summary>
2020-02-26 21:25:50 +00:00
/// TODO - double-check that riffmaster is not filling memory at load-time but reading through to the disk
2015-06-23 18:57:11 +00:00
/// TODO - clarify stream disposing semantics
2014-12-04 05:40:10 +00:00
/// </summary>
2015-06-23 18:57:11 +00:00
internal class Blob_WaveFile : IBlob
2011-08-06 10:43:05 +00:00
{
2013-11-15 00:49:19 +00:00
[Serializable]
2011-08-06 10:43:05 +00:00
public class Blob_WaveFile_Exception : Exception
{
public Blob_WaveFile_Exception ( string message )
: base ( message )
{
}
}
public Blob_WaveFile ( )
{
2015-06-23 18:57:11 +00:00
}
private class Blob_RawFile : IBlob
{
public string PhysicalPath
2014-12-04 05:40:10 +00:00
{
2020-02-25 20:13:06 +00:00
get = > physicalPath ;
2015-06-23 18:57:11 +00:00
set
{
physicalPath = value ;
length = new FileInfo ( physicalPath ) . Length ;
}
2014-12-04 05:40:10 +00:00
}
2015-06-23 18:57:11 +00:00
string physicalPath ;
long length ;
2014-12-04 05:40:10 +00:00
2015-06-23 18:57:11 +00:00
public long Offset = 0 ;
2014-12-04 05:40:10 +00:00
2015-06-23 18:57:11 +00:00
BufferedStream fs ;
public void Dispose ( )
2014-12-04 05:40:10 +00:00
{
2015-06-23 18:57:11 +00:00
if ( fs ! = null )
{
fs . Dispose ( ) ;
fs = null ;
}
2014-12-04 05:40:10 +00:00
}
2015-06-23 18:57:11 +00:00
public int Read ( long byte_pos , byte [ ] buffer , int offset , int count )
{
//use quite a large buffer, because normally we will be reading these sequentially but in small chunks.
//this enhances performance considerably
const int buffersize = 2352 * 75 * 2 ;
if ( fs = = null )
fs = new BufferedStream ( new FileStream ( physicalPath , FileMode . Open , FileAccess . Read , FileShare . Read ) , buffersize ) ;
long target = byte_pos + Offset ;
if ( fs . Position ! = target )
fs . Position = target ;
return fs . Read ( buffer , offset , count ) ;
}
2020-02-25 20:13:06 +00:00
public long Length = > length ;
2011-08-06 10:43:05 +00:00
}
2011-08-08 01:48:31 +00:00
public void Load ( byte [ ] waveData )
{
}
2011-08-06 10:43:05 +00:00
public void Load ( string wavePath )
2011-08-08 01:48:31 +00:00
{
var stream = new FileStream ( wavePath , FileMode . Open , FileAccess . Read , FileShare . Read ) ;
Load ( stream ) ;
}
2019-12-29 10:52:32 +00:00
/// <exception cref="Blob_WaveFile_Exception">not a valid RIFF WAVE file with exactly one data chunk containing two 16-bit PCM channels at 44.1 kHz</exception>
2011-08-08 01:48:31 +00:00
public void Load ( Stream stream )
2011-08-06 10:43:05 +00:00
{
try
{
RiffSource = null ;
var rm = new RiffMaster ( ) ;
2011-08-08 01:48:31 +00:00
rm . LoadStream ( stream ) ;
2011-08-06 10:43:05 +00:00
RiffSource = rm ;
//analyze the file to make sure its an OK wave file
if ( rm . riff . type ! = "WAVE" )
{
throw new Blob_WaveFile_Exception ( "Not a RIFF WAVE file" ) ;
}
2013-11-04 03:12:50 +00:00
var fmt = rm . riff . subchunks . FirstOrDefault ( chunk = > chunk . tag = = "fmt " ) as RiffMaster . RiffSubchunk_fmt ;
2011-08-06 10:43:05 +00:00
if ( fmt = = null )
{
throw new Blob_WaveFile_Exception ( "Not a valid RIFF WAVE file (missing fmt chunk" ) ;
}
2013-11-04 03:12:50 +00:00
if ( 1 ! = rm . riff . subchunks . Count ( chunk = > chunk . tag = = "data" ) )
2011-08-06 10:43:05 +00:00
{
//later, we could make a Stream which would make an index of data chunks and walk around them
throw new Blob_WaveFile_Exception ( "Multi-data-chunk WAVE files not supported" ) ;
}
if ( fmt . format_tag ! = RiffMaster . RiffSubchunk_fmt . FORMAT_TAG . WAVE_FORMAT_PCM )
{
throw new Blob_WaveFile_Exception ( "Not a valid PCM WAVE file (only PCM is supported)" ) ;
}
if ( fmt . channels ! = 2 | | fmt . bitsPerSample ! = 16 | | fmt . samplesPerSec ! = 44100 )
{
throw new Blob_WaveFile_Exception ( "Not a CDA format WAVE file (conversion not yet supported)" ) ;
}
//acquire the start of the data chunk
2013-11-04 03:12:50 +00:00
var dataChunk = rm . riff . subchunks . FirstOrDefault ( chunk = > chunk . tag = = "data" ) as RiffMaster . RiffSubchunk ;
2011-08-06 10:43:05 +00:00
waveDataStreamPos = dataChunk . Position ;
mDataLength = dataChunk . Length ;
}
2015-07-01 06:09:20 +00:00
catch ( Exception )
2011-08-06 10:43:05 +00:00
{
Dispose ( ) ;
2011-08-08 01:48:31 +00:00
throw ;
2011-08-06 10:43:05 +00:00
}
}
public int Read ( long byte_pos , byte [ ] buffer , int offset , int count )
{
RiffSource . BaseStream . Position = byte_pos + waveDataStreamPos ;
return RiffSource . BaseStream . Read ( buffer , offset , count ) ;
}
RiffMaster RiffSource ;
long waveDataStreamPos ;
long mDataLength ;
2020-02-25 20:13:06 +00:00
public long Length = > mDataLength ;
2011-08-06 10:43:05 +00:00
2014-10-12 04:24:31 +00:00
public void Dispose ( )
2011-08-06 10:43:05 +00:00
{
2020-02-25 20:13:06 +00:00
RiffSource ? . Dispose ( ) ;
2011-08-06 10:43:05 +00:00
RiffSource = null ;
}
}
}
2014-10-12 04:24:31 +00:00
}