Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

716 lines
19 KiB

  1. #include "basetypes.h"
  2. #include "commonmacros.h"
  3. #include "soundsystem/lowlevel.h"
  4. #include "tier1/uniqueid.h"
  5. #include "mix.h"
  6. #define DIRECTSOUND_VERSION 0x0800
  7. #include "../thirdparty/dxsdk/include/dsound.h"
  8. #pragma warning(disable : 4201) // nameless struct/union
  9. #include <ks.h>
  10. #include <ksmedia.h>
  11. static HRESULT (WINAPI *g_pDirectSoundCreate)(GUID FAR *lpGUID, LPDIRECTSOUND FAR *lplpDS, IUnknown FAR *pUnkOuter);
  12. extern void ReleaseSurround(void);
  13. static LPDIRECTSOUND pDS;
  14. static LPDIRECTSOUNDBUFFER pDSBuf, pDSPBuf;
  15. //-----------------------------------------------------------------------------
  16. // Purpose: Implementation of direct sound
  17. //-----------------------------------------------------------------------------
  18. class CAudioDirectSound2 : public IAudioDevice2
  19. {
  20. public:
  21. CAudioDirectSound2()
  22. {
  23. m_pName = "Windows DirectSound";
  24. m_nChannels = 2;
  25. m_nSampleBits = 16;
  26. m_nSampleRate = 44100;
  27. m_bIsActive = true;
  28. m_hWindow = NULL;
  29. m_hInstDS = 0;
  30. m_bIsHeadphone = false;
  31. m_bSupportsBufferStarvationDetection = false;
  32. m_bIsCaptureDevice = false;
  33. m_bPlayEvenWhenNotInFocus = false;
  34. }
  35. ~CAudioDirectSound2( void );
  36. bool Init( const audio_device_init_params_t &params );
  37. void Shutdown( void );
  38. void OutputBuffer( int nChannels, CAudioMixBuffer *pChannelArray );
  39. int QueuedBufferCount();
  40. int EmptyBufferCount();
  41. void CancelOutput( void );
  42. void WaitForComplete();
  43. const wchar_t *GetDeviceID() const { return m_deviceID; }
  44. bool SetShouldPlayWhenNotInFocus( bool bPlayEvenWhenNotInFocus ) OVERRIDE
  45. {
  46. if ( bPlayEvenWhenNotInFocus != m_bPlayEvenWhenNotInFocus )
  47. return false;
  48. return true;
  49. }
  50. // directsound handles this itself
  51. void UpdateFocus( bool bWindowHasFocus ) {}
  52. void ClearBuffer();
  53. void OutputDebugInfo() const;
  54. inline int BytesPerSample() { return BitsPerSample()>>3; }
  55. // Singleton object
  56. static CAudioDirectSound2 *m_pSingleton;
  57. private:
  58. // no copies of this class ever
  59. CAudioDirectSound2( const CAudioDirectSound2 & );
  60. CAudioDirectSound2 & operator=( const CAudioDirectSound2 & );
  61. bool LockDSBuffer( LPDIRECTSOUNDBUFFER pBuffer, DWORD **pdwWriteBuffer, DWORD *pdwSizeBuffer, const char *pBufferName, int lockFlags = 0 );
  62. int GetOutputPosition();
  63. bool SNDDMA_InitInterleaved( LPDIRECTSOUND lpDS, WAVEFORMATEX* lpFormat, const audio_device_init_params_t *pParams, int nChannelCount );
  64. int m_nTotalBufferSizeBytes; // size of a single hardware output buffer, in bytes
  65. int m_nOneBufferInBytes;
  66. int m_nBufferCount;
  67. int m_nSubmitPosition;
  68. DWORD m_nOutputBufferStartOffset; // output buffer playback starting byte offset
  69. HINSTANCE m_hInstDS;
  70. HWND m_hWindow;
  71. wchar_t m_deviceID[256];
  72. bool m_bPlayEvenWhenNotInFocus;
  73. };
  74. struct dsound_list_t
  75. {
  76. audio_device_description_t *m_pDeviceListOut;
  77. int m_nListMax;
  78. int m_nListCount;
  79. };
  80. #pragma warning(disable:4996) // suppress: deprecated use strncpy_s instead
  81. static BOOL CALLBACK DSEnumCallback( LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext )
  82. {
  83. dsound_list_t *pList = reinterpret_cast<dsound_list_t *>(lpContext);
  84. audio_device_description_t *pDesc = pList->m_pDeviceListOut + pList->m_nListCount;
  85. if ( pList->m_nListCount < pList->m_nListMax )
  86. {
  87. if ( !lpGuid )
  88. {
  89. V_memset( pDesc->m_deviceName, 0, sizeof(pDesc->m_deviceName) );
  90. pDesc->m_bIsDefault = true;
  91. }
  92. else
  93. {
  94. pDesc->m_bIsDefault = false;
  95. char tempString[256];
  96. UniqueIdToString( *reinterpret_cast<const UniqueId_t *>(lpGuid), tempString, sizeof(tempString) );
  97. for ( int i = 0; i < sizeof(UniqueId_t); i++ )
  98. {
  99. pDesc->m_deviceName[i] = tempString[i];
  100. }
  101. }
  102. pDesc->m_bIsAvailable = true;
  103. V_strncpy( pDesc->m_friendlyName, lpcstrDescription, sizeof(pDesc->m_friendlyName) );
  104. pDesc->m_nChannelCount = 2;
  105. pDesc->m_nSubsystemId = AUDIO_SUBSYSTEM_DSOUND;
  106. pList->m_nListCount++;
  107. }
  108. return 1;
  109. }
  110. extern HRESULT WINAPI DirectSoundEnumerateA(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext);
  111. int Audio_EnumerateDSoundDevices( audio_device_description_t *pDeviceListOut, int listCount )
  112. {
  113. HINSTANCE hInstDS = LoadLibrary("dsound.dll");
  114. HRESULT (WINAPI *pDirectSoundEnumerate)(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID lpContext);
  115. pDirectSoundEnumerate = (long (WINAPI *)(LPDSENUMCALLBACKA ,LPVOID))GetProcAddress(hInstDS,"DirectSoundEnumerateA");
  116. dsound_list_t list;
  117. list.m_nListCount = 0;
  118. list.m_nListMax = listCount;
  119. list.m_pDeviceListOut = pDeviceListOut;
  120. pDirectSoundEnumerate( &DSEnumCallback, (LPVOID)&list );
  121. FreeLibrary( hInstDS );
  122. return list.m_nListCount;
  123. }
  124. //-----------------------------------------------------------------------------
  125. // Class factory
  126. //-----------------------------------------------------------------------------
  127. IAudioDevice2 *Audio_CreateDSoundDevice( const audio_device_init_params_t &params )
  128. {
  129. if ( !CAudioDirectSound2::m_pSingleton )
  130. {
  131. CAudioDirectSound2::m_pSingleton = new CAudioDirectSound2;
  132. }
  133. if ( CAudioDirectSound2::m_pSingleton->Init( params ) )
  134. return CAudioDirectSound2::m_pSingleton;
  135. delete CAudioDirectSound2::m_pSingleton;
  136. CAudioDirectSound2::m_pSingleton = NULL;
  137. Warning("Failed to initialize direct sound!\n");
  138. return NULL;
  139. }
  140. CAudioDirectSound2 *CAudioDirectSound2::m_pSingleton = NULL;
  141. // ----------------------------------------------------------------------------- //
  142. // Helpers.
  143. // ----------------------------------------------------------------------------- //
  144. CAudioDirectSound2::~CAudioDirectSound2( void )
  145. {
  146. Shutdown();
  147. m_pSingleton = NULL;
  148. }
  149. static int GetWindowsSpeakerConfig()
  150. {
  151. DWORD nSpeakerConfig = DSSPEAKER_STEREO;
  152. if (DS_OK == pDS->GetSpeakerConfig( &nSpeakerConfig ))
  153. {
  154. // split out settings
  155. nSpeakerConfig = DSSPEAKER_CONFIG(nSpeakerConfig);
  156. if ( nSpeakerConfig == DSSPEAKER_7POINT1_SURROUND )
  157. nSpeakerConfig = DSSPEAKER_7POINT1;
  158. if ( nSpeakerConfig == DSSPEAKER_5POINT1_SURROUND)
  159. nSpeakerConfig = DSSPEAKER_5POINT1;
  160. switch( nSpeakerConfig )
  161. {
  162. case DSSPEAKER_HEADPHONE:
  163. return 0;
  164. case DSSPEAKER_MONO:
  165. case DSSPEAKER_STEREO:
  166. default:
  167. return 2;
  168. case DSSPEAKER_QUAD:
  169. return 4;
  170. case DSSPEAKER_5POINT1:
  171. return 5;
  172. case DSSPEAKER_7POINT1:
  173. return 7;
  174. }
  175. }
  176. return 2;
  177. }
  178. bool CAudioDirectSound2::Init( const audio_device_init_params_t &params )
  179. {
  180. DSBUFFERDESC dsbuf;
  181. DSBCAPS dsbcaps;
  182. WAVEFORMATEX format;
  183. WAVEFORMATEX pformat;
  184. HRESULT hresult;
  185. bool primary_format_set = false;
  186. // if a specific device was requested use that one, otherwise use the default (NULL means default)
  187. LPGUID pGUID = NULL;
  188. UniqueId_t overrideGUID;
  189. m_bPlayEvenWhenNotInFocus = params.m_bPlayEvenWhenNotInFocus;
  190. if ( params.m_bOverrideDevice )
  191. {
  192. char tempString[ Q_ARRAYSIZE(params.m_overrideDeviceName) ];
  193. int nLen = V_wcslen( params.m_overrideDeviceName );
  194. if ( nLen > 0 )
  195. {
  196. for ( int i = 0; i < nLen+1; i++ )
  197. {
  198. tempString[i] = params.m_overrideDeviceName[i] & 0xFF;
  199. }
  200. UniqueIdFromString( &overrideGUID, tempString );
  201. pGUID = &(( GUID &)overrideGUID);
  202. V_wcscpy_safe( m_deviceID, params.m_overrideDeviceName );
  203. }
  204. }
  205. if ( !pGUID )
  206. {
  207. V_memset( m_deviceID, 0, sizeof(m_deviceID) );
  208. }
  209. if (!m_hInstDS)
  210. {
  211. m_hInstDS = LoadLibrary("dsound.dll");
  212. if (m_hInstDS == NULL)
  213. {
  214. Warning( "Couldn't load dsound.dll\n");
  215. return false;
  216. }
  217. g_pDirectSoundCreate = (long (__stdcall *)(struct _GUID *,struct IDirectSound ** ,struct IUnknown *))GetProcAddress(m_hInstDS,"DirectSoundCreate");
  218. if (!g_pDirectSoundCreate)
  219. {
  220. Warning( "Couldn't get DS proc addr\n");
  221. return false;
  222. }
  223. }
  224. while ((hresult = g_pDirectSoundCreate(pGUID, &pDS, NULL)) != DS_OK)
  225. {
  226. if (hresult == DSERR_ALLOCATED)
  227. {
  228. Warning("DirectSound hardware in use, can't initialize!\n");
  229. return false;
  230. }
  231. Warning("DirectSound Create failed.\n");
  232. return false;
  233. }
  234. int nSpeakerConfig = -1;
  235. if ( params.m_bOverrideSpeakerConfig )
  236. {
  237. nSpeakerConfig = params.m_nOverrideSpeakerConfig;
  238. }
  239. else
  240. {
  241. nSpeakerConfig = GetWindowsSpeakerConfig();
  242. }
  243. if ( nSpeakerConfig == 0 )
  244. {
  245. m_bIsHeadphone = true;
  246. }
  247. // NOTE: This is basically the same as SpeakerConfigToChannelCount() but we
  248. // have to set primary channels correctly and DirectSound maps 7.1 to 5.1
  249. // at the moment (seems like it could support it easily though)
  250. int nPrimaryChannels = 2;
  251. switch( nSpeakerConfig )
  252. {
  253. // stereo
  254. case 0:
  255. case 2:
  256. default:
  257. nPrimaryChannels = 2;
  258. m_nChannels = 2; // secondary buffers should have same # channels as primary
  259. break;
  260. // surround, use mono 3d primary buffer
  261. // quad surround
  262. case 4:
  263. nPrimaryChannels = 1;
  264. m_nChannels = 4;
  265. break;
  266. case 5:
  267. case 7:
  268. nPrimaryChannels = 1;
  269. m_nChannels = 6;
  270. break;
  271. }
  272. V_memset( &format, 0, sizeof(format) );
  273. format.wFormatTag = WAVE_FORMAT_PCM;
  274. format.nChannels = nPrimaryChannels;
  275. format.wBitsPerSample = BitsPerSample();
  276. format.nSamplesPerSec = SampleRate();
  277. format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8;
  278. format.cbSize = 0;
  279. format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
  280. DSCAPS dscaps;
  281. V_memset( &dscaps, 0, sizeof(dscaps) );
  282. dscaps.dwSize = sizeof(dscaps);
  283. if (DS_OK != pDS->GetCaps(&dscaps))
  284. {
  285. Warning( "Couldn't get DS caps\n");
  286. }
  287. if (dscaps.dwFlags & DSCAPS_EMULDRIVER)
  288. {
  289. Warning( "No DirectSound driver installed\n");
  290. Shutdown();
  291. return false;
  292. }
  293. m_hWindow = (HWND)params.m_pWindowHandle;
  294. DWORD dwCooperativeLevel = DSSCL_EXCLUSIVE;
  295. if (DS_OK != pDS->SetCooperativeLevel( m_hWindow, dwCooperativeLevel ) )
  296. {
  297. Warning( "Set coop level failed\n");
  298. Shutdown();
  299. return false;
  300. }
  301. // get access to the primary buffer, if possible, so we can set the
  302. // sound hardware format
  303. V_memset( &dsbuf, 0, sizeof(dsbuf) );
  304. dsbuf.dwSize = sizeof(DSBUFFERDESC);
  305. dsbuf.dwFlags = DSBCAPS_PRIMARYBUFFER;
  306. if ( m_nChannels > 2 )
  307. {
  308. dsbuf.dwFlags |= DSBCAPS_CTRL3D;
  309. Assert( nPrimaryChannels == 1 );
  310. }
  311. dsbuf.dwBufferBytes = 0;
  312. dsbuf.lpwfxFormat = NULL;
  313. V_memset( &dsbcaps, 0, sizeof(dsbcaps) );
  314. dsbcaps.dwSize = sizeof(dsbcaps);
  315. if ( 1 )
  316. {
  317. if (DS_OK == pDS->CreateSoundBuffer(&dsbuf, &pDSPBuf, NULL))
  318. {
  319. pformat = format;
  320. if (DS_OK != pDSPBuf->SetFormat(&pformat))
  321. {
  322. }
  323. else
  324. {
  325. primary_format_set = true;
  326. }
  327. }
  328. }
  329. bool bRet = SNDDMA_InitInterleaved( pDS, &format, &params, m_nChannels );
  330. // number of mono samples output buffer may hold
  331. m_nSubmitPosition = 0;
  332. return bRet;
  333. }
  334. void CAudioDirectSound2::Shutdown( void )
  335. {
  336. if (pDSBuf)
  337. {
  338. pDSBuf->Stop();
  339. pDSBuf->Release();
  340. }
  341. // only release primary buffer if it's not also the mixing buffer we just released
  342. if (pDSPBuf && (pDSBuf != pDSPBuf))
  343. {
  344. pDSPBuf->Release();
  345. }
  346. if ( pDS && m_hWindow )
  347. {
  348. pDS->SetCooperativeLevel( m_hWindow, DSSCL_NORMAL);
  349. pDS->Release();
  350. }
  351. pDS = NULL;
  352. pDSBuf = NULL;
  353. pDSPBuf = NULL;
  354. if ( m_hInstDS )
  355. {
  356. FreeLibrary( m_hInstDS );
  357. m_hInstDS = NULL;
  358. }
  359. if ( this == CAudioDirectSound2::m_pSingleton )
  360. {
  361. CAudioDirectSound2::m_pSingleton = NULL;
  362. }
  363. }
  364. void CAudioDirectSound2::OutputDebugInfo() const
  365. {
  366. Msg( "Direct Sound Device\n" );
  367. Msg( "Channels:\t%d\n", ChannelCount() );
  368. Msg( "Bits/Sample:\t%d\n", BitsPerSample() );
  369. Msg( "Rate:\t\t%d\n", SampleRate() );
  370. }
  371. void CAudioDirectSound2::CancelOutput( void )
  372. {
  373. if (pDSBuf)
  374. {
  375. DWORD dwSize;
  376. DWORD *pData;
  377. int reps;
  378. HRESULT hresult;
  379. reps = 0;
  380. while ((hresult = pDSBuf->Lock(0, m_nTotalBufferSizeBytes, (void**)&pData, &dwSize, NULL, NULL, 0)) != DS_OK)
  381. {
  382. if (hresult != DSERR_BUFFERLOST)
  383. {
  384. Msg("S_ClearBuffer: DS::Lock Sound Buffer Failed\n");
  385. return;
  386. }
  387. if (++reps > 10000)
  388. {
  389. Msg("S_ClearBuffer: DS: couldn't restore buffer\n");
  390. return;
  391. }
  392. }
  393. V_memset(pData, 0, dwSize);
  394. pDSBuf->Unlock(pData, dwSize, NULL, 0);
  395. }
  396. }
  397. bool CAudioDirectSound2::SNDDMA_InitInterleaved( LPDIRECTSOUND lpDS, WAVEFORMATEX* lpFormat, const audio_device_init_params_t *pParams, int nChannelCount )
  398. {
  399. WAVEFORMATEXTENSIBLE wfx = { 0 } ; // DirectSoundBuffer wave format (extensible)
  400. // set the channel mask and number of channels based on the command line parameter
  401. if( nChannelCount == 2 )
  402. {
  403. wfx.Format.nChannels = 2;
  404. wfx.dwChannelMask = KSAUDIO_SPEAKER_STEREO; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
  405. }
  406. else if( nChannelCount == 4 )
  407. {
  408. wfx.Format.nChannels = 4;
  409. wfx.dwChannelMask = KSAUDIO_SPEAKER_QUAD; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT;
  410. }
  411. else if( nChannelCount == 6 )
  412. {
  413. wfx.Format.nChannels = 6;
  414. wfx.dwChannelMask = KSAUDIO_SPEAKER_5POINT1; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT;
  415. }
  416. else
  417. {
  418. return false;
  419. }
  420. // setup the extensible structure
  421. int nBytesPerSample = lpFormat->wBitsPerSample / 8;
  422. wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
  423. //wfx.Format.nChannels = SET ABOVE
  424. wfx.Format.nSamplesPerSec = lpFormat->nSamplesPerSec;
  425. wfx.Format.wBitsPerSample = lpFormat->wBitsPerSample;
  426. wfx.Format.nBlockAlign = nBytesPerSample * wfx.Format.nChannels;
  427. wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign;
  428. wfx.Format.cbSize = 22; // size from after this to end of extensible struct. sizeof(WORD + DWORD + GUID)
  429. wfx.Samples.wValidBitsPerSample = lpFormat->wBitsPerSample;
  430. //wfx.dwChannelMask = SET ABOVE BASED ON COMMAND LINE PARAMETERS
  431. wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
  432. // setup the DirectSound
  433. DSBUFFERDESC dsbdesc = { 0 }; // DirectSoundBuffer descriptor
  434. dsbdesc.dwSize = sizeof(DSBUFFERDESC);
  435. DWORD nBaseFlags = pParams->m_bPlayEvenWhenNotInFocus ? DSBCAPS_GLOBALFOCUS : 0;
  436. m_nOneBufferInBytes = ( MIX_BUFFER_SIZE * nBytesPerSample * nChannelCount );
  437. m_nBufferCount = pParams->m_nOutputBufferCount + 1;
  438. m_nTotalBufferSizeBytes = m_nBufferCount * m_nOneBufferInBytes;
  439. dsbdesc.dwBufferBytes = m_nTotalBufferSizeBytes;
  440. dsbdesc.lpwfxFormat = (WAVEFORMATEX*)&wfx;
  441. bool bSuccess = false;
  442. for ( int i = 0; i < 3; i++ )
  443. {
  444. switch(i)
  445. {
  446. case 0:
  447. dsbdesc.dwFlags = nBaseFlags | DSBCAPS_LOCHARDWARE;
  448. break;
  449. case 1:
  450. dsbdesc.dwFlags = nBaseFlags | DSBCAPS_LOCSOFTWARE;
  451. break;
  452. case 2:
  453. dsbdesc.dwFlags = nBaseFlags;
  454. break;
  455. }
  456. if(!FAILED(lpDS->CreateSoundBuffer(&dsbdesc, &pDSBuf, NULL)))
  457. {
  458. bSuccess = true;
  459. break;
  460. }
  461. }
  462. if ( !bSuccess )
  463. {
  464. dsbdesc.dwFlags = nBaseFlags;
  465. if(FAILED(lpDS->CreateSoundBuffer(&dsbdesc, &pDSBuf, NULL)))
  466. {
  467. wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
  468. wfx.Format.cbSize = 0;
  469. dsbdesc.dwFlags = DSBCAPS_LOCSOFTWARE | nBaseFlags;
  470. HRESULT hr = lpDS->CreateSoundBuffer(&dsbdesc, &pDSBuf, NULL);
  471. if(FAILED(hr))
  472. {
  473. printf("Failed %d\n", hr );
  474. return false;
  475. }
  476. }
  477. }
  478. DWORD dwSize = 0, dwWrite;
  479. DWORD *pBuffer = 0;
  480. if ( !LockDSBuffer( pDSBuf, &pBuffer, &dwSize, "DS_INTERLEAVED", DSBLOCK_ENTIREBUFFER ) )
  481. return false;
  482. m_nChannels = wfx.Format.nChannels;
  483. V_memset( pBuffer, 0, dwSize );
  484. pDSBuf->Unlock(pBuffer, dwSize, NULL, 0);
  485. // Make sure mixer is active (this was moved after the zeroing to avoid popping on startup -- at least when using the dx9.0b debug .dlls)
  486. pDSBuf->Play(0, 0, DSBPLAY_LOOPING);
  487. pDSBuf->Stop();
  488. pDSBuf->GetCurrentPosition(&m_nOutputBufferStartOffset, &dwWrite);
  489. pDSBuf->Play(0, 0, DSBPLAY_LOOPING);
  490. return true;
  491. }
  492. bool CAudioDirectSound2::LockDSBuffer( LPDIRECTSOUNDBUFFER pBuffer, DWORD **pdwWriteBuffer, DWORD *pdwSizeBuffer, const char *pBufferName, int lockFlags )
  493. {
  494. if ( !pBuffer )
  495. return false;
  496. HRESULT hr;
  497. int reps = 0;
  498. while ((hr = pBuffer->Lock(0, m_nTotalBufferSizeBytes, (void**)pdwWriteBuffer, pdwSizeBuffer,
  499. NULL, NULL, lockFlags)) != DS_OK)
  500. {
  501. if (hr != DSERR_BUFFERLOST)
  502. {
  503. Msg ("DS::Lock Sound Buffer Failed %s\n", pBufferName);
  504. return false;
  505. }
  506. if (++reps > 10000)
  507. {
  508. Msg ("DS:: couldn't restore buffer %s\n", pBufferName);
  509. return false;
  510. }
  511. }
  512. return true;
  513. }
  514. void CAudioDirectSound2::OutputBuffer( int nMixChannelCount, CAudioMixBuffer *pMixChannels )
  515. {
  516. HRESULT hr;
  517. int nDeviceChannelCount = ChannelCount();
  518. int nOutputSize = BytesPerSample() * nDeviceChannelCount * MIX_BUFFER_SIZE;
  519. void *pBuffer0=NULL;
  520. void *pBuffer1=NULL;
  521. DWORD nSize0, nSize1;
  522. int nReps = 0;
  523. while ( (hr = pDSBuf->Lock( m_nSubmitPosition, nOutputSize, &pBuffer0, &nSize0, &pBuffer1, &nSize1, 0 )) != DS_OK )
  524. {
  525. if ( hr == DSERR_BUFFERLOST )
  526. {
  527. if ( ++nReps < 10000 )
  528. continue;
  529. }
  530. Msg ("DS::Lock Sound Buffer Failed\n");
  531. return;
  532. }
  533. int nStart = 0;
  534. if ( pBuffer0 )
  535. {
  536. short *pOut = (short *)pBuffer0;
  537. int nSamplesOut = nSize0 / (nDeviceChannelCount*2);
  538. if ( nMixChannelCount == 2 && nMixChannelCount == nDeviceChannelCount )
  539. {
  540. ConvertFloat32Int16_Clamp_Interleave2( pOut, pMixChannels[0].m_flData, pMixChannels[1].m_flData, nSamplesOut );
  541. }
  542. else
  543. {
  544. ConvertFloat32Int16_Clamp_InterleaveStride( pOut, nDeviceChannelCount, MIX_BUFFER_SIZE, pMixChannels[0].m_flData, nMixChannelCount, nSamplesOut );
  545. }
  546. nStart = nSamplesOut;
  547. }
  548. if ( pBuffer1 )
  549. {
  550. short *pOut = (short *)pBuffer1;
  551. int nSamplesOut = nSize1 / (nDeviceChannelCount*2);
  552. if ( nMixChannelCount == 2 && nMixChannelCount == nDeviceChannelCount )
  553. {
  554. ConvertFloat32Int16_Clamp_Interleave2( pOut, pMixChannels[0].m_flData, pMixChannels[1].m_flData, nSamplesOut );
  555. }
  556. else
  557. {
  558. ConvertFloat32Int16_Clamp_InterleaveStride( pOut, nDeviceChannelCount, MIX_BUFFER_SIZE, pMixChannels[0].m_flData, nMixChannelCount, nSamplesOut );
  559. }
  560. }
  561. pDSBuf->Unlock(pBuffer0, nSize0, pBuffer1, nSize1);
  562. m_nSubmitPosition += nOutputSize;
  563. m_nSubmitPosition %= m_nTotalBufferSizeBytes;
  564. }
  565. int CAudioDirectSound2::QueuedBufferCount()
  566. {
  567. int nStart, nCurrent;
  568. DWORD dwCurrentPlayCursor;
  569. // get size in bytes of output buffer
  570. const int nSizeInBytes = m_nTotalBufferSizeBytes;
  571. // multi-channel interleaved output buffer
  572. // get byte offset of playback cursor in output buffer
  573. HRESULT hr = pDSBuf->GetCurrentPosition(&dwCurrentPlayCursor, NULL);
  574. if ( hr != S_OK )
  575. return m_nBufferCount;
  576. if ( dwCurrentPlayCursor > DWORD(m_nTotalBufferSizeBytes) )
  577. {
  578. // BUGBUG: ??? what do do here?
  579. DebuggerBreakIfDebugging();
  580. dwCurrentPlayCursor %= m_nTotalBufferSizeBytes;
  581. }
  582. nStart = (int) m_nOutputBufferStartOffset;
  583. nCurrent = (int) dwCurrentPlayCursor;
  584. // get 16 bit samples played, relative to buffer starting offset
  585. int delta = m_nSubmitPosition - nCurrent;
  586. if ( delta < 0 )
  587. {
  588. delta += nSizeInBytes;
  589. }
  590. int nSamples = delta / (ChannelCount() * BytesPerSample());
  591. int nBuffers = nSamples / MIX_BUFFER_SIZE;
  592. //int nTotalBuffers = (m_nTotalBufferSizeBytes/ (ChannelCount() * BytesPerSample())) / MIX_BUFFER_SIZE;
  593. //Msg("%d buffers remain %d total\n", nBuffers, nTotalBuffers);
  594. if ( nBuffers == 0 )
  595. {
  596. //Msg("cursor %d, submit %d, relative %d\n", nCurrent, m_nSubmitPosition, delta );
  597. }
  598. return nBuffers;
  599. }
  600. int CAudioDirectSound2::EmptyBufferCount()
  601. {
  602. return (m_nBufferCount-1) - QueuedBufferCount();
  603. }
  604. void CAudioDirectSound2::WaitForComplete()
  605. {
  606. while ( QueuedBufferCount() )
  607. {
  608. ThreadSleep(0);
  609. }
  610. }
  611. void CAudioDirectSound2::ClearBuffer( void )
  612. {
  613. DWORD dwSize = 0;
  614. DWORD *pBuffer = 0;
  615. if ( LockDSBuffer( pDSBuf, &pBuffer, &dwSize, "DS_INTERLEAVED", DSBLOCK_ENTIREBUFFER ) )
  616. {
  617. V_memset( pBuffer, 0, dwSize );
  618. pDSBuf->Unlock(pBuffer, dwSize, NULL, 0);
  619. }
  620. }