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.

2093 lines
55 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=====================================================================================//
  6. #include "audio_pch.h"
  7. #if USE_AUDIO_DEVICE_V1
  8. #include <dsound.h>
  9. #pragma warning(disable : 4201) // nameless struct/union
  10. #include <ks.h>
  11. #include <ksmedia.h>
  12. #include "iprediction.h"
  13. #include "tier0/icommandline.h"
  14. #include "avi/ibik.h"
  15. #include "../../sys_dll.h"
  16. #if defined( PLATFORM_WINDOWS )
  17. #include "vaudio/ivaudio.h"
  18. extern void VAudioInit();
  19. extern IVAudio * vaudio;
  20. #endif
  21. // memdbgon must be the last include file in a .cpp file!!!
  22. #include "tier0/memdbgon.h"
  23. extern bool snd_firsttime;
  24. extern void DEBUG_StartSoundMeasure(int type, int samplecount );
  25. extern void DEBUG_StopSoundMeasure(int type, int samplecount );
  26. // legacy support
  27. extern ConVar sxroom_off;
  28. extern ConVar sxroom_type;
  29. extern ConVar sxroomwater_type;
  30. extern float sxroom_typeprev;
  31. extern HWND* pmainwindow;
  32. typedef enum {SIS_SUCCESS, SIS_FAILURE, SIS_NOTAVAIL} sndinitstat;
  33. #define SECONDARY_BUFFER_SIZE 0x10000 // output buffer size in bytes
  34. #define SECONDARY_BUFFER_SIZE_SURROUND 0x04000 // output buffer size in bytes, one per channel
  35. // hack - need to include latest dsound.h
  36. COMPILE_TIME_ASSERT( DSSPEAKER_5POINT1 == 6 );
  37. COMPILE_TIME_ASSERT( DSSPEAKER_7POINT1 == 7 );
  38. #define DSSPEAKER_7POINT1_SURROUND 8
  39. #define DSSPEAKER_5POINT1_SURROUND 9
  40. HRESULT (WINAPI *pDirectSoundCreate)(GUID FAR *lpGUID, LPDIRECTSOUND FAR *lplpDS, IUnknown FAR *pUnkOuter);
  41. extern void ReleaseSurround(void);
  42. extern bool MIX_ScaleChannelVolume( paintbuffer_t *ppaint, channel_t *pChannel, float volume[CCHANVOLUMES], int mixchans );
  43. void OnSndSurroundCvarChanged( IConVar *var, const char *pOldString, float flOldValue );
  44. void OnSndSurroundLegacyChanged( IConVar *var, const char *pOldString, float flOldValue );
  45. void OnSndVarChanged( IConVar *var, const char *pOldString, float flOldValue );
  46. static LPDIRECTSOUND pDS;
  47. static LPDIRECTSOUNDBUFFER pDSBuf, pDSPBuf;
  48. static GUID IID_IDirectSound3DBufferDef = {0x279AFA86, 0x4981, 0x11CE, {0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60}};
  49. static ConVar windows_speaker_config("windows_speaker_config", "-1", FCVAR_RELEASE|FCVAR_ARCHIVE);
  50. static DWORD g_ForcedSpeakerConfig = 0;
  51. #if !defined( DX_TO_GL_ABSTRACTION )
  52. ConVar snd_mute_losefocus( "snd_mute_losefocus", "1", FCVAR_ARCHIVE );
  53. #else
  54. extern ConVar snd_mute_losefocus;
  55. #endif
  56. //-----------------------------------------------------------------------------
  57. // Purpose: Implementation of direct sound
  58. //-----------------------------------------------------------------------------
  59. class CAudioDirectSound : public CAudioDeviceBase
  60. {
  61. public:
  62. CAudioDirectSound()
  63. {
  64. m_pName = "Windows DirectSound";
  65. m_nChannels = 2;
  66. m_nSampleBits = 16;
  67. m_nSampleRate = 44100;
  68. m_bIsActive = true;
  69. }
  70. virtual ~CAudioDirectSound( void );
  71. bool IsActive( void ) { return true; }
  72. bool Init( void );
  73. void Shutdown( void );
  74. void Pause( void );
  75. void UnPause( void );
  76. int64 PaintBegin( float mixAheadTime, int64 soundtime, int64 paintedtime );
  77. void PaintEnd( void );
  78. int GetOutputPosition( void );
  79. void ClearBuffer( void );
  80. void TransferSamples( int end );
  81. int DeviceSampleCount( void ) { return m_deviceSampleCount; }
  82. bool IsInterleaved() { return m_isInterleaved; }
  83. // Singleton object
  84. static CAudioDirectSound *m_pSingleton;
  85. bool IsSurround() { return m_bSurround; }
  86. bool IsSurroundCenter() { return m_bSurroundCenter; }
  87. private:
  88. void DetectWindowsSpeakerSetup();
  89. bool LockDSBuffer( LPDIRECTSOUNDBUFFER pBuffer, DWORD **pdwWriteBuffer, DWORD *pdwSizeBuffer, const char *pBufferName, int lockFlags = 0 );
  90. bool IsUsingBufferPerSpeaker();
  91. sndinitstat SNDDMA_InitDirect( void );
  92. bool SNDDMA_InitInterleaved( LPDIRECTSOUND lpDS, WAVEFORMATEX* lpFormat, int channelCount );
  93. bool SNDDMA_InitSurround(LPDIRECTSOUND lpDS, WAVEFORMATEX* lpFormat, DSBCAPS* lpdsbc, int cchan);
  94. void S_TransferSurround16( portable_samplepair_t *pfront, portable_samplepair_t *prear, portable_samplepair_t *pcenter, int64 lpaintedtime, int64 endtime, int cchan);
  95. void S_TransferSurround16Interleaved( const portable_samplepair_t *pfront, const portable_samplepair_t *prear, const portable_samplepair_t *pcenter, int64 lpaintedtime, int64 endtime);
  96. void S_TransferSurround16Interleaved_FullLock( const portable_samplepair_t *pfront, const portable_samplepair_t *prear, const portable_samplepair_t *pcenter, int64 lpaintedtime, int64 endtime);
  97. int m_deviceSampleCount; // count of mono samples in output buffer
  98. int m_bufferSizeBytes; // size of a single hardware output buffer, in bytes
  99. DWORD m_outputBufferStartOffset; // output buffer playback starting byte offset
  100. HINSTANCE m_hInstDS;
  101. bool m_isInterleaved;
  102. bool m_bSurround;
  103. bool m_bSurroundCenter;
  104. };
  105. CAudioDirectSound *CAudioDirectSound::m_pSingleton = NULL;
  106. LPDIRECTSOUNDBUFFER pDSBufFL = NULL;
  107. LPDIRECTSOUNDBUFFER pDSBufFR = NULL;
  108. LPDIRECTSOUNDBUFFER pDSBufRL = NULL;
  109. LPDIRECTSOUNDBUFFER pDSBufRR = NULL;
  110. LPDIRECTSOUNDBUFFER pDSBufFC = NULL;
  111. LPDIRECTSOUND3DBUFFER pDSBuf3DFL = NULL;
  112. LPDIRECTSOUND3DBUFFER pDSBuf3DFR = NULL;
  113. LPDIRECTSOUND3DBUFFER pDSBuf3DRL = NULL;
  114. LPDIRECTSOUND3DBUFFER pDSBuf3DRR = NULL;
  115. LPDIRECTSOUND3DBUFFER pDSBuf3DFC = NULL;
  116. // ----------------------------------------------------------------------------- //
  117. // Helpers.
  118. // ----------------------------------------------------------------------------- //
  119. CAudioDirectSound::~CAudioDirectSound( void )
  120. {
  121. m_pSingleton = NULL;
  122. }
  123. bool CAudioDirectSound::Init( void )
  124. {
  125. m_hInstDS = NULL;
  126. static bool first = true;
  127. if ( first )
  128. {
  129. snd_surround.InstallChangeCallback( &OnSndSurroundCvarChanged );
  130. snd_legacy_surround.InstallChangeCallback( &OnSndSurroundLegacyChanged );
  131. snd_mute_losefocus.InstallChangeCallback( &OnSndVarChanged );
  132. first = false;
  133. }
  134. if ( SNDDMA_InitDirect() == SIS_SUCCESS)
  135. {
  136. #if defined ( BINK_VIDEO )
  137. if ( g_pBIK != NULL )
  138. {
  139. ConVarRef windows_speaker_config("windows_speaker_config");
  140. if ( windows_speaker_config.IsValid() && windows_speaker_config.GetInt() >= 5 )
  141. {
  142. // For 5.1, we need to use Miles otherwise the movies will play in stereo
  143. VAudioInit();
  144. void * pMilesEngine = vaudio ? vaudio->CreateMilesAudioEngine() : NULL;
  145. if ( g_pBIK->SetMilesSoundDevice( pMilesEngine ) == 0 )
  146. {
  147. Assert( false );
  148. return false;
  149. }
  150. }
  151. else
  152. {
  153. if ( g_pBIK->SetDirectSoundDevice( pDS ) == 0 )
  154. {
  155. Assert( false );
  156. return false;
  157. }
  158. }
  159. }
  160. #endif
  161. return true;
  162. }
  163. return false;
  164. }
  165. void CAudioDirectSound::Shutdown( void )
  166. {
  167. ReleaseSurround();
  168. if (pDSBuf)
  169. {
  170. pDSBuf->Stop();
  171. pDSBuf->Release();
  172. }
  173. // only release primary buffer if it's not also the mixing buffer we just released
  174. if (pDSPBuf && (pDSBuf != pDSPBuf))
  175. {
  176. pDSPBuf->Release();
  177. }
  178. if (pDS)
  179. {
  180. pDS->SetCooperativeLevel(*pmainwindow, DSSCL_NORMAL);
  181. pDS->Release();
  182. }
  183. pDS = NULL;
  184. pDSBuf = NULL;
  185. pDSPBuf = NULL;
  186. if ( m_hInstDS )
  187. {
  188. FreeLibrary( m_hInstDS );
  189. m_hInstDS = NULL;
  190. }
  191. if ( this == CAudioDirectSound::m_pSingleton )
  192. {
  193. CAudioDirectSound::m_pSingleton = NULL;
  194. }
  195. }
  196. // Total number of samples that have played out to hardware
  197. // for current output buffer (ie: from buffer offset start).
  198. // return playback position within output playback buffer:
  199. // the output units are dependant on the device channels
  200. // so the ouput units for a 2 channel device are as 16 bit LR pairs
  201. // and the output unit for a 1 channel device are as 16 bit mono samples.
  202. // take into account the original start position within the buffer, and
  203. // calculate difference between current position (with buffer wrap) and
  204. // start position.
  205. int CAudioDirectSound::GetOutputPosition( void )
  206. {
  207. int samp16;
  208. int start, current;
  209. DWORD dwCurrent;
  210. // get size in bytes of output buffer
  211. const int size_bytes = m_bufferSizeBytes;
  212. if ( IsUsingBufferPerSpeaker() )
  213. {
  214. // mono output buffers
  215. // get byte offset of playback cursor in Front Left output buffer
  216. pDSBufFL->GetCurrentPosition(&dwCurrent, NULL);
  217. start = (int) m_outputBufferStartOffset;
  218. current = (int) dwCurrent;
  219. }
  220. else
  221. {
  222. // multi-channel interleavd output buffer
  223. // get byte offset of playback cursor in output buffer
  224. pDSBuf->GetCurrentPosition(&dwCurrent, NULL);
  225. start = (int) m_outputBufferStartOffset;
  226. current = (int) dwCurrent;
  227. }
  228. // get 16 bit samples played, relative to buffer starting offset
  229. if (current > start)
  230. {
  231. // get difference & convert to 16 bit mono samples
  232. samp16 = (current - start) >> SAMPLE_16BIT_SHIFT;
  233. }
  234. else
  235. {
  236. // get difference (with buffer wrap) convert to 16 bit mono samples
  237. samp16 = ((size_bytes - start) + current) >> SAMPLE_16BIT_SHIFT;
  238. }
  239. int outputPosition = samp16 / ChannelCount();
  240. return outputPosition;
  241. }
  242. void CAudioDirectSound::Pause( void )
  243. {
  244. if (pDSBuf)
  245. {
  246. pDSBuf->Stop();
  247. }
  248. if ( pDSBufFL ) pDSBufFL->Stop();
  249. if ( pDSBufFR ) pDSBufFR->Stop();
  250. if ( pDSBufRL ) pDSBufRL->Stop();
  251. if ( pDSBufRR ) pDSBufRR->Stop();
  252. if ( pDSBufFC ) pDSBufFC->Stop();
  253. }
  254. void CAudioDirectSound::UnPause( void )
  255. {
  256. if (pDSBuf)
  257. pDSBuf->Play(0, 0, DSBPLAY_LOOPING);
  258. if (pDSBufFL) pDSBufFL->Play(0, 0, DSBPLAY_LOOPING);
  259. if (pDSBufFR) pDSBufFR->Play(0, 0, DSBPLAY_LOOPING);
  260. if (pDSBufRL) pDSBufRL->Play(0, 0, DSBPLAY_LOOPING);
  261. if (pDSBufRR) pDSBufRR->Play( 0, 0, DSBPLAY_LOOPING);
  262. if (pDSBufFC) pDSBufFC->Play( 0, 0, DSBPLAY_LOOPING);
  263. }
  264. IAudioDevice *Audio_CreateDirectSoundDevice( void )
  265. {
  266. if ( !CAudioDirectSound::m_pSingleton )
  267. CAudioDirectSound::m_pSingleton = new CAudioDirectSound;
  268. if ( CAudioDirectSound::m_pSingleton->Init() )
  269. {
  270. if (snd_firsttime)
  271. DevMsg ("DirectSound initialized\n");
  272. return CAudioDirectSound::m_pSingleton;
  273. }
  274. DevMsg ("DirectSound failed to init\n");
  275. delete CAudioDirectSound::m_pSingleton;
  276. CAudioDirectSound::m_pSingleton = NULL;
  277. return NULL;
  278. }
  279. int64 CAudioDirectSound::PaintBegin( float mixAheadTime, int64 soundtime, int64 lpaintedtime )
  280. {
  281. // soundtime - total full samples that have been played out to hardware at dmaspeed
  282. // paintedtime - total full samples that have been mixed at speed
  283. // endtime - target for full samples in mixahead buffer at speed
  284. // samps - size of output buffer in full samples
  285. int mixaheadtime = mixAheadTime * SampleRate();
  286. int64 endtime = soundtime + mixaheadtime;
  287. if ( endtime <= lpaintedtime )
  288. return endtime;
  289. int fullsamps = DeviceSampleCount() / ChannelCount();
  290. if ((endtime - soundtime) > fullsamps)
  291. endtime = soundtime + fullsamps;
  292. if ((endtime - lpaintedtime) & 0x3)
  293. {
  294. // The difference between endtime and painted time should align on
  295. // boundaries of 4 samples. This is important when upsampling from 11khz -> 44khz.
  296. endtime -= (endtime - lpaintedtime) & 0x3;
  297. }
  298. DWORD dwStatus;
  299. // If using surround, there are 4 or 5 different buffers being used and the pDSBuf is NULL.
  300. if ( IsUsingBufferPerSpeaker() )
  301. {
  302. if (pDSBufFL->GetStatus(&dwStatus) != DS_OK)
  303. Msg ("Couldn't get SURROUND FL sound buffer status\n");
  304. if (dwStatus & DSBSTATUS_BUFFERLOST)
  305. pDSBufFL->Restore();
  306. if (!(dwStatus & DSBSTATUS_PLAYING))
  307. pDSBufFL->Play(0, 0, DSBPLAY_LOOPING);
  308. if (pDSBufFR->GetStatus(&dwStatus) != DS_OK)
  309. Msg ("Couldn't get SURROUND FR sound buffer status\n");
  310. if (dwStatus & DSBSTATUS_BUFFERLOST)
  311. pDSBufFR->Restore();
  312. if (!(dwStatus & DSBSTATUS_PLAYING))
  313. pDSBufFR->Play(0, 0, DSBPLAY_LOOPING);
  314. if (pDSBufRL->GetStatus(&dwStatus) != DS_OK)
  315. Msg ("Couldn't get SURROUND RL sound buffer status\n");
  316. if (dwStatus & DSBSTATUS_BUFFERLOST)
  317. pDSBufRL->Restore();
  318. if (!(dwStatus & DSBSTATUS_PLAYING))
  319. pDSBufRL->Play(0, 0, DSBPLAY_LOOPING);
  320. if (pDSBufRR->GetStatus(&dwStatus) != DS_OK)
  321. Msg ("Couldn't get SURROUND RR sound buffer status\n");
  322. if (dwStatus & DSBSTATUS_BUFFERLOST)
  323. pDSBufRR->Restore();
  324. if (!(dwStatus & DSBSTATUS_PLAYING))
  325. pDSBufRR->Play(0, 0, DSBPLAY_LOOPING);
  326. if ( m_bSurroundCenter )
  327. {
  328. if (pDSBufFC->GetStatus(&dwStatus) != DS_OK)
  329. Msg ("Couldn't get SURROUND FC sound buffer status\n");
  330. if (dwStatus & DSBSTATUS_BUFFERLOST)
  331. pDSBufFC->Restore();
  332. if (!(dwStatus & DSBSTATUS_PLAYING))
  333. pDSBufFC->Play(0, 0, DSBPLAY_LOOPING);
  334. }
  335. }
  336. else if (pDSBuf)
  337. {
  338. if ( pDSBuf->GetStatus (&dwStatus) != DS_OK )
  339. Msg("Couldn't get sound buffer status\n");
  340. if ( dwStatus & DSBSTATUS_BUFFERLOST )
  341. pDSBuf->Restore();
  342. if ( !(dwStatus & DSBSTATUS_PLAYING) )
  343. pDSBuf->Play(0, 0, DSBPLAY_LOOPING);
  344. }
  345. return endtime;
  346. }
  347. void CAudioDirectSound::PaintEnd()
  348. {
  349. }
  350. void CAudioDirectSound::ClearBuffer( void )
  351. {
  352. int clear;
  353. DWORD dwSizeFL, dwSizeFR, dwSizeRL, dwSizeRR, dwSizeFC;
  354. char *pDataFL, *pDataFR, *pDataRL, *pDataRR, *pDataFC;
  355. dwSizeFC = 0; // compiler warning
  356. pDataFC = NULL;
  357. if ( IsUsingBufferPerSpeaker() )
  358. {
  359. int SURROUNDreps;
  360. HRESULT SURROUNDhresult;
  361. SURROUNDreps = 0;
  362. if ( !pDSBufFL && !pDSBufFR && !pDSBufRL && !pDSBufRR && !pDSBufFC )
  363. return;
  364. while ((SURROUNDhresult = pDSBufFL->Lock(0, m_bufferSizeBytes, (void**)&pDataFL, &dwSizeFL, NULL, NULL, 0)) != DS_OK)
  365. {
  366. if (SURROUNDhresult != DSERR_BUFFERLOST)
  367. {
  368. Msg ("S_ClearBuffer: DS::Lock FL Sound Buffer Failed\n");
  369. S_Shutdown ();
  370. return;
  371. }
  372. if (++SURROUNDreps > 10000)
  373. {
  374. Msg ("S_ClearBuffer: DS: couldn't restore FL buffer\n");
  375. S_Shutdown ();
  376. return;
  377. }
  378. }
  379. SURROUNDreps = 0;
  380. while ((SURROUNDhresult = pDSBufFR->Lock(0, m_bufferSizeBytes, (void**)&pDataFR, &dwSizeFR, NULL, NULL, 0)) != DS_OK)
  381. {
  382. if (SURROUNDhresult != DSERR_BUFFERLOST)
  383. {
  384. Msg ("S_ClearBuffer: DS::Lock FR Sound Buffer Failed\n");
  385. S_Shutdown ();
  386. return;
  387. }
  388. if (++SURROUNDreps > 10000)
  389. {
  390. Msg ("S_ClearBuffer: DS: couldn't restore FR buffer\n");
  391. S_Shutdown ();
  392. return;
  393. }
  394. }
  395. SURROUNDreps = 0;
  396. while ((SURROUNDhresult = pDSBufRL->Lock(0, m_bufferSizeBytes, (void**)&pDataRL, &dwSizeRL, NULL, NULL, 0)) != DS_OK)
  397. {
  398. if (SURROUNDhresult != DSERR_BUFFERLOST)
  399. {
  400. Msg ("S_ClearBuffer: DS::Lock RL Sound Buffer Failed\n");
  401. S_Shutdown ();
  402. return;
  403. }
  404. if (++SURROUNDreps > 10000)
  405. {
  406. Msg ("S_ClearBuffer: DS: couldn't restore RL buffer\n");
  407. S_Shutdown ();
  408. return;
  409. }
  410. }
  411. SURROUNDreps = 0;
  412. while ((SURROUNDhresult = pDSBufRR->Lock(0, m_bufferSizeBytes, (void**)&pDataRR, &dwSizeRR, NULL, NULL, 0)) != DS_OK)
  413. {
  414. if (SURROUNDhresult != DSERR_BUFFERLOST)
  415. {
  416. Msg ("S_ClearBuffer: DS::Lock RR Sound Buffer Failed\n");
  417. S_Shutdown ();
  418. return;
  419. }
  420. if (++SURROUNDreps > 10000)
  421. {
  422. Msg ("S_ClearBuffer: DS: couldn't restore RR buffer\n");
  423. S_Shutdown ();
  424. return;
  425. }
  426. }
  427. if (m_bSurroundCenter)
  428. {
  429. SURROUNDreps = 0;
  430. while ((SURROUNDhresult = pDSBufFC->Lock(0, m_bufferSizeBytes, (void**)&pDataFC, &dwSizeFC, NULL, NULL, 0)) != DS_OK)
  431. {
  432. if (SURROUNDhresult != DSERR_BUFFERLOST)
  433. {
  434. Msg ("S_ClearBuffer: DS::Lock FC Sound Buffer Failed\n");
  435. S_Shutdown ();
  436. return;
  437. }
  438. if (++SURROUNDreps > 10000)
  439. {
  440. Msg ("S_ClearBuffer: DS: couldn't restore FC buffer\n");
  441. S_Shutdown ();
  442. return;
  443. }
  444. }
  445. }
  446. Q_memset(pDataFL, 0, m_bufferSizeBytes);
  447. Q_memset(pDataFR, 0, m_bufferSizeBytes);
  448. Q_memset(pDataRL, 0, m_bufferSizeBytes);
  449. Q_memset(pDataRR, 0, m_bufferSizeBytes);
  450. if (m_bSurroundCenter)
  451. Q_memset(pDataFC, 0, m_bufferSizeBytes);
  452. pDSBufFL->Unlock(pDataFL, dwSizeFL, NULL, 0);
  453. pDSBufFR->Unlock(pDataFR, dwSizeFR, NULL, 0);
  454. pDSBufRL->Unlock(pDataRL, dwSizeRL, NULL, 0);
  455. pDSBufRR->Unlock(pDataRR, dwSizeRR, NULL, 0);
  456. if (m_bSurroundCenter)
  457. pDSBufFC->Unlock(pDataFC, dwSizeFC, NULL, 0);
  458. return;
  459. }
  460. if ( !pDSBuf )
  461. return;
  462. if ( BitsPerSample() == 8 )
  463. clear = 0x80;
  464. else
  465. clear = 0;
  466. if (pDSBuf)
  467. {
  468. DWORD dwSize;
  469. DWORD *pData;
  470. int reps;
  471. HRESULT hresult;
  472. reps = 0;
  473. while ((hresult = pDSBuf->Lock(0, m_bufferSizeBytes, (void**)&pData, &dwSize, NULL, NULL, 0)) != DS_OK)
  474. {
  475. if (hresult != DSERR_BUFFERLOST)
  476. {
  477. Msg("S_ClearBuffer: DS::Lock Sound Buffer Failed\n");
  478. S_Shutdown();
  479. return;
  480. }
  481. if (++reps > 10000)
  482. {
  483. Msg("S_ClearBuffer: DS: couldn't restore buffer\n");
  484. S_Shutdown();
  485. return;
  486. }
  487. }
  488. Q_memset(pData, clear, dwSize);
  489. pDSBuf->Unlock(pData, dwSize, NULL, 0);
  490. }
  491. }
  492. bool CAudioDirectSound::SNDDMA_InitInterleaved( LPDIRECTSOUND lpDS, WAVEFORMATEX* lpFormat, int channelCount )
  493. {
  494. WAVEFORMATEXTENSIBLE wfx = { 0 } ; // DirectSoundBuffer wave format (extensible)
  495. // set the channel mask and number of channels based on the command line parameter
  496. if(channelCount == 2)
  497. {
  498. wfx.Format.nChannels = 2;
  499. wfx.dwChannelMask = KSAUDIO_SPEAKER_STEREO; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
  500. }
  501. else if(channelCount == 4)
  502. {
  503. wfx.Format.nChannels = 4;
  504. wfx.dwChannelMask = KSAUDIO_SPEAKER_QUAD; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT;
  505. }
  506. else if(channelCount == 6)
  507. {
  508. wfx.Format.nChannels = 6;
  509. wfx.dwChannelMask = KSAUDIO_SPEAKER_5POINT1; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT;
  510. }
  511. else
  512. {
  513. return false;
  514. }
  515. // setup the extensible structure
  516. wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
  517. //wfx.Format.nChannels = SET ABOVE
  518. wfx.Format.nSamplesPerSec = lpFormat->nSamplesPerSec;
  519. wfx.Format.wBitsPerSample = lpFormat->wBitsPerSample;
  520. wfx.Format.nBlockAlign = wfx.Format.wBitsPerSample / 8 * wfx.Format.nChannels;
  521. wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign;
  522. wfx.Format.cbSize = 22; // size from after this to end of extensible struct. sizeof(WORD + DWORD + GUID)
  523. wfx.Samples.wValidBitsPerSample = lpFormat->wBitsPerSample;
  524. //wfx.dwChannelMask = SET ABOVE BASED ON COMMAND LINE PARAMETERS
  525. // This bit of ugliness is for the benefit of Source licensees who install their own version of Direct X
  526. #if defined( KSDATAFORMAT_SUBTYPE_PCM_STRUCT )
  527. wfx.SubFormat = __uuidof(KSDATAFORMAT_SUBTYPE_PCM);
  528. #else
  529. wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
  530. #endif
  531. // setup the DirectSound
  532. DSBUFFERDESC dsbdesc = { 0 }; // DirectSoundBuffer descriptor
  533. dsbdesc.dwSize = sizeof(DSBUFFERDESC);
  534. dsbdesc.dwFlags = 0;
  535. dsbdesc.dwBufferBytes = SECONDARY_BUFFER_SIZE_SURROUND * channelCount;
  536. dsbdesc.lpwfxFormat = (WAVEFORMATEX*)&wfx;
  537. bool bSuccess = false;
  538. for ( int i = 0; i < 3; i++ )
  539. {
  540. switch(i)
  541. {
  542. case 0:
  543. dsbdesc.dwFlags = DSBCAPS_LOCHARDWARE;
  544. break;
  545. case 1:
  546. dsbdesc.dwFlags = DSBCAPS_LOCSOFTWARE;
  547. break;
  548. case 2:
  549. dsbdesc.dwFlags = 0;
  550. break;
  551. }
  552. if ( !snd_mute_losefocus.GetBool() )
  553. {
  554. dsbdesc.dwFlags |= DSBCAPS_GLOBALFOCUS;
  555. }
  556. if(!FAILED(lpDS->CreateSoundBuffer(&dsbdesc, &pDSBuf, NULL)))
  557. {
  558. bSuccess = true;
  559. break;
  560. }
  561. }
  562. if ( !bSuccess )
  563. return false;
  564. DWORD dwSize = 0, dwWrite;
  565. DWORD *pBuffer = 0;
  566. if ( !LockDSBuffer( pDSBuf, &pBuffer, &dwSize, "DS_INTERLEAVED", DSBLOCK_ENTIREBUFFER ) )
  567. return false;
  568. m_nChannels = wfx.Format.nChannels;
  569. m_nSampleBits = wfx.Format.wBitsPerSample;
  570. m_nSampleRate = wfx.Format.nSamplesPerSec;
  571. m_bufferSizeBytes = dsbdesc.dwBufferBytes;
  572. m_isInterleaved = true;
  573. Q_memset( pBuffer, 0, dwSize );
  574. pDSBuf->Unlock(pBuffer, dwSize, NULL, 0);
  575. // 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)
  576. pDSBuf->Play(0, 0, DSBPLAY_LOOPING);
  577. pDSBuf->Stop();
  578. pDSBuf->GetCurrentPosition(&m_outputBufferStartOffset, &dwWrite);
  579. pDSBuf->Play(0, 0, DSBPLAY_LOOPING);
  580. return true;
  581. }
  582. /*
  583. ==================
  584. SNDDMA_InitDirect
  585. Direct-Sound support
  586. ==================
  587. */
  588. sndinitstat CAudioDirectSound::SNDDMA_InitDirect( void )
  589. {
  590. DSBUFFERDESC dsbuf;
  591. DSBCAPS dsbcaps;
  592. DWORD dwSize, dwWrite;
  593. WAVEFORMATEX format;
  594. WAVEFORMATEX pformat;
  595. HRESULT hresult;
  596. void *lpData = NULL;
  597. bool primary_format_set = false;
  598. int pri_channels = 2;
  599. if (!m_hInstDS)
  600. {
  601. m_hInstDS = LoadLibrary("dsound.dll");
  602. if (m_hInstDS == NULL)
  603. {
  604. Warning( "Couldn't load dsound.dll\n");
  605. return SIS_FAILURE;
  606. }
  607. pDirectSoundCreate = (long (__stdcall *)(struct _GUID *,struct IDirectSound ** ,struct IUnknown *))GetProcAddress(m_hInstDS,"DirectSoundCreate");
  608. if (!pDirectSoundCreate)
  609. {
  610. Warning( "Couldn't get DS proc addr\n");
  611. return SIS_FAILURE;
  612. }
  613. }
  614. while ((hresult = pDirectSoundCreate(NULL, &pDS, NULL)) != DS_OK)
  615. {
  616. if (hresult != DSERR_ALLOCATED)
  617. {
  618. DevMsg ("DirectSound create failed\n");
  619. return SIS_FAILURE;
  620. }
  621. return SIS_NOTAVAIL;
  622. }
  623. // get snd_surround value from window settings
  624. DetectWindowsSpeakerSetup();
  625. m_bSurround = false;
  626. m_bSurroundCenter = false;
  627. m_bIsHeadphone = false;
  628. m_isInterleaved = false;
  629. switch ( snd_surround.GetInt() )
  630. {
  631. case 0:
  632. m_bIsHeadphone = true; // stereo headphone
  633. pri_channels = 2; // primary buffer mixes stereo input data
  634. break;
  635. default:
  636. case 2:
  637. pri_channels = 2; // primary buffer mixes stereo input data
  638. break; // no surround
  639. case 4:
  640. m_bSurround = true; // quad surround
  641. pri_channels = 1; // primary buffer mixes 3d mono input data
  642. break;
  643. case 5:
  644. case 7:
  645. m_bSurround = true; // 5.1 surround
  646. m_bSurroundCenter = true;
  647. pri_channels = 1; // primary buffer mixes 3d mono input data
  648. break;
  649. }
  650. m_nChannels = pri_channels; // secondary buffers should have same # channels as primary
  651. m_nSampleBits = 16; // hardware bits per sample
  652. m_nSampleRate = SOUND_DMA_SPEED; // hardware playback rate
  653. Q_memset( &format, 0, sizeof(format) );
  654. format.wFormatTag = WAVE_FORMAT_PCM;
  655. format.nChannels = pri_channels;
  656. format.wBitsPerSample = m_nSampleBits;
  657. format.nSamplesPerSec = m_nSampleRate;
  658. format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8;
  659. format.cbSize = 0;
  660. format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
  661. DSCAPS dscaps;
  662. Q_memset( &dscaps, 0, sizeof(dscaps) );
  663. dscaps.dwSize = sizeof(dscaps);
  664. if (DS_OK != pDS->GetCaps(&dscaps))
  665. {
  666. Warning( "Couldn't get DS caps\n");
  667. }
  668. if (dscaps.dwFlags & DSCAPS_EMULDRIVER)
  669. {
  670. Warning( "No DirectSound driver installed\n");
  671. Shutdown();
  672. return SIS_FAILURE;
  673. }
  674. if (DS_OK != pDS->SetCooperativeLevel(*pmainwindow, DSSCL_EXCLUSIVE))
  675. {
  676. Warning( "Set coop level failed\n");
  677. Shutdown();
  678. return SIS_FAILURE;
  679. }
  680. // get access to the primary buffer, if possible, so we can set the
  681. // sound hardware format
  682. Q_memset( &dsbuf, 0, sizeof(dsbuf) );
  683. dsbuf.dwSize = sizeof(DSBUFFERDESC);
  684. dsbuf.dwFlags = DSBCAPS_PRIMARYBUFFER;
  685. if ( snd_legacy_surround.GetBool() || m_bSurround )
  686. {
  687. dsbuf.dwFlags |= DSBCAPS_CTRL3D;
  688. }
  689. dsbuf.dwBufferBytes = 0;
  690. dsbuf.lpwfxFormat = NULL;
  691. Q_memset( &dsbcaps, 0, sizeof(dsbcaps) );
  692. dsbcaps.dwSize = sizeof(dsbcaps);
  693. if ( !CommandLine()->CheckParm("-snoforceformat"))
  694. {
  695. if (DS_OK == pDS->CreateSoundBuffer(&dsbuf, &pDSPBuf, NULL))
  696. {
  697. pformat = format;
  698. if (DS_OK != pDSPBuf->SetFormat(&pformat))
  699. {
  700. if (snd_firsttime)
  701. DevMsg ("Set primary sound buffer format: no\n");
  702. }
  703. else
  704. {
  705. if (snd_firsttime)
  706. DevMsg ("Set primary sound buffer format: yes\n");
  707. primary_format_set = true;
  708. }
  709. }
  710. }
  711. m_pName = "Windows DirectSound";
  712. if ( m_bSurround )
  713. {
  714. // try to init surround
  715. m_bSurround = false;
  716. if ( snd_legacy_surround.GetBool() )
  717. {
  718. if (snd_surround.GetInt() == 4)
  719. {
  720. // attempt to init 4 channel surround
  721. m_bSurround = SNDDMA_InitSurround(pDS, &format, &dsbcaps, 4);
  722. if ( m_bSurround )
  723. {
  724. m_pName = "4 Channel Surround";
  725. }
  726. }
  727. else if (snd_surround.GetInt() == 5 || snd_surround.GetInt() == 7)
  728. {
  729. // attempt to init 5 channel surround
  730. m_bSurroundCenter = SNDDMA_InitSurround(pDS, &format, &dsbcaps, 5);
  731. m_bSurround = m_bSurroundCenter;
  732. if ( m_bSurroundCenter )
  733. {
  734. m_pName = "6 Channel Surround";
  735. }
  736. }
  737. }
  738. if ( !m_bSurround )
  739. {
  740. pri_channels = 6;
  741. if ( snd_surround.GetInt() < 5 )
  742. {
  743. pri_channels = 4;
  744. }
  745. m_bSurround = SNDDMA_InitInterleaved( pDS, &format, pri_channels );
  746. if ( m_bSurround )
  747. {
  748. m_pName = "Interleaved surround";
  749. }
  750. }
  751. }
  752. if ( !m_bSurround )
  753. {
  754. // snd_surround.SetValue( 0 );
  755. if ( !primary_format_set || !CommandLine()->CheckParm ("-primarysound") )
  756. {
  757. // create the secondary buffer we'll actually work with
  758. Q_memset( &dsbuf, 0, sizeof(dsbuf) );
  759. dsbuf.dwSize = sizeof(DSBUFFERDESC);
  760. dsbuf.dwFlags = DSBCAPS_LOCSOFTWARE; // NOTE: don't use CTRLFREQUENCY (slow)
  761. dsbuf.dwBufferBytes = SECONDARY_BUFFER_SIZE;
  762. dsbuf.lpwfxFormat = &format;
  763. if ( !snd_mute_losefocus.GetBool() )
  764. {
  765. dsbuf.dwFlags |= DSBCAPS_GLOBALFOCUS;
  766. }
  767. if (DS_OK != pDS->CreateSoundBuffer(&dsbuf, &pDSBuf, NULL))
  768. {
  769. Warning( "DS:CreateSoundBuffer Failed");
  770. Shutdown();
  771. return SIS_FAILURE;
  772. }
  773. m_nChannels = format.nChannels;
  774. m_nSampleBits = format.wBitsPerSample;
  775. m_nSampleRate = format.nSamplesPerSec;
  776. Q_memset(&dsbcaps, 0, sizeof(dsbcaps));
  777. dsbcaps.dwSize = sizeof(dsbcaps);
  778. if (DS_OK != pDSBuf->GetCaps( &dsbcaps ))
  779. {
  780. Warning( "DS:GetCaps failed\n");
  781. Shutdown();
  782. return SIS_FAILURE;
  783. }
  784. if ( snd_firsttime )
  785. DevMsg ("Using secondary sound buffer\n");
  786. }
  787. else
  788. {
  789. if (DS_OK != pDS->SetCooperativeLevel(*pmainwindow, DSSCL_WRITEPRIMARY))
  790. {
  791. Warning( "Set coop level failed\n");
  792. Shutdown();
  793. return SIS_FAILURE;
  794. }
  795. Q_memset(&dsbcaps, 0, sizeof(dsbcaps));
  796. dsbcaps.dwSize = sizeof(dsbcaps);
  797. if (DS_OK != pDSPBuf->GetCaps(&dsbcaps))
  798. {
  799. Msg ("DS:GetCaps failed\n");
  800. return SIS_FAILURE;
  801. }
  802. pDSBuf = pDSPBuf;
  803. DevMsg ("Using primary sound buffer\n");
  804. }
  805. if ( snd_firsttime )
  806. {
  807. DevMsg(" %d channel(s)\n"
  808. " %d bits/sample\n"
  809. " %d samples/sec\n",
  810. ChannelCount(), BitsPerSample(), SampleRate());
  811. }
  812. // initialize the buffer
  813. m_bufferSizeBytes = dsbcaps.dwBufferBytes;
  814. int reps = 0;
  815. while ((hresult = pDSBuf->Lock(0, m_bufferSizeBytes, (void**)&lpData, &dwSize, NULL, NULL, 0)) != DS_OK)
  816. {
  817. if (hresult != DSERR_BUFFERLOST)
  818. {
  819. Warning( "SNDDMA_InitDirect: DS::Lock Sound Buffer Failed\n");
  820. Shutdown();
  821. return SIS_FAILURE;
  822. }
  823. if (++reps > 10000)
  824. {
  825. Warning( "SNDDMA_InitDirect: DS: couldn't restore buffer\n");
  826. Shutdown();
  827. return SIS_FAILURE;
  828. }
  829. }
  830. Q_memset( lpData, 0, dwSize );
  831. pDSBuf->Unlock(lpData, dwSize, NULL, 0);
  832. // 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)
  833. pDSBuf->Play(0, 0, DSBPLAY_LOOPING);
  834. // we don't want anyone to access the buffer directly w/o locking it first.
  835. lpData = NULL;
  836. pDSBuf->Stop();
  837. pDSBuf->GetCurrentPosition(&m_outputBufferStartOffset, &dwWrite);
  838. pDSBuf->Play(0, 0, DSBPLAY_LOOPING);
  839. }
  840. // number of mono samples output buffer may hold
  841. m_deviceSampleCount = m_bufferSizeBytes/(DeviceSampleBytes());
  842. return SIS_SUCCESS;
  843. }
  844. static DWORD GetSpeakerConfigForSurroundMode( int surroundMode, const char **pConfigDesc )
  845. {
  846. DWORD newSpeakerConfig = DSSPEAKER_STEREO;
  847. const char *speakerConfigDesc = "";
  848. switch ( surroundMode )
  849. {
  850. case 0:
  851. newSpeakerConfig = DSSPEAKER_HEADPHONE;
  852. speakerConfigDesc = "headphone";
  853. break;
  854. case 2:
  855. default:
  856. newSpeakerConfig = DSSPEAKER_STEREO;
  857. speakerConfigDesc = "stereo speaker";
  858. break;
  859. case 4:
  860. newSpeakerConfig = DSSPEAKER_QUAD;
  861. speakerConfigDesc = "quad speaker";
  862. break;
  863. case 5:
  864. newSpeakerConfig = DSSPEAKER_5POINT1;
  865. speakerConfigDesc = "5.1 speaker";
  866. break;
  867. case 7:
  868. newSpeakerConfig = DSSPEAKER_7POINT1;
  869. speakerConfigDesc = "7.1 speaker";
  870. break;
  871. }
  872. if ( pConfigDesc )
  873. {
  874. *pConfigDesc = speakerConfigDesc;
  875. }
  876. return newSpeakerConfig;
  877. }
  878. // Read the speaker config from windows
  879. static DWORD GetWindowsSpeakerConfig()
  880. {
  881. DWORD speaker_config = windows_speaker_config.GetInt();
  882. if ( speaker_config < 0 )
  883. {
  884. speaker_config = DSSPEAKER_STEREO;
  885. if (DS_OK == pDS->GetSpeakerConfig( &speaker_config ))
  886. {
  887. // split out settings
  888. speaker_config = DSSPEAKER_CONFIG(speaker_config);
  889. if (speaker_config == DSSPEAKER_STEREO)
  890. speaker_config = DSSPEAKER_HEADPHONE;
  891. if ( speaker_config == DSSPEAKER_7POINT1_SURROUND )
  892. speaker_config = DSSPEAKER_5POINT1;
  893. if ( speaker_config == DSSPEAKER_5POINT1_SURROUND)
  894. speaker_config = DSSPEAKER_5POINT1;
  895. }
  896. windows_speaker_config.SetValue((int)speaker_config);
  897. }
  898. return speaker_config;
  899. }
  900. // Writes snd_surround convar given a directsound speaker config
  901. static void SetSurroundModeFromSpeakerConfig( DWORD speakerConfig )
  902. {
  903. // set the cvar to be the windows setting
  904. switch (speakerConfig)
  905. {
  906. case DSSPEAKER_HEADPHONE:
  907. snd_surround.SetValue(0);
  908. break;
  909. case DSSPEAKER_MONO:
  910. case DSSPEAKER_STEREO:
  911. default:
  912. snd_surround.SetValue( 2 );
  913. break;
  914. case DSSPEAKER_QUAD:
  915. snd_surround.SetValue(4);
  916. break;
  917. case DSSPEAKER_5POINT1:
  918. snd_surround.SetValue(5);
  919. break;
  920. case DSSPEAKER_7POINT1:
  921. snd_surround.SetValue(7);
  922. break;
  923. }
  924. }
  925. /*
  926. Sets the snd_surround_speakers cvar based on the windows setting
  927. */
  928. void CAudioDirectSound::DetectWindowsSpeakerSetup()
  929. {
  930. // detect speaker settings from windows
  931. DWORD speaker_config = GetWindowsSpeakerConfig();
  932. SetSurroundModeFromSpeakerConfig(speaker_config);
  933. // DEBUG
  934. if (speaker_config == DSSPEAKER_MONO)
  935. DevMsg( "DS:mono configuration detected\n");
  936. if (speaker_config == DSSPEAKER_HEADPHONE)
  937. DevMsg( "DS:headphone configuration detected\n");
  938. if (speaker_config == DSSPEAKER_STEREO)
  939. DevMsg( "DS:stereo speaker configuration detected\n");
  940. if (speaker_config == DSSPEAKER_QUAD)
  941. DevMsg( "DS:quad speaker configuration detected\n");
  942. if (speaker_config == DSSPEAKER_SURROUND)
  943. DevMsg( "DS:surround speaker configuration detected\n");
  944. if (speaker_config == DSSPEAKER_5POINT1)
  945. DevMsg( "DS:5.1 speaker configuration detected\n");
  946. if (speaker_config == DSSPEAKER_7POINT1)
  947. DevMsg( "DS:7.1 speaker configuration detected\n");
  948. }
  949. /*
  950. Updates windows settings based on snd_surround_speakers cvar changing
  951. This should only happen if the user has changed it via the console or the UI
  952. Changes won't take effect until the engine has restarted
  953. */
  954. void OnSndSurroundCvarChanged( IConVar *pVar, const char *pOldString, float flOldValue )
  955. {
  956. // if the old value is -1, we're setting this from the detect routine for the first time
  957. // no need to reset the device
  958. if (!pDS || flOldValue == -1 )
  959. return;
  960. // get the user's previous speaker config
  961. DWORD speaker_config = GetWindowsSpeakerConfig();
  962. // get the new config
  963. DWORD newSpeakerConfig = 0;
  964. const char *speakerConfigDesc = "";
  965. ConVarRef var( pVar );
  966. newSpeakerConfig = GetSpeakerConfigForSurroundMode( var.GetInt(), &speakerConfigDesc );
  967. // make sure the config has changed
  968. if (newSpeakerConfig == speaker_config)
  969. return;
  970. // set new configuration
  971. windows_speaker_config.SetValue( (int)newSpeakerConfig );
  972. Msg("Speaker configuration has been changed to %s.\n", speakerConfigDesc);
  973. // restart sound system so it takes effect
  974. g_pSoundServices->RestartSoundSystem();
  975. }
  976. void OnSndSurroundLegacyChanged( IConVar *pVar, const char *pOldString, float flOldValue )
  977. {
  978. ConVarRef var( pVar );
  979. if( var.GetFloat() == flOldValue )
  980. return;
  981. if ( pDS && CAudioDirectSound::m_pSingleton )
  982. {
  983. // should either be interleaved or have legacy surround set, not both
  984. if ( CAudioDirectSound::m_pSingleton->IsInterleaved() == var.GetBool() )
  985. {
  986. Msg( "Legacy Surround %s.\n", var.GetBool() ? "enabled" : "disabled" );
  987. // restart sound system so it takes effect
  988. g_pSoundServices->RestartSoundSystem();
  989. }
  990. }
  991. }
  992. void OnSndVarChanged( IConVar *pVar, const char *pOldString, float flOldValue )
  993. {
  994. ConVarRef var(pVar);
  995. // restart sound system so the change takes effect
  996. if ( var.GetInt() != int(flOldValue) )
  997. {
  998. g_pSoundServices->RestartSoundSystem();
  999. }
  1000. }
  1001. /*
  1002. Release all Surround buffer pointers
  1003. */
  1004. void ReleaseSurround(void)
  1005. {
  1006. if ( pDSBuf3DFL != NULL )
  1007. {
  1008. pDSBuf3DFL->Release();
  1009. pDSBuf3DFL = NULL;
  1010. }
  1011. if ( pDSBuf3DFR != NULL)
  1012. {
  1013. pDSBuf3DFR->Release();
  1014. pDSBuf3DFR = NULL;
  1015. }
  1016. if ( pDSBuf3DRL != NULL )
  1017. {
  1018. pDSBuf3DRL->Release();
  1019. pDSBuf3DRL = NULL;
  1020. }
  1021. if ( pDSBuf3DRR != NULL )
  1022. {
  1023. pDSBuf3DRR->Release();
  1024. pDSBuf3DRR = NULL;
  1025. }
  1026. if ( pDSBufFL != NULL )
  1027. {
  1028. pDSBufFL->Release();
  1029. pDSBufFL = NULL;
  1030. }
  1031. if ( pDSBufFR != NULL )
  1032. {
  1033. pDSBufFR->Release();
  1034. pDSBufFR = NULL;
  1035. }
  1036. if ( pDSBufRL != NULL )
  1037. {
  1038. pDSBufRL->Release();
  1039. pDSBufRL = NULL;
  1040. }
  1041. if ( pDSBufRR != NULL )
  1042. {
  1043. pDSBufRR->Release();
  1044. pDSBufRR = NULL;
  1045. }
  1046. if ( pDSBufFC != NULL )
  1047. {
  1048. pDSBufFC->Release();
  1049. pDSBufFC = NULL;
  1050. }
  1051. }
  1052. void DEBUG_DS_FillSquare( void *lpData, DWORD dwSize )
  1053. {
  1054. short *lpshort = (short *)lpData;
  1055. DWORD j = MIN(10000, dwSize/2);
  1056. for (DWORD i = 0; i < j; i++)
  1057. lpshort[i] = 8000;
  1058. }
  1059. void DEBUG_DS_FillSquare2( void *lpData, DWORD dwSize )
  1060. {
  1061. short *lpshort = (short *)lpData;
  1062. DWORD j = MIN(1000, dwSize/2);
  1063. for (DWORD i = 0; i < j; i++)
  1064. lpshort[i] = 16000;
  1065. }
  1066. // helper to set default buffer params
  1067. void DS3D_SetBufferParams( LPDIRECTSOUND3DBUFFER pDSBuf3D, D3DVECTOR *pbpos, D3DVECTOR *pbdir )
  1068. {
  1069. DS3DBUFFER bparm;
  1070. D3DVECTOR bvel;
  1071. D3DVECTOR bpos, bdir;
  1072. HRESULT hr;
  1073. bvel.x = 0.0f; bvel.y = 0.0f; bvel.z = 0.0f;
  1074. bpos = *pbpos;
  1075. bdir = *pbdir;
  1076. bparm.dwSize = sizeof(DS3DBUFFER);
  1077. hr = pDSBuf3D->GetAllParameters( &bparm );
  1078. bparm.vPosition = bpos;
  1079. bparm.vVelocity = bvel;
  1080. bparm.dwInsideConeAngle = 5.0; // narrow cones for each speaker
  1081. bparm.dwOutsideConeAngle = 10.0;
  1082. bparm.vConeOrientation = bdir;
  1083. bparm.lConeOutsideVolume = DSBVOLUME_MIN;
  1084. bparm.flMinDistance = 100.0; // no rolloff (until > 2.0 meter distance)
  1085. bparm.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
  1086. bparm.dwMode = DS3DMODE_NORMAL;
  1087. hr = pDSBuf3D->SetAllParameters( &bparm, DS3D_DEFERRED );
  1088. }
  1089. // Initialization for Surround sound support (4 channel or 5 channel).
  1090. // Creates 4 or 5 mono 3D buffers to be used as Front Left, (Front Center), Front Right, Rear Left, Rear Right
  1091. bool CAudioDirectSound::SNDDMA_InitSurround(LPDIRECTSOUND lpDS, WAVEFORMATEX* lpFormat, DSBCAPS* lpdsbc, int cchan)
  1092. {
  1093. DSBUFFERDESC dsbuf;
  1094. WAVEFORMATEX wvex;
  1095. DWORD dwSize, dwWrite;
  1096. int reps;
  1097. HRESULT hresult;
  1098. void *lpData = NULL;
  1099. if ( lpDS == NULL ) return FALSE;
  1100. // Force format to mono channel
  1101. memcpy(&wvex, lpFormat, sizeof(WAVEFORMATEX));
  1102. wvex.nChannels = 1;
  1103. wvex.nBlockAlign = wvex.nChannels * wvex.wBitsPerSample / 8;
  1104. wvex.nAvgBytesPerSec = wvex.nSamplesPerSec * wvex.nBlockAlign;
  1105. memset (&dsbuf, 0, sizeof(dsbuf));
  1106. dsbuf.dwSize = sizeof(DSBUFFERDESC);
  1107. // NOTE: LOCHARDWARE causes SB AWE64 to crash in it's DSOUND driver
  1108. dsbuf.dwFlags = DSBCAPS_CTRL3D; // don't use CTRLFREQUENCY (slow)
  1109. if ( !snd_mute_losefocus.GetBool() )
  1110. {
  1111. dsbuf.dwFlags |= DSBCAPS_GLOBALFOCUS;
  1112. }
  1113. // reserve space for each buffer
  1114. dsbuf.dwBufferBytes = SECONDARY_BUFFER_SIZE_SURROUND;
  1115. dsbuf.lpwfxFormat = &wvex;
  1116. // create 4 mono buffers FL, FR, RL, RR
  1117. if (DS_OK != lpDS->CreateSoundBuffer(&dsbuf, &pDSBufFL, NULL))
  1118. {
  1119. Warning( "DS:CreateSoundBuffer for 3d front left failed");
  1120. ReleaseSurround();
  1121. return FALSE;
  1122. }
  1123. if (DS_OK != lpDS->CreateSoundBuffer(&dsbuf, &pDSBufFR, NULL))
  1124. {
  1125. Warning( "DS:CreateSoundBuffer for 3d front right failed");
  1126. ReleaseSurround();
  1127. return FALSE;
  1128. }
  1129. if (DS_OK != lpDS->CreateSoundBuffer(&dsbuf, &pDSBufRL, NULL))
  1130. {
  1131. Warning( "DS:CreateSoundBuffer for 3d rear left failed");
  1132. ReleaseSurround();
  1133. return FALSE;
  1134. }
  1135. if (DS_OK != lpDS->CreateSoundBuffer(&dsbuf, &pDSBufRR, NULL))
  1136. {
  1137. Warning( "DS:CreateSoundBuffer for 3d rear right failed");
  1138. ReleaseSurround();
  1139. return FALSE;
  1140. }
  1141. // create center channel
  1142. if (cchan == 5)
  1143. {
  1144. if (DS_OK != lpDS->CreateSoundBuffer(&dsbuf, &pDSBufFC, NULL))
  1145. {
  1146. Warning( "DS:CreateSoundBuffer for 3d front center failed");
  1147. ReleaseSurround();
  1148. return FALSE;
  1149. }
  1150. }
  1151. // Try to get 4 or 5 3D buffers from the mono DS buffers
  1152. if (DS_OK != pDSBufFL->QueryInterface(IID_IDirectSound3DBufferDef, (void**)&pDSBuf3DFL))
  1153. {
  1154. Warning( "DS:Query 3DBuffer for 3d front left failed");
  1155. ReleaseSurround();
  1156. return FALSE;
  1157. }
  1158. if (DS_OK != pDSBufFR->QueryInterface(IID_IDirectSound3DBufferDef, (void**)&pDSBuf3DFR))
  1159. {
  1160. Warning( "DS:Query 3DBuffer for 3d front right failed");
  1161. ReleaseSurround();
  1162. return FALSE;
  1163. }
  1164. if (DS_OK != pDSBufRL->QueryInterface(IID_IDirectSound3DBufferDef, (void**)&pDSBuf3DRL))
  1165. {
  1166. Warning( "DS:Query 3DBuffer for 3d rear left failed");
  1167. ReleaseSurround();
  1168. return FALSE;
  1169. }
  1170. if (DS_OK != pDSBufRR->QueryInterface(IID_IDirectSound3DBufferDef, (void**)&pDSBuf3DRR))
  1171. {
  1172. Warning( "DS:Query 3DBuffer for 3d rear right failed");
  1173. ReleaseSurround();
  1174. return FALSE;
  1175. }
  1176. if (cchan == 5)
  1177. {
  1178. if (DS_OK != pDSBufFC->QueryInterface(IID_IDirectSound3DBufferDef, (void**)&pDSBuf3DFC))
  1179. {
  1180. Warning( "DS:Query 3DBuffer for 3d front center failed");
  1181. ReleaseSurround();
  1182. return FALSE;
  1183. }
  1184. }
  1185. // set listener position & orientation.
  1186. // DS uses left handed coord system: +x is right, +y is up, +z is forward
  1187. HRESULT hr;
  1188. IDirectSound3DListener *plistener = NULL;
  1189. hr = pDSPBuf->QueryInterface(IID_IDirectSound3DListener, (void**)&plistener);
  1190. if (plistener)
  1191. {
  1192. DS3DLISTENER lparm;
  1193. lparm.dwSize = sizeof(DS3DLISTENER);
  1194. hr = plistener->GetAllParameters( &lparm );
  1195. hr = plistener->SetOrientation( 0.0f,0.0f,1.0f, 0.0f,1.0f,0.0f, DS3D_IMMEDIATE); // frontx,y,z topx,y,z
  1196. hr = plistener->SetPosition(0.0f, 0.0f, 0.0f, DS3D_IMMEDIATE);
  1197. }
  1198. else
  1199. {
  1200. Warning( "DS: failed to get 3D listener interface.");
  1201. ReleaseSurround();
  1202. return FALSE;
  1203. }
  1204. // set 3d buffer position and orientation params
  1205. D3DVECTOR bpos, bdir;
  1206. bpos.x = -1.0; bpos.y = 0.0; bpos.z = 1.0; // FL
  1207. bdir.x = 1.0; bdir.y = 0.0; bdir.z = -1.0;
  1208. DS3D_SetBufferParams( pDSBuf3DFL, &bpos, &bdir );
  1209. bpos.x = 1.0; bpos.y = 0.0; bpos.z = 1.0; // FR
  1210. bdir.x = -1.0; bdir.y = 0.0; bdir.z = -1.0;
  1211. DS3D_SetBufferParams( pDSBuf3DFR, &bpos, &bdir );
  1212. bpos.x = -1.0; bpos.y = 0.0; bpos.z = -1.0; // RL
  1213. bdir.x = 1.0; bdir.y = 0.0; bdir.z = 1.0;
  1214. DS3D_SetBufferParams( pDSBuf3DRL, &bpos, &bdir );
  1215. bpos.x = 1.0; bpos.y = 0.0; bpos.z = -1.0; // RR
  1216. bdir.x = -1.0; bdir.y = 0.0; bdir.z = 1.0;
  1217. DS3D_SetBufferParams( pDSBuf3DRR, &bpos, &bdir );
  1218. if (cchan == 5)
  1219. {
  1220. bpos.x = 0.0; bpos.y = 0.0; bpos.z = 1.0; // FC
  1221. bdir.x = 0.0; bdir.y = 0.0; bdir.z = -1.0;
  1222. DS3D_SetBufferParams( pDSBuf3DFC, &bpos, &bdir );
  1223. }
  1224. // commit all buffer param settings
  1225. hr = plistener->CommitDeferredSettings();
  1226. m_nChannels = 1; // 1 mono 3d output buffer
  1227. m_nSampleBits = lpFormat->wBitsPerSample;
  1228. m_nSampleRate = lpFormat->nSamplesPerSec;
  1229. memset(lpdsbc, 0, sizeof(DSBCAPS));
  1230. lpdsbc->dwSize = sizeof(DSBCAPS);
  1231. if (DS_OK != pDSBufFL->GetCaps (lpdsbc))
  1232. {
  1233. Warning( "DS:GetCaps failed for 3d sound buffer\n");
  1234. ReleaseSurround();
  1235. return FALSE;
  1236. }
  1237. pDSBufFL->Play(0, 0, DSBPLAY_LOOPING);
  1238. pDSBufFR->Play(0, 0, DSBPLAY_LOOPING);
  1239. pDSBufRL->Play(0, 0, DSBPLAY_LOOPING);
  1240. pDSBufRR->Play(0, 0, DSBPLAY_LOOPING);
  1241. if (cchan == 5)
  1242. pDSBufFC->Play(0, 0, DSBPLAY_LOOPING);
  1243. if (snd_firsttime)
  1244. DevMsg(" %d channel(s)\n"
  1245. " %d bits/sample\n"
  1246. " %d samples/sec\n",
  1247. cchan, BitsPerSample(), SampleRate());
  1248. m_bufferSizeBytes = lpdsbc->dwBufferBytes;
  1249. // Test everything just like in the normal initialization.
  1250. if (cchan == 5)
  1251. {
  1252. reps = 0;
  1253. while ((hresult = pDSBufFC->Lock(0, lpdsbc->dwBufferBytes, (void**)&lpData, &dwSize, NULL, NULL, 0)) != DS_OK)
  1254. {
  1255. if (hresult != DSERR_BUFFERLOST)
  1256. {
  1257. Warning( "SNDDMA_InitDirect: DS::Lock Sound Buffer Failed for FC\n");
  1258. ReleaseSurround();
  1259. return FALSE;
  1260. }
  1261. if (++reps > 10000)
  1262. {
  1263. Warning( "SNDDMA_InitDirect: DS: couldn't restore buffer for FC\n");
  1264. ReleaseSurround();
  1265. return FALSE;
  1266. }
  1267. }
  1268. memset(lpData, 0, dwSize);
  1269. // DEBUG_DS_FillSquare( lpData, dwSize );
  1270. pDSBufFC->Unlock(lpData, dwSize, NULL, 0);
  1271. }
  1272. reps = 0;
  1273. while ((hresult = pDSBufFL->Lock(0, lpdsbc->dwBufferBytes, (void**)&lpData, &dwSize, NULL, NULL, 0)) != DS_OK)
  1274. {
  1275. if (hresult != DSERR_BUFFERLOST)
  1276. {
  1277. Warning( "SNDDMA_InitSurround: DS::Lock Sound Buffer Failed for 3d FL\n");
  1278. ReleaseSurround();
  1279. return FALSE;
  1280. }
  1281. if (++reps > 10000)
  1282. {
  1283. Warning( "SNDDMA_InitSurround: DS: couldn't restore buffer for 3d FL\n");
  1284. ReleaseSurround();
  1285. return FALSE;
  1286. }
  1287. }
  1288. memset(lpData, 0, dwSize);
  1289. // DEBUG_DS_FillSquare( lpData, dwSize );
  1290. pDSBufFL->Unlock(lpData, dwSize, NULL, 0);
  1291. reps = 0;
  1292. while ((hresult = pDSBufFR->Lock(0, lpdsbc->dwBufferBytes, (void**)&lpData, &dwSize, NULL, NULL, 0)) != DS_OK)
  1293. {
  1294. if (hresult != DSERR_BUFFERLOST)
  1295. {
  1296. Warning( "SNDDMA_InitSurround: DS::Lock Sound Buffer Failed for 3d FR\n");
  1297. ReleaseSurround();
  1298. return FALSE;
  1299. }
  1300. if (++reps > 10000)
  1301. {
  1302. Warning( "SNDDMA_InitSurround: DS: couldn't restore buffer for FR\n");
  1303. ReleaseSurround();
  1304. return FALSE;
  1305. }
  1306. }
  1307. memset(lpData, 0, dwSize);
  1308. // DEBUG_DS_FillSquare( lpData, dwSize );
  1309. pDSBufFR->Unlock(lpData, dwSize, NULL, 0);
  1310. reps = 0;
  1311. while ((hresult = pDSBufRL->Lock(0, lpdsbc->dwBufferBytes, (void**)&lpData, &dwSize, NULL, NULL, 0)) != DS_OK)
  1312. {
  1313. if (hresult != DSERR_BUFFERLOST)
  1314. {
  1315. Warning( "SNDDMA_InitDirect: DS::Lock Sound Buffer Failed for RL\n");
  1316. ReleaseSurround();
  1317. return FALSE;
  1318. }
  1319. if (++reps > 10000)
  1320. {
  1321. Warning( "SNDDMA_InitDirect: DS: couldn't restore buffer for RL\n");
  1322. ReleaseSurround();
  1323. return FALSE;
  1324. }
  1325. }
  1326. memset(lpData, 0, dwSize);
  1327. // DEBUG_DS_FillSquare( lpData, dwSize );
  1328. pDSBufRL->Unlock(lpData, dwSize, NULL, 0);
  1329. reps = 0;
  1330. while ((hresult = pDSBufRR->Lock(0, lpdsbc->dwBufferBytes, (void**)&lpData, &dwSize, NULL, NULL, 0)) != DS_OK)
  1331. {
  1332. if (hresult != DSERR_BUFFERLOST)
  1333. {
  1334. Warning( "SNDDMA_InitDirect: DS::Lock Sound Buffer Failed for RR\n");
  1335. ReleaseSurround();
  1336. return FALSE;
  1337. }
  1338. if (++reps > 10000)
  1339. {
  1340. Warning( "SNDDMA_InitDirect: DS: couldn't restore buffer for RR\n");
  1341. ReleaseSurround();
  1342. return FALSE;
  1343. }
  1344. }
  1345. memset(lpData, 0, dwSize);
  1346. // DEBUG_DS_FillSquare( lpData, dwSize );
  1347. pDSBufRR->Unlock(lpData, dwSize, NULL, 0);
  1348. lpData = NULL; // this is invalid now
  1349. // OK Stop and get our positions and were good to go.
  1350. pDSBufFL->Stop();
  1351. pDSBufFR->Stop();
  1352. pDSBufRL->Stop();
  1353. pDSBufRR->Stop();
  1354. if (cchan == 5)
  1355. pDSBufFC->Stop();
  1356. // get hardware playback position, store it, syncronize all buffers to FL
  1357. pDSBufFL->GetCurrentPosition(&m_outputBufferStartOffset, &dwWrite);
  1358. pDSBufFR->SetCurrentPosition(m_outputBufferStartOffset);
  1359. pDSBufRL->SetCurrentPosition(m_outputBufferStartOffset);
  1360. pDSBufRR->SetCurrentPosition(m_outputBufferStartOffset);
  1361. if (cchan == 5)
  1362. pDSBufFC->SetCurrentPosition(m_outputBufferStartOffset);
  1363. pDSBufFL->Play(0, 0, DSBPLAY_LOOPING);
  1364. pDSBufFR->Play(0, 0, DSBPLAY_LOOPING);
  1365. pDSBufRL->Play(0, 0, DSBPLAY_LOOPING);
  1366. pDSBufRR->Play(0, 0, DSBPLAY_LOOPING);
  1367. if (cchan == 5)
  1368. pDSBufFC->Play(0, 0, DSBPLAY_LOOPING);
  1369. if (snd_firsttime)
  1370. Warning( "3d surround sound initialization successful\n");
  1371. return TRUE;
  1372. }
  1373. // use the partial buffer locking code in stereo as well - not available when recording a movie
  1374. ConVar snd_lockpartial("snd_lockpartial","1");
  1375. // Transfer up to a full paintbuffer (PAINTBUFFER_SIZE) of stereo samples
  1376. // out to the directsound secondary buffer(s).
  1377. // For 4 or 5 ch surround, there are 4 or 5 mono 16 bit secondary DS streaming buffers.
  1378. // For stereo speakers, there is one stereo 16 bit secondary DS streaming buffer.
  1379. void CAudioDirectSound::TransferSamples( int end )
  1380. {
  1381. int64 lpaintedtime = g_paintedtime;
  1382. int64 endtime = end;
  1383. // When Surround is enabled, divert to 4 or 5 chan xfer scheme.
  1384. if ( m_bSurround )
  1385. {
  1386. if ( m_isInterleaved )
  1387. {
  1388. S_TransferSurround16Interleaved( PAINTBUFFER, REARPAINTBUFFER, CENTERPAINTBUFFER, lpaintedtime, endtime);
  1389. }
  1390. else
  1391. {
  1392. int cchan = ( m_bSurroundCenter ? 5 : 4);
  1393. S_TransferSurround16( PAINTBUFFER, REARPAINTBUFFER, CENTERPAINTBUFFER, lpaintedtime, endtime, cchan);
  1394. }
  1395. return;
  1396. }
  1397. else if ( snd_lockpartial.GetBool() && ChannelCount() == 2 && BitsPerSample() == 16 && !SND_IsRecording() )
  1398. {
  1399. S_TransferSurround16Interleaved( PAINTBUFFER, NULL, NULL, lpaintedtime, endtime );
  1400. }
  1401. else
  1402. {
  1403. DWORD *pBuffer = NULL;
  1404. DWORD dwSize = 0;
  1405. if ( !LockDSBuffer( pDSBuf, &pBuffer, &dwSize, "DS_STEREO" ) )
  1406. {
  1407. S_Shutdown();
  1408. S_Startup();
  1409. return;
  1410. }
  1411. if ( pBuffer )
  1412. {
  1413. S_TransferStereo16( pBuffer, PAINTBUFFER, lpaintedtime, endtime );
  1414. pDSBuf->Unlock( pBuffer, dwSize, NULL, 0 );
  1415. }
  1416. }
  1417. }
  1418. bool CAudioDirectSound::IsUsingBufferPerSpeaker()
  1419. {
  1420. return m_bSurround && !m_isInterleaved;
  1421. }
  1422. bool CAudioDirectSound::LockDSBuffer( LPDIRECTSOUNDBUFFER pBuffer, DWORD **pdwWriteBuffer, DWORD *pdwSizeBuffer, const char *pBufferName, int lockFlags )
  1423. {
  1424. if ( !pBuffer )
  1425. return false;
  1426. HRESULT hr;
  1427. int reps = 0;
  1428. while ((hr = pBuffer->Lock(0, m_bufferSizeBytes, (void**)pdwWriteBuffer, pdwSizeBuffer,
  1429. NULL, NULL, lockFlags)) != DS_OK)
  1430. {
  1431. if (hr != DSERR_BUFFERLOST)
  1432. {
  1433. Msg ("DS::Lock Sound Buffer Failed %s\n", pBufferName);
  1434. return false;
  1435. }
  1436. if (++reps > 10000)
  1437. {
  1438. Msg ("DS:: couldn't restore buffer %s\n", pBufferName);
  1439. return false;
  1440. }
  1441. }
  1442. return true;
  1443. }
  1444. //////////////////////////////////////////////////////////////////////////////////////////////////
  1445. // Given front, rear and center stereo paintbuffers, split samples into 4 or 5 mono directsound buffers (FL, FC, FR, RL, RR)
  1446. void CAudioDirectSound::S_TransferSurround16( portable_samplepair_t *pfront, portable_samplepair_t *prear, portable_samplepair_t *pcenter, int64 lpaintedtime, int64 endtime, int cchan)
  1447. {
  1448. int lpos;
  1449. DWORD *pdwWriteFL=NULL, *pdwWriteFR=NULL, *pdwWriteRL=NULL, *pdwWriteRR=NULL, *pdwWriteFC=NULL;
  1450. DWORD dwSizeFL=0, dwSizeFR=0, dwSizeRL=0, dwSizeRR=0, dwSizeFC=0;
  1451. int i, j, *snd_p, *snd_rp, *snd_cp, volumeFactor;
  1452. short *snd_out_fleft, *snd_out_fright, *snd_out_rleft, *snd_out_rright, *snd_out_fcenter;
  1453. pdwWriteFC = NULL; // compiler warning
  1454. dwSizeFC = 0;
  1455. snd_out_fcenter = NULL;
  1456. volumeFactor = S_GetMasterVolume() * 256;
  1457. // lock all 4 or 5 mono directsound buffers FL, FR, RL, RR, FC
  1458. if ( !LockDSBuffer( pDSBufFL, &pdwWriteFL, &dwSizeFL, "FL" ) ||
  1459. !LockDSBuffer( pDSBufFR, &pdwWriteFR, &dwSizeFR, "FR" ) ||
  1460. !LockDSBuffer( pDSBufRL, &pdwWriteRL, &dwSizeRL, "RL" ) ||
  1461. !LockDSBuffer( pDSBufRR, &pdwWriteRR, &dwSizeRR, "RR" ) )
  1462. {
  1463. S_Shutdown();
  1464. S_Startup();
  1465. return;
  1466. }
  1467. if (cchan == 5 && !LockDSBuffer( pDSBufFC, &pdwWriteFC, &dwSizeFC, "FC" ))
  1468. {
  1469. S_Shutdown ();
  1470. S_Startup ();
  1471. return;
  1472. }
  1473. // take stereo front and rear paintbuffers, and center paintbuffer if provided,
  1474. // and copy samples into the 4 or 5 mono directsound buffers
  1475. snd_rp = (int *)prear;
  1476. snd_cp = (int *)pcenter;
  1477. snd_p = (int *)pfront;
  1478. int linearCount; // space in output buffer for linearCount mono samples
  1479. int sampleMonoCount = DeviceSampleCount(); // number of mono samples per output buffer (was;(DeviceSampleCount()>>1))
  1480. int sampleMask = sampleMonoCount - 1;
  1481. // paintedtime - number of full samples that have played since start
  1482. // endtime - number of full samples to play to - endtime is g_soundtime + mixahead samples
  1483. while (lpaintedtime < endtime)
  1484. {
  1485. lpos = lpaintedtime & sampleMask; // lpos is next output position in output buffer
  1486. linearCount = sampleMonoCount - lpos;
  1487. // limit output count to requested number of samples
  1488. if (linearCount > endtime - lpaintedtime)
  1489. linearCount = endtime - lpaintedtime;
  1490. snd_out_fleft = (short *)pdwWriteFL + lpos;
  1491. snd_out_fright = (short *)pdwWriteFR + lpos;
  1492. snd_out_rleft = (short *)pdwWriteRL + lpos;
  1493. snd_out_rright = (short *)pdwWriteRR + lpos;
  1494. if (cchan == 5)
  1495. snd_out_fcenter = (short *)pdwWriteFC + lpos;
  1496. // for 16 bit sample in the front and rear stereo paintbuffers, copy
  1497. // into the 4 or 5 FR, FL, RL, RR, FC directsound paintbuffers
  1498. for (i=0, j= 0 ; i<linearCount ; i++, j+=2)
  1499. {
  1500. snd_out_fleft[i] = (snd_p[j]*volumeFactor)>>8;
  1501. snd_out_fright[i] = (snd_p[j + 1]*volumeFactor)>>8;
  1502. snd_out_rleft[i] = (snd_rp[j]*volumeFactor)>>8;
  1503. snd_out_rright[i] = (snd_rp[j + 1]*volumeFactor)>>8;
  1504. }
  1505. // copy front center buffer (mono) data to center chan directsound paintbuffer
  1506. if (cchan == 5)
  1507. {
  1508. for (i=0, j=0 ; i<linearCount ; i++, j+=2)
  1509. {
  1510. snd_out_fcenter[i] = (snd_cp[j]*volumeFactor)>>8;
  1511. }
  1512. }
  1513. snd_p += linearCount << 1;
  1514. snd_rp += linearCount << 1;
  1515. snd_cp += linearCount << 1;
  1516. lpaintedtime += linearCount;
  1517. }
  1518. pDSBufFL->Unlock(pdwWriteFL, dwSizeFL, NULL, 0);
  1519. pDSBufFR->Unlock(pdwWriteFR, dwSizeFR, NULL, 0);
  1520. pDSBufRL->Unlock(pdwWriteRL, dwSizeRL, NULL, 0);
  1521. pDSBufRR->Unlock(pdwWriteRR, dwSizeRR, NULL, 0);
  1522. if (cchan == 5)
  1523. pDSBufFC->Unlock(pdwWriteFC, dwSizeFC, NULL, 0);
  1524. }
  1525. struct surround_transfer_t
  1526. {
  1527. int64 paintedtime;
  1528. int linearCount;
  1529. int sampleMask;
  1530. int channelCount;
  1531. int *snd_p;
  1532. int *snd_rp;
  1533. int *snd_cp;
  1534. short *pOutput;
  1535. };
  1536. static void TransferSamplesToSurroundBuffer( int outputCount, surround_transfer_t &transfer )
  1537. {
  1538. int i, j;
  1539. int volumeFactor = S_GetMasterVolume() * 256;
  1540. if ( transfer.channelCount == 2 )
  1541. {
  1542. for (i=0, j=0; i<outputCount ; i++, j+=2)
  1543. {
  1544. transfer.pOutput[0] = (transfer.snd_p[j]*volumeFactor)>>8; // FL
  1545. transfer.pOutput[1] = (transfer.snd_p[j + 1]*volumeFactor)>>8; // FR
  1546. transfer.pOutput += 2;
  1547. }
  1548. }
  1549. // no center channel, 4 channel surround
  1550. else if ( transfer.channelCount == 4 )
  1551. {
  1552. for (i=0, j=0; i<outputCount ; i++, j+=2)
  1553. {
  1554. transfer.pOutput[0] = (transfer.snd_p[j]*volumeFactor)>>8; // FL
  1555. transfer.pOutput[1] = (transfer.snd_p[j + 1]*volumeFactor)>>8; // FR
  1556. transfer.pOutput[2] = (transfer.snd_rp[j]*volumeFactor)>>8; // RL
  1557. transfer.pOutput[3] = (transfer.snd_rp[j + 1]*volumeFactor)>>8; // RR
  1558. transfer.pOutput += 4;
  1559. //Assert( baseOffset <= (DeviceSampleCount()) );
  1560. }
  1561. }
  1562. else
  1563. {
  1564. Assert(transfer.snd_cp);
  1565. // 6 channel / 5.1
  1566. for (i=0, j=0 ; i<outputCount ; i++, j+=2)
  1567. {
  1568. transfer.pOutput[0] = (transfer.snd_p[j]*volumeFactor)>>8; // FL
  1569. transfer.pOutput[1] = (transfer.snd_p[j + 1]*volumeFactor)>>8; // FR
  1570. transfer.pOutput[2] = (transfer.snd_cp[j]*volumeFactor)>>8; // Center
  1571. transfer.pOutput[3] = 0;
  1572. transfer.pOutput[4] = (transfer.snd_rp[j]*volumeFactor)>>8; // RL
  1573. transfer.pOutput[5] = (transfer.snd_rp[j + 1]*volumeFactor)>>8; // RR
  1574. #if 0
  1575. // average channels into the subwoofer, let the sub filter the output
  1576. // NOTE: avg l/r rear to do 2 shifts instead of divide by 5
  1577. int sumFront = (int)transfer.pOutput[0] + (int)transfer.pOutput[1] + (int)transfer.pOutput[2];
  1578. int sumRear = (int)transfer.pOutput[4] + (int)transfer.pOutput[5];
  1579. transfer.pOutput[3] = (sumFront + (sumRear>>1)) >> 2;
  1580. #endif
  1581. transfer.pOutput += 6;
  1582. //Assert( baseOffset <= (DeviceSampleCount()) );
  1583. }
  1584. }
  1585. transfer.snd_p += outputCount << 1;
  1586. if ( transfer.snd_rp )
  1587. {
  1588. transfer.snd_rp += outputCount << 1;
  1589. }
  1590. if ( transfer.snd_cp )
  1591. {
  1592. transfer.snd_cp += outputCount << 1;
  1593. }
  1594. transfer.paintedtime += outputCount;
  1595. transfer.linearCount -= outputCount;
  1596. }
  1597. void CAudioDirectSound::S_TransferSurround16Interleaved_FullLock( const portable_samplepair_t *pfront, const portable_samplepair_t *prear, const portable_samplepair_t *pcenter, int64 lpaintedtime, int64 endtime )
  1598. {
  1599. int lpos;
  1600. DWORD *pdwWrite = NULL;
  1601. DWORD dwSize = 0;
  1602. int i, j, *snd_p, *snd_rp, *snd_cp, volumeFactor;
  1603. volumeFactor = S_GetMasterVolume() * 256;
  1604. int channelCount = m_bSurroundCenter ? 5 : 4;
  1605. if ( ChannelCount() == 2 )
  1606. {
  1607. channelCount = 2;
  1608. }
  1609. // lock single interleaved buffer
  1610. if ( !LockDSBuffer( pDSBuf, &pdwWrite, &dwSize, "DS_INTERLEAVED" ) )
  1611. {
  1612. S_Shutdown ();
  1613. S_Startup ();
  1614. return;
  1615. }
  1616. // take stereo front and rear paintbuffers, and center paintbuffer if provided,
  1617. // and copy samples into the 4 or 5 mono directsound buffers
  1618. snd_rp = (int *)prear;
  1619. snd_cp = (int *)pcenter;
  1620. snd_p = (int *)pfront;
  1621. int linearCount; // space in output buffer for linearCount mono samples
  1622. int sampleMonoCount = m_bufferSizeBytes/(DeviceSampleBytes()*ChannelCount()); // number of mono samples per output buffer (was;(DeviceSampleCount()>>1))
  1623. int sampleMask = sampleMonoCount - 1;
  1624. // paintedtime - number of full samples that have played since start
  1625. // endtime - number of full samples to play to - endtime is g_soundtime + mixahead samples
  1626. short *pOutput = (short *)pdwWrite;
  1627. while (lpaintedtime < endtime)
  1628. {
  1629. lpos = lpaintedtime & sampleMask; // lpos is next output position in output buffer
  1630. linearCount = sampleMonoCount - lpos;
  1631. // limit output count to requested number of samples
  1632. if (linearCount > endtime - lpaintedtime)
  1633. linearCount = endtime - lpaintedtime;
  1634. if ( channelCount == 4 )
  1635. {
  1636. int baseOffset = lpos * channelCount;
  1637. for (i=0, j= 0 ; i<linearCount ; i++, j+=2)
  1638. {
  1639. pOutput[baseOffset+0] = (snd_p[j]*volumeFactor)>>8; // FL
  1640. pOutput[baseOffset+1] = (snd_p[j + 1]*volumeFactor)>>8; // FR
  1641. pOutput[baseOffset+2] = (snd_rp[j]*volumeFactor)>>8; // RL
  1642. pOutput[baseOffset+3] = (snd_rp[j + 1]*volumeFactor)>>8; // RR
  1643. baseOffset += 4;
  1644. }
  1645. }
  1646. else
  1647. {
  1648. Assert(channelCount==5); // 6 channel / 5.1
  1649. int baseOffset = lpos * 6;
  1650. for (i=0, j= 0 ; i<linearCount ; i++, j+=2)
  1651. {
  1652. pOutput[baseOffset+0] = (snd_p[j]*volumeFactor)>>8; // FL
  1653. pOutput[baseOffset+1] = (snd_p[j + 1]*volumeFactor)>>8; // FR
  1654. pOutput[baseOffset+2] = (snd_cp[j]*volumeFactor)>>8; // Center
  1655. // NOTE: Let the hardware mix the sub from the main channels since
  1656. // we don't have any sub-specific sounds, or direct sub-addressing
  1657. pOutput[baseOffset+3] = 0;
  1658. pOutput[baseOffset+4] = (snd_rp[j]*volumeFactor)>>8; // RL
  1659. pOutput[baseOffset+5] = (snd_rp[j + 1]*volumeFactor)>>8; // RR
  1660. baseOffset += 6;
  1661. }
  1662. }
  1663. snd_p += linearCount << 1;
  1664. snd_rp += linearCount << 1;
  1665. snd_cp += linearCount << 1;
  1666. lpaintedtime += linearCount;
  1667. }
  1668. pDSBuf->Unlock(pdwWrite, dwSize, NULL, 0);
  1669. }
  1670. void CAudioDirectSound::S_TransferSurround16Interleaved( const portable_samplepair_t *pfront, const portable_samplepair_t *prear, const portable_samplepair_t *pcenter, int64 lpaintedtime, int64 endtime )
  1671. {
  1672. if ( !pDSBuf )
  1673. return;
  1674. if ( !snd_lockpartial.GetBool() )
  1675. {
  1676. S_TransferSurround16Interleaved_FullLock( pfront, prear, pcenter, lpaintedtime, endtime );
  1677. return;
  1678. }
  1679. // take stereo front and rear paintbuffers, and center paintbuffer if provided,
  1680. // and copy samples into the 4 or 5 mono directsound buffers
  1681. surround_transfer_t transfer;
  1682. transfer.snd_rp = (int *)prear;
  1683. transfer.snd_cp = (int *)pcenter;
  1684. transfer.snd_p = (int *)pfront;
  1685. int sampleMonoCount = DeviceSampleCount()/ChannelCount(); // number of full samples per output buffer
  1686. Assert(IsPowerOfTwo(sampleMonoCount));
  1687. transfer.sampleMask = sampleMonoCount - 1;
  1688. transfer.paintedtime = lpaintedtime;
  1689. transfer.linearCount = endtime - lpaintedtime;
  1690. // paintedtime - number of full samples that have played since start
  1691. // endtime - number of full samples to play to - endtime is g_soundtime + mixahead samples
  1692. int channelCount = m_bSurroundCenter ? 6 : 4;
  1693. if ( ChannelCount() == 2 )
  1694. {
  1695. channelCount = 2;
  1696. }
  1697. transfer.channelCount = channelCount;
  1698. void *pBuffer0=NULL;
  1699. void *pBuffer1=NULL;
  1700. DWORD size0, size1;
  1701. int lpos = transfer.paintedtime & transfer.sampleMask; // lpos is next output position in output buffer
  1702. int offset = lpos*2*channelCount;
  1703. int lockSize = transfer.linearCount*2*channelCount;
  1704. int reps = 0;
  1705. HRESULT hr;
  1706. while ( (hr = pDSBuf->Lock( offset, lockSize, &pBuffer0, &size0, &pBuffer1, &size1, 0 )) != DS_OK )
  1707. {
  1708. if ( hr == DSERR_BUFFERLOST )
  1709. {
  1710. if ( ++reps < 10000 )
  1711. continue;
  1712. }
  1713. Msg ("DS::Lock Sound Buffer Failed\n");
  1714. return;
  1715. }
  1716. if ( pBuffer0 )
  1717. {
  1718. transfer.pOutput = (short *)pBuffer0;
  1719. TransferSamplesToSurroundBuffer( size0 / (channelCount*2), transfer );
  1720. }
  1721. if ( pBuffer1 )
  1722. {
  1723. transfer.pOutput = (short *)pBuffer1;
  1724. TransferSamplesToSurroundBuffer( size1 / (channelCount*2), transfer );
  1725. }
  1726. pDSBuf->Unlock(pBuffer0, size0, pBuffer1, size1);
  1727. }
  1728. #endif