AkApplyGain.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. /*******************************************************************************
  2. The content of this file includes portions of the AUDIOKINETIC Wwise Technology
  3. released in source code form as part of the SDK installer package.
  4. Commercial License Usage
  5. Licensees holding valid commercial licenses to the AUDIOKINETIC Wwise Technology
  6. may use this file in accordance with the end user license agreement provided
  7. with the software or, alternatively, in accordance with the terms contained in a
  8. written agreement between you and Audiokinetic Inc.
  9. Apache License Usage
  10. Alternatively, this file may be used under the Apache License, Version 2.0 (the
  11. "Apache License"); you may not use this file except in compliance with the
  12. Apache License. You may obtain a copy of the Apache License at
  13. http://www.apache.org/licenses/LICENSE-2.0.
  14. Unless required by applicable law or agreed to in writing, software distributed
  15. under the Apache License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
  16. OR CONDITIONS OF ANY KIND, either express or implied. See the Apache License for
  17. the specific language governing permissions and limitations under the License.
  18. Copyright (c) 2023 Audiokinetic Inc.
  19. *******************************************************************************/
  20. // Accumulate (+=) signal into output buffer
  21. // To be used on mono signals, create as many instances as there are channels if need be
  22. #ifndef _AKAPPLYGAIN_H_
  23. #define _AKAPPLYGAIN_H_
  24. #include <AK/SoundEngine/Common/AkTypes.h>
  25. #include <AK/SoundEngine/Common/AkCommonDefs.h>
  26. #include <AK/SoundEngine/Common/AkSimd.h>
  27. #if defined (AKSIMD_V4F32_SUPPORTED) || defined (AKSIMD_V2F32_SUPPORTED)
  28. #include <AK/Plugin/PluginServices/AkVectorValueRamp.h>
  29. // Otherwise, it is preferrable not to use a generic implementation of a vector type.
  30. #endif
  31. namespace AK
  32. {
  33. namespace DSP
  34. {
  35. /// Single channel, in-place interpolating gain helper (do not call directly) use ApplyGain instead.
  36. static inline void ApplyGainRamp(
  37. AkSampleType * AK_RESTRICT io_pfBuffer,
  38. AkReal32 in_fCurGain,
  39. AkReal32 in_fTargetGain,
  40. AkUInt32 in_uNumFrames )
  41. {
  42. AkSampleType * AK_RESTRICT pfBuf = (AkSampleType *) io_pfBuffer;
  43. const AkSampleType * const pfEnd = io_pfBuffer + in_uNumFrames;
  44. #ifdef AKSIMD_V4F32_SUPPORTED
  45. const AkUInt32 uNumVecIter = in_uNumFrames/4;
  46. if(uNumVecIter)
  47. {
  48. CAkVectorValueRamp vGainRamp;
  49. AKSIMD_V4F32 vfGain = vGainRamp.Setup(in_fCurGain,in_fTargetGain,uNumVecIter*4);
  50. const AkSampleType * const pfVecEnd = io_pfBuffer + uNumVecIter*4;
  51. while ( pfBuf < pfVecEnd )
  52. {
  53. AKSIMD_V4F32 vfIn = AKSIMD_LOAD_V4F32((AKSIMD_F32*)pfBuf);
  54. AKSIMD_V4F32 vfOut = AKSIMD_MUL_V4F32( vfIn, vfGain );
  55. AKSIMD_STORE_V4F32( (AKSIMD_F32*)pfBuf, vfOut );
  56. vfGain = vGainRamp.Tick();
  57. pfBuf+=4;
  58. }
  59. }
  60. #elif defined (AKSIMD_V2F32_SUPPORTED)
  61. // Unroll 4 times x v2.
  62. const AkUInt32 uNumVecIter = in_uNumFrames/8;
  63. if(uNumVecIter)
  64. {
  65. CAkVectorValueRampV2 vGainRamp;
  66. AKSIMD_V2F32 vfGain = vGainRamp.Setup(in_fCurGain,in_fTargetGain,uNumVecIter*8);
  67. const AkSampleType * const AK_RESTRICT pfVecEnd = io_pfBuffer + uNumVecIter*8;
  68. while ( pfBuf < pfVecEnd )
  69. {
  70. AKSIMD_V2F32 vfIn1 = AKSIMD_LOAD_V2F32_OFFSET( pfBuf, 0 );
  71. AKSIMD_V2F32 vfIn2 = AKSIMD_LOAD_V2F32_OFFSET( pfBuf, 8 );
  72. AKSIMD_V2F32 vfIn3 = AKSIMD_LOAD_V2F32_OFFSET( pfBuf, 16 );
  73. AKSIMD_V2F32 vfIn4 = AKSIMD_LOAD_V2F32_OFFSET( pfBuf, 24 );
  74. AKSIMD_V2F32 vfOut1 = AKSIMD_MUL_V2F32( vfIn1, vfGain );
  75. vfGain = vGainRamp.Tick();
  76. AKSIMD_V2F32 vfOut2 = AKSIMD_MUL_V2F32( vfIn2, vfGain );
  77. vfGain = vGainRamp.Tick();
  78. AKSIMD_V2F32 vfOut3 = AKSIMD_MUL_V2F32( vfIn3, vfGain );
  79. vfGain = vGainRamp.Tick();
  80. AKSIMD_V2F32 vfOut4 = AKSIMD_MUL_V2F32( vfIn4, vfGain );
  81. vfGain = vGainRamp.Tick();
  82. AKSIMD_STORE_V2F32_OFFSET( pfBuf, 0, vfOut1 );
  83. AKSIMD_STORE_V2F32_OFFSET( pfBuf, 8, vfOut2 );
  84. AKSIMD_STORE_V2F32_OFFSET( pfBuf, 16, vfOut3 );
  85. AKSIMD_STORE_V2F32_OFFSET( pfBuf, 24, vfOut4 );
  86. pfBuf+=8;
  87. }
  88. }
  89. /*
  90. const AkUInt32 uNumVecIter = in_uNumFrames/2;
  91. CAkVectorValueRampV2 vGainRamp;
  92. AKSIMD_V2F32 vfGain = vGainRamp.Setup(in_fCurGain,in_fTargetGain,uNumVecIter*2);
  93. const AkSampleType * const pfVecEnd = io_pfBuffer + uNumVecIter*2;
  94. while ( pfBuf < pfVecEnd )
  95. {
  96. AKSIMD_V2F32 vfIn = AKSIMD_LOAD_V2F32_OFFSET( pfBuf, 0 );
  97. AKSIMD_V2F32 vfOut = AKSIMD_MUL_V2F32( vfIn, vfGain );
  98. AKSIMD_STORE_V2F32_OFFSET( pfBuf, 0, vfOut );
  99. vfGain = vGainRamp.Tick();
  100. pfBuf+=2;
  101. }
  102. */
  103. #endif
  104. if ( pfBuf < pfEnd )
  105. {
  106. const AkReal32 fInc = (in_fTargetGain - in_fCurGain) / in_uNumFrames;
  107. do
  108. {
  109. *pfBuf = (AkSampleType)(*pfBuf * in_fCurGain);
  110. in_fCurGain += fInc;
  111. pfBuf++;
  112. }while ( pfBuf < pfEnd );
  113. }
  114. }
  115. /// Single channel, out-of-place interpolating gain helper (do not call directly) use ApplyGain instead.
  116. static inline void ApplyGainRamp(
  117. AkSampleType * AK_RESTRICT in_pfBufferIn,
  118. AkSampleType * AK_RESTRICT out_pfBufferOut,
  119. AkReal32 in_fCurGain,
  120. AkReal32 in_fTargetGain,
  121. AkUInt32 in_uNumFrames )
  122. {
  123. AkSampleType * AK_RESTRICT pfInBuf = (AkSampleType * ) in_pfBufferIn;
  124. AkSampleType * AK_RESTRICT pfOutBuf = (AkSampleType * ) out_pfBufferOut;
  125. const AkSampleType * const pfEnd = pfInBuf + in_uNumFrames;
  126. #ifdef AKSIMD_V4F32_SUPPORTED
  127. const AkUInt32 uNumVecIter = in_uNumFrames/4;
  128. if(uNumVecIter)
  129. {
  130. CAkVectorValueRamp vGainRamp;
  131. AKSIMD_V4F32 vfGain = vGainRamp.Setup(in_fCurGain,in_fTargetGain,uNumVecIter*4);
  132. const AkSampleType * const pfVecEnd = in_pfBufferIn + uNumVecIter*4;
  133. while ( pfInBuf < pfVecEnd )
  134. {
  135. AKSIMD_V4F32 vfIn = AKSIMD_LOAD_V4F32((AKSIMD_F32*)pfInBuf);
  136. AKSIMD_V4F32 vfOut = AKSIMD_MUL_V4F32( vfIn, vfGain );
  137. AKSIMD_STORE_V4F32( (AKSIMD_F32*)pfOutBuf, vfOut );
  138. vfGain = vGainRamp.Tick();
  139. pfInBuf+=4;
  140. pfOutBuf+=4;
  141. }
  142. }
  143. #elif defined (AKSIMD_V2F32_SUPPORTED)
  144. const AkUInt32 uNumVecIter = in_uNumFrames/2;
  145. if(uNumVecIter)
  146. {
  147. CAkVectorValueRampV2 vGainRamp;
  148. f32x2 vfGain = vGainRamp.Setup(in_fCurGain,in_fTargetGain,uNumVecIter*2);
  149. const AkSampleType * const pfVecEnd = in_pfBufferIn + uNumVecIter*2;
  150. while ( pfInBuf < pfVecEnd )
  151. {
  152. AKSIMD_V2F32 vfIn = AKSIMD_LOAD_V2F32_OFFSET( pfInBuf, 0 );
  153. AKSIMD_V2F32 vfOut = AKSIMD_MUL_V2F32( vfIn, vfGain );
  154. AKSIMD_STORE_V2F32_OFFSET( pfOutBuf, 0, vfOut );
  155. vfGain = vGainRamp.Tick();
  156. pfInBuf+=2;
  157. pfOutBuf+=2;
  158. }
  159. }
  160. #endif
  161. if ( pfInBuf < pfEnd )
  162. {
  163. const AkReal32 fInc = (in_fTargetGain - in_fCurGain) / in_uNumFrames;
  164. do
  165. {
  166. *pfOutBuf++ = (AkSampleType)(*pfInBuf++ * in_fCurGain);
  167. in_fCurGain += fInc;
  168. }while ( pfInBuf < pfEnd );
  169. }
  170. }
  171. /// Single channel, in-place static gain.
  172. static inline void ApplyGain(
  173. AkSampleType * AK_RESTRICT io_pfBuffer,
  174. AkReal32 in_fGain,
  175. AkUInt32 in_uNumFrames )
  176. {
  177. if ( in_fGain != 1.f )
  178. {
  179. AkSampleType * AK_RESTRICT pfBuf = (AkSampleType * ) io_pfBuffer;
  180. const AkSampleType * const pfEnd = io_pfBuffer + in_uNumFrames;
  181. #ifdef AKSIMD_V4F32_SUPPORTED
  182. const AkUInt32 uNumVecIter = in_uNumFrames/4;
  183. if(uNumVecIter)
  184. {
  185. const AkSampleType * const pfVecEnd = io_pfBuffer + uNumVecIter*4;
  186. const AKSIMD_V4F32 vfGain = AKSIMD_LOAD1_V4F32( in_fGain );
  187. while ( pfBuf < pfVecEnd )
  188. {
  189. AKSIMD_V4F32 vfIn = AKSIMD_LOAD_V4F32((AKSIMD_F32*)pfBuf);
  190. AKSIMD_V4F32 vfOut = AKSIMD_MUL_V4F32( vfIn, vfGain );
  191. AKSIMD_STORE_V4F32( (AKSIMD_F32*)pfBuf, vfOut );
  192. pfBuf+=4;
  193. }
  194. }
  195. #elif defined (AKSIMD_V2F32_SUPPORTED)
  196. // Unroll 4 times x 2 floats
  197. const AkUInt32 uNumVecIter = in_uNumFrames/8;
  198. if( uNumVecIter)
  199. {
  200. AKSIMD_V2F32 vfGain = __PS_FDUP( in_fGain );
  201. const AkSampleType * const pfVecEnd = io_pfBuffer + uNumVecIter*8;
  202. while ( pfBuf < pfVecEnd )
  203. {
  204. AKSIMD_V2F32 vfIn1 = AKSIMD_LOAD_V2F32_OFFSET( pfBuf, 0 );
  205. AKSIMD_V2F32 vfIn2 = AKSIMD_LOAD_V2F32_OFFSET( pfBuf, 8 );
  206. AKSIMD_V2F32 vfIn3 = AKSIMD_LOAD_V2F32_OFFSET( pfBuf, 16 );
  207. AKSIMD_V2F32 vfIn4 = AKSIMD_LOAD_V2F32_OFFSET( pfBuf, 24 );
  208. AKSIMD_V2F32 vfOut1 = AKSIMD_MUL_V2F32( vfIn1, vfGain );
  209. AKSIMD_V2F32 vfOut2 = AKSIMD_MUL_V2F32( vfIn2, vfGain );
  210. AKSIMD_V2F32 vfOut3 = AKSIMD_MUL_V2F32( vfIn3, vfGain );
  211. AKSIMD_V2F32 vfOut4 = AKSIMD_MUL_V2F32( vfIn4, vfGain );
  212. AKSIMD_STORE_V2F32_OFFSET( pfBuf, 0, vfOut1 );
  213. AKSIMD_STORE_V2F32_OFFSET( pfBuf, 8, vfOut2 );
  214. AKSIMD_STORE_V2F32_OFFSET( pfBuf, 16, vfOut3 );
  215. AKSIMD_STORE_V2F32_OFFSET( pfBuf, 24, vfOut4 );
  216. pfBuf+=8;
  217. }
  218. }
  219. /*
  220. const AkUInt32 uNumVecIter = in_uNumFrames/2;
  221. AKSIMD_V2F32 vfGain = __PS_FDUP( in_fGain );
  222. const AkSampleType * const pfVecEnd = io_pfBuffer + uNumVecIter*2;
  223. while ( pfBuf < pfVecEnd )
  224. {
  225. AKSIMD_V2F32 vfIn = AKSIMD_LOAD_V2F32_OFFSET( pfBuf, 0 );
  226. AKSIMD_V2F32 vfOut = AKSIMD_MUL_V2F32( vfIn, vfGain );
  227. AKSIMD_STORE_V2F32_OFFSET( pfBuf, 0, vfOut );
  228. pfBuf+=2;
  229. }
  230. */
  231. #endif
  232. while ( pfBuf < pfEnd )
  233. {
  234. *pfBuf = (AkSampleType)(*pfBuf * in_fGain);
  235. pfBuf++;
  236. }
  237. }
  238. }
  239. /// Single channel, Out-of-place static gain.
  240. static inline void ApplyGain(
  241. AkSampleType * AK_RESTRICT in_pfBufferIn,
  242. AkSampleType * AK_RESTRICT out_pfBufferOut,
  243. AkReal32 in_fGain,
  244. AkUInt32 in_uNumFrames )
  245. {
  246. AkSampleType * AK_RESTRICT pfInBuf = (AkSampleType * ) in_pfBufferIn;
  247. AkSampleType * AK_RESTRICT pfOutBuf = (AkSampleType * ) out_pfBufferOut;
  248. const AkSampleType * const pfEnd = in_pfBufferIn + in_uNumFrames;
  249. #ifdef AKSIMD_V4F32_SUPPORTED
  250. const AkUInt32 uNumVecIter = in_uNumFrames/4;
  251. if( uNumVecIter)
  252. {
  253. const AkSampleType * const pfVecEnd = in_pfBufferIn + uNumVecIter*4;
  254. const AKSIMD_V4F32 vfGain = AKSIMD_LOAD1_V4F32( in_fGain );
  255. while ( pfInBuf < pfVecEnd )
  256. {
  257. AKSIMD_V4F32 vfIn = AKSIMD_LOAD_V4F32((AKSIMD_F32*)pfInBuf);
  258. AKSIMD_V4F32 vfOut = AKSIMD_MUL_V4F32( vfIn, vfGain );
  259. AKSIMD_STORE_V4F32( (AKSIMD_F32*)pfOutBuf, vfOut );
  260. pfInBuf+=4;
  261. pfOutBuf+=4;
  262. }
  263. }
  264. #elif defined (AKSIMD_V2F32_SUPPORTED)
  265. // Unroll 4 times x 2 floats
  266. const AkUInt32 uNumVecIter = in_uNumFrames/8;
  267. if( uNumVecIter)
  268. {
  269. const AkSampleType * const pfVecEnd = in_pfBufferIn + uNumVecIter*8;
  270. AKSIMD_V2F32 vfGain = __PS_FDUP( in_fGain );
  271. while ( pfInBuf < pfVecEnd )
  272. {
  273. AKSIMD_V2F32 vfIn1 = AKSIMD_LOAD_V2F32_OFFSET( pfInBuf, 0 );
  274. AKSIMD_V2F32 vfIn2 = AKSIMD_LOAD_V2F32_OFFSET( pfInBuf, 8 );
  275. AKSIMD_V2F32 vfIn3 = AKSIMD_LOAD_V2F32_OFFSET( pfInBuf, 16 );
  276. AKSIMD_V2F32 vfIn4 = AKSIMD_LOAD_V2F32_OFFSET( pfInBuf, 24 );
  277. pfInBuf+=8;
  278. AKSIMD_V2F32 vfOut1 = AKSIMD_MUL_V2F32( vfIn1, vfGain );
  279. AKSIMD_V2F32 vfOut2 = AKSIMD_MUL_V2F32( vfIn2, vfGain );
  280. AKSIMD_V2F32 vfOut3 = AKSIMD_MUL_V2F32( vfIn3, vfGain );
  281. AKSIMD_V2F32 vfOut4 = AKSIMD_MUL_V2F32( vfIn4, vfGain );
  282. AKSIMD_STORE_V2F32_OFFSET( pfOutBuf, 0, vfOut1 );
  283. AKSIMD_STORE_V2F32_OFFSET( pfOutBuf, 8, vfOut2 );
  284. AKSIMD_STORE_V2F32_OFFSET( pfOutBuf, 16, vfOut3 );
  285. AKSIMD_STORE_V2F32_OFFSET( pfOutBuf, 24, vfOut4 );
  286. pfOutBuf+=8;
  287. }
  288. }
  289. /*
  290. const AkUInt32 uNumVecIter = in_uNumFrames/2;
  291. const AkSampleType * const pfVecEnd = in_pfBufferIn + uNumVecIter*2;
  292. AKSIMD_V2F32 vfGain = __PS_FDUP( in_fGain );
  293. while ( pfInBuf < pfVecEnd )
  294. {
  295. AKSIMD_V2F32 vfIn = AKSIMD_LOAD_V2F32_OFFSET( pfInBuf, 0 );
  296. AKSIMD_V2F32 vfOut = AKSIMD_MUL_V2F32( vfIn, vfGain );
  297. AKSIMD_STORE_V2F32_OFFSET( pfOutBuf, 0, vfOut );
  298. pfInBuf+=2;
  299. pfOutBuf+=2;
  300. }
  301. */
  302. #endif
  303. while ( pfInBuf < pfEnd )
  304. {
  305. *pfOutBuf++ = (AkSampleType)(*pfInBuf++ * in_fGain);
  306. }
  307. }
  308. /// Single channel, In-place (possibly interpolating) gain.
  309. static inline void ApplyGain(
  310. AkSampleType * AK_RESTRICT io_pfBuffer,
  311. AkReal32 in_fCurGain,
  312. AkReal32 in_fTargetGain,
  313. AkUInt32 in_uNumFrames )
  314. {
  315. if ( in_fTargetGain == in_fCurGain )
  316. ApplyGain(io_pfBuffer, in_fCurGain, in_uNumFrames );
  317. else
  318. ApplyGainRamp( io_pfBuffer, in_fCurGain, in_fTargetGain, in_uNumFrames );
  319. }
  320. /// Single channel, Out-of-place (possibly interpolating) gain.
  321. static inline void ApplyGain(
  322. AkSampleType * AK_RESTRICT in_pfBufferIn,
  323. AkSampleType * AK_RESTRICT out_pfBufferOut,
  324. AkReal32 in_fCurGain,
  325. AkReal32 in_fTargetGain,
  326. AkUInt32 in_uNumFrames )
  327. {
  328. if ( in_fTargetGain == in_fCurGain )
  329. ApplyGain(in_pfBufferIn, out_pfBufferOut, in_fCurGain, in_uNumFrames );
  330. else
  331. ApplyGainRamp( in_pfBufferIn, out_pfBufferOut, in_fCurGain, in_fTargetGain, in_uNumFrames );
  332. }
  333. /// Multi-channel in-place (possibly interpolating) gain.
  334. static inline void ApplyGain(
  335. AkAudioBuffer * io_pBuffer,
  336. AkReal32 in_fCurGain,
  337. AkReal32 in_fTargetGain,
  338. bool in_bProcessLFE = true )
  339. {
  340. AkUInt32 uNumChannels = io_pBuffer->NumChannels();
  341. if ( !in_bProcessLFE && io_pBuffer->HasLFE() )
  342. uNumChannels--;
  343. const AkUInt32 uNumFrames = io_pBuffer->uValidFrames;
  344. if ( in_fTargetGain == in_fCurGain )
  345. {
  346. // No need for interpolation
  347. for ( AkUInt32 i = 0; i < uNumChannels; i++ )
  348. {
  349. AkSampleType * pfChan = io_pBuffer->GetChannel( i );
  350. ApplyGain(pfChan, in_fCurGain, uNumFrames );
  351. }
  352. }
  353. else
  354. {
  355. // Interpolate gains toward target
  356. for ( AkUInt32 i = 0; i < uNumChannels; i++ )
  357. {
  358. AkSampleType * pfChan = io_pBuffer->GetChannel( i );
  359. ApplyGainRamp(pfChan, in_fCurGain, in_fTargetGain, uNumFrames );
  360. }
  361. }
  362. }
  363. /// Single-channel LFE in-place (possibly interpolating) gain.
  364. static inline void ApplyGainLFE(
  365. AkAudioBuffer * io_pBuffer,
  366. AkReal32 in_fCurGain,
  367. AkReal32 in_fTargetGain )
  368. {
  369. if( io_pBuffer->HasLFE() )
  370. {
  371. AkUInt32 uLFEChannelIdx = io_pBuffer->NumChannels()-1;
  372. const AkUInt32 uNumFrames = io_pBuffer->uValidFrames;
  373. AkSampleType * pfChan = io_pBuffer->GetChannel( uLFEChannelIdx );
  374. if ( in_fTargetGain == in_fCurGain )
  375. {
  376. // No need for interpolation
  377. ApplyGain(pfChan, in_fCurGain, uNumFrames );
  378. }
  379. else
  380. {
  381. // Interpolate gains toward target
  382. ApplyGainRamp(pfChan, in_fCurGain, in_fTargetGain, uNumFrames );
  383. }
  384. }
  385. }
  386. /// Multi-channel out-of-place (possibly interpolating) gain.
  387. static inline void ApplyGain(
  388. AkAudioBuffer * in_pBuffer,
  389. AkAudioBuffer * out_pBuffer,
  390. AkReal32 in_fCurGain,
  391. AkReal32 in_fTargetGain,
  392. bool in_bProcessLFE = true )
  393. {
  394. AKASSERT( in_pBuffer->NumChannels() == out_pBuffer->NumChannels() );
  395. AkUInt32 uNumChannels = in_pBuffer->NumChannels();
  396. if ( !in_bProcessLFE && in_pBuffer->HasLFE() )
  397. uNumChannels--;
  398. const AkUInt32 uNumFrames = AkMin( in_pBuffer->uValidFrames, out_pBuffer->MaxFrames() );
  399. if ( in_fTargetGain == in_fCurGain )
  400. {
  401. // No need for interpolation
  402. for ( AkUInt32 i = 0; i < uNumChannels; i++ )
  403. {
  404. AkSampleType * pfInChan = in_pBuffer->GetChannel( i );
  405. AkSampleType * pfOutChan = out_pBuffer->GetChannel( i );
  406. ApplyGain(pfInChan, pfOutChan, in_fCurGain, uNumFrames );
  407. }
  408. }
  409. else
  410. {
  411. // Interpolate gains toward target
  412. for ( AkUInt32 i = 0; i < uNumChannels; i++ )
  413. {
  414. AkSampleType * pfInChan = in_pBuffer->GetChannel( i );
  415. AkSampleType * pfOutChan = out_pBuffer->GetChannel( i );
  416. ApplyGainRamp( pfInChan, pfOutChan, in_fCurGain, in_fTargetGain, uNumFrames );
  417. }
  418. }
  419. }
  420. } // namespace DSP
  421. } // namespace AK
  422. #endif // _AKAPPLYGAIN_H_