DirectSound的简单使用

DirectSound是DirectX中为游戏处理所有声音输出的组件,只需要告诉DirectSound要播放的声音,它会处理所有细节。使用DirectSound创建、初始化、装载及播放声音文件的代码比起之前的内容要复杂一些,为了避免重复劳动,这里将使用Microsoft自己的DirectSound包装器。有些时候,考虑时间因素,必须妥协并使用已有的东西。DirectX SDK包括一个称为DXUTsound的实用工具库,我们不准备使用,因为它需要的支持文件太多。我们将使用一个老一点的版本,来自以前的DirectX 9.0c版,老的DirectSound的DXUT版可以在名为dsutil.cpp和dsutil.h的这一对文件中找到;后来的DirectX Sound类库与DXUTsound.h和DXUTsound.cpp合并在了一起;最新版的DirectX将这些类藏到了另外一组文件中:SDKsound.h、SDKsound.cpp和SDKwavefile.h。由于这些不一致性,我们创建了一对新的音频文件DirectSound.h与DirectSound.cpp以供使用,包含来自老的dsutil的源代码,这些在最新DirectX中也没更改。

 

为使用DirectSound,首先要做的是创建CSoundManager类的实例,CSoundManager *dsound = new CSoundManager();下一步调用Initialize函数来初始化DirectSound管理器,dsound->Initialize(window_handle, DSSCL_PRIORITY);初始化后,我们必须设置音频缓冲区格式,dsound->SetPrimaryBufferFormat(2, 22050, 16);在初始化了DirectSound管理器后,我们要接着创建声音缓冲区,CSound *wave,wave是名为LPDIRECTSOUNDBUFFER8的第二声音缓冲区的包装器,由于存在实用工具类,我们无需自己来编程。可以把由DirectSound创建好管理的声音混音器当成声音的主缓冲区,如Direct3D一样,主缓冲区是输出发生的地方。只不过在DirectSound的情况中,第二缓冲区是声音数据而不是位图数据。将声音文件装载到DirectSound的第二缓冲区中只涉及对一个Create函数的调用,即dsound->Create(&wave, "snicker.wav");要播放声音,可以使用wave->Play(); 要循环播放,使用wave->Play(0, DSBPLAY_LOOPING); 要停止播放,使用wave->Stop()。

 

下面的例子基于前面的例子,同时必须使用下面的两个文件。

DirectSound.h:

View Code
 1 //-----------------------------------------------------------------------------  2 // File: DSUtil.h  3 //
 4 // Desc:  5 //
 6 // Copyright (c) Microsoft Corp. All rights reserved.  7 //-----------------------------------------------------------------------------  8 //
 9 // Note: This file has been edited for use in Beginning Game Programming, Third Edition,  10 // originally distributed with a 2004 release of DirectX 9.0c SDK.  11 //  12 
 13 #ifndef DSUTIL_H  14 #define DSUTIL_H
 15 
 16 #include <windows.h>
 17 #include <mmsystem.h>
 18 #include <mmreg.h>
 19 #include <dsound.h>
 20 #include <dxerr.h>
 21 
 22 #pragma comment(lib, "dxerr.lib")
 23 #pragma comment(lib, "dsound.lib")
 24 
 25 
 26 //-----------------------------------------------------------------------------  27 // Classes used by this header  28 //-----------------------------------------------------------------------------
 29 class CSoundManager;  30 class CSound;  31 class CStreamingSound;  32 class CWaveFile;  33 
 34 
 35 
 36 
 37 //-----------------------------------------------------------------------------  38 // Typing macros  39 //-----------------------------------------------------------------------------
 40 #define WAVEFILE_READ   1
 41 #define WAVEFILE_WRITE  2
 42 
 43 #define DSUtil_StopSound(s)         { if(s) s->Stop(); }
 44 #define DSUtil_PlaySound(s)         { if(s) s->Play( 0, 0 ); }
 45 #define DSUtil_PlaySoundLooping(s)  { if(s) s->Play( 0, DSBPLAY_LOOPING ); }
 46 
 47 
 48 
 49 
 50 //-----------------------------------------------------------------------------  51 // Name: class CSoundManager  52 // Desc:  53 //-----------------------------------------------------------------------------
 54 class CSoundManager  55 {  56 protected:  57  LPDIRECTSOUND8 m_pDS;  58 
 59 public:  60  CSoundManager();  61     ~CSoundManager();  62 
 63  HRESULT Initialize( HWND hWnd, DWORD dwCoopLevel );  64 
 65     inline  LPDIRECTSOUND8 GetDirectSound() { return m_pDS; }  66 
 67  HRESULT SetPrimaryBufferFormat( DWORD dwPrimaryChannels, DWORD dwPrimaryFreq,  68  DWORD dwPrimaryBitRate );  69 
 70     HRESULT Create( CSound** ppSound, LPTSTR strWaveFileName, DWORD dwCreationFlags = 0,  71         GUID guid3DAlgorithm = GUID_NULL, DWORD dwNumBuffers = 1 );  72 };  73 
 74 
 75 
 76 
 77 //-----------------------------------------------------------------------------  78 // Name: class CSound  79 // Desc: Encapsulates functionality of a DirectSound buffer.  80 //-----------------------------------------------------------------------------
 81 class CSound  82 {  83 protected:  84     LPDIRECTSOUNDBUFFER* m_apDSBuffer;  85  DWORD m_dwDSBufferSize;  86     CWaveFile* m_pWaveFile;  87  DWORD m_dwNumBuffers;  88  DWORD m_dwCreationFlags;  89 
 90     HRESULT RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, BOOL* pbWasRestored );  91 
 92 public:  93     CSound( LPDIRECTSOUNDBUFFER* apDSBuffer, DWORD dwDSBufferSize, DWORD dwNumBuffers,  94         CWaveFile* pWaveFile, DWORD dwCreationFlags );  95     virtual ~CSound();  96 
 97  HRESULT FillBufferWithSound( LPDIRECTSOUNDBUFFER pDSB, BOOL bRepeatWavIfBufferLarger );  98  LPDIRECTSOUNDBUFFER GetFreeBuffer();  99 
100     HRESULT Play( DWORD dwPriority = 0, DWORD dwFlags = 0, LONG lVolume = 0, 101         LONG lFrequency = -1, LONG lPan = 0 ); 102  HRESULT Stop(); 103  HRESULT Reset(); 104  BOOL IsSoundPlaying(); 105 }; 106 
107 
108 //----------------------------------------------------------------------------- 109 // Name: class CWaveFile 110 // Desc: Encapsulates reading or writing sound data to or from a wave file 111 //-----------------------------------------------------------------------------
112 class CWaveFile 113 { 114 public: 115     WAVEFORMATEX* m_pwfx;        // Pointer to WAVEFORMATEX structure
116     HMMIO         m_hmmio;       // MM I/O handle for the WAVE
117     MMCKINFO      m_ck;          // Multimedia RIFF chunk
118     MMCKINFO      m_ckRiff;      // Use in opening a WAVE file
119     DWORD         m_dwSize;      // The size of the wave file
120  MMIOINFO m_mmioinfoOut; 121  DWORD m_dwFlags; 122  BOOL m_bIsReadingFromMemory; 123     BYTE* m_pbData; 124     BYTE* m_pbDataCur; 125  ULONG m_ulDataSize; 126     CHAR* m_pResourceBuffer; 127 
128 protected: 129  HRESULT ReadMMIO(); 130     HRESULT WriteMMIO( WAVEFORMATEX *pwfxDest ); 131 
132 public: 133  CWaveFile(); 134     ~CWaveFile(); 135 
136     HRESULT Open( LPTSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags ); 137  HRESULT Close(); 138 
139     HRESULT Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead ); 140     HRESULT Write( UINT nSizeToWrite, BYTE* pbData, UINT* pnSizeWrote ); 141 
142  DWORD GetSize(); 143  HRESULT ResetFile(); 144     WAVEFORMATEX* GetFormat() { return m_pwfx; }; 145 }; 146 
147 
148 
149 
150 #endif // DSUTIL_H

 

DirectSound.cpp:

View Code
 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 //
 11 // Note: This file has been edited for use in Beginning Game Programming, Third Edition,  12 // originally distributed with a 2004 release of DirectX 9.0c SDK.  13 //  14 
 15 #define STRICT
 16 #include <windows.h>
 17 #include <mmsystem.h>
 18 #include "DirectSound.h"
 19 
 20 
 21 //-----------------------------------------------------------------------------  22 // Miscellaneous helper functions  23 //-----------------------------------------------------------------------------
 24 #define SAFE_DELETE(p)       { if(p) { delete (p);     (p)=NULL; } }
 25 #define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p);   (p)=NULL; } }
 26 #define SAFE_RELEASE(p)      { if(p) { (p)->Release(); (p)=NULL; } }
 27 
 28 
 29 //-----------------------------------------------------------------------------  30 // Name: CSoundManager::CSoundManager()  31 // Desc: Constructs the class  32 //-----------------------------------------------------------------------------
 33 CSoundManager::CSoundManager()  34 {  35     m_pDS = NULL;  36 }  37 
 38 //-----------------------------------------------------------------------------  39 // Name: CSoundManager::~CSoundManager()  40 // Desc: Destroys the class  41 //-----------------------------------------------------------------------------
 42 CSoundManager::~CSoundManager()  43 {  44  SAFE_RELEASE( m_pDS );  45 }  46 
 47 //-----------------------------------------------------------------------------  48 // Name: CSoundManager::Initialize()  49 // Desc: Initializes the IDirectSound object and also sets the primary buffer  50 // format. This function must be called before any others.  51 //-----------------------------------------------------------------------------
 52 HRESULT CSoundManager::Initialize( HWND hWnd,  53  DWORD dwCoopLevel )  54 {  55  HRESULT hr;  56 
 57  SAFE_RELEASE( m_pDS );  58 
 59     // Create IDirectSound using the primary sound device
 60     if( FAILED( hr = DirectSoundCreate8( NULL, &m_pDS, NULL ) ) )  61         return DXTRACE_ERR( TEXT("DirectSoundCreate8"), hr );  62 
 63     // Set DirectSound coop level 
 64     if( FAILED( hr = m_pDS->SetCooperativeLevel( hWnd, dwCoopLevel ) ) )  65         return DXTRACE_ERR( TEXT("SetCooperativeLevel"), hr );  66 
 67     return S_OK;  68 }  69 
 70 
 71 
 72 
 73 //-----------------------------------------------------------------------------  74 // Name: CSoundManager::SetPrimaryBufferFormat()  75 // Desc: Set primary buffer to a specified format  76 // !WARNING! - Setting the primary buffer format and then using this  77 // same dsound object for DirectMusic messes up DirectMusic!  78 // For example, to set the primary buffer format to 22kHz stereo, 16-bit  79 // then: dwPrimaryChannels = 2  80 // dwPrimaryFreq = 22050,  81 // dwPrimaryBitRate = 16  82 //-----------------------------------------------------------------------------
 83 HRESULT CSoundManager::SetPrimaryBufferFormat( DWORD dwPrimaryChannels,  84  DWORD dwPrimaryFreq,  85  DWORD dwPrimaryBitRate )  86 {  87  HRESULT hr;  88     LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;  89 
 90     if( m_pDS == NULL )  91         return CO_E_NOTINITIALIZED;  92 
 93     // Get the primary buffer 
 94  DSBUFFERDESC dsbd;  95     ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );  96     dsbd.dwSize        = sizeof(DSBUFFERDESC);  97     dsbd.dwFlags       = DSBCAPS_PRIMARYBUFFER;  98     dsbd.dwBufferBytes = 0;  99     dsbd.lpwfxFormat   = NULL;  100        
 101     if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBPrimary, NULL ) ) )  102         return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );  103 
 104  WAVEFORMATEX wfx;  105     ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );  106     wfx.wFormatTag      = (WORD) WAVE_FORMAT_PCM;  107     wfx.nChannels       = (WORD) dwPrimaryChannels;  108     wfx.nSamplesPerSec  = (DWORD) dwPrimaryFreq;  109     wfx.wBitsPerSample  = (WORD) dwPrimaryBitRate;  110     wfx.nBlockAlign     = (WORD) (wfx.wBitsPerSample / 8 * wfx.nChannels);  111     wfx.nAvgBytesPerSec = (DWORD) (wfx.nSamplesPerSec * wfx.nBlockAlign);  112 
 113     if( FAILED( hr = pDSBPrimary->SetFormat(&wfx) ) )  114         return DXTRACE_ERR( TEXT("SetFormat"), hr );  115 
 116  SAFE_RELEASE( pDSBPrimary );  117 
 118     return S_OK;  119 }  120 
 121 
 122 
 123 //-----------------------------------------------------------------------------  124 // Name: CSoundManager::Create()  125 // Desc:  126 //-----------------------------------------------------------------------------
 127 HRESULT CSoundManager::Create( CSound** ppSound,  128  LPTSTR strWaveFileName,  129  DWORD dwCreationFlags,  130  GUID guid3DAlgorithm,  131  DWORD dwNumBuffers )  132 {  133  HRESULT hr;  134     HRESULT hrRet = S_OK;  135  DWORD i;  136     LPDIRECTSOUNDBUFFER* apDSBuffer     = NULL;  137     DWORD                dwDSBufferSize = NULL;  138     CWaveFile*           pWaveFile      = NULL;  139 
 140     if( m_pDS == NULL )  141         return CO_E_NOTINITIALIZED;  142     if( strWaveFileName == NULL || ppSound == NULL || dwNumBuffers < 1 )  143         return E_INVALIDARG;  144 
 145     apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];  146     if( apDSBuffer == NULL )  147  {  148         hr = E_OUTOFMEMORY;  149         goto LFail;  150  }  151 
 152     pWaveFile = new CWaveFile();  153     if( pWaveFile == NULL )  154  {  155         hr = E_OUTOFMEMORY;  156         goto LFail;  157  }  158 
 159     pWaveFile->Open( strWaveFileName, NULL, WAVEFILE_READ );  160 
 161     if( pWaveFile->GetSize() == 0 )  162  {  163         // Wave is blank, so don't create it.
 164         hr = E_FAIL;  165         goto LFail;  166  }  167 
 168     // Make the DirectSound buffer the same size as the wav file
 169     dwDSBufferSize = pWaveFile->GetSize();  170 
 171     // Create the direct sound buffer, and only request the flags needed  172     // since each requires some overhead and limits if the buffer can  173     // be hardware accelerated
 174  DSBUFFERDESC dsbd;  175     ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );  176     dsbd.dwSize          = sizeof(DSBUFFERDESC);  177     dsbd.dwFlags         = dwCreationFlags;  178     dsbd.dwBufferBytes   = dwDSBufferSize;  179     dsbd.guid3DAlgorithm = guid3DAlgorithm;  180     dsbd.lpwfxFormat     = pWaveFile->m_pwfx;  181     
 182     // DirectSound is only guarenteed to play PCM data. Other  183     // formats may or may not work depending the sound card driver.
 184     hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[0], NULL );  185 
 186     // Be sure to return this error code if it occurs so the  187     // callers knows this happened.
 188     if( hr == DS_NO_VIRTUALIZATION )  189         hrRet = DS_NO_VIRTUALIZATION;  190             
 191     if( FAILED(hr) )  192  {  193         // DSERR_BUFFERTOOSMALL will be returned if the buffer is  194         // less than DSBSIZE_FX_MIN and the buffer is created  195         // with DSBCAPS_CTRLFX.  196         
 197         // It might also fail if hardware buffer mixing was requested  198         // on a device that doesn't support it.
 199         DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );  200                     
 201         goto LFail;  202  }  203 
 204     // Default to use DuplicateSoundBuffer() when created extra buffers since always  205     // create a buffer that uses the same memory however DuplicateSoundBuffer() will fail if  206     // DSBCAPS_CTRLFX is used, so use CreateSoundBuffer() instead in this case.
 207     if( (dwCreationFlags & DSBCAPS_CTRLFX) == 0 )  208  {  209         for( i=1; i<dwNumBuffers; i++ )  210  {  211             if( FAILED( hr = m_pDS->DuplicateSoundBuffer( apDSBuffer[0], &apDSBuffer[i] ) ) )  212  {  213                 DXTRACE_ERR( TEXT("DuplicateSoundBuffer"), hr );  214                 goto LFail;  215  }  216  }  217  }  218     else
 219  {  220         for( i=1; i<dwNumBuffers; i++ )  221  {  222             hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[i], NULL );  223             if( FAILED(hr) )  224  {  225                 DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );  226                 goto LFail;  227  }  228  }  229  }  230     
 231     // Create the sound
 232     *ppSound = new CSound( apDSBuffer, dwDSBufferSize, dwNumBuffers, pWaveFile, dwCreationFlags );  233     
 234  SAFE_DELETE_ARRAY( apDSBuffer );  235     return hrRet;  236 
 237 LFail:  238     // Cleanup
 239  SAFE_DELETE( pWaveFile );  240  SAFE_DELETE_ARRAY( apDSBuffer );  241     return hr;  242 }  243 
 244 
 245 
 246 //-----------------------------------------------------------------------------  247 // Name: CSound::CSound()  248 // Desc: Constructs the class  249 //-----------------------------------------------------------------------------
 250 CSound::CSound( LPDIRECTSOUNDBUFFER* apDSBuffer, DWORD dwDSBufferSize,  251                 DWORD dwNumBuffers, CWaveFile* pWaveFile, DWORD dwCreationFlags )  252 {  253  DWORD i;  254 
 255     m_apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];  256     if( NULL != m_apDSBuffer )  257  {  258         for( i=0; i<dwNumBuffers; i++ )  259             m_apDSBuffer[i] = apDSBuffer[i];  260     
 261         m_dwDSBufferSize = dwDSBufferSize;  262         m_dwNumBuffers   = dwNumBuffers;  263         m_pWaveFile      = pWaveFile;  264         m_dwCreationFlags = dwCreationFlags;  265         
 266         FillBufferWithSound( m_apDSBuffer[0], FALSE );  267  }  268 }  269 
 270 
 271 
 272 
 273 //-----------------------------------------------------------------------------  274 // Name: CSound::~CSound()  275 // Desc: Destroys the class  276 //-----------------------------------------------------------------------------
 277 CSound::~CSound()  278 {  279     for( DWORD i=0; i<m_dwNumBuffers; i++ )  280  {  281  SAFE_RELEASE( m_apDSBuffer[i] );  282  }  283 
 284  SAFE_DELETE_ARRAY( m_apDSBuffer );  285  SAFE_DELETE( m_pWaveFile );  286 }  287 
 288 
 289 
 290 
 291 //-----------------------------------------------------------------------------  292 // Name: CSound::FillBufferWithSound()  293 // Desc: Fills a DirectSound buffer with a sound file  294 //-----------------------------------------------------------------------------
 295 HRESULT CSound::FillBufferWithSound( LPDIRECTSOUNDBUFFER pDSB, BOOL bRepeatWavIfBufferLarger )  296 {  297  HRESULT hr;  298     VOID*   pDSLockedBuffer      = NULL; // Pointer to locked buffer memory
 299     DWORD   dwDSLockedBufferSize = 0;    // Size of the locked DirectSound buffer
 300     DWORD   dwWavDataRead        = 0;    // Amount of data read from the wav file 
 301 
 302     if( pDSB == NULL )  303         return CO_E_NOTINITIALIZED;  304 
 305     // Make sure we have focus, and we didn't just switch in from  306     // an app which had a DirectSound device
 307     if( FAILED( hr = RestoreBuffer( pDSB, NULL ) ) )  308         return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );  309 
 310     // Lock the buffer down
 311     if( FAILED( hr = pDSB->Lock( 0, m_dwDSBufferSize,  312                                  &pDSLockedBuffer, &dwDSLockedBufferSize,  313                                  NULL, NULL, 0L ) ) )  314         return DXTRACE_ERR( TEXT("Lock"), hr );  315 
 316     // Reset the wave file to the beginning 
 317     m_pWaveFile->ResetFile();  318 
 319     if( FAILED( hr = m_pWaveFile->Read( (BYTE*) pDSLockedBuffer,  320  dwDSLockedBufferSize,  321                                         &dwWavDataRead ) ) )  322         return DXTRACE_ERR( TEXT("Read"), hr );  323 
 324     if( dwWavDataRead == 0 )  325  {  326         // Wav is blank, so just fill with silence
 327         FillMemory( (BYTE*) pDSLockedBuffer,  328  dwDSLockedBufferSize,  329                     (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );  330  }  331     else if( dwWavDataRead < dwDSLockedBufferSize )  332  {  333         // If the wav file was smaller than the DirectSound buffer,  334         // we need to fill the remainder of the buffer with data 
 335         if( bRepeatWavIfBufferLarger )  336  {  337             // Reset the file and fill the buffer with wav data
 338             DWORD dwReadSoFar = dwWavDataRead;    // From previous call above.
 339             while( dwReadSoFar < dwDSLockedBufferSize )  340  {  341                 // This will keep reading in until the buffer is full  342                 // for very short files
 343                 if( FAILED( hr = m_pWaveFile->ResetFile() ) )  344                     return DXTRACE_ERR( TEXT("ResetFile"), hr );  345 
 346                 hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar,  347                                         dwDSLockedBufferSize - dwReadSoFar,  348                                         &dwWavDataRead );  349                 if( FAILED(hr) )  350                     return DXTRACE_ERR( TEXT("Read"), hr );  351 
 352                 dwReadSoFar += dwWavDataRead;  353  }  354  }  355         else
 356  {  357             // Don't repeat the wav file, just fill in silence 
 358             FillMemory( (BYTE*) pDSLockedBuffer + dwWavDataRead,  359                         dwDSLockedBufferSize - dwWavDataRead,  360                         (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );  361  }  362  }  363 
 364     // Unlock the buffer, we don't need it anymore.
 365     pDSB->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );  366 
 367     return S_OK;  368 }  369 
 370 
 371 
 372 
 373 //-----------------------------------------------------------------------------  374 // Name: CSound::RestoreBuffer()  375 // Desc: Restores the lost buffer. *pbWasRestored returns TRUE if the buffer was  376 // restored. It can also NULL if the information is not needed.  377 //-----------------------------------------------------------------------------
 378 HRESULT CSound::RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, BOOL* pbWasRestored )  379 {  380  HRESULT hr;  381 
 382     if( pDSB == NULL )  383         return CO_E_NOTINITIALIZED;  384     if( pbWasRestored )  385         *pbWasRestored = FALSE;  386 
 387  DWORD dwStatus;  388     if( FAILED( hr = pDSB->GetStatus( &dwStatus ) ) )  389         return DXTRACE_ERR( TEXT("GetStatus"), hr );  390 
 391     if( dwStatus & DSBSTATUS_BUFFERLOST )  392  {  393         // Since the app could have just been activated, then  394         // DirectSound may not be giving us control yet, so  395         // the restoring the buffer may fail.  396         // If it does, sleep until DirectSound gives us control.
 397         do 
 398  {  399             hr = pDSB->Restore();  400             if( hr == DSERR_BUFFERLOST )  401                 Sleep( 10 );  402  }  403         while( ( hr = pDSB->Restore() ) == DSERR_BUFFERLOST );  404 
 405         if( pbWasRestored != NULL )  406             *pbWasRestored = TRUE;  407 
 408         return S_OK;  409  }  410     else
 411  {  412         return S_FALSE;  413  }  414 }  415 
 416 
 417 
 418 
 419 //-----------------------------------------------------------------------------  420 // Name: CSound::GetFreeBuffer()  421 // Desc: Finding the first buffer that is not playing and return a pointer to  422 // it, or if all are playing return a pointer to a randomly selected buffer.  423 //-----------------------------------------------------------------------------
 424 LPDIRECTSOUNDBUFFER CSound::GetFreeBuffer()  425 {  426     if( m_apDSBuffer == NULL )  427         return FALSE;  428  DWORD i;  429     for( i=0; i<m_dwNumBuffers; i++ )  430  {  431         if( m_apDSBuffer[i] )  432  {  433             DWORD dwStatus = 0;  434             m_apDSBuffer[i]->GetStatus( &dwStatus );  435             if ( ( dwStatus & DSBSTATUS_PLAYING ) == 0 )  436                 break;  437  }  438  }  439 
 440     if( i != m_dwNumBuffers )  441         return m_apDSBuffer[ i ];  442     else
 443         return m_apDSBuffer[ rand() % m_dwNumBuffers ];  444 }  445 
 446 
 447 
 448 //-----------------------------------------------------------------------------  449 // Name: CSound::Play()  450 // Desc: Plays the sound using voice management flags. Pass in DSBPLAY_LOOPING  451 // in the dwFlags to loop the sound  452 //-----------------------------------------------------------------------------
 453 HRESULT CSound::Play( DWORD dwPriority, DWORD dwFlags, LONG lVolume, LONG lFrequency, LONG lPan )  454 {  455  HRESULT hr;  456  BOOL bRestored;  457 
 458     if( m_apDSBuffer == NULL )  459         return CO_E_NOTINITIALIZED;  460 
 461     LPDIRECTSOUNDBUFFER pDSB = GetFreeBuffer();  462 
 463     if( pDSB == NULL )  464         return DXTRACE_ERR( TEXT("GetFreeBuffer"), E_FAIL );  465 
 466     // Restore the buffer if it was lost
 467     if( FAILED( hr = RestoreBuffer( pDSB, &bRestored ) ) )  468         return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );  469 
 470     if( bRestored )  471  {  472         // The buffer was restored, so we need to fill it with new data
 473         if( FAILED( hr = FillBufferWithSound( pDSB, FALSE ) ) )  474             return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );  475  }  476 
 477     if( m_dwCreationFlags & DSBCAPS_CTRLVOLUME )  478  {  479         pDSB->SetVolume( lVolume );  480  }  481 
 482     if( lFrequency != -1 && 
 483         (m_dwCreationFlags & DSBCAPS_CTRLFREQUENCY) )  484  {  485         pDSB->SetFrequency( lFrequency );  486  }  487     
 488     if( m_dwCreationFlags & DSBCAPS_CTRLPAN )  489  {  490         pDSB->SetPan( lPan );  491  }  492     
 493     return pDSB->Play( 0, dwPriority, dwFlags );  494 }  495 
 496 
 497 
 498 //-----------------------------------------------------------------------------  499 // Name: CSound::Stop()  500 // Desc: Stops the sound from playing  501 //-----------------------------------------------------------------------------
 502 HRESULT CSound::Stop()  503 {  504     if( m_apDSBuffer == NULL )  505         return CO_E_NOTINITIALIZED;  506 
 507     HRESULT hr = 0;  508 
 509     for( DWORD i=0; i<m_dwNumBuffers; i++ )  510         hr |= m_apDSBuffer[i]->Stop();  511 
 512     return hr;  513 }  514 
 515 
 516 
 517 
 518 //-----------------------------------------------------------------------------  519 // Name: CSound::Reset()  520 // Desc: Reset all of the sound buffers  521 //-----------------------------------------------------------------------------
 522 HRESULT CSound::Reset()  523 {  524     if( m_apDSBuffer == NULL )  525         return CO_E_NOTINITIALIZED;  526 
 527     HRESULT hr = 0;  528 
 529     for( DWORD i=0; i<m_dwNumBuffers; i++ )  530         hr |= m_apDSBuffer[i]->SetCurrentPosition( 0 );  531 
 532     return hr;  533 }  534 
 535 
 536 
 537 
 538 //-----------------------------------------------------------------------------  539 // Name: CSound::IsSoundPlaying()  540 // Desc: Checks to see if a buffer is playing and returns TRUE if it is.  541 //-----------------------------------------------------------------------------
 542 BOOL CSound::IsSoundPlaying()  543 {  544     BOOL bIsPlaying = FALSE;  545 
 546     if( m_apDSBuffer == NULL )  547         return FALSE;  548 
 549     for( DWORD i=0; i<m_dwNumBuffers; i++ )  550  {  551         if( m_apDSBuffer[i] )  552  {  553             DWORD dwStatus = 0;  554             m_apDSBuffer[i]->GetStatus( &dwStatus );  555             bIsPlaying |= ( ( dwStatus & DSBSTATUS_PLAYING ) != 0 );  556  }  557  }  558 
 559     return bIsPlaying;  560 }  561 
 562 
 563 
 564 //-----------------------------------------------------------------------------  565 // Name: CWaveFile::CWaveFile()  566 // Desc: Constructs the class. Call Open() to open a wave file for reading.  567 // Then call Read() as needed. Calling the destructor or Close()  568 // will close the file.  569 //-----------------------------------------------------------------------------
 570 CWaveFile::CWaveFile()  571 {  572     m_pwfx    = NULL;  573     m_hmmio   = NULL;  574     m_pResourceBuffer = NULL;  575     m_dwSize  = 0;  576     m_bIsReadingFromMemory = FALSE;  577 }  578 
 579 
 580 
 581 
 582 //-----------------------------------------------------------------------------  583 // Name: CWaveFile::~CWaveFile()  584 // Desc: Destructs the class  585 //-----------------------------------------------------------------------------
 586 CWaveFile::~CWaveFile()  587 {  588  Close();  589 
 590     if( !m_bIsReadingFromMemory )  591  SAFE_DELETE_ARRAY( m_pwfx );  592 }  593 
 594 
 595 
 596 
 597 //-----------------------------------------------------------------------------  598 // Name: CWaveFile::Open()  599 // Desc: Opens a wave file for reading  600 //-----------------------------------------------------------------------------
 601 HRESULT CWaveFile::Open( LPTSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags )  602 {  603  HRESULT hr;  604 
 605     m_dwFlags = dwFlags;  606     m_bIsReadingFromMemory = FALSE;  607 
 608     if( m_dwFlags == WAVEFILE_READ )  609  {  610         if( strFileName == NULL )  611             return E_INVALIDARG;  612  SAFE_DELETE_ARRAY( m_pwfx );  613 
 614         m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF | MMIO_READ );  615 
 616         if( NULL == m_hmmio )  617  {  618  HRSRC hResInfo;  619  HGLOBAL hResData;  620  DWORD dwSize;  621             VOID* pvRes;  622 
 623             // Loading it as a file failed, so try it as a resource
 624             if( NULL == ( hResInfo = FindResource( NULL, strFileName, TEXT("WAVE") ) ) )  625  {  626                 if( NULL == ( hResInfo = FindResource( NULL, strFileName, TEXT("WAV") ) ) )  627                     return DXTRACE_ERR( TEXT("FindResource"), E_FAIL );  628  }  629 
 630             if( NULL == ( hResData = LoadResource( NULL, hResInfo ) ) )  631                 return DXTRACE_ERR( TEXT("LoadResource"), E_FAIL );  632 
 633             if( 0 == ( dwSize = SizeofResource( NULL, hResInfo ) ) )  634                 return DXTRACE_ERR( TEXT("SizeofResource"), E_FAIL );  635 
 636             if( NULL == ( pvRes = LockResource( hResData ) ) )  637                 return DXTRACE_ERR( TEXT("LockResource"), E_FAIL );  638 
 639             m_pResourceBuffer = new CHAR[ dwSize ];  640  memcpy( m_pResourceBuffer, pvRes, dwSize );  641 
 642  MMIOINFO mmioInfo;  643             ZeroMemory( &mmioInfo, sizeof(mmioInfo) );  644             mmioInfo.fccIOProc = FOURCC_MEM;  645             mmioInfo.cchBuffer = dwSize;  646             mmioInfo.pchBuffer = (CHAR*) m_pResourceBuffer;  647 
 648             m_hmmio = mmioOpen( NULL, &mmioInfo, MMIO_ALLOCBUF | MMIO_READ );  649  }  650 
 651         if( FAILED( hr = ReadMMIO() ) )  652  {  653             // ReadMMIO will fail if its an not a wave file
 654             mmioClose( m_hmmio, 0 );  655             return DXTRACE_ERR( TEXT("ReadMMIO"), hr );  656  }  657 
 658         if( FAILED( hr = ResetFile() ) )  659             return DXTRACE_ERR( TEXT("ResetFile"), hr );  660 
 661         // After the reset, the size of the wav file is m_ck.cksize so store it now
 662         m_dwSize = m_ck.cksize;  663  }  664     else
 665  {  666         m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF  | 
 667                                                   MMIO_READWRITE | 
 668  MMIO_CREATE );  669         if( NULL == m_hmmio )  670             return DXTRACE_ERR( TEXT("mmioOpen"), E_FAIL );  671 
 672         if( FAILED( hr = WriteMMIO( pwfx ) ) )  673  {  674             mmioClose( m_hmmio, 0 );  675             return DXTRACE_ERR( TEXT("WriteMMIO"), hr );  676  }  677                         
 678         if( FAILED( hr = ResetFile() ) )  679             return DXTRACE_ERR( TEXT("ResetFile"), hr );  680  }  681 
 682     return hr;  683 }  684 
 685 
 686 
 687 //-----------------------------------------------------------------------------  688 // Name: CWaveFile::ReadMMIO()  689 // Desc: Support function for reading from a multimedia I/O stream.  690 // m_hmmio must be valid before calling. This function uses it to  691 // update m_ckRiff, and m_pwfx.  692 //-----------------------------------------------------------------------------
 693 HRESULT CWaveFile::ReadMMIO()  694 {  695     MMCKINFO        ckIn;           // chunk info. for general use.
 696     PCMWAVEFORMAT   pcmWaveFormat;  // Temp PCM structure to load in. 
 697 
 698     m_pwfx = NULL;  699 
 700     if( ( 0 != mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) ) )  701         return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );  702 
 703     // Check to make sure this is a valid wave file
 704     if( (m_ckRiff.ckid != FOURCC_RIFF) ||
 705         (m_ckRiff.fccType != mmioFOURCC('W', 'A', 'V', 'E') ) )  706         return DXTRACE_ERR( TEXT("mmioFOURCC"), E_FAIL );  707 
 708     // Search the input file for for the 'fmt ' chunk.
 709     ckIn.ckid = mmioFOURCC('f', 'm', 't', ' ');  710     if( 0 != mmioDescend( m_hmmio, &ckIn, &m_ckRiff, MMIO_FINDCHUNK ) )  711         return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );  712 
 713     // Expect the 'fmt' chunk to be at least as large as <PCMWAVEFORMAT>;  714     // if there are extra parameters at the end, we'll ignore them
 715        if( ckIn.cksize < (LONG) sizeof(PCMWAVEFORMAT) )  716            return DXTRACE_ERR( TEXT("sizeof(PCMWAVEFORMAT)"), E_FAIL );  717 
 718     // Read the 'fmt ' chunk into <pcmWaveFormat>.
 719     if( mmioRead( m_hmmio, (HPSTR) &pcmWaveFormat,  720                   sizeof(pcmWaveFormat)) != sizeof(pcmWaveFormat) )  721         return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );  722 
 723     // Allocate the waveformatex, but if its not pcm format, read the next  724     // word, and thats how many extra bytes to allocate.
 725     if( pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM )  726  {  727         m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) ];  728         if( NULL == m_pwfx )  729             return DXTRACE_ERR( TEXT("m_pwfx"), E_FAIL );  730 
 731         // Copy the bytes from the pcm structure to the waveformatex structure
 732         memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );  733         m_pwfx->cbSize = 0;  734  }  735     else
 736  {  737         // Read in length of extra bytes.
 738         WORD cbExtraBytes = 0L;  739         if( mmioRead( m_hmmio, (CHAR*)&cbExtraBytes, sizeof(WORD)) != sizeof(WORD) )  740             return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );  741 
 742         m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) + cbExtraBytes ];  743         if( NULL == m_pwfx )  744             return DXTRACE_ERR( TEXT("new"), E_FAIL );  745 
 746         // Copy the bytes from the pcm structure to the waveformatex structure
 747         memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );  748         m_pwfx->cbSize = cbExtraBytes;  749 
 750         // Now, read those extra bytes into the structure, if cbExtraAlloc != 0.
 751         if( mmioRead( m_hmmio, (CHAR*)(((BYTE*)&(m_pwfx->cbSize))+sizeof(WORD)),  752                       cbExtraBytes ) != cbExtraBytes )  753  {  754  SAFE_DELETE( m_pwfx );  755             return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );  756  }  757  }  758 
 759     // Ascend the input file out of the 'fmt ' chunk.
 760     if( 0 != mmioAscend( m_hmmio, &ckIn, 0 ) )  761  {  762  SAFE_DELETE( m_pwfx );  763         return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );  764  }  765 
 766     return S_OK;  767 }  768 
 769 
 770 
 771 
 772 //-----------------------------------------------------------------------------  773 // Name: CWaveFile::GetSize()  774 // Desc: Retuns the size of the read access wave file  775 //-----------------------------------------------------------------------------
 776 DWORD CWaveFile::GetSize()  777 {  778     return m_dwSize;  779 }  780 
 781 
 782 
 783 
 784 //-----------------------------------------------------------------------------  785 // Name: CWaveFile::ResetFile()  786 // Desc: Resets the internal m_ck pointer so reading starts from the  787 // beginning of the file again  788 //-----------------------------------------------------------------------------
 789 HRESULT CWaveFile::ResetFile()  790 {  791     if( m_bIsReadingFromMemory )  792  {  793         m_pbDataCur = m_pbData;  794  }  795     else 
 796  {  797         if( m_hmmio == NULL )  798             return CO_E_NOTINITIALIZED;  799 
 800         if( m_dwFlags == WAVEFILE_READ )  801  {  802             // Seek to the data
 803             if( -1 == mmioSeek( m_hmmio, m_ckRiff.dwDataOffset + sizeof(FOURCC),  804  SEEK_SET ) )  805                 return DXTRACE_ERR( TEXT("mmioSeek"), E_FAIL );  806 
 807             // Search the input file for the 'data' chunk.
 808             m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');  809             if( 0 != mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) )  810               return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );  811  }  812         else
 813  {  814             // Create the 'data' chunk that holds the waveform samples. 
 815             m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');  816             m_ck.cksize = 0;  817 
 818             if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) )  819                 return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );  820 
 821             if( 0 != mmioGetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )  822                 return DXTRACE_ERR( TEXT("mmioGetInfo"), E_FAIL );  823  }  824  }  825     
 826     return S_OK;  827 }  828 
 829 
 830 
 831 
 832 //-----------------------------------------------------------------------------  833 // Name: CWaveFile::Read()  834 // Desc: Reads section of data from a wave file into pBuffer and returns  835 // how much read in pdwSizeRead, reading not more than dwSizeToRead.  836 // This uses m_ck to determine where to start reading from. So  837 // subsequent calls will be continue where the last left off unless  838 // Reset() is called.  839 //-----------------------------------------------------------------------------
 840 HRESULT CWaveFile::Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead )  841 {  842     if( m_bIsReadingFromMemory )  843  {  844         if( m_pbDataCur == NULL )  845             return CO_E_NOTINITIALIZED;  846         if( pdwSizeRead != NULL )  847             *pdwSizeRead = 0;  848 
 849         if( (BYTE*)(m_pbDataCur + dwSizeToRead) > 
 850             (BYTE*)(m_pbData + m_ulDataSize) )  851  {  852             dwSizeToRead = m_ulDataSize - (DWORD)(m_pbDataCur - m_pbData);  853  }  854         
 855  CopyMemory( pBuffer, m_pbDataCur, dwSizeToRead );  856         
 857         if( pdwSizeRead != NULL )  858             *pdwSizeRead = dwSizeToRead;  859 
 860         return S_OK;  861  }  862     else 
 863  {  864         MMIOINFO mmioinfoIn; // current status of m_hmmio
 865 
 866         if( m_hmmio == NULL )  867             return CO_E_NOTINITIALIZED;  868         if( pBuffer == NULL || pdwSizeRead == NULL )  869             return E_INVALIDARG;  870 
 871         if( pdwSizeRead != NULL )  872             *pdwSizeRead = 0;  873 
 874         if( 0 != mmioGetInfo( m_hmmio, &mmioinfoIn, 0 ) )  875             return DXTRACE_ERR( TEXT("mmioGetInfo"), E_FAIL );  876                 
 877         UINT cbDataIn = dwSizeToRead;  878         if( cbDataIn > m_ck.cksize )  879             cbDataIn = m_ck.cksize;  880 
 881         m_ck.cksize -= cbDataIn;  882     
 883         for( DWORD cT = 0; cT < cbDataIn; cT++ )  884  {  885             // Copy the bytes from the io to the buffer.
 886             if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )  887  {  888                 if( 0 != mmioAdvance( m_hmmio, &mmioinfoIn, MMIO_READ ) )  889                     return DXTRACE_ERR( TEXT("mmioAdvance"), E_FAIL );  890 
 891                 if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )  892                     return DXTRACE_ERR( TEXT("mmioinfoIn.pchNext"), E_FAIL );  893  }  894 
 895             // Actual copy.
 896             *((BYTE*)pBuffer+cT) = *((BYTE*)mmioinfoIn.pchNext);  897             mmioinfoIn.pchNext++;  898  }  899 
 900         if( 0 != mmioSetInfo( m_hmmio, &mmioinfoIn, 0 ) )  901             return DXTRACE_ERR( TEXT("mmioSetInfo"), E_FAIL );  902 
 903         if( pdwSizeRead != NULL )  904             *pdwSizeRead = cbDataIn;  905 
 906         return S_OK;  907  }  908 }  909 
 910 
 911 
 912 
 913 //-----------------------------------------------------------------------------  914 // Name: CWaveFile::Close()  915 // Desc: Closes the wave file  916 //-----------------------------------------------------------------------------
 917 HRESULT CWaveFile::Close()  918 {  919     if( m_dwFlags == WAVEFILE_READ )  920  {  921         mmioClose( m_hmmio, 0 );  922         m_hmmio = NULL;  923  SAFE_DELETE_ARRAY( m_pResourceBuffer );  924  }  925     else
 926  {  927         m_mmioinfoOut.dwFlags |= MMIO_DIRTY;  928 
 929         if( m_hmmio == NULL )  930             return CO_E_NOTINITIALIZED;  931 
 932         if( 0 != mmioSetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )  933             return DXTRACE_ERR( TEXT("mmioSetInfo"), E_FAIL );  934     
 935         // Ascend the output file out of the 'data' chunk -- this will cause  936         // the chunk size of the 'data' chunk to be written.
 937         if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )  938             return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );  939     
 940         // Do this here instead...
 941         if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )  942             return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );  943         
 944         mmioSeek( m_hmmio, 0, SEEK_SET );  945 
 946         if( 0 != (INT)mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) )  947             return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );  948     
 949         m_ck.ckid = mmioFOURCC('f', 'a', 'c', 't');  950 
 951         if( 0 == mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) )  952  {  953             DWORD dwSamples = 0;  954             mmioWrite( m_hmmio, (HPSTR)&dwSamples, sizeof(DWORD) );  955             mmioAscend( m_hmmio, &m_ck, 0 );  956  }  957     
 958         // Ascend the output file out of the 'RIFF' chunk -- this will cause  959         // the chunk size of the 'RIFF' chunk to be written.
 960         if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )  961             return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );  962     
 963         mmioClose( m_hmmio, 0 );  964         m_hmmio = NULL;  965  }  966 
 967     return S_OK;  968 }  969 
 970 
 971 
 972 
 973 //-----------------------------------------------------------------------------  974 // Name: CWaveFile::WriteMMIO()  975 // Desc: Support function for reading from a multimedia I/O stream  976 // pwfxDest is the WAVEFORMATEX for this new wave file.  977 // m_hmmio must be valid before calling. This function uses it to  978 // update m_ckRiff, and m_ck.  979 //-----------------------------------------------------------------------------
 980 HRESULT CWaveFile::WriteMMIO( WAVEFORMATEX *pwfxDest )  981 {  982     DWORD    dwFactChunk; // Contains the actual fact chunk. Garbage until WaveCloseWriteFile.
 983  MMCKINFO ckOut1;  984     
 985     dwFactChunk = (DWORD)-1;  986 
 987     // Create the output file RIFF chunk of form type 'WAVE'.
 988     m_ckRiff.fccType = mmioFOURCC('W', 'A', 'V', 'E');  989     m_ckRiff.cksize = 0;  990 
 991     if( 0 != mmioCreateChunk( m_hmmio, &m_ckRiff, MMIO_CREATERIFF ) )  992         return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );  993     
 994     // We are now descended into the 'RIFF' chunk we just created.  995     // Now create the 'fmt ' chunk. Since we know the size of this chunk,  996     // specify it in the MMCKINFO structure so MMIO doesn't have to seek  997     // back and set the chunk size after ascending from the chunk.
 998     m_ck.ckid = mmioFOURCC('f', 'm', 't', ' ');  999     m_ck.cksize = sizeof(PCMWAVEFORMAT); 1000 
1001     if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) ) 1002         return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL ); 1003     
1004     // Write the PCMWAVEFORMAT structure to the 'fmt ' chunk if its that type. 
1005     if( pwfxDest->wFormatTag == WAVE_FORMAT_PCM ) 1006  { 1007         if( mmioWrite( m_hmmio, (HPSTR) pwfxDest, 1008                        sizeof(PCMWAVEFORMAT)) != sizeof(PCMWAVEFORMAT)) 1009             return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL ); 1010  } 1011     else 
1012  { 1013         // Write the variable length size.
1014         if( (UINT)mmioWrite( m_hmmio, (HPSTR) pwfxDest, 1015                              sizeof(*pwfxDest) + pwfxDest->cbSize ) != 
1016                              ( sizeof(*pwfxDest) + pwfxDest->cbSize ) ) 1017             return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL ); 1018  } 1019     
1020     // Ascend out of the 'fmt ' chunk, back into the 'RIFF' chunk.
1021     if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) ) 1022         return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL ); 1023     
1024     // Now create the fact chunk, not required for PCM but nice to have. This is filled 1025     // in when the close routine is called.
1026     ckOut1.ckid = mmioFOURCC('f', 'a', 'c', 't'); 1027     ckOut1.cksize = 0; 1028 
1029     if( 0 != mmioCreateChunk( m_hmmio, &ckOut1, 0 ) ) 1030         return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL ); 1031     
1032     if( mmioWrite( m_hmmio, (HPSTR)&dwFactChunk, sizeof(dwFactChunk)) != 
1033                     sizeof(dwFactChunk) ) 1034          return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL ); 1035     
1036     // Now ascend out of the fact chunk...
1037     if( 0 != mmioAscend( m_hmmio, &ckOut1, 0 ) ) 1038         return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL ); 1039        
1040     return S_OK; 1041 } 1042 
1043 
1044 
1045 
1046 //----------------------------------------------------------------------------- 1047 // Name: CWaveFile::Write() 1048 // Desc: Writes data to the open wave file 1049 //-----------------------------------------------------------------------------
1050 HRESULT CWaveFile::Write( UINT nSizeToWrite, BYTE* pbSrcData, UINT* pnSizeWrote ) 1051 { 1052  UINT cT; 1053 
1054     if( m_bIsReadingFromMemory ) 1055         return E_NOTIMPL; 1056     if( m_hmmio == NULL ) 1057         return CO_E_NOTINITIALIZED; 1058     if( pnSizeWrote == NULL || pbSrcData == NULL ) 1059         return E_INVALIDARG; 1060 
1061     *pnSizeWrote = 0; 1062     
1063     for( cT = 0; cT < nSizeToWrite; cT++ ) 1064  { 1065         if( m_mmioinfoOut.pchNext == m_mmioinfoOut.pchEndWrite ) 1066  { 1067             m_mmioinfoOut.dwFlags |= MMIO_DIRTY; 1068             if( 0 != mmioAdvance( m_hmmio, &m_mmioinfoOut, MMIO_WRITE ) ) 1069                 return DXTRACE_ERR( TEXT("mmioAdvance"), E_FAIL ); 1070  } 1071 
1072         *((BYTE*)m_mmioinfoOut.pchNext) = *((BYTE*)pbSrcData+cT); 1073         (BYTE*)m_mmioinfoOut.pchNext++; 1074 
1075         (*pnSizeWrote)++; 1076  } 1077 
1078     return S_OK; 1079 }

 

