📄 dxutsound.cpp
字号:
hr = pDSB->Play( 0, dwPriority, dwFlags );
}
pDS3DBuffer->Release();
}
return hr;
}
//-----------------------------------------------------------------------------
// 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;
}
//-----------------------------------------------------------------------------
// Name: CSound::IsSoundPlaying()
// Desc: Checks to see if a buffer is playing and returns TRUE if it is.
//-----------------------------------------------------------------------------
BOOL CSound::IsSoundPlaying()
{
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 );
bIsPlaying |= ( ( dwStatus & DSBSTATUS_PLAYING ) != 0 );
}
}
return bIsPlaying;
}
//-----------------------------------------------------------------------------
// Name: CStreamingSound::CStreamingSound()
// Desc: Setups up a buffer so data can be streamed from the wave file into
// a buffer. This is very useful for large wav files that would take a
// while to load. The buffer is initially filled with data, then
// as sound is played the notification events are signaled and more data
// is written into the buffer by calling HandleWaveStreamNotification()
//-----------------------------------------------------------------------------
CStreamingSound::CStreamingSound( LPDIRECTSOUNDBUFFER pDSBuffer, DWORD dwDSBufferSize,
CWaveFile* pWaveFile, DWORD dwNotifySize )
: CSound( &pDSBuffer, dwDSBufferSize, 1, pWaveFile, 0 )
{
m_dwLastPlayPos = 0;
m_dwPlayProgress = 0;
m_dwNotifySize = dwNotifySize;
m_dwNextWriteOffset = 0;
m_bFillNextNotificationWithSilence = FALSE;
}
//-----------------------------------------------------------------------------
// Name: CStreamingSound::~CStreamingSound()
// Desc: Destroys the class
//-----------------------------------------------------------------------------
CStreamingSound::~CStreamingSound()
{
}
//-----------------------------------------------------------------------------
// Name: CStreamingSound::HandleWaveStreamNotification()
// Desc: Handle the notification that tells us to put more wav data in the
// circular buffer
//-----------------------------------------------------------------------------
HRESULT CStreamingSound::HandleWaveStreamNotification( BOOL bLoopedPlay )
{
HRESULT hr;
DWORD dwCurrentPlayPos;
DWORD dwPlayDelta;
DWORD dwBytesWrittenToBuffer;
VOID* pDSLockedBuffer = NULL;
VOID* pDSLockedBuffer2 = NULL;
DWORD dwDSLockedBufferSize;
DWORD dwDSLockedBufferSize2;
if( m_apDSBuffer == NULL || m_pWaveFile == NULL )
return CO_E_NOTINITIALIZED;
// Restore the buffer if it was lost
BOOL bRestored;
if( FAILED( hr = RestoreBuffer( m_apDSBuffer[0], &bRestored ) ) )
return DXUT_ERR( L"RestoreBuffer", hr );
if( bRestored )
{
// The buffer was restored, so we need to fill it with new data
if( FAILED( hr = FillBufferWithSound( m_apDSBuffer[0], FALSE ) ) )
return DXUT_ERR( L"FillBufferWithSound", hr );
return S_OK;
}
// Lock the DirectSound buffer
if( FAILED( hr = m_apDSBuffer[0]->Lock( m_dwNextWriteOffset, m_dwNotifySize,
&pDSLockedBuffer, &dwDSLockedBufferSize,
&pDSLockedBuffer2, &dwDSLockedBufferSize2, 0L ) ) )
return DXUT_ERR( L"Lock", hr );
// m_dwDSBufferSize and m_dwNextWriteOffset are both multiples of m_dwNotifySize,
// it should the second buffer, so it should never be valid
if( pDSLockedBuffer2 != NULL )
return E_UNEXPECTED;
if( !m_bFillNextNotificationWithSilence )
{
// Fill the DirectSound buffer with wav data
if( FAILED( hr = m_pWaveFile->Read( (BYTE*) pDSLockedBuffer,
dwDSLockedBufferSize,
&dwBytesWrittenToBuffer ) ) )
return DXUT_ERR( L"Read", hr );
}
else
{
// Fill the DirectSound buffer with silence
FillMemory( pDSLockedBuffer, dwDSLockedBufferSize,
(BYTE)( m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
dwBytesWrittenToBuffer = dwDSLockedBufferSize;
}
// If the number of bytes written is less than the
// amount we requested, we have a short file.
if( dwBytesWrittenToBuffer < dwDSLockedBufferSize )
{
if( !bLoopedPlay )
{
// Fill in silence for the rest of the buffer.
FillMemory( (BYTE*) pDSLockedBuffer + dwBytesWrittenToBuffer,
dwDSLockedBufferSize - dwBytesWrittenToBuffer,
(BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
// Any future notifications should just fill the buffer with silence
m_bFillNextNotificationWithSilence = TRUE;
}
else
{
// We are looping, so reset the file and fill the buffer with wav data
DWORD dwReadSoFar = dwBytesWrittenToBuffer; // 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 );
if( FAILED( hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar,
dwDSLockedBufferSize - dwReadSoFar,
&dwBytesWrittenToBuffer ) ) )
return DXUT_ERR( L"Read", hr );
dwReadSoFar += dwBytesWrittenToBuffer;
}
}
}
// Unlock the DirectSound buffer
m_apDSBuffer[0]->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );
// Figure out how much data has been played so far. When we have played
// past the end of the file, we will either need to start filling the
// buffer with silence or starting reading from the beginning of the file,
// depending if the user wants to loop the sound
if( FAILED( hr = m_apDSBuffer[0]->GetCurrentPosition( &dwCurrentPlayPos, NULL ) ) )
return DXUT_ERR( L"GetCurrentPosition", hr );
// Check to see if the position counter looped
if( dwCurrentPlayPos < m_dwLastPlayPos )
dwPlayDelta = ( m_dwDSBufferSize - m_dwLastPlayPos ) + dwCurrentPlayPos;
else
dwPlayDelta = dwCurrentPlayPos - m_dwLastPlayPos;
m_dwPlayProgress += dwPlayDelta;
m_dwLastPlayPos = dwCurrentPlayPos;
// If we are now filling the buffer with silence, then we have found the end so
// check to see if the entire sound has played, if it has then stop the buffer.
if( m_bFillNextNotificationWithSilence )
{
// We don't want to cut off the sound before it's done playing.
if( m_dwPlayProgress >= m_pWaveFile->GetSize() )
{
m_apDSBuffer[0]->Stop();
}
}
// Update where the buffer will lock (for next time)
m_dwNextWriteOffset += dwDSLockedBufferSize;
m_dwNextWriteOffset %= m_dwDSBufferSize; // Circular buffer
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: CStreamingSound::Reset()
// Desc: Resets the sound so it will begin playing at the beginning
//-----------------------------------------------------------------------------
HRESULT CStreamingSound::Reset()
{
HRESULT hr;
if( m_apDSBuffer[0] == NULL || m_pWaveFile == NULL )
return CO_E_NOTINITIALIZED;
m_dwLastPlayPos = 0;
m_dwPlayProgress = 0;
m_dwNextWriteOffset = 0;
m_bFillNextNotificationWithSilence = FALSE;
// Restore the buffer if it was lost
BOOL bRestored;
if( FAILED( hr = RestoreBuffer( m_apDSBuffer[0], &bRestored ) ) )
return DXUT_ERR( L"RestoreBuffer", hr );
if( bRestored )
{
// The buffer was restored, so we need to fill it with new data
if( FAILED( hr = FillBufferWithSound( m_apDSBuffer[0], FALSE ) ) )
return DXUT_ERR( L"FillBufferWithSound", hr );
}
m_pWaveFile->ResetFile();
return m_apDSBuffer[0]->SetCurrentPosition( 0L );
}
//-----------------------------------------------------------------------------
// Name: CWaveFile::CWaveFile()
// Desc: Constructs the class. Call Open() to open a wave file for reading.
// Then call Read() as needed. Calling the destructor or Close()
// will close the file.
//-----------------------------------------------------------------------------
CWaveFile::CWaveFile()
{
m_pwfx = NULL;
m_hmmio = NULL;
m_pResourceBuffer = NULL;
m_dwSize = 0;
m_bIsReadingFromMemory = FALSE;
}
//-----------------------------------------------------------------------------
// Name: CWaveFile::~CWaveFile()
// Desc: Destructs the class
//-----------------------------------------------------------------------------
CWaveFile::~CWaveFile()
{
Close();
if( !m_bIsReadingFromMemory )
SAFE_DELETE_ARRAY( m_pwfx );
}
//-----------------------------------------------------------------------------
// Name: CWaveFile::Open()
// Desc: Opens a wave file for reading
//-----------------------------------------------------------------------------
HRESULT CWaveFile::Open( LPWSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags )
{
HRESULT hr;
m_dwFlags = dwFlags;
m_bIsReadingFromMemory = FALSE;
if( m_dwFlags == WAVEFILE_READ )
{
if( strFileName == NULL )
return E_INVALIDARG;
SAFE_DELETE_ARRAY( m_pwfx );
m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF | MMIO_READ );
if( NULL == m_hmmio )
{
HRSRC hResInfo;
HGLOBAL hResData;
DWORD dwSize;
VOID* pvRes;
// Loading it as a file failed, so try it as a resource
if( NULL == ( hResInfo = FindResource( NULL, strFileName, L"WAVE" ) ) )
{
if( NULL == ( hResInfo = FindResource( NULL, strFileName, L"WAV" ) ) )
return DXUT_ERR( L"FindResource", E_FAIL );
}
if( NULL == ( hResData = LoadResource( GetModuleHandle(NULL), hResInfo ) ) )
return DXUT_ERR( L"LoadResource", E_FAIL );
if( 0 == ( dwSize = SizeofResource( GetModuleHandle(NULL), hResInfo ) ) )
return DXUT_ERR( L"SizeofResource", E_FAIL );
if( NULL == ( pvRes = LockResource( hResData ) ) )
return DXUT_ERR( L"LockResource", E_FAIL );
m_pResourceBuffer = new CHAR[ dwSize ];
if( m_pResourceBuffer == NULL )
return DXUT_ERR( L"new", E_OUTOFMEMORY );
memcpy( m_pResourceBuffer, pvRes, dwSize );
MMIOINFO mmioInfo;
ZeroMemory( &mmioInfo, sizeof(mmioInfo) );
mmioInfo.fccIOProc = FOURCC_MEM;
mmioInfo.cchBuffer = dwSize;
mmioInfo.pchBuffer = (CHAR*) m_pResourceBuffer;
m_hmmio = mmioOpen( NULL, &mmioInfo, MMIO_ALLOCBUF | MMIO_READ );
}
if( FAILED( hr = ReadMMIO() ) )
{
// ReadMMIO will fail if its an not a wave file
mmioClose( m_hmmio, 0 );
return DXUT_ERR( L"ReadMMIO", hr );
}
if( FAILED( hr = ResetFile() ) )
return DXUT_ERR( L"ResetFile", hr );
// After the reset, the size of the wav file is m_ck.cksize so store it now
m_dwSize = m_ck.cksize;
}
else
{
m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF |
MMIO_READWRITE |
MMIO_CREATE );
if( NULL == m_hmmio )
return DXUT_ERR( L"mmioOpen", E_FAIL );
if( FAILED( hr = WriteMMIO( pwfx ) ) )
{
mmioClose( m_hmmio, 0 );
return DXUT_ERR( L"WriteMMIO", hr );
}
if( FAILED( hr = ResetFile() ) )
return DXUT_ERR( L"ResetFile", hr );
}
return hr;
}
//-----------------------------------------------------------------------------
// Name: CWaveFile::OpenFromMemory()
// Desc: copy data to CWaveFile member variable from memory
//-----------------------------------------------------------------------------
HRESULT CWaveFile::OpenFromMemory( BYTE* pbData, ULONG ulDataSize,
WAVEFORMATEX* pwfx, DWORD dwFlags )
{
m_pwfx = pwfx;
m_ulDataSize = ulDataSize;
m_pbData = pbData;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -