dsutil.cpp
上传用户:sycq158
上传日期:2008-10-22
资源大小:15361k
文件大小:55k
源码类别:

游戏

开发平台:

Visual C++

  1. //-----------------------------------------------------------------------------
  2. // File: DSUtil.cpp
  3. //
  4. // Desc: DirectSound framework classes for reading and writing wav files and
  5. //       playing them in DirectSound buffers. Feel free to use this class 
  6. //       as a starting point for adding extra functionality.
  7. //
  8. // Copyright (c) Microsoft Corp. All rights reserved.
  9. //-----------------------------------------------------------------------------
  10. #define STRICT
  11. #include <windows.h>
  12. #include <mmsystem.h>
  13. #include <dxerr9.h>
  14. #include <dsound.h>
  15. #include "DSUtil.h"
  16. #include "DXUtil.h"
  17. //-----------------------------------------------------------------------------
  18. // Name: CSoundManager::CSoundManager()
  19. // Desc: Constructs the class
  20. //-----------------------------------------------------------------------------
  21. CSoundManager::CSoundManager()
  22. {
  23.     m_pDS = NULL;
  24. }
  25. //-----------------------------------------------------------------------------
  26. // Name: CSoundManager::~CSoundManager()
  27. // Desc: Destroys the class
  28. //-----------------------------------------------------------------------------
  29. CSoundManager::~CSoundManager()
  30. {
  31.     SAFE_RELEASE( m_pDS ); 
  32. }
  33. //-----------------------------------------------------------------------------
  34. // Name: CSoundManager::Initialize()
  35. // Desc: Initializes the IDirectSound object and also sets the primary buffer
  36. //       format.  This function must be called before any others.
  37. //-----------------------------------------------------------------------------
  38. HRESULT CSoundManager::Initialize( HWND  hWnd, 
  39.                                    DWORD dwCoopLevel )
  40. {
  41.     HRESULT             hr;
  42.     SAFE_RELEASE( m_pDS );
  43.     // Create IDirectSound using the primary sound device
  44.     if( FAILED( hr = DirectSoundCreate8( NULL, &m_pDS, NULL ) ) )
  45.         return DXTRACE_ERR( TEXT("DirectSoundCreate8"), hr );
  46.     // Set DirectSound coop level 
  47.     if( FAILED( hr = m_pDS->SetCooperativeLevel( hWnd, dwCoopLevel ) ) )
  48.         return DXTRACE_ERR( TEXT("SetCooperativeLevel"), hr );   
  49.     return S_OK;
  50. }
  51. //-----------------------------------------------------------------------------
  52. // Name: CSoundManager::SetPrimaryBufferFormat()
  53. // Desc: Set primary buffer to a specified format 
  54. //       !WARNING! - Setting the primary buffer format and then using this
  55. //                   same dsound object for DirectMusic messes up DirectMusic! 
  56. //       For example, to set the primary buffer format to 22kHz stereo, 16-bit
  57. //       then:   dwPrimaryChannels = 2
  58. //               dwPrimaryFreq     = 22050, 
  59. //               dwPrimaryBitRate  = 16
  60. //-----------------------------------------------------------------------------
  61. HRESULT CSoundManager::SetPrimaryBufferFormat( DWORD dwPrimaryChannels, 
  62.                                                DWORD dwPrimaryFreq, 
  63.                                                DWORD dwPrimaryBitRate )
  64. {
  65.     HRESULT             hr;
  66.     LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
  67.     if( m_pDS == NULL )
  68.         return CO_E_NOTINITIALIZED;
  69.     // Get the primary buffer 
  70.     DSBUFFERDESC dsbd;
  71.     ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
  72.     dsbd.dwSize        = sizeof(DSBUFFERDESC);
  73.     dsbd.dwFlags       = DSBCAPS_PRIMARYBUFFER;
  74.     dsbd.dwBufferBytes = 0;
  75.     dsbd.lpwfxFormat   = NULL;
  76.        
  77.     if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBPrimary, NULL ) ) )
  78.         return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
  79.     WAVEFORMATEX wfx;
  80.     ZeroMemory( &wfx, sizeof(WAVEFORMATEX) ); 
  81.     wfx.wFormatTag      = (WORD) WAVE_FORMAT_PCM; 
  82.     wfx.nChannels       = (WORD) dwPrimaryChannels; 
  83.     wfx.nSamplesPerSec  = (DWORD) dwPrimaryFreq; 
  84.     wfx.wBitsPerSample  = (WORD) dwPrimaryBitRate; 
  85.     wfx.nBlockAlign     = (WORD) (wfx.wBitsPerSample / 8 * wfx.nChannels);
  86.     wfx.nAvgBytesPerSec = (DWORD) (wfx.nSamplesPerSec * wfx.nBlockAlign);
  87.     if( FAILED( hr = pDSBPrimary->SetFormat(&wfx) ) )
  88.         return DXTRACE_ERR( TEXT("SetFormat"), hr );
  89.     SAFE_RELEASE( pDSBPrimary );
  90.     return S_OK;
  91. }
  92. //-----------------------------------------------------------------------------
  93. // Name: CSoundManager::Get3DListenerInterface()
  94. // Desc: Returns the 3D listener interface associated with primary buffer.
  95. //-----------------------------------------------------------------------------
  96. HRESULT CSoundManager::Get3DListenerInterface( LPDIRECTSOUND3DLISTENER* ppDSListener )
  97. {
  98.     HRESULT             hr;
  99.     DSBUFFERDESC        dsbdesc;
  100.     LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
  101.     if( ppDSListener == NULL )
  102.         return E_INVALIDARG;
  103.     if( m_pDS == NULL )
  104.         return CO_E_NOTINITIALIZED;
  105.     *ppDSListener = NULL;
  106.     // Obtain primary buffer, asking it for 3D control
  107.     ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) );
  108.     dsbdesc.dwSize = sizeof(DSBUFFERDESC);
  109.     dsbdesc.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_PRIMARYBUFFER;
  110.     if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbdesc, &pDSBPrimary, NULL ) ) )
  111.         return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
  112.     if( FAILED( hr = pDSBPrimary->QueryInterface( IID_IDirectSound3DListener, 
  113.                                                   (VOID**)ppDSListener ) ) )
  114.     {
  115.         SAFE_RELEASE( pDSBPrimary );
  116.         return DXTRACE_ERR( TEXT("QueryInterface"), hr );
  117.     }
  118.     // Release the primary buffer, since it is not need anymore
  119.     SAFE_RELEASE( pDSBPrimary );
  120.     return S_OK;
  121. }
  122. //-----------------------------------------------------------------------------
  123. // Name: CSoundManager::Create()
  124. // Desc: 
  125. //-----------------------------------------------------------------------------
  126. HRESULT CSoundManager::Create( CSound** ppSound, 
  127.                                LPTSTR strWaveFileName, 
  128.                                DWORD dwCreationFlags, 
  129.                                GUID guid3DAlgorithm,
  130.                                DWORD dwNumBuffers )
  131. {
  132.     HRESULT hr;
  133.     HRESULT hrRet = S_OK;
  134.     DWORD   i;
  135.     LPDIRECTSOUNDBUFFER* apDSBuffer     = NULL;
  136.     DWORD                dwDSBufferSize = NULL;
  137.     CWaveFile*           pWaveFile      = NULL;
  138.     if( m_pDS == NULL )
  139.         return CO_E_NOTINITIALIZED;
  140.     if( strWaveFileName == NULL || ppSound == NULL || dwNumBuffers < 1 )
  141.         return E_INVALIDARG;
  142.     apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
  143.     if( apDSBuffer == NULL )
  144.     {
  145.         hr = E_OUTOFMEMORY;
  146.         goto LFail;
  147.     }
  148.     pWaveFile = new CWaveFile();
  149.     if( pWaveFile == NULL )
  150.     {
  151.         hr = E_OUTOFMEMORY;
  152.         goto LFail;
  153.     }
  154.     pWaveFile->Open( strWaveFileName, NULL, WAVEFILE_READ );
  155.     if( pWaveFile->GetSize() == 0 )
  156.     {
  157.         // Wave is blank, so don't create it.
  158.         hr = E_FAIL;
  159.         goto LFail;
  160.     }
  161.     // Make the DirectSound buffer the same size as the wav file
  162.     dwDSBufferSize = pWaveFile->GetSize();
  163.     // Create the direct sound buffer, and only request the flags needed
  164.     // since each requires some overhead and limits if the buffer can 
  165.     // be hardware accelerated
  166.     DSBUFFERDESC dsbd;
  167.     ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
  168.     dsbd.dwSize          = sizeof(DSBUFFERDESC);
  169.     dsbd.dwFlags         = dwCreationFlags;
  170.     dsbd.dwBufferBytes   = dwDSBufferSize;
  171.     dsbd.guid3DAlgorithm = guid3DAlgorithm;
  172.     dsbd.lpwfxFormat     = pWaveFile->m_pwfx;
  173.     
  174.     // DirectSound is only guarenteed to play PCM data.  Other
  175.     // formats may or may not work depending the sound card driver.
  176.     hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[0], NULL );
  177.     // Be sure to return this error code if it occurs so the
  178.     // callers knows this happened.
  179.     if( hr == DS_NO_VIRTUALIZATION )
  180.         hrRet = DS_NO_VIRTUALIZATION;
  181.             
  182.     if( FAILED(hr) )
  183.     {
  184.         // DSERR_BUFFERTOOSMALL will be returned if the buffer is
  185.         // less than DSBSIZE_FX_MIN and the buffer is created
  186.         // with DSBCAPS_CTRLFX.
  187.         
  188.         // It might also fail if hardware buffer mixing was requested
  189.         // on a device that doesn't support it.
  190.         DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
  191.                     
  192.         goto LFail;
  193.     }
  194.     // Default to use DuplicateSoundBuffer() when created extra buffers since always 
  195.     // create a buffer that uses the same memory however DuplicateSoundBuffer() will fail if 
  196.     // DSBCAPS_CTRLFX is used, so use CreateSoundBuffer() instead in this case.
  197.     if( (dwCreationFlags & DSBCAPS_CTRLFX) == 0 )
  198.     {
  199.         for( i=1; i<dwNumBuffers; i++ )
  200.         {
  201.             if( FAILED( hr = m_pDS->DuplicateSoundBuffer( apDSBuffer[0], &apDSBuffer[i] ) ) )
  202.             {
  203.                 DXTRACE_ERR( TEXT("DuplicateSoundBuffer"), hr );
  204.                 goto LFail;
  205.             }
  206.         }
  207.     }
  208.     else
  209.     {
  210.         for( i=1; i<dwNumBuffers; i++ )
  211.         {
  212.             hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[i], NULL );
  213.             if( FAILED(hr) )
  214.             {
  215.                 DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
  216.                 goto LFail;
  217.             }
  218.         }
  219.    }
  220.     
  221.     // Create the sound
  222.     *ppSound = new CSound( apDSBuffer, dwDSBufferSize, dwNumBuffers, pWaveFile, dwCreationFlags );
  223.     
  224.     SAFE_DELETE_ARRAY( apDSBuffer );
  225.     return hrRet;
  226. LFail:
  227.     // Cleanup
  228.     SAFE_DELETE( pWaveFile );
  229.     SAFE_DELETE_ARRAY( apDSBuffer );
  230.     return hr;
  231. }
  232. //-----------------------------------------------------------------------------
  233. // Name: CSoundManager::CreateFromMemory()
  234. // Desc: 
  235. //-----------------------------------------------------------------------------
  236. HRESULT CSoundManager::CreateFromMemory( CSound** ppSound, 
  237.                                         BYTE* pbData,
  238.                                         ULONG  ulDataSize,
  239.                                         LPWAVEFORMATEX pwfx,
  240.                                         DWORD dwCreationFlags, 
  241.                                         GUID guid3DAlgorithm,
  242.                                         DWORD dwNumBuffers )
  243. {
  244.     HRESULT hr;
  245.     DWORD   i;
  246.     LPDIRECTSOUNDBUFFER* apDSBuffer     = NULL;
  247.     DWORD                dwDSBufferSize = NULL;
  248.     CWaveFile*           pWaveFile      = NULL;
  249.     if( m_pDS == NULL )
  250.         return CO_E_NOTINITIALIZED;
  251.     if( pbData == NULL || ppSound == NULL || dwNumBuffers < 1 )
  252.         return E_INVALIDARG;
  253.     apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
  254.     if( apDSBuffer == NULL )
  255.     {
  256.         hr = E_OUTOFMEMORY;
  257.         goto LFail;
  258.     }
  259.     pWaveFile = new CWaveFile();
  260.     if( pWaveFile == NULL )
  261.     {
  262.         hr = E_OUTOFMEMORY;
  263.         goto LFail;
  264.     }
  265.     pWaveFile->OpenFromMemory( pbData,ulDataSize, pwfx, WAVEFILE_READ );
  266.     // Make the DirectSound buffer the same size as the wav file
  267.     dwDSBufferSize = ulDataSize;
  268.     // Create the direct sound buffer, and only request the flags needed
  269.     // since each requires some overhead and limits if the buffer can 
  270.     // be hardware accelerated
  271.     DSBUFFERDESC dsbd;
  272.     ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
  273.     dsbd.dwSize          = sizeof(DSBUFFERDESC);
  274.     dsbd.dwFlags         = dwCreationFlags;
  275.     dsbd.dwBufferBytes   = dwDSBufferSize;
  276.     dsbd.guid3DAlgorithm = guid3DAlgorithm;
  277.     dsbd.lpwfxFormat     = pwfx;
  278.     if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[0], NULL ) ) )
  279.     {
  280.         DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
  281.         goto LFail;
  282.     }
  283.     // Default to use DuplicateSoundBuffer() when created extra buffers since always 
  284.     // create a buffer that uses the same memory however DuplicateSoundBuffer() will fail if 
  285.     // DSBCAPS_CTRLFX is used, so use CreateSoundBuffer() instead in this case.
  286.     if( (dwCreationFlags & DSBCAPS_CTRLFX) == 0 )
  287.     {
  288.         for( i=1; i<dwNumBuffers; i++ )
  289.         {
  290.             if( FAILED( hr = m_pDS->DuplicateSoundBuffer( apDSBuffer[0], &apDSBuffer[i] ) ) )
  291.             {
  292.                 DXTRACE_ERR( TEXT("DuplicateSoundBuffer"), hr );
  293.                 goto LFail;
  294.             }
  295.         }
  296.     }
  297.     else
  298.     {
  299.         for( i=1; i<dwNumBuffers; i++ )
  300.         {
  301.             hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[i], NULL );
  302.             if( FAILED(hr) )
  303.             {
  304.                 DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
  305.                 goto LFail;
  306.             }
  307.         }
  308.    }
  309.     // Create the sound
  310.     *ppSound = new CSound( apDSBuffer, dwDSBufferSize, dwNumBuffers, pWaveFile, dwCreationFlags );
  311.     SAFE_DELETE_ARRAY( apDSBuffer );
  312.     return S_OK;
  313. LFail:
  314.     // Cleanup
  315.    
  316.     SAFE_DELETE_ARRAY( apDSBuffer );
  317.     return hr;
  318. }
  319. //-----------------------------------------------------------------------------
  320. // Name: CSoundManager::CreateStreaming()
  321. // Desc: 
  322. //-----------------------------------------------------------------------------
  323. HRESULT CSoundManager::CreateStreaming( CStreamingSound** ppStreamingSound, 
  324.                                         LPTSTR strWaveFileName, 
  325.                                         DWORD dwCreationFlags, 
  326.                                         GUID guid3DAlgorithm,
  327.                                         DWORD dwNotifyCount, 
  328.                                         DWORD dwNotifySize, 
  329.                                         HANDLE hNotifyEvent )
  330. {
  331.     HRESULT hr;
  332.     if( m_pDS == NULL )
  333.         return CO_E_NOTINITIALIZED;
  334.     if( strWaveFileName == NULL || ppStreamingSound == NULL || hNotifyEvent == NULL )
  335.         return E_INVALIDARG;
  336.     LPDIRECTSOUNDBUFFER pDSBuffer      = NULL;
  337.     DWORD               dwDSBufferSize = NULL;
  338.     CWaveFile*          pWaveFile      = NULL;
  339.     DSBPOSITIONNOTIFY*  aPosNotify     = NULL; 
  340.     LPDIRECTSOUNDNOTIFY pDSNotify      = NULL;
  341.     pWaveFile = new CWaveFile();
  342.     if( pWaveFile == NULL )
  343.         return E_OUTOFMEMORY;
  344.     pWaveFile->Open( strWaveFileName, NULL, WAVEFILE_READ );
  345.     // Figure out how big the DSound buffer should be 
  346.     dwDSBufferSize = dwNotifySize * dwNotifyCount;
  347.     // Set up the direct sound buffer.  Request the NOTIFY flag, so
  348.     // that we are notified as the sound buffer plays.  Note, that using this flag
  349.     // may limit the amount of hardware acceleration that can occur. 
  350.     DSBUFFERDESC dsbd;
  351.     ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
  352.     dsbd.dwSize          = sizeof(DSBUFFERDESC);
  353.     dsbd.dwFlags         = dwCreationFlags | 
  354.                            DSBCAPS_CTRLPOSITIONNOTIFY | 
  355.                            DSBCAPS_GETCURRENTPOSITION2;
  356.     dsbd.dwBufferBytes   = dwDSBufferSize;
  357.     dsbd.guid3DAlgorithm = guid3DAlgorithm;
  358.     dsbd.lpwfxFormat     = pWaveFile->m_pwfx;
  359.     if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBuffer, NULL ) ) )
  360.     {
  361.         // If wave format isn't then it will return 
  362.         // either DSERR_BADFORMAT or E_INVALIDARG
  363.         if( hr == DSERR_BADFORMAT || hr == E_INVALIDARG )
  364.             return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
  365.         return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
  366.     }
  367.     // Create the notification events, so that we know when to fill
  368.     // the buffer as the sound plays. 
  369.     if( FAILED( hr = pDSBuffer->QueryInterface( IID_IDirectSoundNotify, 
  370.                                                 (VOID**)&pDSNotify ) ) )
  371.     {
  372.         SAFE_DELETE_ARRAY( aPosNotify );
  373.         return DXTRACE_ERR( TEXT("QueryInterface"), hr );
  374.     }
  375.     aPosNotify = new DSBPOSITIONNOTIFY[ dwNotifyCount ];
  376.     if( aPosNotify == NULL )
  377.         return E_OUTOFMEMORY;
  378.     for( DWORD i = 0; i < dwNotifyCount; i++ )
  379.     {
  380.         aPosNotify[i].dwOffset     = (dwNotifySize * i) + dwNotifySize - 1;
  381.         aPosNotify[i].hEventNotify = hNotifyEvent;             
  382.     }
  383.     
  384.     // Tell DirectSound when to notify us. The notification will come in the from 
  385.     // of signaled events that are handled in WinMain()
  386.     if( FAILED( hr = pDSNotify->SetNotificationPositions( dwNotifyCount, 
  387.                                                           aPosNotify ) ) )
  388.     {
  389.         SAFE_RELEASE( pDSNotify );
  390.         SAFE_DELETE_ARRAY( aPosNotify );
  391.         return DXTRACE_ERR( TEXT("SetNotificationPositions"), hr );
  392.     }
  393.     SAFE_RELEASE( pDSNotify );
  394.     SAFE_DELETE_ARRAY( aPosNotify );
  395.     // Create the sound
  396.     *ppStreamingSound = new CStreamingSound( pDSBuffer, dwDSBufferSize, pWaveFile, dwNotifySize );
  397.     return S_OK;
  398. }
  399. //-----------------------------------------------------------------------------
  400. // Name: CSound::CSound()
  401. // Desc: Constructs the class
  402. //-----------------------------------------------------------------------------
  403. CSound::CSound( LPDIRECTSOUNDBUFFER* apDSBuffer, DWORD dwDSBufferSize, 
  404.                 DWORD dwNumBuffers, CWaveFile* pWaveFile, DWORD dwCreationFlags )
  405. {
  406.     DWORD i;
  407.     m_apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
  408.     if( NULL != m_apDSBuffer )
  409.     {
  410.         for( i=0; i<dwNumBuffers; i++ )
  411.             m_apDSBuffer[i] = apDSBuffer[i];
  412.     
  413.         m_dwDSBufferSize = dwDSBufferSize;
  414.         m_dwNumBuffers   = dwNumBuffers;
  415.         m_pWaveFile      = pWaveFile;
  416.         m_dwCreationFlags = dwCreationFlags;
  417.         
  418.         FillBufferWithSound( m_apDSBuffer[0], FALSE );
  419.     }
  420. }
  421. //-----------------------------------------------------------------------------
  422. // Name: CSound::~CSound()
  423. // Desc: Destroys the class
  424. //-----------------------------------------------------------------------------
  425. CSound::~CSound()
  426. {
  427.     for( DWORD i=0; i<m_dwNumBuffers; i++ )
  428.     {
  429.         SAFE_RELEASE( m_apDSBuffer[i] ); 
  430.     }
  431.     SAFE_DELETE_ARRAY( m_apDSBuffer ); 
  432.     SAFE_DELETE( m_pWaveFile );
  433. }
  434. //-----------------------------------------------------------------------------
  435. // Name: CSound::FillBufferWithSound()
  436. // Desc: Fills a DirectSound buffer with a sound file 
  437. //-----------------------------------------------------------------------------
  438. HRESULT CSound::FillBufferWithSound( LPDIRECTSOUNDBUFFER pDSB, BOOL bRepeatWavIfBufferLarger )
  439. {
  440.     HRESULT hr; 
  441.     VOID*   pDSLockedBuffer      = NULL; // Pointer to locked buffer memory
  442.     DWORD   dwDSLockedBufferSize = 0;    // Size of the locked DirectSound buffer
  443.     DWORD   dwWavDataRead        = 0;    // Amount of data read from the wav file 
  444.     if( pDSB == NULL )
  445.         return CO_E_NOTINITIALIZED;
  446.     // Make sure we have focus, and we didn't just switch in from
  447.     // an app which had a DirectSound device
  448.     if( FAILED( hr = RestoreBuffer( pDSB, NULL ) ) ) 
  449.         return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
  450.     // Lock the buffer down
  451.     if( FAILED( hr = pDSB->Lock( 0, m_dwDSBufferSize, 
  452.                                  &pDSLockedBuffer, &dwDSLockedBufferSize, 
  453.                                  NULL, NULL, 0L ) ) )
  454.         return DXTRACE_ERR( TEXT("Lock"), hr );
  455.     // Reset the wave file to the beginning 
  456.     m_pWaveFile->ResetFile();
  457.     if( FAILED( hr = m_pWaveFile->Read( (BYTE*) pDSLockedBuffer,
  458.                                         dwDSLockedBufferSize, 
  459.                                         &dwWavDataRead ) ) )           
  460.         return DXTRACE_ERR( TEXT("Read"), hr );
  461.     if( dwWavDataRead == 0 )
  462.     {
  463.         // Wav is blank, so just fill with silence
  464.         FillMemory( (BYTE*) pDSLockedBuffer, 
  465.                     dwDSLockedBufferSize, 
  466.                     (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
  467.     }
  468.     else if( dwWavDataRead < dwDSLockedBufferSize )
  469.     {
  470.         // If the wav file was smaller than the DirectSound buffer, 
  471.         // we need to fill the remainder of the buffer with data 
  472.         if( bRepeatWavIfBufferLarger )
  473.         {       
  474.             // Reset the file and fill the buffer with wav data
  475.             DWORD dwReadSoFar = dwWavDataRead;    // From previous call above.
  476.             while( dwReadSoFar < dwDSLockedBufferSize )
  477.             {  
  478.                 // This will keep reading in until the buffer is full 
  479.                 // for very short files
  480.                 if( FAILED( hr = m_pWaveFile->ResetFile() ) )
  481.                     return DXTRACE_ERR( TEXT("ResetFile"), hr );
  482.                 hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar,
  483.                                         dwDSLockedBufferSize - dwReadSoFar,
  484.                                         &dwWavDataRead );
  485.                 if( FAILED(hr) )
  486.                     return DXTRACE_ERR( TEXT("Read"), hr );
  487.                 dwReadSoFar += dwWavDataRead;
  488.             } 
  489.         }
  490.         else
  491.         {
  492.             // Don't repeat the wav file, just fill in silence 
  493.             FillMemory( (BYTE*) pDSLockedBuffer + dwWavDataRead, 
  494.                         dwDSLockedBufferSize - dwWavDataRead, 
  495.                         (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
  496.         }
  497.     }
  498.     // Unlock the buffer, we don't need it anymore.
  499.     pDSB->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );
  500.     return S_OK;
  501. }
  502. //-----------------------------------------------------------------------------
  503. // Name: CSound::RestoreBuffer()
  504. // Desc: Restores the lost buffer. *pbWasRestored returns TRUE if the buffer was 
  505. //       restored.  It can also NULL if the information is not needed.
  506. //-----------------------------------------------------------------------------
  507. HRESULT CSound::RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, BOOL* pbWasRestored )
  508. {
  509.     HRESULT hr;
  510.     if( pDSB == NULL )
  511.         return CO_E_NOTINITIALIZED;
  512.     if( pbWasRestored )
  513.         *pbWasRestored = FALSE;
  514.     DWORD dwStatus;
  515.     if( FAILED( hr = pDSB->GetStatus( &dwStatus ) ) )
  516.         return DXTRACE_ERR( TEXT("GetStatus"), hr );
  517.     if( dwStatus & DSBSTATUS_BUFFERLOST )
  518.     {
  519.         // Since the app could have just been activated, then
  520.         // DirectSound may not be giving us control yet, so 
  521.         // the restoring the buffer may fail.  
  522.         // If it does, sleep until DirectSound gives us control.
  523.         do 
  524.         {
  525.             hr = pDSB->Restore();
  526.             if( hr == DSERR_BUFFERLOST )
  527.                 Sleep( 10 );
  528.         }
  529.         while( ( hr = pDSB->Restore() ) == DSERR_BUFFERLOST );
  530.         if( pbWasRestored != NULL )
  531.             *pbWasRestored = TRUE;
  532.         return S_OK;
  533.     }
  534.     else
  535.     {
  536.         return S_FALSE;
  537.     }
  538. }
  539. //-----------------------------------------------------------------------------
  540. // Name: CSound::GetFreeBuffer()
  541. // Desc: Finding the first buffer that is not playing and return a pointer to 
  542. //       it, or if all are playing return a pointer to a randomly selected buffer.
  543. //-----------------------------------------------------------------------------
  544. LPDIRECTSOUNDBUFFER CSound::GetFreeBuffer()
  545. {
  546.     if( m_apDSBuffer == NULL )
  547.         return FALSE; 
  548.     for( DWORD i=0; i<m_dwNumBuffers; i++ )
  549.     {
  550.         if( m_apDSBuffer[i] )
  551.         {  
  552.             DWORD dwStatus = 0;
  553.             m_apDSBuffer[i]->GetStatus( &dwStatus );
  554.             if ( ( dwStatus & DSBSTATUS_PLAYING ) == 0 )
  555.                 break;
  556.         }
  557.     }
  558.     if( i != m_dwNumBuffers )
  559.         return m_apDSBuffer[ i ];
  560.     else
  561.         return m_apDSBuffer[ rand() % m_dwNumBuffers ];
  562. }
  563. //-----------------------------------------------------------------------------
  564. // Name: CSound::GetBuffer()
  565. // Desc: 
  566. //-----------------------------------------------------------------------------
  567. LPDIRECTSOUNDBUFFER CSound::GetBuffer( DWORD dwIndex )
  568. {
  569.     if( m_apDSBuffer == NULL )
  570.         return NULL;
  571.     if( dwIndex >= m_dwNumBuffers )
  572.         return NULL;
  573.     return m_apDSBuffer[dwIndex];
  574. }
  575. //-----------------------------------------------------------------------------
  576. // Name: CSound::Get3DBufferInterface()
  577. // Desc: 
  578. //-----------------------------------------------------------------------------
  579. HRESULT CSound::Get3DBufferInterface( DWORD dwIndex, LPDIRECTSOUND3DBUFFER* ppDS3DBuffer )
  580. {
  581.     if( m_apDSBuffer == NULL )
  582.         return CO_E_NOTINITIALIZED;
  583.     if( dwIndex >= m_dwNumBuffers )
  584.         return E_INVALIDARG;
  585.     *ppDS3DBuffer = NULL;
  586.     return m_apDSBuffer[dwIndex]->QueryInterface( IID_IDirectSound3DBuffer, 
  587.                                                   (VOID**)ppDS3DBuffer );
  588. }
  589. //-----------------------------------------------------------------------------
  590. // Name: CSound::Play()
  591. // Desc: Plays the sound using voice management flags.  Pass in DSBPLAY_LOOPING
  592. //       in the dwFlags to loop the sound
  593. //-----------------------------------------------------------------------------
  594. HRESULT CSound::Play( DWORD dwPriority, DWORD dwFlags, LONG lVolume, LONG lFrequency, LONG lPan )
  595. {
  596.     HRESULT hr;
  597.     BOOL    bRestored;
  598.     if( m_apDSBuffer == NULL )
  599.         return CO_E_NOTINITIALIZED;
  600.     LPDIRECTSOUNDBUFFER pDSB = GetFreeBuffer();
  601.     if( pDSB == NULL )
  602.         return DXTRACE_ERR( TEXT("GetFreeBuffer"), E_FAIL );
  603.     // Restore the buffer if it was lost
  604.     if( FAILED( hr = RestoreBuffer( pDSB, &bRestored ) ) )
  605.         return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
  606.     if( bRestored )
  607.     {
  608.         // The buffer was restored, so we need to fill it with new data
  609.         if( FAILED( hr = FillBufferWithSound( pDSB, FALSE ) ) )
  610.             return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
  611.     }
  612.     if( m_dwCreationFlags & DSBCAPS_CTRLVOLUME )
  613.     {
  614.         pDSB->SetVolume( lVolume );
  615.     }
  616.     if( lFrequency != -1 && 
  617.         (m_dwCreationFlags & DSBCAPS_CTRLFREQUENCY) )
  618.     {
  619.         pDSB->SetFrequency( lFrequency );
  620.     }
  621.     
  622.     if( m_dwCreationFlags & DSBCAPS_CTRLPAN )
  623.     {
  624.         pDSB->SetPan( lPan );
  625.     }
  626.     
  627.     return pDSB->Play( 0, dwPriority, dwFlags );
  628. }
  629. //-----------------------------------------------------------------------------
  630. // Name: CSound::Play3D()
  631. // Desc: Plays the sound using voice management flags.  Pass in DSBPLAY_LOOPING
  632. //       in the dwFlags to loop the sound
  633. //-----------------------------------------------------------------------------
  634. HRESULT CSound::Play3D( LPDS3DBUFFER p3DBuffer, DWORD dwPriority, DWORD dwFlags, LONG lFrequency )
  635. {
  636.     HRESULT hr;
  637.     BOOL    bRestored;
  638.     DWORD   dwBaseFrequency;
  639.     if( m_apDSBuffer == NULL )
  640.         return CO_E_NOTINITIALIZED;
  641.     LPDIRECTSOUNDBUFFER pDSB = GetFreeBuffer();
  642.     if( pDSB == NULL )
  643.         return DXTRACE_ERR( TEXT("GetFreeBuffer"), E_FAIL );
  644.     // Restore the buffer if it was lost
  645.     if( FAILED( hr = RestoreBuffer( pDSB, &bRestored ) ) )
  646.         return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
  647.     if( bRestored )
  648.     {
  649.         // The buffer was restored, so we need to fill it with new data
  650.         if( FAILED( hr = FillBufferWithSound( pDSB, FALSE ) ) )
  651.             return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
  652.     }
  653.     if( m_dwCreationFlags & DSBCAPS_CTRLFREQUENCY )
  654.     {
  655.         pDSB->GetFrequency( &dwBaseFrequency );
  656.         pDSB->SetFrequency( dwBaseFrequency + lFrequency );
  657.     }
  658.     // QI for the 3D buffer 
  659.     LPDIRECTSOUND3DBUFFER pDS3DBuffer;
  660.     hr = pDSB->QueryInterface( IID_IDirectSound3DBuffer, (VOID**) &pDS3DBuffer );
  661.     if( SUCCEEDED( hr ) )
  662.     {
  663.         hr = pDS3DBuffer->SetAllParameters( p3DBuffer, DS3D_IMMEDIATE );
  664.         if( SUCCEEDED( hr ) )
  665.         {
  666.             hr = pDSB->Play( 0, dwPriority, dwFlags );
  667.         }
  668.         pDS3DBuffer->Release();
  669.     }
  670.     return hr;
  671. }
  672. //-----------------------------------------------------------------------------
  673. // Name: CSound::Stop()
  674. // Desc: Stops the sound from playing
  675. //-----------------------------------------------------------------------------
  676. HRESULT CSound::Stop()
  677. {
  678.     if( m_apDSBuffer == NULL )
  679.         return CO_E_NOTINITIALIZED;
  680.     HRESULT hr = 0;
  681.     for( DWORD i=0; i<m_dwNumBuffers; i++ )
  682.         hr |= m_apDSBuffer[i]->Stop();
  683.     return hr;
  684. }
  685. //-----------------------------------------------------------------------------
  686. // Name: CSound::Reset()
  687. // Desc: Reset all of the sound buffers
  688. //-----------------------------------------------------------------------------
  689. HRESULT CSound::Reset()
  690. {
  691.     if( m_apDSBuffer == NULL )
  692.         return CO_E_NOTINITIALIZED;
  693.     HRESULT hr = 0;
  694.     for( DWORD i=0; i<m_dwNumBuffers; i++ )
  695.         hr |= m_apDSBuffer[i]->SetCurrentPosition( 0 );
  696.     return hr;
  697. }
  698. //-----------------------------------------------------------------------------
  699. // Name: CSound::IsSoundPlaying()
  700. // Desc: Checks to see if a buffer is playing and returns TRUE if it is.
  701. //-----------------------------------------------------------------------------
  702. BOOL CSound::IsSoundPlaying()
  703. {
  704.     BOOL bIsPlaying = FALSE;
  705.     if( m_apDSBuffer == NULL )
  706.         return FALSE; 
  707.     for( DWORD i=0; i<m_dwNumBuffers; i++ )
  708.     {
  709.         if( m_apDSBuffer[i] )
  710.         {  
  711.             DWORD dwStatus = 0;
  712.             m_apDSBuffer[i]->GetStatus( &dwStatus );
  713.             bIsPlaying |= ( ( dwStatus & DSBSTATUS_PLAYING ) != 0 );
  714.         }
  715.     }
  716.     return bIsPlaying;
  717. }
  718. //-----------------------------------------------------------------------------
  719. // Name: CStreamingSound::CStreamingSound()
  720. // Desc: Setups up a buffer so data can be streamed from the wave file into 
  721. //       a buffer.  This is very useful for large wav files that would take a 
  722. //       while to load.  The buffer is initially filled with data, then 
  723. //       as sound is played the notification events are signaled and more data
  724. //       is written into the buffer by calling HandleWaveStreamNotification()
  725. //-----------------------------------------------------------------------------
  726. CStreamingSound::CStreamingSound( LPDIRECTSOUNDBUFFER pDSBuffer, DWORD dwDSBufferSize, 
  727.                                   CWaveFile* pWaveFile, DWORD dwNotifySize ) 
  728.                 : CSound( &pDSBuffer, dwDSBufferSize, 1, pWaveFile, 0 )           
  729. {
  730.     m_dwLastPlayPos     = 0;
  731.     m_dwPlayProgress    = 0;
  732.     m_dwNotifySize      = dwNotifySize;
  733.     m_dwNextWriteOffset = 0;
  734.     m_bFillNextNotificationWithSilence = FALSE;
  735. }
  736. //-----------------------------------------------------------------------------
  737. // Name: CStreamingSound::~CStreamingSound()
  738. // Desc: Destroys the class
  739. //-----------------------------------------------------------------------------
  740. CStreamingSound::~CStreamingSound()
  741. {
  742. }
  743. //-----------------------------------------------------------------------------
  744. // Name: CStreamingSound::HandleWaveStreamNotification()
  745. // Desc: Handle the notification that tells us to put more wav data in the 
  746. //       circular buffer
  747. //-----------------------------------------------------------------------------
  748. HRESULT CStreamingSound::HandleWaveStreamNotification( BOOL bLoopedPlay )
  749. {
  750.     HRESULT hr;
  751.     DWORD   dwCurrentPlayPos;
  752.     DWORD   dwPlayDelta;
  753.     DWORD   dwBytesWrittenToBuffer;
  754.     VOID*   pDSLockedBuffer = NULL;
  755.     VOID*   pDSLockedBuffer2 = NULL;
  756.     DWORD   dwDSLockedBufferSize;
  757.     DWORD   dwDSLockedBufferSize2;
  758.     if( m_apDSBuffer == NULL || m_pWaveFile == NULL )
  759.         return CO_E_NOTINITIALIZED;
  760.     // Restore the buffer if it was lost
  761.     BOOL bRestored;
  762.     if( FAILED( hr = RestoreBuffer( m_apDSBuffer[0], &bRestored ) ) )
  763.         return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
  764.     if( bRestored )
  765.     {
  766.         // The buffer was restored, so we need to fill it with new data
  767.         if( FAILED( hr = FillBufferWithSound( m_apDSBuffer[0], FALSE ) ) )
  768.             return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
  769.         return S_OK;
  770.     }
  771.     // Lock the DirectSound buffer
  772.     if( FAILED( hr = m_apDSBuffer[0]->Lock( m_dwNextWriteOffset, m_dwNotifySize, 
  773.                                             &pDSLockedBuffer, &dwDSLockedBufferSize, 
  774.                                             &pDSLockedBuffer2, &dwDSLockedBufferSize2, 0L ) ) )
  775.         return DXTRACE_ERR( TEXT("Lock"), hr );
  776.     // m_dwDSBufferSize and m_dwNextWriteOffset are both multiples of m_dwNotifySize, 
  777.     // it should the second buffer, so it should never be valid
  778.     if( pDSLockedBuffer2 != NULL )
  779.         return E_UNEXPECTED; 
  780.     if( !m_bFillNextNotificationWithSilence )
  781.     {
  782.         // Fill the DirectSound buffer with wav data
  783.         if( FAILED( hr = m_pWaveFile->Read( (BYTE*) pDSLockedBuffer, 
  784.                                                   dwDSLockedBufferSize, 
  785.                                                   &dwBytesWrittenToBuffer ) ) )           
  786.             return DXTRACE_ERR( TEXT("Read"), hr );
  787.     }
  788.     else
  789.     {
  790.         // Fill the DirectSound buffer with silence
  791.         FillMemory( pDSLockedBuffer, dwDSLockedBufferSize, 
  792.                     (BYTE)( m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
  793.         dwBytesWrittenToBuffer = dwDSLockedBufferSize;
  794.     }
  795.     // If the number of bytes written is less than the 
  796.     // amount we requested, we have a short file.
  797.     if( dwBytesWrittenToBuffer < dwDSLockedBufferSize )
  798.     {
  799.         if( !bLoopedPlay ) 
  800.         {
  801.             // Fill in silence for the rest of the buffer.
  802.             FillMemory( (BYTE*) pDSLockedBuffer + dwBytesWrittenToBuffer, 
  803.                         dwDSLockedBufferSize - dwBytesWrittenToBuffer, 
  804.                         (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
  805.             // Any future notifications should just fill the buffer with silence
  806.             m_bFillNextNotificationWithSilence = TRUE;
  807.         }
  808.         else
  809.         {
  810.             // We are looping, so reset the file and fill the buffer with wav data
  811.             DWORD dwReadSoFar = dwBytesWrittenToBuffer;    // From previous call above.
  812.             while( dwReadSoFar < dwDSLockedBufferSize )
  813.             {  
  814.                 // This will keep reading in until the buffer is full (for very short files).
  815.                 if( FAILED( hr = m_pWaveFile->ResetFile() ) )
  816.                     return DXTRACE_ERR( TEXT("ResetFile"), hr );
  817.                 if( FAILED( hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar,
  818.                                                           dwDSLockedBufferSize - dwReadSoFar,
  819.                                                           &dwBytesWrittenToBuffer ) ) )
  820.                     return DXTRACE_ERR( TEXT("Read"), hr );
  821.                 dwReadSoFar += dwBytesWrittenToBuffer;
  822.             } 
  823.         } 
  824.     }
  825.     // Unlock the DirectSound buffer
  826.     m_apDSBuffer[0]->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );
  827.     // Figure out how much data has been played so far.  When we have played
  828.     // past the end of the file, we will either need to start filling the
  829.     // buffer with silence or starting reading from the beginning of the file, 
  830.     // depending if the user wants to loop the sound
  831.     if( FAILED( hr = m_apDSBuffer[0]->GetCurrentPosition( &dwCurrentPlayPos, NULL ) ) )
  832.         return DXTRACE_ERR( TEXT("GetCurrentPosition"), hr );
  833.     // Check to see if the position counter looped
  834.     if( dwCurrentPlayPos < m_dwLastPlayPos )
  835.         dwPlayDelta = ( m_dwDSBufferSize - m_dwLastPlayPos ) + dwCurrentPlayPos;
  836.     else
  837.         dwPlayDelta = dwCurrentPlayPos - m_dwLastPlayPos;
  838.     m_dwPlayProgress += dwPlayDelta;
  839.     m_dwLastPlayPos = dwCurrentPlayPos;
  840.     // If we are now filling the buffer with silence, then we have found the end so 
  841.     // check to see if the entire sound has played, if it has then stop the buffer.
  842.     if( m_bFillNextNotificationWithSilence )
  843.     {
  844.         // We don't want to cut off the sound before it's done playing.
  845.         if( m_dwPlayProgress >= m_pWaveFile->GetSize() )
  846.         {
  847.             m_apDSBuffer[0]->Stop();
  848.         }
  849.     }
  850.     // Update where the buffer will lock (for next time)
  851.     m_dwNextWriteOffset += dwDSLockedBufferSize; 
  852.     m_dwNextWriteOffset %= m_dwDSBufferSize; // Circular buffer
  853.     return S_OK;
  854. }
  855. //-----------------------------------------------------------------------------
  856. // Name: CStreamingSound::Reset()
  857. // Desc: Resets the sound so it will begin playing at the beginning
  858. //-----------------------------------------------------------------------------
  859. HRESULT CStreamingSound::Reset()
  860. {
  861.     HRESULT hr;
  862.     if( m_apDSBuffer[0] == NULL || m_pWaveFile == NULL )
  863.         return CO_E_NOTINITIALIZED;
  864.     m_dwLastPlayPos     = 0;
  865.     m_dwPlayProgress    = 0;
  866.     m_dwNextWriteOffset = 0;
  867.     m_bFillNextNotificationWithSilence = FALSE;
  868.     // Restore the buffer if it was lost
  869.     BOOL bRestored;
  870.     if( FAILED( hr = RestoreBuffer( m_apDSBuffer[0], &bRestored ) ) )
  871.         return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
  872.     if( bRestored )
  873.     {
  874.         // The buffer was restored, so we need to fill it with new data
  875.         if( FAILED( hr = FillBufferWithSound( m_apDSBuffer[0], FALSE ) ) )
  876.             return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
  877.     }
  878.     m_pWaveFile->ResetFile();
  879.     return m_apDSBuffer[0]->SetCurrentPosition( 0L );  
  880. }
  881. //-----------------------------------------------------------------------------
  882. // Name: CWaveFile::CWaveFile()
  883. // Desc: Constructs the class.  Call Open() to open a wave file for reading.  
  884. //       Then call Read() as needed.  Calling the destructor or Close() 
  885. //       will close the file.  
  886. //-----------------------------------------------------------------------------
  887. CWaveFile::CWaveFile()
  888. {
  889.     m_pwfx    = NULL;
  890.     m_hmmio   = NULL;
  891.     m_pResourceBuffer = NULL;
  892.     m_dwSize  = 0;
  893.     m_bIsReadingFromMemory = FALSE;
  894. }
  895. //-----------------------------------------------------------------------------
  896. // Name: CWaveFile::~CWaveFile()
  897. // Desc: Destructs the class
  898. //-----------------------------------------------------------------------------
  899. CWaveFile::~CWaveFile()
  900. {
  901.     Close();
  902.     if( !m_bIsReadingFromMemory )
  903.         SAFE_DELETE_ARRAY( m_pwfx );
  904. }
  905. //-----------------------------------------------------------------------------
  906. // Name: CWaveFile::Open()
  907. // Desc: Opens a wave file for reading
  908. //-----------------------------------------------------------------------------
  909. HRESULT CWaveFile::Open( LPTSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags )
  910. {
  911.     HRESULT hr;
  912.     m_dwFlags = dwFlags;
  913.     m_bIsReadingFromMemory = FALSE;
  914.     if( m_dwFlags == WAVEFILE_READ )
  915.     {
  916.         if( strFileName == NULL )
  917.             return E_INVALIDARG;
  918.         SAFE_DELETE_ARRAY( m_pwfx );
  919.         m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF | MMIO_READ );
  920.         if( NULL == m_hmmio )
  921.         {
  922.             HRSRC   hResInfo;
  923.             HGLOBAL hResData;
  924.             DWORD   dwSize;
  925.             VOID*   pvRes;
  926.             // Loading it as a file failed, so try it as a resource
  927.             if( NULL == ( hResInfo = FindResource( NULL, strFileName, TEXT("WAVE") ) ) )
  928.             {
  929.                 if( NULL == ( hResInfo = FindResource( NULL, strFileName, TEXT("WAV") ) ) )
  930.                     return DXTRACE_ERR( TEXT("FindResource"), E_FAIL );
  931.             }
  932.             if( NULL == ( hResData = LoadResource( NULL, hResInfo ) ) )
  933.                 return DXTRACE_ERR( TEXT("LoadResource"), E_FAIL );
  934.             if( 0 == ( dwSize = SizeofResource( NULL, hResInfo ) ) ) 
  935.                 return DXTRACE_ERR( TEXT("SizeofResource"), E_FAIL );
  936.             if( NULL == ( pvRes = LockResource( hResData ) ) )
  937.                 return DXTRACE_ERR( TEXT("LockResource"), E_FAIL );
  938.             m_pResourceBuffer = new CHAR[ dwSize ];
  939.             memcpy( m_pResourceBuffer, pvRes, dwSize );
  940.             MMIOINFO mmioInfo;
  941.             ZeroMemory( &mmioInfo, sizeof(mmioInfo) );
  942.             mmioInfo.fccIOProc = FOURCC_MEM;
  943.             mmioInfo.cchBuffer = dwSize;
  944.             mmioInfo.pchBuffer = (CHAR*) m_pResourceBuffer;
  945.             m_hmmio = mmioOpen( NULL, &mmioInfo, MMIO_ALLOCBUF | MMIO_READ );
  946.         }
  947.         if( FAILED( hr = ReadMMIO() ) )
  948.         {
  949.             // ReadMMIO will fail if its an not a wave file
  950.             mmioClose( m_hmmio, 0 );
  951.             return DXTRACE_ERR( TEXT("ReadMMIO"), hr );
  952.         }
  953.         if( FAILED( hr = ResetFile() ) )
  954.             return DXTRACE_ERR( TEXT("ResetFile"), hr );
  955.         // After the reset, the size of the wav file is m_ck.cksize so store it now
  956.         m_dwSize = m_ck.cksize;
  957.     }
  958.     else
  959.     {
  960.         m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF  | 
  961.                                                   MMIO_READWRITE | 
  962.                                                   MMIO_CREATE );
  963.         if( NULL == m_hmmio )
  964.             return DXTRACE_ERR( TEXT("mmioOpen"), E_FAIL );
  965.         if( FAILED( hr = WriteMMIO( pwfx ) ) )
  966.         {
  967.             mmioClose( m_hmmio, 0 );
  968.             return DXTRACE_ERR( TEXT("WriteMMIO"), hr );
  969.         }
  970.                         
  971.         if( FAILED( hr = ResetFile() ) )
  972.             return DXTRACE_ERR( TEXT("ResetFile"), hr );
  973.     }
  974.     return hr;
  975. }
  976. //-----------------------------------------------------------------------------
  977. // Name: CWaveFile::OpenFromMemory()
  978. // Desc: copy data to CWaveFile member variable from memory
  979. //-----------------------------------------------------------------------------
  980. HRESULT CWaveFile::OpenFromMemory( BYTE* pbData, ULONG ulDataSize, 
  981.                                    WAVEFORMATEX* pwfx, DWORD dwFlags )
  982. {
  983.     m_pwfx       = pwfx;
  984.     m_ulDataSize = ulDataSize;
  985.     m_pbData     = pbData;
  986.     m_pbDataCur  = m_pbData;
  987.     m_bIsReadingFromMemory = TRUE;
  988.     
  989.     if( dwFlags != WAVEFILE_READ )
  990.         return E_NOTIMPL;       
  991.     
  992.     return S_OK;
  993. }
  994. //-----------------------------------------------------------------------------
  995. // Name: CWaveFile::ReadMMIO()
  996. // Desc: Support function for reading from a multimedia I/O stream.
  997. //       m_hmmio must be valid before calling.  This function uses it to
  998. //       update m_ckRiff, and m_pwfx. 
  999. //-----------------------------------------------------------------------------
  1000. HRESULT CWaveFile::ReadMMIO()
  1001. {
  1002.     MMCKINFO        ckIn;           // chunk info. for general use.
  1003.     PCMWAVEFORMAT   pcmWaveFormat;  // Temp PCM structure to load in.       
  1004.     m_pwfx = NULL;
  1005.     if( ( 0 != mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) ) )
  1006.         return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
  1007.     // Check to make sure this is a valid wave file
  1008.     if( (m_ckRiff.ckid != FOURCC_RIFF) ||
  1009.         (m_ckRiff.fccType != mmioFOURCC('W', 'A', 'V', 'E') ) )
  1010.         return DXTRACE_ERR( TEXT("mmioFOURCC"), E_FAIL ); 
  1011.     // Search the input file for for the 'fmt ' chunk.
  1012.     ckIn.ckid = mmioFOURCC('f', 'm', 't', ' ');
  1013.     if( 0 != mmioDescend( m_hmmio, &ckIn, &m_ckRiff, MMIO_FINDCHUNK ) )
  1014.         return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
  1015.     // Expect the 'fmt' chunk to be at least as large as <PCMWAVEFORMAT>;
  1016.     // if there are extra parameters at the end, we'll ignore them
  1017.        if( ckIn.cksize < (LONG) sizeof(PCMWAVEFORMAT) )
  1018.            return DXTRACE_ERR( TEXT("sizeof(PCMWAVEFORMAT)"), E_FAIL );
  1019.     // Read the 'fmt ' chunk into <pcmWaveFormat>.
  1020.     if( mmioRead( m_hmmio, (HPSTR) &pcmWaveFormat, 
  1021.                   sizeof(pcmWaveFormat)) != sizeof(pcmWaveFormat) )
  1022.         return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
  1023.     // Allocate the waveformatex, but if its not pcm format, read the next
  1024.     // word, and thats how many extra bytes to allocate.
  1025.     if( pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM )
  1026.     {
  1027.         m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) ];
  1028.         if( NULL == m_pwfx )
  1029.             return DXTRACE_ERR( TEXT("m_pwfx"), E_FAIL );
  1030.         // Copy the bytes from the pcm structure to the waveformatex structure
  1031.         memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
  1032.         m_pwfx->cbSize = 0;
  1033.     }
  1034.     else
  1035.     {
  1036.         // Read in length of extra bytes.
  1037.         WORD cbExtraBytes = 0L;
  1038.         if( mmioRead( m_hmmio, (CHAR*)&cbExtraBytes, sizeof(WORD)) != sizeof(WORD) )
  1039.             return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
  1040.         m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) + cbExtraBytes ];
  1041.         if( NULL == m_pwfx )
  1042.             return DXTRACE_ERR( TEXT("new"), E_FAIL );
  1043.         // Copy the bytes from the pcm structure to the waveformatex structure
  1044.         memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
  1045.         m_pwfx->cbSize = cbExtraBytes;
  1046.         // Now, read those extra bytes into the structure, if cbExtraAlloc != 0.
  1047.         if( mmioRead( m_hmmio, (CHAR*)(((BYTE*)&(m_pwfx->cbSize))+sizeof(WORD)),
  1048.                       cbExtraBytes ) != cbExtraBytes )
  1049.         {
  1050.             SAFE_DELETE( m_pwfx );
  1051.             return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
  1052.         }
  1053.     }
  1054.     // Ascend the input file out of the 'fmt ' chunk.
  1055.     if( 0 != mmioAscend( m_hmmio, &ckIn, 0 ) )
  1056.     {
  1057.         SAFE_DELETE( m_pwfx );
  1058.         return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
  1059.     }
  1060.     return S_OK;
  1061. }
  1062. //-----------------------------------------------------------------------------
  1063. // Name: CWaveFile::GetSize()
  1064. // Desc: Retuns the size of the read access wave file 
  1065. //-----------------------------------------------------------------------------
  1066. DWORD CWaveFile::GetSize()
  1067. {
  1068.     return m_dwSize;
  1069. }
  1070. //-----------------------------------------------------------------------------
  1071. // Name: CWaveFile::ResetFile()
  1072. // Desc: Resets the internal m_ck pointer so reading starts from the 
  1073. //       beginning of the file again 
  1074. //-----------------------------------------------------------------------------
  1075. HRESULT CWaveFile::ResetFile()
  1076. {
  1077.     if( m_bIsReadingFromMemory )
  1078.     {
  1079.         m_pbDataCur = m_pbData;
  1080.     }
  1081.     else 
  1082.     {
  1083.         if( m_hmmio == NULL )
  1084.             return CO_E_NOTINITIALIZED;
  1085.         if( m_dwFlags == WAVEFILE_READ )
  1086.         {
  1087.             // Seek to the data
  1088.             if( -1 == mmioSeek( m_hmmio, m_ckRiff.dwDataOffset + sizeof(FOURCC),
  1089.                             SEEK_SET ) )
  1090.                 return DXTRACE_ERR( TEXT("mmioSeek"), E_FAIL );
  1091.             // Search the input file for the 'data' chunk.
  1092.             m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
  1093.             if( 0 != mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) )
  1094.               return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
  1095.         }
  1096.         else
  1097.         {
  1098.             // Create the 'data' chunk that holds the waveform samples.  
  1099.             m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
  1100.             m_ck.cksize = 0;
  1101.             if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) ) 
  1102.                 return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
  1103.             if( 0 != mmioGetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
  1104.                 return DXTRACE_ERR( TEXT("mmioGetInfo"), E_FAIL );
  1105.         }
  1106.     }
  1107.     
  1108.     return S_OK;
  1109. }
  1110. //-----------------------------------------------------------------------------
  1111. // Name: CWaveFile::Read()
  1112. // Desc: Reads section of data from a wave file into pBuffer and returns 
  1113. //       how much read in pdwSizeRead, reading not more than dwSizeToRead.
  1114. //       This uses m_ck to determine where to start reading from.  So 
  1115. //       subsequent calls will be continue where the last left off unless 
  1116. //       Reset() is called.
  1117. //-----------------------------------------------------------------------------
  1118. HRESULT CWaveFile::Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead )
  1119. {
  1120.     if( m_bIsReadingFromMemory )
  1121.     {
  1122.         if( m_pbDataCur == NULL )
  1123.             return CO_E_NOTINITIALIZED;
  1124.         if( pdwSizeRead != NULL )
  1125.             *pdwSizeRead = 0;
  1126.         if( (BYTE*)(m_pbDataCur + dwSizeToRead) > 
  1127.             (BYTE*)(m_pbData + m_ulDataSize) )
  1128.         {
  1129.             dwSizeToRead = m_ulDataSize - (DWORD)(m_pbDataCur - m_pbData);
  1130.         }
  1131.         
  1132.         CopyMemory( pBuffer, m_pbDataCur, dwSizeToRead );
  1133.         
  1134.         if( pdwSizeRead != NULL )
  1135.             *pdwSizeRead = dwSizeToRead;
  1136.         return S_OK;
  1137.     }
  1138.     else 
  1139.     {
  1140.         MMIOINFO mmioinfoIn; // current status of m_hmmio
  1141.         if( m_hmmio == NULL )
  1142.             return CO_E_NOTINITIALIZED;
  1143.         if( pBuffer == NULL || pdwSizeRead == NULL )
  1144.             return E_INVALIDARG;
  1145.         if( pdwSizeRead != NULL )
  1146.             *pdwSizeRead = 0;
  1147.         if( 0 != mmioGetInfo( m_hmmio, &mmioinfoIn, 0 ) )
  1148.             return DXTRACE_ERR( TEXT("mmioGetInfo"), E_FAIL );
  1149.                 
  1150.         UINT cbDataIn = dwSizeToRead;
  1151.         if( cbDataIn > m_ck.cksize ) 
  1152.             cbDataIn = m_ck.cksize;       
  1153.         m_ck.cksize -= cbDataIn;
  1154.     
  1155.         for( DWORD cT = 0; cT < cbDataIn; cT++ )
  1156.         {
  1157.             // Copy the bytes from the io to the buffer.
  1158.             if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
  1159.             {
  1160.                 if( 0 != mmioAdvance( m_hmmio, &mmioinfoIn, MMIO_READ ) )
  1161.                     return DXTRACE_ERR( TEXT("mmioAdvance"), E_FAIL );
  1162.                 if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
  1163.                     return DXTRACE_ERR( TEXT("mmioinfoIn.pchNext"), E_FAIL );
  1164.             }
  1165.             // Actual copy.
  1166.             *((BYTE*)pBuffer+cT) = *((BYTE*)mmioinfoIn.pchNext);
  1167.             mmioinfoIn.pchNext++;
  1168.         }
  1169.         if( 0 != mmioSetInfo( m_hmmio, &mmioinfoIn, 0 ) )
  1170.             return DXTRACE_ERR( TEXT("mmioSetInfo"), E_FAIL );
  1171.         if( pdwSizeRead != NULL )
  1172.             *pdwSizeRead = cbDataIn;
  1173.         return S_OK;
  1174.     }
  1175. }
  1176. //-----------------------------------------------------------------------------
  1177. // Name: CWaveFile::Close()
  1178. // Desc: Closes the wave file 
  1179. //-----------------------------------------------------------------------------
  1180. HRESULT CWaveFile::Close()
  1181. {
  1182.     if( m_dwFlags == WAVEFILE_READ )
  1183.     {
  1184.         mmioClose( m_hmmio, 0 );
  1185.         m_hmmio = NULL;
  1186.         SAFE_DELETE_ARRAY( m_pResourceBuffer );
  1187.     }
  1188.     else
  1189.     {
  1190.         m_mmioinfoOut.dwFlags |= MMIO_DIRTY;
  1191.         if( m_hmmio == NULL )
  1192.             return CO_E_NOTINITIALIZED;
  1193.         if( 0 != mmioSetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
  1194.             return DXTRACE_ERR( TEXT("mmioSetInfo"), E_FAIL );
  1195.     
  1196.         // Ascend the output file out of the 'data' chunk -- this will cause
  1197.         // the chunk size of the 'data' chunk to be written.
  1198.         if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
  1199.             return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
  1200.     
  1201.         // Do this here instead...
  1202.         if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
  1203.             return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
  1204.         
  1205.         mmioSeek( m_hmmio, 0, SEEK_SET );
  1206.         if( 0 != (INT)mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) )
  1207.             return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
  1208.     
  1209.         m_ck.ckid = mmioFOURCC('f', 'a', 'c', 't');
  1210.         if( 0 == mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) ) 
  1211.         {
  1212.             DWORD dwSamples = 0;
  1213.             mmioWrite( m_hmmio, (HPSTR)&dwSamples, sizeof(DWORD) );
  1214.             mmioAscend( m_hmmio, &m_ck, 0 ); 
  1215.         }
  1216.     
  1217.         // Ascend the output file out of the 'RIFF' chunk -- this will cause
  1218.         // the chunk size of the 'RIFF' chunk to be written.
  1219.         if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
  1220.             return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
  1221.     
  1222.         mmioClose( m_hmmio, 0 );
  1223.         m_hmmio = NULL;
  1224.     }
  1225.     return S_OK;
  1226. }
  1227. //-----------------------------------------------------------------------------
  1228. // Name: CWaveFile::WriteMMIO()
  1229. // Desc: Support function for reading from a multimedia I/O stream
  1230. //       pwfxDest is the WAVEFORMATEX for this new wave file.  
  1231. //       m_hmmio must be valid before calling.  This function uses it to
  1232. //       update m_ckRiff, and m_ck.  
  1233. //-----------------------------------------------------------------------------
  1234. HRESULT CWaveFile::WriteMMIO( WAVEFORMATEX *pwfxDest )
  1235. {
  1236.     DWORD    dwFactChunk; // Contains the actual fact chunk. Garbage until WaveCloseWriteFile.
  1237.     MMCKINFO ckOut1;
  1238.     
  1239.     dwFactChunk = (DWORD)-1;
  1240.     // Create the output file RIFF chunk of form type 'WAVE'.
  1241.     m_ckRiff.fccType = mmioFOURCC('W', 'A', 'V', 'E');       
  1242.     m_ckRiff.cksize = 0;
  1243.     if( 0 != mmioCreateChunk( m_hmmio, &m_ckRiff, MMIO_CREATERIFF ) )
  1244.         return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
  1245.     
  1246.     // We are now descended into the 'RIFF' chunk we just created.
  1247.     // Now create the 'fmt ' chunk. Since we know the size of this chunk,
  1248.     // specify it in the MMCKINFO structure so MMIO doesn't have to seek
  1249.     // back and set the chunk size after ascending from the chunk.
  1250.     m_ck.ckid = mmioFOURCC('f', 'm', 't', ' ');
  1251.     m_ck.cksize = sizeof(PCMWAVEFORMAT);   
  1252.     if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) )
  1253.         return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
  1254.     
  1255.     // Write the PCMWAVEFORMAT structure to the 'fmt ' chunk if its that type. 
  1256.     if( pwfxDest->wFormatTag == WAVE_FORMAT_PCM )
  1257.     {
  1258.         if( mmioWrite( m_hmmio, (HPSTR) pwfxDest, 
  1259.                        sizeof(PCMWAVEFORMAT)) != sizeof(PCMWAVEFORMAT))
  1260.             return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
  1261.     }   
  1262.     else 
  1263.     {
  1264.         // Write the variable length size.
  1265.         if( (UINT)mmioWrite( m_hmmio, (HPSTR) pwfxDest, 
  1266.                              sizeof(*pwfxDest) + pwfxDest->cbSize ) != 
  1267.                              ( sizeof(*pwfxDest) + pwfxDest->cbSize ) )
  1268.             return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
  1269.     }  
  1270.     
  1271.     // Ascend out of the 'fmt ' chunk, back into the 'RIFF' chunk.
  1272.     if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
  1273.         return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
  1274.     
  1275.     // Now create the fact chunk, not required for PCM but nice to have.  This is filled
  1276.     // in when the close routine is called.
  1277.     ckOut1.ckid = mmioFOURCC('f', 'a', 'c', 't');
  1278.     ckOut1.cksize = 0;
  1279.     if( 0 != mmioCreateChunk( m_hmmio, &ckOut1, 0 ) )
  1280.         return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
  1281.     
  1282.     if( mmioWrite( m_hmmio, (HPSTR)&dwFactChunk, sizeof(dwFactChunk)) != 
  1283.                     sizeof(dwFactChunk) )
  1284.          return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
  1285.     
  1286.     // Now ascend out of the fact chunk...
  1287.     if( 0 != mmioAscend( m_hmmio, &ckOut1, 0 ) )
  1288.         return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
  1289.        
  1290.     return S_OK;
  1291. }
  1292. //-----------------------------------------------------------------------------
  1293. // Name: CWaveFile::Write()
  1294. // Desc: Writes data to the open wave file
  1295. //-----------------------------------------------------------------------------
  1296. HRESULT CWaveFile::Write( UINT nSizeToWrite, BYTE* pbSrcData, UINT* pnSizeWrote )
  1297. {
  1298.     UINT cT;
  1299.     if( m_bIsReadingFromMemory )
  1300.         return E_NOTIMPL;
  1301.     if( m_hmmio == NULL )
  1302.         return CO_E_NOTINITIALIZED;
  1303.     if( pnSizeWrote == NULL || pbSrcData == NULL )
  1304.         return E_INVALIDARG;
  1305.     *pnSizeWrote = 0;
  1306.     
  1307.     for( cT = 0; cT < nSizeToWrite; cT++ )
  1308.     {       
  1309.         if( m_mmioinfoOut.pchNext == m_mmioinfoOut.pchEndWrite )
  1310.         {
  1311.             m_mmioinfoOut.dwFlags |= MMIO_DIRTY;
  1312.             if( 0 != mmioAdvance( m_hmmio, &m_mmioinfoOut, MMIO_WRITE ) )
  1313.                 return DXTRACE_ERR( TEXT("mmioAdvance"), E_FAIL );
  1314.         }
  1315.         *((BYTE*)m_mmioinfoOut.pchNext) = *((BYTE*)pbSrcData+cT);
  1316.         (BYTE*)m_mmioinfoOut.pchNext++;
  1317.         (*pnSizeWrote)++;
  1318.     }
  1319.     return S_OK;
  1320. }