win_snd.cpp 26 KB

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