📄 dsutil.cpp
字号:
if( strWaveFileName == NULL || ppStreamingSound == NULL || hNotifyEvent == NULL ) return E_INVALIDARG; LPDIRECTSOUNDBUFFER pDSBuffer = NULL; DWORD dwDSBufferSize = NULL; CWaveFile* pWaveFile = NULL; DSBPOSITIONNOTIFY* aPosNotify = NULL; LPDIRECTSOUNDNOTIFY pDSNotify = NULL; pWaveFile = new CWaveFile(); if( pWaveFile == NULL ) return E_OUTOFMEMORY; pWaveFile->Open( strWaveFileName, NULL, WAVEFILE_READ ); // Figure out how big the DSound buffer should be dwDSBufferSize = dwNotifySize * dwNotifyCount; // Set up the direct sound buffer. Request the NOTIFY flag, so // that we are notified as the sound buffer plays. Note, that using this flag // may limit the amount of hardware acceleration that can occur. DSBUFFERDESC dsbd; ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) ); dsbd.dwSize = sizeof(DSBUFFERDESC); dsbd.dwFlags = dwCreationFlags | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GETCURRENTPOSITION2; dsbd.dwBufferBytes = dwDSBufferSize; dsbd.guid3DAlgorithm = guid3DAlgorithm; dsbd.lpwfxFormat = pWaveFile->m_pwfx; if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBuffer, NULL ) ) ) { // If wave format isn't then it will return // either DSERR_BADFORMAT or E_INVALIDARG if( hr == DSERR_BADFORMAT || hr == E_INVALIDARG ) return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr ); return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr ); } // Create the notification events, so that we know when to fill // the buffer as the sound plays. if( FAILED( hr = pDSBuffer->QueryInterface( IID_IDirectSoundNotify, (VOID**)&pDSNotify ) ) ) { SAFE_DELETE_ARRAY( aPosNotify ); return DXTRACE_ERR( TEXT("QueryInterface"), hr ); } aPosNotify = new DSBPOSITIONNOTIFY[ dwNotifyCount ]; if( aPosNotify == NULL ) return E_OUTOFMEMORY; for( DWORD i = 0; i < dwNotifyCount; i++ ) { aPosNotify[i].dwOffset = (dwNotifySize * i) + dwNotifySize - 1; aPosNotify[i].hEventNotify = hNotifyEvent; } // Tell DirectSound when to notify us. The notification will come in the from // of signaled events that are handled in WinMain() if( FAILED( hr = pDSNotify->SetNotificationPositions( dwNotifyCount, aPosNotify ) ) ) { SAFE_RELEASE( pDSNotify ); SAFE_DELETE_ARRAY( aPosNotify ); return DXTRACE_ERR( TEXT("SetNotificationPositions"), hr ); } SAFE_RELEASE( pDSNotify ); SAFE_DELETE_ARRAY( aPosNotify ); // Create the sound *ppStreamingSound = new CStreamingSound( pDSBuffer, dwDSBufferSize, pWaveFile, dwNotifySize ); return S_OK;}//-----------------------------------------------------------------------------// Name: CSound::CSound()// Desc: Constructs the class//-----------------------------------------------------------------------------CSound::CSound( LPDIRECTSOUNDBUFFER* apDSBuffer, DWORD dwDSBufferSize, DWORD dwNumBuffers, CWaveFile* pWaveFile, DWORD dwCreationFlags ){ DWORD i; m_apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers]; if( NULL != m_apDSBuffer ) { for( i=0; i<dwNumBuffers; i++ ) m_apDSBuffer[i] = apDSBuffer[i]; m_dwDSBufferSize = dwDSBufferSize; m_dwNumBuffers = dwNumBuffers; m_pWaveFile = pWaveFile; m_dwCreationFlags = dwCreationFlags; FillBufferWithSound( m_apDSBuffer[0], false ); }}//-----------------------------------------------------------------------------// Name: CSound::~CSound()// Desc: Destroys the class//-----------------------------------------------------------------------------CSound::~CSound(){ for( DWORD i=0; i<m_dwNumBuffers; i++ ) { SAFE_RELEASE( m_apDSBuffer[i] ); } SAFE_DELETE_ARRAY( m_apDSBuffer ); SAFE_DELETE( m_pWaveFile );}//-----------------------------------------------------------------------------// Name: CSound::FillBufferWithSound()// Desc: Fills a DirectSound buffer with a sound file //-----------------------------------------------------------------------------HRESULT CSound::FillBufferWithSound( LPDIRECTSOUNDBUFFER pDSB, BOOL bRepeatWavIfBufferLarger ){ HRESULT hr; VOID* pDSLockedBuffer = NULL; // Pointer to locked buffer memory DWORD dwDSLockedBufferSize = 0; // Size of the locked DirectSound buffer DWORD dwWavDataRead = 0; // Amount of data read from the wav file if( pDSB == NULL ) return CO_E_NOTINITIALIZED; // Make sure we have focus, and we didn't just switch in from // an app which had a DirectSound device if( FAILED( hr = RestoreBuffer( pDSB, NULL ) ) ) return DXTRACE_ERR( TEXT("RestoreBuffer"), hr ); // Lock the buffer down if( FAILED( hr = pDSB->Lock( 0, m_dwDSBufferSize, &pDSLockedBuffer, &dwDSLockedBufferSize, NULL, NULL, 0L ) ) ) return DXTRACE_ERR( TEXT("Lock"), hr ); // Reset the wave file to the beginning m_pWaveFile->ResetFile(); if( FAILED( hr = m_pWaveFile->Read( (BYTE*) pDSLockedBuffer, dwDSLockedBufferSize, &dwWavDataRead ) ) ) return DXTRACE_ERR( TEXT("Read"), hr ); if( dwWavDataRead == 0 ) { // Wav is blank, so just fill with silence FillMemory( (BYTE*) pDSLockedBuffer, dwDSLockedBufferSize, (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) ); } else if( dwWavDataRead < dwDSLockedBufferSize ) { // If the wav file was smaller than the DirectSound buffer, // we need to fill the remainder of the buffer with data if( bRepeatWavIfBufferLarger ) { // Reset the file and fill the buffer with wav data DWORD dwReadSoFar = dwWavDataRead; // From previous call above. while( dwReadSoFar < dwDSLockedBufferSize ) { // This will keep reading in until the buffer is full // for very short files if( FAILED( hr = m_pWaveFile->ResetFile() ) ) return DXTRACE_ERR( TEXT("ResetFile"), hr ); hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar, dwDSLockedBufferSize - dwReadSoFar, &dwWavDataRead ); if( FAILED(hr) ) return DXTRACE_ERR( TEXT("Read"), hr ); dwReadSoFar += dwWavDataRead; } } else { // Don't repeat the wav file, just fill in silence FillMemory( (BYTE*) pDSLockedBuffer + dwWavDataRead, dwDSLockedBufferSize - dwWavDataRead, (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) ); } } // Unlock the buffer, we don't need it anymore. pDSB->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 ); return S_OK;}//-----------------------------------------------------------------------------// Name: CSound::RestoreBuffer()// Desc: Restores the lost buffer. *pbWasRestored returns true if the buffer was // restored. It can also NULL if the information is not needed.//-----------------------------------------------------------------------------HRESULT CSound::RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, BOOL* pbWasRestored ){ HRESULT hr; if( pDSB == NULL ) return CO_E_NOTINITIALIZED; if( pbWasRestored ) *pbWasRestored = false; DWORD dwStatus; if( FAILED( hr = pDSB->GetStatus( &dwStatus ) ) ) return DXTRACE_ERR( TEXT("GetStatus"), hr ); if( dwStatus & DSBSTATUS_BUFFERLOST ) { // Since the app could have just been activated, then // DirectSound may not be giving us control yet, so // the restoring the buffer may fail. // If it does, sleep until DirectSound gives us control. do { hr = pDSB->Restore(); if( hr == DSERR_BUFFERLOST ) Sleep( 10 ); } while( ( hr = pDSB->Restore() ) == DSERR_BUFFERLOST ); if( pbWasRestored != NULL ) *pbWasRestored = true; return S_OK; } else { return S_FALSE; }}//-----------------------------------------------------------------------------// Name: CSound::GetFreeBuffer()// Desc: Finding the first buffer that is not playing and return a pointer to // it, or if all are playing return a pointer to a randomly selected buffer.//-----------------------------------------------------------------------------LPDIRECTSOUNDBUFFER CSound::GetFreeBuffer(){ if( m_apDSBuffer == NULL ) return false; for( DWORD i=0; i<m_dwNumBuffers; i++ ) { if( m_apDSBuffer[i] ) { DWORD dwStatus = 0; m_apDSBuffer[i]->GetStatus( &dwStatus ); if ( ( dwStatus & DSBSTATUS_PLAYING ) == 0 ) break; } } if( i != m_dwNumBuffers ) return m_apDSBuffer[ i ]; else return m_apDSBuffer[ rand() % m_dwNumBuffers ];}//-----------------------------------------------------------------------------// Name: CSound::GetBuffer()// Desc: //-----------------------------------------------------------------------------LPDIRECTSOUNDBUFFER CSound::GetBuffer( DWORD dwIndex ){ if( m_apDSBuffer == NULL ) return NULL; if( dwIndex >= m_dwNumBuffers ) return NULL; return m_apDSBuffer[dwIndex];}//-----------------------------------------------------------------------------// Name: CSound::Get3DBufferInterface()// Desc: //-----------------------------------------------------------------------------HRESULT CSound::Get3DBufferInterface( DWORD dwIndex, LPDIRECTSOUND3DBUFFER* ppDS3DBuffer ){ if( m_apDSBuffer == NULL ) return CO_E_NOTINITIALIZED; if( dwIndex >= m_dwNumBuffers ) return E_INVALIDARG; *ppDS3DBuffer = NULL; return m_apDSBuffer[dwIndex]->QueryInterface( IID_IDirectSound3DBuffer, (VOID**)ppDS3DBuffer );}//-----------------------------------------------------------------------------// Name: CSound::Play()// Desc: Plays the sound using voice management flags. Pass in DSBPLAY_LOOPING// in the dwFlags to loop the sound//-----------------------------------------------------------------------------HRESULT CSound::Play( DWORD dwPriority, DWORD dwFlags, LONG lVolume, LONG lFrequency, LONG lPan ){ HRESULT hr; BOOL bRestored; if( m_apDSBuffer == NULL ) return CO_E_NOTINITIALIZED; LPDIRECTSOUNDBUFFER pDSB = GetFreeBuffer(); if( pDSB == NULL ) return DXTRACE_ERR( TEXT("GetFreeBuffer"), E_FAIL ); // Restore the buffer if it was lost if( FAILED( hr = RestoreBuffer( pDSB, &bRestored ) ) ) return DXTRACE_ERR( TEXT("RestoreBuffer"), hr ); if( bRestored ) { // The buffer was restored, so we need to fill it with new data if( FAILED( hr = FillBufferWithSound( pDSB, false ) ) ) return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr ); } if( m_dwCreationFlags & DSBCAPS_CTRLVOLUME ) { pDSB->SetVolume( lVolume ); } if( lFrequency != -1 && (m_dwCreationFlags & DSBCAPS_CTRLFREQUENCY) ) { pDSB->SetFrequency( lFrequency ); } if( m_dwCreationFlags & DSBCAPS_CTRLPAN ) { pDSB->SetPan( lPan ); } return pDSB->Play( 0, dwPriority, dwFlags );}//-----------------------------------------------------------------------------// Name: CSound::Play3D()// Desc: Plays the sound using voice management flags. Pass in DSBPLAY_LOOPING// in the dwFlags to loop the sound//-----------------------------------------------------------------------------HRESULT CSound::Play3D( LPDS3DBUFFER p3DBuffer, DWORD dwPriority, DWORD dwFlags, LONG lFrequency ){ HRESULT hr; BOOL bRestored; DWORD dwBaseFrequency; if( m_apDSBuffer == NULL ) return CO_E_NOTINITIALIZED; LPDIRECTSOUNDBUFFER pDSB = GetFreeBuffer(); if( pDSB == NULL ) return DXTRACE_ERR( TEXT("GetFreeBuffer"), E_FAIL ); // Restore the buffer if it was lost if( FAILED( hr = RestoreBuffer( pDSB, &bRestored ) ) ) return DXTRACE_ERR( TEXT("RestoreBuffer"), hr ); if( bRestored ) { // The buffer was restored, so we need to fill it with new data if( FAILED( hr = FillBufferWithSound( pDSB, false ) ) ) return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr ); } if( m_dwCreationFlags & DSBCAPS_CTRLFREQUENCY ) { pDSB->GetFrequency( &dwBaseFrequency ); pDSB->SetFrequency( dwBaseFrequency + lFrequency ); } // QI for the 3D buffer LPDIRECTSOUND3DBUFFER pDS3DBuffer; hr = pDSB->QueryInterface( IID_IDirectSound3DBuffer, (VOID**) &pDS3DBuffer ); if( SUCCEEDED( hr ) ) { hr = pDS3DBuffer->SetAllParameters( p3DBuffer, DS3D_IMMEDIATE ); if( SUCCEEDED( hr ) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -