Team Fortress 2 Source Code as on 22/4/2020
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.

2094 lines
56 KiB

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