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