📄 dsutil.cpp
字号:
pWaveFile = new CWaveFile();
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_NOMSGBOX( 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( 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( aPosNotify );
return DXTRACE_ERR( TEXT("SetNotificationPositions"), hr );
}
SAFE_RELEASE( pDSNotify );
SAFE_DELETE( 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 i;
m_apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
for( i=0; i<dwNumBuffers; i++ )
m_apDSBuffer[i] = apDSBuffer[i];
m_dwDSBufferSize = dwDSBufferSize;
m_dwNumBuffers = dwNumBuffers;
m_pWaveFile = pWaveFile;
FillBufferWithSound( m_apDSBuffer[0], FALSE );
// Make DirectSound do pre-processing on sound effects
for( i=0; i<dwNumBuffers; i++ )
m_apDSBuffer[i]->SetCurrentPosition(0);
}
//-----------------------------------------------------------------------------
// 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() );
if( pbWasRestored != NULL )
*pbWasRestored = TRUE;
return S_OK;
}
else
{
return S_FALSE;
}
}
//-----------------------------------------------------------------------------
// Name: CSound::GetFreeBuffer()
// Desc: Checks to see if a buffer is playing and returns TRUE if it is.
//-----------------------------------------------------------------------------
LPDIRECTSOUNDBUFFER CSound::GetFreeBuffer()
{
BOOL bIsPlaying = FALSE;
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 )
{
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 );
// Make DirectSound do pre-processing on sound effects
Reset();
}
return pDSB->Play( 0, dwPriority, dwFlags );
}
//-----------------------------------------------------------------------------
// Name: CSound::Stop()
// Desc: Stops the sound from playing
//-----------------------------------------------------------------------------
HRESULT CSound::Stop()
{
if( m_apDSBuffer == NULL )
return CO_E_NOTINITIALIZED;
HRESULT hr = 0;
for( DWORD i=0; i<m_dwNumBuffers; i++ )
hr |= m_apDSBuffer[i]->Stop();
return hr;
}
//-----------------------------------------------------------------------------
// Name: CSound::Reset()
// Desc: Reset all of the sound buffers
//-----------------------------------------------------------------------------
HRESULT CSound::Reset()
{
if( m_apDSBuffer == NULL )
return CO_E_NOTINITIALIZED;
HRESULT hr = 0;
for( DWORD i=0; i<m_dwNumBuffers; i++ )
hr |= m_apDSBuffer[i]->SetCurrentPosition( 0 );
return hr;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -