doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
win_snd.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 #include "../../idlib/precompiled.h"
29 #pragma hdrstop
30 
31 // DirectX SDK
32 #include <DxErr.h>
33 
34 #include <ks.h>
35 #include <ksmedia.h>
36 #include "../../sound/snd_local.h"
37 #include "win_local.h"
38 
39 #include "../../openal/idal.cpp"
40 
41 #define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
42 #define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
43 #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
44 
46 public:
47  idAudioBufferWIN32( LPDIRECTSOUNDBUFFER apDSBuffer, dword dwDSBufferSize, idWaveFile* pWaveFile=NULL );
49 
50  int FillBufferWithSound( LPDIRECTSOUNDBUFFER pDSB, bool bRepeatWavIfBufferLarger );
51 
52  bool Lock( void **pDSLockedBuffer, ulong *dwDSLockedBufferSize );
53  bool Unlock(void *pDSLockedBuffer, dword dwDSLockedBufferSize );
54  bool GetCurrentPosition( ulong *pdwCurrentWriteCursor );
55 
56  int Play( dword dwPriority=0, dword dwFlags=0 );
57  int Stop( void );
58  int Reset( void );
59  bool IsSoundPlaying( void );
60  void SetVolume( float x);
61 
63 private:
64  LPDIRECTSOUNDBUFFER m_apDSBuffer;
66 
67  int RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, bool* pbWasRestored );
68 };
69 
71 
72 public:
75 
76  bool Initialize( );
77  bool InitializeSpeakers( byte *buffer, int bufferSize, dword dwPrimaryFreq, dword dwPrimaryBitRate, dword dwSpeakers );
78 
79  void SetPrimaryBufferFormat( dword dwPrimaryFreq, dword dwPrimaryBitRate, dword dwSpeakers );
80 
81  int Create( idWaveFile* pWaveFile, idAudioBuffer** ppiab );
82  int Create( idAudioBuffer** ppSound, const char* strWaveFileName, dword dwCreationFlags = 0 );
83  int CreateFromMemory( idAudioBufferWIN32** ppSound, byte* pbData, ulong ulDataSize, waveformatextensible_t *pwfx, dword dwCreationFlags = 0 );
84 
85  bool Lock( void **pDSLockedBuffer, ulong *dwDSLockedBufferSize );
86  bool Unlock( void *pDSLockedBuffer, dword dwDSLockedBufferSize );
87  bool GetCurrentPosition( ulong *pdwCurrentWriteCursor );
88 
89  int GetNumberOfSpeakers() { return numSpeakers; }
91 
92  // WIN32 driver doesn't support write API
93  bool Flush( void ) { return true; }
94  void Write( bool ) { }
95  short* GetMixBuffer( void ) { return NULL; }
96 
97 private:
98  LPDIRECTSOUND m_pDS;
99  LPDIRECTSOUNDBUFFER pDSBPrimary;
101 
104  int bufferSize; // allocate buffer handed over to DirectSound
105  int blockAlign; // channels * bits per sample / 8: sound frame size
106 };
107 
110 
111 /*
112 ================
113 idAudioHardwareWIN32::idAudioHardware
114 ================
115 */
117  m_pDS = NULL;
118  pDSBPrimary = NULL;
119  speakers = NULL;
120 }
121 
122 /*
123 ================
124 idAudioHardwareWIN32::~idAudioHardware
125 ================
126 */
130  SAFE_RELEASE( m_pDS );
131 }
132 
133 /*
134 ===============
135 idAudioHardwareWIN32::Initialize
136 ===============
137 */
139  int hr;
140 
141  bufferSize = 0;
142  numSpeakers = 0;
143  blockAlign = 0;
144 
145  SAFE_RELEASE( m_pDS );
146 
147  // Create IDirectSound using the primary sound device
148  if( FAILED( hr = DirectSoundCreate( NULL, &m_pDS, NULL ) )) {
149  return false;
150  }
151 
152  // Set primary buffer format
154  return true;
155 }
156 
157 /*
158 ===============
159 idAudioHardwareWIN32::InitializeSpeakers
160 ===============
161 */
162 bool idAudioHardwareWIN32::InitializeSpeakers( byte *speakerData, int bufferSize, dword dwPrimaryFreq, dword dwPrimaryBitRate, dword dwSpeakers ) {
163  if ( dwSpeakers == 2 ) {
164  WAVEFORMATEXTENSIBLE wfx;
165  ZeroMemory( &wfx, sizeof(WAVEFORMATEXTENSIBLE) );
166  wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
167  wfx.Format.nChannels = 2;
168  wfx.Format.nSamplesPerSec = dwPrimaryFreq;
169  wfx.Format.wBitsPerSample = dwPrimaryBitRate;
170  wfx.Format.nBlockAlign = wfx.Format.wBitsPerSample / 8 * wfx.Format.nChannels;
171  wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign;
172  wfx.Format.cbSize = sizeof(WAVEFORMATEX);
173 
174  CreateFromMemory( &speakers, speakerData, bufferSize, (waveformatextensible_t *)&wfx );
175 
176  common->Printf("sound: STEREO\n");
177  } else {
178  WAVEFORMATEXTENSIBLE waveFormatPCMEx;
179  ZeroMemory( &waveFormatPCMEx, sizeof(WAVEFORMATEXTENSIBLE) );
180 
181  waveFormatPCMEx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
182  waveFormatPCMEx.Format.nChannels = 6;
183  waveFormatPCMEx.Format.nSamplesPerSec = dwPrimaryFreq;
184  waveFormatPCMEx.Format.wBitsPerSample = dwPrimaryBitRate;
185  waveFormatPCMEx.Format.nBlockAlign = waveFormatPCMEx.Format.wBitsPerSample / 8 * waveFormatPCMEx.Format.nChannels;
186  waveFormatPCMEx.Format.nAvgBytesPerSec = waveFormatPCMEx.Format.nSamplesPerSec * waveFormatPCMEx.Format.nBlockAlign;
187  waveFormatPCMEx.dwChannelMask = KSAUDIO_SPEAKER_5POINT1;
188  // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT |
189  // SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY |
190  // SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT
191  waveFormatPCMEx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; // Specify PCM
192  waveFormatPCMEx.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE);
193  waveFormatPCMEx.Samples.wValidBitsPerSample = 16;
194 
195  CreateFromMemory( &speakers, speakerData, bufferSize, (waveformatextensible_t *)&waveFormatPCMEx );
196 
197  common->Printf("sound: MULTICHANNEL\n");
198  }
199 
200  if (!speakers) {
201  return false;
202  }
203 
204  speakers->Play(0,DSBPLAY_LOOPING);
205 
206  return true;
207 }
208 
209 /*
210 ===============
211 idAudioHardwareWIN32::SetPrimaryBufferFormat
212 Set primary buffer to a specified format
213 For example, to set the primary buffer format to 22kHz stereo, 16-bit
214 then: dwPrimaryChannels = 2
215  dwPrimaryFreq = 22050,
216  dwPrimaryBitRate = 16
217 ===============
218 */
219 void idAudioHardwareWIN32::SetPrimaryBufferFormat( dword dwPrimaryFreq, dword dwPrimaryBitRate, dword dwSpeakers ) {
220  HRESULT hr;
221 
222  if( m_pDS == NULL ) {
223  return;
224  }
225 
226  ulong cfgSpeakers;
227  m_pDS->GetSpeakerConfig( &cfgSpeakers );
228 
229  DSCAPS dscaps;
230  dscaps.dwSize = sizeof(DSCAPS);
231  m_pDS->GetCaps(&dscaps);
232 
233  if (dscaps.dwFlags & DSCAPS_EMULDRIVER) {
234  return;
235  }
236 
237  // Get the primary buffer
238  DSBUFFERDESC dsbd;
239  ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
240  dsbd.dwSize = sizeof(DSBUFFERDESC);
241  dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
242  dsbd.dwBufferBytes = 0;
243  dsbd.lpwfxFormat = NULL;
244 
245  // Obtain write-primary cooperative level.
246  if( FAILED( hr = m_pDS->SetCooperativeLevel(win32.hWnd, DSSCL_PRIORITY ) ) ) {
247  DXTRACE_ERR( TEXT("SetPrimaryBufferFormat"), hr );
248  return;
249  }
250 
251  if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBPrimary, NULL ) ) ) {
252  return;
253  }
254 
255  if ( dwSpeakers == 6 && (cfgSpeakers == DSSPEAKER_5POINT1 || cfgSpeakers == DSSPEAKER_SURROUND) ) {
256  WAVEFORMATEXTENSIBLE waveFormatPCMEx;
257  ZeroMemory( &waveFormatPCMEx, sizeof(WAVEFORMATEXTENSIBLE) );
258 
259  waveFormatPCMEx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
260  waveFormatPCMEx.Format.nChannels = 6;
261  waveFormatPCMEx.Format.nSamplesPerSec = dwPrimaryFreq;
262  waveFormatPCMEx.Format.wBitsPerSample = (WORD) dwPrimaryBitRate;
263  waveFormatPCMEx.Format.nBlockAlign = waveFormatPCMEx.Format.wBitsPerSample / 8 * waveFormatPCMEx.Format.nChannels;
264  waveFormatPCMEx.Format.nAvgBytesPerSec = waveFormatPCMEx.Format.nSamplesPerSec * waveFormatPCMEx.Format.nBlockAlign;
265  waveFormatPCMEx.dwChannelMask = KSAUDIO_SPEAKER_5POINT1;
266  // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT |
267  // SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY |
268  // SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT
269  waveFormatPCMEx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; // Specify PCM
270  waveFormatPCMEx.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE);
271  waveFormatPCMEx.Samples.wValidBitsPerSample = 16;
272 
273  if( FAILED( hr = pDSBPrimary->SetFormat((WAVEFORMATEX*)&waveFormatPCMEx) ) ) {
274  DXTRACE_ERR( TEXT("SetPrimaryBufferFormat"), hr );
275  return;
276  }
277  numSpeakers = 6; // force it to think 5.1
278  blockAlign = waveFormatPCMEx.Format.nBlockAlign;
279  } else {
280  if (dwSpeakers == 6) {
281  common->Printf("sound: hardware reported unable to use multisound, defaulted to stereo\n");
282  }
283  WAVEFORMATEX wfx;
284  ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
285  wfx.wFormatTag = WAVE_FORMAT_PCM;
286  wfx.nChannels = 2;
287  wfx.nSamplesPerSec = dwPrimaryFreq;
288  wfx.wBitsPerSample = (WORD) dwPrimaryBitRate;
289  wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
290  wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
291  wfx.cbSize = sizeof(WAVEFORMATEX);
292 
293  if( FAILED( hr = pDSBPrimary->SetFormat(&wfx) ) ) {
294  return;
295  }
296  numSpeakers = 2; // force it to think stereo
297  blockAlign = wfx.nBlockAlign;
298  }
299 
300  byte *speakerData;
302  speakerData = (byte *)Mem_Alloc( bufferSize );
303  memset( speakerData, 0, bufferSize );
304 
305  InitializeSpeakers( speakerData, bufferSize, dwPrimaryFreq, dwPrimaryBitRate, numSpeakers );
306 }
307 
308 /*
309 ===============
310 idAudioHardwareWIN32::Create
311 ===============
312 */
314  const char* strWaveFileName,
315  dword dwCreationFlags ) {
316  int hr;
317  LPDIRECTSOUNDBUFFER apDSBuffer = NULL;
318  dword dwDSBufferSize = NULL;
319  idWaveFile* pWaveFile = NULL;
320 
321  if( m_pDS == NULL )
322  return -1;
323  if( strWaveFileName == NULL || ppSound == NULL )
324  return -1;
325 
326  pWaveFile = new idWaveFile();
327 
328  pWaveFile->Open( strWaveFileName, NULL );
329 
330  if( pWaveFile->GetOutputSize() == 0 ) {
331  // Wave is blank, so don't create it.
332  hr = E_FAIL;
333  goto LFail;
334  }
335 
336  // Make the DirectSound buffer the same size as the wav file
337  dwDSBufferSize = pWaveFile->GetOutputSize();
338 
339  // Create the direct sound buffer, and only request the flags needed
340  // since each requires some overhead and limits if the buffer can
341  // be hardware accelerated
342  DSBUFFERDESC dsbd;
343  memset( &dsbd, 0, sizeof(DSBUFFERDESC) );
344  dsbd.dwSize = sizeof(DSBUFFERDESC);
345  dsbd.dwFlags = dwCreationFlags;
346  dsbd.dwBufferBytes = dwDSBufferSize;
347  dsbd.guid3DAlgorithm = GUID_NULL;
348  dsbd.lpwfxFormat = (WAVEFORMATEX*)&pWaveFile->mpwfx;
349 
350  // DirectSound is only guarenteed to play PCM data. Other
351  // formats may or may not work depending the sound card driver.
352  if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer, NULL ) ) )
353  return -1;
354 
355  // Create the sound
356  *ppSound = new idAudioBufferWIN32( apDSBuffer, dwDSBufferSize, pWaveFile );
357 
358  pWaveFile->Close();
359 
360  return 0;
361 
362 LFail:
363  // Cleanup
364  SAFE_DELETE( pWaveFile );
365  return -1;
366 }
367 
368 /*
369 ===============
370 idAudioHardwareWIN32::Create
371 ===============
372 */
374  int hr;
375  LPDIRECTSOUNDBUFFER apDSBuffer = NULL;
376  dword dwDSBufferSize = NULL;
377 
378  if( m_pDS == NULL )
379  return -1;
380 
381  if( pWaveFile == NULL )
382  return -1;
383 
384  *ppiab = NULL;
385 
386  if( pWaveFile->GetOutputSize() == 0 ) {
387  // Wave is blank, so don't create it.
388  hr = E_FAIL;
389  goto LFail;
390  }
391 
392  // Make the DirectSound buffer the same size as the wav file
393  dwDSBufferSize = pWaveFile->GetOutputSize();
394 
395  // Create the direct sound buffer, and only request the flags needed
396  // since each requires some overhead and limits if the buffer can
397  // be hardware accelerated
398  DSBUFFERDESC dsbd;
399  memset( &dsbd, 0, sizeof(DSBUFFERDESC) );
400  dsbd.dwSize = sizeof(DSBUFFERDESC);
401  dsbd.dwFlags = 0;
402  dsbd.dwBufferBytes = dwDSBufferSize;
403  dsbd.guid3DAlgorithm = GUID_NULL;
404  dsbd.lpwfxFormat = (WAVEFORMATEX*)&pWaveFile->mpwfx;
405 
406  // DirectSound is only guarenteed to play PCM data. Other
407  // formats may or may not work depending the sound card driver.
408  if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer, NULL ) ) )
409  return -1;
410 
411  // Create the sound
412  *ppiab = new idAudioBufferWIN32( apDSBuffer, dwDSBufferSize, pWaveFile );
413 
414  return 0;
415 
416 LFail:
417  // Cleanup
418  SAFE_DELETE( pWaveFile );
419  return -1;
420 }
421 
422 //-----------------------------------------------------------------------------
423 // Name: idAudioHardwareWIN32::CreateFromMemory()
424 // Desc:
425 //-----------------------------------------------------------------------------
427  byte* pbData,
428  ulong ulDataSize,
430  dword dwCreationFlags ) {
431  int hr;
432  LPDIRECTSOUNDBUFFER apDSBuffer = NULL;
433  dword dwDSBufferSize = NULL;
434  idWaveFile* pWaveFile = NULL;
435 
436  if( m_pDS == NULL )
437  return -1;
438  if( pbData == NULL || ppSound == NULL )
439  return -1;
440 
441  pWaveFile = new idWaveFile();
442 
443  pWaveFile->OpenFromMemory( (short *)pbData, ulDataSize, (waveformatextensible_t *)pwfx);
444 
445 
446  // Make the DirectSound buffer the same size as the wav file
447  dwDSBufferSize = ulDataSize;
448 
449  // Create the direct sound buffer, and only request the flags needed
450  // since each requires some overhead and limits if the buffer can
451  // be hardware accelerated
452  DSBUFFERDESC dsbd;
453  memset( &dsbd, 0, sizeof(DSBUFFERDESC) );
454  dsbd.dwSize = sizeof(DSBUFFERDESC);
455  dsbd.dwFlags = dwCreationFlags | DSBCAPS_GETCURRENTPOSITION2;
456  dsbd.dwBufferBytes = dwDSBufferSize;
457  dsbd.guid3DAlgorithm = GUID_NULL;
458  dsbd.lpwfxFormat = (WAVEFORMATEX *)pwfx;
459 
460  if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer, NULL ) ) )
461  return -1;
462 
463  // Create the sound
464  *ppSound = new idAudioBufferWIN32( apDSBuffer, dwDSBufferSize, pWaveFile );
465 
466  return S_OK;
467 }
468 
469 /*
470 ===============
471 idAudioHardwareWIN32::Lock
472 ===============
473 */
474 bool idAudioHardwareWIN32::Lock( void **pDSLockedBuffer, ulong *dwDSLockedBufferSize ) {
475  if (speakers) {
476  return speakers->Lock( pDSLockedBuffer, dwDSLockedBufferSize );
477  }
478  return false;
479 }
480 
481 /*
482 ===============
483 idAudioHardwareWIN32::Unlock
484 ===============
485 */
486 bool idAudioHardwareWIN32::Unlock(void *pDSLockedBuffer, dword dwDSLockedBufferSize ) {
487  if (speakers) {
488  return speakers->Unlock( pDSLockedBuffer, dwDSLockedBufferSize );
489  }
490  return false;
491 }
492 
493 /*
494 ===============
495 idAudioHardwareWIN32::GetCurrentPosition
496 ===============
497 */
498 bool idAudioHardwareWIN32::GetCurrentPosition( ulong *pdwCurrentWriteCursor ) {
499  if (speakers) {
500  return speakers->GetCurrentPosition( pdwCurrentWriteCursor );
501  }
502  return false;
503 }
504 
505 static HMODULE hOpenAL = NULL;
506 
507 /*
508 ===============
509 Sys_LoadOpenAL
510 ===============
511 */
512 bool Sys_LoadOpenAL( void ) {
513 #if ID_OPENAL
514  const char *sym;
515 
516  if ( hOpenAL ) {
517  return true;
518  }
519 
520  hOpenAL = LoadLibrary( idSoundSystemLocal::s_libOpenAL.GetString() );
521  if ( !hOpenAL ) {
522  common->Warning( "LoadLibrary %s failed.", idSoundSystemLocal::s_libOpenAL.GetString() );
523  return false;
524  }
525  if ( ( sym = InitializeIDAL( hOpenAL ) ) ) {
526  common->Warning( "GetProcAddress %s failed.", sym );
527  FreeLibrary( hOpenAL );
528  hOpenAL = NULL;
529  return false;
530  }
531  return true;
532 #else
533  return false;
534 #endif
535 }
536 
537 /*
538 ===============
539 Sys_FreeOpenAL
540 ===============
541 */
542 void Sys_FreeOpenAL( void ) {
543  if ( hOpenAL ) {
544  FreeLibrary( hOpenAL );
545  hOpenAL = NULL;
546  }
547 }
548 
549 /*
550 ===============
551 idAudioBufferWIN32::idAudioBuffer
552 ===============
553 */
554 idAudioBufferWIN32::idAudioBufferWIN32( LPDIRECTSOUNDBUFFER apDSBuffer, dword dwDSBufferSize, idWaveFile* pWaveFile ) {
555 
556  m_apDSBuffer = apDSBuffer;
557 
558  m_dwDSBufferSize = dwDSBufferSize;
559  m_pWaveFile = pWaveFile;
560 
561  if (pWaveFile) {
563 
564  m_apDSBuffer->SetCurrentPosition(0);
565  }
566 }
567 
568 /*
569 ===============
570 idAudioBufferWIN32::~idAudioBuffer
571 ===============
572 */
576  m_pWaveFile = NULL;
577  m_apDSBuffer = NULL;
578 }
579 
580 /*
581 ===============
582 idAudioBufferWIN32::FillBufferWithSound
583 ===============
584 */
585 int idAudioBufferWIN32::FillBufferWithSound( LPDIRECTSOUNDBUFFER pDSB, bool bRepeatWavIfBufferLarger ) {
586  int hr;
587  void* pDSLockedBuffer = NULL; // Pointer to locked buffer memory
588  ulong dwDSLockedBufferSize = 0; // Size of the locked DirectSound buffer
589  int dwWavDataRead = 0; // Amount of data read from the wav file
590 
591  if( pDSB == NULL )
592  return -1;
593 
594  // we may not even have a wavefile
595  if (m_pWaveFile==NULL) {
596  return -1;
597  }
598 
599  // Make sure we have focus, and we didn't just switch in from
600  // an app which had a DirectSound device
601  if( FAILED( hr = RestoreBuffer( pDSB, NULL ) ) ) {
602  DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
603  return -1;
604  }
605 
606  // Lock the buffer down
607  if( FAILED( hr = pDSB->Lock( 0, m_dwDSBufferSize, &pDSLockedBuffer, &dwDSLockedBufferSize, NULL, NULL, 0L ) ) ) {
608  DXTRACE_ERR( TEXT("Lock"), hr );
609  return -1;
610  }
611 
612  // Reset the wave file to the beginning
614 
615  if( FAILED( hr = m_pWaveFile->Read( (byte*) pDSLockedBuffer, dwDSLockedBufferSize, &dwWavDataRead ) ) ) {
616  return DXTRACE_ERR( TEXT("Read"), hr );
617  }
618 
619  if( dwWavDataRead == 0 ) {
620  // Wav is blank, so just fill with silence
621  memset( pDSLockedBuffer, (byte)(m_pWaveFile->mpwfx.Format.wBitsPerSample == 8 ? 128 : 0 ), dwDSLockedBufferSize );
622  } else if( dwWavDataRead < (int)dwDSLockedBufferSize ) {
623  // If the wav file was smaller than the DirectSound buffer,
624  // we need to fill the remainder of the buffer with data
625  if( bRepeatWavIfBufferLarger ) {
626  // Reset the file and fill the buffer with wav data
627  int dwReadSoFar = dwWavDataRead; // From previous call above.
628  while( dwReadSoFar < (int)dwDSLockedBufferSize ) {
629  // This will keep reading in until the buffer is full
630  // for very short files
631  if( FAILED( hr = m_pWaveFile->ResetFile() ) ) {
632  return DXTRACE_ERR( TEXT("ResetFile"), hr );
633  }
634 
635  hr = m_pWaveFile->Read( (byte*)pDSLockedBuffer + dwReadSoFar, dwDSLockedBufferSize - dwReadSoFar, &dwWavDataRead );
636  if( FAILED(hr) ) {
637  return DXTRACE_ERR( TEXT("Read"), hr );
638  }
639 
640  dwReadSoFar += dwWavDataRead;
641  }
642  } else {
643  // Don't repeat the wav file, just fill in silence
644  memset( (byte*) pDSLockedBuffer + dwWavDataRead, (byte)(m_pWaveFile->mpwfx.Format.wBitsPerSample == 8 ? 128 : 0 ), dwDSLockedBufferSize - dwWavDataRead);
645  }
646  }
647 
648  // Unlock the buffer, we don't need it anymore.
649  pDSB->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );
650 
651  return S_OK;
652 }
653 
654 /*
655 ===============
656 idAudioBufferWIN32::RestoreBuffer
657 Desc: Restores the lost buffer. *pbWasRestored returns true if the buffer was
658  restored. It can also NULL if the information is not needed.
659 ===============
660 */
661 int idAudioBufferWIN32::RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, bool* pbWasRestored ) {
662  int hr;
663 
664  if( pDSB == NULL ) {
665  return -1;
666  }
667  if( pbWasRestored ) {
668  *pbWasRestored = false;
669  }
670 
671  ulong dwStatus;
672  if( FAILED( hr = pDSB->GetStatus( &dwStatus ) ) ) {
673  return DXTRACE_ERR( TEXT("GetStatus"), hr );
674  }
675 
676  if( dwStatus & DSBSTATUS_BUFFERLOST ) {
677  // Since the app could have just been activated, then
678  // DirectSound may not be giving us control yet, so
679  // the restoring the buffer may fail.
680  // If it does, sleep until DirectSound gives us control.
681  do {
682  hr = pDSB->Restore();
683  if( hr == DSERR_BUFFERLOST ) {
684  Sleep( 10 );
685  }
686  hr = pDSB->Restore();
687  } while( hr );
688 
689  if( pbWasRestored != NULL ) {
690  *pbWasRestored = true;
691  }
692 
693  return S_OK;
694  } else {
695  return S_FALSE;
696  }
697 }
698 
699 /*
700 ===============
701 idAudioBufferWIN32::Play
702 Desc: Plays the sound using voice management flags. Pass in DSBPLAY_LOOPING
703  in the dwFlags to loop the sound
704 ===============
705 */
706 int idAudioBufferWIN32::Play( dword dwPriority, dword dwFlags ) {
707  int hr;
708  bool bRestored;
709 
710  if( m_apDSBuffer == NULL ) {
711  return -1;
712  }
713 
714  // Restore the buffer if it was lost
715  if( FAILED( hr = RestoreBuffer( m_apDSBuffer, &bRestored ) ) ) {
716  common->Error( TEXT("RestoreBuffer"), hr );
717  }
718 
719  if( bRestored ) {
720  // The buffer was restored, so we need to fill it with new data
721  if( FAILED( hr = FillBufferWithSound( m_apDSBuffer, false ) ) ) {
722  common->Error( TEXT("FillBufferWithSound"), hr );
723  }
724 
725  // Make DirectSound do pre-processing on sound effects
726  Reset();
727  }
728 
729  m_apDSBuffer->Play( 0, dwPriority, dwFlags );
730  return 0;
731 }
732 
733 /*
734 ===============
735 idAudioBufferWIN32::Stop
736 Desc: Stops the sound from playing
737 ===============
738 */
740  if( this == NULL || m_apDSBuffer == NULL ) {
741  return -1;
742  }
743 
744  m_apDSBuffer->Stop();
745 
746  return 0;
747 }
748 
749 /*
750 ===============
751 idAudioBufferWIN32::Reset
752 Desc: Reset all of the sound buffers
753 ===============
754 */
756  if( m_apDSBuffer == NULL ) {
757  return -1;
758  }
759 
760  m_apDSBuffer->SetCurrentPosition( 0 );
761 
762  return 0;
763 }
764 
765 /*
766 ===============
767 idAudioBufferWIN32::IsSoundPlaying
768 Desc: Checks to see if a buffer is playing and returns true if it
769 ===============
770 */
772  if( m_apDSBuffer == NULL ) {
773  return false;
774  }
775 
776  if( m_apDSBuffer ) {
777  ulong dwStatus = 0;
778  m_apDSBuffer->GetStatus( &dwStatus );
779  if ( dwStatus & DSBSTATUS_PLAYING ) {
780  return true;
781  }
782  }
783  return false;
784 }
785 
786 /*
787 ===============
788 idAudioBufferWIN32::Lock
789 ===============
790 */
791 bool idAudioBufferWIN32::Lock( void **pDSLockedBuffer, ulong *dwDSLockedBufferSize ) {
792  int hr;
793  // Restore the buffer if it was lost
794  bool bRestored;
795  if( FAILED( hr = RestoreBuffer( m_apDSBuffer, &bRestored ) ) ) {
796  return false;
797  }
798 
799  // Lock the DirectSound buffer
800  if( FAILED( hr = m_apDSBuffer->Lock( 0, m_dwDSBufferSize, pDSLockedBuffer, dwDSLockedBufferSize, NULL, NULL, 0 ) ) ) {
801  return false;
802  }
803  return true;
804 }
805 
806 /*
807 ===============
808 idAudioBufferWIN32::Unlock
809 ===============
810 */
811 bool idAudioBufferWIN32::Unlock(void *pDSLockedBuffer, dword dwDSLockedBufferSize ) {
812  // Unlock the DirectSound buffer
813  m_apDSBuffer->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );
814  return true;
815 }
816 
817 /*
818 ===============
819 idAudioBufferWIN32::GetCurrentPosition
820 ===============
821 */
822 bool idAudioBufferWIN32::GetCurrentPosition( ulong *pdwCurrentWriteCursor ) {
823  int hr;
824 
825  // Make sure we have focus, and we didn't just switch in from
826  // an app which had a DirectSound device
827  if( FAILED( hr = RestoreBuffer( m_apDSBuffer, NULL ) ) ) {
828  DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
829  return false;
830  }
831 
832  if( FAILED( hr = m_apDSBuffer->GetCurrentPosition( NULL, pdwCurrentWriteCursor ) ) ) {
833  return false;
834  }
835  return true;
836 }
837 
838 /*
839 ===============
840 idAudioBufferWIN32::SetVolume
841 ===============
842 */
844  if (m_apDSBuffer) {
845  m_apDSBuffer->SetVolume(x);
846  }
847 }
unsigned int dword
Definition: Lib.h:77
waveformatextensible_t mpwfx
Definition: snd_local.h:198
bool Sys_LoadOpenAL(void)
Definition: win_snd.cpp:512
bool Lock(void **pDSLockedBuffer, ulong *dwDSLockedBufferSize)
Definition: win_snd.cpp:791
static idCVar s_numberOfSpeakers
Definition: snd_local.h:802
const int MIXBUFFER_SAMPLES
Definition: Simd.h:84
void Sys_FreeOpenAL(void)
Definition: win_snd.cpp:542
int FillBufferWithSound(LPDIRECTSOUNDBUFFER pDSB, bool bRepeatWavIfBufferLarger)
Definition: win_snd.cpp:585
static idCVar s_libOpenAL
Definition: snd_local.h:806
LPDIRECTSOUNDBUFFER pDSBPrimary
Definition: win_snd.cpp:99
int Stop(void)
Definition: win_snd.cpp:739
bool GetCurrentPosition(ulong *pdwCurrentWriteCursor)
Definition: win_snd.cpp:822
void Sleep(const int time)
GLenum GLint x
Definition: glext.h:2849
void Write(bool)
Definition: win_snd.cpp:94
const char * InitializeIDAL(HMODULE h)
Definition: idal.cpp:36
int Open(const char *strFileName, waveformatex_t *pwfx=NULL)
bool GetCurrentPosition(ulong *pdwCurrentWriteCursor)
Definition: win_snd.cpp:498
const int ROOM_SLICES_IN_BUFFER
Definition: snd_local.h:70
int Create(idWaveFile *pWaveFile, idAudioBuffer **ppiab)
Definition: win_snd.cpp:373
idWaveFile * m_pWaveFile
Definition: win_snd.cpp:62
int OpenFromMemory(short *pbData, int ulDataSize, waveformatextensible_t *pwfx)
int GetNumberOfSpeakers()
Definition: win_snd.cpp:89
short * GetMixBuffer(void)
Definition: win_snd.cpp:95
idCommon * common
Definition: Common.cpp:206
bool Unlock(void *pDSLockedBuffer, dword dwDSLockedBufferSize)
Definition: win_snd.cpp:811
#define NULL
Definition: Lib.h:88
int Close(void)
GLuint buffer
Definition: glext.h:3108
#define SAFE_RELEASE(p)
Definition: win_snd.cpp:43
Definition: eax4.h:1413
int Play(dword dwPriority=0, dword dwFlags=0)
Definition: win_snd.cpp:706
int Read(byte *pBuffer, int dwSizeToRead, int *pdwSizeRead)
word wBitsPerSample
Definition: snd_local.h:102
virtual void Printf(const char *fmt,...) id_attribute((format(printf
bool Lock(void **pDSLockedBuffer, ulong *dwDSLockedBufferSize)
Definition: win_snd.cpp:474
dword m_dwDSBufferSize
Definition: win_snd.cpp:65
LPDIRECTSOUND m_pDS
Definition: win_snd.cpp:98
bool IsSoundPlaying(void)
Definition: win_snd.cpp:771
int CreateFromMemory(idAudioBufferWIN32 **ppSound, byte *pbData, ulong ulDataSize, waveformatextensible_t *pwfx, dword dwCreationFlags=0)
Definition: win_snd.cpp:426
#define SAFE_DELETE(p)
Definition: win_snd.cpp:41
bool InitializeSpeakers(byte *buffer, int bufferSize, dword dwPrimaryFreq, dword dwPrimaryBitRate, dword dwSpeakers)
Definition: win_snd.cpp:162
LPCSTR GetString(LPCSTR psPrompt)
Definition: GetString.cpp:87
idAudioBufferWIN32 * speakers
Definition: win_snd.cpp:100
waveformatex_t Format
Definition: snd_local.h:143
unsigned short word
Definition: Lib.h:76
unsigned char byte
Definition: Lib.h:75
bool Flush(void)
Definition: win_snd.cpp:93
void SetVolume(float x)
Definition: win_snd.cpp:843
int GetOutputSize(void)
Definition: snd_local.h:195
int RestoreBuffer(LPDIRECTSOUNDBUFFER pDSB, bool *pbWasRestored)
Definition: win_snd.cpp:661
int Reset(void)
Definition: win_snd.cpp:755
LPDIRECTSOUNDBUFFER m_apDSBuffer
Definition: win_snd.cpp:64
unsigned long ulong
Definition: Lib.h:79
void * Mem_Alloc(const int size)
Definition: Heap.cpp:1067
int ResetFile(void)
void SetPrimaryBufferFormat(dword dwPrimaryFreq, dword dwPrimaryBitRate, dword dwSpeakers)
Definition: win_snd.cpp:219
static idAudioHardware * Alloc()
Definition: sound.cpp:52
Win32Vars_t win32
Definition: win_main.cpp:65
const int PRIMARYFREQ
Definition: snd_local.h:67
virtual void Error(const char *fmt,...) id_attribute((format(printf
virtual void virtual void Warning(const char *fmt,...) id_attribute((format(printf
bool Unlock(void *pDSLockedBuffer, dword dwDSLockedBufferSize)
Definition: win_snd.cpp:486
idAudioBufferWIN32(LPDIRECTSOUNDBUFFER apDSBuffer, dword dwDSBufferSize, idWaveFile *pWaveFile=NULL)
Definition: win_snd.cpp:554
virtual ~idAudioHardware()
Definition: sound.cpp:78
LPDIRECTSOUND IUnknown FAR *typedef HRESULT(FAR PASCAL *LPEAXDIRECTSOUNDCREATE)(GUID *