然后是我们自己的文件,先看到头文件DirectX.h,加入了新的支持声音播放的函数

View Code
 1 #pragma once
 2 
 3 //header files
 4 #define WIN32_EXTRA_LEAN
 5 #define DIRECTINPUT_VERSION 0x0800
 6 #include <windows.h>
 7 #include <d3d9.h>
 8 #include <d3dx9.h>
 9 #include <dxerr.h>
 10 #include <dinput.h>
 11 #include <xinput.h>
 12 #include <ctime>
 13 #include <iostream>
 14 #include <iomanip>
 15 #include "DirectSound.h"
 16 using namespace std;  17 
 18 //libraries
 19 #pragma comment(lib,"winmm.lib")
 20 #pragma comment(lib,"user32.lib")
 21 #pragma comment(lib,"gdi32.lib")
 22 #pragma comment(lib,"dxguid.lib")
 23 #pragma comment(lib,"d3d9.lib")
 24 #pragma comment(lib,"d3dx9.lib")
 25 #pragma comment(lib, "dxerr.lib")
 26 #pragma comment(lib,"dinput8.lib")
 27 #pragma comment(lib,"xinput.lib")
 28 
 29 //program values
 30 extern const string APPTITLE;  31 extern const int SCREENW;  32 extern const int SCREENH;  33 extern bool gameover;  34 
 35 //macro to detect key presses
 36 #define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
 37 
 38 //Direct3D objects
 39 extern LPDIRECT3D9 d3d;  40 extern LPDIRECT3DDEVICE9 d3ddev;  41 extern LPDIRECT3DSURFACE9 backbuffer;  42 extern LPD3DXSPRITE spriteobj;  43 
 44 //DirectSound object
 45 extern CSoundManager *dsound;  46 
 47 //sprite structure
 48 struct SPRITE  49 {  50     float x,y;  51     int frame, columns;  52     int width, height;  53     float scaling, rotation;  54     int startframe, endframe;  55     int starttime, delay;  56     int direction;  57     float velx, vely;  58  D3DCOLOR color;  59 
 60  SPRITE()  61  {  62         frame = 0;  63         columns = 1;  64         width = height = 0;  65         scaling = 1.0f;  66         rotation = 0.0f;  67         startframe = endframe = 0;  68         direction = 1;  69         starttime = delay = 0;  70         velx = vely = 0.0f;  71         color = D3DCOLOR_XRGB(255,255,255);  72  }  73 };  74 
 75 //Direct3D functions
 76 bool Direct3D_Init(HWND hwnd, int width, int height, bool fullscreen);  77 void Direct3D_Shutdown();  78 LPDIRECT3DSURFACE9 LoadSurface(string filename);  79 void DrawSurface(LPDIRECT3DSURFACE9 dest, float x, float y, LPDIRECT3DSURFACE9 source);  80 LPDIRECT3DTEXTURE9 LoadTexture(string filename, D3DCOLOR transcolor = D3DCOLOR_XRGB(0,0,0));  81 void Sprite_Draw_Frame(LPDIRECT3DTEXTURE9 texture, int destx, int desty,  82     int framenum, int framew, int frameh, int columns);  83 void Sprite_Animate(int &frame, int startframe, int endframe, int direction, int &starttime, int delay);  84 
 85 void Sprite_Transform_Draw(LPDIRECT3DTEXTURE9 image, int x, int y, int width, int height,  86     int frame = 0, int columns = 1, float rotation = 0.0f, float scaling = 1.0f,  87     D3DCOLOR color = D3DCOLOR_XRGB(255,255,255));  88 
 89 //bounding box collision detection
 90 int Collision(SPRITE sprite1, SPRITE sprite2);  91 
 92 //distance based collision detection
 93 bool CollisionD(SPRITE sprite1, SPRITE sprite2);  94 
 95 //DirectInput objects, devices, and states
 96 extern LPDIRECTINPUT8 dinput;  97 extern LPDIRECTINPUTDEVICE8 dimouse;  98 extern LPDIRECTINPUTDEVICE8 dikeyboard;  99 extern DIMOUSESTATE mouse_state; 100 extern XINPUT_GAMEPAD controllers[4]; 101 
102 //DirectInput functions
103 bool DirectInput_Init(HWND); 104 void DirectInput_Update(); 105 void DirectInput_Shutdown(); 106 bool Key_Down(int); 107 int Mouse_Button(int); 108 int Mouse_X(); 109 int Mouse_Y(); 110 void XInput_Vibrate(int contNum = 0, int amount = 65535); 111 bool XInput_Controller_Found(); 112 
113 //game functions
114 bool Game_Init(HWND window); 115 void Game_Run(HWND window); 116 void Game_End(); 117 
118 
119 //font functions
120 LPD3DXFONT MakeFont(string name, int size); 121 void FontPrint(LPD3DXFONT font, int x, int y, string text, D3DCOLOR color = D3DCOLOR_XRGB(255,255,255)); 122 
123 //DirectSound functions
124 bool DirectSound_Init(HWND hwnd); 125 void DirectSound_Shutdown(); 126 CSound* LoadSound(string filename); 127 void PlaySound(CSound *sound); 128 void LoopSound(CSound *sound); 129 void StopSound(CSound *sound);

 

 接着是DirectX.cpp文件,先看看前面的一部分,和之前的一样

View Code
 1 #include "DirectX.h"
 2 #include <iostream>
 3 #include <string>
 4 using namespace std;  5 
 6 //DirectSound object
 7 CSoundManager *dsound = NULL;  8 
 9 //Direct3D variables
 10 LPDIRECT3D9 d3d = NULL;  11 LPDIRECT3DDEVICE9 d3ddev = NULL;  12 LPDIRECT3DSURFACE9 backbuffer = NULL;  13 LPD3DXSPRITE spriteobj;  14 
 15 //DirectInput variables
 16 LPDIRECTINPUT8 dinput = NULL;  17 LPDIRECTINPUTDEVICE8 dimouse = NULL;  18 LPDIRECTINPUTDEVICE8 dikeyboard = NULL;  19 DIMOUSESTATE mouse_state;  20 char keys[256];  21 XINPUT_GAMEPAD controllers[4];  22 
 23 
 24 bool Direct3D_Init(HWND window, int width, int height, bool fullscreen)  25 {  26     //initialize Direct3D
 27     d3d = Direct3DCreate9(D3D_SDK_VERSION);  28     if (!d3d) return false;  29 
 30     //set Direct3D presentation parameters
 31  D3DPRESENT_PARAMETERS d3dpp;  32     ZeroMemory(&d3dpp, sizeof(d3dpp));  33     d3dpp.hDeviceWindow = window;  34     d3dpp.Windowed = (!fullscreen);  35     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;  36     d3dpp.EnableAutoDepthStencil = 1;  37     d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;  38     d3dpp.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;  39     d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;  40     d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;  41     d3dpp.BackBufferCount = 1;  42     d3dpp.BackBufferWidth = width;  43     d3dpp.BackBufferHeight = height;  44 
 45     //create Direct3D device
 46     d3d->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window,  47         D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev);  48     if (!d3ddev) return false;  49 
 50 
 51     //get a pointer to the back buffer surface
 52     d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);  53 
 54     //create sprite object
 55     D3DXCreateSprite(d3ddev, &spriteobj);  56 
 57     return 1;  58 }  59 
 60 void Direct3D_Shutdown()  61 {  62     if (spriteobj) spriteobj->Release();  63 
 64     if (d3ddev) d3ddev->Release();  65     if (d3d) d3d->Release();  66 }  67 
 68 void DrawSurface(LPDIRECT3DSURFACE9 dest, float x, float y, LPDIRECT3DSURFACE9 source)  69 {  70     //get width/height from source surface
 71  D3DSURFACE_DESC desc;  72     source->GetDesc(&desc);  73 
 74     //create rects for drawing
 75     RECT source_rect = {0, 0, (long)desc.Width, (long)desc.Height };  76     RECT dest_rect = { (long)x, (long)y, (long)x+desc.Width, (long)y+desc.Height};  77     
 78     //draw the source surface onto the dest
 79     d3ddev->StretchRect(source, &source_rect, dest, &dest_rect, D3DTEXF_NONE);  80 
 81 }  82 
 83 LPDIRECT3DSURFACE9 LoadSurface(string filename)  84 {  85     LPDIRECT3DSURFACE9 image = NULL;  86     
 87     //get width and height from bitmap file
 88  D3DXIMAGE_INFO info;  89     HRESULT result = D3DXGetImageInfoFromFile(filename.c_str(), &info);  90     if (result != D3D_OK)  91         return NULL;  92 
 93     //create surface
 94     result = d3ddev->CreateOffscreenPlainSurface(  95         info.Width,         //width of the surface
 96         info.Height,        //height of the surface
 97         D3DFMT_X8R8G8B8,    //surface format
 98         D3DPOOL_DEFAULT,    //memory pool to use
 99         &image,             //pointer to the surface
100         NULL);              //reserved (always NULL)
101 
102     if (result != D3D_OK) return NULL; 103 
104     //load surface from file into newly created surface
105     result = D3DXLoadSurfaceFromFile( 106         image,                  //destination surface
107         NULL,                   //destination palette
108         NULL,                   //destination rectangle
109         filename.c_str(),       //source filename
110         NULL,                   //source rectangle
111         D3DX_DEFAULT,           //controls how image is filtered
112         D3DCOLOR_XRGB(0,0,0),   //for transparency (0 for none)
113         NULL);                  //source image info (usually NULL) 114 
115     //make sure file was loaded okay
116     if (result != D3D_OK) return NULL; 117 
118     return image; 119 } 120 
121 
122 LPDIRECT3DTEXTURE9 LoadTexture(std::string filename, D3DCOLOR transcolor) 123 { 124     LPDIRECT3DTEXTURE9 texture = NULL; 125 
126     //get width and height from bitmap file
127  D3DXIMAGE_INFO info; 128     HRESULT result = D3DXGetImageInfoFromFile(filename.c_str(), &info); 129     if (result != D3D_OK) return NULL; 130 
131     //create the new texture by loading a bitmap image file
132  D3DXCreateTextureFromFileEx( 133         d3ddev,                //Direct3D device object
134         filename.c_str(),      //bitmap filename
135         info.Width,            //bitmap image width
136         info.Height,           //bitmap image height
137         1,                     //mip-map levels (1 for no chain)
138         D3DPOOL_DEFAULT,       //the type of surface (standard)
139         D3DFMT_UNKNOWN,        //surface format (default)
140         D3DPOOL_DEFAULT,       //memory class for the texture
141         D3DX_DEFAULT,          //image filter
142         D3DX_DEFAULT,          //mip filter
143         transcolor,            //color key for transparency
144         &info,                 //bitmap file info (from loaded file)
145         NULL,                  //color palette
146         &texture );            //destination texture 147 
148     //make sure the bitmap textre was loaded correctly
149     if (result != D3D_OK) return NULL; 150 
151     return texture; 152 } 153 
154 
155 void Sprite_Draw_Frame(LPDIRECT3DTEXTURE9 texture, int destx, int desty, int framenum, int framew, int frameh, int columns) 156 { 157     D3DXVECTOR3 position( (float)destx, (float)desty, 0 ); 158     D3DCOLOR white = D3DCOLOR_XRGB(255,255,255); 159 
160  RECT rect; 161      rect.left = (framenum % columns) * framew; 162     rect.top = (framenum / columns) * frameh; 163     rect.right = rect.left + framew; 164     rect.bottom = rect.top + frameh; 165 
166     spriteobj->Draw( texture, &rect, NULL, &position, white); 167 } 168 
169 void Sprite_Animate(int &frame, int startframe, int endframe, int direction, int &starttime, int delay) 170 { 171     if ((int)GetTickCount() > starttime + delay) 172  { 173         starttime = GetTickCount(); 174 
175         frame += direction; 176         if (frame > endframe) frame = startframe; 177         if (frame < startframe) frame = endframe; 178  } 179 } 180 void Sprite_Transform_Draw(LPDIRECT3DTEXTURE9 image, int x, int y, int width, int height, 181     int frame, int columns, float rotation, float scaling, D3DCOLOR color) 182 { 183     //create a scale vector
184  D3DXVECTOR2 scale( scaling, scaling ); 185 
186     //create a translate vector
187  D3DXVECTOR2 trans( x, y ); 188 
189     //set center by dividing width and height by two
190     D3DXVECTOR2 center( (float)( width * scaling )/2, (float)( height * scaling )/2); 191 
192     //create 2D transformation matrix
193  D3DXMATRIX mat; 194     D3DXMatrixTransformation2D( &mat, NULL, 0, &scale, &center, rotation, &trans ); 195     
196     //tell sprite object to use the transform
197     spriteobj->SetTransform( &mat ); 198 
199     //calculate frame location in source image
200     int fx = (frame % columns) * width; 201     int fy = (frame / columns) * height; 202     RECT srcRect = {fx, fy, fx + width, fy + height}; 203 
204     //draw the sprite frame
205     spriteobj->Draw( image, &srcRect, NULL, NULL, color ); 206 } 207 
208 //bounding box collision detection
209 int Collision(SPRITE sprite1, SPRITE sprite2) 210 { 211  RECT rect1; 212     rect1.left = (long)sprite1.x; 213     rect1.top = (long)sprite1.y; 214     rect1.right = (long)sprite1.x + sprite1.width * sprite1.scaling; 215     rect1.bottom = (long)sprite1.y + sprite1.height * sprite1.scaling; 216 
217  RECT rect2; 218     rect2.left = (long)sprite2.x; 219     rect2.top = (long)sprite2.y; 220     rect2.right = (long)sprite2.x + sprite2.width * sprite2.scaling; 221     rect2.bottom = (long)sprite2.y + sprite2.height * sprite2.scaling; 222 
223     RECT dest; //ignored
224     return IntersectRect(&dest, &rect1, &rect2); 225 } 226 
227 
228 bool CollisionD(SPRITE sprite1, SPRITE sprite2) 229 { 230     double radius1, radius2; 231 
232     //calculate radius 1
233     if (sprite1.width > sprite1.height) 234         radius1 = (sprite1.width * sprite1.scaling) / 2.0; 235     else
236         radius1 = (sprite1.height * sprite1.scaling) / 2.0; 237 
238     //center point 1
239     double x1 = sprite1.x + radius1; 240     double y1 = sprite1.y + radius1; 241  D3DXVECTOR2 vector1(x1, y1); 242 
243     //calculate radius 2
244     if (sprite2.width > sprite2.height) 245         radius2 = (sprite2.width * sprite2.scaling) / 2.0; 246     else
247         radius2 = (sprite2.height * sprite2.scaling) / 2.0; 248 
249     //center point 2
250     double x2 = sprite2.x + radius2; 251     double y2 = sprite2.y + radius2; 252  D3DXVECTOR2 vector2(x2, y2); 253 
254     //calculate distance
255     double deltax = vector1.x - vector2.x; 256     double deltay = vector2.y - vector1.y; 257     double dist = sqrt((deltax * deltax) + (deltay * deltay)); 258 
259     //return distance comparison
260     return (dist < radius1 + radius2); 261 } 262 
263 bool DirectInput_Init(HWND hwnd) 264 { 265     //initialize DirectInput object
266  DirectInput8Create( 267  GetModuleHandle(NULL), 268  DIRECTINPUT_VERSION, 269  IID_IDirectInput8, 270         (void**)&dinput, 271  NULL); 272 
273     //initialize the keyboard
274     dinput->CreateDevice(GUID_SysKeyboard, &dikeyboard, NULL); 275     dikeyboard->SetDataFormat(&c_dfDIKeyboard); 276     dikeyboard->SetCooperativeLevel(hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND); 277     dikeyboard->Acquire(); 278 
279     //initialize the mouse
280     dinput->CreateDevice(GUID_SysMouse, &dimouse, NULL); 281     dimouse->SetDataFormat(&c_dfDIMouse); 282     dimouse->SetCooperativeLevel(hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND); 283     dimouse->Acquire(); 284     d3ddev->ShowCursor(false); 285 
286     return true; 287 } 288 
289 void DirectInput_Update() 290 { 291     //update mouse
292     dimouse->Poll(); 293     if (!SUCCEEDED(dimouse->GetDeviceState(sizeof(DIMOUSESTATE),&mouse_state))) 294  { 295         //mouse device lose, try to re-acquire
296         dimouse->Acquire(); 297  } 298 
299     //update keyboard
300     dikeyboard->Poll(); 301     if (!SUCCEEDED(dikeyboard->GetDeviceState(256,(LPVOID)&keys))) 302  { 303         //keyboard device lost, try to re-acquire
304         dikeyboard->Acquire(); 305  } 306 
307     //update controllers
308     for (int i=0; i< 4; i++ ) 309  { 310         ZeroMemory( &controllers[i], sizeof(XINPUT_STATE) ); 311 
312         //get the state of the controller
313  XINPUT_STATE state; 314         DWORD result = XInputGetState( i, &state ); 315 
316         //store state in global controllers array
317         if (result == 0) controllers[i] = state.Gamepad; 318  } 319 } 320 
321 
322 int Mouse_X() 323 { 324     return mouse_state.lX; 325 } 326 
327 int Mouse_Y() 328 { 329     return mouse_state.lY; 330 } 331 
332 int Mouse_Button(int button) 333 { 334     return mouse_state.rgbButtons[button] & 0x80; 335 } 336 
337 bool Key_Down(int key) 338 { 339     return (bool)(keys[key] & 0x80); 340 } 341 
342 
343 void DirectInput_Shutdown() 344 { 345     if (dikeyboard) 346  { 347         dikeyboard->Unacquire(); 348         dikeyboard->Release(); 349         dikeyboard = NULL; 350  } 351     if (dimouse) 352  { 353         dimouse->Unacquire(); 354         dimouse->Release(); 355         dimouse = NULL; 356  } 357 } 358 
359 bool XInput_Controller_Found() 360 { 361  XINPUT_CAPABILITIES caps; 362     ZeroMemory(&caps, sizeof(XINPUT_CAPABILITIES)); 363     XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps); 364     if (caps.Type != 0) return false; 365     
366     return true; 367 } 368 
369 void XInput_Vibrate(int contNum, int amount) 370 { 371  XINPUT_VIBRATION vibration; 372     ZeroMemory( &vibration, sizeof(XINPUT_VIBRATION) ); 373     vibration.wLeftMotorSpeed = amount; 374     vibration.wRightMotorSpeed = amount; 375     XInputSetState( contNum, &vibration ); 376 } 377 
378 LPD3DXFONT MakeFont(string name, int size) 379 { 380     LPD3DXFONT font = NULL; 381 
382     D3DXFONT_DESC desc = { 383         size,                   //height
384         0,                      //width
385         0,                      //weight
386         0,                      //miplevels
387         false,                  //italic
388         DEFAULT_CHARSET,        //charset
389         OUT_TT_PRECIS,          //output precision
390         CLIP_DEFAULT_PRECIS,    //quality
391         DEFAULT_PITCH,          //pitch and family
392         ""                      //font name
393  }; 394 
395  strcpy(desc.FaceName, name.c_str()); 396 
397     D3DXCreateFontIndirect(d3ddev, &desc, &font); 398 
399     return font; 400 } 401 
402 void FontPrint(LPD3DXFONT font, int x, int y, string text, D3DCOLOR color) 403 { 404     //figure out the text boundary
405     RECT rect = { x, y, 0, 0 }; 406     font->DrawText( NULL, text.c_str(), text.length(), &rect, DT_CALCRECT, color); 407 
408     //print the text
409     font->DrawText(spriteobj, text.c_str(), text.length(), &rect, DT_LEFT, color); 410 }

 

下面是一些DirectSound方面的函数实现。在DirectSound_Init中,用类CSoundManager创建了DirectSound对象dsound,接着调用dsound->Initialize来初始化dsound,最后要设置音频缓冲区的格式dsound->SetPrimaryBufferFormat。

 1 bool DirectSound_Init(HWND hwnd)  2 {  3     //create DirectSound manager object
 4     dsound = new CSoundManager();  5 
 6     //initialize DirectSound
 7  HRESULT result;  8     result = dsound->Initialize(hwnd, DSSCL_PRIORITY);  9     if (FAILED(result)) 10         return false; 11 
12     //set the primary buffer format
13     result = dsound->SetPrimaryBufferFormat(2, 22050, 16); 14     if (FAILED(result)) 15         return false; 16 
17     return true; 18 } 19 
20 void DirectSound_Shutdown() 21 { 22     if (dsound) 23  delete dsound; 24 } 25 
26 CSound* LoadSound(string filename) 27 { 28  HRESULT result; 29 
30     //create local reference to wave data
31     CSound *wave = NULL; 32 
33     //attempt to load the wave file
34     char s[255]; 35     sprintf(s, "%s", filename.c_str()); 36     result = dsound->Create(&wave, s); 37     if (FAILED(result)) 38         wave = NULL; 39 
40     return wave; 41 } 42 
43 void PlaySound(CSound *sound) 44 { 45     sound->Play(); 46 } 47 
48 void LoopSound(CSound *sound) 49 { 50     sound->Play(0, DSBPLAY_LOOPING); 51 } 52 
53 void StopSound(CSound *sound) 54 { 55     sound->Stop(); 56 }

 

main.cpp文件依然没什么改变

View Code
 1 #include "DirectX.h"
 2 using namespace std;  3 
 4 bool gameover = false;  5 
 6 //windows event handling function
 7 LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)  8 {  9     switch (message) 10  { 11     case WM_DESTROY: 12         gameover = true; 13         PostQuitMessage(0); 14         return 0; 15  } 16 
17     return DefWindowProc(hwnd, message, wParam, lParam); 18 } 19 
20 
21 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPSTR lpCmdLine, int nCmdShow) 22 { 23     //set the windows properties
24  WNDCLASSEX wc; 25     wc.cbSize = sizeof(WNDCLASSEX); 26     wc.style = CS_HREDRAW | CS_VREDRAW; 27     wc.lpfnWndProc = (WNDPROC)WinProc; 28     wc.cbClsExtra = 0; 29     wc.cbWndExtra = 0; 30     wc.hInstance = hInstance; 31     wc.hIcon = NULL; 32     wc.hCursor = LoadCursor(NULL, IDC_ARROW); 33     wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 34     wc.lpszMenuName = NULL; 35     wc.lpszClassName = APPTITLE.c_str(); 36     wc.hIconSm = NULL; 37     RegisterClassEx(&wc); 38 
39     //determine the resolution of the clients desktop screen
40     int screenWidth = GetSystemMetrics(SM_CXSCREEN); 41     int screenHeight = GetSystemMetrics(SM_CYSCREEN); 42 
43     //place the window in the middle of screen
44     int posX = (GetSystemMetrics(SM_CXSCREEN) - SCREENW) / 2; 45     int posY = (GetSystemMetrics(SM_CYSCREEN) - SCREENH) / 2; 46 
47     //Create a window
48  HWND window; 49     window = CreateWindow(APPTITLE.c_str(), APPTITLE.c_str(), 50         WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU, posX, posY, SCREENW, SCREENH, 51  NULL, NULL, hInstance, NULL); 52     if (window == 0) 53         return false; 54 
55     //display the window
56  ShowWindow(window, nCmdShow); 57  UpdateWindow(window); 58 
59     //initialize the game
60     if (!Game_Init(window)) 61         return 0; 62 
63     //main message loop
64  MSG msg; 65     while (!gameover) 66  { 67         //process windows events
68         if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 69  { 70             //handle any event messages
71             TranslateMessage(&msg); 72             DispatchMessage(&msg); 73  } 74 
75         //process game loop
76  Game_Run(window); 77  } 78 
79     //free game resources
80  Game_End(); 81 
82     return msg.wParam; 83 }

 

game.cpp文件如下,先看开头部分。这里定义了3张图片,ball_image、bumper_image、background,待会儿要实现一个简单的碰撞模拟。ball_image代表移动的小球,bumper_image代表缓冲器转置,如小球撞上了缓冲器装置就会发出声音,小球会简单的反弹。

 1 #include "DirectX.h"
 2 using namespace std;  3 
 4 const string APPTITLE = "Play Sound Demo";  5 const int SCREENW = 1024;  6 const int SCREENH = 576;  7 
 8 LPDIRECT3DTEXTURE9 ball_image = NULL;  9 LPDIRECT3DTEXTURE9 bumper_image = NULL; 10 LPDIRECT3DTEXTURE9 background = NULL; 11 
12 //balls
13 const int NUMBALLS = 10; 14 SPRITE balls[NUMBALLS]; 15 
16 //bumpers
17 const int NUMBUMPERS = 3; 18 SPRITE bumpers[NUMBUMPERS]; 19 
20 //timing variable
21 DWORD screentimer = timeGetTime(); 22 DWORD coretimer = timeGetTime(); 23 DWORD bumpertimer = timeGetTime(); 24 
25 //the wave sound
26 CSound *sound_bounce = NULL;

 

下面的Game_Init函数先用DirectSound_Init初始化了DirectSound,然后加载3张图片。接着用随机数设置小球出现的位置与初始速度,而3个缓冲器的位置是固定的,参数velx、vely决定了小球的速度。

 1 bool Game_Init(HWND window)  2 {  3  srand(time(NULL));  4 
 5     //initialize Direct3D
 6     if (!Direct3D_Init(window, SCREENW, SCREENH, false))  7  {  8         MessageBox(window,"Error initializing Direct3D",APPTITLE.c_str(),0);  9         return false; 10  } 11 
12     //initialize DirectInput
13     if (!DirectInput_Init(window)) 14  { 15         MessageBox(window,"Error initializing DirectInput",APPTITLE.c_str(),0); 16         return false; 17  } 18 
19     //initialize DirectSound
20     if (!DirectSound_Init(window)) 21  { 22         MessageBox(window,"Error initializing DirectSound",APPTITLE.c_str(),0); 23         return false; 24  } 25 
26 
27     //load the background image
28     background = LoadTexture("craters.tga"); 29     if (!background) 30  { 31         MessageBox(window,"Error loading craters.tga",APPTITLE.c_str(),0); 32         return false; 33  } 34 
35     //load the ball image
36     ball_image = LoadTexture("lightningball.tga"); 37     if (!ball_image) 38  { 39         MessageBox(window,"Error loading lightningball.tga",APPTITLE.c_str(),0); 40         return false; 41  } 42 
43     //load the bumper image
44     bumper_image = LoadTexture("bumper.tga"); 45     if (!ball_image) 46  { 47         MessageBox(window,"Error loading bumper.tga",APPTITLE.c_str(),0); 48         return false; 49  } 50 
51     //set the balls' properties
52     for (int n=0; n<NUMBALLS; n++) 53  { 54         balls[n].x = (float)(rand() % (SCREENW-200)); 55         balls[n].y = (float)(rand() % (SCREENH-200)); 56         balls[n].width = 64; 57         balls[n].height = 64; 58         balls[n].velx = (float)(rand() % 6 - 3); 59         balls[n].vely = (float)(rand() % 6 - 3); 60  } 61 
62     //set the bumpers' properties
63     for (int n=0; n<NUMBUMPERS; n++) 64  { 65         bumpers[n].width = 128; 66         bumpers[n].height = 128; 67         bumpers[n].columns = 2; 68         bumpers[n].frame = 0; 69  } 70     bumpers[0].x = SCREENW/2; 71     bumpers[0].y = 64; 72     bumpers[1].x = 128; 73     bumpers[1].y = SCREENH - 256; 74     bumpers[2].x = SCREENW - 256; 75     bumpers[2].y = SCREENH - 256; 76 
77     //load bounce wave file
78     sound_bounce = LoadSound("bounce.wav"); 79     if (!sound_bounce) 80  { 81         MessageBox(window,"Error loading wav file",APPTITLE.c_str(),0); 82         return false; 83  } 84 
85     return true; 86 }

 

下面这个函数表示两个精灵碰撞后的反弹效果,就是简单的乘以-1来改变移动方向。

 1 void rebound(SPRITE &sprite1, SPRITE &sprite2)  2 {  3     float centerx1 = sprite1.x + sprite1.width/2;  4     float centery1 = sprite1.y + sprite1.height/2;  5 
 6     float centerx2 = sprite2.x + sprite2.width/2;  7     float centery2 = sprite2.y + sprite2.height/2;  8 
 9     if (centerx1 < centerx2) 10  { 11         sprite1.velx = fabs(sprite1.velx) * -1; 12  } 13     else if (centerx1 > centerx2) 14  { 15         sprite1.velx = fabs(sprite1.velx); 16  } 17 
18     if (centery1 < centery2) 19  { 20         sprite1.vely = fabs(sprite1.vely) * -1; 21  } 22     else { 23         sprite1.vely = fabs(sprite1.vely); 24  } 25 
26     sprite1.x += sprite1.velx; 27     sprite1.y += sprite1.vely; 28 
29 }

 

这里先介绍Game_End函数

 1 void Game_End()  2 {  3 
 4     if (ball_image) ball_image->Release();  5     if (bumper_image) bumper_image->Release();  6     if (background) background->Release();  7 
 8     if (sound_bounce) delete sound_bounce;  9  
10  DirectSound_Shutdown(); 11  DirectInput_Shutdown(); 12  Direct3D_Shutdown(); 13 }

 

最后介绍的是很长的Game_Run函数,其实这样的代码风格很差,更别提这种C语言风格的C++代码了,但我没时间去修改它。在这段代码中,先看到第一个for循环,这里对小球的运动做了些设计,如果小球移出边界,则会从屏幕另一侧出来。然后看到bumpertimer = timeGetTime()这段,由于小球撞击缓冲器时,缓冲器要产生一个变亮的动画效果,这段代码中把frame改为0是为了结束动画效果。接下来的for循环语句用来检测小球与缓冲器的碰撞,既小球先反弹rebound(balls, bumpers),然后把frame设为1产生动画效果,紧接着播放声音。注意rebound函数,这里的调用只会使第一个参数小球的移动方向改变,缓冲器时不动的。下面的循环用来检测小球之间的碰撞,两个for循环中各自定义两个小球,由于不能与自己碰撞,所以one != two。那么,如果发生碰撞了,就依次用两个rebound来反弹两个小球。作者在里面使用了一个While,这里其实没什么用处,可以去掉。接下来开始绘制图像了,调用之前的Sprite_Transform_Draw函数便可产生动画效果。

 1 void Game_Run(HWND window)  2 {  3     int n;  4 
 5     if (!d3ddev) return;  6  DirectInput_Update();  7     d3ddev->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,100), 1.0f, 0);  8 
 9 
 10     /*
 11  * slow ball movement  12      */
 13     if (timeGetTime() > coretimer + 10)  14  {  15         //reset timing
 16         coretimer = GetTickCount();  17 
 18         int width = balls[0].width;  19         int height = balls[0].height;  20 
 21         //move the ball sprites
 22         for (n=0; n<NUMBALLS; n++)  23  {  24             balls[n].x += balls[n].velx;  25             balls[n].y += balls[n].vely;  26     
 27             //warp the ball at screen edges
 28             if (balls[n].x > SCREENW)  29  {  30                 balls[n].x = -width;  31  }  32             else if (balls[n].x < -width)  33  {  34                 balls[n].x = SCREENW+width;  35  }  36 
 37             if (balls[n].y > SCREENH+height)  38  {  39                 balls[n].y = -height;  40  }  41             else if (balls[n].y < -height)  42  {  43                 balls[n].y = SCREENH+height;  44  }  45  }  46  }  47 
 48 
 49     //reset bumper frames
 50     if (timeGetTime() > bumpertimer + 250)  51  {  52         bumpertimer = timeGetTime();  53         for (int bumper=0; bumper<NUMBUMPERS; bumper++)  54  {  55             bumpers[bumper].frame = 0;  56  }  57  }  58 
 59     /*
 60  * check for ball collisions with bumpers  61      */
 62     for (int ball=0; ball<NUMBALLS; ball++)  63  {  64         for (int bumper=0; bumper<NUMBUMPERS; bumper++)  65  {  66             if (CollisionD(balls[ball], bumpers[bumper]))  67  {  68  rebound(balls[ball], bumpers[bumper]);  69                 bumpers[bumper].frame = 1;  70  PlaySound(sound_bounce);  71  }  72  }  73  }  74 
 75     /*
 76  * check for sprite collisions with each other  77  * (as fast as possible--with no time limiter)  78      */
 79     for (int one=0; one<NUMBALLS; one++)  80  {  81         for (int two=0; two<NUMBALLS; two++)  82  {  83             if (one != two)  84  {  85                 if (CollisionD(balls[one], balls[two]))  86  {  87                     while (CollisionD(balls[one], balls[two]))  88  {  89                         //rebound ball one
 90  rebound(balls[one], balls[two]);  91 
 92                         //rebound ball two
 93  rebound(balls[two], balls[one]);  94  }  95  }  96  }  97  }  98  }  99 
100 
101     /*
102  * slow rendering to approximately 60 fps 103      */
104     if (timeGetTime() > screentimer + 14) 105  { 106         screentimer = GetTickCount(); 107 
108         //start rendering
109         if (d3ddev->BeginScene()) 110  { 111             //start sprite handler
112             spriteobj->Begin(D3DXSPRITE_ALPHABLEND); 113 
114             //draw background
115             Sprite_Transform_Draw(background, 0, 0, SCREENW, SCREENH); 116 
117             //draw the balls
118             for (n=0; n<NUMBALLS; n++) 119  { 120  Sprite_Transform_Draw(ball_image, 121  balls[n].x, balls[n].y, 122  balls[n].width, balls[n].height); 123  } 124 
125             //draw the bumpers
126             for (n=0; n<NUMBUMPERS; n++) 127  { 128  Sprite_Transform_Draw(bumper_image, 129  bumpers[n].x, 130  bumpers[n].y, 131  bumpers[n].width, 132  bumpers[n].height, 133  bumpers[n].frame, 134  bumpers[n].columns); 135  } 136 
137             //stop drawing
138             spriteobj->End(); 139 
140 
141             //stop rendering
142             d3ddev->EndScene(); 143             d3ddev->Present(NULL, NULL, NULL, NULL); 144  } 145  } 146 
147     //exit with escape key or controller Back button
148     if (KEY_DOWN(VK_ESCAPE)) gameover = true; 149     if (controllers[0].wButtons & XINPUT_GAMEPAD_BACK) gameover = true; 150 
151 }

 

最后放出截图,源代码,参考自游戏编程入门。

 DirectSound的简单使用_第1张图片

你可能感兴趣的:(DI)