📄 sdksound.cpp
字号:
if( FAILED(hr) )
{
DXUT_ERR( L"CreateSoundBuffer", hr );
goto LFail;
}
}
}
// Create the sound
*ppSound = new CSound( apDSBuffer, dwDSBufferSize, dwNumBuffers, pWaveFile, dwCreationFlags );
SAFE_DELETE_ARRAY( apDSBuffer );
return S_OK;
LFail:
// Cleanup
SAFE_DELETE_ARRAY( apDSBuffer );
return hr;
}
//-----------------------------------------------------------------------------
// Name: CSoundManager::CreateStreaming()
// Desc:
//-----------------------------------------------------------------------------
HRESULT CSoundManager::CreateStreaming( CStreamingSound** ppStreamingSound,
LPWSTR strWaveFileName,
DWORD dwCreationFlags,
GUID guid3DAlgorithm,
DWORD dwNotifyCount,
DWORD dwNotifySize,
HANDLE hNotifyEvent )
{
HRESULT hr;
if( m_pDS == NULL )
return CO_E_NOTINITIALIZED;
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 DirectSound 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 DXUT_ERR( L"CreateSoundBuffer", hr );
return DXUT_ERR( L"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 DXUT_ERR( L"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 DXUT_ERR( L"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;
if( dwNumBuffers <= 0 )
return;
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 DXUT_ERR( L"RestoreBuffer", hr );
// Lock the buffer down
if( FAILED( hr = pDSB->Lock( 0, m_dwDSBufferSize,
&pDSLockedBuffer, &dwDSLockedBufferSize,
NULL, NULL, 0L ) ) )
return DXUT_ERR( L"Lock", hr );
// Reset the wave file to the beginning
m_pWaveFile->ResetFile();
if( FAILED( hr = m_pWaveFile->Read( (BYTE*) pDSLockedBuffer,
dwDSLockedBufferSize,
&dwWavDataRead ) ) )
return DXUT_ERR( L"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 DXUT_ERR( L"ResetFile", hr );
hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar,
dwDSLockedBufferSize - dwReadSoFar,
&dwWavDataRead );
if( FAILED(hr) )
return DXUT_ERR( L"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 DXUT_ERR( L"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;
DWORD i;
for( 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
//-----------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -