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.

599 lines
17 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include "audio_pch.h"
  7. #include <AudioToolbox/AudioQueue.h>
  8. #include <AudioToolbox/AudioFile.h>
  9. #include <AudioToolbox/AudioFormat.h>
  10. // memdbgon must be the last include file in a .cpp file!!!
  11. #include "tier0/memdbgon.h"
  12. extern bool snd_firsttime;
  13. extern bool MIX_ScaleChannelVolume( paintbuffer_t *ppaint, channel_t *pChannel, int volume[CCHANVOLUMES], int mixchans );
  14. extern void S_SpatializeChannel( int volume[6], int master_vol, const Vector *psourceDir, float gain, float mono );
  15. #define NUM_BUFFERS_SOURCES 128
  16. #define BUFF_MASK (NUM_BUFFERS_SOURCES - 1 )
  17. #define BUFFER_SIZE 0x0400
  18. //-----------------------------------------------------------------------------
  19. //
  20. // NOTE: This only allows 16-bit, stereo wave out
  21. //
  22. //-----------------------------------------------------------------------------
  23. class CAudioDeviceAudioQueue : public CAudioDeviceBase
  24. {
  25. public:
  26. bool IsActive( void );
  27. bool Init( void );
  28. void Shutdown( void );
  29. void PaintEnd( void );
  30. int GetOutputPosition( void );
  31. void ChannelReset( int entnum, int channelIndex, float distanceMod );
  32. void Pause( void );
  33. void UnPause( void );
  34. float MixDryVolume( void );
  35. bool Should3DMix( void );
  36. void StopAllSounds( void );
  37. int PaintBegin( float mixAheadTime, int soundtime, int paintedtime );
  38. void ClearBuffer( void );
  39. void UpdateListener( const Vector& position, const Vector& forward, const Vector& right, const Vector& up );
  40. void MixBegin( int sampleCount );
  41. void MixUpsample( int sampleCount, int filtertype );
  42. void Mix8Mono( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
  43. void Mix8Stereo( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
  44. void Mix16Mono( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
  45. void Mix16Stereo( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
  46. void TransferSamples( int end );
  47. void SpatializeChannel( int volume[CCHANVOLUMES/2], int master_vol, const Vector& sourceDir, float gain, float mono);
  48. void ApplyDSPEffects( int idsp, portable_samplepair_t *pbuffront, portable_samplepair_t *pbufrear, portable_samplepair_t *pbufcenter, int samplecount );
  49. const char *DeviceName( void ) { return "AudioQueue"; }
  50. int DeviceChannels( void ) { return 2; }
  51. int DeviceSampleBits( void ) { return 16; }
  52. int DeviceSampleBytes( void ) { return 2; }
  53. int DeviceDmaSpeed( void ) { return SOUND_DMA_SPEED; }
  54. int DeviceSampleCount( void ) { return m_deviceSampleCount; }
  55. void BufferCompleted() { m_buffersCompleted++; }
  56. void SetRunning( bool bState ) { m_bRunning = bState; }
  57. private:
  58. void OpenWaveOut( void );
  59. void CloseWaveOut( void );
  60. bool ValidWaveOut( void ) const;
  61. bool BIsPlaying();
  62. AudioStreamBasicDescription m_DataFormat;
  63. AudioQueueRef m_Queue;
  64. AudioQueueBufferRef m_Buffers[NUM_BUFFERS_SOURCES];
  65. int m_SndBufSize;
  66. void *m_sndBuffers;
  67. CInterlockedInt m_deviceSampleCount;
  68. int m_buffersSent;
  69. int m_buffersCompleted;
  70. int m_pauseCount;
  71. bool m_bSoundsShutdown;
  72. bool m_bFailed;
  73. bool m_bRunning;
  74. };
  75. CAudioDeviceAudioQueue *wave = NULL;
  76. static void AudioCallback(void *pContext, AudioQueueRef pQueue, AudioQueueBufferRef pBuffer)
  77. {
  78. if ( wave )
  79. wave->BufferCompleted();
  80. }
  81. IAudioDevice *Audio_CreateMacAudioQueueDevice( void )
  82. {
  83. wave = new CAudioDeviceAudioQueue;
  84. if ( wave->Init() )
  85. return wave;
  86. delete wave;
  87. wave = NULL;
  88. return NULL;
  89. }
  90. void OnSndSurroundCvarChanged2( IConVar *pVar, const char *pOldString, float flOldValue );
  91. void OnSndSurroundLegacyChanged2( IConVar *pVar, const char *pOldString, float flOldValue );
  92. //-----------------------------------------------------------------------------
  93. // Init, shutdown
  94. //-----------------------------------------------------------------------------
  95. bool CAudioDeviceAudioQueue::Init( void )
  96. {
  97. m_SndBufSize = 0;
  98. m_sndBuffers = NULL;
  99. m_pauseCount = 0;
  100. m_bSurround = false;
  101. m_bSurroundCenter = false;
  102. m_bHeadphone = false;
  103. m_buffersSent = 0;
  104. m_buffersCompleted = 0;
  105. m_pauseCount = 0;
  106. m_bSoundsShutdown = false;
  107. m_bFailed = false;
  108. m_bRunning = false;
  109. m_Queue = NULL;
  110. static bool first = true;
  111. if ( first )
  112. {
  113. snd_surround.SetValue( 2 );
  114. snd_surround.InstallChangeCallback( &OnSndSurroundCvarChanged2 );
  115. snd_legacy_surround.InstallChangeCallback( &OnSndSurroundLegacyChanged2 );
  116. first = false;
  117. }
  118. OpenWaveOut();
  119. if ( snd_firsttime )
  120. {
  121. DevMsg( "Wave sound initialized\n" );
  122. }
  123. return ValidWaveOut() && !m_bFailed;
  124. }
  125. void CAudioDeviceAudioQueue::Shutdown( void )
  126. {
  127. CloseWaveOut();
  128. }
  129. //-----------------------------------------------------------------------------
  130. // WAV out device
  131. //-----------------------------------------------------------------------------
  132. inline bool CAudioDeviceAudioQueue::ValidWaveOut( void ) const
  133. {
  134. return m_sndBuffers != 0 && m_Queue;
  135. }
  136. //-----------------------------------------------------------------------------
  137. // called by the mac audioqueue code when we run out of playback buffers
  138. //-----------------------------------------------------------------------------
  139. void AudioQueueIsRunningCallback( void* inClientData, AudioQueueRef inAQ, AudioQueuePropertyID inID)
  140. {
  141. CAudioDeviceAudioQueue* audioqueue = (CAudioDeviceAudioQueue*)inClientData;
  142. UInt32 running = 0;
  143. UInt32 size;
  144. OSStatus err = AudioQueueGetProperty(inAQ, kAudioQueueProperty_IsRunning, &running, &size);
  145. audioqueue->SetRunning( running != 0 );
  146. //DevWarning( "AudioQueueStart %d\n", running );
  147. }
  148. //-----------------------------------------------------------------------------
  149. // Opens the windows wave out device
  150. //-----------------------------------------------------------------------------
  151. void CAudioDeviceAudioQueue::OpenWaveOut( void )
  152. {
  153. if ( m_Queue )
  154. return;
  155. m_buffersSent = 0;
  156. m_buffersCompleted = 0;
  157. m_DataFormat.mSampleRate = 44100;
  158. m_DataFormat.mFormatID = kAudioFormatLinearPCM;
  159. m_DataFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger|kAudioFormatFlagIsPacked;
  160. m_DataFormat.mBytesPerPacket = 4; // 16-bit samples * 2 channels
  161. m_DataFormat.mFramesPerPacket = 1;
  162. m_DataFormat.mBytesPerFrame = 4; // 16-bit samples * 2 channels
  163. m_DataFormat.mChannelsPerFrame = 2;
  164. m_DataFormat.mBitsPerChannel = 16;
  165. m_DataFormat.mReserved = 0;
  166. // Create the audio queue that will be used to manage the array of audio
  167. // buffers used to queue samples.
  168. OSStatus err = AudioQueueNewOutput(&m_DataFormat, AudioCallback, this, NULL, NULL, 0, &m_Queue);
  169. if ( err != noErr)
  170. {
  171. DevMsg( "Failed to create AudioQueue output %d\n", (int)err );
  172. m_bFailed = true;
  173. return;
  174. }
  175. for ( int i = 0; i < NUM_BUFFERS_SOURCES; ++i)
  176. {
  177. err = AudioQueueAllocateBuffer( m_Queue, BUFFER_SIZE,&(m_Buffers[i]));
  178. if ( err != noErr)
  179. {
  180. DevMsg( "Failed to AudioQueueAllocateBuffer output %d (%i)\n",(int)err,i );
  181. m_bFailed = true;
  182. }
  183. m_Buffers[i]->mAudioDataByteSize = BUFFER_SIZE;
  184. Q_memset( m_Buffers[i]->mAudioData, 0, BUFFER_SIZE );
  185. }
  186. err = AudioQueuePrime( m_Queue, 0, NULL);
  187. if ( err != noErr)
  188. {
  189. DevMsg( "Failed to create AudioQueue output %d\n", (int)err );
  190. m_bFailed = true;
  191. return;
  192. }
  193. AudioQueueSetParameter( m_Queue, kAudioQueueParam_Volume, 1.0);
  194. err = AudioQueueAddPropertyListener( m_Queue, kAudioQueueProperty_IsRunning, AudioQueueIsRunningCallback, this );
  195. if ( err != noErr)
  196. {
  197. DevMsg( "Failed to create AudioQueue output %d\n", (int)err );
  198. m_bFailed = true;
  199. return;
  200. }
  201. m_SndBufSize = NUM_BUFFERS_SOURCES*BUFFER_SIZE;
  202. m_deviceSampleCount = m_SndBufSize / DeviceSampleBytes();
  203. if ( !m_sndBuffers )
  204. {
  205. m_sndBuffers = malloc( m_SndBufSize );
  206. memset( m_sndBuffers, 0x0, m_SndBufSize );
  207. }
  208. }
  209. //-----------------------------------------------------------------------------
  210. // Closes the windows wave out device
  211. //-----------------------------------------------------------------------------
  212. void CAudioDeviceAudioQueue::CloseWaveOut( void )
  213. {
  214. if ( ValidWaveOut() )
  215. {
  216. AudioQueueStop(m_Queue, true);
  217. m_bRunning = false;
  218. AudioQueueRemovePropertyListener( m_Queue, kAudioQueueProperty_IsRunning, AudioQueueIsRunningCallback, this );
  219. for ( int i = 0; i < NUM_BUFFERS_SOURCES; i++ )
  220. AudioQueueFreeBuffer( m_Queue, m_Buffers[i]);
  221. AudioQueueDispose( m_Queue, true);
  222. m_Queue = NULL;
  223. }
  224. if ( m_sndBuffers )
  225. {
  226. free( m_sndBuffers );
  227. m_sndBuffers = NULL;
  228. }
  229. }
  230. //-----------------------------------------------------------------------------
  231. // Mixing setup
  232. //-----------------------------------------------------------------------------
  233. int CAudioDeviceAudioQueue::PaintBegin( float mixAheadTime, int soundtime, int paintedtime )
  234. {
  235. // soundtime - total samples that have been played out to hardware at dmaspeed
  236. // paintedtime - total samples that have been mixed at speed
  237. // endtime - target for samples in mixahead buffer at speed
  238. unsigned int endtime = soundtime + mixAheadTime * DeviceDmaSpeed();
  239. int samps = DeviceSampleCount() >> (DeviceChannels()-1);
  240. if ((int)(endtime - soundtime) > samps)
  241. endtime = soundtime + samps;
  242. if ((endtime - paintedtime) & 0x3)
  243. {
  244. // The difference between endtime and painted time should align on
  245. // boundaries of 4 samples. This is important when upsampling from 11khz -> 44khz.
  246. endtime -= (endtime - paintedtime) & 0x3;
  247. }
  248. return endtime;
  249. }
  250. //-----------------------------------------------------------------------------
  251. // Actually performs the mixing
  252. //-----------------------------------------------------------------------------
  253. void CAudioDeviceAudioQueue::PaintEnd( void )
  254. {
  255. int cblocks = 4 << 1;
  256. if ( m_bRunning && m_buffersSent == m_buffersCompleted )
  257. {
  258. // We are running the audio queue but have become starved of buffers.
  259. // Stop the audio queue so we force a restart of it.
  260. AudioQueueStop( m_Queue, true );
  261. }
  262. //
  263. // submit a few new sound blocks
  264. //
  265. // 44K sound support
  266. while (((m_buffersSent - m_buffersCompleted) >> SAMPLE_16BIT_SHIFT) < cblocks)
  267. {
  268. int iBuf = m_buffersSent&BUFF_MASK;
  269. m_Buffers[iBuf]->mAudioDataByteSize = BUFFER_SIZE;
  270. Q_memcpy( m_Buffers[iBuf]->mAudioData, (char *)m_sndBuffers + iBuf*BUFFER_SIZE, BUFFER_SIZE);
  271. // Queue the buffer for playback.
  272. OSStatus err = AudioQueueEnqueueBuffer( m_Queue, m_Buffers[iBuf], 0, NULL);
  273. if ( err != noErr)
  274. {
  275. DevMsg( "Failed to AudioQueueEnqueueBuffer output %d\n", (int)err );
  276. }
  277. m_buffersSent++;
  278. }
  279. if ( !m_bRunning )
  280. {
  281. DevMsg( "Restarting sound playback\n" );
  282. m_bRunning = true;
  283. AudioQueueStart( m_Queue, NULL);
  284. }
  285. }
  286. int CAudioDeviceAudioQueue::GetOutputPosition( void )
  287. {
  288. int s = m_buffersSent * BUFFER_SIZE;
  289. s >>= SAMPLE_16BIT_SHIFT;
  290. s &= (DeviceSampleCount()-1);
  291. return s / DeviceChannels();
  292. }
  293. //-----------------------------------------------------------------------------
  294. // Pausing
  295. //-----------------------------------------------------------------------------
  296. void CAudioDeviceAudioQueue::Pause( void )
  297. {
  298. m_pauseCount++;
  299. if (m_pauseCount == 1)
  300. {
  301. m_bRunning = false;
  302. AudioQueueStop(m_Queue, true);
  303. }
  304. }
  305. void CAudioDeviceAudioQueue::UnPause( void )
  306. {
  307. if ( m_pauseCount > 0 )
  308. {
  309. m_pauseCount--;
  310. }
  311. if ( m_pauseCount == 0 )
  312. {
  313. m_bRunning = true;
  314. AudioQueueStart( m_Queue, NULL);
  315. }
  316. }
  317. bool CAudioDeviceAudioQueue::IsActive( void )
  318. {
  319. return ( m_pauseCount == 0 );
  320. }
  321. float CAudioDeviceAudioQueue::MixDryVolume( void )
  322. {
  323. return 0;
  324. }
  325. bool CAudioDeviceAudioQueue::Should3DMix( void )
  326. {
  327. return false;
  328. }
  329. void CAudioDeviceAudioQueue::ClearBuffer( void )
  330. {
  331. if ( !m_sndBuffers )
  332. return;
  333. Q_memset( m_sndBuffers, 0x0, DeviceSampleCount() * DeviceSampleBytes() );
  334. }
  335. void CAudioDeviceAudioQueue::UpdateListener( const Vector& position, const Vector& forward, const Vector& right, const Vector& up )
  336. {
  337. }
  338. bool CAudioDeviceAudioQueue::BIsPlaying()
  339. {
  340. UInt32 isRunning;
  341. UInt32 propSize = sizeof(isRunning);
  342. OSStatus result = AudioQueueGetProperty( m_Queue, kAudioQueueProperty_IsRunning, &isRunning, &propSize);
  343. return isRunning != 0;
  344. }
  345. void CAudioDeviceAudioQueue::MixBegin( int sampleCount )
  346. {
  347. MIX_ClearAllPaintBuffers( sampleCount, false );
  348. }
  349. void CAudioDeviceAudioQueue::MixUpsample( int sampleCount, int filtertype )
  350. {
  351. paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();
  352. int ifilter = ppaint->ifilter;
  353. Assert (ifilter < CPAINTFILTERS);
  354. S_MixBufferUpsample2x( sampleCount, ppaint->pbuf, &(ppaint->fltmem[ifilter][0]), CPAINTFILTERMEM, filtertype );
  355. ppaint->ifilter++;
  356. }
  357. void CAudioDeviceAudioQueue::Mix8Mono( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
  358. {
  359. int volume[CCHANVOLUMES];
  360. paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();
  361. if (!MIX_ScaleChannelVolume( ppaint, pChannel, volume, 1))
  362. return;
  363. Mix8MonoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, (byte *)pData, inputOffset, rateScaleFix, outCount );
  364. }
  365. void CAudioDeviceAudioQueue::Mix8Stereo( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
  366. {
  367. int volume[CCHANVOLUMES];
  368. paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();
  369. if (!MIX_ScaleChannelVolume( ppaint, pChannel, volume, 2 ))
  370. return;
  371. Mix8StereoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, (byte *)pData, inputOffset, rateScaleFix, outCount );
  372. }
  373. void CAudioDeviceAudioQueue::Mix16Mono( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
  374. {
  375. int volume[CCHANVOLUMES];
  376. paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();
  377. if (!MIX_ScaleChannelVolume( ppaint, pChannel, volume, 1 ))
  378. return;
  379. Mix16MonoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, pData, inputOffset, rateScaleFix, outCount );
  380. }
  381. void CAudioDeviceAudioQueue::Mix16Stereo( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
  382. {
  383. int volume[CCHANVOLUMES];
  384. paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();
  385. if (!MIX_ScaleChannelVolume( ppaint, pChannel, volume, 2 ))
  386. return;
  387. Mix16StereoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, pData, inputOffset, rateScaleFix, outCount );
  388. }
  389. void CAudioDeviceAudioQueue::ChannelReset( int entnum, int channelIndex, float distanceMod )
  390. {
  391. }
  392. void CAudioDeviceAudioQueue::TransferSamples( int end )
  393. {
  394. int lpaintedtime = g_paintedtime;
  395. int endtime = end;
  396. // resumes playback...
  397. if ( m_sndBuffers )
  398. {
  399. S_TransferStereo16( m_sndBuffers, PAINTBUFFER, lpaintedtime, endtime );
  400. }
  401. }
  402. void CAudioDeviceAudioQueue::SpatializeChannel( int volume[CCHANVOLUMES/2], int master_vol, const Vector& sourceDir, float gain, float mono )
  403. {
  404. VPROF("CAudioDeviceAudioQueue::SpatializeChannel");
  405. S_SpatializeChannel( volume, master_vol, &sourceDir, gain, mono );
  406. }
  407. void CAudioDeviceAudioQueue::StopAllSounds( void )
  408. {
  409. m_bSoundsShutdown = true;
  410. m_bRunning = false;
  411. AudioQueueStop(m_Queue, true);
  412. }
  413. void CAudioDeviceAudioQueue::ApplyDSPEffects( int idsp, portable_samplepair_t *pbuffront, portable_samplepair_t *pbufrear, portable_samplepair_t *pbufcenter, int samplecount )
  414. {
  415. //SX_RoomFX( endtime, filter, timefx );
  416. DSP_Process( idsp, pbuffront, pbufrear, pbufcenter, samplecount );
  417. }
  418. static uint32 GetOSXSpeakerConfig()
  419. {
  420. return 2;
  421. }
  422. static uint32 GetSpeakerConfigForSurroundMode( int surroundMode, const char **pConfigDesc )
  423. {
  424. uint32 newSpeakerConfig = 2;
  425. *pConfigDesc = "stereo speaker";
  426. return newSpeakerConfig;
  427. }
  428. void OnSndSurroundCvarChanged2( IConVar *pVar, const char *pOldString, float flOldValue )
  429. {
  430. // if the old value is -1, we're setting this from the detect routine for the first time
  431. // no need to reset the device
  432. if ( flOldValue == -1 )
  433. return;
  434. // get the user's previous speaker config
  435. uint32 speaker_config = GetOSXSpeakerConfig();
  436. // get the new config
  437. uint32 newSpeakerConfig = 0;
  438. const char *speakerConfigDesc = "";
  439. ConVarRef var( pVar );
  440. newSpeakerConfig = GetSpeakerConfigForSurroundMode( var.GetInt(), &speakerConfigDesc );
  441. // make sure the config has changed
  442. if (newSpeakerConfig == speaker_config)
  443. return;
  444. // set new configuration
  445. //SetWindowsSpeakerConfig(newSpeakerConfig);
  446. Msg("Speaker configuration has been changed to %s.\n", speakerConfigDesc);
  447. // restart sound system so it takes effect
  448. //g_pSoundServices->RestartSoundSystem();
  449. }
  450. void OnSndSurroundLegacyChanged2( IConVar *pVar, const char *pOldString, float flOldValue )
  451. {
  452. }