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

432 lines
12 KiB

  1. //===== Copyright � Valve Corporation, All rights reserved. =================//
  2. //
  3. // Purpose: audio mix data structures
  4. //
  5. //===========================================================================//
  6. #ifndef AUDIO_MIX_H
  7. #define AUDIO_MIX_H
  8. #ifdef _WIN32
  9. #pragma once
  10. #endif
  11. #include "strtools.h" // V_memset
  12. #include "utlstring.h"
  13. #include "utlstringtoken.h"
  14. #include "soundsystem/lowlevel.h"
  15. struct dspglobalvars_t
  16. {
  17. float m_flMixMin; // min dsp mix at close range
  18. float m_flMixMax; // max dsp mix at long range
  19. float m_fldbMixDrop; // reduce mix_min/max by n% if sndlvl of new sound less than dbMin
  20. float m_flDistanceMin; // range at which sounds are mixed at flMixMin
  21. float m_flDistanceMax; // range at which sounds are mixed at flMixMax
  22. uint16 m_ndbMin; // if sndlvl of a new sound is < dbMin, reduce mix_min/max by m_fldbMixDrop
  23. bool m_bIsOff;
  24. };
  25. class CAudioProcessor
  26. {
  27. public:
  28. virtual ~CAudioProcessor() {}
  29. CAudioProcessor( const char *pDebugName, int nChannelCount );
  30. void SetDebugName( const char *pName );
  31. virtual void Process( CAudioMixBuffer *pInput, CAudioMixBuffer *pOutput, int nChannelCount, dspglobalvars_t *pGlobals );
  32. virtual void ProcessSingleChannel( const CAudioMixBuffer &input, CAudioMixBuffer *pOutput, int nChannelIndex ) = 0;
  33. // Parameter set can modify internal or global state (or both)
  34. virtual bool SetControlParameter( CUtlStringToken name, float flValue );
  35. virtual float GetControlParameter( CUtlStringToken name, float flDefaultValue = 0.0f ) = 0;
  36. virtual bool SetNameParameter( CUtlStringToken name, uint32 nNameValue ) = 0;
  37. virtual uint32 GetNameParameter( CUtlStringToken name, uint32 nDefaultValue ) = 0;
  38. virtual bool ShouldProcess();
  39. float GetPrevMix( float flMix );
  40. void ApplyMonoProcessor( CAudioMixBuffer *pInput, CAudioMixBuffer *pOutput, int nOutputChannelCount, float flMix );
  41. void ApplyStereoProcessor( CAudioMixBuffer *pInput, CAudioMixBuffer *pOutput, int nOutputChannelCount, float flMix );
  42. void ApplyNChannelProcessor( CAudioMixBuffer *pInput, CAudioMixBuffer *pOutput, int nChannelCount, float flMix );
  43. CUtlString m_debugName;
  44. uint32 m_nNameHashCode;
  45. float m_flXFade;
  46. float m_flXFadePrev;
  47. float m_flMix;
  48. int m_nChannels;
  49. bool m_bEnabled;
  50. };
  51. struct audio_buffer_input_t
  52. {
  53. const short *m_pSamples; // pointer to the samples themselves (in 8, 16, or 32-bit format)
  54. uint m_nSampleCount; // number of whole samples *not bytes* *not multiplied by channel count* (e.g. a one-second 16-bit 44.1KHz file would be 44100 samples)
  55. };
  56. // UNDONE: deprecate this and move to a 8-int, 16-int, 32-float, N channel with extract specific channel design
  57. enum vaudio_sampleformats_t
  58. {
  59. SAMPLE_INT16_MONO = 0, // default
  60. SAMPLE_INT8_MONO, // increase to 16-bit and convert to float
  61. SAMPLE_INT16_STEREO_L, // stereo wave, extract left channel
  62. SAMPLE_INT16_STEREO_R, // stereo wave, extract right channel
  63. SAMPLE_INT8_STEREO_L, // stereo wave, extract left channel
  64. SAMPLE_INT8_STEREO_R, // stereo wave, extract right channel
  65. SAMPLE_FLOAT32_MONO, // no reformat needed
  66. };
  67. struct audio_source_input_t
  68. {
  69. const audio_buffer_input_t *m_pPackets;
  70. uint m_nSamplingRate;
  71. uint16 m_nPacketCount;
  72. uint16 m_nSampleFormat;
  73. void InitPackets( const audio_buffer_input_t *pPacketsIn, int nPacketCountIn, int nSamplingRate, int nBitsPerSample, int nChannelsPerSample )
  74. {
  75. V_memset( this, 0, sizeof(*this) );
  76. Assert( nPacketCountIn >= 0 && nPacketCountIn <= UINT16_MAX );
  77. m_nPacketCount = (uint16)nPacketCountIn;
  78. m_pPackets = pPacketsIn;
  79. m_nSamplingRate = nSamplingRate;
  80. switch( nBitsPerSample )
  81. {
  82. case 16:
  83. m_nSampleFormat = (uint16)( (nChannelsPerSample == 1) ? SAMPLE_INT16_MONO : SAMPLE_INT16_STEREO_L );
  84. break;
  85. case 8:
  86. m_nSampleFormat = (uint16)( (nChannelsPerSample == 1) ? SAMPLE_INT8_MONO : SAMPLE_INT8_STEREO_L );
  87. break;
  88. }
  89. }
  90. };
  91. struct audio_source_indexstate_t
  92. {
  93. uint m_nPacketIndex;
  94. uint m_nBufferSampleOffset;
  95. uint m_nSampleFracOffset;
  96. inline void Clear()
  97. {
  98. m_nPacketIndex = 0;
  99. m_nBufferSampleOffset = 0;
  100. m_nSampleFracOffset = 0;
  101. }
  102. };
  103. class CAudioMixState
  104. {
  105. audio_source_input_t *m_pChannelsIn;
  106. audio_source_indexstate_t *m_pChannelsOut;
  107. uint32 m_nInputStride;
  108. uint32 m_nPlaybackStride;
  109. uint32 m_nChannelCount;
  110. dspglobalvars_t *m_pGlobals;
  111. public:
  112. inline void Init( audio_source_input_t *pInput, uint32 nInputStride, audio_source_indexstate_t *pPlayback, uint32 nPlaybackStride, uint32 nCount )
  113. {
  114. m_pChannelsIn = pInput;
  115. m_pChannelsOut = pPlayback;
  116. m_nInputStride = nInputStride;
  117. m_nPlaybackStride = nPlaybackStride;
  118. m_nChannelCount = nCount;
  119. }
  120. void SetDSPGlobals( dspglobalvars_t *pGlobals )
  121. {
  122. m_pGlobals = pGlobals;
  123. }
  124. CAudioMixState( audio_source_input_t *pInput, uint32 nInputStride, audio_source_indexstate_t *pPlayback, uint32 nPlaybackStride, uint32 nCount )
  125. : m_pChannelsIn(pInput), m_pChannelsOut(pPlayback), m_nInputStride(nInputStride), m_nPlaybackStride(nPlaybackStride), m_nChannelCount(nCount)
  126. {
  127. }
  128. CAudioMixState()
  129. {
  130. m_pChannelsIn = 0;
  131. m_pChannelsOut = 0;
  132. m_nChannelCount = 0;
  133. m_pGlobals = nullptr;
  134. }
  135. inline void Clear()
  136. {
  137. m_pChannelsIn = NULL;
  138. m_pChannelsOut = NULL;
  139. m_nChannelCount = 0;
  140. }
  141. inline audio_source_input_t *GetInput( int nIndex ) const
  142. {
  143. return (audio_source_input_t *)( (byte *)m_pChannelsIn + nIndex * m_nInputStride );
  144. }
  145. inline audio_source_indexstate_t *GetOutput( int nIndex ) const
  146. {
  147. return (audio_source_indexstate_t *)( (byte *)m_pChannelsOut + nIndex * m_nPlaybackStride );
  148. }
  149. bool IsChannelFinished( int nChannel ) const
  150. {
  151. return ( GetOutput( nChannel )->m_nPacketIndex >= GetInput( nChannel )->m_nPacketCount ) ? true : false;
  152. }
  153. dspglobalvars_t *DSPGlobals() const { return m_pGlobals; }
  154. };
  155. enum mix_command_id_t
  156. {
  157. AUDIO_MIX_CLEAR = 0,
  158. AUDIO_MIX_EXTRACT_SOURCE,
  159. AUDIO_MIX_ADVANCE_SOURCE,
  160. AUDIO_MIX_ACCUMULATE,
  161. AUDIO_MIX_ACCUMULATE_RAMP,
  162. AUDIO_MIX_MULTIPLY,
  163. AUDIO_MIX_PROCESS,
  164. AUDIO_MIX_SUM,
  165. AUDIO_MIX_SWAP, // swap two buffers
  166. AUDIO_MIX_MEASURE_DEBUG_LEVEL,
  167. AUDIO_MIX_OUTPUT_LEVEL,
  168. };
  169. struct audio_mix_command_t
  170. {
  171. uint16 m_nCommandId;
  172. uint16 m_nOutput;
  173. uint16 m_nInput0;
  174. uint16 m_nInput1;
  175. float m_flParam0;
  176. float m_flParam1;
  177. void Init( mix_command_id_t cmd, uint16 nOut )
  178. {
  179. m_nCommandId = (uint16)cmd;
  180. m_nOutput = nOut;
  181. m_nInput0 = 0;
  182. m_nInput1 = 0;
  183. m_flParam0 = 0.0f;
  184. m_flParam1 = 0.0f;
  185. }
  186. void Init( mix_command_id_t cmd, uint16 nOut, uint16 nIn0, float flScale )
  187. {
  188. m_nCommandId = (uint16)cmd;
  189. m_nOutput = nOut;
  190. m_nInput0 = nIn0;
  191. m_nInput1 = 0;
  192. m_flParam0 = flScale;
  193. m_flParam1 = 0.0f;
  194. }
  195. void Init( mix_command_id_t cmd, uint16 nOut, uint16 nIn0, uint16 nIn1, float flScale0, float flScale1 )
  196. {
  197. m_nCommandId = (uint16)cmd;
  198. m_nOutput = nOut;
  199. m_nInput0 = nIn0;
  200. m_nInput1 = nIn1;
  201. m_flParam0 = flScale0;
  202. m_flParam1 = flScale1;
  203. }
  204. };
  205. class CAudioMixCommandList
  206. {
  207. public:
  208. inline void ClearBuffer( uint16 nTarget )
  209. {
  210. audio_mix_command_t cmd;
  211. cmd.Init( AUDIO_MIX_CLEAR, nTarget );
  212. m_commands.AddToTail( cmd );
  213. }
  214. void ClearMultichannel( uint16 nTarget, int nCount );
  215. void ScaleMultichannel( uint16 nTarget, uint16 nInput, int nCount, float flVolume );
  216. inline void ExtractSourceToBuffer( uint16 nTarget, uint16 nChannel, float flVolume, float flPitch )
  217. {
  218. audio_mix_command_t cmd;
  219. cmd.Init( AUDIO_MIX_EXTRACT_SOURCE, nTarget, nChannel, 0, flVolume, flPitch );
  220. m_commands.AddToTail( cmd );
  221. }
  222. inline void AdvanceSource( uint16 nChannel, float flPitch )
  223. {
  224. audio_mix_command_t cmd;
  225. cmd.Init( AUDIO_MIX_ADVANCE_SOURCE, 0, nChannel, 0, 0, flPitch );
  226. m_commands.AddToTail( cmd );
  227. }
  228. inline void ProcessBuffer( uint16 nOutput, uint16 nInput, uint16 nProcessor, int nChannelCount )
  229. {
  230. audio_mix_command_t cmd;
  231. cmd.Init( AUDIO_MIX_PROCESS, nOutput, nInput, nProcessor, float(nChannelCount), 0.0f );
  232. m_commands.AddToTail( cmd );
  233. }
  234. inline uint16 ProcessBuffer( uint16 nOutput, uint16 nInput, int nChannelCount, CAudioProcessor *pProc )
  235. {
  236. uint16 nProcessor = (uint16)m_processors.AddToTail( pProc );
  237. ProcessBuffer( nOutput, nInput, nProcessor, nChannelCount );
  238. return nProcessor;
  239. }
  240. inline void ScaleBuffer( uint16 nOutput, uint16 nInput, float flVolume )
  241. {
  242. audio_mix_command_t cmd;
  243. cmd.Init( AUDIO_MIX_MULTIPLY, nOutput, nInput, flVolume );
  244. m_commands.AddToTail( cmd );
  245. }
  246. inline void AccumulateToBuffer( uint16 nOutput, uint16 nInput, float flVolume )
  247. {
  248. // if the volume is zero this will have no effect, so it is safe to skip it
  249. if ( flVolume == 0.0f )
  250. return;
  251. audio_mix_command_t cmd;
  252. cmd.Init( AUDIO_MIX_ACCUMULATE, nOutput, nInput, flVolume );
  253. m_commands.AddToTail( cmd );
  254. }
  255. inline void AccumulateToBufferVolumeRamp( uint16 nOutput, uint16 nInput, float flVolumeStart, float flVolumeEnd )
  256. {
  257. // Too small of a volume change to ramp? Just output without the ramp
  258. // 1e-3f is small enough that we might do it during a normal ramp
  259. // (2e-3f is the slope of a full scale fade at 512 samples per batch)
  260. if ( fabs( flVolumeEnd-flVolumeStart) < 1e-3f )
  261. {
  262. AccumulateToBuffer( nOutput, nInput, flVolumeEnd );
  263. return;
  264. }
  265. audio_mix_command_t cmd;
  266. cmd.Init( AUDIO_MIX_ACCUMULATE_RAMP, nOutput, nInput, 0, flVolumeStart, flVolumeEnd );
  267. m_commands.AddToTail( cmd );
  268. }
  269. inline void Mix2x1( uint16 nOutput, uint16 nInput0, uint16 nInput1, float flVolume0, float flVolume1 )
  270. {
  271. audio_mix_command_t cmd;
  272. cmd.Init( AUDIO_MIX_SUM, nOutput, nInput0, nInput1, flVolume0, flVolume1 );
  273. m_commands.AddToTail( cmd );
  274. }
  275. inline void SwapBuffers( uint16 nInput0, uint16 nInput1 )
  276. {
  277. audio_mix_command_t cmd;
  278. cmd.Init( AUDIO_MIX_SWAP, nInput0, nInput1, 1.0f );
  279. m_commands.AddToTail( cmd );
  280. }
  281. inline void ReadOutputLevel( uint16 nLevelOutput, uint16 nInput0, uint16 nInputChannelCount )
  282. {
  283. audio_mix_command_t cmd;
  284. cmd.Init( AUDIO_MIX_OUTPUT_LEVEL, nLevelOutput, nInput0, nInputChannelCount, 1.0f, 1.0f );
  285. m_commands.AddToTail( cmd );
  286. }
  287. inline void DebugReadLevel( uint16 nDebugOutput0, uint16 nInput0, uint16 nInputChannelCount )
  288. {
  289. audio_mix_command_t cmd;
  290. cmd.Init( AUDIO_MIX_MEASURE_DEBUG_LEVEL, nDebugOutput0, nInput0, nInputChannelCount, 1.0f, 1.0f );
  291. m_commands.AddToTail( cmd );
  292. }
  293. inline uint16 AddProcessor( CAudioProcessor *pProc )
  294. {
  295. return (uint16)m_processors.AddToTail( pProc );
  296. }
  297. inline void Clear()
  298. {
  299. m_commands.RemoveAll();
  300. m_processors.RemoveAll();
  301. }
  302. void AccumulateMultichannel( uint16 nOutput, int nOutputChannels, uint16 nInput, int nInputChannels, float flInputVolume );
  303. CUtlVectorFixedGrowable<audio_mix_command_t, 256> m_commands;
  304. CUtlVectorFixedGrowable<CAudioProcessor *, 8> m_processors;
  305. };
  306. // This describes the state for each iteration of mixing
  307. // it is the list of all low-level audio operations that need to take place
  308. // in order to produce one buffer of mixed output
  309. class CAudioMixDescription : public CAudioMixCommandList
  310. {
  311. public:
  312. inline void Init( int nChannels )
  313. {
  314. m_nMixBuffersInUse = 0;
  315. m_nMixBufferMax = 0;
  316. m_nDebugOutputCount = 0;
  317. m_nOutputLevelCount = 0;
  318. Clear();
  319. #if USE_VOICE_LAYERS
  320. for ( int i = 0; i < NUM_VOICE_LAYERS; i++ )
  321. {
  322. m_flLayerVolume[i] = 1.0f;
  323. }
  324. #endif
  325. }
  326. // Add a new mix buffer
  327. inline uint16 AllocMixBuffer( uint nCount = 1 )
  328. {
  329. int nOut = m_nMixBuffersInUse;
  330. m_nMixBuffersInUse += nCount;
  331. m_nMixBufferMax = MAX( m_nMixBufferMax, m_nMixBuffersInUse );
  332. return (uint16)nOut;
  333. }
  334. inline void FreeMixBuffer( uint16 nStart, uint nCount = 1 )
  335. {
  336. // we only support freeing from the end of the stack
  337. Assert( nStart + nCount == m_nMixBuffersInUse );
  338. if ( nStart + nCount == m_nMixBuffersInUse )
  339. {
  340. m_nMixBuffersInUse -= nCount;
  341. }
  342. }
  343. inline int AllocDebugOutputs( int nOutputs )
  344. {
  345. int nRet = m_nDebugOutputCount;
  346. m_nDebugOutputCount += nOutputs;
  347. return nRet;
  348. }
  349. inline int AllocOutputLevels( int nOutputs )
  350. {
  351. int nRet = m_nOutputLevelCount;
  352. m_nOutputLevelCount += nOutputs;
  353. return nRet;
  354. }
  355. uint m_nMixBufferMax;
  356. uint m_nMixBuffersInUse;
  357. uint m_nDebugOutputCount;
  358. uint m_nOutputLevelCount;
  359. #if USE_VOICE_LAYERS
  360. float m_flLayerVolume[NUM_VOICE_LAYERS];
  361. #endif
  362. };
  363. struct mix_debug_outputs_t
  364. {
  365. uint32 m_nChannelCount;
  366. float m_flLevel;
  367. float m_flChannelLevels[8];
  368. };
  369. // NOTE: This object is large (>64KB) declaring one on the stack may crash some platforms
  370. class CAudioMixResults
  371. {
  372. public:
  373. CUtlVectorFixedGrowable<mix_debug_outputs_t,8> m_debugOutputs;
  374. CUtlVectorFixedGrowable<float, 16> m_flOutputLevels;
  375. CUtlVectorFixedGrowable<CAudioMixBuffer, 32> m_pOutput;
  376. };
  377. extern void ProcessAudioMix( CAudioMixResults *pResults, const CAudioMixState &mixState, CAudioMixDescription &mixSetup );
  378. #endif // AUDIO_MIX_H