aboutsummaryrefslogtreecommitdiff
path: root/samples/DX_APIUsage/DXUT/Optional/SDKwavefile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'samples/DX_APIUsage/DXUT/Optional/SDKwavefile.cpp')
-rw-r--r--samples/DX_APIUsage/DXUT/Optional/SDKwavefile.cpp546
1 files changed, 546 insertions, 0 deletions
diff --git a/samples/DX_APIUsage/DXUT/Optional/SDKwavefile.cpp b/samples/DX_APIUsage/DXUT/Optional/SDKwavefile.cpp
new file mode 100644
index 0000000..f60bf78
--- /dev/null
+++ b/samples/DX_APIUsage/DXUT/Optional/SDKwavefile.cpp
@@ -0,0 +1,546 @@
+//-----------------------------------------------------------------------------
+// File: SDKWaveFile.cpp
+//
+// Desc: Classes for reading and writing wav files. Feel free to use this class
+// as a starting point for adding extra functionality.
+//
+// XNA Developer Connection
+//
+// Copyright (c) Microsoft Corp. All rights reserved.
+//-----------------------------------------------------------------------------
+#define STRICT
+#include "DXUT.h"
+#include "SDKwavefile.h"
+#undef min // use __min instead
+#undef max // use __max instead
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::CWaveFile()
+// Desc: Constructs the class. Call Open() to open a wave file for reading.
+// Then call Read() as needed. Calling the destructor or Close()
+// will close the file.
+//-----------------------------------------------------------------------------
+CWaveFile::CWaveFile()
+{
+ m_pwfx = NULL;
+ m_hmmio = NULL;
+ m_pResourceBuffer = NULL;
+ m_dwSize = 0;
+ m_bIsReadingFromMemory = FALSE;
+}
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::~CWaveFile()
+// Desc: Destructs the class
+//-----------------------------------------------------------------------------
+CWaveFile::~CWaveFile()
+{
+ Close();
+
+ if( !m_bIsReadingFromMemory )
+ SAFE_DELETE_ARRAY( m_pwfx );
+}
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Open()
+// Desc: Opens a wave file for reading
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::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 = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF | MMIO_READ );
+
+ if( NULL == m_hmmio )
+ {
+ HRSRC hResInfo;
+ HGLOBAL hResData;
+ DWORD dwSize;
+ VOID* pvRes;
+
+ // Loading it as a file failed, so try it as a resource
+ if( NULL == ( hResInfo = FindResource( NULL, strFileName, L"WAVE" ) ) )
+ {
+ if( NULL == ( hResInfo = FindResource( 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() ) )
+ {
+ // ReadMMIO will fail if its an not a wave file
+ mmioClose( m_hmmio, 0 );
+ return DXTRACE_ERR( L"ReadMMIO", hr );
+ }
+
+ if( FAILED( hr = ResetFile() ) )
+ return DXTRACE_ERR( L"ResetFile", hr );
+
+ // After the reset, the size of the wav file is m_ck.cksize so store it now
+ m_dwSize = m_ck.cksize;
+ }
+ else
+ {
+ m_hmmio = mmioOpen( 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;
+}
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::OpenFromMemory()
+// Desc: copy data to CWaveFile member variable from memory
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::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;
+}
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::ReadMMIO()
+// Desc: Support function for reading from a multimedia I/O stream.
+// m_hmmio must be valid before calling. This function uses it to
+// update m_ckRiff, and m_pwfx.
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::ReadMMIO()
+{
+ MMCKINFO ckIn; // chunk info. for general use.
+ PCMWAVEFORMAT pcmWaveFormat; // Temp PCM structure to load in.
+
+ memset( &ckIn, 0, sizeof(ckIn) );
+
+ m_pwfx = NULL;
+
+ if( ( 0 != mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) ) )
+ return DXTRACE_ERR( L"mmioDescend", E_FAIL );
+
+ // Check to make sure this is a valid wave file
+ if( ( m_ckRiff.ckid != FOURCC_RIFF ) ||
+ ( m_ckRiff.fccType != mmioFOURCC( 'W', 'A', 'V', 'E' ) ) )
+ return DXTRACE_ERR( L"mmioFOURCC", E_FAIL );
+
+ // Search the input file for for the 'fmt ' chunk.
+ ckIn.ckid = mmioFOURCC( 'f', 'm', 't', ' ' );
+ if( 0 != mmioDescend( m_hmmio, &ckIn, &m_ckRiff, MMIO_FINDCHUNK ) )
+ return DXTRACE_ERR( L"mmioDescend", E_FAIL );
+
+ // Expect the 'fmt' chunk to be at least as large as <PCMWAVEFORMAT>;
+ // if there are extra parameters at the end, we'll ignore them
+ if( ckIn.cksize < ( LONG )sizeof( PCMWAVEFORMAT ) )
+ return DXTRACE_ERR( L"sizeof(PCMWAVEFORMAT)", E_FAIL );
+
+ // Read the 'fmt ' chunk into <pcmWaveFormat>.
+ if( mmioRead( m_hmmio, ( HPSTR )&pcmWaveFormat,
+ sizeof( pcmWaveFormat ) ) != sizeof( pcmWaveFormat ) )
+ return DXTRACE_ERR( L"mmioRead", E_FAIL );
+
+ // Allocate the waveformatex, but if its not pcm format, read the next
+ // word, and thats how many extra bytes to allocate.
+ 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 );
+
+ // Copy the bytes from the pcm structure to the waveformatex structure
+ memcpy( m_pwfx, &pcmWaveFormat, sizeof( pcmWaveFormat ) );
+ m_pwfx->cbSize = 0;
+ }
+ else
+ {
+ // Read in length of extra bytes.
+ 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 );
+
+ // Copy the bytes from the pcm structure to the waveformatex structure
+ memcpy( m_pwfx, &pcmWaveFormat, sizeof( pcmWaveFormat ) );
+ m_pwfx->cbSize = cbExtraBytes;
+
+ // Now, read those extra bytes into the structure, if cbExtraAlloc != 0.
+ if( mmioRead( m_hmmio, ( CHAR* )( ( ( BYTE* )&( m_pwfx->cbSize ) ) + sizeof( WORD ) ),
+ cbExtraBytes ) != cbExtraBytes )
+ {
+ SAFE_DELETE( m_pwfx );
+ return DXTRACE_ERR( L"mmioRead", E_FAIL );
+ }
+ }
+
+ // Ascend the input file out of the 'fmt ' chunk.
+ if( 0 != mmioAscend( m_hmmio, &ckIn, 0 ) )
+ {
+ SAFE_DELETE( m_pwfx );
+ return DXTRACE_ERR( L"mmioAscend", E_FAIL );
+ }
+
+ return S_OK;
+}
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::GetSize()
+// Desc: Retuns the size of the read access wave file
+//-----------------------------------------------------------------------------
+DWORD CWaveFile::GetSize()
+{
+ return m_dwSize;
+}
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::ResetFile()
+// Desc: Resets the internal m_ck pointer so reading starts from the
+// beginning of the file again
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::ResetFile()
+{
+ if( m_bIsReadingFromMemory )
+ {
+ m_pbDataCur = m_pbData;
+ }
+ else
+ {
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ if( m_dwFlags == WAVEFILE_READ )
+ {
+ // Seek to the data
+ if( -1 == mmioSeek( m_hmmio, m_ckRiff.dwDataOffset + sizeof( FOURCC ),
+ SEEK_SET ) )
+ return DXTRACE_ERR( L"mmioSeek", E_FAIL );
+
+ // Search the input file for the 'data' chunk.
+ 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
+ {
+ // Create the 'data' chunk that holds the waveform samples.
+ 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;
+}
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Read()
+// Desc: Reads section of data from a wave file into pBuffer and returns
+// how much read in pdwSizeRead, reading not more than dwSizeToRead.
+// This uses m_ck to determine where to start reading from. So
+// subsequent calls will be continue where the last left off unless
+// Reset() is called.
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::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 ) // disable warning about warning number '22104' being out of range
+#pragma warning( disable: 22104 ) // disable PREfast warning during static code analysis
+ CopyMemory( pBuffer, m_pbDataCur, dwSizeToRead );
+#pragma warning( default: 22104 )
+#pragma warning( default: 4616 )
+
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = dwSizeToRead;
+
+ return S_OK;
+ }
+ else
+ {
+ MMIOINFO mmioinfoIn; // current status of m_hmmio
+
+ 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++ )
+ {
+ // Copy the bytes from the io to the buffer.
+ 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 );
+ }
+
+ // Actual copy.
+ *( ( 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;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Close()
+// Desc: Closes the wave file
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Close()
+{
+ if( m_dwFlags == WAVEFILE_READ )
+ {
+ if ( m_hmmio != NULL )
+ {
+ 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 );
+
+ // Ascend the output file out of the 'data' chunk -- this will cause
+ // the chunk size of the 'data' chunk to be written.
+ if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( L"mmioAscend", E_FAIL );
+
+ // Do this here instead...
+ 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 );
+ }
+
+ // Ascend the output file out of the 'RIFF' chunk -- this will cause
+ // the chunk size of the 'RIFF' chunk to be written.
+ 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;
+}
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::WriteMMIO()
+// Desc: Support function for reading from a multimedia I/O stream
+// pwfxDest is the WAVEFORMATEX for this new wave file.
+// m_hmmio must be valid before calling. This function uses it to
+// update m_ckRiff, and m_ck.
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::WriteMMIO( WAVEFORMATEX* pwfxDest )
+{
+ DWORD dwFactChunk; // Contains the actual fact chunk. Garbage until WaveCloseWriteFile.
+ MMCKINFO ckOut1;
+
+ memset( &ckOut1, 0, sizeof(ckOut1) );
+
+ dwFactChunk = ( DWORD )-1;
+
+ // Create the output file RIFF chunk of form type 'WAVE'.
+ 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 );
+
+ // We are now descended into the 'RIFF' chunk we just created.
+ // Now create the 'fmt ' chunk. Since we know the size of this chunk,
+ // specify it in the MMCKINFO structure so MMIO doesn't have to seek
+ // back and set the chunk size after ascending from the chunk.
+ 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 );
+
+ // Write the PCMWAVEFORMAT structure to the 'fmt ' chunk if its that type.
+ if( pwfxDest->wFormatTag == WAVE_FORMAT_PCM )
+ {
+ if( mmioWrite( m_hmmio, ( HPSTR )pwfxDest,
+ sizeof( PCMWAVEFORMAT ) ) != sizeof( PCMWAVEFORMAT ) )
+ return DXTRACE_ERR( L"mmioWrite", E_FAIL );
+ }
+ else
+ {
+ // Write the variable length size.
+ if( ( UINT )mmioWrite( m_hmmio, ( HPSTR )pwfxDest,
+ sizeof( *pwfxDest ) + pwfxDest->cbSize ) !=
+ ( sizeof( *pwfxDest ) + pwfxDest->cbSize ) )
+ return DXTRACE_ERR( L"mmioWrite", E_FAIL );
+ }
+
+ // Ascend out of the 'fmt ' chunk, back into the 'RIFF' chunk.
+ if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( L"mmioAscend", E_FAIL );
+
+ // Now create the fact chunk, not required for PCM but nice to have. This is filled
+ // in when the close routine is called.
+ 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 );
+
+ // Now ascend out of the fact chunk...
+ if( 0 != mmioAscend( m_hmmio, &ckOut1, 0 ) )
+ return DXTRACE_ERR( L"mmioAscend", E_FAIL );
+
+ return S_OK;
+}
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Write()
+// Desc: Writes data to the open wave file
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::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;
+}