[3255] | 1 | //-----------------------------------------------------------------------------
|
---|
| 2 | // File: DXUTsound.cpp
|
---|
| 3 | //
|
---|
| 4 | // Desc: DirectSound framework classes for reading and writing wav files and
|
---|
| 5 | // playing them in DirectSound buffers. Feel free to use this class
|
---|
| 6 | // as a starting point for adding extra functionality.
|
---|
| 7 | //
|
---|
| 8 | // Copyright (c) Microsoft Corp. All rights reserved.
|
---|
| 9 | //-----------------------------------------------------------------------------
|
---|
| 10 | #define STRICT
|
---|
| 11 | #include "dxstdafx.h"
|
---|
| 12 | #include <mmsystem.h>
|
---|
| 13 | #include <dsound.h>
|
---|
| 14 | #include "DXUTsound.h"
|
---|
| 15 | #undef min // use __min instead
|
---|
| 16 | #undef max // use __max instead
|
---|
| 17 |
|
---|
| 18 |
|
---|
| 19 | //-----------------------------------------------------------------------------
|
---|
| 20 | // Name: CSoundManager::CSoundManager()
|
---|
| 21 | // Desc: Constructs the class
|
---|
| 22 | //-----------------------------------------------------------------------------
|
---|
| 23 | CSoundManager::CSoundManager()
|
---|
| 24 | {
|
---|
| 25 | m_pDS = NULL;
|
---|
| 26 | }
|
---|
| 27 |
|
---|
| 28 |
|
---|
| 29 | //-----------------------------------------------------------------------------
|
---|
| 30 | // Name: CSoundManager::~CSoundManager()
|
---|
| 31 | // Desc: Destroys the class
|
---|
| 32 | //-----------------------------------------------------------------------------
|
---|
| 33 | CSoundManager::~CSoundManager()
|
---|
| 34 | {
|
---|
| 35 | SAFE_RELEASE( m_pDS );
|
---|
| 36 | }
|
---|
| 37 |
|
---|
| 38 |
|
---|
| 39 | //-----------------------------------------------------------------------------
|
---|
| 40 | // Name: CSoundManager::Initialize()
|
---|
| 41 | // Desc: Initializes the IDirectSound object and also sets the primary buffer
|
---|
| 42 | // format. This function must be called before any others.
|
---|
| 43 | //-----------------------------------------------------------------------------
|
---|
| 44 | HRESULT CSoundManager::Initialize( HWND hWnd,
|
---|
| 45 | DWORD dwCoopLevel )
|
---|
| 46 | {
|
---|
| 47 | HRESULT hr;
|
---|
| 48 |
|
---|
| 49 | SAFE_RELEASE( m_pDS );
|
---|
| 50 |
|
---|
| 51 | // Create IDirectSound using the primary sound device
|
---|
| 52 | if( FAILED( hr = DirectSoundCreate8( NULL, &m_pDS, NULL ) ) )
|
---|
| 53 | return DXUT_ERR( L"DirectSoundCreate8", hr );
|
---|
| 54 |
|
---|
| 55 | // Set DirectSound coop level
|
---|
| 56 | if( FAILED( hr = m_pDS->SetCooperativeLevel( hWnd, dwCoopLevel ) ) )
|
---|
| 57 | return DXUT_ERR( L"SetCooperativeLevel", hr );
|
---|
| 58 |
|
---|
| 59 | return S_OK;
|
---|
| 60 | }
|
---|
| 61 |
|
---|
| 62 |
|
---|
| 63 | //-----------------------------------------------------------------------------
|
---|
| 64 | // Name: CSoundManager::SetPrimaryBufferFormat()
|
---|
| 65 | // Desc: Set primary buffer to a specified format
|
---|
| 66 | // !WARNING! - Setting the primary buffer format and then using this
|
---|
| 67 | // same DirectSound object for DirectMusic messes up
|
---|
| 68 | // DirectMusic!
|
---|
| 69 | // For example, to set the primary buffer format to 22kHz stereo, 16-bit
|
---|
| 70 | // then: dwPrimaryChannels = 2
|
---|
| 71 | // dwPrimaryFreq = 22050,
|
---|
| 72 | // dwPrimaryBitRate = 16
|
---|
| 73 | //-----------------------------------------------------------------------------
|
---|
| 74 | HRESULT CSoundManager::SetPrimaryBufferFormat( DWORD dwPrimaryChannels,
|
---|
| 75 | DWORD dwPrimaryFreq,
|
---|
| 76 | DWORD dwPrimaryBitRate )
|
---|
| 77 | {
|
---|
| 78 | HRESULT hr;
|
---|
| 79 | LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
|
---|
| 80 |
|
---|
| 81 | if( m_pDS == NULL )
|
---|
| 82 | return CO_E_NOTINITIALIZED;
|
---|
| 83 |
|
---|
| 84 | // Get the primary buffer
|
---|
| 85 | DSBUFFERDESC dsbd;
|
---|
| 86 | ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
|
---|
| 87 | dsbd.dwSize = sizeof(DSBUFFERDESC);
|
---|
| 88 | dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
|
---|
| 89 | dsbd.dwBufferBytes = 0;
|
---|
| 90 | dsbd.lpwfxFormat = NULL;
|
---|
| 91 |
|
---|
| 92 | if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBPrimary, NULL ) ) )
|
---|
| 93 | return DXUT_ERR( L"CreateSoundBuffer", hr );
|
---|
| 94 |
|
---|
| 95 | WAVEFORMATEX wfx;
|
---|
| 96 | ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
|
---|
| 97 | wfx.wFormatTag = (WORD) WAVE_FORMAT_PCM;
|
---|
| 98 | wfx.nChannels = (WORD) dwPrimaryChannels;
|
---|
| 99 | wfx.nSamplesPerSec = (DWORD) dwPrimaryFreq;
|
---|
| 100 | wfx.wBitsPerSample = (WORD) dwPrimaryBitRate;
|
---|
| 101 | wfx.nBlockAlign = (WORD) (wfx.wBitsPerSample / 8 * wfx.nChannels);
|
---|
| 102 | wfx.nAvgBytesPerSec = (DWORD) (wfx.nSamplesPerSec * wfx.nBlockAlign);
|
---|
| 103 |
|
---|
| 104 | if( FAILED( hr = pDSBPrimary->SetFormat(&wfx) ) )
|
---|
| 105 | return DXUT_ERR( L"SetFormat", hr );
|
---|
| 106 |
|
---|
| 107 | SAFE_RELEASE( pDSBPrimary );
|
---|
| 108 |
|
---|
| 109 | return S_OK;
|
---|
| 110 | }
|
---|
| 111 |
|
---|
| 112 |
|
---|
| 113 | //-----------------------------------------------------------------------------
|
---|
| 114 | // Name: CSoundManager::Get3DListenerInterface()
|
---|
| 115 | // Desc: Returns the 3D listener interface associated with primary buffer.
|
---|
| 116 | //-----------------------------------------------------------------------------
|
---|
| 117 | HRESULT CSoundManager::Get3DListenerInterface( LPDIRECTSOUND3DLISTENER* ppDSListener )
|
---|
| 118 | {
|
---|
| 119 | HRESULT hr;
|
---|
| 120 | DSBUFFERDESC dsbdesc;
|
---|
| 121 | LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
|
---|
| 122 |
|
---|
| 123 | if( ppDSListener == NULL )
|
---|
| 124 | return E_INVALIDARG;
|
---|
| 125 | if( m_pDS == NULL )
|
---|
| 126 | return CO_E_NOTINITIALIZED;
|
---|
| 127 |
|
---|
| 128 | *ppDSListener = NULL;
|
---|
| 129 |
|
---|
| 130 | // Obtain primary buffer, asking it for 3D control
|
---|
| 131 | ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) );
|
---|
| 132 | dsbdesc.dwSize = sizeof(DSBUFFERDESC);
|
---|
| 133 | dsbdesc.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_PRIMARYBUFFER;
|
---|
| 134 | if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbdesc, &pDSBPrimary, NULL ) ) )
|
---|
| 135 | return DXUT_ERR( L"CreateSoundBuffer", hr );
|
---|
| 136 |
|
---|
| 137 | if( FAILED( hr = pDSBPrimary->QueryInterface( IID_IDirectSound3DListener,
|
---|
| 138 | (VOID**)ppDSListener ) ) )
|
---|
| 139 | {
|
---|
| 140 | SAFE_RELEASE( pDSBPrimary );
|
---|
| 141 | return DXUT_ERR( L"QueryInterface", hr );
|
---|
| 142 | }
|
---|
| 143 |
|
---|
| 144 | // Release the primary buffer, since it is not need anymore
|
---|
| 145 | SAFE_RELEASE( pDSBPrimary );
|
---|
| 146 |
|
---|
| 147 | return S_OK;
|
---|
| 148 | }
|
---|
| 149 |
|
---|
| 150 |
|
---|
| 151 | //-----------------------------------------------------------------------------
|
---|
| 152 | // Name: CSoundManager::Create()
|
---|
| 153 | // Desc:
|
---|
| 154 | //-----------------------------------------------------------------------------
|
---|
| 155 | HRESULT CSoundManager::Create( CSound** ppSound,
|
---|
| 156 | LPWSTR strWaveFileName,
|
---|
| 157 | DWORD dwCreationFlags,
|
---|
| 158 | GUID guid3DAlgorithm,
|
---|
| 159 | DWORD dwNumBuffers )
|
---|
| 160 | {
|
---|
| 161 | HRESULT hr;
|
---|
| 162 | HRESULT hrRet = S_OK;
|
---|
| 163 | DWORD i;
|
---|
| 164 | LPDIRECTSOUNDBUFFER* apDSBuffer = NULL;
|
---|
| 165 | DWORD dwDSBufferSize = NULL;
|
---|
| 166 | CWaveFile* pWaveFile = NULL;
|
---|
| 167 |
|
---|
| 168 | if( m_pDS == NULL )
|
---|
| 169 | return CO_E_NOTINITIALIZED;
|
---|
| 170 | if( strWaveFileName == NULL || ppSound == NULL || dwNumBuffers < 1 )
|
---|
| 171 | return E_INVALIDARG;
|
---|
| 172 |
|
---|
| 173 | apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
|
---|
| 174 | if( apDSBuffer == NULL )
|
---|
| 175 | {
|
---|
| 176 | hr = E_OUTOFMEMORY;
|
---|
| 177 | goto LFail;
|
---|
| 178 | }
|
---|
| 179 |
|
---|
| 180 | pWaveFile = new CWaveFile();
|
---|
| 181 | if( pWaveFile == NULL )
|
---|
| 182 | {
|
---|
| 183 | hr = E_OUTOFMEMORY;
|
---|
| 184 | goto LFail;
|
---|
| 185 | }
|
---|
| 186 |
|
---|
| 187 | pWaveFile->Open( strWaveFileName, NULL, WAVEFILE_READ );
|
---|
| 188 |
|
---|
| 189 | if( pWaveFile->GetSize() == 0 )
|
---|
| 190 | {
|
---|
| 191 | // Wave is blank, so don't create it.
|
---|
| 192 | hr = E_FAIL;
|
---|
| 193 | goto LFail;
|
---|
| 194 | }
|
---|
| 195 |
|
---|
| 196 | // Make the DirectSound buffer the same size as the wav file
|
---|
| 197 | dwDSBufferSize = pWaveFile->GetSize();
|
---|
| 198 |
|
---|
| 199 | // Create the direct sound buffer, and only request the flags needed
|
---|
| 200 | // since each requires some overhead and limits if the buffer can
|
---|
| 201 | // be hardware accelerated
|
---|
| 202 | DSBUFFERDESC dsbd;
|
---|
| 203 | ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
|
---|
| 204 | dsbd.dwSize = sizeof(DSBUFFERDESC);
|
---|
| 205 | dsbd.dwFlags = dwCreationFlags;
|
---|
| 206 | dsbd.dwBufferBytes = dwDSBufferSize;
|
---|
| 207 | dsbd.guid3DAlgorithm = guid3DAlgorithm;
|
---|
| 208 | dsbd.lpwfxFormat = pWaveFile->m_pwfx;
|
---|
| 209 |
|
---|
| 210 | // DirectSound is only guarenteed to play PCM data. Other
|
---|
| 211 | // formats may or may not work depending the sound card driver.
|
---|
| 212 | hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[0], NULL );
|
---|
| 213 |
|
---|
| 214 | // Be sure to return this error code if it occurs so the
|
---|
| 215 | // callers knows this happened.
|
---|
| 216 | if( hr == DS_NO_VIRTUALIZATION )
|
---|
| 217 | hrRet = DS_NO_VIRTUALIZATION;
|
---|
| 218 |
|
---|
| 219 | if( FAILED(hr) )
|
---|
| 220 | {
|
---|
| 221 | // DSERR_BUFFERTOOSMALL will be returned if the buffer is
|
---|
| 222 | // less than DSBSIZE_FX_MIN and the buffer is created
|
---|
| 223 | // with DSBCAPS_CTRLFX.
|
---|
| 224 |
|
---|
| 225 | // It might also fail if hardware buffer mixing was requested
|
---|
| 226 | // on a device that doesn't support it.
|
---|
| 227 | DXUT_ERR( L"CreateSoundBuffer", hr );
|
---|
| 228 |
|
---|
| 229 | goto LFail;
|
---|
| 230 | }
|
---|
| 231 |
|
---|
| 232 | // Default to use DuplicateSoundBuffer() when created extra buffers since always
|
---|
| 233 | // create a buffer that uses the same memory however DuplicateSoundBuffer() will fail if
|
---|
| 234 | // DSBCAPS_CTRLFX is used, so use CreateSoundBuffer() instead in this case.
|
---|
| 235 | if( (dwCreationFlags & DSBCAPS_CTRLFX) == 0 )
|
---|
| 236 | {
|
---|
| 237 | for( i=1; i<dwNumBuffers; i++ )
|
---|
| 238 | {
|
---|
| 239 | if( FAILED( hr = m_pDS->DuplicateSoundBuffer( apDSBuffer[0], &apDSBuffer[i] ) ) )
|
---|
| 240 | {
|
---|
| 241 | DXUT_ERR( L"DuplicateSoundBuffer", hr );
|
---|
| 242 | goto LFail;
|
---|
| 243 | }
|
---|
| 244 | }
|
---|
| 245 | }
|
---|
| 246 | else
|
---|
| 247 | {
|
---|
| 248 | for( i=1; i<dwNumBuffers; i++ )
|
---|
| 249 | {
|
---|
| 250 | hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[i], NULL );
|
---|
| 251 | if( FAILED(hr) )
|
---|
| 252 | {
|
---|
| 253 | DXUT_ERR( L"CreateSoundBuffer", hr );
|
---|
| 254 | goto LFail;
|
---|
| 255 | }
|
---|
| 256 | }
|
---|
| 257 | }
|
---|
| 258 |
|
---|
| 259 | // Create the sound
|
---|
| 260 | *ppSound = new CSound( apDSBuffer, dwDSBufferSize, dwNumBuffers, pWaveFile, dwCreationFlags );
|
---|
| 261 |
|
---|
| 262 | SAFE_DELETE_ARRAY( apDSBuffer );
|
---|
| 263 | return hrRet;
|
---|
| 264 |
|
---|
| 265 | LFail:
|
---|
| 266 | // Cleanup
|
---|
| 267 | SAFE_DELETE( pWaveFile );
|
---|
| 268 | SAFE_DELETE_ARRAY( apDSBuffer );
|
---|
| 269 | return hr;
|
---|
| 270 | }
|
---|
| 271 |
|
---|
| 272 |
|
---|
| 273 | //-----------------------------------------------------------------------------
|
---|
| 274 | // Name: CSoundManager::CreateFromMemory()
|
---|
| 275 | // Desc:
|
---|
| 276 | //-----------------------------------------------------------------------------
|
---|
| 277 | HRESULT CSoundManager::CreateFromMemory( CSound** ppSound,
|
---|
| 278 | BYTE* pbData,
|
---|
| 279 | ULONG ulDataSize,
|
---|
| 280 | LPWAVEFORMATEX pwfx,
|
---|
| 281 | DWORD dwCreationFlags,
|
---|
| 282 | GUID guid3DAlgorithm,
|
---|
| 283 | DWORD dwNumBuffers )
|
---|
| 284 | {
|
---|
| 285 | HRESULT hr;
|
---|
| 286 | DWORD i;
|
---|
| 287 | LPDIRECTSOUNDBUFFER* apDSBuffer = NULL;
|
---|
| 288 | DWORD dwDSBufferSize = NULL;
|
---|
| 289 | CWaveFile* pWaveFile = NULL;
|
---|
| 290 |
|
---|
| 291 | if( m_pDS == NULL )
|
---|
| 292 | return CO_E_NOTINITIALIZED;
|
---|
| 293 | if( pbData == NULL || ppSound == NULL || dwNumBuffers < 1 )
|
---|
| 294 | return E_INVALIDARG;
|
---|
| 295 |
|
---|
| 296 | apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
|
---|
| 297 | if( apDSBuffer == NULL )
|
---|
| 298 | {
|
---|
| 299 | hr = E_OUTOFMEMORY;
|
---|
| 300 | goto LFail;
|
---|
| 301 | }
|
---|
| 302 |
|
---|
| 303 | pWaveFile = new CWaveFile();
|
---|
| 304 | if( pWaveFile == NULL )
|
---|
| 305 | {
|
---|
| 306 | hr = E_OUTOFMEMORY;
|
---|
| 307 | goto LFail;
|
---|
| 308 | }
|
---|
| 309 |
|
---|
| 310 | pWaveFile->OpenFromMemory( pbData,ulDataSize, pwfx, WAVEFILE_READ );
|
---|
| 311 |
|
---|
| 312 |
|
---|
| 313 | // Make the DirectSound buffer the same size as the wav file
|
---|
| 314 | dwDSBufferSize = ulDataSize;
|
---|
| 315 |
|
---|
| 316 | // Create the direct sound buffer, and only request the flags needed
|
---|
| 317 | // since each requires some overhead and limits if the buffer can
|
---|
| 318 | // be hardware accelerated
|
---|
| 319 | DSBUFFERDESC dsbd;
|
---|
| 320 | ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
|
---|
| 321 | dsbd.dwSize = sizeof(DSBUFFERDESC);
|
---|
| 322 | dsbd.dwFlags = dwCreationFlags;
|
---|
| 323 | dsbd.dwBufferBytes = dwDSBufferSize;
|
---|
| 324 | dsbd.guid3DAlgorithm = guid3DAlgorithm;
|
---|
| 325 | dsbd.lpwfxFormat = pwfx;
|
---|
| 326 |
|
---|
| 327 | if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[0], NULL ) ) )
|
---|
| 328 | {
|
---|
| 329 | DXUT_ERR( L"CreateSoundBuffer", hr );
|
---|
| 330 | goto LFail;
|
---|
| 331 | }
|
---|
| 332 |
|
---|
| 333 | // Default to use DuplicateSoundBuffer() when created extra buffers since always
|
---|
| 334 | // create a buffer that uses the same memory however DuplicateSoundBuffer() will fail if
|
---|
| 335 | // DSBCAPS_CTRLFX is used, so use CreateSoundBuffer() instead in this case.
|
---|
| 336 | if( (dwCreationFlags & DSBCAPS_CTRLFX) == 0 )
|
---|
| 337 | {
|
---|
| 338 | for( i=1; i<dwNumBuffers; i++ )
|
---|
| 339 | {
|
---|
| 340 | if( FAILED( hr = m_pDS->DuplicateSoundBuffer( apDSBuffer[0], &apDSBuffer[i] ) ) )
|
---|
| 341 | {
|
---|
| 342 | DXUT_ERR( L"DuplicateSoundBuffer", hr );
|
---|
| 343 | goto LFail;
|
---|
| 344 | }
|
---|
| 345 | }
|
---|
| 346 | }
|
---|
| 347 | else
|
---|
| 348 | {
|
---|
| 349 | for( i=1; i<dwNumBuffers; i++ )
|
---|
| 350 | {
|
---|
| 351 | hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[i], NULL );
|
---|
| 352 | if( FAILED(hr) )
|
---|
| 353 | {
|
---|
| 354 | DXUT_ERR( L"CreateSoundBuffer", hr );
|
---|
| 355 | goto LFail;
|
---|
| 356 | }
|
---|
| 357 | }
|
---|
| 358 | }
|
---|
| 359 |
|
---|
| 360 | // Create the sound
|
---|
| 361 | *ppSound = new CSound( apDSBuffer, dwDSBufferSize, dwNumBuffers, pWaveFile, dwCreationFlags );
|
---|
| 362 |
|
---|
| 363 | SAFE_DELETE_ARRAY( apDSBuffer );
|
---|
| 364 | return S_OK;
|
---|
| 365 |
|
---|
| 366 | LFail:
|
---|
| 367 | // Cleanup
|
---|
| 368 |
|
---|
| 369 | SAFE_DELETE_ARRAY( apDSBuffer );
|
---|
| 370 | return hr;
|
---|
| 371 | }
|
---|
| 372 |
|
---|
| 373 |
|
---|
| 374 | //-----------------------------------------------------------------------------
|
---|
| 375 | // Name: CSoundManager::CreateStreaming()
|
---|
| 376 | // Desc:
|
---|
| 377 | //-----------------------------------------------------------------------------
|
---|
| 378 | HRESULT CSoundManager::CreateStreaming( CStreamingSound** ppStreamingSound,
|
---|
| 379 | LPWSTR strWaveFileName,
|
---|
| 380 | DWORD dwCreationFlags,
|
---|
| 381 | GUID guid3DAlgorithm,
|
---|
| 382 | DWORD dwNotifyCount,
|
---|
| 383 | DWORD dwNotifySize,
|
---|
| 384 | HANDLE hNotifyEvent )
|
---|
| 385 | {
|
---|
| 386 | HRESULT hr;
|
---|
| 387 |
|
---|
| 388 | if( m_pDS == NULL )
|
---|
| 389 | return CO_E_NOTINITIALIZED;
|
---|
| 390 | if( strWaveFileName == NULL || ppStreamingSound == NULL || hNotifyEvent == NULL )
|
---|
| 391 | return E_INVALIDARG;
|
---|
| 392 |
|
---|
| 393 | LPDIRECTSOUNDBUFFER pDSBuffer = NULL;
|
---|
| 394 | DWORD dwDSBufferSize = NULL;
|
---|
| 395 | CWaveFile* pWaveFile = NULL;
|
---|
| 396 | DSBPOSITIONNOTIFY* aPosNotify = NULL;
|
---|
| 397 | LPDIRECTSOUNDNOTIFY pDSNotify = NULL;
|
---|
| 398 |
|
---|
| 399 | pWaveFile = new CWaveFile();
|
---|
| 400 | if( pWaveFile == NULL )
|
---|
| 401 | return E_OUTOFMEMORY;
|
---|
| 402 | pWaveFile->Open( strWaveFileName, NULL, WAVEFILE_READ );
|
---|
| 403 |
|
---|
| 404 | // Figure out how big the DirectSound buffer should be
|
---|
| 405 | dwDSBufferSize = dwNotifySize * dwNotifyCount;
|
---|
| 406 |
|
---|
| 407 | // Set up the direct sound buffer. Request the NOTIFY flag, so
|
---|
| 408 | // that we are notified as the sound buffer plays. Note, that using this flag
|
---|
| 409 | // may limit the amount of hardware acceleration that can occur.
|
---|
| 410 | DSBUFFERDESC dsbd;
|
---|
| 411 | ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
|
---|
| 412 | dsbd.dwSize = sizeof(DSBUFFERDESC);
|
---|
| 413 | dsbd.dwFlags = dwCreationFlags |
|
---|
| 414 | DSBCAPS_CTRLPOSITIONNOTIFY |
|
---|
| 415 | DSBCAPS_GETCURRENTPOSITION2;
|
---|
| 416 | dsbd.dwBufferBytes = dwDSBufferSize;
|
---|
| 417 | dsbd.guid3DAlgorithm = guid3DAlgorithm;
|
---|
| 418 | dsbd.lpwfxFormat = pWaveFile->m_pwfx;
|
---|
| 419 |
|
---|
| 420 | if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBuffer, NULL ) ) )
|
---|
| 421 | {
|
---|
| 422 | // If wave format isn't then it will return
|
---|
| 423 | // either DSERR_BADFORMAT or E_INVALIDARG
|
---|
| 424 | if( hr == DSERR_BADFORMAT || hr == E_INVALIDARG )
|
---|
| 425 | return DXUT_ERR( L"CreateSoundBuffer", hr );
|
---|
| 426 |
|
---|
| 427 | return DXUT_ERR( L"CreateSoundBuffer", hr );
|
---|
| 428 | }
|
---|
| 429 |
|
---|
| 430 | // Create the notification events, so that we know when to fill
|
---|
| 431 | // the buffer as the sound plays.
|
---|
| 432 | if( FAILED( hr = pDSBuffer->QueryInterface( IID_IDirectSoundNotify,
|
---|
| 433 | (VOID**)&pDSNotify ) ) )
|
---|
| 434 | {
|
---|
| 435 | SAFE_DELETE_ARRAY( aPosNotify );
|
---|
| 436 | return DXUT_ERR( L"QueryInterface", hr );
|
---|
| 437 | }
|
---|
| 438 |
|
---|
| 439 | aPosNotify = new DSBPOSITIONNOTIFY[ dwNotifyCount ];
|
---|
| 440 | if( aPosNotify == NULL )
|
---|
| 441 | return E_OUTOFMEMORY;
|
---|
| 442 |
|
---|
| 443 | for( DWORD i = 0; i < dwNotifyCount; i++ )
|
---|
| 444 | {
|
---|
| 445 | aPosNotify[i].dwOffset = (dwNotifySize * i) + dwNotifySize - 1;
|
---|
| 446 | aPosNotify[i].hEventNotify = hNotifyEvent;
|
---|
| 447 | }
|
---|
| 448 |
|
---|
| 449 | // Tell DirectSound when to notify us. The notification will come in the from
|
---|
| 450 | // of signaled events that are handled in WinMain()
|
---|
| 451 | if( FAILED( hr = pDSNotify->SetNotificationPositions( dwNotifyCount,
|
---|
| 452 | aPosNotify ) ) )
|
---|
| 453 | {
|
---|
| 454 | SAFE_RELEASE( pDSNotify );
|
---|
| 455 | SAFE_DELETE_ARRAY( aPosNotify );
|
---|
| 456 | return DXUT_ERR( L"SetNotificationPositions", hr );
|
---|
| 457 | }
|
---|
| 458 |
|
---|
| 459 | SAFE_RELEASE( pDSNotify );
|
---|
| 460 | SAFE_DELETE_ARRAY( aPosNotify );
|
---|
| 461 |
|
---|
| 462 | // Create the sound
|
---|
| 463 | *ppStreamingSound = new CStreamingSound( pDSBuffer, dwDSBufferSize, pWaveFile, dwNotifySize );
|
---|
| 464 |
|
---|
| 465 | return S_OK;
|
---|
| 466 | }
|
---|
| 467 |
|
---|
| 468 |
|
---|
| 469 | //-----------------------------------------------------------------------------
|
---|
| 470 | // Name: CSound::CSound()
|
---|
| 471 | // Desc: Constructs the class
|
---|
| 472 | //-----------------------------------------------------------------------------
|
---|
| 473 | CSound::CSound( LPDIRECTSOUNDBUFFER* apDSBuffer, DWORD dwDSBufferSize,
|
---|
| 474 | DWORD dwNumBuffers, CWaveFile* pWaveFile, DWORD dwCreationFlags )
|
---|
| 475 | {
|
---|
| 476 | DWORD i;
|
---|
| 477 |
|
---|
| 478 | if( dwNumBuffers <= 0 )
|
---|
| 479 | return;
|
---|
| 480 |
|
---|
| 481 | m_apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
|
---|
| 482 | if( NULL != m_apDSBuffer )
|
---|
| 483 | {
|
---|
| 484 | for( i=0; i<dwNumBuffers; i++ )
|
---|
| 485 | m_apDSBuffer[i] = apDSBuffer[i];
|
---|
| 486 |
|
---|
| 487 | m_dwDSBufferSize = dwDSBufferSize;
|
---|
| 488 | m_dwNumBuffers = dwNumBuffers;
|
---|
| 489 | m_pWaveFile = pWaveFile;
|
---|
| 490 | m_dwCreationFlags = dwCreationFlags;
|
---|
| 491 |
|
---|
| 492 | FillBufferWithSound( m_apDSBuffer[0], FALSE );
|
---|
| 493 | }
|
---|
| 494 | }
|
---|
| 495 |
|
---|
| 496 |
|
---|
| 497 | //-----------------------------------------------------------------------------
|
---|
| 498 | // Name: CSound::~CSound()
|
---|
| 499 | // Desc: Destroys the class
|
---|
| 500 | //-----------------------------------------------------------------------------
|
---|
| 501 | CSound::~CSound()
|
---|
| 502 | {
|
---|
| 503 | for( DWORD i=0; i<m_dwNumBuffers; i++ )
|
---|
| 504 | {
|
---|
| 505 | SAFE_RELEASE( m_apDSBuffer[i] );
|
---|
| 506 | }
|
---|
| 507 |
|
---|
| 508 | SAFE_DELETE_ARRAY( m_apDSBuffer );
|
---|
| 509 | SAFE_DELETE( m_pWaveFile );
|
---|
| 510 | }
|
---|
| 511 |
|
---|
| 512 |
|
---|
| 513 | //-----------------------------------------------------------------------------
|
---|
| 514 | // Name: CSound::FillBufferWithSound()
|
---|
| 515 | // Desc: Fills a DirectSound buffer with a sound file
|
---|
| 516 | //-----------------------------------------------------------------------------
|
---|
| 517 | HRESULT CSound::FillBufferWithSound( LPDIRECTSOUNDBUFFER pDSB, BOOL bRepeatWavIfBufferLarger )
|
---|
| 518 | {
|
---|
| 519 | HRESULT hr;
|
---|
| 520 | VOID* pDSLockedBuffer = NULL; // Pointer to locked buffer memory
|
---|
| 521 | DWORD dwDSLockedBufferSize = 0; // Size of the locked DirectSound buffer
|
---|
| 522 | DWORD dwWavDataRead = 0; // Amount of data read from the wav file
|
---|
| 523 |
|
---|
| 524 | if( pDSB == NULL )
|
---|
| 525 | return CO_E_NOTINITIALIZED;
|
---|
| 526 |
|
---|
| 527 | // Make sure we have focus, and we didn't just switch in from
|
---|
| 528 | // an app which had a DirectSound device
|
---|
| 529 | if( FAILED( hr = RestoreBuffer( pDSB, NULL ) ) )
|
---|
| 530 | return DXUT_ERR( L"RestoreBuffer", hr );
|
---|
| 531 |
|
---|
| 532 | // Lock the buffer down
|
---|
| 533 | if( FAILED( hr = pDSB->Lock( 0, m_dwDSBufferSize,
|
---|
| 534 | &pDSLockedBuffer, &dwDSLockedBufferSize,
|
---|
| 535 | NULL, NULL, 0L ) ) )
|
---|
| 536 | return DXUT_ERR( L"Lock", hr );
|
---|
| 537 |
|
---|
| 538 | // Reset the wave file to the beginning
|
---|
| 539 | m_pWaveFile->ResetFile();
|
---|
| 540 |
|
---|
| 541 | if( FAILED( hr = m_pWaveFile->Read( (BYTE*) pDSLockedBuffer,
|
---|
| 542 | dwDSLockedBufferSize,
|
---|
| 543 | &dwWavDataRead ) ) )
|
---|
| 544 | return DXUT_ERR( L"Read", hr );
|
---|
| 545 |
|
---|
| 546 | if( dwWavDataRead == 0 )
|
---|
| 547 | {
|
---|
| 548 | // Wav is blank, so just fill with silence
|
---|
| 549 | FillMemory( (BYTE*) pDSLockedBuffer,
|
---|
| 550 | dwDSLockedBufferSize,
|
---|
| 551 | (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
|
---|
| 552 | }
|
---|
| 553 | else if( dwWavDataRead < dwDSLockedBufferSize )
|
---|
| 554 | {
|
---|
| 555 | // If the wav file was smaller than the DirectSound buffer,
|
---|
| 556 | // we need to fill the remainder of the buffer with data
|
---|
| 557 | if( bRepeatWavIfBufferLarger )
|
---|
| 558 | {
|
---|
| 559 | // Reset the file and fill the buffer with wav data
|
---|
| 560 | DWORD dwReadSoFar = dwWavDataRead; // From previous call above.
|
---|
| 561 | while( dwReadSoFar < dwDSLockedBufferSize )
|
---|
| 562 | {
|
---|
| 563 | // This will keep reading in until the buffer is full
|
---|
| 564 | // for very short files
|
---|
| 565 | if( FAILED( hr = m_pWaveFile->ResetFile() ) )
|
---|
| 566 | return DXUT_ERR( L"ResetFile", hr );
|
---|
| 567 |
|
---|
| 568 | hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar,
|
---|
| 569 | dwDSLockedBufferSize - dwReadSoFar,
|
---|
| 570 | &dwWavDataRead );
|
---|
| 571 | if( FAILED(hr) )
|
---|
| 572 | return DXUT_ERR( L"Read", hr );
|
---|
| 573 |
|
---|
| 574 | dwReadSoFar += dwWavDataRead;
|
---|
| 575 | }
|
---|
| 576 | }
|
---|
| 577 | else
|
---|
| 578 | {
|
---|
| 579 | // Don't repeat the wav file, just fill in silence
|
---|
| 580 | FillMemory( (BYTE*) pDSLockedBuffer + dwWavDataRead,
|
---|
| 581 | dwDSLockedBufferSize - dwWavDataRead,
|
---|
| 582 | (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
|
---|
| 583 | }
|
---|
| 584 | }
|
---|
| 585 |
|
---|
| 586 | // Unlock the buffer, we don't need it anymore.
|
---|
| 587 | pDSB->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );
|
---|
| 588 |
|
---|
| 589 | return S_OK;
|
---|
| 590 | }
|
---|
| 591 |
|
---|
| 592 |
|
---|
| 593 | //-----------------------------------------------------------------------------
|
---|
| 594 | // Name: CSound::RestoreBuffer()
|
---|
| 595 | // Desc: Restores the lost buffer. *pbWasRestored returns TRUE if the buffer was
|
---|
| 596 | // restored. It can also NULL if the information is not needed.
|
---|
| 597 | //-----------------------------------------------------------------------------
|
---|
| 598 | HRESULT CSound::RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, BOOL* pbWasRestored )
|
---|
| 599 | {
|
---|
| 600 | HRESULT hr;
|
---|
| 601 |
|
---|
| 602 | if( pDSB == NULL )
|
---|
| 603 | return CO_E_NOTINITIALIZED;
|
---|
| 604 | if( pbWasRestored )
|
---|
| 605 | *pbWasRestored = FALSE;
|
---|
| 606 |
|
---|
| 607 | DWORD dwStatus;
|
---|
| 608 | if( FAILED( hr = pDSB->GetStatus( &dwStatus ) ) )
|
---|
| 609 | return DXUT_ERR( L"GetStatus", hr );
|
---|
| 610 |
|
---|
| 611 | if( dwStatus & DSBSTATUS_BUFFERLOST )
|
---|
| 612 | {
|
---|
| 613 | // Since the app could have just been activated, then
|
---|
| 614 | // DirectSound may not be giving us control yet, so
|
---|
| 615 | // the restoring the buffer may fail.
|
---|
| 616 | // If it does, sleep until DirectSound gives us control.
|
---|
| 617 | do
|
---|
| 618 | {
|
---|
| 619 | hr = pDSB->Restore();
|
---|
| 620 | if( hr == DSERR_BUFFERLOST )
|
---|
| 621 | Sleep( 10 );
|
---|
| 622 | }
|
---|
| 623 | while( ( hr = pDSB->Restore() ) == DSERR_BUFFERLOST );
|
---|
| 624 |
|
---|
| 625 | if( pbWasRestored != NULL )
|
---|
| 626 | *pbWasRestored = TRUE;
|
---|
| 627 |
|
---|
| 628 | return S_OK;
|
---|
| 629 | }
|
---|
| 630 | else
|
---|
| 631 | {
|
---|
| 632 | return S_FALSE;
|
---|
| 633 | }
|
---|
| 634 | }
|
---|
| 635 |
|
---|
| 636 |
|
---|
| 637 | //-----------------------------------------------------------------------------
|
---|
| 638 | // Name: CSound::GetFreeBuffer()
|
---|
| 639 | // Desc: Finding the first buffer that is not playing and return a pointer to
|
---|
| 640 | // it, or if all are playing return a pointer to a randomly selected buffer.
|
---|
| 641 | //-----------------------------------------------------------------------------
|
---|
| 642 | LPDIRECTSOUNDBUFFER CSound::GetFreeBuffer()
|
---|
| 643 | {
|
---|
| 644 | if( m_apDSBuffer == NULL )
|
---|
| 645 | return FALSE;
|
---|
| 646 |
|
---|
| 647 | DWORD i;
|
---|
| 648 | for( i=0; i<m_dwNumBuffers; i++ )
|
---|
| 649 | {
|
---|
| 650 | if( m_apDSBuffer[i] )
|
---|
| 651 | {
|
---|
| 652 | DWORD dwStatus = 0;
|
---|
| 653 | m_apDSBuffer[i]->GetStatus( &dwStatus );
|
---|
| 654 | if ( ( dwStatus & DSBSTATUS_PLAYING ) == 0 )
|
---|
| 655 | break;
|
---|
| 656 | }
|
---|
| 657 | }
|
---|
| 658 |
|
---|
| 659 | if( i != m_dwNumBuffers )
|
---|
| 660 | return m_apDSBuffer[ i ];
|
---|
| 661 | else
|
---|
| 662 | return m_apDSBuffer[ rand() % m_dwNumBuffers ];
|
---|
| 663 | }
|
---|
| 664 |
|
---|
| 665 |
|
---|
| 666 | //-----------------------------------------------------------------------------
|
---|
| 667 | // Name: CSound::GetBuffer()
|
---|
| 668 | // Desc:
|
---|
| 669 | //-----------------------------------------------------------------------------
|
---|
| 670 | LPDIRECTSOUNDBUFFER CSound::GetBuffer( DWORD dwIndex )
|
---|
| 671 | {
|
---|
| 672 | if( m_apDSBuffer == NULL )
|
---|
| 673 | return NULL;
|
---|
| 674 | if( dwIndex >= m_dwNumBuffers )
|
---|
| 675 | return NULL;
|
---|
| 676 |
|
---|
| 677 | return m_apDSBuffer[dwIndex];
|
---|
| 678 | }
|
---|
| 679 |
|
---|
| 680 |
|
---|
| 681 | //-----------------------------------------------------------------------------
|
---|
| 682 | // Name: CSound::Get3DBufferInterface()
|
---|
| 683 | // Desc:
|
---|
| 684 | //-----------------------------------------------------------------------------
|
---|
| 685 | HRESULT CSound::Get3DBufferInterface( DWORD dwIndex, LPDIRECTSOUND3DBUFFER* ppDS3DBuffer )
|
---|
| 686 | {
|
---|
| 687 | if( m_apDSBuffer == NULL )
|
---|
| 688 | return CO_E_NOTINITIALIZED;
|
---|
| 689 | if( dwIndex >= m_dwNumBuffers )
|
---|
| 690 | return E_INVALIDARG;
|
---|
| 691 |
|
---|
| 692 | *ppDS3DBuffer = NULL;
|
---|
| 693 |
|
---|
| 694 | return m_apDSBuffer[dwIndex]->QueryInterface( IID_IDirectSound3DBuffer,
|
---|
| 695 | (VOID**)ppDS3DBuffer );
|
---|
| 696 | }
|
---|
| 697 |
|
---|
| 698 |
|
---|
| 699 | //-----------------------------------------------------------------------------
|
---|
| 700 | // Name: CSound::Play()
|
---|
| 701 | // Desc: Plays the sound using voice management flags. Pass in DSBPLAY_LOOPING
|
---|
| 702 | // in the dwFlags to loop the sound
|
---|
| 703 | //-----------------------------------------------------------------------------
|
---|
| 704 | HRESULT CSound::Play( DWORD dwPriority, DWORD dwFlags, LONG lVolume, LONG lFrequency, LONG lPan )
|
---|
| 705 | {
|
---|
| 706 | HRESULT hr;
|
---|
| 707 | BOOL bRestored;
|
---|
| 708 |
|
---|
| 709 | if( m_apDSBuffer == NULL )
|
---|
| 710 | return CO_E_NOTINITIALIZED;
|
---|
| 711 |
|
---|
| 712 | LPDIRECTSOUNDBUFFER pDSB = GetFreeBuffer();
|
---|
| 713 |
|
---|
| 714 | if( pDSB == NULL )
|
---|
| 715 | return DXUT_ERR( L"GetFreeBuffer", E_FAIL );
|
---|
| 716 |
|
---|
| 717 | // Restore the buffer if it was lost
|
---|
| 718 | if( FAILED( hr = RestoreBuffer( pDSB, &bRestored ) ) )
|
---|
| 719 | return DXUT_ERR( L"RestoreBuffer", hr );
|
---|
| 720 |
|
---|
| 721 | if( bRestored )
|
---|
| 722 | {
|
---|
| 723 | // The buffer was restored, so we need to fill it with new data
|
---|
| 724 | if( FAILED( hr = FillBufferWithSound( pDSB, FALSE ) ) )
|
---|
| 725 | return DXUT_ERR( L"FillBufferWithSound", hr );
|
---|
| 726 | }
|
---|
| 727 |
|
---|
| 728 | if( m_dwCreationFlags & DSBCAPS_CTRLVOLUME )
|
---|
| 729 | {
|
---|
| 730 | pDSB->SetVolume( lVolume );
|
---|
| 731 | }
|
---|
| 732 |
|
---|
| 733 | if( lFrequency != -1 &&
|
---|
| 734 | (m_dwCreationFlags & DSBCAPS_CTRLFREQUENCY) )
|
---|
| 735 | {
|
---|
| 736 | pDSB->SetFrequency( lFrequency );
|
---|
| 737 | }
|
---|
| 738 |
|
---|
| 739 | if( m_dwCreationFlags & DSBCAPS_CTRLPAN )
|
---|
| 740 | {
|
---|
| 741 | pDSB->SetPan( lPan );
|
---|
| 742 | }
|
---|
| 743 |
|
---|
| 744 | return pDSB->Play( 0, dwPriority, dwFlags );
|
---|
| 745 | }
|
---|
| 746 |
|
---|
| 747 |
|
---|
| 748 | //-----------------------------------------------------------------------------
|
---|
| 749 | // Name: CSound::Play3D()
|
---|
| 750 | // Desc: Plays the sound using voice management flags. Pass in DSBPLAY_LOOPING
|
---|
| 751 | // in the dwFlags to loop the sound
|
---|
| 752 | //-----------------------------------------------------------------------------
|
---|
| 753 | HRESULT CSound::Play3D( LPDS3DBUFFER p3DBuffer, DWORD dwPriority, DWORD dwFlags, LONG lFrequency )
|
---|
| 754 | {
|
---|
| 755 | HRESULT hr;
|
---|
| 756 | BOOL bRestored;
|
---|
| 757 | DWORD dwBaseFrequency;
|
---|
| 758 |
|
---|
| 759 | if( m_apDSBuffer == NULL )
|
---|
| 760 | return CO_E_NOTINITIALIZED;
|
---|
| 761 |
|
---|
| 762 | LPDIRECTSOUNDBUFFER pDSB = GetFreeBuffer();
|
---|
| 763 | if( pDSB == NULL )
|
---|
| 764 | return DXUT_ERR( L"GetFreeBuffer", E_FAIL );
|
---|
| 765 |
|
---|
| 766 | // Restore the buffer if it was lost
|
---|
| 767 | if( FAILED( hr = RestoreBuffer( pDSB, &bRestored ) ) )
|
---|
| 768 | return DXUT_ERR( L"RestoreBuffer", hr );
|
---|
| 769 |
|
---|
| 770 | if( bRestored )
|
---|
| 771 | {
|
---|
| 772 | // The buffer was restored, so we need to fill it with new data
|
---|
| 773 | if( FAILED( hr = FillBufferWithSound( pDSB, FALSE ) ) )
|
---|
| 774 | return DXUT_ERR( L"FillBufferWithSound", hr );
|
---|
| 775 | }
|
---|
| 776 |
|
---|
| 777 | if( m_dwCreationFlags & DSBCAPS_CTRLFREQUENCY )
|
---|
| 778 | {
|
---|
| 779 | pDSB->GetFrequency( &dwBaseFrequency );
|
---|
| 780 | pDSB->SetFrequency( dwBaseFrequency + lFrequency );
|
---|
| 781 | }
|
---|
| 782 |
|
---|
| 783 | // QI for the 3D buffer
|
---|
| 784 | LPDIRECTSOUND3DBUFFER pDS3DBuffer;
|
---|
| 785 | hr = pDSB->QueryInterface( IID_IDirectSound3DBuffer, (VOID**) &pDS3DBuffer );
|
---|
| 786 | if( SUCCEEDED( hr ) )
|
---|
| 787 | {
|
---|
| 788 | hr = pDS3DBuffer->SetAllParameters( p3DBuffer, DS3D_IMMEDIATE );
|
---|
| 789 | if( SUCCEEDED( hr ) )
|
---|
| 790 | {
|
---|
| 791 | hr = pDSB->Play( 0, dwPriority, dwFlags );
|
---|
| 792 | }
|
---|
| 793 |
|
---|
| 794 | pDS3DBuffer->Release();
|
---|
| 795 | }
|
---|
| 796 |
|
---|
| 797 | return hr;
|
---|
| 798 | }
|
---|
| 799 |
|
---|
| 800 |
|
---|
| 801 | //-----------------------------------------------------------------------------
|
---|
| 802 | // Name: CSound::Stop()
|
---|
| 803 | // Desc: Stops the sound from playing
|
---|
| 804 | //-----------------------------------------------------------------------------
|
---|
| 805 | HRESULT CSound::Stop()
|
---|
| 806 | {
|
---|
| 807 | if( m_apDSBuffer == NULL )
|
---|
| 808 | return CO_E_NOTINITIALIZED;
|
---|
| 809 |
|
---|
| 810 | HRESULT hr = 0;
|
---|
| 811 |
|
---|
| 812 | for( DWORD i=0; i<m_dwNumBuffers; i++ )
|
---|
| 813 | hr |= m_apDSBuffer[i]->Stop();
|
---|
| 814 |
|
---|
| 815 | return hr;
|
---|
| 816 | }
|
---|
| 817 |
|
---|
| 818 |
|
---|
| 819 | //-----------------------------------------------------------------------------
|
---|
| 820 | // Name: CSound::Reset()
|
---|
| 821 | // Desc: Reset all of the sound buffers
|
---|
| 822 | //-----------------------------------------------------------------------------
|
---|
| 823 | HRESULT CSound::Reset()
|
---|
| 824 | {
|
---|
| 825 | if( m_apDSBuffer == NULL )
|
---|
| 826 | return CO_E_NOTINITIALIZED;
|
---|
| 827 |
|
---|
| 828 | HRESULT hr = 0;
|
---|
| 829 |
|
---|
| 830 | for( DWORD i=0; i<m_dwNumBuffers; i++ )
|
---|
| 831 | hr |= m_apDSBuffer[i]->SetCurrentPosition( 0 );
|
---|
| 832 |
|
---|
| 833 | return hr;
|
---|
| 834 | }
|
---|
| 835 |
|
---|
| 836 |
|
---|
| 837 | //-----------------------------------------------------------------------------
|
---|
| 838 | // Name: CSound::IsSoundPlaying()
|
---|
| 839 | // Desc: Checks to see if a buffer is playing and returns TRUE if it is.
|
---|
| 840 | //-----------------------------------------------------------------------------
|
---|
| 841 | BOOL CSound::IsSoundPlaying()
|
---|
| 842 | {
|
---|
| 843 | BOOL bIsPlaying = FALSE;
|
---|
| 844 |
|
---|
| 845 | if( m_apDSBuffer == NULL )
|
---|
| 846 | return FALSE;
|
---|
| 847 |
|
---|
| 848 | for( DWORD i=0; i<m_dwNumBuffers; i++ )
|
---|
| 849 | {
|
---|
| 850 | if( m_apDSBuffer[i] )
|
---|
| 851 | {
|
---|
| 852 | DWORD dwStatus = 0;
|
---|
| 853 | m_apDSBuffer[i]->GetStatus( &dwStatus );
|
---|
| 854 | bIsPlaying |= ( ( dwStatus & DSBSTATUS_PLAYING ) != 0 );
|
---|
| 855 | }
|
---|
| 856 | }
|
---|
| 857 |
|
---|
| 858 | return bIsPlaying;
|
---|
| 859 | }
|
---|
| 860 |
|
---|
| 861 |
|
---|
| 862 | //-----------------------------------------------------------------------------
|
---|
| 863 | // Name: CStreamingSound::CStreamingSound()
|
---|
| 864 | // Desc: Setups up a buffer so data can be streamed from the wave file into
|
---|
| 865 | // a buffer. This is very useful for large wav files that would take a
|
---|
| 866 | // while to load. The buffer is initially filled with data, then
|
---|
| 867 | // as sound is played the notification events are signaled and more data
|
---|
| 868 | // is written into the buffer by calling HandleWaveStreamNotification()
|
---|
| 869 | //-----------------------------------------------------------------------------
|
---|
| 870 | CStreamingSound::CStreamingSound( LPDIRECTSOUNDBUFFER pDSBuffer, DWORD dwDSBufferSize,
|
---|
| 871 | CWaveFile* pWaveFile, DWORD dwNotifySize )
|
---|
| 872 | : CSound( &pDSBuffer, dwDSBufferSize, 1, pWaveFile, 0 )
|
---|
| 873 | {
|
---|
| 874 | m_dwLastPlayPos = 0;
|
---|
| 875 | m_dwPlayProgress = 0;
|
---|
| 876 | m_dwNotifySize = dwNotifySize;
|
---|
| 877 | m_dwNextWriteOffset = 0;
|
---|
| 878 | m_bFillNextNotificationWithSilence = FALSE;
|
---|
| 879 | }
|
---|
| 880 |
|
---|
| 881 |
|
---|
| 882 | //-----------------------------------------------------------------------------
|
---|
| 883 | // Name: CStreamingSound::~CStreamingSound()
|
---|
| 884 | // Desc: Destroys the class
|
---|
| 885 | //-----------------------------------------------------------------------------
|
---|
| 886 | CStreamingSound::~CStreamingSound()
|
---|
| 887 | {
|
---|
| 888 | }
|
---|
| 889 |
|
---|
| 890 |
|
---|
| 891 | //-----------------------------------------------------------------------------
|
---|
| 892 | // Name: CStreamingSound::HandleWaveStreamNotification()
|
---|
| 893 | // Desc: Handle the notification that tells us to put more wav data in the
|
---|
| 894 | // circular buffer
|
---|
| 895 | //-----------------------------------------------------------------------------
|
---|
| 896 | HRESULT CStreamingSound::HandleWaveStreamNotification( BOOL bLoopedPlay )
|
---|
| 897 | {
|
---|
| 898 | HRESULT hr;
|
---|
| 899 | DWORD dwCurrentPlayPos;
|
---|
| 900 | DWORD dwPlayDelta;
|
---|
| 901 | DWORD dwBytesWrittenToBuffer;
|
---|
| 902 | VOID* pDSLockedBuffer = NULL;
|
---|
| 903 | VOID* pDSLockedBuffer2 = NULL;
|
---|
| 904 | DWORD dwDSLockedBufferSize;
|
---|
| 905 | DWORD dwDSLockedBufferSize2;
|
---|
| 906 |
|
---|
| 907 | if( m_apDSBuffer == NULL || m_pWaveFile == NULL )
|
---|
| 908 | return CO_E_NOTINITIALIZED;
|
---|
| 909 |
|
---|
| 910 | // Restore the buffer if it was lost
|
---|
| 911 | BOOL bRestored;
|
---|
| 912 | if( FAILED( hr = RestoreBuffer( m_apDSBuffer[0], &bRestored ) ) )
|
---|
| 913 | return DXUT_ERR( L"RestoreBuffer", hr );
|
---|
| 914 |
|
---|
| 915 | if( bRestored )
|
---|
| 916 | {
|
---|
| 917 | // The buffer was restored, so we need to fill it with new data
|
---|
| 918 | if( FAILED( hr = FillBufferWithSound( m_apDSBuffer[0], FALSE ) ) )
|
---|
| 919 | return DXUT_ERR( L"FillBufferWithSound", hr );
|
---|
| 920 | return S_OK;
|
---|
| 921 | }
|
---|
| 922 |
|
---|
| 923 | // Lock the DirectSound buffer
|
---|
| 924 | if( FAILED( hr = m_apDSBuffer[0]->Lock( m_dwNextWriteOffset, m_dwNotifySize,
|
---|
| 925 | &pDSLockedBuffer, &dwDSLockedBufferSize,
|
---|
| 926 | &pDSLockedBuffer2, &dwDSLockedBufferSize2, 0L ) ) )
|
---|
| 927 | return DXUT_ERR( L"Lock", hr );
|
---|
| 928 |
|
---|
| 929 | // m_dwDSBufferSize and m_dwNextWriteOffset are both multiples of m_dwNotifySize,
|
---|
| 930 | // it should the second buffer, so it should never be valid
|
---|
| 931 | if( pDSLockedBuffer2 != NULL )
|
---|
| 932 | return E_UNEXPECTED;
|
---|
| 933 |
|
---|
| 934 | if( !m_bFillNextNotificationWithSilence )
|
---|
| 935 | {
|
---|
| 936 | // Fill the DirectSound buffer with wav data
|
---|
| 937 | if( FAILED( hr = m_pWaveFile->Read( (BYTE*) pDSLockedBuffer,
|
---|
| 938 | dwDSLockedBufferSize,
|
---|
| 939 | &dwBytesWrittenToBuffer ) ) )
|
---|
| 940 | return DXUT_ERR( L"Read", hr );
|
---|
| 941 | }
|
---|
| 942 | else
|
---|
| 943 | {
|
---|
| 944 | // Fill the DirectSound buffer with silence
|
---|
| 945 | FillMemory( pDSLockedBuffer, dwDSLockedBufferSize,
|
---|
| 946 | (BYTE)( m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
|
---|
| 947 | dwBytesWrittenToBuffer = dwDSLockedBufferSize;
|
---|
| 948 | }
|
---|
| 949 |
|
---|
| 950 | // If the number of bytes written is less than the
|
---|
| 951 | // amount we requested, we have a short file.
|
---|
| 952 | if( dwBytesWrittenToBuffer < dwDSLockedBufferSize )
|
---|
| 953 | {
|
---|
| 954 | if( !bLoopedPlay )
|
---|
| 955 | {
|
---|
| 956 | // Fill in silence for the rest of the buffer.
|
---|
| 957 | FillMemory( (BYTE*) pDSLockedBuffer + dwBytesWrittenToBuffer,
|
---|
| 958 | dwDSLockedBufferSize - dwBytesWrittenToBuffer,
|
---|
| 959 | (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
|
---|
| 960 |
|
---|
| 961 | // Any future notifications should just fill the buffer with silence
|
---|
| 962 | m_bFillNextNotificationWithSilence = TRUE;
|
---|
| 963 | }
|
---|
| 964 | else
|
---|
| 965 | {
|
---|
| 966 | // We are looping, so reset the file and fill the buffer with wav data
|
---|
| 967 | DWORD dwReadSoFar = dwBytesWrittenToBuffer; // From previous call above.
|
---|
| 968 | while( dwReadSoFar < dwDSLockedBufferSize )
|
---|
| 969 | {
|
---|
| 970 | // This will keep reading in until the buffer is full (for very short files).
|
---|
| 971 | if( FAILED( hr = m_pWaveFile->ResetFile() ) )
|
---|
| 972 | return DXUT_ERR( L"ResetFile", hr );
|
---|
| 973 |
|
---|
| 974 | if( FAILED( hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar,
|
---|
| 975 | dwDSLockedBufferSize - dwReadSoFar,
|
---|
| 976 | &dwBytesWrittenToBuffer ) ) )
|
---|
| 977 | return DXUT_ERR( L"Read", hr );
|
---|
| 978 |
|
---|
| 979 | dwReadSoFar += dwBytesWrittenToBuffer;
|
---|
| 980 | }
|
---|
| 981 | }
|
---|
| 982 | }
|
---|
| 983 |
|
---|
| 984 | // Unlock the DirectSound buffer
|
---|
| 985 | m_apDSBuffer[0]->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );
|
---|
| 986 |
|
---|
| 987 | // Figure out how much data has been played so far. When we have played
|
---|
| 988 | // past the end of the file, we will either need to start filling the
|
---|
| 989 | // buffer with silence or starting reading from the beginning of the file,
|
---|
| 990 | // depending if the user wants to loop the sound
|
---|
| 991 | if( FAILED( hr = m_apDSBuffer[0]->GetCurrentPosition( &dwCurrentPlayPos, NULL ) ) )
|
---|
| 992 | return DXUT_ERR( L"GetCurrentPosition", hr );
|
---|
| 993 |
|
---|
| 994 | // Check to see if the position counter looped
|
---|
| 995 | if( dwCurrentPlayPos < m_dwLastPlayPos )
|
---|
| 996 | dwPlayDelta = ( m_dwDSBufferSize - m_dwLastPlayPos ) + dwCurrentPlayPos;
|
---|
| 997 | else
|
---|
| 998 | dwPlayDelta = dwCurrentPlayPos - m_dwLastPlayPos;
|
---|
| 999 |
|
---|
| 1000 | m_dwPlayProgress += dwPlayDelta;
|
---|
| 1001 | m_dwLastPlayPos = dwCurrentPlayPos;
|
---|
| 1002 |
|
---|
| 1003 | // If we are now filling the buffer with silence, then we have found the end so
|
---|
| 1004 | // check to see if the entire sound has played, if it has then stop the buffer.
|
---|
| 1005 | if( m_bFillNextNotificationWithSilence )
|
---|
| 1006 | {
|
---|
| 1007 | // We don't want to cut off the sound before it's done playing.
|
---|
| 1008 | if( m_dwPlayProgress >= m_pWaveFile->GetSize() )
|
---|
| 1009 | {
|
---|
| 1010 | m_apDSBuffer[0]->Stop();
|
---|
| 1011 | }
|
---|
| 1012 | }
|
---|
| 1013 |
|
---|
| 1014 | // Update where the buffer will lock (for next time)
|
---|
| 1015 | m_dwNextWriteOffset += dwDSLockedBufferSize;
|
---|
| 1016 | m_dwNextWriteOffset %= m_dwDSBufferSize; // Circular buffer
|
---|
| 1017 |
|
---|
| 1018 | return S_OK;
|
---|
| 1019 | }
|
---|
| 1020 |
|
---|
| 1021 |
|
---|
| 1022 | //-----------------------------------------------------------------------------
|
---|
| 1023 | // Name: CStreamingSound::Reset()
|
---|
| 1024 | // Desc: Resets the sound so it will begin playing at the beginning
|
---|
| 1025 | //-----------------------------------------------------------------------------
|
---|
| 1026 | HRESULT CStreamingSound::Reset()
|
---|
| 1027 | {
|
---|
| 1028 | HRESULT hr;
|
---|
| 1029 |
|
---|
| 1030 | if( m_apDSBuffer[0] == NULL || m_pWaveFile == NULL )
|
---|
| 1031 | return CO_E_NOTINITIALIZED;
|
---|
| 1032 |
|
---|
| 1033 | m_dwLastPlayPos = 0;
|
---|
| 1034 | m_dwPlayProgress = 0;
|
---|
| 1035 | m_dwNextWriteOffset = 0;
|
---|
| 1036 | m_bFillNextNotificationWithSilence = FALSE;
|
---|
| 1037 |
|
---|
| 1038 | // Restore the buffer if it was lost
|
---|
| 1039 | BOOL bRestored;
|
---|
| 1040 | if( FAILED( hr = RestoreBuffer( m_apDSBuffer[0], &bRestored ) ) )
|
---|
| 1041 | return DXUT_ERR( L"RestoreBuffer", hr );
|
---|
| 1042 |
|
---|
| 1043 | if( bRestored )
|
---|
| 1044 | {
|
---|
| 1045 | // The buffer was restored, so we need to fill it with new data
|
---|
| 1046 | if( FAILED( hr = FillBufferWithSound( m_apDSBuffer[0], FALSE ) ) )
|
---|
| 1047 | return DXUT_ERR( L"FillBufferWithSound", hr );
|
---|
| 1048 | }
|
---|
| 1049 |
|
---|
| 1050 | m_pWaveFile->ResetFile();
|
---|
| 1051 |
|
---|
| 1052 | return m_apDSBuffer[0]->SetCurrentPosition( 0L );
|
---|
| 1053 | }
|
---|
| 1054 |
|
---|
| 1055 |
|
---|
| 1056 | //-----------------------------------------------------------------------------
|
---|
| 1057 | // Name: CWaveFile::CWaveFile()
|
---|
| 1058 | // Desc: Constructs the class. Call Open() to open a wave file for reading.
|
---|
| 1059 | // Then call Read() as needed. Calling the destructor or Close()
|
---|
| 1060 | // will close the file.
|
---|
| 1061 | //-----------------------------------------------------------------------------
|
---|
| 1062 | CWaveFile::CWaveFile()
|
---|
| 1063 | {
|
---|
| 1064 | m_pwfx = NULL;
|
---|
| 1065 | m_hmmio = NULL;
|
---|
| 1066 | m_pResourceBuffer = NULL;
|
---|
| 1067 | m_dwSize = 0;
|
---|
| 1068 | m_bIsReadingFromMemory = FALSE;
|
---|
| 1069 | }
|
---|
| 1070 |
|
---|
| 1071 |
|
---|
| 1072 | //-----------------------------------------------------------------------------
|
---|
| 1073 | // Name: CWaveFile::~CWaveFile()
|
---|
| 1074 | // Desc: Destructs the class
|
---|
| 1075 | //-----------------------------------------------------------------------------
|
---|
| 1076 | CWaveFile::~CWaveFile()
|
---|
| 1077 | {
|
---|
| 1078 | Close();
|
---|
| 1079 |
|
---|
| 1080 | if( !m_bIsReadingFromMemory )
|
---|
| 1081 | SAFE_DELETE_ARRAY( m_pwfx );
|
---|
| 1082 | }
|
---|
| 1083 |
|
---|
| 1084 |
|
---|
| 1085 | //-----------------------------------------------------------------------------
|
---|
| 1086 | // Name: CWaveFile::Open()
|
---|
| 1087 | // Desc: Opens a wave file for reading
|
---|
| 1088 | //-----------------------------------------------------------------------------
|
---|
| 1089 | HRESULT CWaveFile::Open( LPWSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags )
|
---|
| 1090 | {
|
---|
| 1091 | HRESULT hr;
|
---|
| 1092 |
|
---|
| 1093 | m_dwFlags = dwFlags;
|
---|
| 1094 | m_bIsReadingFromMemory = FALSE;
|
---|
| 1095 |
|
---|
| 1096 | if( m_dwFlags == WAVEFILE_READ )
|
---|
| 1097 | {
|
---|
| 1098 | if( strFileName == NULL )
|
---|
| 1099 | return E_INVALIDARG;
|
---|
| 1100 | SAFE_DELETE_ARRAY( m_pwfx );
|
---|
| 1101 |
|
---|
| 1102 | m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF | MMIO_READ );
|
---|
| 1103 |
|
---|
| 1104 | if( NULL == m_hmmio )
|
---|
| 1105 | {
|
---|
| 1106 | HRSRC hResInfo;
|
---|
| 1107 | HGLOBAL hResData;
|
---|
| 1108 | DWORD dwSize;
|
---|
| 1109 | VOID* pvRes;
|
---|
| 1110 |
|
---|
| 1111 | // Loading it as a file failed, so try it as a resource
|
---|
| 1112 | if( NULL == ( hResInfo = FindResource( NULL, strFileName, L"WAVE" ) ) )
|
---|
| 1113 | {
|
---|
| 1114 | if( NULL == ( hResInfo = FindResource( NULL, strFileName, L"WAV" ) ) )
|
---|
| 1115 | return DXUT_ERR( L"FindResource", E_FAIL );
|
---|
| 1116 | }
|
---|
| 1117 |
|
---|
| 1118 | if( NULL == ( hResData = LoadResource( GetModuleHandle(NULL), hResInfo ) ) )
|
---|
| 1119 | return DXUT_ERR( L"LoadResource", E_FAIL );
|
---|
| 1120 |
|
---|
| 1121 | if( 0 == ( dwSize = SizeofResource( GetModuleHandle(NULL), hResInfo ) ) )
|
---|
| 1122 | return DXUT_ERR( L"SizeofResource", E_FAIL );
|
---|
| 1123 |
|
---|
| 1124 | if( NULL == ( pvRes = LockResource( hResData ) ) )
|
---|
| 1125 | return DXUT_ERR( L"LockResource", E_FAIL );
|
---|
| 1126 |
|
---|
| 1127 | m_pResourceBuffer = new CHAR[ dwSize ];
|
---|
| 1128 | if( m_pResourceBuffer == NULL )
|
---|
| 1129 | return DXUT_ERR( L"new", E_OUTOFMEMORY );
|
---|
| 1130 | memcpy( m_pResourceBuffer, pvRes, dwSize );
|
---|
| 1131 |
|
---|
| 1132 | MMIOINFO mmioInfo;
|
---|
| 1133 | ZeroMemory( &mmioInfo, sizeof(mmioInfo) );
|
---|
| 1134 | mmioInfo.fccIOProc = FOURCC_MEM;
|
---|
| 1135 | mmioInfo.cchBuffer = dwSize;
|
---|
| 1136 | mmioInfo.pchBuffer = (CHAR*) m_pResourceBuffer;
|
---|
| 1137 |
|
---|
| 1138 | m_hmmio = mmioOpen( NULL, &mmioInfo, MMIO_ALLOCBUF | MMIO_READ );
|
---|
| 1139 | }
|
---|
| 1140 |
|
---|
| 1141 | if( FAILED( hr = ReadMMIO() ) )
|
---|
| 1142 | {
|
---|
| 1143 | // ReadMMIO will fail if its an not a wave file
|
---|
| 1144 | mmioClose( m_hmmio, 0 );
|
---|
| 1145 | return DXUT_ERR( L"ReadMMIO", hr );
|
---|
| 1146 | }
|
---|
| 1147 |
|
---|
| 1148 | if( FAILED( hr = ResetFile() ) )
|
---|
| 1149 | return DXUT_ERR( L"ResetFile", hr );
|
---|
| 1150 |
|
---|
| 1151 | // After the reset, the size of the wav file is m_ck.cksize so store it now
|
---|
| 1152 | m_dwSize = m_ck.cksize;
|
---|
| 1153 | }
|
---|
| 1154 | else
|
---|
| 1155 | {
|
---|
| 1156 | m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF |
|
---|
| 1157 | MMIO_READWRITE |
|
---|
| 1158 | MMIO_CREATE );
|
---|
| 1159 | if( NULL == m_hmmio )
|
---|
| 1160 | return DXUT_ERR( L"mmioOpen", E_FAIL );
|
---|
| 1161 |
|
---|
| 1162 | if( FAILED( hr = WriteMMIO( pwfx ) ) )
|
---|
| 1163 | {
|
---|
| 1164 | mmioClose( m_hmmio, 0 );
|
---|
| 1165 | return DXUT_ERR( L"WriteMMIO", hr );
|
---|
| 1166 | }
|
---|
| 1167 |
|
---|
| 1168 | if( FAILED( hr = ResetFile() ) )
|
---|
| 1169 | return DXUT_ERR( L"ResetFile", hr );
|
---|
| 1170 | }
|
---|
| 1171 |
|
---|
| 1172 | return hr;
|
---|
| 1173 | }
|
---|
| 1174 |
|
---|
| 1175 |
|
---|
| 1176 | //-----------------------------------------------------------------------------
|
---|
| 1177 | // Name: CWaveFile::OpenFromMemory()
|
---|
| 1178 | // Desc: copy data to CWaveFile member variable from memory
|
---|
| 1179 | //-----------------------------------------------------------------------------
|
---|
| 1180 | HRESULT CWaveFile::OpenFromMemory( BYTE* pbData, ULONG ulDataSize,
|
---|
| 1181 | WAVEFORMATEX* pwfx, DWORD dwFlags )
|
---|
| 1182 | {
|
---|
| 1183 | m_pwfx = pwfx;
|
---|
| 1184 | m_ulDataSize = ulDataSize;
|
---|
| 1185 | m_pbData = pbData;
|
---|
| 1186 | m_pbDataCur = m_pbData;
|
---|
| 1187 | m_bIsReadingFromMemory = TRUE;
|
---|
| 1188 |
|
---|
| 1189 | if( dwFlags != WAVEFILE_READ )
|
---|
| 1190 | return E_NOTIMPL;
|
---|
| 1191 |
|
---|
| 1192 | return S_OK;
|
---|
| 1193 | }
|
---|
| 1194 |
|
---|
| 1195 |
|
---|
| 1196 | //-----------------------------------------------------------------------------
|
---|
| 1197 | // Name: CWaveFile::ReadMMIO()
|
---|
| 1198 | // Desc: Support function for reading from a multimedia I/O stream.
|
---|
| 1199 | // m_hmmio must be valid before calling. This function uses it to
|
---|
| 1200 | // update m_ckRiff, and m_pwfx.
|
---|
| 1201 | //-----------------------------------------------------------------------------
|
---|
| 1202 | HRESULT CWaveFile::ReadMMIO()
|
---|
| 1203 | {
|
---|
| 1204 | MMCKINFO ckIn; // chunk info. for general use.
|
---|
| 1205 | PCMWAVEFORMAT pcmWaveFormat; // Temp PCM structure to load in.
|
---|
| 1206 |
|
---|
| 1207 | m_pwfx = NULL;
|
---|
| 1208 |
|
---|
| 1209 | if( ( 0 != mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) ) )
|
---|
| 1210 | return DXUT_ERR( L"mmioDescend", E_FAIL );
|
---|
| 1211 |
|
---|
| 1212 | // Check to make sure this is a valid wave file
|
---|
| 1213 | if( (m_ckRiff.ckid != FOURCC_RIFF) ||
|
---|
| 1214 | (m_ckRiff.fccType != mmioFOURCC('W', 'A', 'V', 'E') ) )
|
---|
| 1215 | return DXUT_ERR( L"mmioFOURCC", E_FAIL );
|
---|
| 1216 |
|
---|
| 1217 | // Search the input file for for the 'fmt ' chunk.
|
---|
| 1218 | ckIn.ckid = mmioFOURCC('f', 'm', 't', ' ');
|
---|
| 1219 | if( 0 != mmioDescend( m_hmmio, &ckIn, &m_ckRiff, MMIO_FINDCHUNK ) )
|
---|
| 1220 | return DXUT_ERR( L"mmioDescend", E_FAIL );
|
---|
| 1221 |
|
---|
| 1222 | // Expect the 'fmt' chunk to be at least as large as <PCMWAVEFORMAT>;
|
---|
| 1223 | // if there are extra parameters at the end, we'll ignore them
|
---|
| 1224 | if( ckIn.cksize < (LONG) sizeof(PCMWAVEFORMAT) )
|
---|
| 1225 | return DXUT_ERR( L"sizeof(PCMWAVEFORMAT)", E_FAIL );
|
---|
| 1226 |
|
---|
| 1227 | // Read the 'fmt ' chunk into <pcmWaveFormat>.
|
---|
| 1228 | if( mmioRead( m_hmmio, (HPSTR) &pcmWaveFormat,
|
---|
| 1229 | sizeof(pcmWaveFormat)) != sizeof(pcmWaveFormat) )
|
---|
| 1230 | return DXUT_ERR( L"mmioRead", E_FAIL );
|
---|
| 1231 |
|
---|
| 1232 | // Allocate the waveformatex, but if its not pcm format, read the next
|
---|
| 1233 | // word, and thats how many extra bytes to allocate.
|
---|
| 1234 | if( pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM )
|
---|
| 1235 | {
|
---|
| 1236 | m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) ];
|
---|
| 1237 | if( NULL == m_pwfx )
|
---|
| 1238 | return DXUT_ERR( L"m_pwfx", E_FAIL );
|
---|
| 1239 |
|
---|
| 1240 | // Copy the bytes from the pcm structure to the waveformatex structure
|
---|
| 1241 | memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
|
---|
| 1242 | m_pwfx->cbSize = 0;
|
---|
| 1243 | }
|
---|
| 1244 | else
|
---|
| 1245 | {
|
---|
| 1246 | // Read in length of extra bytes.
|
---|
| 1247 | WORD cbExtraBytes = 0L;
|
---|
| 1248 | if( mmioRead( m_hmmio, (CHAR*)&cbExtraBytes, sizeof(WORD)) != sizeof(WORD) )
|
---|
| 1249 | return DXUT_ERR( L"mmioRead", E_FAIL );
|
---|
| 1250 |
|
---|
| 1251 | m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) + cbExtraBytes ];
|
---|
| 1252 | if( NULL == m_pwfx )
|
---|
| 1253 | return DXUT_ERR( L"new", E_FAIL );
|
---|
| 1254 |
|
---|
| 1255 | // Copy the bytes from the pcm structure to the waveformatex structure
|
---|
| 1256 | memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
|
---|
| 1257 | m_pwfx->cbSize = cbExtraBytes;
|
---|
| 1258 |
|
---|
| 1259 | // Now, read those extra bytes into the structure, if cbExtraAlloc != 0.
|
---|
| 1260 | if( mmioRead( m_hmmio, (CHAR*)(((BYTE*)&(m_pwfx->cbSize))+sizeof(WORD)),
|
---|
| 1261 | cbExtraBytes ) != cbExtraBytes )
|
---|
| 1262 | {
|
---|
| 1263 | SAFE_DELETE( m_pwfx );
|
---|
| 1264 | return DXUT_ERR( L"mmioRead", E_FAIL );
|
---|
| 1265 | }
|
---|
| 1266 | }
|
---|
| 1267 |
|
---|
| 1268 | // Ascend the input file out of the 'fmt ' chunk.
|
---|
| 1269 | if( 0 != mmioAscend( m_hmmio, &ckIn, 0 ) )
|
---|
| 1270 | {
|
---|
| 1271 | SAFE_DELETE( m_pwfx );
|
---|
| 1272 | return DXUT_ERR( L"mmioAscend", E_FAIL );
|
---|
| 1273 | }
|
---|
| 1274 |
|
---|
| 1275 | return S_OK;
|
---|
| 1276 | }
|
---|
| 1277 |
|
---|
| 1278 |
|
---|
| 1279 | //-----------------------------------------------------------------------------
|
---|
| 1280 | // Name: CWaveFile::GetSize()
|
---|
| 1281 | // Desc: Retuns the size of the read access wave file
|
---|
| 1282 | //-----------------------------------------------------------------------------
|
---|
| 1283 | DWORD CWaveFile::GetSize()
|
---|
| 1284 | {
|
---|
| 1285 | return m_dwSize;
|
---|
| 1286 | }
|
---|
| 1287 |
|
---|
| 1288 |
|
---|
| 1289 | //-----------------------------------------------------------------------------
|
---|
| 1290 | // Name: CWaveFile::ResetFile()
|
---|
| 1291 | // Desc: Resets the internal m_ck pointer so reading starts from the
|
---|
| 1292 | // beginning of the file again
|
---|
| 1293 | //-----------------------------------------------------------------------------
|
---|
| 1294 | HRESULT CWaveFile::ResetFile()
|
---|
| 1295 | {
|
---|
| 1296 | if( m_bIsReadingFromMemory )
|
---|
| 1297 | {
|
---|
| 1298 | m_pbDataCur = m_pbData;
|
---|
| 1299 | }
|
---|
| 1300 | else
|
---|
| 1301 | {
|
---|
| 1302 | if( m_hmmio == NULL )
|
---|
| 1303 | return CO_E_NOTINITIALIZED;
|
---|
| 1304 |
|
---|
| 1305 | if( m_dwFlags == WAVEFILE_READ )
|
---|
| 1306 | {
|
---|
| 1307 | // Seek to the data
|
---|
| 1308 | if( -1 == mmioSeek( m_hmmio, m_ckRiff.dwDataOffset + sizeof(FOURCC),
|
---|
| 1309 | SEEK_SET ) )
|
---|
| 1310 | return DXUT_ERR( L"mmioSeek", E_FAIL );
|
---|
| 1311 |
|
---|
| 1312 | // Search the input file for the 'data' chunk.
|
---|
| 1313 | m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
|
---|
| 1314 | if( 0 != mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) )
|
---|
| 1315 | return DXUT_ERR( L"mmioDescend", E_FAIL );
|
---|
| 1316 | }
|
---|
| 1317 | else
|
---|
| 1318 | {
|
---|
| 1319 | // Create the 'data' chunk that holds the waveform samples.
|
---|
| 1320 | m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
|
---|
| 1321 | m_ck.cksize = 0;
|
---|
| 1322 |
|
---|
| 1323 | if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) )
|
---|
| 1324 | return DXUT_ERR( L"mmioCreateChunk", E_FAIL );
|
---|
| 1325 |
|
---|
| 1326 | if( 0 != mmioGetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
|
---|
| 1327 | return DXUT_ERR( L"mmioGetInfo", E_FAIL );
|
---|
| 1328 | }
|
---|
| 1329 | }
|
---|
| 1330 |
|
---|
| 1331 | return S_OK;
|
---|
| 1332 | }
|
---|
| 1333 |
|
---|
| 1334 |
|
---|
| 1335 | //-----------------------------------------------------------------------------
|
---|
| 1336 | // Name: CWaveFile::Read()
|
---|
| 1337 | // Desc: Reads section of data from a wave file into pBuffer and returns
|
---|
| 1338 | // how much read in pdwSizeRead, reading not more than dwSizeToRead.
|
---|
| 1339 | // This uses m_ck to determine where to start reading from. So
|
---|
| 1340 | // subsequent calls will be continue where the last left off unless
|
---|
| 1341 | // Reset() is called.
|
---|
| 1342 | //-----------------------------------------------------------------------------
|
---|
| 1343 | HRESULT CWaveFile::Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead )
|
---|
| 1344 | {
|
---|
| 1345 | if( m_bIsReadingFromMemory )
|
---|
| 1346 | {
|
---|
| 1347 | if( m_pbDataCur == NULL )
|
---|
| 1348 | return CO_E_NOTINITIALIZED;
|
---|
| 1349 | if( pdwSizeRead != NULL )
|
---|
| 1350 | *pdwSizeRead = 0;
|
---|
| 1351 |
|
---|
| 1352 | if( (BYTE*)(m_pbDataCur + dwSizeToRead) >
|
---|
| 1353 | (BYTE*)(m_pbData + m_ulDataSize) )
|
---|
| 1354 | {
|
---|
| 1355 | dwSizeToRead = m_ulDataSize - (DWORD)(m_pbDataCur - m_pbData);
|
---|
| 1356 | }
|
---|
| 1357 |
|
---|
| 1358 | CopyMemory( pBuffer, m_pbDataCur, dwSizeToRead );
|
---|
| 1359 |
|
---|
| 1360 | if( pdwSizeRead != NULL )
|
---|
| 1361 | *pdwSizeRead = dwSizeToRead;
|
---|
| 1362 |
|
---|
| 1363 | return S_OK;
|
---|
| 1364 | }
|
---|
| 1365 | else
|
---|
| 1366 | {
|
---|
| 1367 | MMIOINFO mmioinfoIn; // current status of m_hmmio
|
---|
| 1368 |
|
---|
| 1369 | if( m_hmmio == NULL )
|
---|
| 1370 | return CO_E_NOTINITIALIZED;
|
---|
| 1371 | if( pBuffer == NULL || pdwSizeRead == NULL )
|
---|
| 1372 | return E_INVALIDARG;
|
---|
| 1373 |
|
---|
| 1374 | if( pdwSizeRead != NULL )
|
---|
| 1375 | *pdwSizeRead = 0;
|
---|
| 1376 |
|
---|
| 1377 | if( 0 != mmioGetInfo( m_hmmio, &mmioinfoIn, 0 ) )
|
---|
| 1378 | return DXUT_ERR( L"mmioGetInfo", E_FAIL );
|
---|
| 1379 |
|
---|
| 1380 | UINT cbDataIn = dwSizeToRead;
|
---|
| 1381 | if( cbDataIn > m_ck.cksize )
|
---|
| 1382 | cbDataIn = m_ck.cksize;
|
---|
| 1383 |
|
---|
| 1384 | m_ck.cksize -= cbDataIn;
|
---|
| 1385 |
|
---|
| 1386 | for( DWORD cT = 0; cT < cbDataIn; cT++ )
|
---|
| 1387 | {
|
---|
| 1388 | // Copy the bytes from the io to the buffer.
|
---|
| 1389 | if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
|
---|
| 1390 | {
|
---|
| 1391 | if( 0 != mmioAdvance( m_hmmio, &mmioinfoIn, MMIO_READ ) )
|
---|
| 1392 | return DXUT_ERR( L"mmioAdvance", E_FAIL );
|
---|
| 1393 |
|
---|
| 1394 | if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
|
---|
| 1395 | return DXUT_ERR( L"mmioinfoIn.pchNext", E_FAIL );
|
---|
| 1396 | }
|
---|
| 1397 |
|
---|
| 1398 | // Actual copy.
|
---|
| 1399 | *((BYTE*)pBuffer+cT) = *((BYTE*)mmioinfoIn.pchNext);
|
---|
| 1400 | mmioinfoIn.pchNext++;
|
---|
| 1401 | }
|
---|
| 1402 |
|
---|
| 1403 | if( 0 != mmioSetInfo( m_hmmio, &mmioinfoIn, 0 ) )
|
---|
| 1404 | return DXUT_ERR( L"mmioSetInfo", E_FAIL );
|
---|
| 1405 |
|
---|
| 1406 | if( pdwSizeRead != NULL )
|
---|
| 1407 | *pdwSizeRead = cbDataIn;
|
---|
| 1408 |
|
---|
| 1409 | return S_OK;
|
---|
| 1410 | }
|
---|
| 1411 | }
|
---|
| 1412 |
|
---|
| 1413 |
|
---|
| 1414 | //-----------------------------------------------------------------------------
|
---|
| 1415 | // Name: CWaveFile::Close()
|
---|
| 1416 | // Desc: Closes the wave file
|
---|
| 1417 | //-----------------------------------------------------------------------------
|
---|
| 1418 | HRESULT CWaveFile::Close()
|
---|
| 1419 | {
|
---|
| 1420 | if( m_dwFlags == WAVEFILE_READ )
|
---|
| 1421 | {
|
---|
| 1422 | mmioClose( m_hmmio, 0 );
|
---|
| 1423 | m_hmmio = NULL;
|
---|
| 1424 | SAFE_DELETE_ARRAY( m_pResourceBuffer );
|
---|
| 1425 | }
|
---|
| 1426 | else
|
---|
| 1427 | {
|
---|
| 1428 | m_mmioinfoOut.dwFlags |= MMIO_DIRTY;
|
---|
| 1429 |
|
---|
| 1430 | if( m_hmmio == NULL )
|
---|
| 1431 | return CO_E_NOTINITIALIZED;
|
---|
| 1432 |
|
---|
| 1433 | if( 0 != mmioSetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
|
---|
| 1434 | return DXUT_ERR( L"mmioSetInfo", E_FAIL );
|
---|
| 1435 |
|
---|
| 1436 | // Ascend the output file out of the 'data' chunk -- this will cause
|
---|
| 1437 | // the chunk size of the 'data' chunk to be written.
|
---|
| 1438 | if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
|
---|
| 1439 | return DXUT_ERR( L"mmioAscend", E_FAIL );
|
---|
| 1440 |
|
---|
| 1441 | // Do this here instead...
|
---|
| 1442 | if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
|
---|
| 1443 | return DXUT_ERR( L"mmioAscend", E_FAIL );
|
---|
| 1444 |
|
---|
| 1445 | mmioSeek( m_hmmio, 0, SEEK_SET );
|
---|
| 1446 |
|
---|
| 1447 | if( 0 != (INT)mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) )
|
---|
| 1448 | return DXUT_ERR( L"mmioDescend", E_FAIL );
|
---|
| 1449 |
|
---|
| 1450 | m_ck.ckid = mmioFOURCC('f', 'a', 'c', 't');
|
---|
| 1451 |
|
---|
| 1452 | if( 0 == mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) )
|
---|
| 1453 | {
|
---|
| 1454 | DWORD dwSamples = 0;
|
---|
| 1455 | mmioWrite( m_hmmio, (HPSTR)&dwSamples, sizeof(DWORD) );
|
---|
| 1456 | mmioAscend( m_hmmio, &m_ck, 0 );
|
---|
| 1457 | }
|
---|
| 1458 |
|
---|
| 1459 | // Ascend the output file out of the 'RIFF' chunk -- this will cause
|
---|
| 1460 | // the chunk size of the 'RIFF' chunk to be written.
|
---|
| 1461 | if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
|
---|
| 1462 | return DXUT_ERR( L"mmioAscend", E_FAIL );
|
---|
| 1463 |
|
---|
| 1464 | mmioClose( m_hmmio, 0 );
|
---|
| 1465 | m_hmmio = NULL;
|
---|
| 1466 | }
|
---|
| 1467 |
|
---|
| 1468 | return S_OK;
|
---|
| 1469 | }
|
---|
| 1470 |
|
---|
| 1471 |
|
---|
| 1472 | //-----------------------------------------------------------------------------
|
---|
| 1473 | // Name: CWaveFile::WriteMMIO()
|
---|
| 1474 | // Desc: Support function for reading from a multimedia I/O stream
|
---|
| 1475 | // pwfxDest is the WAVEFORMATEX for this new wave file.
|
---|
| 1476 | // m_hmmio must be valid before calling. This function uses it to
|
---|
| 1477 | // update m_ckRiff, and m_ck.
|
---|
| 1478 | //-----------------------------------------------------------------------------
|
---|
| 1479 | HRESULT CWaveFile::WriteMMIO( WAVEFORMATEX *pwfxDest )
|
---|
| 1480 | {
|
---|
| 1481 | DWORD dwFactChunk; // Contains the actual fact chunk. Garbage until WaveCloseWriteFile.
|
---|
| 1482 | MMCKINFO ckOut1;
|
---|
| 1483 |
|
---|
| 1484 | dwFactChunk = (DWORD)-1;
|
---|
| 1485 |
|
---|
| 1486 | // Create the output file RIFF chunk of form type 'WAVE'.
|
---|
| 1487 | m_ckRiff.fccType = mmioFOURCC('W', 'A', 'V', 'E');
|
---|
| 1488 | m_ckRiff.cksize = 0;
|
---|
| 1489 |
|
---|
| 1490 | if( 0 != mmioCreateChunk( m_hmmio, &m_ckRiff, MMIO_CREATERIFF ) )
|
---|
| 1491 | return DXUT_ERR( L"mmioCreateChunk", E_FAIL );
|
---|
| 1492 |
|
---|
| 1493 | // We are now descended into the 'RIFF' chunk we just created.
|
---|
| 1494 | // Now create the 'fmt ' chunk. Since we know the size of this chunk,
|
---|
| 1495 | // specify it in the MMCKINFO structure so MMIO doesn't have to seek
|
---|
| 1496 | // back and set the chunk size after ascending from the chunk.
|
---|
| 1497 | m_ck.ckid = mmioFOURCC('f', 'm', 't', ' ');
|
---|
| 1498 | m_ck.cksize = sizeof(PCMWAVEFORMAT);
|
---|
| 1499 |
|
---|
| 1500 | if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) )
|
---|
| 1501 | return DXUT_ERR( L"mmioCreateChunk", E_FAIL );
|
---|
| 1502 |
|
---|
| 1503 | // Write the PCMWAVEFORMAT structure to the 'fmt ' chunk if its that type.
|
---|
| 1504 | if( pwfxDest->wFormatTag == WAVE_FORMAT_PCM )
|
---|
| 1505 | {
|
---|
| 1506 | if( mmioWrite( m_hmmio, (HPSTR) pwfxDest,
|
---|
| 1507 | sizeof(PCMWAVEFORMAT)) != sizeof(PCMWAVEFORMAT))
|
---|
| 1508 | return DXUT_ERR( L"mmioWrite", E_FAIL );
|
---|
| 1509 | }
|
---|
| 1510 | else
|
---|
| 1511 | {
|
---|
| 1512 | // Write the variable length size.
|
---|
| 1513 | if( (UINT)mmioWrite( m_hmmio, (HPSTR) pwfxDest,
|
---|
| 1514 | sizeof(*pwfxDest) + pwfxDest->cbSize ) !=
|
---|
| 1515 | ( sizeof(*pwfxDest) + pwfxDest->cbSize ) )
|
---|
| 1516 | return DXUT_ERR( L"mmioWrite", E_FAIL );
|
---|
| 1517 | }
|
---|
| 1518 |
|
---|
| 1519 | // Ascend out of the 'fmt ' chunk, back into the 'RIFF' chunk.
|
---|
| 1520 | if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
|
---|
| 1521 | return DXUT_ERR( L"mmioAscend", E_FAIL );
|
---|
| 1522 |
|
---|
| 1523 | // Now create the fact chunk, not required for PCM but nice to have. This is filled
|
---|
| 1524 | // in when the close routine is called.
|
---|
| 1525 | ckOut1.ckid = mmioFOURCC('f', 'a', 'c', 't');
|
---|
| 1526 | ckOut1.cksize = 0;
|
---|
| 1527 |
|
---|
| 1528 | if( 0 != mmioCreateChunk( m_hmmio, &ckOut1, 0 ) )
|
---|
| 1529 | return DXUT_ERR( L"mmioCreateChunk", E_FAIL );
|
---|
| 1530 |
|
---|
| 1531 | if( mmioWrite( m_hmmio, (HPSTR)&dwFactChunk, sizeof(dwFactChunk)) !=
|
---|
| 1532 | sizeof(dwFactChunk) )
|
---|
| 1533 | return DXUT_ERR( L"mmioWrite", E_FAIL );
|
---|
| 1534 |
|
---|
| 1535 | // Now ascend out of the fact chunk...
|
---|
| 1536 | if( 0 != mmioAscend( m_hmmio, &ckOut1, 0 ) )
|
---|
| 1537 | return DXUT_ERR( L"mmioAscend", E_FAIL );
|
---|
| 1538 |
|
---|
| 1539 | return S_OK;
|
---|
| 1540 | }
|
---|
| 1541 |
|
---|
| 1542 |
|
---|
| 1543 | //-----------------------------------------------------------------------------
|
---|
| 1544 | // Name: CWaveFile::Write()
|
---|
| 1545 | // Desc: Writes data to the open wave file
|
---|
| 1546 | //-----------------------------------------------------------------------------
|
---|
| 1547 | HRESULT CWaveFile::Write( UINT nSizeToWrite, BYTE* pbSrcData, UINT* pnSizeWrote )
|
---|
| 1548 | {
|
---|
| 1549 | UINT cT;
|
---|
| 1550 |
|
---|
| 1551 | if( m_bIsReadingFromMemory )
|
---|
| 1552 | return E_NOTIMPL;
|
---|
| 1553 | if( m_hmmio == NULL )
|
---|
| 1554 | return CO_E_NOTINITIALIZED;
|
---|
| 1555 | if( pnSizeWrote == NULL || pbSrcData == NULL )
|
---|
| 1556 | return E_INVALIDARG;
|
---|
| 1557 |
|
---|
| 1558 | *pnSizeWrote = 0;
|
---|
| 1559 |
|
---|
| 1560 | for( cT = 0; cT < nSizeToWrite; cT++ )
|
---|
| 1561 | {
|
---|
| 1562 | if( m_mmioinfoOut.pchNext == m_mmioinfoOut.pchEndWrite )
|
---|
| 1563 | {
|
---|
| 1564 | m_mmioinfoOut.dwFlags |= MMIO_DIRTY;
|
---|
| 1565 | if( 0 != mmioAdvance( m_hmmio, &m_mmioinfoOut, MMIO_WRITE ) )
|
---|
| 1566 | return DXUT_ERR( L"mmioAdvance", E_FAIL );
|
---|
| 1567 | }
|
---|
| 1568 |
|
---|
| 1569 | *((BYTE*)m_mmioinfoOut.pchNext) = *((BYTE*)pbSrcData+cT);
|
---|
| 1570 | (BYTE*)m_mmioinfoOut.pchNext++;
|
---|
| 1571 |
|
---|
| 1572 | (*pnSizeWrote)++;
|
---|
| 1573 | }
|
---|
| 1574 |
|
---|
| 1575 | return S_OK;
|
---|
| 1576 | }
|
---|