📄 dxutsound.cpp
字号:
//-----------------------------------------------------------------------------
// File: DXUTsound.cpp
//
// Desc: DirectSound framework classes for reading and writing wav files and
// playing them in DirectSound buffers. Feel free to use this class
// as a starting point for adding extra functionality.
//
// Copyright (c) Microsoft Corp. All rights reserved.
//-----------------------------------------------------------------------------
#define STRICT
#include "dxstdafx.h"
#include <mmsystem.h>
#include <dsound.h>
#include "DXUTsound.h"
#undef min // use __min instead
#undef max // use __max instead
//-----------------------------------------------------------------------------
// Name: CSoundManager::CSoundManager()
// Desc: Constructs the class
//-----------------------------------------------------------------------------
CSoundManager::CSoundManager()
{
m_pDS = NULL;
}
//-----------------------------------------------------------------------------
// Name: CSoundManager::~CSoundManager()
// Desc: Destroys the class
//-----------------------------------------------------------------------------
CSoundManager::~CSoundManager()
{
SAFE_RELEASE( m_pDS );
}
//-----------------------------------------------------------------------------
// Name: CSoundManager::Initialize()
// Desc: Initializes the IDirectSound object and also sets the primary buffer
// format. This function must be called before any others.
//-----------------------------------------------------------------------------
HRESULT CSoundManager::Initialize( HWND hWnd,
DWORD dwCoopLevel )
{
HRESULT hr;
SAFE_RELEASE( m_pDS );
// Create IDirectSound using the primary sound device
if( FAILED( hr = DirectSoundCreate8( NULL, &m_pDS, NULL ) ) )
return DXUT_ERR( L"DirectSoundCreate8", hr );
// Set DirectSound coop level
if( FAILED( hr = m_pDS->SetCooperativeLevel( hWnd, dwCoopLevel ) ) )
return DXUT_ERR( L"SetCooperativeLevel", hr );
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: CSoundManager::SetPrimaryBufferFormat()
// Desc: Set primary buffer to a specified format
// !WARNING! - Setting the primary buffer format and then using this
// same DirectSound object for DirectMusic messes up
// DirectMusic!
// For example, to set the primary buffer format to 22kHz stereo, 16-bit
// then: dwPrimaryChannels = 2
// dwPrimaryFreq = 22050,
// dwPrimaryBitRate = 16
//-----------------------------------------------------------------------------
HRESULT CSoundManager::SetPrimaryBufferFormat( DWORD dwPrimaryChannels,
DWORD dwPrimaryFreq,
DWORD dwPrimaryBitRate )
{
HRESULT hr;
LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
if( m_pDS == NULL )
return CO_E_NOTINITIALIZED;
// Get the primary buffer
DSBUFFERDESC dsbd;
ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
dsbd.dwSize = sizeof(DSBUFFERDESC);
dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
dsbd.dwBufferBytes = 0;
dsbd.lpwfxFormat = NULL;
if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBPrimary, NULL ) ) )
return DXUT_ERR( L"CreateSoundBuffer", hr );
WAVEFORMATEX wfx;
ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
wfx.wFormatTag = (WORD) WAVE_FORMAT_PCM;
wfx.nChannels = (WORD) dwPrimaryChannels;
wfx.nSamplesPerSec = (DWORD) dwPrimaryFreq;
wfx.wBitsPerSample = (WORD) dwPrimaryBitRate;
wfx.nBlockAlign = (WORD) (wfx.wBitsPerSample / 8 * wfx.nChannels);
wfx.nAvgBytesPerSec = (DWORD) (wfx.nSamplesPerSec * wfx.nBlockAlign);
if( FAILED( hr = pDSBPrimary->SetFormat(&wfx) ) )
return DXUT_ERR( L"SetFormat", hr );
SAFE_RELEASE( pDSBPrimary );
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: CSoundManager::Get3DListenerInterface()
// Desc: Returns the 3D listener interface associated with primary buffer.
//-----------------------------------------------------------------------------
HRESULT CSoundManager::Get3DListenerInterface( LPDIRECTSOUND3DLISTENER* ppDSListener )
{
HRESULT hr;
DSBUFFERDESC dsbdesc;
LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
if( ppDSListener == NULL )
return E_INVALIDARG;
if( m_pDS == NULL )
return CO_E_NOTINITIALIZED;
*ppDSListener = NULL;
// Obtain primary buffer, asking it for 3D control
ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) );
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
dsbdesc.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_PRIMARYBUFFER;
if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbdesc, &pDSBPrimary, NULL ) ) )
return DXUT_ERR( L"CreateSoundBuffer", hr );
if( FAILED( hr = pDSBPrimary->QueryInterface( IID_IDirectSound3DListener,
(VOID**)ppDSListener ) ) )
{
SAFE_RELEASE( pDSBPrimary );
return DXUT_ERR( L"QueryInterface", hr );
}
// Release the primary buffer, since it is not need anymore
SAFE_RELEASE( pDSBPrimary );
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: CSoundManager::Create()
// Desc:
//-----------------------------------------------------------------------------
HRESULT CSoundManager::Create( CSound** ppSound,
LPWSTR strWaveFileName,
DWORD dwCreationFlags,
GUID guid3DAlgorithm,
DWORD dwNumBuffers )
{
HRESULT hr;
HRESULT hrRet = S_OK;
DWORD i;
LPDIRECTSOUNDBUFFER* apDSBuffer = NULL;
DWORD dwDSBufferSize = NULL;
CWaveFile* pWaveFile = NULL;
if( m_pDS == NULL )
return CO_E_NOTINITIALIZED;
if( strWaveFileName == NULL || ppSound == NULL || dwNumBuffers < 1 )
return E_INVALIDARG;
apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
if( apDSBuffer == NULL )
{
hr = E_OUTOFMEMORY;
goto LFail;
}
pWaveFile = new CWaveFile();
if( pWaveFile == NULL )
{
hr = E_OUTOFMEMORY;
goto LFail;
}
pWaveFile->Open( strWaveFileName, NULL, WAVEFILE_READ );
if( pWaveFile->GetSize() == 0 )
{
// Wave is blank, so don't create it.
hr = E_FAIL;
goto LFail;
}
// Make the DirectSound buffer the same size as the wav file
dwDSBufferSize = pWaveFile->GetSize();
// Create the direct sound buffer, and only request the flags needed
// since each requires some overhead and limits if the buffer can
// be hardware accelerated
DSBUFFERDESC dsbd;
ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
dsbd.dwSize = sizeof(DSBUFFERDESC);
dsbd.dwFlags = dwCreationFlags;
dsbd.dwBufferBytes = dwDSBufferSize;
dsbd.guid3DAlgorithm = guid3DAlgorithm;
dsbd.lpwfxFormat = pWaveFile->m_pwfx;
// DirectSound is only guarenteed to play PCM data. Other
// formats may or may not work depending the sound card driver.
hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[0], NULL );
// Be sure to return this error code if it occurs so the
// callers knows this happened.
if( hr == DS_NO_VIRTUALIZATION )
hrRet = DS_NO_VIRTUALIZATION;
if( FAILED(hr) )
{
// DSERR_BUFFERTOOSMALL will be returned if the buffer is
// less than DSBSIZE_FX_MIN and the buffer is created
// with DSBCAPS_CTRLFX.
// It might also fail if hardware buffer mixing was requested
// on a device that doesn't support it.
DXUT_ERR( L"CreateSoundBuffer", hr );
goto LFail;
}
// Default to use DuplicateSoundBuffer() when created extra buffers since always
// create a buffer that uses the same memory however DuplicateSoundBuffer() will fail if
// DSBCAPS_CTRLFX is used, so use CreateSoundBuffer() instead in this case.
if( (dwCreationFlags & DSBCAPS_CTRLFX) == 0 )
{
for( i=1; i<dwNumBuffers; i++ )
{
if( FAILED( hr = m_pDS->DuplicateSoundBuffer( apDSBuffer[0], &apDSBuffer[i] ) ) )
{
DXUT_ERR( L"DuplicateSoundBuffer", hr );
goto LFail;
}
}
}
else
{
for( i=1; i<dwNumBuffers; i++ )
{
hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[i], NULL );
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 hrRet;
LFail:
// Cleanup
SAFE_DELETE( pWaveFile );
SAFE_DELETE_ARRAY( apDSBuffer );
return hr;
}
//-----------------------------------------------------------------------------
// Name: CSoundManager::CreateFromMemory()
// Desc:
//-----------------------------------------------------------------------------
HRESULT CSoundManager::CreateFromMemory( CSound** ppSound,
BYTE* pbData,
ULONG ulDataSize,
LPWAVEFORMATEX pwfx,
DWORD dwCreationFlags,
GUID guid3DAlgorithm,
DWORD dwNumBuffers )
{
HRESULT hr;
DWORD i;
LPDIRECTSOUNDBUFFER* apDSBuffer = NULL;
DWORD dwDSBufferSize = NULL;
CWaveFile* pWaveFile = NULL;
if( m_pDS == NULL )
return CO_E_NOTINITIALIZED;
if( pbData == NULL || ppSound == NULL || dwNumBuffers < 1 )
return E_INVALIDARG;
apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
if( apDSBuffer == NULL )
{
hr = E_OUTOFMEMORY;
goto LFail;
}
pWaveFile = new CWaveFile();
if( pWaveFile == NULL )
{
hr = E_OUTOFMEMORY;
goto LFail;
}
pWaveFile->OpenFromMemory( pbData,ulDataSize, pwfx, WAVEFILE_READ );
// Make the DirectSound buffer the same size as the wav file
dwDSBufferSize = ulDataSize;
// Create the direct sound buffer, and only request the flags needed
// since each requires some overhead and limits if the buffer can
// be hardware accelerated
DSBUFFERDESC dsbd;
ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
dsbd.dwSize = sizeof(DSBUFFERDESC);
dsbd.dwFlags = dwCreationFlags;
dsbd.dwBufferBytes = dwDSBufferSize;
dsbd.guid3DAlgorithm = guid3DAlgorithm;
dsbd.lpwfxFormat = pwfx;
if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[0], NULL ) ) )
{
DXUT_ERR( L"CreateSoundBuffer", hr );
goto LFail;
}
// Default to use DuplicateSoundBuffer() when created extra buffers since always
// create a buffer that uses the same memory however DuplicateSoundBuffer() will fail if
// DSBCAPS_CTRLFX is used, so use CreateSoundBuffer() instead in this case.
if( (dwCreationFlags & DSBCAPS_CTRLFX) == 0 )
{
for( i=1; i<dwNumBuffers; i++ )
{
if( FAILED( hr = m_pDS->DuplicateSoundBuffer( apDSBuffer[0], &apDSBuffer[i] ) ) )
{
DXUT_ERR( L"DuplicateSoundBuffer", hr );
goto LFail;
}
}
}
else
{
for( i=1; i<dwNumBuffers; i++ )
{
hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[i], NULL );
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -