1 /* -----------------------------------------------------------------------------
2 Software License for The Fraunhofer FDK AAC Codec Library for Android
3
4 © Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
5 Forschung e.V. All rights reserved.
6
7 1. INTRODUCTION
8 The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software
9 that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding
10 scheme for digital audio. This FDK AAC Codec software is intended to be used on
11 a wide variety of Android devices.
12
13 AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient
14 general perceptual audio codecs. AAC-ELD is considered the best-performing
15 full-bandwidth communications codec by independent studies and is widely
16 deployed. AAC has been standardized by ISO and IEC as part of the MPEG
17 specifications.
18
19 Patent licenses for necessary patent claims for the FDK AAC Codec (including
20 those of Fraunhofer) may be obtained through Via Licensing
21 (www.vialicensing.com) or through the respective patent owners individually for
22 the purpose of encoding or decoding bit streams in products that are compliant
23 with the ISO/IEC MPEG audio standards. Please note that most manufacturers of
24 Android devices already license these patent claims through Via Licensing or
25 directly from the patent owners, and therefore FDK AAC Codec software may
26 already be covered under those patent licenses when it is used for those
27 licensed purposes only.
28
29 Commercially-licensed AAC software libraries, including floating-point versions
30 with enhanced sound quality, are also available from Fraunhofer. Users are
31 encouraged to check the Fraunhofer website for additional applications
32 information and documentation.
33
34 2. COPYRIGHT LICENSE
35
36 Redistribution and use in source and binary forms, with or without modification,
37 are permitted without payment of copyright license fees provided that you
38 satisfy the following conditions:
39
40 You must retain the complete text of this software license in redistributions of
41 the FDK AAC Codec or your modifications thereto in source code form.
42
43 You must retain the complete text of this software license in the documentation
44 and/or other materials provided with redistributions of the FDK AAC Codec or
45 your modifications thereto in binary form. You must make available free of
46 charge copies of the complete source code of the FDK AAC Codec and your
47 modifications thereto to recipients of copies in binary form.
48
49 The name of Fraunhofer may not be used to endorse or promote products derived
50 from this library without prior written permission.
51
52 You may not charge copyright license fees for anyone to use, copy or distribute
53 the FDK AAC Codec software or your modifications thereto.
54
55 Your modified versions of the FDK AAC Codec must carry prominent notices stating
56 that you changed the software and the date of any change. For modified versions
57 of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android"
58 must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK
59 AAC Codec Library for Android."
60
61 3. NO PATENT LICENSE
62
63 NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without
64 limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE.
65 Fraunhofer provides no warranty of patent non-infringement with respect to this
66 software.
67
68 You may use this FDK AAC Codec software or modifications thereto only for
69 purposes that are authorized by appropriate patent licenses.
70
71 4. DISCLAIMER
72
73 This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright
74 holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
75 including but not limited to the implied warranties of merchantability and
76 fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
77 CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary,
78 or consequential damages, including but not limited to procurement of substitute
79 goods or services; loss of use, data, or profits, or business interruption,
80 however caused and on any theory of liability, whether in contract, strict
81 liability, or tort (including negligence), arising in any way out of the use of
82 this software, even if advised of the possibility of such damage.
83
84 5. CONTACT INFORMATION
85
86 Fraunhofer Institute for Integrated Circuits IIS
87 Attention: Audio and Multimedia Departments - FDK AAC LL
88 Am Wolfsmantel 33
89 91058 Erlangen, Germany
90
91 www.iis.fraunhofer.de/amm
92 amm-info@iis.fraunhofer.de
93 ----------------------------------------------------------------------------- */
94
95 /************************* MPEG-D DRC decoder library **************************
96
97 Author(s):
98
99 Description:
100
101 *******************************************************************************/
102
103 #include "drcDec_types.h"
104 #include "drcDec_gainDecoder.h"
105 #include "drcGainDec_process.h"
106
107 #define E_TGAINSTEP 12
108
_prepareLnbIndex(ACTIVE_DRC * pActiveDrc,const int channelOffset,const int drcChannelOffset,const int numChannelsProcessed,const int lnbPointer)109 static DRC_ERROR _prepareLnbIndex(ACTIVE_DRC* pActiveDrc,
110 const int channelOffset,
111 const int drcChannelOffset,
112 const int numChannelsProcessed,
113 const int lnbPointer) {
114 int g, c;
115 DRC_INSTRUCTIONS_UNI_DRC* pInst = pActiveDrc->pInst;
116
117 /* channelOffset: start index of physical channels
118 numChannelsProcessed: number of processed channels, physical channels and
119 DRC channels channelOffset + drcChannelOffset: start index of DRC channels,
120 i.e. the channel order referenced in pInst.sequenceIndex */
121
122 /* sanity checks */
123 if ((channelOffset + numChannelsProcessed) > 8) return DE_NOT_OK;
124
125 if ((channelOffset + drcChannelOffset + numChannelsProcessed) > 8)
126 return DE_NOT_OK;
127
128 if ((channelOffset + drcChannelOffset) < 0) return DE_NOT_OK;
129
130 /* prepare lnbIndexForChannel, a map of indices from each channel to its
131 * corresponding linearNodeBuffer instance */
132 for (c = channelOffset; c < channelOffset + numChannelsProcessed; c++) {
133 if (pInst->drcSetId > 0) {
134 int drcChannel = c + drcChannelOffset;
135 /* fallback for configuration with more physical channels than DRC
136 channels: reuse DRC gain of first channel. This is necessary for HE-AAC
137 mono with stereo output */
138 if (drcChannel >= pInst->drcChannelCount) drcChannel = 0;
139 g = pActiveDrc->channelGroupForChannel[drcChannel];
140 if ((g >= 0) && !pActiveDrc->channelGroupIsParametricDrc[g]) {
141 pActiveDrc->lnbIndexForChannel[c][lnbPointer] =
142 pActiveDrc->activeDrcOffset + pActiveDrc->gainElementForGroup[g];
143 }
144 }
145 }
146
147 return DE_OK;
148 }
149
_interpolateDrcGain(const GAIN_INTERPOLATION_TYPE gainInterpolationType,const SHORT timePrev,const SHORT tGainStep,const SHORT start,const SHORT stop,const SHORT stepsize,const FIXP_DBL gainLeft,const FIXP_DBL gainRight,const FIXP_DBL slopeLeft,const FIXP_DBL slopeRight,FIXP_DBL * buffer)150 static DRC_ERROR _interpolateDrcGain(
151 const GAIN_INTERPOLATION_TYPE gainInterpolationType,
152 const SHORT timePrev, /* time0 */
153 const SHORT tGainStep, /* time1 - time0 */
154 const SHORT start, const SHORT stop, const SHORT stepsize,
155 const FIXP_DBL gainLeft, const FIXP_DBL gainRight, const FIXP_DBL slopeLeft,
156 const FIXP_DBL slopeRight, FIXP_DBL* buffer) {
157 int n, n_buf;
158 int start_modulo, start_offset;
159
160 if (tGainStep < 0) {
161 return DE_NOT_OK;
162 }
163 if (tGainStep == 0) {
164 return DE_OK;
165 }
166
167 /* get start index offset and buffer index for downsampled interpolation */
168 /* start_modulo = (start+timePrev)%stepsize; */ /* stepsize is a power of 2 */
169 start_modulo = (start + timePrev) & (stepsize - 1);
170 start_offset = (start_modulo ? stepsize - start_modulo : 0);
171 /* n_buf = (start + timePrev + start_offset)/stepsize; */
172 n_buf = (start + timePrev + start_offset) >> (15 - fixnormz_S(stepsize));
173
174 { /* gainInterpolationType == GIT_LINEAR */
175 LONG a;
176 /* runs = ceil((stop - start - start_offset)/stepsize). This works for
177 * stepsize = 2^N only. */
178 INT runs = (INT)(stop - start - start_offset + stepsize - 1) >>
179 (30 - CountLeadingBits(stepsize));
180 INT n_min = fMin(
181 fMin(CntLeadingZeros(gainRight), CntLeadingZeros(gainLeft)) - 1, 8);
182 a = (LONG)((gainRight << n_min) - (gainLeft << n_min)) / tGainStep;
183 LONG a_step = a * stepsize;
184 n = start + start_offset;
185 a = a * n + (LONG)(gainLeft << n_min);
186 buffer += n_buf;
187 #if defined(FUNCTION_interpolateDrcGain_func1)
188 interpolateDrcGain_func1(buffer, a, a_step, n_min, runs);
189 #else
190 a -= a_step;
191 n_min = 8 - n_min;
192 for (int i = 0; i < runs; i++) {
193 a += a_step;
194 buffer[i] = fMultDiv2(buffer[i], (FIXP_DBL)a) << n_min;
195 }
196 #endif /* defined(FUNCTION_interpolateDrcGain_func1) */
197 }
198 return DE_OK;
199 }
200
_processNodeSegments(const int frameSize,const GAIN_INTERPOLATION_TYPE gainInterpolationType,const int nNodes,const NODE_LIN * pNodeLin,const int offset,const SHORT stepsize,const NODE_LIN nodePrevious,const FIXP_DBL channelGain,FIXP_DBL * buffer)201 static DRC_ERROR _processNodeSegments(
202 const int frameSize, const GAIN_INTERPOLATION_TYPE gainInterpolationType,
203 const int nNodes, const NODE_LIN* pNodeLin, const int offset,
204 const SHORT stepsize,
205 const NODE_LIN nodePrevious, /* the last node of the previous frame */
206 const FIXP_DBL channelGain, FIXP_DBL* buffer) {
207 DRC_ERROR err = DE_OK;
208 SHORT timePrev, duration, start, stop, time;
209 int n;
210 FIXP_DBL gainLin = FL2FXCONST_DBL(1.0f / (float)(1 << 7)), gainLinPrev;
211 FIXP_DBL slopeLin = (FIXP_DBL)0, slopeLinPrev = (FIXP_DBL)0;
212
213 timePrev = nodePrevious.time + offset;
214 gainLinPrev = nodePrevious.gainLin;
215 for (n = 0; n < nNodes; n++) {
216 time = pNodeLin[n].time + offset;
217 duration = time - timePrev;
218 gainLin = pNodeLin[n].gainLin;
219 if (channelGain != FL2FXCONST_DBL(1.0f / (float)(1 << 8)))
220 gainLin =
221 SATURATE_LEFT_SHIFT(fMultDiv2(gainLin, channelGain), 9, DFRACT_BITS);
222
223 if ((timePrev >= (frameSize - 1)) ||
224 (time < 0)) { /* This segment (between previous and current node) lies
225 outside of this audio frame */
226 timePrev = time;
227 gainLinPrev = gainLin;
228 slopeLinPrev = slopeLin;
229 continue;
230 }
231
232 /* start and stop are the boundaries of the region of this segment that lie
233 within this audio frame. Their values are relative to the beginning of
234 this segment. stop is the first sample that isn't processed any more. */
235 start = fMax(-timePrev, 1);
236 stop = fMin(time, (SHORT)(frameSize - 1)) - timePrev + 1;
237
238 err = _interpolateDrcGain(gainInterpolationType, timePrev, duration, start,
239 stop, stepsize, gainLinPrev, gainLin,
240 slopeLinPrev, slopeLin, buffer);
241 if (err) return err;
242
243 timePrev = time;
244 gainLinPrev = gainLin;
245 }
246 return err;
247 }
248
249 /* process DRC on time-domain signal */
250 DRC_ERROR
processDrcTime(HANDLE_DRC_GAIN_DECODER hGainDec,const int activeDrcIndex,const int delaySamples,const int channelOffset,const int drcChannelOffset,const int numChannelsProcessed,const int timeDataChannelOffset,FIXP_DBL * deinterleavedAudio)251 processDrcTime(HANDLE_DRC_GAIN_DECODER hGainDec, const int activeDrcIndex,
252 const int delaySamples, const int channelOffset,
253 const int drcChannelOffset, const int numChannelsProcessed,
254 const int timeDataChannelOffset, FIXP_DBL* deinterleavedAudio) {
255 DRC_ERROR err = DE_OK;
256 int c, b, i;
257 ACTIVE_DRC* pActiveDrc = &(hGainDec->activeDrc[activeDrcIndex]);
258 DRC_GAIN_BUFFERS* pDrcGainBuffers = &(hGainDec->drcGainBuffers);
259 int lnbPointer = pDrcGainBuffers->lnbPointer, lnbIx;
260 LINEAR_NODE_BUFFER* pLinearNodeBuffer = pDrcGainBuffers->linearNodeBuffer;
261 LINEAR_NODE_BUFFER* pDummyLnb = &(pDrcGainBuffers->dummyLnb);
262 int offset = 0;
263
264 if (hGainDec->delayMode == DM_REGULAR_DELAY) {
265 offset = hGainDec->frameSize;
266 }
267
268 if ((delaySamples + offset) >
269 (NUM_LNB_FRAMES - 2) *
270 hGainDec->frameSize) /* if delaySamples is too big, NUM_LNB_FRAMES
271 should be increased */
272 return DE_NOT_OK;
273
274 err = _prepareLnbIndex(pActiveDrc, channelOffset, drcChannelOffset,
275 numChannelsProcessed, lnbPointer);
276 if (err) return err;
277
278 deinterleavedAudio +=
279 channelOffset * timeDataChannelOffset; /* apply channelOffset */
280
281 /* signal processing loop */
282 for (c = channelOffset; c < channelOffset + numChannelsProcessed; c++) {
283 if (activeDrcIndex == hGainDec->channelGainActiveDrcIndex)
284 pDrcGainBuffers->channelGain[c][lnbPointer] = hGainDec->channelGain[c];
285
286 b = 0;
287 {
288 LINEAR_NODE_BUFFER *pLnb, *pLnbPrevious;
289 NODE_LIN nodePrevious;
290 int lnbPointerDiff;
291 FIXP_DBL channelGain;
292 /* get pointer to oldest linearNodes */
293 lnbIx = lnbPointer + 1 - NUM_LNB_FRAMES;
294 while (lnbIx < 0) lnbIx += NUM_LNB_FRAMES;
295
296 if (activeDrcIndex == hGainDec->channelGainActiveDrcIndex)
297 channelGain = pDrcGainBuffers->channelGain[c][lnbIx];
298 else
299 channelGain = FL2FXCONST_DBL(1.0f / (float)(1 << 8));
300
301 /* Loop over all node buffers in linearNodeBuffer.
302 All nodes which are not relevant for the current frame are sorted out
303 inside _processNodeSegments. */
304 for (i = 0; i < NUM_LNB_FRAMES - 1; i++) {
305 /* Prepare previous node */
306 if (pActiveDrc->lnbIndexForChannel[c][lnbIx] >= 0)
307 pLnbPrevious = &(
308 pLinearNodeBuffer[pActiveDrc->lnbIndexForChannel[c][lnbIx] + b]);
309 else
310 pLnbPrevious = pDummyLnb;
311 nodePrevious =
312 pLnbPrevious->linearNode[lnbIx][pLnbPrevious->nNodes[lnbIx] - 1];
313 nodePrevious.time -= hGainDec->frameSize;
314 if (channelGain != FL2FXCONST_DBL(1.0f / (float)(1 << 8)))
315 nodePrevious.gainLin = SATURATE_LEFT_SHIFT(
316 fMultDiv2(nodePrevious.gainLin,
317 pDrcGainBuffers->channelGain[c][lnbIx]),
318 9, DFRACT_BITS);
319
320 /* Prepare current linearNodeBuffer instance */
321 lnbIx++;
322 if (lnbIx >= NUM_LNB_FRAMES) lnbIx = 0;
323
324 /* if lnbIndexForChannel changes over time, use the old indices for
325 * smooth transitions */
326 if (pActiveDrc->lnbIndexForChannel[c][lnbIx] >= 0)
327 pLnb = &(
328 pLinearNodeBuffer[pActiveDrc->lnbIndexForChannel[c][lnbIx] + b]);
329 else /* lnbIndexForChannel = -1 means "no DRC processing", due to
330 drcInstructionsIndex < 0, drcSetId < 0 or channel group < 0 */
331 pLnb = pDummyLnb;
332
333 if (activeDrcIndex == hGainDec->channelGainActiveDrcIndex)
334 channelGain = pDrcGainBuffers->channelGain[c][lnbIx];
335
336 /* number of frames of offset with respect to lnbPointer */
337 lnbPointerDiff = i - (NUM_LNB_FRAMES - 2);
338
339 err = _processNodeSegments(
340 hGainDec->frameSize, pLnb->gainInterpolationType,
341 pLnb->nNodes[lnbIx], pLnb->linearNode[lnbIx],
342 lnbPointerDiff * hGainDec->frameSize + delaySamples + offset, 1,
343 nodePrevious, channelGain, deinterleavedAudio);
344 if (err) return err;
345 }
346 deinterleavedAudio += timeDataChannelOffset; /* proceed to next channel */
347 }
348 }
349 return DE_OK;
350 }
351
352 /* process DRC on subband-domain signal */
353 DRC_ERROR
processDrcSubband(HANDLE_DRC_GAIN_DECODER hGainDec,const int activeDrcIndex,const int delaySamples,const int channelOffset,const int drcChannelOffset,const int numChannelsProcessed,const int processSingleTimeslot,FIXP_DBL * deinterleavedAudioReal[],FIXP_DBL * deinterleavedAudioImag[])354 processDrcSubband(HANDLE_DRC_GAIN_DECODER hGainDec, const int activeDrcIndex,
355 const int delaySamples, const int channelOffset,
356 const int drcChannelOffset, const int numChannelsProcessed,
357 const int processSingleTimeslot,
358 FIXP_DBL* deinterleavedAudioReal[],
359 FIXP_DBL* deinterleavedAudioImag[]) {
360 DRC_ERROR err = DE_OK;
361 int b, c, g, m, m_start, m_stop, s, i;
362 FIXP_DBL gainSb;
363 DRC_INSTRUCTIONS_UNI_DRC* pInst = hGainDec->activeDrc[activeDrcIndex].pInst;
364 DRC_GAIN_BUFFERS* pDrcGainBuffers = &(hGainDec->drcGainBuffers);
365 ACTIVE_DRC* pActiveDrc = &(hGainDec->activeDrc[activeDrcIndex]);
366 int activeDrcOffset = pActiveDrc->activeDrcOffset;
367 int lnbPointer = pDrcGainBuffers->lnbPointer, lnbIx;
368 LINEAR_NODE_BUFFER* pLinearNodeBuffer = pDrcGainBuffers->linearNodeBuffer;
369 FIXP_DBL(*subbandGains)[4 * 1024 / 256] = hGainDec->subbandGains;
370 FIXP_DBL* dummySubbandGains = hGainDec->dummySubbandGains;
371 SUBBAND_DOMAIN_MODE subbandDomainMode = hGainDec->subbandDomainSupported;
372 int signalIndex = 0;
373 int frameSizeSb = 0;
374 int nDecoderSubbands;
375 SHORT L = 0; /* L: downsampling factor */
376 int offset = 0;
377 FIXP_DBL *audioReal = NULL, *audioImag = NULL;
378
379 if (hGainDec->delayMode == DM_REGULAR_DELAY) {
380 offset = hGainDec->frameSize;
381 }
382
383 if ((delaySamples + offset) >
384 (NUM_LNB_FRAMES - 2) *
385 hGainDec->frameSize) /* if delaySamples is too big, NUM_LNB_FRAMES
386 should be increased */
387 return DE_NOT_OK;
388
389 switch (subbandDomainMode) {
390 #if ((1024 / 256) >= (4096 / SUBBAND_DOWNSAMPLING_FACTOR_QMF64))
391 case SDM_QMF64:
392 nDecoderSubbands = SUBBAND_NUM_BANDS_QMF64;
393 L = SUBBAND_DOWNSAMPLING_FACTOR_QMF64;
394 /* analysisDelay = SUBBAND_ANALYSIS_DELAY_QMF64; */
395 break;
396 case SDM_QMF71:
397 nDecoderSubbands = SUBBAND_NUM_BANDS_QMF71;
398 L = SUBBAND_DOWNSAMPLING_FACTOR_QMF71;
399 /* analysisDelay = SUBBAND_ANALYSIS_DELAY_QMF71; */
400 break;
401 #else
402 case SDM_QMF64:
403 case SDM_QMF71:
404 /* QMF domain processing is not supported. */
405 return DE_NOT_OK;
406 #endif
407 case SDM_STFT256:
408 nDecoderSubbands = SUBBAND_NUM_BANDS_STFT256;
409 L = SUBBAND_DOWNSAMPLING_FACTOR_STFT256;
410 /* analysisDelay = SUBBAND_ANALYSIS_DELAY_STFT256; */
411 break;
412 default:
413 return DE_NOT_OK;
414 }
415
416 /* frameSizeSb = hGainDec->frameSize/L; */ /* L is a power of 2 */
417 frameSizeSb =
418 hGainDec->frameSize >> (15 - fixnormz_S(L)); /* timeslots per frame */
419
420 if ((processSingleTimeslot < 0) || (processSingleTimeslot >= frameSizeSb)) {
421 m_start = 0;
422 m_stop = frameSizeSb;
423 } else {
424 m_start = processSingleTimeslot;
425 m_stop = m_start + 1;
426 }
427
428 err = _prepareLnbIndex(pActiveDrc, channelOffset, drcChannelOffset,
429 numChannelsProcessed, lnbPointer);
430 if (err) return err;
431
432 if (!pActiveDrc->subbandGainsReady) /* only for the first time per frame that
433 processDrcSubband is called */
434 {
435 /* write subbandGains */
436 for (g = 0; g < pInst->nDrcChannelGroups; g++) {
437 b = 0;
438 {
439 LINEAR_NODE_BUFFER* pLnb =
440 &(pLinearNodeBuffer[activeDrcOffset +
441 pActiveDrc->gainElementForGroup[g] + b]);
442 NODE_LIN nodePrevious;
443 int lnbPointerDiff;
444
445 for (m = 0; m < frameSizeSb; m++) {
446 subbandGains[activeDrcOffset + g][b * frameSizeSb + m] =
447 FL2FXCONST_DBL(1.0f / (float)(1 << 7));
448 }
449
450 lnbIx = lnbPointer - (NUM_LNB_FRAMES - 1);
451 while (lnbIx < 0) lnbIx += NUM_LNB_FRAMES;
452
453 /* Loop over all node buffers in linearNodeBuffer.
454 All nodes which are not relevant for the current frame are sorted out
455 inside _processNodeSegments. */
456 for (i = 0; i < NUM_LNB_FRAMES - 1; i++) {
457 /* Prepare previous node */
458 nodePrevious = pLnb->linearNode[lnbIx][pLnb->nNodes[lnbIx] - 1];
459 nodePrevious.time -= hGainDec->frameSize;
460
461 lnbIx++;
462 if (lnbIx >= NUM_LNB_FRAMES) lnbIx = 0;
463
464 /* number of frames of offset with respect to lnbPointer */
465 lnbPointerDiff = i - (NUM_LNB_FRAMES - 2);
466
467 err = _processNodeSegments(
468 hGainDec->frameSize, pLnb->gainInterpolationType,
469 pLnb->nNodes[lnbIx], pLnb->linearNode[lnbIx],
470 lnbPointerDiff * hGainDec->frameSize + delaySamples + offset -
471 (L - 1) / 2,
472 L, nodePrevious, FL2FXCONST_DBL(1.0f / (float)(1 << 8)),
473 &(subbandGains[activeDrcOffset + g][b * frameSizeSb]));
474 if (err) return err;
475 }
476 }
477 }
478 pActiveDrc->subbandGainsReady = 1;
479 }
480
481 for (c = channelOffset; c < channelOffset + numChannelsProcessed; c++) {
482 FIXP_DBL* thisSubbandGainsBuffer;
483 if (pInst->drcSetId > 0)
484 g = pActiveDrc->channelGroupForChannel[c + drcChannelOffset];
485 else
486 g = -1;
487
488 audioReal = deinterleavedAudioReal[signalIndex];
489 if (subbandDomainMode != SDM_STFT256) {
490 audioImag = deinterleavedAudioImag[signalIndex];
491 }
492
493 if ((g >= 0) && !pActiveDrc->channelGroupIsParametricDrc[g]) {
494 thisSubbandGainsBuffer = subbandGains[activeDrcOffset + g];
495 } else {
496 thisSubbandGainsBuffer = dummySubbandGains;
497 }
498
499 for (m = m_start; m < m_stop; m++) {
500 INT n_min = 8;
501 { /* single-band DRC */
502 gainSb = thisSubbandGainsBuffer[m];
503 if (activeDrcIndex == hGainDec->channelGainActiveDrcIndex)
504 gainSb = SATURATE_LEFT_SHIFT(
505 fMultDiv2(gainSb, hGainDec->channelGain[c]), 9, DFRACT_BITS);
506 /* normalize gainSb for keeping signal precision */
507 n_min = fMin(CntLeadingZeros(gainSb) - 1, n_min);
508 gainSb <<= n_min;
509 n_min = 8 - n_min;
510 if (subbandDomainMode ==
511 SDM_STFT256) { /* For STFT filterbank, real and imaginary parts are
512 interleaved. */
513 for (s = 0; s < nDecoderSubbands; s++) {
514 *audioReal = fMultDiv2(*audioReal, gainSb) << n_min;
515 audioReal++;
516 *audioReal = fMultDiv2(*audioReal, gainSb) << n_min;
517 audioReal++;
518 }
519 } else {
520 for (s = 0; s < nDecoderSubbands; s++) {
521 *audioReal = fMultDiv2(*audioReal, gainSb) << n_min;
522 audioReal++;
523 *audioImag = fMultDiv2(*audioImag, gainSb) << n_min;
524 audioImag++;
525 }
526 }
527 }
528 }
529 signalIndex++;
530 }
531 return DE_OK;
532 }
533