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.

570 lines
16 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include "audio_pch.h"
  7. // memdbgon must be the last include file in a .cpp file!!!
  8. #include "tier0/memdbgon.h"
  9. extern bool snd_firsttime;
  10. extern bool MIX_ScaleChannelVolume( paintbuffer_t *ppaint, channel_t *pChannel, int volume[CCHANVOLUMES], int mixchans );
  11. extern void S_SpatializeChannel( int volume[6], int master_vol, const Vector *psourceDir, float gain, float mono );
  12. // 64K is > 1 second at 16-bit, 22050 Hz
  13. // 44k: UNDONE - need to double buffers now that we're playing back at 44100?
  14. #define WAV_BUFFERS 64
  15. #define WAV_MASK 0x3F
  16. #define WAV_BUFFER_SIZE 0x0400
  17. //-----------------------------------------------------------------------------
  18. //
  19. // NOTE: This only allows 16-bit, stereo wave out
  20. //
  21. //-----------------------------------------------------------------------------
  22. class CAudioDeviceWave : public CAudioDeviceBase
  23. {
  24. public:
  25. bool IsActive( void );
  26. bool Init( void );
  27. void Shutdown( void );
  28. void PaintEnd( void );
  29. int GetOutputPosition( void );
  30. void ChannelReset( int entnum, int channelIndex, float distanceMod );
  31. void Pause( void );
  32. void UnPause( void );
  33. float MixDryVolume( void );
  34. bool Should3DMix( void );
  35. void StopAllSounds( void );
  36. int PaintBegin( float mixAheadTime, int soundtime, int paintedtime );
  37. void ClearBuffer( void );
  38. void UpdateListener( const Vector& position, const Vector& forward, const Vector& right, const Vector& up );
  39. void MixBegin( int sampleCount );
  40. void MixUpsample( int sampleCount, int filtertype );
  41. void Mix8Mono( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
  42. void Mix8Stereo( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
  43. void Mix16Mono( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
  44. void Mix16Stereo( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
  45. void TransferSamples( int end );
  46. void SpatializeChannel( int volume[CCHANVOLUMES/2], int master_vol, const Vector& sourceDir, float gain, float mono);
  47. void ApplyDSPEffects( int idsp, portable_samplepair_t *pbuffront, portable_samplepair_t *pbufrear, portable_samplepair_t *pbufcenter, int samplecount );
  48. const char *DeviceName( void ) { return "Windows WAVE"; }
  49. int DeviceChannels( void ) { return 2; }
  50. int DeviceSampleBits( void ) { return 16; }
  51. int DeviceSampleBytes( void ) { return 2; }
  52. int DeviceDmaSpeed( void ) { return SOUND_DMA_SPEED; }
  53. int DeviceSampleCount( void ) { return m_deviceSampleCount; }
  54. private:
  55. void OpenWaveOut( void );
  56. void CloseWaveOut( void );
  57. void AllocateOutputBuffers();
  58. void FreeOutputBuffers();
  59. void* AllocOutputMemory( int nSize, HGLOBAL &hMemory );
  60. void FreeOutputMemory( HGLOBAL &hMemory );
  61. bool ValidWaveOut( void ) const;
  62. int m_deviceSampleCount;
  63. int m_buffersSent;
  64. int m_buffersCompleted;
  65. int m_pauseCount;
  66. // This is a single allocation for all wave headers (there are OUTPUT_BUFFER_COUNT of them)
  67. HGLOBAL m_hWaveHdr;
  68. // This is a single allocation for all wave data (there are OUTPUT_BUFFER_COUNT of them)
  69. HANDLE m_hWaveData;
  70. HWAVEOUT m_waveOutHandle;
  71. // Memory for the wave data + wave headers
  72. void *m_pBuffer;
  73. LPWAVEHDR m_pWaveHdr;
  74. };
  75. //-----------------------------------------------------------------------------
  76. // Class factory
  77. //-----------------------------------------------------------------------------
  78. IAudioDevice *Audio_CreateWaveDevice( void )
  79. {
  80. CAudioDeviceWave *wave = NULL;
  81. if ( !wave )
  82. {
  83. wave = new CAudioDeviceWave;
  84. }
  85. if ( wave->Init() )
  86. return wave;
  87. delete wave;
  88. wave = NULL;
  89. return NULL;
  90. }
  91. //-----------------------------------------------------------------------------
  92. // Init, shutdown
  93. //-----------------------------------------------------------------------------
  94. bool CAudioDeviceWave::Init( void )
  95. {
  96. m_bSurround = false;
  97. m_bSurroundCenter = false;
  98. m_bHeadphone = false;
  99. m_buffersSent = 0;
  100. m_buffersCompleted = 0;
  101. m_pauseCount = 0;
  102. m_waveOutHandle = 0;
  103. m_pBuffer = NULL;
  104. m_pWaveHdr = NULL;
  105. m_hWaveHdr = NULL;
  106. m_hWaveData = NULL;
  107. OpenWaveOut();
  108. if ( snd_firsttime )
  109. {
  110. DevMsg( "Wave sound initialized\n" );
  111. }
  112. return ValidWaveOut();
  113. }
  114. void CAudioDeviceWave::Shutdown( void )
  115. {
  116. CloseWaveOut();
  117. }
  118. //-----------------------------------------------------------------------------
  119. // WAV out device
  120. //-----------------------------------------------------------------------------
  121. inline bool CAudioDeviceWave::ValidWaveOut( void ) const
  122. {
  123. return m_waveOutHandle != 0;
  124. }
  125. //-----------------------------------------------------------------------------
  126. // Opens the windows wave out device
  127. //-----------------------------------------------------------------------------
  128. void CAudioDeviceWave::OpenWaveOut( void )
  129. {
  130. WAVEFORMATEX waveFormat;
  131. memset( &waveFormat, 0, sizeof(waveFormat) );
  132. // Select a PCM, 16-bit stereo playback device
  133. waveFormat.cbSize = sizeof(waveFormat);
  134. waveFormat.wFormatTag = WAVE_FORMAT_PCM;
  135. waveFormat.nChannels = DeviceChannels();
  136. waveFormat.wBitsPerSample = DeviceSampleBits();
  137. waveFormat.nSamplesPerSec = DeviceDmaSpeed(); // DeviceSampleRate
  138. waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
  139. waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
  140. MMRESULT errorCode = waveOutOpen( &m_waveOutHandle, WAVE_MAPPER, &waveFormat, 0, 0L, CALLBACK_NULL );
  141. while ( errorCode != MMSYSERR_NOERROR )
  142. {
  143. if ( errorCode != MMSYSERR_ALLOCATED )
  144. {
  145. DevWarning( "waveOutOpen failed\n" );
  146. m_waveOutHandle = 0;
  147. return;
  148. }
  149. int nRetVal = MessageBox( NULL,
  150. "The sound hardware is in use by another app.\n\n"
  151. "Select Retry to try to start sound again or Cancel to run with no sound.",
  152. "Sound not available",
  153. MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION);
  154. if ( nRetVal != IDRETRY )
  155. {
  156. DevWarning( "waveOutOpen failure--hardware already in use\n" );
  157. m_waveOutHandle = 0;
  158. return;
  159. }
  160. errorCode = waveOutOpen( &m_waveOutHandle, WAVE_MAPPER, &waveFormat, 0, 0L, CALLBACK_NULL );
  161. }
  162. AllocateOutputBuffers();
  163. }
  164. //-----------------------------------------------------------------------------
  165. // Closes the windows wave out device
  166. //-----------------------------------------------------------------------------
  167. void CAudioDeviceWave::CloseWaveOut( void )
  168. {
  169. if ( ValidWaveOut() )
  170. {
  171. waveOutReset( m_waveOutHandle );
  172. FreeOutputBuffers();
  173. waveOutClose( m_waveOutHandle );
  174. m_waveOutHandle = NULL;
  175. }
  176. }
  177. //-----------------------------------------------------------------------------
  178. // Alloc output memory
  179. //-----------------------------------------------------------------------------
  180. void* CAudioDeviceWave::AllocOutputMemory( int nSize, HGLOBAL &hMemory )
  181. {
  182. // Output memory for waveform data+hdrs must be
  183. // globally allocated with GMEM_MOVEABLE and GMEM_SHARE flags.
  184. hMemory = GlobalAlloc( GMEM_MOVEABLE | GMEM_SHARE, nSize );
  185. if ( !hMemory )
  186. {
  187. DevWarning( "Sound: Out of memory.\n");
  188. CloseWaveOut();
  189. return NULL;
  190. }
  191. HPSTR lpData = (char *)GlobalLock( hMemory );
  192. if ( !lpData )
  193. {
  194. DevWarning( "Sound: Failed to lock.\n");
  195. GlobalFree( hMemory );
  196. hMemory = NULL;
  197. CloseWaveOut();
  198. return NULL;
  199. }
  200. memset( lpData, 0, nSize );
  201. return lpData;
  202. }
  203. //-----------------------------------------------------------------------------
  204. // Free output memory
  205. //-----------------------------------------------------------------------------
  206. void CAudioDeviceWave::FreeOutputMemory( HGLOBAL &hMemory )
  207. {
  208. if ( hMemory )
  209. {
  210. GlobalUnlock( hMemory );
  211. GlobalFree( hMemory );
  212. hMemory = NULL;
  213. }
  214. }
  215. //-----------------------------------------------------------------------------
  216. // Allocate output buffers
  217. //-----------------------------------------------------------------------------
  218. void CAudioDeviceWave::AllocateOutputBuffers()
  219. {
  220. // Allocate and lock memory for the waveform data.
  221. int nBufferSize = WAV_BUFFER_SIZE * WAV_BUFFERS;
  222. HPSTR lpData = (char *)AllocOutputMemory( nBufferSize, m_hWaveData );
  223. if ( !lpData )
  224. return;
  225. // Allocate and lock memory for the waveform header
  226. int nHdrSize = sizeof( WAVEHDR ) * WAV_BUFFERS;
  227. LPWAVEHDR lpWaveHdr = (LPWAVEHDR)AllocOutputMemory( nHdrSize, m_hWaveHdr );
  228. if ( !lpWaveHdr )
  229. return;
  230. // After allocation, set up and prepare headers.
  231. for ( int i=0 ; i < WAV_BUFFERS; i++ )
  232. {
  233. LPWAVEHDR lpHdr = lpWaveHdr + i;
  234. lpHdr->dwBufferLength = WAV_BUFFER_SIZE;
  235. lpHdr->lpData = lpData + (i * WAV_BUFFER_SIZE);
  236. MMRESULT nResult = waveOutPrepareHeader( m_waveOutHandle, lpHdr, sizeof(WAVEHDR) );
  237. if ( nResult != MMSYSERR_NOERROR )
  238. {
  239. DevWarning( "Sound: failed to prepare wave headers\n" );
  240. CloseWaveOut();
  241. return;
  242. }
  243. }
  244. m_deviceSampleCount = nBufferSize / DeviceSampleBytes();
  245. m_pBuffer = (void *)lpData;
  246. m_pWaveHdr = lpWaveHdr;
  247. }
  248. //-----------------------------------------------------------------------------
  249. // Free output buffers
  250. //-----------------------------------------------------------------------------
  251. void CAudioDeviceWave::FreeOutputBuffers()
  252. {
  253. // Unprepare headers.
  254. if ( m_pWaveHdr )
  255. {
  256. for ( int i=0 ; i < WAV_BUFFERS; i++ )
  257. {
  258. waveOutUnprepareHeader( m_waveOutHandle, m_pWaveHdr+i, sizeof(WAVEHDR) );
  259. }
  260. }
  261. m_pWaveHdr = NULL;
  262. m_pBuffer = NULL;
  263. FreeOutputMemory( m_hWaveData );
  264. FreeOutputMemory( m_hWaveHdr );
  265. }
  266. //-----------------------------------------------------------------------------
  267. // Mixing setup
  268. //-----------------------------------------------------------------------------
  269. int CAudioDeviceWave::PaintBegin( float mixAheadTime, int soundtime, int paintedtime )
  270. {
  271. // soundtime - total samples that have been played out to hardware at dmaspeed
  272. // paintedtime - total samples that have been mixed at speed
  273. // endtime - target for samples in mixahead buffer at speed
  274. unsigned int endtime = soundtime + mixAheadTime * DeviceDmaSpeed();
  275. int samps = DeviceSampleCount() >> (DeviceChannels()-1);
  276. if ((int)(endtime - soundtime) > samps)
  277. endtime = soundtime + samps;
  278. if ((endtime - paintedtime) & 0x3)
  279. {
  280. // The difference between endtime and painted time should align on
  281. // boundaries of 4 samples. This is important when upsampling from 11khz -> 44khz.
  282. endtime -= (endtime - paintedtime) & 0x3;
  283. }
  284. return endtime;
  285. }
  286. //-----------------------------------------------------------------------------
  287. // Actually performs the mixing
  288. //-----------------------------------------------------------------------------
  289. void CAudioDeviceWave::PaintEnd( void )
  290. {
  291. LPWAVEHDR h;
  292. int wResult;
  293. int cblocks;
  294. //
  295. // find which sound blocks have completed
  296. //
  297. while (1)
  298. {
  299. if ( m_buffersCompleted == m_buffersSent )
  300. {
  301. //DevMsg ("Sound overrun\n");
  302. break;
  303. }
  304. if ( ! (m_pWaveHdr[ m_buffersCompleted & WAV_MASK].dwFlags & WHDR_DONE) )
  305. {
  306. break;
  307. }
  308. m_buffersCompleted++; // this buffer has been played
  309. }
  310. //
  311. // submit a few new sound blocks
  312. //
  313. // 22K sound support
  314. // 44k: UNDONE - double blocks out now that we're at 44k playback?
  315. cblocks = 4 << 1;
  316. while (((m_buffersSent - m_buffersCompleted) >> SAMPLE_16BIT_SHIFT) < cblocks)
  317. {
  318. h = m_pWaveHdr + ( m_buffersSent&WAV_MASK );
  319. m_buffersSent++;
  320. /*
  321. * Now the data block can be sent to the output device. The
  322. * waveOutWrite function returns immediately and waveform
  323. * data is sent to the output device in the background.
  324. */
  325. wResult = waveOutWrite( m_waveOutHandle, h, sizeof(WAVEHDR) );
  326. if (wResult != MMSYSERR_NOERROR)
  327. {
  328. Warning( "Failed to write block to device\n");
  329. Shutdown();
  330. return;
  331. }
  332. }
  333. }
  334. int CAudioDeviceWave::GetOutputPosition( void )
  335. {
  336. int s = m_buffersSent * WAV_BUFFER_SIZE;
  337. s >>= SAMPLE_16BIT_SHIFT;
  338. s &= (DeviceSampleCount()-1);
  339. return s / DeviceChannels();
  340. }
  341. //-----------------------------------------------------------------------------
  342. // Pausing
  343. //-----------------------------------------------------------------------------
  344. void CAudioDeviceWave::Pause( void )
  345. {
  346. m_pauseCount++;
  347. if (m_pauseCount == 1)
  348. {
  349. waveOutReset( m_waveOutHandle );
  350. }
  351. }
  352. void CAudioDeviceWave::UnPause( void )
  353. {
  354. if ( m_pauseCount > 0 )
  355. {
  356. m_pauseCount--;
  357. }
  358. }
  359. bool CAudioDeviceWave::IsActive( void )
  360. {
  361. return ( m_pauseCount == 0 );
  362. }
  363. float CAudioDeviceWave::MixDryVolume( void )
  364. {
  365. return 0;
  366. }
  367. bool CAudioDeviceWave::Should3DMix( void )
  368. {
  369. return false;
  370. }
  371. void CAudioDeviceWave::ClearBuffer( void )
  372. {
  373. int clear;
  374. if ( !m_pBuffer )
  375. return;
  376. clear = 0;
  377. Q_memset(m_pBuffer, clear, DeviceSampleCount() * DeviceSampleBytes() );
  378. }
  379. void CAudioDeviceWave::UpdateListener( const Vector& position, const Vector& forward, const Vector& right, const Vector& up )
  380. {
  381. }
  382. void CAudioDeviceWave::MixBegin( int sampleCount )
  383. {
  384. MIX_ClearAllPaintBuffers( sampleCount, false );
  385. }
  386. void CAudioDeviceWave::MixUpsample( int sampleCount, int filtertype )
  387. {
  388. paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();
  389. int ifilter = ppaint->ifilter;
  390. Assert (ifilter < CPAINTFILTERS);
  391. S_MixBufferUpsample2x( sampleCount, ppaint->pbuf, &(ppaint->fltmem[ifilter][0]), CPAINTFILTERMEM, filtertype );
  392. ppaint->ifilter++;
  393. }
  394. void CAudioDeviceWave::Mix8Mono( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
  395. {
  396. int volume[CCHANVOLUMES];
  397. paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();
  398. if (!MIX_ScaleChannelVolume( ppaint, pChannel, volume, 1))
  399. return;
  400. Mix8MonoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, (byte *)pData, inputOffset, rateScaleFix, outCount );
  401. }
  402. void CAudioDeviceWave::Mix8Stereo( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
  403. {
  404. int volume[CCHANVOLUMES];
  405. paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();
  406. if (!MIX_ScaleChannelVolume( ppaint, pChannel, volume, 2 ))
  407. return;
  408. Mix8StereoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, (byte *)pData, inputOffset, rateScaleFix, outCount );
  409. }
  410. void CAudioDeviceWave::Mix16Mono( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
  411. {
  412. int volume[CCHANVOLUMES];
  413. paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();
  414. if (!MIX_ScaleChannelVolume( ppaint, pChannel, volume, 1 ))
  415. return;
  416. Mix16MonoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, pData, inputOffset, rateScaleFix, outCount );
  417. }
  418. void CAudioDeviceWave::Mix16Stereo( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
  419. {
  420. int volume[CCHANVOLUMES];
  421. paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();
  422. if (!MIX_ScaleChannelVolume( ppaint, pChannel, volume, 2 ))
  423. return;
  424. Mix16StereoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, pData, inputOffset, rateScaleFix, outCount );
  425. }
  426. void CAudioDeviceWave::ChannelReset( int entnum, int channelIndex, float distanceMod )
  427. {
  428. }
  429. void CAudioDeviceWave::TransferSamples( int end )
  430. {
  431. int lpaintedtime = g_paintedtime;
  432. int endtime = end;
  433. // resumes playback...
  434. if ( m_pBuffer )
  435. {
  436. S_TransferStereo16( m_pBuffer, PAINTBUFFER, lpaintedtime, endtime );
  437. }
  438. }
  439. void CAudioDeviceWave::SpatializeChannel( int volume[CCHANVOLUMES/2], int master_vol, const Vector& sourceDir, float gain, float mono )
  440. {
  441. VPROF("CAudioDeviceWave::SpatializeChannel");
  442. S_SpatializeChannel( volume, master_vol, &sourceDir, gain, mono );
  443. }
  444. void CAudioDeviceWave::StopAllSounds( void )
  445. {
  446. }
  447. void CAudioDeviceWave::ApplyDSPEffects( int idsp, portable_samplepair_t *pbuffront, portable_samplepair_t *pbufrear, portable_samplepair_t *pbufcenter, int samplecount )
  448. {
  449. //SX_RoomFX( endtime, filter, timefx );
  450. DSP_Process( idsp, pbuffront, pbufrear, pbufcenter, samplecount );
  451. }