#define SAFE_DELETE(p) { if (p) { delete (p); (p)=NULL; } }
#define SAFE_DELETE_ARRAY(p) { if (p) { delete[] (p); (p)=NULL; } }
#undef DXTRACE_ERR
#define DXTRACE_ERR(str,hr) (hr)
WaveFileReader::WaveFileReader()
{
m_pwfx = NULL;
m_hmmio = NULL;
m_pResourceBuffer = NULL;
m_dwSize = 0;
m_bIsReadingFromMemory = FALSE;
}
WaveFileReader::~WaveFileReader()
{
Close();
if( !m_bIsReadingFromMemory )
SAFE_DELETE_ARRAY( m_pwfx );
}
HRESULT WaveFileReader::Open( LPWSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags )
{
HRESULT hr;
m_dwFlags = dwFlags;
m_bIsReadingFromMemory = FALSE;
if( m_dwFlags == WAVEFILE_READ )
{
if( strFileName == NULL )
return E_INVALIDARG;
SAFE_DELETE_ARRAY( m_pwfx );
m_hmmio = mmioOpenW( strFileName, NULL, MMIO_ALLOCBUF | MMIO_READ );
if( NULL == m_hmmio )
{
HRSRC hResInfo;
HGLOBAL hResData;
DWORD dwSize;
VOID* pvRes;
if( NULL == ( hResInfo = FindResourceW( NULL, strFileName, L"WAVE" ) ) )
{
if( NULL == ( hResInfo = FindResourceW( NULL, strFileName, L"WAV" ) ) )
return DXTRACE_ERR( L"FindResource", E_FAIL );
}
if( NULL == ( hResData = LoadResource( GetModuleHandle( NULL ), hResInfo ) ) )
return DXTRACE_ERR( L"LoadResource", E_FAIL );
if( 0 == ( dwSize = SizeofResource( GetModuleHandle( NULL ), hResInfo ) ) )
return DXTRACE_ERR( L"SizeofResource", E_FAIL );
if( NULL == ( pvRes = LockResource( hResData ) ) )
return DXTRACE_ERR( L"LockResource", E_FAIL );
m_pResourceBuffer = new CHAR[ dwSize ];
if( m_pResourceBuffer == NULL )
return DXTRACE_ERR( L"new", E_OUTOFMEMORY );
memcpy( m_pResourceBuffer, pvRes, dwSize );
MMIOINFO mmioInfo;
ZeroMemory( &mmioInfo, sizeof( mmioInfo ) );
mmioInfo.fccIOProc = FOURCC_MEM;
mmioInfo.cchBuffer = dwSize;
mmioInfo.pchBuffer = ( CHAR* )m_pResourceBuffer;
m_hmmio = mmioOpen( NULL, &mmioInfo, MMIO_ALLOCBUF | MMIO_READ );
}
if( FAILED( hr = ReadMMIO() ) )
{
mmioClose( m_hmmio, 0 );
return DXTRACE_ERR( L"ReadMMIO", hr );
}
if( FAILED( hr = ResetFile() ) )
return DXTRACE_ERR( L"ResetFile", hr );
m_dwSize = m_ck.cksize;
}
else
{
m_hmmio = mmioOpenW( strFileName, NULL, MMIO_ALLOCBUF |
MMIO_READWRITE |
MMIO_CREATE );
if( NULL == m_hmmio )
return DXTRACE_ERR( L"mmioOpen", E_FAIL );
if( FAILED( hr = WriteMMIO( pwfx ) ) )
{
mmioClose( m_hmmio, 0 );
return DXTRACE_ERR( L"WriteMMIO", hr );
}
if( FAILED( hr = ResetFile() ) )
return DXTRACE_ERR( L"ResetFile", hr );
}
return hr;
}
HRESULT WaveFileReader::OpenFromMemory( BYTE* pbData, ULONG ulDataSize,
WAVEFORMATEX* pwfx, DWORD dwFlags )
{
m_pwfx = pwfx;
m_ulDataSize = ulDataSize;
m_pbData = pbData;
m_pbDataCur = m_pbData;
m_bIsReadingFromMemory = TRUE;
if( dwFlags != WAVEFILE_READ )
return E_NOTIMPL;
return S_OK;
}
HRESULT WaveFileReader::ReadMMIO()
{
MMCKINFO ckIn; PCMWAVEFORMAT pcmWaveFormat;
m_pwfx = NULL;
if( ( 0 != mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) ) )
return DXTRACE_ERR( L"mmioDescend", E_FAIL );
if( ( m_ckRiff.ckid != FOURCC_RIFF ) ||
( m_ckRiff.fccType != mmioFOURCC( 'W', 'A', 'V', 'E' ) ) )
return DXTRACE_ERR( L"mmioFOURCC", E_FAIL );
ckIn.ckid = mmioFOURCC( 'f', 'm', 't', ' ' );
if( 0 != mmioDescend( m_hmmio, &ckIn, &m_ckRiff, MMIO_FINDCHUNK ) )
return DXTRACE_ERR( L"mmioDescend", E_FAIL );
if( ckIn.cksize < ( LONG )sizeof( PCMWAVEFORMAT ) )
return DXTRACE_ERR( L"sizeof(PCMWAVEFORMAT)", E_FAIL );
if( mmioRead( m_hmmio, ( HPSTR )&pcmWaveFormat,
sizeof( pcmWaveFormat ) ) != sizeof( pcmWaveFormat ) )
return DXTRACE_ERR( L"mmioRead", E_FAIL );
if( pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM )
{
m_pwfx = ( WAVEFORMATEX* )new CHAR[ sizeof( WAVEFORMATEX ) ];
if( NULL == m_pwfx )
return DXTRACE_ERR( L"m_pwfx", E_FAIL );
memcpy( m_pwfx, &pcmWaveFormat, sizeof( pcmWaveFormat ) );
m_pwfx->cbSize = 0;
}
else
{
WORD cbExtraBytes = 0L;
if( mmioRead( m_hmmio, ( CHAR* )&cbExtraBytes, sizeof( WORD ) ) != sizeof( WORD ) )
return DXTRACE_ERR( L"mmioRead", E_FAIL );
m_pwfx = ( WAVEFORMATEX* )new CHAR[ sizeof( WAVEFORMATEX ) + cbExtraBytes ];
if( NULL == m_pwfx )
return DXTRACE_ERR( L"new", E_FAIL );
memcpy( m_pwfx, &pcmWaveFormat, sizeof( pcmWaveFormat ) );
m_pwfx->cbSize = cbExtraBytes;
if( mmioRead( m_hmmio, ( CHAR* )( ( ( BYTE* )&( m_pwfx->cbSize ) ) + sizeof( WORD ) ),
cbExtraBytes ) != cbExtraBytes )
{
SAFE_DELETE( m_pwfx );
return DXTRACE_ERR( L"mmioRead", E_FAIL );
}
}
if( 0 != mmioAscend( m_hmmio, &ckIn, 0 ) )
{
SAFE_DELETE( m_pwfx );
return DXTRACE_ERR( L"mmioAscend", E_FAIL );
}
return S_OK;
}
DWORD WaveFileReader::GetSize()
{
return m_dwSize;
}
HRESULT WaveFileReader::ResetFile()
{
if( m_bIsReadingFromMemory )
{
m_pbDataCur = m_pbData;
}
else
{
if( m_hmmio == NULL )
return CO_E_NOTINITIALIZED;
if( m_dwFlags == WAVEFILE_READ )
{
if( -1 == mmioSeek( m_hmmio, m_ckRiff.dwDataOffset + sizeof( FOURCC ),
SEEK_SET ) )
return DXTRACE_ERR( L"mmioSeek", E_FAIL );
m_ck.ckid = mmioFOURCC( 'd', 'a', 't', 'a' );
if( 0 != mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) )
return DXTRACE_ERR( L"mmioDescend", E_FAIL );
}
else
{
m_ck.ckid = mmioFOURCC( 'd', 'a', 't', 'a' );
m_ck.cksize = 0;
if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) )
return DXTRACE_ERR( L"mmioCreateChunk", E_FAIL );
if( 0 != mmioGetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
return DXTRACE_ERR( L"mmioGetInfo", E_FAIL );
}
}
return S_OK;
}
HRESULT WaveFileReader::Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead )
{
if( m_bIsReadingFromMemory )
{
if( m_pbDataCur == NULL )
return CO_E_NOTINITIALIZED;
if( pdwSizeRead != NULL )
*pdwSizeRead = 0;
if( ( BYTE* )( m_pbDataCur + dwSizeToRead ) >
( BYTE* )( m_pbData + m_ulDataSize ) )
{
dwSizeToRead = m_ulDataSize - ( DWORD )( m_pbDataCur - m_pbData );
}
#pragma warning( disable: 4616 ) #pragma warning( disable: 22104 ) CopyMemory( pBuffer, m_pbDataCur, dwSizeToRead );
#pragma warning( default: 22104 )
#pragma warning( default: 4616 )
if( pdwSizeRead != NULL )
*pdwSizeRead = dwSizeToRead;
return S_OK;
}
else
{
MMIOINFO mmioinfoIn;
if( m_hmmio == NULL )
return CO_E_NOTINITIALIZED;
if( pBuffer == NULL || pdwSizeRead == NULL )
return E_INVALIDARG;
*pdwSizeRead = 0;
if( 0 != mmioGetInfo( m_hmmio, &mmioinfoIn, 0 ) )
return DXTRACE_ERR( L"mmioGetInfo", E_FAIL );
UINT cbDataIn = dwSizeToRead;
if( cbDataIn > m_ck.cksize )
cbDataIn = m_ck.cksize;
m_ck.cksize -= cbDataIn;
for( DWORD cT = 0; cT < cbDataIn; cT++ )
{
if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
{
if( 0 != mmioAdvance( m_hmmio, &mmioinfoIn, MMIO_READ ) )
return DXTRACE_ERR( L"mmioAdvance", E_FAIL );
if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
return DXTRACE_ERR( L"mmioinfoIn.pchNext", E_FAIL );
}
*( ( BYTE* )pBuffer + cT ) = *( ( BYTE* )mmioinfoIn.pchNext );
mmioinfoIn.pchNext++;
}
if( 0 != mmioSetInfo( m_hmmio, &mmioinfoIn, 0 ) )
return DXTRACE_ERR( L"mmioSetInfo", E_FAIL );
*pdwSizeRead = cbDataIn;
return S_OK;
}
}
HRESULT WaveFileReader::Close()
{
if( m_dwFlags == WAVEFILE_READ )
{
mmioClose( m_hmmio, 0 );
m_hmmio = NULL;
SAFE_DELETE_ARRAY( m_pResourceBuffer );
}
else
{
m_mmioinfoOut.dwFlags |= MMIO_DIRTY;
if( m_hmmio == NULL )
return CO_E_NOTINITIALIZED;
if( 0 != mmioSetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
return DXTRACE_ERR( L"mmioSetInfo", E_FAIL );
if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
return DXTRACE_ERR( L"mmioAscend", E_FAIL );
if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
return DXTRACE_ERR( L"mmioAscend", E_FAIL );
mmioSeek( m_hmmio, 0, SEEK_SET );
if( 0 != ( INT )mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) )
return DXTRACE_ERR( L"mmioDescend", E_FAIL );
m_ck.ckid = mmioFOURCC( 'f', 'a', 'c', 't' );
if( 0 == mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) )
{
DWORD dwSamples = 0;
mmioWrite( m_hmmio, ( HPSTR )&dwSamples, sizeof( DWORD ) );
mmioAscend( m_hmmio, &m_ck, 0 );
}
if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
return DXTRACE_ERR( L"mmioAscend", E_FAIL );
mmioClose( m_hmmio, 0 );
m_hmmio = NULL;
}
return S_OK;
}
HRESULT WaveFileReader::WriteMMIO( WAVEFORMATEX* pwfxDest )
{
DWORD dwFactChunk; MMCKINFO ckOut1;
dwFactChunk = ( DWORD )-1;
m_ckRiff.fccType = mmioFOURCC( 'W', 'A', 'V', 'E' );
m_ckRiff.cksize = 0;
if( 0 != mmioCreateChunk( m_hmmio, &m_ckRiff, MMIO_CREATERIFF ) )
return DXTRACE_ERR( L"mmioCreateChunk", E_FAIL );
m_ck.ckid = mmioFOURCC( 'f', 'm', 't', ' ' );
m_ck.cksize = sizeof( PCMWAVEFORMAT );
if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) )
return DXTRACE_ERR( L"mmioCreateChunk", E_FAIL );
if( pwfxDest->wFormatTag == WAVE_FORMAT_PCM )
{
if( mmioWrite( m_hmmio, ( HPSTR )pwfxDest,
sizeof( PCMWAVEFORMAT ) ) != sizeof( PCMWAVEFORMAT ) )
return DXTRACE_ERR( L"mmioWrite", E_FAIL );
}
else
{
if( ( UINT )mmioWrite( m_hmmio, ( HPSTR )pwfxDest,
sizeof( *pwfxDest ) + pwfxDest->cbSize ) !=
( sizeof( *pwfxDest ) + pwfxDest->cbSize ) )
return DXTRACE_ERR( L"mmioWrite", E_FAIL );
}
if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
return DXTRACE_ERR( L"mmioAscend", E_FAIL );
ckOut1.ckid = mmioFOURCC( 'f', 'a', 'c', 't' );
ckOut1.cksize = 0;
if( 0 != mmioCreateChunk( m_hmmio, &ckOut1, 0 ) )
return DXTRACE_ERR( L"mmioCreateChunk", E_FAIL );
if( mmioWrite( m_hmmio, ( HPSTR )&dwFactChunk, sizeof( dwFactChunk ) ) !=
sizeof( dwFactChunk ) )
return DXTRACE_ERR( L"mmioWrite", E_FAIL );
if( 0 != mmioAscend( m_hmmio, &ckOut1, 0 ) )
return DXTRACE_ERR( L"mmioAscend", E_FAIL );
return S_OK;
}
HRESULT WaveFileReader::Write( UINT nSizeToWrite, BYTE* pbSrcData, UINT* pnSizeWrote )
{
UINT cT;
if( m_bIsReadingFromMemory )
return E_NOTIMPL;
if( m_hmmio == NULL )
return CO_E_NOTINITIALIZED;
if( pnSizeWrote == NULL || pbSrcData == NULL )
return E_INVALIDARG;
*pnSizeWrote = 0;
for( cT = 0; cT < nSizeToWrite; cT++ )
{
if( m_mmioinfoOut.pchNext == m_mmioinfoOut.pchEndWrite )
{
m_mmioinfoOut.dwFlags |= MMIO_DIRTY;
if( 0 != mmioAdvance( m_hmmio, &m_mmioinfoOut, MMIO_WRITE ) )
return DXTRACE_ERR( L"mmioAdvance", E_FAIL );
}
*( ( BYTE* )m_mmioinfoOut.pchNext ) = *( ( BYTE* )pbSrcData + cT );
( BYTE* )m_mmioinfoOut.pchNext++;
( *pnSizeWrote )++;
}
return S_OK;
}