xref: /aosp_15_r20/external/aac/libSBRdec/src/env_calc.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 - 2021 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 /**************************** SBR 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 /*!
104*e5436536SAndroid Build Coastguard Worker   \file
105*e5436536SAndroid Build Coastguard Worker   \brief  Envelope calculation
106*e5436536SAndroid Build Coastguard Worker 
107*e5436536SAndroid Build Coastguard Worker   The envelope adjustor compares the energies present in the transposed
108*e5436536SAndroid Build Coastguard Worker   highband to the reference energies conveyed with the bitstream.
109*e5436536SAndroid Build Coastguard Worker   The highband is amplified (sometimes) or attenuated (mostly) to the
110*e5436536SAndroid Build Coastguard Worker   desired level.
111*e5436536SAndroid Build Coastguard Worker 
112*e5436536SAndroid Build Coastguard Worker   The spectral shape of the reference energies can be changed several times per
113*e5436536SAndroid Build Coastguard Worker   frame if necessary. Each set of energy values corresponding to a certain range
114*e5436536SAndroid Build Coastguard Worker   in time will be called an <em>envelope</em> here.
115*e5436536SAndroid Build Coastguard Worker   The bitstream supports several frequency scales and two resolutions. Normally,
116*e5436536SAndroid Build Coastguard Worker   one or more QMF-subbands are grouped to one SBR-band. An envelope contains
117*e5436536SAndroid Build Coastguard Worker   reference energies for each SBR-band.
118*e5436536SAndroid Build Coastguard Worker   In addition to the energy envelopes, noise envelopes are transmitted that
119*e5436536SAndroid Build Coastguard Worker   define the ratio of energy which is generated by adding noise instead of
120*e5436536SAndroid Build Coastguard Worker   transposing the lowband. The noise envelopes are given in a coarser time
121*e5436536SAndroid Build Coastguard Worker   and frequency resolution.
122*e5436536SAndroid Build Coastguard Worker   If a signal contains strong tonal components, synthetic sines can be
123*e5436536SAndroid Build Coastguard Worker   generated in individual SBR bands.
124*e5436536SAndroid Build Coastguard Worker 
125*e5436536SAndroid Build Coastguard Worker   An overlap buffer of 6 QMF-timeslots is used to allow a more
126*e5436536SAndroid Build Coastguard Worker   flexible alignment of the envelopes in time that is not restricted to the
127*e5436536SAndroid Build Coastguard Worker   core codec's frame borders.
128*e5436536SAndroid Build Coastguard Worker   Therefore the envelope adjustor has access to the spectral data of the
129*e5436536SAndroid Build Coastguard Worker   current frame as well as the last 6 QMF-timeslots of the previous frame.
130*e5436536SAndroid Build Coastguard Worker   However, in average only the data of 1 frame is being processed as
131*e5436536SAndroid Build Coastguard Worker   the adjustor is called once per frame.
132*e5436536SAndroid Build Coastguard Worker 
133*e5436536SAndroid Build Coastguard Worker   Depending on the frequency range set in the bitstream, only QMF-subbands
134*e5436536SAndroid Build Coastguard Worker   between <em>lowSubband</em> and <em>highSubband</em> are adjusted.
135*e5436536SAndroid Build Coastguard Worker 
136*e5436536SAndroid Build Coastguard Worker   Scaling of spectral data to maximize SNR (see #QMF_SCALE_FACTOR) as well as a
137*e5436536SAndroid Build Coastguard Worker   special Mantissa-Exponent format ( see  calculateSbrEnvelope() ) are being
138*e5436536SAndroid Build Coastguard Worker   used. The main entry point for this modules is calculateSbrEnvelope().
139*e5436536SAndroid Build Coastguard Worker 
140*e5436536SAndroid Build Coastguard Worker   \sa sbr_scale.h, #QMF_SCALE_FACTOR, calculateSbrEnvelope(), \ref
141*e5436536SAndroid Build Coastguard Worker   documentationOverview
142*e5436536SAndroid Build Coastguard Worker */
143*e5436536SAndroid Build Coastguard Worker 
144*e5436536SAndroid Build Coastguard Worker #include "env_calc.h"
145*e5436536SAndroid Build Coastguard Worker 
146*e5436536SAndroid Build Coastguard Worker #include "sbrdec_freq_sca.h"
147*e5436536SAndroid Build Coastguard Worker #include "env_extr.h"
148*e5436536SAndroid Build Coastguard Worker #include "transcendent.h"
149*e5436536SAndroid Build Coastguard Worker #include "sbr_ram.h"
150*e5436536SAndroid Build Coastguard Worker #include "sbr_rom.h"
151*e5436536SAndroid Build Coastguard Worker 
152*e5436536SAndroid Build Coastguard Worker #include "genericStds.h" /* need FDKpow() for debug outputs */
153*e5436536SAndroid Build Coastguard Worker 
154*e5436536SAndroid Build Coastguard Worker #define MAX_SFB_NRG_HEADROOM (1)
155*e5436536SAndroid Build Coastguard Worker #define MAX_VAL_NRG_HEADROOM ((((FIXP_DBL)MAXVAL_DBL) >> MAX_SFB_NRG_HEADROOM))
156*e5436536SAndroid Build Coastguard Worker 
157*e5436536SAndroid Build Coastguard Worker typedef struct {
158*e5436536SAndroid Build Coastguard Worker   FIXP_DBL nrgRef[MAX_FREQ_COEFFS];
159*e5436536SAndroid Build Coastguard Worker   FIXP_DBL nrgEst[MAX_FREQ_COEFFS];
160*e5436536SAndroid Build Coastguard Worker   FIXP_DBL nrgGain[MAX_FREQ_COEFFS];
161*e5436536SAndroid Build Coastguard Worker   FIXP_DBL noiseLevel[MAX_FREQ_COEFFS];
162*e5436536SAndroid Build Coastguard Worker   FIXP_DBL nrgSine[MAX_FREQ_COEFFS];
163*e5436536SAndroid Build Coastguard Worker 
164*e5436536SAndroid Build Coastguard Worker   SCHAR nrgRef_e[MAX_FREQ_COEFFS];
165*e5436536SAndroid Build Coastguard Worker   SCHAR nrgEst_e[MAX_FREQ_COEFFS];
166*e5436536SAndroid Build Coastguard Worker   SCHAR nrgGain_e[MAX_FREQ_COEFFS];
167*e5436536SAndroid Build Coastguard Worker   SCHAR noiseLevel_e[MAX_FREQ_COEFFS];
168*e5436536SAndroid Build Coastguard Worker   SCHAR nrgSine_e[MAX_FREQ_COEFFS];
169*e5436536SAndroid Build Coastguard Worker   /* yet another exponent [0]: for ts < no_cols; [1]: for ts >= no_cols */
170*e5436536SAndroid Build Coastguard Worker   SCHAR exponent[2];
171*e5436536SAndroid Build Coastguard Worker } ENV_CALC_NRGS;
172*e5436536SAndroid Build Coastguard Worker 
173*e5436536SAndroid Build Coastguard Worker static void equalizeFiltBufferExp(FIXP_DBL *filtBuffer, SCHAR *filtBuffer_e,
174*e5436536SAndroid Build Coastguard Worker                                   FIXP_DBL *NrgGain, SCHAR *NrgGain_e,
175*e5436536SAndroid Build Coastguard Worker                                   int subbands);
176*e5436536SAndroid Build Coastguard Worker 
177*e5436536SAndroid Build Coastguard Worker static void calcNrgPerSubband(FIXP_DBL **analysBufferReal,
178*e5436536SAndroid Build Coastguard Worker                               FIXP_DBL **analysBufferImag, int lowSubband,
179*e5436536SAndroid Build Coastguard Worker                               int highSubband, int start_pos, int next_pos,
180*e5436536SAndroid Build Coastguard Worker                               SCHAR frameExp, FIXP_DBL *nrgEst,
181*e5436536SAndroid Build Coastguard Worker                               SCHAR *nrgEst_e);
182*e5436536SAndroid Build Coastguard Worker 
183*e5436536SAndroid Build Coastguard Worker static void calcNrgPerSfb(FIXP_DBL **analysBufferReal,
184*e5436536SAndroid Build Coastguard Worker                           FIXP_DBL **analysBufferImag, int nSfb,
185*e5436536SAndroid Build Coastguard Worker                           UCHAR *freqBandTable, int start_pos, int next_pos,
186*e5436536SAndroid Build Coastguard Worker                           SCHAR input_e, FIXP_DBL *nrg_est, SCHAR *nrg_est_e);
187*e5436536SAndroid Build Coastguard Worker 
188*e5436536SAndroid Build Coastguard Worker static void calcSubbandGain(FIXP_DBL nrgRef, SCHAR nrgRef_e,
189*e5436536SAndroid Build Coastguard Worker                             ENV_CALC_NRGS *nrgs, int c, FIXP_DBL tmpNoise,
190*e5436536SAndroid Build Coastguard Worker                             SCHAR tmpNoise_e, UCHAR sinePresentFlag,
191*e5436536SAndroid Build Coastguard Worker                             UCHAR sineMapped, int noNoiseFlag);
192*e5436536SAndroid Build Coastguard Worker 
193*e5436536SAndroid Build Coastguard Worker static void calcAvgGain(ENV_CALC_NRGS *nrgs, int lowSubband, int highSubband,
194*e5436536SAndroid Build Coastguard Worker                         FIXP_DBL *sumRef_m, SCHAR *sumRef_e,
195*e5436536SAndroid Build Coastguard Worker                         FIXP_DBL *ptrAvgGain_m, SCHAR *ptrAvgGain_e);
196*e5436536SAndroid Build Coastguard Worker 
197*e5436536SAndroid Build Coastguard Worker static void adjustTimeSlot_EldGrid(FIXP_DBL *ptrReal, ENV_CALC_NRGS *nrgs,
198*e5436536SAndroid Build Coastguard Worker                                    UCHAR *ptrHarmIndex, int lowSubbands,
199*e5436536SAndroid Build Coastguard Worker                                    int noSubbands, int scale_change,
200*e5436536SAndroid Build Coastguard Worker                                    int noNoiseFlag, int *ptrPhaseIndex,
201*e5436536SAndroid Build Coastguard Worker                                    int scale_diff_low);
202*e5436536SAndroid Build Coastguard Worker 
203*e5436536SAndroid Build Coastguard Worker static void adjustTimeSlotLC(FIXP_DBL *ptrReal, ENV_CALC_NRGS *nrgs,
204*e5436536SAndroid Build Coastguard Worker                              UCHAR *ptrHarmIndex, int lowSubbands,
205*e5436536SAndroid Build Coastguard Worker                              int noSubbands, int scale_change, int noNoiseFlag,
206*e5436536SAndroid Build Coastguard Worker                              int *ptrPhaseIndex);
207*e5436536SAndroid Build Coastguard Worker 
208*e5436536SAndroid Build Coastguard Worker /**
209*e5436536SAndroid Build Coastguard Worker  * \brief Variant of adjustTimeSlotHQ() which only regards gain and noise but no
210*e5436536SAndroid Build Coastguard Worker  * additional harmonics
211*e5436536SAndroid Build Coastguard Worker  */
212*e5436536SAndroid Build Coastguard Worker static void adjustTimeSlotHQ_GainAndNoise(
213*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *ptrReal, FIXP_DBL *ptrImag,
214*e5436536SAndroid Build Coastguard Worker     HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env, ENV_CALC_NRGS *nrgs,
215*e5436536SAndroid Build Coastguard Worker     int lowSubbands, int noSubbands, int scale_change, FIXP_SGL smooth_ratio,
216*e5436536SAndroid Build Coastguard Worker     int noNoiseFlag, int filtBufferNoiseShift);
217*e5436536SAndroid Build Coastguard Worker /**
218*e5436536SAndroid Build Coastguard Worker  * \brief Variant of adjustTimeSlotHQ() which only adds the additional harmonics
219*e5436536SAndroid Build Coastguard Worker  */
220*e5436536SAndroid Build Coastguard Worker static void adjustTimeSlotHQ_AddHarmonics(
221*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *ptrReal, FIXP_DBL *ptrImag,
222*e5436536SAndroid Build Coastguard Worker     HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env, ENV_CALC_NRGS *nrgs,
223*e5436536SAndroid Build Coastguard Worker     int lowSubbands, int noSubbands, int scale_change);
224*e5436536SAndroid Build Coastguard Worker 
225*e5436536SAndroid Build Coastguard Worker static void adjustTimeSlotHQ(FIXP_DBL *ptrReal, FIXP_DBL *ptrImag,
226*e5436536SAndroid Build Coastguard Worker                              HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env,
227*e5436536SAndroid Build Coastguard Worker                              ENV_CALC_NRGS *nrgs, int lowSubbands,
228*e5436536SAndroid Build Coastguard Worker                              int noSubbands, int scale_change,
229*e5436536SAndroid Build Coastguard Worker                              FIXP_SGL smooth_ratio, int noNoiseFlag,
230*e5436536SAndroid Build Coastguard Worker                              int filtBufferNoiseShift);
231*e5436536SAndroid Build Coastguard Worker 
232*e5436536SAndroid Build Coastguard Worker /*!
233*e5436536SAndroid Build Coastguard Worker   \brief     Map sine flags from bitstream to QMF bands
234*e5436536SAndroid Build Coastguard Worker 
235*e5436536SAndroid Build Coastguard Worker   The bitstream carries only 1 sine flag per band (Sfb) and frame.
236*e5436536SAndroid Build Coastguard Worker   This function maps every sine flag from the bitstream to a specific QMF
237*e5436536SAndroid Build Coastguard Worker   subband and to a specific envelope where the sine shall start. The result is
238*e5436536SAndroid Build Coastguard Worker   stored in the vector sineMapped which contains one entry per QMF subband. The
239*e5436536SAndroid Build Coastguard Worker   value of an entry specifies the envelope where a sine shall start. A value of
240*e5436536SAndroid Build Coastguard Worker   32 indicates that no sine is present in the subband. The missing harmonics
241*e5436536SAndroid Build Coastguard Worker   flags from the previous frame (harmFlagsPrev) determine if a sine starts at
242*e5436536SAndroid Build Coastguard Worker   the beginning of the frame or at the transient position. Additionally, the
243*e5436536SAndroid Build Coastguard Worker   flags in harmFlagsPrev are being updated by this function for the next frame.
244*e5436536SAndroid Build Coastguard Worker */
mapSineFlags(UCHAR * freqBandTable,int nSfb,ULONG * addHarmonics,ULONG * harmFlagsPrev,ULONG * harmFlagsPrevActive,int tranEnv,SCHAR * sineMapped)245*e5436536SAndroid Build Coastguard Worker static void mapSineFlags(
246*e5436536SAndroid Build Coastguard Worker     UCHAR *freqBandTable, /*!< Band borders (there's only 1 flag per band) */
247*e5436536SAndroid Build Coastguard Worker     int nSfb,             /*!< Number of bands in the table */
248*e5436536SAndroid Build Coastguard Worker     ULONG *addHarmonics,  /*!< Packed addHarmonics of current frame (aligned to
249*e5436536SAndroid Build Coastguard Worker                              the MSB) */
250*e5436536SAndroid Build Coastguard Worker     ULONG *harmFlagsPrev, /*!< Packed addHarmonics of previous frame (aligned to
251*e5436536SAndroid Build Coastguard Worker                              the LSB) */
252*e5436536SAndroid Build Coastguard Worker     ULONG *harmFlagsPrevActive, /*!< Packed sineMapped of previous frame
253*e5436536SAndroid Build Coastguard Worker                                    (aligned to the LSB) */
254*e5436536SAndroid Build Coastguard Worker     int tranEnv,                /*!< Transient position */
255*e5436536SAndroid Build Coastguard Worker     SCHAR *sineMapped) /*!< Resulting vector of sine start positions for each
256*e5436536SAndroid Build Coastguard Worker                           QMF band */
257*e5436536SAndroid Build Coastguard Worker 
258*e5436536SAndroid Build Coastguard Worker {
259*e5436536SAndroid Build Coastguard Worker   int i;
260*e5436536SAndroid Build Coastguard Worker   int bitcount = 31;
261*e5436536SAndroid Build Coastguard Worker   ULONG harmFlagsQmfBands[ADD_HARMONICS_FLAGS_SIZE] = {0};
262*e5436536SAndroid Build Coastguard Worker   ULONG *curFlags = addHarmonics;
263*e5436536SAndroid Build Coastguard Worker 
264*e5436536SAndroid Build Coastguard Worker   /*
265*e5436536SAndroid Build Coastguard Worker     Format of addHarmonics (aligned to MSB):
266*e5436536SAndroid Build Coastguard Worker 
267*e5436536SAndroid Build Coastguard Worker       Up to MAX_FREQ_COEFFS sfb bands can be flagged for a sign.
268*e5436536SAndroid Build Coastguard Worker       first word  = flags for lowest 32 sfb bands in use
269*e5436536SAndroid Build Coastguard Worker       second word = flags for higest 32 sfb bands (if present)
270*e5436536SAndroid Build Coastguard Worker 
271*e5436536SAndroid Build Coastguard Worker     Format of harmFlagsPrev (aligned to LSB):
272*e5436536SAndroid Build Coastguard Worker 
273*e5436536SAndroid Build Coastguard Worker       Index is absolute (not relative to lsb) so it is correct even if lsb
274*e5436536SAndroid Build Coastguard Worker     changes first word  = flags for lowest 32 qmf bands (0...31) second word =
275*e5436536SAndroid Build Coastguard Worker     flags for next higher 32 qmf bands (32...63)
276*e5436536SAndroid Build Coastguard Worker 
277*e5436536SAndroid Build Coastguard Worker   */
278*e5436536SAndroid Build Coastguard Worker 
279*e5436536SAndroid Build Coastguard Worker   /* Reset the output vector first */
280*e5436536SAndroid Build Coastguard Worker   FDKmemset(sineMapped, 32,
281*e5436536SAndroid Build Coastguard Worker             MAX_FREQ_COEFFS * sizeof(SCHAR)); /* 32 means 'no sine' */
282*e5436536SAndroid Build Coastguard Worker   FDKmemclear(harmFlagsPrevActive, ADD_HARMONICS_FLAGS_SIZE * sizeof(ULONG));
283*e5436536SAndroid Build Coastguard Worker   for (i = 0; i < nSfb; i++) {
284*e5436536SAndroid Build Coastguard Worker     ULONG maskSfb =
285*e5436536SAndroid Build Coastguard Worker         1 << bitcount; /* mask to extract addHarmonics flag of current Sfb */
286*e5436536SAndroid Build Coastguard Worker 
287*e5436536SAndroid Build Coastguard Worker     if (*curFlags & maskSfb) {          /* There is a sine in this band */
288*e5436536SAndroid Build Coastguard Worker       const int lsb = freqBandTable[0]; /* start of sbr range */
289*e5436536SAndroid Build Coastguard Worker       /* qmf band to which sine should be added */
290*e5436536SAndroid Build Coastguard Worker       const int qmfBand = (freqBandTable[i] + freqBandTable[i + 1]) >> 1;
291*e5436536SAndroid Build Coastguard Worker       const int qmfBandDiv32 = qmfBand >> 5;
292*e5436536SAndroid Build Coastguard Worker       const int maskQmfBand =
293*e5436536SAndroid Build Coastguard Worker           1 << (qmfBand &
294*e5436536SAndroid Build Coastguard Worker                 31); /* mask to extract harmonic flag from prevFlags */
295*e5436536SAndroid Build Coastguard Worker 
296*e5436536SAndroid Build Coastguard Worker       /* mapping of sfb with sine to a certain qmf band -> for harmFlagsPrev */
297*e5436536SAndroid Build Coastguard Worker       harmFlagsQmfBands[qmfBandDiv32] |= maskQmfBand;
298*e5436536SAndroid Build Coastguard Worker 
299*e5436536SAndroid Build Coastguard Worker       /*
300*e5436536SAndroid Build Coastguard Worker         If there was a sine in the last frame, let it continue from the first
301*e5436536SAndroid Build Coastguard Worker         envelope on else start at the transient position. Indexing of sineMapped
302*e5436536SAndroid Build Coastguard Worker         starts relative to lsb.
303*e5436536SAndroid Build Coastguard Worker       */
304*e5436536SAndroid Build Coastguard Worker       sineMapped[qmfBand - lsb] =
305*e5436536SAndroid Build Coastguard Worker           (harmFlagsPrev[qmfBandDiv32] & maskQmfBand) ? 0 : tranEnv;
306*e5436536SAndroid Build Coastguard Worker       if (sineMapped[qmfBand - lsb] < PVC_NTIMESLOT) {
307*e5436536SAndroid Build Coastguard Worker         harmFlagsPrevActive[qmfBandDiv32] |= maskQmfBand;
308*e5436536SAndroid Build Coastguard Worker       }
309*e5436536SAndroid Build Coastguard Worker     }
310*e5436536SAndroid Build Coastguard Worker 
311*e5436536SAndroid Build Coastguard Worker     if (bitcount-- == 0) {
312*e5436536SAndroid Build Coastguard Worker       bitcount = 31;
313*e5436536SAndroid Build Coastguard Worker       curFlags++;
314*e5436536SAndroid Build Coastguard Worker     }
315*e5436536SAndroid Build Coastguard Worker   }
316*e5436536SAndroid Build Coastguard Worker   FDKmemcpy(harmFlagsPrev, harmFlagsQmfBands,
317*e5436536SAndroid Build Coastguard Worker             sizeof(ULONG) * ADD_HARMONICS_FLAGS_SIZE);
318*e5436536SAndroid Build Coastguard Worker }
319*e5436536SAndroid Build Coastguard Worker 
320*e5436536SAndroid Build Coastguard Worker /*!
321*e5436536SAndroid Build Coastguard Worker   \brief     Restore sineMapped of previous frame
322*e5436536SAndroid Build Coastguard Worker 
323*e5436536SAndroid Build Coastguard Worker   For PVC it might happen that the PVC framing (always 0) is out of sync with
324*e5436536SAndroid Build Coastguard Worker   the SBR framing. The adding of additional harmonics is done based on the SBR
325*e5436536SAndroid Build Coastguard Worker   framing. If the SBR framing is trailing the PVC framing the sine mapping of
326*e5436536SAndroid Build Coastguard Worker   the previous SBR frame needs to be used for the overlapping time slots.
327*e5436536SAndroid Build Coastguard Worker */
mapSineFlagsPvc(UCHAR * freqBandTable,int nSfb,ULONG * harmFlagsPrev,ULONG * harmFlagsPrevActive,SCHAR * sineMapped,int sinusoidalPos,SCHAR * sinusoidalPosPrev,int trailingSbrFrame)328*e5436536SAndroid Build Coastguard Worker /*static*/ void mapSineFlagsPvc(
329*e5436536SAndroid Build Coastguard Worker     UCHAR *freqBandTable,       /*!< Band borders (there's only 1 flag per
330*e5436536SAndroid Build Coastguard Worker                                    band) */
331*e5436536SAndroid Build Coastguard Worker     int nSfb,                   /*!< Number of bands in the table */
332*e5436536SAndroid Build Coastguard Worker     ULONG *harmFlagsPrev,       /*!< Packed addHarmonics of previous frame
333*e5436536SAndroid Build Coastguard Worker                                    (aligned to the MSB) */
334*e5436536SAndroid Build Coastguard Worker     ULONG *harmFlagsPrevActive, /*!< Packed sineMapped of previous
335*e5436536SAndroid Build Coastguard Worker                                    frame (aligned to the LSB) */
336*e5436536SAndroid Build Coastguard Worker     SCHAR *sineMapped,          /*!< Resulting vector of sine start positions
337*e5436536SAndroid Build Coastguard Worker                                    for each QMF band */
338*e5436536SAndroid Build Coastguard Worker     int sinusoidalPos,          /*!< sinusoidal position */
339*e5436536SAndroid Build Coastguard Worker     SCHAR *sinusoidalPosPrev,   /*!< sinusoidal position of previous
340*e5436536SAndroid Build Coastguard Worker                                    frame */
341*e5436536SAndroid Build Coastguard Worker     int trailingSbrFrame)       /*!< indication if the SBR framing is
342*e5436536SAndroid Build Coastguard Worker                                    trailing the PVC framing */
343*e5436536SAndroid Build Coastguard Worker {
344*e5436536SAndroid Build Coastguard Worker   /* Reset the output vector first */
345*e5436536SAndroid Build Coastguard Worker   FDKmemset(sineMapped, 32, MAX_FREQ_COEFFS); /* 32 means 'no sine' */
346*e5436536SAndroid Build Coastguard Worker 
347*e5436536SAndroid Build Coastguard Worker   if (trailingSbrFrame) {
348*e5436536SAndroid Build Coastguard Worker     /* restore sineMapped[] of previous frame */
349*e5436536SAndroid Build Coastguard Worker     int i;
350*e5436536SAndroid Build Coastguard Worker     const int lsb = freqBandTable[0];
351*e5436536SAndroid Build Coastguard Worker     const int usb = freqBandTable[nSfb];
352*e5436536SAndroid Build Coastguard Worker     for (i = lsb; i < usb; i++) {
353*e5436536SAndroid Build Coastguard Worker       const int qmfBandDiv32 = i >> 5;
354*e5436536SAndroid Build Coastguard Worker       const int maskQmfBand =
355*e5436536SAndroid Build Coastguard Worker           1 << (i & 31); /* mask to extract harmonic flag from prevFlags */
356*e5436536SAndroid Build Coastguard Worker 
357*e5436536SAndroid Build Coastguard Worker       /* Two cases need to be distinguished ... */
358*e5436536SAndroid Build Coastguard Worker       if (harmFlagsPrevActive[qmfBandDiv32] & maskQmfBand) {
359*e5436536SAndroid Build Coastguard Worker         /* the sine mapping already started last PVC frame -> seamlessly
360*e5436536SAndroid Build Coastguard Worker          * continue */
361*e5436536SAndroid Build Coastguard Worker         sineMapped[i - lsb] = 0;
362*e5436536SAndroid Build Coastguard Worker       } else if (harmFlagsPrev[qmfBandDiv32] & maskQmfBand) {
363*e5436536SAndroid Build Coastguard Worker         /* sinusoidalPos of prev PVC frame was >= PVC_NTIMESLOT -> sine starts
364*e5436536SAndroid Build Coastguard Worker          * in this frame */
365*e5436536SAndroid Build Coastguard Worker         sineMapped[i - lsb] =
366*e5436536SAndroid Build Coastguard Worker             *sinusoidalPosPrev - PVC_NTIMESLOT; /* we are 16 sbr time slots
367*e5436536SAndroid Build Coastguard Worker                                                    ahead of last frame now */
368*e5436536SAndroid Build Coastguard Worker       }
369*e5436536SAndroid Build Coastguard Worker     }
370*e5436536SAndroid Build Coastguard Worker   }
371*e5436536SAndroid Build Coastguard Worker   *sinusoidalPosPrev = sinusoidalPos;
372*e5436536SAndroid Build Coastguard Worker }
373*e5436536SAndroid Build Coastguard Worker 
374*e5436536SAndroid Build Coastguard Worker /*!
375*e5436536SAndroid Build Coastguard Worker   \brief     Reduce gain-adjustment induced aliasing for real valued filterbank.
376*e5436536SAndroid Build Coastguard Worker */
aliasingReduction(FIXP_DBL * degreeAlias,ENV_CALC_NRGS * nrgs,UCHAR * useAliasReduction,int noSubbands)377*e5436536SAndroid Build Coastguard Worker /*static*/ void aliasingReduction(
378*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *degreeAlias, /*!< estimated aliasing for each QMF
379*e5436536SAndroid Build Coastguard Worker                               channel */
380*e5436536SAndroid Build Coastguard Worker     ENV_CALC_NRGS *nrgs,
381*e5436536SAndroid Build Coastguard Worker     UCHAR *useAliasReduction, /*!< synthetic sine energy for each
382*e5436536SAndroid Build Coastguard Worker                                  subband, used as flag */
383*e5436536SAndroid Build Coastguard Worker     int noSubbands)           /*!< number of QMF channels to process */
384*e5436536SAndroid Build Coastguard Worker {
385*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *nrgGain = nrgs->nrgGain; /*!< subband gains to be modified */
386*e5436536SAndroid Build Coastguard Worker   SCHAR *nrgGain_e =
387*e5436536SAndroid Build Coastguard Worker       nrgs->nrgGain_e; /*!< subband gains to be modified (exponents) */
388*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *nrgEst = nrgs->nrgEst; /*!< subband energy before amplification */
389*e5436536SAndroid Build Coastguard Worker   SCHAR *nrgEst_e =
390*e5436536SAndroid Build Coastguard Worker       nrgs->nrgEst_e; /*!< subband energy before amplification (exponents) */
391*e5436536SAndroid Build Coastguard Worker   int grouping = 0, index = 0, noGroups, k;
392*e5436536SAndroid Build Coastguard Worker   int groupVector[MAX_FREQ_COEFFS];
393*e5436536SAndroid Build Coastguard Worker 
394*e5436536SAndroid Build Coastguard Worker   /* Calculate grouping*/
395*e5436536SAndroid Build Coastguard Worker   for (k = 0; k < noSubbands - 1; k++) {
396*e5436536SAndroid Build Coastguard Worker     if ((degreeAlias[k + 1] != FL2FXCONST_DBL(0.0f)) && useAliasReduction[k]) {
397*e5436536SAndroid Build Coastguard Worker       if (grouping == 0) {
398*e5436536SAndroid Build Coastguard Worker         groupVector[index++] = k;
399*e5436536SAndroid Build Coastguard Worker         grouping = 1;
400*e5436536SAndroid Build Coastguard Worker       } else {
401*e5436536SAndroid Build Coastguard Worker         if (groupVector[index - 1] + 3 == k) {
402*e5436536SAndroid Build Coastguard Worker           groupVector[index++] = k + 1;
403*e5436536SAndroid Build Coastguard Worker           grouping = 0;
404*e5436536SAndroid Build Coastguard Worker         }
405*e5436536SAndroid Build Coastguard Worker       }
406*e5436536SAndroid Build Coastguard Worker     } else {
407*e5436536SAndroid Build Coastguard Worker       if (grouping) {
408*e5436536SAndroid Build Coastguard Worker         if (useAliasReduction[k])
409*e5436536SAndroid Build Coastguard Worker           groupVector[index++] = k + 1;
410*e5436536SAndroid Build Coastguard Worker         else
411*e5436536SAndroid Build Coastguard Worker           groupVector[index++] = k;
412*e5436536SAndroid Build Coastguard Worker         grouping = 0;
413*e5436536SAndroid Build Coastguard Worker       }
414*e5436536SAndroid Build Coastguard Worker     }
415*e5436536SAndroid Build Coastguard Worker   }
416*e5436536SAndroid Build Coastguard Worker 
417*e5436536SAndroid Build Coastguard Worker   if (grouping) {
418*e5436536SAndroid Build Coastguard Worker     groupVector[index++] = noSubbands;
419*e5436536SAndroid Build Coastguard Worker   }
420*e5436536SAndroid Build Coastguard Worker   noGroups = index >> 1;
421*e5436536SAndroid Build Coastguard Worker 
422*e5436536SAndroid Build Coastguard Worker   /*Calculate new gain*/
423*e5436536SAndroid Build Coastguard Worker   for (int group = 0; group < noGroups; group++) {
424*e5436536SAndroid Build Coastguard Worker     FIXP_DBL nrgOrig = FL2FXCONST_DBL(
425*e5436536SAndroid Build Coastguard Worker         0.0f); /* Original signal energy in current group of bands */
426*e5436536SAndroid Build Coastguard Worker     SCHAR nrgOrig_e = 0;
427*e5436536SAndroid Build Coastguard Worker     FIXP_DBL nrgAmp = FL2FXCONST_DBL(
428*e5436536SAndroid Build Coastguard Worker         0.0f); /* Amplified signal energy in group (using current gains) */
429*e5436536SAndroid Build Coastguard Worker     SCHAR nrgAmp_e = 0;
430*e5436536SAndroid Build Coastguard Worker     FIXP_DBL nrgMod = FL2FXCONST_DBL(
431*e5436536SAndroid Build Coastguard Worker         0.0f); /* Signal energy in group when applying modified gains */
432*e5436536SAndroid Build Coastguard Worker     SCHAR nrgMod_e = 0;
433*e5436536SAndroid Build Coastguard Worker     FIXP_DBL groupGain; /* Total energy gain in group */
434*e5436536SAndroid Build Coastguard Worker     SCHAR groupGain_e;
435*e5436536SAndroid Build Coastguard Worker     FIXP_DBL compensation; /* Compensation factor for the energy change when
436*e5436536SAndroid Build Coastguard Worker                               applying modified gains */
437*e5436536SAndroid Build Coastguard Worker     SCHAR compensation_e;
438*e5436536SAndroid Build Coastguard Worker 
439*e5436536SAndroid Build Coastguard Worker     int startGroup = groupVector[2 * group];
440*e5436536SAndroid Build Coastguard Worker     int stopGroup = groupVector[2 * group + 1];
441*e5436536SAndroid Build Coastguard Worker 
442*e5436536SAndroid Build Coastguard Worker     /* Calculate total energy in group before and after amplification with
443*e5436536SAndroid Build Coastguard Worker      * current gains: */
444*e5436536SAndroid Build Coastguard Worker     for (k = startGroup; k < stopGroup; k++) {
445*e5436536SAndroid Build Coastguard Worker       /* Get original band energy */
446*e5436536SAndroid Build Coastguard Worker       FIXP_DBL tmp = nrgEst[k];
447*e5436536SAndroid Build Coastguard Worker       SCHAR tmp_e = nrgEst_e[k];
448*e5436536SAndroid Build Coastguard Worker 
449*e5436536SAndroid Build Coastguard Worker       FDK_add_MantExp(tmp, tmp_e, nrgOrig, nrgOrig_e, &nrgOrig, &nrgOrig_e);
450*e5436536SAndroid Build Coastguard Worker 
451*e5436536SAndroid Build Coastguard Worker       /* Multiply band energy with current gain */
452*e5436536SAndroid Build Coastguard Worker       tmp = fMult(tmp, nrgGain[k]);
453*e5436536SAndroid Build Coastguard Worker       tmp_e = tmp_e + nrgGain_e[k];
454*e5436536SAndroid Build Coastguard Worker 
455*e5436536SAndroid Build Coastguard Worker       FDK_add_MantExp(tmp, tmp_e, nrgAmp, nrgAmp_e, &nrgAmp, &nrgAmp_e);
456*e5436536SAndroid Build Coastguard Worker     }
457*e5436536SAndroid Build Coastguard Worker 
458*e5436536SAndroid Build Coastguard Worker     /* Calculate total energy gain in group */
459*e5436536SAndroid Build Coastguard Worker     FDK_divide_MantExp(nrgAmp, nrgAmp_e, nrgOrig, nrgOrig_e, &groupGain,
460*e5436536SAndroid Build Coastguard Worker                        &groupGain_e);
461*e5436536SAndroid Build Coastguard Worker 
462*e5436536SAndroid Build Coastguard Worker     for (k = startGroup; k < stopGroup; k++) {
463*e5436536SAndroid Build Coastguard Worker       FIXP_DBL tmp;
464*e5436536SAndroid Build Coastguard Worker       SCHAR tmp_e;
465*e5436536SAndroid Build Coastguard Worker 
466*e5436536SAndroid Build Coastguard Worker       FIXP_DBL alpha = degreeAlias[k];
467*e5436536SAndroid Build Coastguard Worker       if (k < noSubbands - 1) {
468*e5436536SAndroid Build Coastguard Worker         if (degreeAlias[k + 1] > alpha) alpha = degreeAlias[k + 1];
469*e5436536SAndroid Build Coastguard Worker       }
470*e5436536SAndroid Build Coastguard Worker 
471*e5436536SAndroid Build Coastguard Worker       /* Modify gain depending on the degree of aliasing */
472*e5436536SAndroid Build Coastguard Worker       FDK_add_MantExp(
473*e5436536SAndroid Build Coastguard Worker           fMult(alpha, groupGain), groupGain_e,
474*e5436536SAndroid Build Coastguard Worker           fMult(/*FL2FXCONST_DBL(1.0f)*/ (FIXP_DBL)MAXVAL_DBL - alpha,
475*e5436536SAndroid Build Coastguard Worker                 nrgGain[k]),
476*e5436536SAndroid Build Coastguard Worker           nrgGain_e[k], &nrgGain[k], &nrgGain_e[k]);
477*e5436536SAndroid Build Coastguard Worker 
478*e5436536SAndroid Build Coastguard Worker       /* Apply modified gain to original energy */
479*e5436536SAndroid Build Coastguard Worker       tmp = fMult(nrgGain[k], nrgEst[k]);
480*e5436536SAndroid Build Coastguard Worker       tmp_e = nrgGain_e[k] + nrgEst_e[k];
481*e5436536SAndroid Build Coastguard Worker 
482*e5436536SAndroid Build Coastguard Worker       /* Accumulate energy with modified gains applied */
483*e5436536SAndroid Build Coastguard Worker       FDK_add_MantExp(tmp, tmp_e, nrgMod, nrgMod_e, &nrgMod, &nrgMod_e);
484*e5436536SAndroid Build Coastguard Worker     }
485*e5436536SAndroid Build Coastguard Worker 
486*e5436536SAndroid Build Coastguard Worker     /* Calculate compensation factor to retain the energy of the amplified
487*e5436536SAndroid Build Coastguard Worker      * signal */
488*e5436536SAndroid Build Coastguard Worker     FDK_divide_MantExp(nrgAmp, nrgAmp_e, nrgMod, nrgMod_e, &compensation,
489*e5436536SAndroid Build Coastguard Worker                        &compensation_e);
490*e5436536SAndroid Build Coastguard Worker 
491*e5436536SAndroid Build Coastguard Worker     /* Apply compensation factor to all gains of the group */
492*e5436536SAndroid Build Coastguard Worker     for (k = startGroup; k < stopGroup; k++) {
493*e5436536SAndroid Build Coastguard Worker       nrgGain[k] = fMult(nrgGain[k], compensation);
494*e5436536SAndroid Build Coastguard Worker       nrgGain_e[k] = nrgGain_e[k] + compensation_e;
495*e5436536SAndroid Build Coastguard Worker     }
496*e5436536SAndroid Build Coastguard Worker   }
497*e5436536SAndroid Build Coastguard Worker }
498*e5436536SAndroid Build Coastguard Worker 
499*e5436536SAndroid Build Coastguard Worker #define INTER_TES_SF_CHANGE 4
500*e5436536SAndroid Build Coastguard Worker 
501*e5436536SAndroid Build Coastguard Worker typedef struct {
502*e5436536SAndroid Build Coastguard Worker   FIXP_DBL subsample_power_low[(((1024) / (32) * (4) / 2) + (3 * (4)))];
503*e5436536SAndroid Build Coastguard Worker   FIXP_DBL subsample_power_high[(((1024) / (32) * (4) / 2) + (3 * (4)))];
504*e5436536SAndroid Build Coastguard Worker   FIXP_DBL gain[(((1024) / (32) * (4) / 2) + (3 * (4)))];
505*e5436536SAndroid Build Coastguard Worker   SCHAR subsample_power_low_sf[(((1024) / (32) * (4) / 2) + (3 * (4)))];
506*e5436536SAndroid Build Coastguard Worker   SCHAR subsample_power_high_sf[(((1024) / (32) * (4) / 2) + (3 * (4)))];
507*e5436536SAndroid Build Coastguard Worker } ITES_TEMP;
508*e5436536SAndroid Build Coastguard Worker 
apply_inter_tes(FIXP_DBL ** qmfReal,FIXP_DBL ** qmfImag,const QMF_SCALE_FACTOR * sbrScaleFactor,const SCHAR exp[2],const int RATE,const int startPos,const int stopPos,const int lowSubband,const int nbSubband,const UCHAR gamma_idx)509*e5436536SAndroid Build Coastguard Worker static void apply_inter_tes(FIXP_DBL **qmfReal, FIXP_DBL **qmfImag,
510*e5436536SAndroid Build Coastguard Worker                             const QMF_SCALE_FACTOR *sbrScaleFactor,
511*e5436536SAndroid Build Coastguard Worker                             const SCHAR exp[2], const int RATE,
512*e5436536SAndroid Build Coastguard Worker                             const int startPos, const int stopPos,
513*e5436536SAndroid Build Coastguard Worker                             const int lowSubband, const int nbSubband,
514*e5436536SAndroid Build Coastguard Worker                             const UCHAR gamma_idx) {
515*e5436536SAndroid Build Coastguard Worker   int highSubband = lowSubband + nbSubband;
516*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *subsample_power_high, *subsample_power_low;
517*e5436536SAndroid Build Coastguard Worker   SCHAR *subsample_power_high_sf, *subsample_power_low_sf;
518*e5436536SAndroid Build Coastguard Worker   FIXP_DBL total_power_high = (FIXP_DBL)0;
519*e5436536SAndroid Build Coastguard Worker   FIXP_DBL total_power_low = (FIXP_DBL)0;
520*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *gain;
521*e5436536SAndroid Build Coastguard Worker   int gain_sf[(((1024) / (32) * (4) / 2) + (3 * (4)))];
522*e5436536SAndroid Build Coastguard Worker 
523*e5436536SAndroid Build Coastguard Worker   /* gamma[gamma_idx] = {0.0f, 1.0f, 2.0f, 4.0f} */
524*e5436536SAndroid Build Coastguard Worker   int gamma_sf =
525*e5436536SAndroid Build Coastguard Worker       (int)gamma_idx - 1; /* perhaps +1 to save one bit? (0.99999f vs 1.f) */
526*e5436536SAndroid Build Coastguard Worker 
527*e5436536SAndroid Build Coastguard Worker   int nbSubsample = stopPos - startPos;
528*e5436536SAndroid Build Coastguard Worker   int i, j;
529*e5436536SAndroid Build Coastguard Worker 
530*e5436536SAndroid Build Coastguard Worker   C_ALLOC_SCRATCH_START(pTmp, ITES_TEMP, 1);
531*e5436536SAndroid Build Coastguard Worker   subsample_power_high = pTmp->subsample_power_high;
532*e5436536SAndroid Build Coastguard Worker   subsample_power_low = pTmp->subsample_power_low;
533*e5436536SAndroid Build Coastguard Worker   subsample_power_high_sf = pTmp->subsample_power_high_sf;
534*e5436536SAndroid Build Coastguard Worker   subsample_power_low_sf = pTmp->subsample_power_low_sf;
535*e5436536SAndroid Build Coastguard Worker   gain = pTmp->gain;
536*e5436536SAndroid Build Coastguard Worker 
537*e5436536SAndroid Build Coastguard Worker   if (gamma_idx > 0) {
538*e5436536SAndroid Build Coastguard Worker     int preShift2 = 32 - fNormz((FIXP_DBL)nbSubsample);
539*e5436536SAndroid Build Coastguard Worker     int total_power_low_sf = 1 - DFRACT_BITS;
540*e5436536SAndroid Build Coastguard Worker     int total_power_high_sf = 1 - DFRACT_BITS;
541*e5436536SAndroid Build Coastguard Worker 
542*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < nbSubsample; ++i) {
543*e5436536SAndroid Build Coastguard Worker       FIXP_DBL bufferReal[(((1024) / (32) * (4) / 2) + (3 * (4)))];
544*e5436536SAndroid Build Coastguard Worker       FIXP_DBL bufferImag[(((1024) / (32) * (4) / 2) + (3 * (4)))];
545*e5436536SAndroid Build Coastguard Worker       FIXP_DBL maxVal = (FIXP_DBL)0;
546*e5436536SAndroid Build Coastguard Worker 
547*e5436536SAndroid Build Coastguard Worker       int ts = startPos + i;
548*e5436536SAndroid Build Coastguard Worker 
549*e5436536SAndroid Build Coastguard Worker       int low_sf = (ts < 3 * RATE) ? sbrScaleFactor->ov_lb_scale
550*e5436536SAndroid Build Coastguard Worker                                    : sbrScaleFactor->lb_scale;
551*e5436536SAndroid Build Coastguard Worker       low_sf = 15 - low_sf;
552*e5436536SAndroid Build Coastguard Worker 
553*e5436536SAndroid Build Coastguard Worker       for (j = 0; j < lowSubband; ++j) {
554*e5436536SAndroid Build Coastguard Worker         bufferImag[j] = qmfImag[startPos + i][j];
555*e5436536SAndroid Build Coastguard Worker         maxVal |= (FIXP_DBL)((LONG)(bufferImag[j]) ^
556*e5436536SAndroid Build Coastguard Worker                              ((LONG)bufferImag[j] >> (DFRACT_BITS - 1)));
557*e5436536SAndroid Build Coastguard Worker         bufferReal[j] = qmfReal[startPos + i][j];
558*e5436536SAndroid Build Coastguard Worker         maxVal |= (FIXP_DBL)((LONG)(bufferReal[j]) ^
559*e5436536SAndroid Build Coastguard Worker                              ((LONG)bufferReal[j] >> (DFRACT_BITS - 1)));
560*e5436536SAndroid Build Coastguard Worker       }
561*e5436536SAndroid Build Coastguard Worker 
562*e5436536SAndroid Build Coastguard Worker       subsample_power_low[i] = (FIXP_DBL)0;
563*e5436536SAndroid Build Coastguard Worker       subsample_power_low_sf[i] = 0;
564*e5436536SAndroid Build Coastguard Worker 
565*e5436536SAndroid Build Coastguard Worker       if (maxVal != FL2FXCONST_DBL(0.f)) {
566*e5436536SAndroid Build Coastguard Worker         /* multiply first, then shift for safe summation */
567*e5436536SAndroid Build Coastguard Worker         int preShift = 1 - CntLeadingZeros(maxVal);
568*e5436536SAndroid Build Coastguard Worker         int postShift = 32 - fNormz((FIXP_DBL)lowSubband);
569*e5436536SAndroid Build Coastguard Worker 
570*e5436536SAndroid Build Coastguard Worker         /* reduce preShift because otherwise we risk to square -1.f */
571*e5436536SAndroid Build Coastguard Worker         if (preShift != 0) preShift++;
572*e5436536SAndroid Build Coastguard Worker 
573*e5436536SAndroid Build Coastguard Worker         subsample_power_low_sf[i] += (low_sf + preShift) * 2 + postShift + 1;
574*e5436536SAndroid Build Coastguard Worker 
575*e5436536SAndroid Build Coastguard Worker         scaleValues(bufferReal, lowSubband, -preShift);
576*e5436536SAndroid Build Coastguard Worker         scaleValues(bufferImag, lowSubband, -preShift);
577*e5436536SAndroid Build Coastguard Worker         for (j = 0; j < lowSubband; ++j) {
578*e5436536SAndroid Build Coastguard Worker           FIXP_DBL addme;
579*e5436536SAndroid Build Coastguard Worker           addme = fPow2Div2(bufferReal[j]);
580*e5436536SAndroid Build Coastguard Worker           subsample_power_low[i] += addme >> postShift;
581*e5436536SAndroid Build Coastguard Worker           addme = fPow2Div2(bufferImag[j]);
582*e5436536SAndroid Build Coastguard Worker           subsample_power_low[i] += addme >> postShift;
583*e5436536SAndroid Build Coastguard Worker         }
584*e5436536SAndroid Build Coastguard Worker       }
585*e5436536SAndroid Build Coastguard Worker 
586*e5436536SAndroid Build Coastguard Worker       /* now get high */
587*e5436536SAndroid Build Coastguard Worker 
588*e5436536SAndroid Build Coastguard Worker       maxVal = (FIXP_DBL)0;
589*e5436536SAndroid Build Coastguard Worker 
590*e5436536SAndroid Build Coastguard Worker       int high_sf = exp[(ts < 16 * RATE) ? 0 : 1];
591*e5436536SAndroid Build Coastguard Worker 
592*e5436536SAndroid Build Coastguard Worker       for (j = lowSubband; j < highSubband; ++j) {
593*e5436536SAndroid Build Coastguard Worker         bufferImag[j] = qmfImag[startPos + i][j];
594*e5436536SAndroid Build Coastguard Worker         maxVal |= (FIXP_DBL)((LONG)(bufferImag[j]) ^
595*e5436536SAndroid Build Coastguard Worker                              ((LONG)bufferImag[j] >> (DFRACT_BITS - 1)));
596*e5436536SAndroid Build Coastguard Worker         bufferReal[j] = qmfReal[startPos + i][j];
597*e5436536SAndroid Build Coastguard Worker         maxVal |= (FIXP_DBL)((LONG)(bufferReal[j]) ^
598*e5436536SAndroid Build Coastguard Worker                              ((LONG)bufferReal[j] >> (DFRACT_BITS - 1)));
599*e5436536SAndroid Build Coastguard Worker       }
600*e5436536SAndroid Build Coastguard Worker 
601*e5436536SAndroid Build Coastguard Worker       subsample_power_high[i] = (FIXP_DBL)0;
602*e5436536SAndroid Build Coastguard Worker       subsample_power_high_sf[i] = 0;
603*e5436536SAndroid Build Coastguard Worker 
604*e5436536SAndroid Build Coastguard Worker       if (maxVal != FL2FXCONST_DBL(0.f)) {
605*e5436536SAndroid Build Coastguard Worker         int preShift = 1 - CntLeadingZeros(maxVal);
606*e5436536SAndroid Build Coastguard Worker         /* reduce preShift because otherwise we risk to square -1.f */
607*e5436536SAndroid Build Coastguard Worker         if (preShift != 0) preShift++;
608*e5436536SAndroid Build Coastguard Worker 
609*e5436536SAndroid Build Coastguard Worker         int postShift = 32 - fNormz((FIXP_DBL)(highSubband - lowSubband));
610*e5436536SAndroid Build Coastguard Worker         subsample_power_high_sf[i] += (high_sf + preShift) * 2 + postShift + 1;
611*e5436536SAndroid Build Coastguard Worker 
612*e5436536SAndroid Build Coastguard Worker         scaleValues(&bufferReal[lowSubband], highSubband - lowSubband,
613*e5436536SAndroid Build Coastguard Worker                     -preShift);
614*e5436536SAndroid Build Coastguard Worker         scaleValues(&bufferImag[lowSubband], highSubband - lowSubband,
615*e5436536SAndroid Build Coastguard Worker                     -preShift);
616*e5436536SAndroid Build Coastguard Worker         for (j = lowSubband; j < highSubband; j++) {
617*e5436536SAndroid Build Coastguard Worker           subsample_power_high[i] += fPow2Div2(bufferReal[j]) >> postShift;
618*e5436536SAndroid Build Coastguard Worker           subsample_power_high[i] += fPow2Div2(bufferImag[j]) >> postShift;
619*e5436536SAndroid Build Coastguard Worker         }
620*e5436536SAndroid Build Coastguard Worker       }
621*e5436536SAndroid Build Coastguard Worker 
622*e5436536SAndroid Build Coastguard Worker       /* sum all together */
623*e5436536SAndroid Build Coastguard Worker       FIXP_DBL new_summand = subsample_power_low[i];
624*e5436536SAndroid Build Coastguard Worker       int new_summand_sf = subsample_power_low_sf[i];
625*e5436536SAndroid Build Coastguard Worker 
626*e5436536SAndroid Build Coastguard Worker       /* make sure the current sum, and the new summand have the same SF */
627*e5436536SAndroid Build Coastguard Worker       if (new_summand_sf > total_power_low_sf) {
628*e5436536SAndroid Build Coastguard Worker         int diff = fMin(DFRACT_BITS - 1, new_summand_sf - total_power_low_sf);
629*e5436536SAndroid Build Coastguard Worker         total_power_low >>= diff;
630*e5436536SAndroid Build Coastguard Worker         total_power_low_sf = new_summand_sf;
631*e5436536SAndroid Build Coastguard Worker       } else if (new_summand_sf < total_power_low_sf) {
632*e5436536SAndroid Build Coastguard Worker         new_summand >>=
633*e5436536SAndroid Build Coastguard Worker             fMin(DFRACT_BITS - 1, total_power_low_sf - new_summand_sf);
634*e5436536SAndroid Build Coastguard Worker       }
635*e5436536SAndroid Build Coastguard Worker 
636*e5436536SAndroid Build Coastguard Worker       total_power_low += (new_summand >> preShift2);
637*e5436536SAndroid Build Coastguard Worker 
638*e5436536SAndroid Build Coastguard Worker       new_summand = subsample_power_high[i];
639*e5436536SAndroid Build Coastguard Worker       new_summand_sf = subsample_power_high_sf[i];
640*e5436536SAndroid Build Coastguard Worker       if (new_summand_sf > total_power_high_sf) {
641*e5436536SAndroid Build Coastguard Worker         total_power_high >>=
642*e5436536SAndroid Build Coastguard Worker             fMin(DFRACT_BITS - 1, new_summand_sf - total_power_high_sf);
643*e5436536SAndroid Build Coastguard Worker         total_power_high_sf = new_summand_sf;
644*e5436536SAndroid Build Coastguard Worker       } else if (new_summand_sf < total_power_high_sf) {
645*e5436536SAndroid Build Coastguard Worker         new_summand >>=
646*e5436536SAndroid Build Coastguard Worker             fMin(DFRACT_BITS - 1, total_power_high_sf - new_summand_sf);
647*e5436536SAndroid Build Coastguard Worker       }
648*e5436536SAndroid Build Coastguard Worker 
649*e5436536SAndroid Build Coastguard Worker       total_power_high += (new_summand >> preShift2);
650*e5436536SAndroid Build Coastguard Worker     }
651*e5436536SAndroid Build Coastguard Worker 
652*e5436536SAndroid Build Coastguard Worker     total_power_low_sf += preShift2;
653*e5436536SAndroid Build Coastguard Worker     total_power_high_sf += preShift2;
654*e5436536SAndroid Build Coastguard Worker 
655*e5436536SAndroid Build Coastguard Worker     /* gain[i] = e_LOW[i] */
656*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < nbSubsample; ++i) {
657*e5436536SAndroid Build Coastguard Worker       int sf2;
658*e5436536SAndroid Build Coastguard Worker       FIXP_DBL mult =
659*e5436536SAndroid Build Coastguard Worker           fMultNorm(subsample_power_low[i], (FIXP_DBL)nbSubsample, &sf2);
660*e5436536SAndroid Build Coastguard Worker       int mult_sf = subsample_power_low_sf[i] + DFRACT_BITS - 1 + sf2;
661*e5436536SAndroid Build Coastguard Worker 
662*e5436536SAndroid Build Coastguard Worker       if (total_power_low != FIXP_DBL(0)) {
663*e5436536SAndroid Build Coastguard Worker         gain[i] = fDivNorm(mult, total_power_low, &sf2);
664*e5436536SAndroid Build Coastguard Worker         gain_sf[i] = mult_sf - total_power_low_sf + sf2;
665*e5436536SAndroid Build Coastguard Worker         gain[i] = sqrtFixp_lookup(gain[i], &gain_sf[i]);
666*e5436536SAndroid Build Coastguard Worker         if (gain_sf[i] < 0) {
667*e5436536SAndroid Build Coastguard Worker           gain[i] >>= fMin(DFRACT_BITS - 1, -gain_sf[i]);
668*e5436536SAndroid Build Coastguard Worker           gain_sf[i] = 0;
669*e5436536SAndroid Build Coastguard Worker         }
670*e5436536SAndroid Build Coastguard Worker       } else {
671*e5436536SAndroid Build Coastguard Worker         if (mult == FIXP_DBL(0)) {
672*e5436536SAndroid Build Coastguard Worker           gain[i] = FIXP_DBL(0);
673*e5436536SAndroid Build Coastguard Worker           gain_sf[i] = 0;
674*e5436536SAndroid Build Coastguard Worker         } else {
675*e5436536SAndroid Build Coastguard Worker           gain[i] = (FIXP_DBL)MAXVAL_DBL;
676*e5436536SAndroid Build Coastguard Worker           gain_sf[i] = 0;
677*e5436536SAndroid Build Coastguard Worker         }
678*e5436536SAndroid Build Coastguard Worker       }
679*e5436536SAndroid Build Coastguard Worker     }
680*e5436536SAndroid Build Coastguard Worker 
681*e5436536SAndroid Build Coastguard Worker     FIXP_DBL total_power_high_after = (FIXP_DBL)0;
682*e5436536SAndroid Build Coastguard Worker     int total_power_high_after_sf = 1 - DFRACT_BITS;
683*e5436536SAndroid Build Coastguard Worker 
684*e5436536SAndroid Build Coastguard Worker     /* gain[i] = g_inter[i] */
685*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < nbSubsample; ++i) {
686*e5436536SAndroid Build Coastguard Worker       /* calculate: gain[i] = 1.0f + gamma * (gain[i] - 1.0f); */
687*e5436536SAndroid Build Coastguard Worker       FIXP_DBL one = (FIXP_DBL)MAXVAL_DBL >>
688*e5436536SAndroid Build Coastguard Worker                      gain_sf[i]; /* to substract this from gain[i] */
689*e5436536SAndroid Build Coastguard Worker 
690*e5436536SAndroid Build Coastguard Worker       /* gamma is actually always 1 according to the table, so skip the
691*e5436536SAndroid Build Coastguard Worker        * fMultDiv2 */
692*e5436536SAndroid Build Coastguard Worker       FIXP_DBL mult = (gain[i] - one) >> 1;
693*e5436536SAndroid Build Coastguard Worker       int mult_sf = gain_sf[i] + gamma_sf;
694*e5436536SAndroid Build Coastguard Worker 
695*e5436536SAndroid Build Coastguard Worker       one = FL2FXCONST_DBL(0.5f) >> mult_sf;
696*e5436536SAndroid Build Coastguard Worker       gain[i] = one + mult;
697*e5436536SAndroid Build Coastguard Worker       gain_sf[i] += gamma_sf + 1; /* +1 because of fMultDiv2() */
698*e5436536SAndroid Build Coastguard Worker 
699*e5436536SAndroid Build Coastguard Worker       /* set gain to at least 0.2f */
700*e5436536SAndroid Build Coastguard Worker       /* limit and calculate gain[i]^2 too */
701*e5436536SAndroid Build Coastguard Worker       FIXP_DBL gain_pow2;
702*e5436536SAndroid Build Coastguard Worker       int gain_pow2_sf;
703*e5436536SAndroid Build Coastguard Worker 
704*e5436536SAndroid Build Coastguard Worker       if (fIsLessThan(gain[i], gain_sf[i], FL2FXCONST_DBL(0.2f), 0)) {
705*e5436536SAndroid Build Coastguard Worker         gain[i] = FL2FXCONST_DBL(0.8f);
706*e5436536SAndroid Build Coastguard Worker         gain_sf[i] = -2;
707*e5436536SAndroid Build Coastguard Worker         gain_pow2 = FL2FXCONST_DBL(0.64f);
708*e5436536SAndroid Build Coastguard Worker         gain_pow2_sf = -4;
709*e5436536SAndroid Build Coastguard Worker       } else {
710*e5436536SAndroid Build Coastguard Worker         /* this upscaling seems quite important */
711*e5436536SAndroid Build Coastguard Worker         int r = CountLeadingBits(gain[i]);
712*e5436536SAndroid Build Coastguard Worker         gain[i] <<= r;
713*e5436536SAndroid Build Coastguard Worker         gain_sf[i] -= r;
714*e5436536SAndroid Build Coastguard Worker 
715*e5436536SAndroid Build Coastguard Worker         gain_pow2 = fPow2(gain[i]);
716*e5436536SAndroid Build Coastguard Worker         gain_pow2_sf = gain_sf[i] << 1;
717*e5436536SAndroid Build Coastguard Worker       }
718*e5436536SAndroid Build Coastguard Worker 
719*e5436536SAndroid Build Coastguard Worker       int room;
720*e5436536SAndroid Build Coastguard Worker       subsample_power_high[i] =
721*e5436536SAndroid Build Coastguard Worker           fMultNorm(subsample_power_high[i], gain_pow2, &room);
722*e5436536SAndroid Build Coastguard Worker       subsample_power_high_sf[i] =
723*e5436536SAndroid Build Coastguard Worker           subsample_power_high_sf[i] + gain_pow2_sf + room;
724*e5436536SAndroid Build Coastguard Worker 
725*e5436536SAndroid Build Coastguard Worker       int new_summand_sf = subsample_power_high_sf[i]; /* + gain_pow2_sf; */
726*e5436536SAndroid Build Coastguard Worker       if (new_summand_sf > total_power_high_after_sf) {
727*e5436536SAndroid Build Coastguard Worker         total_power_high_after >>=
728*e5436536SAndroid Build Coastguard Worker             fMin(DFRACT_BITS - 1, new_summand_sf - total_power_high_after_sf);
729*e5436536SAndroid Build Coastguard Worker         total_power_high_after_sf = new_summand_sf;
730*e5436536SAndroid Build Coastguard Worker       } else if (new_summand_sf < total_power_high_after_sf) {
731*e5436536SAndroid Build Coastguard Worker         subsample_power_high[i] >>=
732*e5436536SAndroid Build Coastguard Worker             fMin(DFRACT_BITS - 1, total_power_high_after_sf - new_summand_sf);
733*e5436536SAndroid Build Coastguard Worker       }
734*e5436536SAndroid Build Coastguard Worker       total_power_high_after += subsample_power_high[i] >> preShift2;
735*e5436536SAndroid Build Coastguard Worker     }
736*e5436536SAndroid Build Coastguard Worker 
737*e5436536SAndroid Build Coastguard Worker     total_power_high_after_sf += preShift2;
738*e5436536SAndroid Build Coastguard Worker 
739*e5436536SAndroid Build Coastguard Worker     int sf2 = 0;
740*e5436536SAndroid Build Coastguard Worker     FIXP_DBL gain_adj_2 = FL2FX_DBL(0.5f);
741*e5436536SAndroid Build Coastguard Worker     int gain_adj_2_sf = 1;
742*e5436536SAndroid Build Coastguard Worker 
743*e5436536SAndroid Build Coastguard Worker     if ((total_power_high != (FIXP_DBL)0) &&
744*e5436536SAndroid Build Coastguard Worker         (total_power_high_after != (FIXP_DBL)0)) {
745*e5436536SAndroid Build Coastguard Worker       gain_adj_2 = fDivNorm(total_power_high, total_power_high_after, &sf2);
746*e5436536SAndroid Build Coastguard Worker       gain_adj_2_sf = total_power_high_sf - total_power_high_after_sf + sf2;
747*e5436536SAndroid Build Coastguard Worker     }
748*e5436536SAndroid Build Coastguard Worker 
749*e5436536SAndroid Build Coastguard Worker     FIXP_DBL gain_adj = sqrtFixp_lookup(gain_adj_2, &gain_adj_2_sf);
750*e5436536SAndroid Build Coastguard Worker     int gain_adj_sf = gain_adj_2_sf;
751*e5436536SAndroid Build Coastguard Worker 
752*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < nbSubsample; ++i) {
753*e5436536SAndroid Build Coastguard Worker       int gain_e = fMax(
754*e5436536SAndroid Build Coastguard Worker           fMin(gain_sf[i] + gain_adj_sf - INTER_TES_SF_CHANGE, DFRACT_BITS - 1),
755*e5436536SAndroid Build Coastguard Worker           -(DFRACT_BITS - 1));
756*e5436536SAndroid Build Coastguard Worker       FIXP_DBL gain_final = fMult(gain[i], gain_adj);
757*e5436536SAndroid Build Coastguard Worker       gain_final = scaleValueSaturate(gain_final, gain_e);
758*e5436536SAndroid Build Coastguard Worker 
759*e5436536SAndroid Build Coastguard Worker       for (j = lowSubband; j < highSubband; j++) {
760*e5436536SAndroid Build Coastguard Worker         qmfReal[startPos + i][j] = fMult(qmfReal[startPos + i][j], gain_final);
761*e5436536SAndroid Build Coastguard Worker         qmfImag[startPos + i][j] = fMult(qmfImag[startPos + i][j], gain_final);
762*e5436536SAndroid Build Coastguard Worker       }
763*e5436536SAndroid Build Coastguard Worker     }
764*e5436536SAndroid Build Coastguard Worker   } else { /* gamma_idx == 0 */
765*e5436536SAndroid Build Coastguard Worker     /* Inter-TES is not active. Still perform the scale change to have a
766*e5436536SAndroid Build Coastguard Worker      * consistent scaling for all envelopes of this frame. */
767*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < nbSubsample; ++i) {
768*e5436536SAndroid Build Coastguard Worker       for (j = lowSubband; j < highSubband; j++) {
769*e5436536SAndroid Build Coastguard Worker         qmfReal[startPos + i][j] >>= INTER_TES_SF_CHANGE;
770*e5436536SAndroid Build Coastguard Worker         qmfImag[startPos + i][j] >>= INTER_TES_SF_CHANGE;
771*e5436536SAndroid Build Coastguard Worker       }
772*e5436536SAndroid Build Coastguard Worker     }
773*e5436536SAndroid Build Coastguard Worker   }
774*e5436536SAndroid Build Coastguard Worker   C_ALLOC_SCRATCH_END(pTmp, ITES_TEMP, 1);
775*e5436536SAndroid Build Coastguard Worker }
776*e5436536SAndroid Build Coastguard Worker 
777*e5436536SAndroid Build Coastguard Worker /*!
778*e5436536SAndroid Build Coastguard Worker   \brief  Apply spectral envelope to subband samples
779*e5436536SAndroid Build Coastguard Worker 
780*e5436536SAndroid Build Coastguard Worker   This function is called from sbr_dec.cpp in each frame.
781*e5436536SAndroid Build Coastguard Worker 
782*e5436536SAndroid Build Coastguard Worker   To enhance accuracy and due to the usage of tables for squareroots and
783*e5436536SAndroid Build Coastguard Worker   inverse, some calculations are performed with the operands being split
784*e5436536SAndroid Build Coastguard Worker   into mantissa and exponent. The variable names in the source code carry
785*e5436536SAndroid Build Coastguard Worker   the suffixes <em>_m</em> and  <em>_e</em> respectively. The control data
786*e5436536SAndroid Build Coastguard Worker   in #hFrameData containts envelope data which is represented by this format but
787*e5436536SAndroid Build Coastguard Worker   stored in single words. (See requantizeEnvelopeData() for details). This data
788*e5436536SAndroid Build Coastguard Worker   is unpacked within calculateSbrEnvelope() to follow the described suffix
789*e5436536SAndroid Build Coastguard Worker   convention.
790*e5436536SAndroid Build Coastguard Worker 
791*e5436536SAndroid Build Coastguard Worker   The actual value (comparable to the corresponding float-variable in the
792*e5436536SAndroid Build Coastguard Worker   research-implementation) of a mantissa/exponent-pair can be calculated as
793*e5436536SAndroid Build Coastguard Worker 
794*e5436536SAndroid Build Coastguard Worker   \f$ value = value\_m * 2^{value\_e} \f$
795*e5436536SAndroid Build Coastguard Worker 
796*e5436536SAndroid Build Coastguard Worker   All energies and noise levels decoded from the bitstream suit for an
797*e5436536SAndroid Build Coastguard Worker   original signal magnitude of \f$\pm 32768 \f$ rather than \f$ \pm 1\f$.
798*e5436536SAndroid Build Coastguard Worker   Therefore, the scale factor <em>hb_scale</em> passed into this function will
799*e5436536SAndroid Build Coastguard Worker   be converted to an 'input exponent' (#input_e), which fits the internal
800*e5436536SAndroid Build Coastguard Worker   representation.
801*e5436536SAndroid Build Coastguard Worker 
802*e5436536SAndroid Build Coastguard Worker   Before the actual processing, an exponent #adj_e for resulting adjusted
803*e5436536SAndroid Build Coastguard Worker   samples is derived from the maximum reference energy.
804*e5436536SAndroid Build Coastguard Worker 
805*e5436536SAndroid Build Coastguard Worker   Then, for each envelope, the following steps are performed:
806*e5436536SAndroid Build Coastguard Worker 
807*e5436536SAndroid Build Coastguard Worker   \li Calculate energy in the signal to be adjusted. Depending on the the value
808*e5436536SAndroid Build Coastguard Worker   of #interpolFreq (interpolation mode), this is either done seperately for each
809*e5436536SAndroid Build Coastguard Worker   QMF-subband or for each SBR-band. The resulting energies are stored in
810*e5436536SAndroid Build Coastguard Worker   #nrgEst_m[#MAX_FREQ_COEFFS] (mantissas) and #nrgEst_e[#MAX_FREQ_COEFFS]
811*e5436536SAndroid Build Coastguard Worker   (exponents). \li Calculate gain and noise level for each subband:<br> \f$ gain
812*e5436536SAndroid Build Coastguard Worker   = \sqrt{ \frac{nrgRef}{nrgEst} \cdot (1 - noiseRatio) } \hspace{2cm} noise =
813*e5436536SAndroid Build Coastguard Worker   \sqrt{ nrgRef \cdot noiseRatio } \f$<br> where <em>noiseRatio</em> and
814*e5436536SAndroid Build Coastguard Worker   <em>nrgRef</em> are extracted from the bitstream and <em>nrgEst</em> is the
815*e5436536SAndroid Build Coastguard Worker   subband energy before adjustment. The resulting gains are stored in
816*e5436536SAndroid Build Coastguard Worker   #nrgGain_m[#MAX_FREQ_COEFFS] (mantissas) and #nrgGain_e[#MAX_FREQ_COEFFS]
817*e5436536SAndroid Build Coastguard Worker   (exponents), the noise levels are stored in #noiseLevel_m[#MAX_FREQ_COEFFS]
818*e5436536SAndroid Build Coastguard Worker   and #noiseLevel_e[#MAX_FREQ_COEFFS] (exponents). The sine levels are stored in
819*e5436536SAndroid Build Coastguard Worker   #nrgSine_m[#MAX_FREQ_COEFFS] and #nrgSine_e[#MAX_FREQ_COEFFS]. \li Noise
820*e5436536SAndroid Build Coastguard Worker   limiting: The gain for each subband is limited both absolutely and relatively
821*e5436536SAndroid Build Coastguard Worker   compared to the total gain over all subbands. \li Boost gain: Calculate and
822*e5436536SAndroid Build Coastguard Worker   apply boost factor for each limiter band in order to compensate for the energy
823*e5436536SAndroid Build Coastguard Worker   loss imposed by the limiting. \li Apply gains and add noise: The gains and
824*e5436536SAndroid Build Coastguard Worker   noise levels are applied to all timeslots of the current envelope. A short
825*e5436536SAndroid Build Coastguard Worker   FIR-filter (length 4 QMF-timeslots) can be used to smooth the sudden change at
826*e5436536SAndroid Build Coastguard Worker   the envelope borders. Each complex subband sample of the current timeslot is
827*e5436536SAndroid Build Coastguard Worker   multiplied by the smoothed gain, then random noise with the calculated level
828*e5436536SAndroid Build Coastguard Worker   is added.
829*e5436536SAndroid Build Coastguard Worker 
830*e5436536SAndroid Build Coastguard Worker   \note
831*e5436536SAndroid Build Coastguard Worker   To reduce the stack size, some of the local arrays could be located within
832*e5436536SAndroid Build Coastguard Worker   the time output buffer. Of the 512 samples temporarily available there,
833*e5436536SAndroid Build Coastguard Worker   about half the size is already used by #SBR_FRAME_DATA. A pointer to the
834*e5436536SAndroid Build Coastguard Worker   remaining free memory could be supplied by an additional argument to
835*e5436536SAndroid Build Coastguard Worker   calculateSbrEnvelope() in sbr_dec:
836*e5436536SAndroid Build Coastguard Worker 
837*e5436536SAndroid Build Coastguard Worker   \par
838*e5436536SAndroid Build Coastguard Worker   \code
839*e5436536SAndroid Build Coastguard Worker     calculateSbrEnvelope (&hSbrDec->sbrScaleFactor,
840*e5436536SAndroid Build Coastguard Worker                           &hSbrDec->SbrCalculateEnvelope,
841*e5436536SAndroid Build Coastguard Worker                           hHeaderData,
842*e5436536SAndroid Build Coastguard Worker                           hFrameData,
843*e5436536SAndroid Build Coastguard Worker                           QmfBufferReal,
844*e5436536SAndroid Build Coastguard Worker                           QmfBufferImag,
845*e5436536SAndroid Build Coastguard Worker                           timeOutPtr + sizeof(SBR_FRAME_DATA)/sizeof(Float) +
846*e5436536SAndroid Build Coastguard Worker   1); \endcode
847*e5436536SAndroid Build Coastguard Worker 
848*e5436536SAndroid Build Coastguard Worker   \par
849*e5436536SAndroid Build Coastguard Worker   Within calculateSbrEnvelope(), some pointers could be defined instead of the
850*e5436536SAndroid Build Coastguard Worker   arrays #nrgRef_m, #nrgRef_e, #nrgEst_m, #nrgEst_e, #noiseLevel_m:
851*e5436536SAndroid Build Coastguard Worker 
852*e5436536SAndroid Build Coastguard Worker   \par
853*e5436536SAndroid Build Coastguard Worker   \code
854*e5436536SAndroid Build Coastguard Worker     fract*        nrgRef_m = timeOutPtr;
855*e5436536SAndroid Build Coastguard Worker     SCHAR*        nrgRef_e = nrgRef_m + MAX_FREQ_COEFFS;
856*e5436536SAndroid Build Coastguard Worker     fract*        nrgEst_m = nrgRef_e + MAX_FREQ_COEFFS;
857*e5436536SAndroid Build Coastguard Worker     SCHAR*        nrgEst_e = nrgEst_m + MAX_FREQ_COEFFS;
858*e5436536SAndroid Build Coastguard Worker     fract*        noiseLevel_m = nrgEst_e + MAX_FREQ_COEFFS;
859*e5436536SAndroid Build Coastguard Worker   \endcode
860*e5436536SAndroid Build Coastguard Worker 
861*e5436536SAndroid Build Coastguard Worker   <br>
862*e5436536SAndroid Build Coastguard Worker */
calculateSbrEnvelope(QMF_SCALE_FACTOR * sbrScaleFactor,HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env,HANDLE_SBR_HEADER_DATA hHeaderData,HANDLE_SBR_FRAME_DATA hFrameData,PVC_DYNAMIC_DATA * pPvcDynamicData,FIXP_DBL ** analysBufferReal,FIXP_DBL ** analysBufferImag,const int useLP,FIXP_DBL * degreeAlias,const UINT flags,const int frameErrorFlag)863*e5436536SAndroid Build Coastguard Worker void calculateSbrEnvelope(
864*e5436536SAndroid Build Coastguard Worker     QMF_SCALE_FACTOR *sbrScaleFactor, /*!< Scaling factors */
865*e5436536SAndroid Build Coastguard Worker     HANDLE_SBR_CALCULATE_ENVELOPE
866*e5436536SAndroid Build Coastguard Worker         h_sbr_cal_env, /*!< Handle to struct filled by the create-function */
867*e5436536SAndroid Build Coastguard Worker     HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */
868*e5436536SAndroid Build Coastguard Worker     HANDLE_SBR_FRAME_DATA hFrameData,   /*!< Control data of current frame */
869*e5436536SAndroid Build Coastguard Worker     PVC_DYNAMIC_DATA *pPvcDynamicData,
870*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *
871*e5436536SAndroid Build Coastguard Worker         *analysBufferReal, /*!< Real part of subband samples to be processed */
872*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *
873*e5436536SAndroid Build Coastguard Worker         *analysBufferImag, /*!< Imag part of subband samples to be processed */
874*e5436536SAndroid Build Coastguard Worker     const int useLP,
875*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *degreeAlias, /*!< Estimated aliasing for each QMF channel */
876*e5436536SAndroid Build Coastguard Worker     const UINT flags, const int frameErrorFlag) {
877*e5436536SAndroid Build Coastguard Worker   int c, i, i_stop, j, envNoise = 0;
878*e5436536SAndroid Build Coastguard Worker   UCHAR *borders = hFrameData->frameInfo.borders;
879*e5436536SAndroid Build Coastguard Worker   UCHAR *bordersPvc = hFrameData->frameInfo.pvcBorders;
880*e5436536SAndroid Build Coastguard Worker   int pvc_mode = pPvcDynamicData->pvc_mode;
881*e5436536SAndroid Build Coastguard Worker   int first_start =
882*e5436536SAndroid Build Coastguard Worker       ((pvc_mode > 0) ? bordersPvc[0] : borders[0]) * hHeaderData->timeStep;
883*e5436536SAndroid Build Coastguard Worker   FIXP_SGL *noiseLevels = hFrameData->sbrNoiseFloorLevel;
884*e5436536SAndroid Build Coastguard Worker   HANDLE_FREQ_BAND_DATA hFreq = &hHeaderData->freqBandData;
885*e5436536SAndroid Build Coastguard Worker   UCHAR **pFreqBandTable = hFreq->freqBandTable;
886*e5436536SAndroid Build Coastguard Worker   UCHAR *pFreqBandTableNoise = hFreq->freqBandTableNoise;
887*e5436536SAndroid Build Coastguard Worker 
888*e5436536SAndroid Build Coastguard Worker   int lowSubband = hFreq->lowSubband;
889*e5436536SAndroid Build Coastguard Worker   int highSubband = hFreq->highSubband;
890*e5436536SAndroid Build Coastguard Worker   int noSubbands = highSubband - lowSubband;
891*e5436536SAndroid Build Coastguard Worker 
892*e5436536SAndroid Build Coastguard Worker   /* old high subband before headerchange
893*e5436536SAndroid Build Coastguard Worker      we asume no headerchange here        */
894*e5436536SAndroid Build Coastguard Worker   int ov_highSubband = hFreq->highSubband;
895*e5436536SAndroid Build Coastguard Worker 
896*e5436536SAndroid Build Coastguard Worker   int noNoiseBands = hFreq->nNfb;
897*e5436536SAndroid Build Coastguard Worker   UCHAR *noSubFrameBands = hFreq->nSfb;
898*e5436536SAndroid Build Coastguard Worker   int no_cols = hHeaderData->numberTimeSlots * hHeaderData->timeStep;
899*e5436536SAndroid Build Coastguard Worker 
900*e5436536SAndroid Build Coastguard Worker   SCHAR sineMapped[MAX_FREQ_COEFFS];
901*e5436536SAndroid Build Coastguard Worker   SCHAR ov_adj_e = SCALE2EXP(sbrScaleFactor->ov_hb_scale);
902*e5436536SAndroid Build Coastguard Worker   SCHAR adj_e = 0;
903*e5436536SAndroid Build Coastguard Worker   SCHAR output_e;
904*e5436536SAndroid Build Coastguard Worker   SCHAR final_e = 0;
905*e5436536SAndroid Build Coastguard Worker   /* inter-TES is active in one or more envelopes of the current SBR frame */
906*e5436536SAndroid Build Coastguard Worker   const int iTES_enable = hFrameData->iTESactive;
907*e5436536SAndroid Build Coastguard Worker   const int iTES_scale_change = (iTES_enable) ? INTER_TES_SF_CHANGE : 0;
908*e5436536SAndroid Build Coastguard Worker   SCHAR maxGainLimit_e = (frameErrorFlag) ? MAX_GAIN_CONCEAL_EXP : MAX_GAIN_EXP;
909*e5436536SAndroid Build Coastguard Worker 
910*e5436536SAndroid Build Coastguard Worker   UCHAR smooth_length = 0;
911*e5436536SAndroid Build Coastguard Worker 
912*e5436536SAndroid Build Coastguard Worker   FIXP_SGL *pIenv = hFrameData->iEnvelope;
913*e5436536SAndroid Build Coastguard Worker 
914*e5436536SAndroid Build Coastguard Worker   C_ALLOC_SCRATCH_START(useAliasReduction, UCHAR, 64)
915*e5436536SAndroid Build Coastguard Worker 
916*e5436536SAndroid Build Coastguard Worker   /* if values differ we had a headerchange; if old highband is bigger then new
917*e5436536SAndroid Build Coastguard Worker      one we need to patch overlap-highband-scaling for this frame (see use of
918*e5436536SAndroid Build Coastguard Worker      ov_highSubband) as overlap contains higher frequency components which would
919*e5436536SAndroid Build Coastguard Worker      get lost */
920*e5436536SAndroid Build Coastguard Worker   if (hFreq->highSubband < hFreq->ov_highSubband) {
921*e5436536SAndroid Build Coastguard Worker     ov_highSubband = hFreq->ov_highSubband;
922*e5436536SAndroid Build Coastguard Worker   }
923*e5436536SAndroid Build Coastguard Worker 
924*e5436536SAndroid Build Coastguard Worker   if (pvc_mode > 0) {
925*e5436536SAndroid Build Coastguard Worker     if (hFrameData->frameInfo.bordersNoise[0] > bordersPvc[0]) {
926*e5436536SAndroid Build Coastguard Worker       /* noise envelope of previous frame is trailing into current PVC frame */
927*e5436536SAndroid Build Coastguard Worker       envNoise = -1;
928*e5436536SAndroid Build Coastguard Worker       noiseLevels = h_sbr_cal_env->prevSbrNoiseFloorLevel;
929*e5436536SAndroid Build Coastguard Worker       noNoiseBands = h_sbr_cal_env->prevNNfb;
930*e5436536SAndroid Build Coastguard Worker       noSubFrameBands = h_sbr_cal_env->prevNSfb;
931*e5436536SAndroid Build Coastguard Worker       lowSubband = h_sbr_cal_env->prevLoSubband;
932*e5436536SAndroid Build Coastguard Worker       highSubband = h_sbr_cal_env->prevHiSubband;
933*e5436536SAndroid Build Coastguard Worker 
934*e5436536SAndroid Build Coastguard Worker       noSubbands = highSubband - lowSubband;
935*e5436536SAndroid Build Coastguard Worker       ov_highSubband = highSubband;
936*e5436536SAndroid Build Coastguard Worker       if (highSubband < h_sbr_cal_env->prev_ov_highSubband) {
937*e5436536SAndroid Build Coastguard Worker         ov_highSubband = h_sbr_cal_env->prev_ov_highSubband;
938*e5436536SAndroid Build Coastguard Worker       }
939*e5436536SAndroid Build Coastguard Worker 
940*e5436536SAndroid Build Coastguard Worker       pFreqBandTable[0] = h_sbr_cal_env->prevFreqBandTableLo;
941*e5436536SAndroid Build Coastguard Worker       pFreqBandTable[1] = h_sbr_cal_env->prevFreqBandTableHi;
942*e5436536SAndroid Build Coastguard Worker       pFreqBandTableNoise = h_sbr_cal_env->prevFreqBandTableNoise;
943*e5436536SAndroid Build Coastguard Worker     }
944*e5436536SAndroid Build Coastguard Worker 
945*e5436536SAndroid Build Coastguard Worker     mapSineFlagsPvc(pFreqBandTable[1], noSubFrameBands[1],
946*e5436536SAndroid Build Coastguard Worker                     h_sbr_cal_env->harmFlagsPrev,
947*e5436536SAndroid Build Coastguard Worker                     h_sbr_cal_env->harmFlagsPrevActive, sineMapped,
948*e5436536SAndroid Build Coastguard Worker                     hFrameData->sinusoidal_position,
949*e5436536SAndroid Build Coastguard Worker                     &h_sbr_cal_env->sinusoidal_positionPrev,
950*e5436536SAndroid Build Coastguard Worker                     (borders[0] > bordersPvc[0]) ? 1 : 0);
951*e5436536SAndroid Build Coastguard Worker   } else {
952*e5436536SAndroid Build Coastguard Worker     /*
953*e5436536SAndroid Build Coastguard Worker       Extract sine flags for all QMF bands
954*e5436536SAndroid Build Coastguard Worker     */
955*e5436536SAndroid Build Coastguard Worker     mapSineFlags(pFreqBandTable[1], noSubFrameBands[1],
956*e5436536SAndroid Build Coastguard Worker                  hFrameData->addHarmonics, h_sbr_cal_env->harmFlagsPrev,
957*e5436536SAndroid Build Coastguard Worker                  h_sbr_cal_env->harmFlagsPrevActive,
958*e5436536SAndroid Build Coastguard Worker                  hFrameData->frameInfo.tranEnv, sineMapped);
959*e5436536SAndroid Build Coastguard Worker   }
960*e5436536SAndroid Build Coastguard Worker 
961*e5436536SAndroid Build Coastguard Worker   /*
962*e5436536SAndroid Build Coastguard Worker     Scan for maximum in bufferd noise levels.
963*e5436536SAndroid Build Coastguard Worker     This is needed in case that we had strong noise in the previous frame
964*e5436536SAndroid Build Coastguard Worker     which is smoothed into the current frame.
965*e5436536SAndroid Build Coastguard Worker     The resulting exponent is used as start value for the maximum search
966*e5436536SAndroid Build Coastguard Worker     in reference energies
967*e5436536SAndroid Build Coastguard Worker   */
968*e5436536SAndroid Build Coastguard Worker   if (!useLP)
969*e5436536SAndroid Build Coastguard Worker     adj_e = h_sbr_cal_env->filtBufferNoise_e -
970*e5436536SAndroid Build Coastguard Worker             getScalefactor(h_sbr_cal_env->filtBufferNoise, noSubbands) +
971*e5436536SAndroid Build Coastguard Worker             (INT)MAX_SFB_NRG_HEADROOM;
972*e5436536SAndroid Build Coastguard Worker 
973*e5436536SAndroid Build Coastguard Worker   /*
974*e5436536SAndroid Build Coastguard Worker     Scan for maximum reference energy to be able
975*e5436536SAndroid Build Coastguard Worker     to select appropriate values for adj_e and final_e.
976*e5436536SAndroid Build Coastguard Worker   */
977*e5436536SAndroid Build Coastguard Worker   if (pvc_mode > 0) {
978*e5436536SAndroid Build Coastguard Worker     INT maxSfbNrg_e = pPvcDynamicData->predEsg_expMax;
979*e5436536SAndroid Build Coastguard Worker 
980*e5436536SAndroid Build Coastguard Worker     /* Energy -> magnitude (sqrt halfens exponent) */
981*e5436536SAndroid Build Coastguard Worker     maxSfbNrg_e =
982*e5436536SAndroid Build Coastguard Worker         (maxSfbNrg_e + 1) >> 1; /* +1 to go safe (round to next higher int) */
983*e5436536SAndroid Build Coastguard Worker 
984*e5436536SAndroid Build Coastguard Worker     /* Some safety margin is needed for 2 reasons:
985*e5436536SAndroid Build Coastguard Worker        - The signal energy is not equally spread over all subband samples in
986*e5436536SAndroid Build Coastguard Worker          a specific sfb of an envelope (Nrg could be too high by a factor of
987*e5436536SAndroid Build Coastguard Worker          envWidth * sfbWidth)
988*e5436536SAndroid Build Coastguard Worker        - Smoothing can smear high gains of the previous envelope into the
989*e5436536SAndroid Build Coastguard Worker        current
990*e5436536SAndroid Build Coastguard Worker     */
991*e5436536SAndroid Build Coastguard Worker     maxSfbNrg_e += (6 + MAX_SFB_NRG_HEADROOM);
992*e5436536SAndroid Build Coastguard Worker 
993*e5436536SAndroid Build Coastguard Worker     adj_e = maxSfbNrg_e;
994*e5436536SAndroid Build Coastguard Worker     // final_e should not exist for PVC fixfix framing
995*e5436536SAndroid Build Coastguard Worker   } else {
996*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < hFrameData->frameInfo.nEnvelopes; i++) {
997*e5436536SAndroid Build Coastguard Worker       INT maxSfbNrg_e =
998*e5436536SAndroid Build Coastguard Worker           -FRACT_BITS + NRG_EXP_OFFSET; /* start value for maximum search */
999*e5436536SAndroid Build Coastguard Worker 
1000*e5436536SAndroid Build Coastguard Worker       /* Fetch frequency resolution for current envelope: */
1001*e5436536SAndroid Build Coastguard Worker       for (j = noSubFrameBands[hFrameData->frameInfo.freqRes[i]]; j != 0; j--) {
1002*e5436536SAndroid Build Coastguard Worker         maxSfbNrg_e = fixMax(maxSfbNrg_e, (INT)((LONG)(*pIenv++) & MASK_E));
1003*e5436536SAndroid Build Coastguard Worker       }
1004*e5436536SAndroid Build Coastguard Worker       maxSfbNrg_e -= NRG_EXP_OFFSET;
1005*e5436536SAndroid Build Coastguard Worker 
1006*e5436536SAndroid Build Coastguard Worker       /* Energy -> magnitude (sqrt halfens exponent) */
1007*e5436536SAndroid Build Coastguard Worker       maxSfbNrg_e =
1008*e5436536SAndroid Build Coastguard Worker           (maxSfbNrg_e + 1) >> 1; /* +1 to go safe (round to next higher int) */
1009*e5436536SAndroid Build Coastguard Worker 
1010*e5436536SAndroid Build Coastguard Worker       /* Some safety margin is needed for 2 reasons:
1011*e5436536SAndroid Build Coastguard Worker          - The signal energy is not equally spread over all subband samples in
1012*e5436536SAndroid Build Coastguard Worker            a specific sfb of an envelope (Nrg could be too high by a factor of
1013*e5436536SAndroid Build Coastguard Worker            envWidth * sfbWidth)
1014*e5436536SAndroid Build Coastguard Worker          - Smoothing can smear high gains of the previous envelope into the
1015*e5436536SAndroid Build Coastguard Worker          current
1016*e5436536SAndroid Build Coastguard Worker       */
1017*e5436536SAndroid Build Coastguard Worker       maxSfbNrg_e += (6 + MAX_SFB_NRG_HEADROOM);
1018*e5436536SAndroid Build Coastguard Worker 
1019*e5436536SAndroid Build Coastguard Worker       if (borders[i] < hHeaderData->numberTimeSlots)
1020*e5436536SAndroid Build Coastguard Worker         /* This envelope affects timeslots that belong to the output frame */
1021*e5436536SAndroid Build Coastguard Worker         adj_e = fMax(maxSfbNrg_e, adj_e);
1022*e5436536SAndroid Build Coastguard Worker 
1023*e5436536SAndroid Build Coastguard Worker       if (borders[i + 1] > hHeaderData->numberTimeSlots)
1024*e5436536SAndroid Build Coastguard Worker         /* This envelope affects timeslots after the output frame */
1025*e5436536SAndroid Build Coastguard Worker         final_e = fMax(maxSfbNrg_e, final_e);
1026*e5436536SAndroid Build Coastguard Worker     }
1027*e5436536SAndroid Build Coastguard Worker   }
1028*e5436536SAndroid Build Coastguard Worker   /*
1029*e5436536SAndroid Build Coastguard Worker     Calculate adjustment factors and apply them for every envelope.
1030*e5436536SAndroid Build Coastguard Worker   */
1031*e5436536SAndroid Build Coastguard Worker   pIenv = hFrameData->iEnvelope;
1032*e5436536SAndroid Build Coastguard Worker 
1033*e5436536SAndroid Build Coastguard Worker   if (pvc_mode > 0) {
1034*e5436536SAndroid Build Coastguard Worker     /* iterate over SBR time slots starting with bordersPvc[i] */
1035*e5436536SAndroid Build Coastguard Worker     i = bordersPvc[0]; /* usually 0; can be >0 if switching from legacy SBR to
1036*e5436536SAndroid Build Coastguard Worker                           PVC */
1037*e5436536SAndroid Build Coastguard Worker     i_stop = PVC_NTIMESLOT;
1038*e5436536SAndroid Build Coastguard Worker     FDK_ASSERT(bordersPvc[hFrameData->frameInfo.nEnvelopes] == PVC_NTIMESLOT);
1039*e5436536SAndroid Build Coastguard Worker   } else {
1040*e5436536SAndroid Build Coastguard Worker     /* iterate over SBR envelopes starting with 0 */
1041*e5436536SAndroid Build Coastguard Worker     i = 0;
1042*e5436536SAndroid Build Coastguard Worker     i_stop = hFrameData->frameInfo.nEnvelopes;
1043*e5436536SAndroid Build Coastguard Worker   }
1044*e5436536SAndroid Build Coastguard Worker   for (; i < i_stop; i++) {
1045*e5436536SAndroid Build Coastguard Worker     int k, noNoiseFlag;
1046*e5436536SAndroid Build Coastguard Worker     SCHAR noise_e, input_e = SCALE2EXP(sbrScaleFactor->hb_scale);
1047*e5436536SAndroid Build Coastguard Worker     C_ALLOC_SCRATCH_START(pNrgs, ENV_CALC_NRGS, 1);
1048*e5436536SAndroid Build Coastguard Worker 
1049*e5436536SAndroid Build Coastguard Worker     /*
1050*e5436536SAndroid Build Coastguard Worker       Helper variables.
1051*e5436536SAndroid Build Coastguard Worker     */
1052*e5436536SAndroid Build Coastguard Worker     int start_pos, stop_pos, freq_res;
1053*e5436536SAndroid Build Coastguard Worker     if (pvc_mode > 0) {
1054*e5436536SAndroid Build Coastguard Worker       start_pos =
1055*e5436536SAndroid Build Coastguard Worker           hHeaderData->timeStep *
1056*e5436536SAndroid Build Coastguard Worker           i; /* Start-position in time (subband sample) for current envelope. */
1057*e5436536SAndroid Build Coastguard Worker       stop_pos = hHeaderData->timeStep * (i + 1); /* Stop-position in time
1058*e5436536SAndroid Build Coastguard Worker                                                      (subband sample) for
1059*e5436536SAndroid Build Coastguard Worker                                                      current envelope. */
1060*e5436536SAndroid Build Coastguard Worker       freq_res =
1061*e5436536SAndroid Build Coastguard Worker           hFrameData->frameInfo
1062*e5436536SAndroid Build Coastguard Worker               .freqRes[0]; /* Frequency resolution for current envelope. */
1063*e5436536SAndroid Build Coastguard Worker       FDK_ASSERT(
1064*e5436536SAndroid Build Coastguard Worker           freq_res ==
1065*e5436536SAndroid Build Coastguard Worker           hFrameData->frameInfo.freqRes[hFrameData->frameInfo.nEnvelopes - 1]);
1066*e5436536SAndroid Build Coastguard Worker     } else {
1067*e5436536SAndroid Build Coastguard Worker       start_pos = hHeaderData->timeStep *
1068*e5436536SAndroid Build Coastguard Worker                   borders[i]; /* Start-position in time (subband sample) for
1069*e5436536SAndroid Build Coastguard Worker                                  current envelope. */
1070*e5436536SAndroid Build Coastguard Worker       stop_pos = hHeaderData->timeStep *
1071*e5436536SAndroid Build Coastguard Worker                  borders[i + 1]; /* Stop-position in time (subband sample) for
1072*e5436536SAndroid Build Coastguard Worker                                     current envelope. */
1073*e5436536SAndroid Build Coastguard Worker       freq_res =
1074*e5436536SAndroid Build Coastguard Worker           hFrameData->frameInfo
1075*e5436536SAndroid Build Coastguard Worker               .freqRes[i]; /* Frequency resolution for current envelope. */
1076*e5436536SAndroid Build Coastguard Worker     }
1077*e5436536SAndroid Build Coastguard Worker 
1078*e5436536SAndroid Build Coastguard Worker     /* Always fully initialize the temporary energy table. This prevents
1079*e5436536SAndroid Build Coastguard Worker        negative energies and extreme gain factors in cases where the number of
1080*e5436536SAndroid Build Coastguard Worker        limiter bands exceeds the number of subbands. The latter can be caused by
1081*e5436536SAndroid Build Coastguard Worker        undetected bit errors and is tested by some streams from the
1082*e5436536SAndroid Build Coastguard Worker        certification set. */
1083*e5436536SAndroid Build Coastguard Worker     FDKmemclear(pNrgs, sizeof(ENV_CALC_NRGS));
1084*e5436536SAndroid Build Coastguard Worker 
1085*e5436536SAndroid Build Coastguard Worker     if (pvc_mode > 0) {
1086*e5436536SAndroid Build Coastguard Worker       /* get predicted energy values from PVC module */
1087*e5436536SAndroid Build Coastguard Worker       expandPredEsg(pPvcDynamicData, i, (int)MAX_FREQ_COEFFS, pNrgs->nrgRef,
1088*e5436536SAndroid Build Coastguard Worker                     pNrgs->nrgRef_e);
1089*e5436536SAndroid Build Coastguard Worker 
1090*e5436536SAndroid Build Coastguard Worker       if (i == borders[0]) {
1091*e5436536SAndroid Build Coastguard Worker         mapSineFlags(pFreqBandTable[1], noSubFrameBands[1],
1092*e5436536SAndroid Build Coastguard Worker                      hFrameData->addHarmonics, h_sbr_cal_env->harmFlagsPrev,
1093*e5436536SAndroid Build Coastguard Worker                      h_sbr_cal_env->harmFlagsPrevActive,
1094*e5436536SAndroid Build Coastguard Worker                      hFrameData->sinusoidal_position, sineMapped);
1095*e5436536SAndroid Build Coastguard Worker       }
1096*e5436536SAndroid Build Coastguard Worker 
1097*e5436536SAndroid Build Coastguard Worker       if (i >= hFrameData->frameInfo.bordersNoise[envNoise + 1]) {
1098*e5436536SAndroid Build Coastguard Worker         if (envNoise >= 0) {
1099*e5436536SAndroid Build Coastguard Worker           noiseLevels += noNoiseBands; /* The noise floor data is stored in a
1100*e5436536SAndroid Build Coastguard Worker                                           row [noiseFloor1 noiseFloor2...].*/
1101*e5436536SAndroid Build Coastguard Worker         } else {
1102*e5436536SAndroid Build Coastguard Worker           /* leave trailing noise envelope of past frame */
1103*e5436536SAndroid Build Coastguard Worker           noNoiseBands = hFreq->nNfb;
1104*e5436536SAndroid Build Coastguard Worker           noSubFrameBands = hFreq->nSfb;
1105*e5436536SAndroid Build Coastguard Worker           noiseLevels = hFrameData->sbrNoiseFloorLevel;
1106*e5436536SAndroid Build Coastguard Worker 
1107*e5436536SAndroid Build Coastguard Worker           lowSubband = hFreq->lowSubband;
1108*e5436536SAndroid Build Coastguard Worker           highSubband = hFreq->highSubband;
1109*e5436536SAndroid Build Coastguard Worker 
1110*e5436536SAndroid Build Coastguard Worker           noSubbands = highSubband - lowSubband;
1111*e5436536SAndroid Build Coastguard Worker           ov_highSubband = highSubband;
1112*e5436536SAndroid Build Coastguard Worker           if (highSubband < hFreq->ov_highSubband) {
1113*e5436536SAndroid Build Coastguard Worker             ov_highSubband = hFreq->ov_highSubband;
1114*e5436536SAndroid Build Coastguard Worker           }
1115*e5436536SAndroid Build Coastguard Worker 
1116*e5436536SAndroid Build Coastguard Worker           pFreqBandTable[0] = hFreq->freqBandTableLo;
1117*e5436536SAndroid Build Coastguard Worker           pFreqBandTable[1] = hFreq->freqBandTableHi;
1118*e5436536SAndroid Build Coastguard Worker           pFreqBandTableNoise = hFreq->freqBandTableNoise;
1119*e5436536SAndroid Build Coastguard Worker         }
1120*e5436536SAndroid Build Coastguard Worker         envNoise++;
1121*e5436536SAndroid Build Coastguard Worker       }
1122*e5436536SAndroid Build Coastguard Worker     } else {
1123*e5436536SAndroid Build Coastguard Worker       /* If the start-pos of the current envelope equals the stop pos of the
1124*e5436536SAndroid Build Coastguard Worker          current noise envelope, increase the pointer (i.e. choose the next
1125*e5436536SAndroid Build Coastguard Worker          noise-floor).*/
1126*e5436536SAndroid Build Coastguard Worker       if (borders[i] == hFrameData->frameInfo.bordersNoise[envNoise + 1]) {
1127*e5436536SAndroid Build Coastguard Worker         noiseLevels += noNoiseBands; /* The noise floor data is stored in a row
1128*e5436536SAndroid Build Coastguard Worker                                         [noiseFloor1 noiseFloor2...].*/
1129*e5436536SAndroid Build Coastguard Worker         envNoise++;
1130*e5436536SAndroid Build Coastguard Worker       }
1131*e5436536SAndroid Build Coastguard Worker     }
1132*e5436536SAndroid Build Coastguard Worker     if (i == hFrameData->frameInfo.tranEnv ||
1133*e5436536SAndroid Build Coastguard Worker         i == h_sbr_cal_env->prevTranEnv) /* attack */
1134*e5436536SAndroid Build Coastguard Worker     {
1135*e5436536SAndroid Build Coastguard Worker       noNoiseFlag = 1;
1136*e5436536SAndroid Build Coastguard Worker       if (!useLP) smooth_length = 0; /* No smoothing on attacks! */
1137*e5436536SAndroid Build Coastguard Worker     } else {
1138*e5436536SAndroid Build Coastguard Worker       noNoiseFlag = 0;
1139*e5436536SAndroid Build Coastguard Worker       if (!useLP)
1140*e5436536SAndroid Build Coastguard Worker         smooth_length = (1 - hHeaderData->bs_data.smoothingLength)
1141*e5436536SAndroid Build Coastguard Worker                         << 2; /* can become either 0 or 4 */
1142*e5436536SAndroid Build Coastguard Worker     }
1143*e5436536SAndroid Build Coastguard Worker 
1144*e5436536SAndroid Build Coastguard Worker     /*
1145*e5436536SAndroid Build Coastguard Worker       Energy estimation in transposed highband.
1146*e5436536SAndroid Build Coastguard Worker     */
1147*e5436536SAndroid Build Coastguard Worker     if (hHeaderData->bs_data.interpolFreq)
1148*e5436536SAndroid Build Coastguard Worker       calcNrgPerSubband(analysBufferReal, (useLP) ? NULL : analysBufferImag,
1149*e5436536SAndroid Build Coastguard Worker                         lowSubband, highSubband, start_pos, stop_pos, input_e,
1150*e5436536SAndroid Build Coastguard Worker                         pNrgs->nrgEst, pNrgs->nrgEst_e);
1151*e5436536SAndroid Build Coastguard Worker     else
1152*e5436536SAndroid Build Coastguard Worker       calcNrgPerSfb(analysBufferReal, (useLP) ? NULL : analysBufferImag,
1153*e5436536SAndroid Build Coastguard Worker                     noSubFrameBands[freq_res], pFreqBandTable[freq_res],
1154*e5436536SAndroid Build Coastguard Worker                     start_pos, stop_pos, input_e, pNrgs->nrgEst,
1155*e5436536SAndroid Build Coastguard Worker                     pNrgs->nrgEst_e);
1156*e5436536SAndroid Build Coastguard Worker 
1157*e5436536SAndroid Build Coastguard Worker     /*
1158*e5436536SAndroid Build Coastguard Worker       Calculate subband gains
1159*e5436536SAndroid Build Coastguard Worker     */
1160*e5436536SAndroid Build Coastguard Worker     {
1161*e5436536SAndroid Build Coastguard Worker       UCHAR *table = pFreqBandTable[freq_res];
1162*e5436536SAndroid Build Coastguard Worker       UCHAR *pUiNoise =
1163*e5436536SAndroid Build Coastguard Worker           &pFreqBandTableNoise[1]; /*! Upper limit of the current noise floor
1164*e5436536SAndroid Build Coastguard Worker                                       band. */
1165*e5436536SAndroid Build Coastguard Worker 
1166*e5436536SAndroid Build Coastguard Worker       FIXP_SGL *pNoiseLevels = noiseLevels;
1167*e5436536SAndroid Build Coastguard Worker 
1168*e5436536SAndroid Build Coastguard Worker       FIXP_DBL tmpNoise =
1169*e5436536SAndroid Build Coastguard Worker           FX_SGL2FX_DBL((FIXP_SGL)((LONG)(*pNoiseLevels) & MASK_M));
1170*e5436536SAndroid Build Coastguard Worker       SCHAR tmpNoise_e =
1171*e5436536SAndroid Build Coastguard Worker           (UCHAR)((LONG)(*pNoiseLevels++) & MASK_E) - NOISE_EXP_OFFSET;
1172*e5436536SAndroid Build Coastguard Worker 
1173*e5436536SAndroid Build Coastguard Worker       int cc = 0;
1174*e5436536SAndroid Build Coastguard Worker       c = 0;
1175*e5436536SAndroid Build Coastguard Worker       if (pvc_mode > 0) {
1176*e5436536SAndroid Build Coastguard Worker         for (j = 0; j < noSubFrameBands[freq_res]; j++) {
1177*e5436536SAndroid Build Coastguard Worker           UCHAR sinePresentFlag = 0;
1178*e5436536SAndroid Build Coastguard Worker           int li = table[j];
1179*e5436536SAndroid Build Coastguard Worker           int ui = table[j + 1];
1180*e5436536SAndroid Build Coastguard Worker 
1181*e5436536SAndroid Build Coastguard Worker           for (k = li; k < ui; k++) {
1182*e5436536SAndroid Build Coastguard Worker             sinePresentFlag |= (i >= sineMapped[cc]);
1183*e5436536SAndroid Build Coastguard Worker             cc++;
1184*e5436536SAndroid Build Coastguard Worker           }
1185*e5436536SAndroid Build Coastguard Worker 
1186*e5436536SAndroid Build Coastguard Worker           for (k = li; k < ui; k++) {
1187*e5436536SAndroid Build Coastguard Worker             FIXP_DBL refNrg = pNrgs->nrgRef[k - lowSubband];
1188*e5436536SAndroid Build Coastguard Worker             SCHAR refNrg_e = pNrgs->nrgRef_e[k - lowSubband];
1189*e5436536SAndroid Build Coastguard Worker 
1190*e5436536SAndroid Build Coastguard Worker             if (k >= *pUiNoise) {
1191*e5436536SAndroid Build Coastguard Worker               tmpNoise =
1192*e5436536SAndroid Build Coastguard Worker                   FX_SGL2FX_DBL((FIXP_SGL)((LONG)(*pNoiseLevels) & MASK_M));
1193*e5436536SAndroid Build Coastguard Worker               tmpNoise_e =
1194*e5436536SAndroid Build Coastguard Worker                   (SCHAR)((LONG)(*pNoiseLevels++) & MASK_E) - NOISE_EXP_OFFSET;
1195*e5436536SAndroid Build Coastguard Worker 
1196*e5436536SAndroid Build Coastguard Worker               pUiNoise++;
1197*e5436536SAndroid Build Coastguard Worker             }
1198*e5436536SAndroid Build Coastguard Worker 
1199*e5436536SAndroid Build Coastguard Worker             FDK_ASSERT(k >= lowSubband);
1200*e5436536SAndroid Build Coastguard Worker 
1201*e5436536SAndroid Build Coastguard Worker             if (useLP) useAliasReduction[k - lowSubband] = !sinePresentFlag;
1202*e5436536SAndroid Build Coastguard Worker 
1203*e5436536SAndroid Build Coastguard Worker             pNrgs->nrgSine[c] = FL2FXCONST_DBL(0.0f);
1204*e5436536SAndroid Build Coastguard Worker             pNrgs->nrgSine_e[c] = 0;
1205*e5436536SAndroid Build Coastguard Worker 
1206*e5436536SAndroid Build Coastguard Worker             calcSubbandGain(refNrg, refNrg_e, pNrgs, c, tmpNoise, tmpNoise_e,
1207*e5436536SAndroid Build Coastguard Worker                             sinePresentFlag, i >= sineMapped[c], noNoiseFlag);
1208*e5436536SAndroid Build Coastguard Worker 
1209*e5436536SAndroid Build Coastguard Worker             c++;
1210*e5436536SAndroid Build Coastguard Worker           }
1211*e5436536SAndroid Build Coastguard Worker         }
1212*e5436536SAndroid Build Coastguard Worker       } else {
1213*e5436536SAndroid Build Coastguard Worker         for (j = 0; j < noSubFrameBands[freq_res]; j++) {
1214*e5436536SAndroid Build Coastguard Worker           FIXP_DBL refNrg = FX_SGL2FX_DBL((FIXP_SGL)((LONG)(*pIenv) & MASK_M));
1215*e5436536SAndroid Build Coastguard Worker           SCHAR refNrg_e = (SCHAR)((LONG)(*pIenv) & MASK_E) - NRG_EXP_OFFSET;
1216*e5436536SAndroid Build Coastguard Worker 
1217*e5436536SAndroid Build Coastguard Worker           UCHAR sinePresentFlag = 0;
1218*e5436536SAndroid Build Coastguard Worker           int li = table[j];
1219*e5436536SAndroid Build Coastguard Worker           int ui = table[j + 1];
1220*e5436536SAndroid Build Coastguard Worker 
1221*e5436536SAndroid Build Coastguard Worker           for (k = li; k < ui; k++) {
1222*e5436536SAndroid Build Coastguard Worker             sinePresentFlag |= (i >= sineMapped[cc]);
1223*e5436536SAndroid Build Coastguard Worker             cc++;
1224*e5436536SAndroid Build Coastguard Worker           }
1225*e5436536SAndroid Build Coastguard Worker 
1226*e5436536SAndroid Build Coastguard Worker           for (k = li; k < ui; k++) {
1227*e5436536SAndroid Build Coastguard Worker             if (k >= *pUiNoise) {
1228*e5436536SAndroid Build Coastguard Worker               tmpNoise =
1229*e5436536SAndroid Build Coastguard Worker                   FX_SGL2FX_DBL((FIXP_SGL)((LONG)(*pNoiseLevels) & MASK_M));
1230*e5436536SAndroid Build Coastguard Worker               tmpNoise_e =
1231*e5436536SAndroid Build Coastguard Worker                   (SCHAR)((LONG)(*pNoiseLevels++) & MASK_E) - NOISE_EXP_OFFSET;
1232*e5436536SAndroid Build Coastguard Worker 
1233*e5436536SAndroid Build Coastguard Worker               pUiNoise++;
1234*e5436536SAndroid Build Coastguard Worker             }
1235*e5436536SAndroid Build Coastguard Worker 
1236*e5436536SAndroid Build Coastguard Worker             FDK_ASSERT(k >= lowSubband);
1237*e5436536SAndroid Build Coastguard Worker 
1238*e5436536SAndroid Build Coastguard Worker             if (useLP) useAliasReduction[k - lowSubband] = !sinePresentFlag;
1239*e5436536SAndroid Build Coastguard Worker 
1240*e5436536SAndroid Build Coastguard Worker             pNrgs->nrgSine[c] = FL2FXCONST_DBL(0.0f);
1241*e5436536SAndroid Build Coastguard Worker             pNrgs->nrgSine_e[c] = 0;
1242*e5436536SAndroid Build Coastguard Worker 
1243*e5436536SAndroid Build Coastguard Worker             calcSubbandGain(refNrg, refNrg_e, pNrgs, c, tmpNoise, tmpNoise_e,
1244*e5436536SAndroid Build Coastguard Worker                             sinePresentFlag, i >= sineMapped[c], noNoiseFlag);
1245*e5436536SAndroid Build Coastguard Worker 
1246*e5436536SAndroid Build Coastguard Worker             pNrgs->nrgRef[c] = refNrg;
1247*e5436536SAndroid Build Coastguard Worker             pNrgs->nrgRef_e[c] = refNrg_e;
1248*e5436536SAndroid Build Coastguard Worker 
1249*e5436536SAndroid Build Coastguard Worker             c++;
1250*e5436536SAndroid Build Coastguard Worker           }
1251*e5436536SAndroid Build Coastguard Worker           pIenv++;
1252*e5436536SAndroid Build Coastguard Worker         }
1253*e5436536SAndroid Build Coastguard Worker       }
1254*e5436536SAndroid Build Coastguard Worker     }
1255*e5436536SAndroid Build Coastguard Worker 
1256*e5436536SAndroid Build Coastguard Worker     /*
1257*e5436536SAndroid Build Coastguard Worker       Noise limiting
1258*e5436536SAndroid Build Coastguard Worker     */
1259*e5436536SAndroid Build Coastguard Worker 
1260*e5436536SAndroid Build Coastguard Worker     for (c = 0; c < hFreq->noLimiterBands; c++) {
1261*e5436536SAndroid Build Coastguard Worker       FIXP_DBL sumRef, boostGain, maxGain;
1262*e5436536SAndroid Build Coastguard Worker       FIXP_DBL accu = FL2FXCONST_DBL(0.0f);
1263*e5436536SAndroid Build Coastguard Worker       SCHAR sumRef_e, boostGain_e, maxGain_e, accu_e = 0;
1264*e5436536SAndroid Build Coastguard Worker       int maxGainLimGainSum_e = 0;
1265*e5436536SAndroid Build Coastguard Worker 
1266*e5436536SAndroid Build Coastguard Worker       calcAvgGain(pNrgs, hFreq->limiterBandTable[c],
1267*e5436536SAndroid Build Coastguard Worker                   hFreq->limiterBandTable[c + 1], &sumRef, &sumRef_e, &maxGain,
1268*e5436536SAndroid Build Coastguard Worker                   &maxGain_e);
1269*e5436536SAndroid Build Coastguard Worker 
1270*e5436536SAndroid Build Coastguard Worker       /* Multiply maxGain with limiterGain: */
1271*e5436536SAndroid Build Coastguard Worker       maxGain = fMult(
1272*e5436536SAndroid Build Coastguard Worker           maxGain,
1273*e5436536SAndroid Build Coastguard Worker           FDK_sbrDecoder_sbr_limGains_m[hHeaderData->bs_data.limiterGains]);
1274*e5436536SAndroid Build Coastguard Worker       /* maxGain_e +=
1275*e5436536SAndroid Build Coastguard Worker        * FDK_sbrDecoder_sbr_limGains_e[hHeaderData->bs_data.limiterGains]; */
1276*e5436536SAndroid Build Coastguard Worker       /* The addition of maxGain_e and FDK_sbrDecoder_sbr_limGains_e[3] might
1277*e5436536SAndroid Build Coastguard Worker          yield values greater than 127 which doesn't fit into an SCHAR! In these
1278*e5436536SAndroid Build Coastguard Worker          rare situations limit maxGain_e to 127.
1279*e5436536SAndroid Build Coastguard Worker       */
1280*e5436536SAndroid Build Coastguard Worker       maxGainLimGainSum_e =
1281*e5436536SAndroid Build Coastguard Worker           maxGain_e +
1282*e5436536SAndroid Build Coastguard Worker           FDK_sbrDecoder_sbr_limGains_e[hHeaderData->bs_data.limiterGains];
1283*e5436536SAndroid Build Coastguard Worker       maxGain_e =
1284*e5436536SAndroid Build Coastguard Worker           (maxGainLimGainSum_e > 127) ? (SCHAR)127 : (SCHAR)maxGainLimGainSum_e;
1285*e5436536SAndroid Build Coastguard Worker 
1286*e5436536SAndroid Build Coastguard Worker       /* Scale mantissa of MaxGain into range between 0.5 and 1: */
1287*e5436536SAndroid Build Coastguard Worker       if (maxGain == FL2FXCONST_DBL(0.0f))
1288*e5436536SAndroid Build Coastguard Worker         maxGain_e = -FRACT_BITS;
1289*e5436536SAndroid Build Coastguard Worker       else {
1290*e5436536SAndroid Build Coastguard Worker         SCHAR charTemp = CountLeadingBits(maxGain);
1291*e5436536SAndroid Build Coastguard Worker         maxGain_e -= charTemp;
1292*e5436536SAndroid Build Coastguard Worker         maxGain <<= (int)charTemp;
1293*e5436536SAndroid Build Coastguard Worker       }
1294*e5436536SAndroid Build Coastguard Worker 
1295*e5436536SAndroid Build Coastguard Worker       if (maxGain_e >= maxGainLimit_e) { /* upper limit (e.g. 96 dB) */
1296*e5436536SAndroid Build Coastguard Worker         maxGain = FL2FXCONST_DBL(0.5f);
1297*e5436536SAndroid Build Coastguard Worker         maxGain_e = maxGainLimit_e;
1298*e5436536SAndroid Build Coastguard Worker       }
1299*e5436536SAndroid Build Coastguard Worker 
1300*e5436536SAndroid Build Coastguard Worker       /* Every subband gain is compared to the scaled "average gain"
1301*e5436536SAndroid Build Coastguard Worker          and limited if necessary: */
1302*e5436536SAndroid Build Coastguard Worker       for (k = hFreq->limiterBandTable[c]; k < hFreq->limiterBandTable[c + 1];
1303*e5436536SAndroid Build Coastguard Worker            k++) {
1304*e5436536SAndroid Build Coastguard Worker         if ((pNrgs->nrgGain_e[k] > maxGain_e) ||
1305*e5436536SAndroid Build Coastguard Worker             (pNrgs->nrgGain_e[k] == maxGain_e && pNrgs->nrgGain[k] > maxGain)) {
1306*e5436536SAndroid Build Coastguard Worker           FIXP_DBL noiseAmp;
1307*e5436536SAndroid Build Coastguard Worker           SCHAR noiseAmp_e;
1308*e5436536SAndroid Build Coastguard Worker 
1309*e5436536SAndroid Build Coastguard Worker           FDK_divide_MantExp(maxGain, maxGain_e, pNrgs->nrgGain[k],
1310*e5436536SAndroid Build Coastguard Worker                              pNrgs->nrgGain_e[k], &noiseAmp, &noiseAmp_e);
1311*e5436536SAndroid Build Coastguard Worker           pNrgs->noiseLevel[k] = fMult(pNrgs->noiseLevel[k], noiseAmp);
1312*e5436536SAndroid Build Coastguard Worker           pNrgs->noiseLevel_e[k] += noiseAmp_e;
1313*e5436536SAndroid Build Coastguard Worker           pNrgs->nrgGain[k] = maxGain;
1314*e5436536SAndroid Build Coastguard Worker           pNrgs->nrgGain_e[k] = maxGain_e;
1315*e5436536SAndroid Build Coastguard Worker         }
1316*e5436536SAndroid Build Coastguard Worker       }
1317*e5436536SAndroid Build Coastguard Worker 
1318*e5436536SAndroid Build Coastguard Worker       /* -- Boost gain
1319*e5436536SAndroid Build Coastguard Worker         Calculate and apply boost factor for each limiter band:
1320*e5436536SAndroid Build Coastguard Worker         1. Check how much energy would be present when using the limited gain
1321*e5436536SAndroid Build Coastguard Worker         2. Calculate boost factor by comparison with reference energy
1322*e5436536SAndroid Build Coastguard Worker         3. Apply boost factor to compensate for the energy loss due to limiting
1323*e5436536SAndroid Build Coastguard Worker       */
1324*e5436536SAndroid Build Coastguard Worker       for (k = hFreq->limiterBandTable[c]; k < hFreq->limiterBandTable[c + 1];
1325*e5436536SAndroid Build Coastguard Worker            k++) {
1326*e5436536SAndroid Build Coastguard Worker         /* 1.a  Add energy of adjusted signal (using preliminary gain) */
1327*e5436536SAndroid Build Coastguard Worker         FIXP_DBL tmp = fMult(pNrgs->nrgGain[k], pNrgs->nrgEst[k]);
1328*e5436536SAndroid Build Coastguard Worker         SCHAR tmp_e = pNrgs->nrgGain_e[k] + pNrgs->nrgEst_e[k];
1329*e5436536SAndroid Build Coastguard Worker         FDK_add_MantExp(tmp, tmp_e, accu, accu_e, &accu, &accu_e);
1330*e5436536SAndroid Build Coastguard Worker 
1331*e5436536SAndroid Build Coastguard Worker         /* 1.b  Add sine energy (if present) */
1332*e5436536SAndroid Build Coastguard Worker         if (pNrgs->nrgSine[k] != FL2FXCONST_DBL(0.0f)) {
1333*e5436536SAndroid Build Coastguard Worker           FDK_add_MantExp(pNrgs->nrgSine[k], pNrgs->nrgSine_e[k], accu, accu_e,
1334*e5436536SAndroid Build Coastguard Worker                           &accu, &accu_e);
1335*e5436536SAndroid Build Coastguard Worker         } else {
1336*e5436536SAndroid Build Coastguard Worker           /* 1.c  Add noise energy (if present) */
1337*e5436536SAndroid Build Coastguard Worker           if (noNoiseFlag == 0) {
1338*e5436536SAndroid Build Coastguard Worker             FDK_add_MantExp(pNrgs->noiseLevel[k], pNrgs->noiseLevel_e[k], accu,
1339*e5436536SAndroid Build Coastguard Worker                             accu_e, &accu, &accu_e);
1340*e5436536SAndroid Build Coastguard Worker           }
1341*e5436536SAndroid Build Coastguard Worker         }
1342*e5436536SAndroid Build Coastguard Worker       }
1343*e5436536SAndroid Build Coastguard Worker 
1344*e5436536SAndroid Build Coastguard Worker       /* 2.a  Calculate ratio of wanted energy and accumulated energy */
1345*e5436536SAndroid Build Coastguard Worker       if (accu == (FIXP_DBL)0) { /* If divisor is 0, limit quotient to +4 dB */
1346*e5436536SAndroid Build Coastguard Worker         boostGain = FL2FXCONST_DBL(0.6279716f);
1347*e5436536SAndroid Build Coastguard Worker         boostGain_e = 2;
1348*e5436536SAndroid Build Coastguard Worker       } else {
1349*e5436536SAndroid Build Coastguard Worker         INT div_e;
1350*e5436536SAndroid Build Coastguard Worker         boostGain = fDivNorm(sumRef, accu, &div_e);
1351*e5436536SAndroid Build Coastguard Worker         boostGain_e = sumRef_e - accu_e + div_e;
1352*e5436536SAndroid Build Coastguard Worker       }
1353*e5436536SAndroid Build Coastguard Worker 
1354*e5436536SAndroid Build Coastguard Worker       /* 2.b Result too high? --> Limit the boost factor to +4 dB */
1355*e5436536SAndroid Build Coastguard Worker       if ((boostGain_e > 3) ||
1356*e5436536SAndroid Build Coastguard Worker           (boostGain_e == 2 && boostGain > FL2FXCONST_DBL(0.6279716f)) ||
1357*e5436536SAndroid Build Coastguard Worker           (boostGain_e == 3 && boostGain > FL2FXCONST_DBL(0.3139858f))) {
1358*e5436536SAndroid Build Coastguard Worker         boostGain = FL2FXCONST_DBL(0.6279716f);
1359*e5436536SAndroid Build Coastguard Worker         boostGain_e = 2;
1360*e5436536SAndroid Build Coastguard Worker       }
1361*e5436536SAndroid Build Coastguard Worker       /* 3.  Multiply all signal components with the boost factor */
1362*e5436536SAndroid Build Coastguard Worker       for (k = hFreq->limiterBandTable[c]; k < hFreq->limiterBandTable[c + 1];
1363*e5436536SAndroid Build Coastguard Worker            k++) {
1364*e5436536SAndroid Build Coastguard Worker         pNrgs->nrgGain[k] = fMultDiv2(pNrgs->nrgGain[k], boostGain);
1365*e5436536SAndroid Build Coastguard Worker         pNrgs->nrgGain_e[k] = pNrgs->nrgGain_e[k] + boostGain_e + 1;
1366*e5436536SAndroid Build Coastguard Worker 
1367*e5436536SAndroid Build Coastguard Worker         pNrgs->nrgSine[k] = fMultDiv2(pNrgs->nrgSine[k], boostGain);
1368*e5436536SAndroid Build Coastguard Worker         pNrgs->nrgSine_e[k] = pNrgs->nrgSine_e[k] + boostGain_e + 1;
1369*e5436536SAndroid Build Coastguard Worker 
1370*e5436536SAndroid Build Coastguard Worker         pNrgs->noiseLevel[k] = fMultDiv2(pNrgs->noiseLevel[k], boostGain);
1371*e5436536SAndroid Build Coastguard Worker         pNrgs->noiseLevel_e[k] = pNrgs->noiseLevel_e[k] + boostGain_e + 1;
1372*e5436536SAndroid Build Coastguard Worker       }
1373*e5436536SAndroid Build Coastguard Worker     }
1374*e5436536SAndroid Build Coastguard Worker     /* End of noise limiting */
1375*e5436536SAndroid Build Coastguard Worker 
1376*e5436536SAndroid Build Coastguard Worker     if (useLP)
1377*e5436536SAndroid Build Coastguard Worker       aliasingReduction(degreeAlias + lowSubband, pNrgs, useAliasReduction,
1378*e5436536SAndroid Build Coastguard Worker                         noSubbands);
1379*e5436536SAndroid Build Coastguard Worker 
1380*e5436536SAndroid Build Coastguard Worker     /* For the timeslots within the range for the output frame,
1381*e5436536SAndroid Build Coastguard Worker        use the same scale for the noise levels.
1382*e5436536SAndroid Build Coastguard Worker        Drawback: If the envelope exceeds the frame border, the noise levels
1383*e5436536SAndroid Build Coastguard Worker                  will have to be rescaled later to fit final_e of
1384*e5436536SAndroid Build Coastguard Worker                  the gain-values.
1385*e5436536SAndroid Build Coastguard Worker     */
1386*e5436536SAndroid Build Coastguard Worker     noise_e = (start_pos < no_cols) ? adj_e : final_e;
1387*e5436536SAndroid Build Coastguard Worker 
1388*e5436536SAndroid Build Coastguard Worker     if (start_pos >= no_cols) {
1389*e5436536SAndroid Build Coastguard Worker       int diff = h_sbr_cal_env->filtBufferNoise_e - noise_e;
1390*e5436536SAndroid Build Coastguard Worker       if (diff > 0) {
1391*e5436536SAndroid Build Coastguard Worker         int s = getScalefactor(h_sbr_cal_env->filtBufferNoise, noSubbands);
1392*e5436536SAndroid Build Coastguard Worker         if (diff > s) {
1393*e5436536SAndroid Build Coastguard Worker           final_e += diff - s;
1394*e5436536SAndroid Build Coastguard Worker           noise_e = final_e;
1395*e5436536SAndroid Build Coastguard Worker         }
1396*e5436536SAndroid Build Coastguard Worker       }
1397*e5436536SAndroid Build Coastguard Worker     }
1398*e5436536SAndroid Build Coastguard Worker 
1399*e5436536SAndroid Build Coastguard Worker     /*
1400*e5436536SAndroid Build Coastguard Worker       Convert energies to amplitude levels
1401*e5436536SAndroid Build Coastguard Worker     */
1402*e5436536SAndroid Build Coastguard Worker     for (k = 0; k < noSubbands; k++) {
1403*e5436536SAndroid Build Coastguard Worker       FDK_sqrt_MantExp(&pNrgs->nrgSine[k], &pNrgs->nrgSine_e[k], &noise_e);
1404*e5436536SAndroid Build Coastguard Worker       FDK_sqrt_MantExp(&pNrgs->nrgGain[k], &pNrgs->nrgGain_e[k],
1405*e5436536SAndroid Build Coastguard Worker                        &pNrgs->nrgGain_e[k]);
1406*e5436536SAndroid Build Coastguard Worker       FDK_sqrt_MantExp(&pNrgs->noiseLevel[k], &pNrgs->noiseLevel_e[k],
1407*e5436536SAndroid Build Coastguard Worker                        &noise_e);
1408*e5436536SAndroid Build Coastguard Worker     }
1409*e5436536SAndroid Build Coastguard Worker 
1410*e5436536SAndroid Build Coastguard Worker     /*
1411*e5436536SAndroid Build Coastguard Worker       Apply calculated gains and adaptive noise
1412*e5436536SAndroid Build Coastguard Worker     */
1413*e5436536SAndroid Build Coastguard Worker 
1414*e5436536SAndroid Build Coastguard Worker     /* assembleHfSignals() */
1415*e5436536SAndroid Build Coastguard Worker     {
1416*e5436536SAndroid Build Coastguard Worker       int scale_change, sc_change;
1417*e5436536SAndroid Build Coastguard Worker       FIXP_SGL smooth_ratio;
1418*e5436536SAndroid Build Coastguard Worker       int filtBufferNoiseShift = 0;
1419*e5436536SAndroid Build Coastguard Worker 
1420*e5436536SAndroid Build Coastguard Worker       /* Initialize smoothing buffers with the first valid values */
1421*e5436536SAndroid Build Coastguard Worker       if (h_sbr_cal_env->startUp) {
1422*e5436536SAndroid Build Coastguard Worker         if (!useLP) {
1423*e5436536SAndroid Build Coastguard Worker           h_sbr_cal_env->filtBufferNoise_e = noise_e;
1424*e5436536SAndroid Build Coastguard Worker 
1425*e5436536SAndroid Build Coastguard Worker           FDKmemcpy(h_sbr_cal_env->filtBuffer_e, pNrgs->nrgGain_e,
1426*e5436536SAndroid Build Coastguard Worker                     noSubbands * sizeof(SCHAR));
1427*e5436536SAndroid Build Coastguard Worker           FDKmemcpy(h_sbr_cal_env->filtBufferNoise, pNrgs->noiseLevel,
1428*e5436536SAndroid Build Coastguard Worker                     noSubbands * sizeof(FIXP_DBL));
1429*e5436536SAndroid Build Coastguard Worker           FDKmemcpy(h_sbr_cal_env->filtBuffer, pNrgs->nrgGain,
1430*e5436536SAndroid Build Coastguard Worker                     noSubbands * sizeof(FIXP_DBL));
1431*e5436536SAndroid Build Coastguard Worker         }
1432*e5436536SAndroid Build Coastguard Worker         h_sbr_cal_env->startUp = 0;
1433*e5436536SAndroid Build Coastguard Worker       }
1434*e5436536SAndroid Build Coastguard Worker 
1435*e5436536SAndroid Build Coastguard Worker       if (!useLP) {
1436*e5436536SAndroid Build Coastguard Worker         equalizeFiltBufferExp(h_sbr_cal_env->filtBuffer,   /* buffered */
1437*e5436536SAndroid Build Coastguard Worker                               h_sbr_cal_env->filtBuffer_e, /* buffered */
1438*e5436536SAndroid Build Coastguard Worker                               pNrgs->nrgGain,              /* current  */
1439*e5436536SAndroid Build Coastguard Worker                               pNrgs->nrgGain_e,            /* current  */
1440*e5436536SAndroid Build Coastguard Worker                               noSubbands);
1441*e5436536SAndroid Build Coastguard Worker 
1442*e5436536SAndroid Build Coastguard Worker         /* Adapt exponent of buffered noise levels to the current exponent
1443*e5436536SAndroid Build Coastguard Worker            so they can easily be smoothed */
1444*e5436536SAndroid Build Coastguard Worker         if ((h_sbr_cal_env->filtBufferNoise_e - noise_e) >= 0) {
1445*e5436536SAndroid Build Coastguard Worker           int shift = fixMin(DFRACT_BITS - 1,
1446*e5436536SAndroid Build Coastguard Worker                              (int)(h_sbr_cal_env->filtBufferNoise_e - noise_e));
1447*e5436536SAndroid Build Coastguard Worker           for (k = 0; k < noSubbands; k++)
1448*e5436536SAndroid Build Coastguard Worker             h_sbr_cal_env->filtBufferNoise[k] <<= shift;
1449*e5436536SAndroid Build Coastguard Worker         } else {
1450*e5436536SAndroid Build Coastguard Worker           int shift =
1451*e5436536SAndroid Build Coastguard Worker               fixMin(DFRACT_BITS - 1,
1452*e5436536SAndroid Build Coastguard Worker                      -(int)(h_sbr_cal_env->filtBufferNoise_e - noise_e));
1453*e5436536SAndroid Build Coastguard Worker           for (k = 0; k < noSubbands; k++)
1454*e5436536SAndroid Build Coastguard Worker             h_sbr_cal_env->filtBufferNoise[k] >>= shift;
1455*e5436536SAndroid Build Coastguard Worker         }
1456*e5436536SAndroid Build Coastguard Worker 
1457*e5436536SAndroid Build Coastguard Worker         h_sbr_cal_env->filtBufferNoise_e = noise_e;
1458*e5436536SAndroid Build Coastguard Worker       }
1459*e5436536SAndroid Build Coastguard Worker 
1460*e5436536SAndroid Build Coastguard Worker       /* find best scaling! */
1461*e5436536SAndroid Build Coastguard Worker       scale_change = -(DFRACT_BITS - 1);
1462*e5436536SAndroid Build Coastguard Worker       for (k = 0; k < noSubbands; k++) {
1463*e5436536SAndroid Build Coastguard Worker         scale_change = fixMax(scale_change, (int)pNrgs->nrgGain_e[k]);
1464*e5436536SAndroid Build Coastguard Worker       }
1465*e5436536SAndroid Build Coastguard Worker       sc_change = (start_pos < no_cols) ? adj_e - input_e : final_e - input_e;
1466*e5436536SAndroid Build Coastguard Worker 
1467*e5436536SAndroid Build Coastguard Worker       if ((scale_change - sc_change + 1) < 0)
1468*e5436536SAndroid Build Coastguard Worker         scale_change -= (scale_change - sc_change + 1);
1469*e5436536SAndroid Build Coastguard Worker 
1470*e5436536SAndroid Build Coastguard Worker       scale_change = (scale_change - sc_change) + 1;
1471*e5436536SAndroid Build Coastguard Worker 
1472*e5436536SAndroid Build Coastguard Worker       for (k = 0; k < noSubbands; k++) {
1473*e5436536SAndroid Build Coastguard Worker         int sc = scale_change - pNrgs->nrgGain_e[k] + (sc_change - 1);
1474*e5436536SAndroid Build Coastguard Worker         pNrgs->nrgGain[k] >>= fixMin(sc, DFRACT_BITS - 1);
1475*e5436536SAndroid Build Coastguard Worker         pNrgs->nrgGain_e[k] += sc;
1476*e5436536SAndroid Build Coastguard Worker       }
1477*e5436536SAndroid Build Coastguard Worker 
1478*e5436536SAndroid Build Coastguard Worker       if (!useLP) {
1479*e5436536SAndroid Build Coastguard Worker         for (k = 0; k < noSubbands; k++) {
1480*e5436536SAndroid Build Coastguard Worker           int sc =
1481*e5436536SAndroid Build Coastguard Worker               scale_change - h_sbr_cal_env->filtBuffer_e[k] + (sc_change - 1);
1482*e5436536SAndroid Build Coastguard Worker           h_sbr_cal_env->filtBuffer[k] >>= fixMin(sc, DFRACT_BITS - 1);
1483*e5436536SAndroid Build Coastguard Worker         }
1484*e5436536SAndroid Build Coastguard Worker       }
1485*e5436536SAndroid Build Coastguard Worker 
1486*e5436536SAndroid Build Coastguard Worker       for (j = start_pos; j < stop_pos; j++) {
1487*e5436536SAndroid Build Coastguard Worker         /* This timeslot is located within the first part of the processing
1488*e5436536SAndroid Build Coastguard Worker            buffer and will be fed into the QMF-synthesis for the current frame.
1489*e5436536SAndroid Build Coastguard Worker                adj_e - input_e
1490*e5436536SAndroid Build Coastguard Worker            This timeslot will not yet be fed into the QMF so we do not care
1491*e5436536SAndroid Build Coastguard Worker            about the adj_e.
1492*e5436536SAndroid Build Coastguard Worker                sc_change = final_e - input_e
1493*e5436536SAndroid Build Coastguard Worker         */
1494*e5436536SAndroid Build Coastguard Worker         if ((j == no_cols) && (start_pos < no_cols)) {
1495*e5436536SAndroid Build Coastguard Worker           int shift = (int)(noise_e - final_e);
1496*e5436536SAndroid Build Coastguard Worker           if (!useLP)
1497*e5436536SAndroid Build Coastguard Worker             filtBufferNoiseShift = shift; /* shifting of
1498*e5436536SAndroid Build Coastguard Worker                                              h_sbr_cal_env->filtBufferNoise[k]
1499*e5436536SAndroid Build Coastguard Worker                                              will be applied in function
1500*e5436536SAndroid Build Coastguard Worker                                              adjustTimeSlotHQ() */
1501*e5436536SAndroid Build Coastguard Worker           if (shift >= 0) {
1502*e5436536SAndroid Build Coastguard Worker             shift = fixMin(DFRACT_BITS - 1, shift);
1503*e5436536SAndroid Build Coastguard Worker             for (k = 0; k < noSubbands; k++) {
1504*e5436536SAndroid Build Coastguard Worker               pNrgs->nrgSine[k] <<= shift;
1505*e5436536SAndroid Build Coastguard Worker               pNrgs->noiseLevel[k] <<= shift;
1506*e5436536SAndroid Build Coastguard Worker               /*
1507*e5436536SAndroid Build Coastguard Worker               if (!useLP)
1508*e5436536SAndroid Build Coastguard Worker                 h_sbr_cal_env->filtBufferNoise[k]  <<= shift;
1509*e5436536SAndroid Build Coastguard Worker               */
1510*e5436536SAndroid Build Coastguard Worker             }
1511*e5436536SAndroid Build Coastguard Worker           } else {
1512*e5436536SAndroid Build Coastguard Worker             shift = fixMin(DFRACT_BITS - 1, -shift);
1513*e5436536SAndroid Build Coastguard Worker             for (k = 0; k < noSubbands; k++) {
1514*e5436536SAndroid Build Coastguard Worker               pNrgs->nrgSine[k] >>= shift;
1515*e5436536SAndroid Build Coastguard Worker               pNrgs->noiseLevel[k] >>= shift;
1516*e5436536SAndroid Build Coastguard Worker               /*
1517*e5436536SAndroid Build Coastguard Worker               if (!useLP)
1518*e5436536SAndroid Build Coastguard Worker                 h_sbr_cal_env->filtBufferNoise[k]  >>= shift;
1519*e5436536SAndroid Build Coastguard Worker               */
1520*e5436536SAndroid Build Coastguard Worker             }
1521*e5436536SAndroid Build Coastguard Worker           }
1522*e5436536SAndroid Build Coastguard Worker 
1523*e5436536SAndroid Build Coastguard Worker           /* update noise scaling */
1524*e5436536SAndroid Build Coastguard Worker           noise_e = final_e;
1525*e5436536SAndroid Build Coastguard Worker           if (!useLP)
1526*e5436536SAndroid Build Coastguard Worker             h_sbr_cal_env->filtBufferNoise_e =
1527*e5436536SAndroid Build Coastguard Worker                 noise_e; /* scaling value unused! */
1528*e5436536SAndroid Build Coastguard Worker 
1529*e5436536SAndroid Build Coastguard Worker           /* update gain buffer*/
1530*e5436536SAndroid Build Coastguard Worker           sc_change -= (final_e - input_e);
1531*e5436536SAndroid Build Coastguard Worker 
1532*e5436536SAndroid Build Coastguard Worker           if (sc_change < 0) {
1533*e5436536SAndroid Build Coastguard Worker             for (k = 0; k < noSubbands; k++) {
1534*e5436536SAndroid Build Coastguard Worker               pNrgs->nrgGain[k] >>= -sc_change;
1535*e5436536SAndroid Build Coastguard Worker               pNrgs->nrgGain_e[k] += -sc_change;
1536*e5436536SAndroid Build Coastguard Worker             }
1537*e5436536SAndroid Build Coastguard Worker             if (!useLP) {
1538*e5436536SAndroid Build Coastguard Worker               for (k = 0; k < noSubbands; k++) {
1539*e5436536SAndroid Build Coastguard Worker                 h_sbr_cal_env->filtBuffer[k] >>= -sc_change;
1540*e5436536SAndroid Build Coastguard Worker               }
1541*e5436536SAndroid Build Coastguard Worker             }
1542*e5436536SAndroid Build Coastguard Worker           } else {
1543*e5436536SAndroid Build Coastguard Worker             scale_change += sc_change;
1544*e5436536SAndroid Build Coastguard Worker           }
1545*e5436536SAndroid Build Coastguard Worker 
1546*e5436536SAndroid Build Coastguard Worker         } /* if */
1547*e5436536SAndroid Build Coastguard Worker 
1548*e5436536SAndroid Build Coastguard Worker         if (!useLP) {
1549*e5436536SAndroid Build Coastguard Worker           /* Prevent the smoothing filter from running on constant levels */
1550*e5436536SAndroid Build Coastguard Worker           if (j - start_pos < smooth_length)
1551*e5436536SAndroid Build Coastguard Worker             smooth_ratio = FDK_sbrDecoder_sbr_smoothFilter[j - start_pos];
1552*e5436536SAndroid Build Coastguard Worker           else
1553*e5436536SAndroid Build Coastguard Worker             smooth_ratio = FL2FXCONST_SGL(0.0f);
1554*e5436536SAndroid Build Coastguard Worker 
1555*e5436536SAndroid Build Coastguard Worker           if (iTES_enable) {
1556*e5436536SAndroid Build Coastguard Worker             /* adjustTimeSlotHQ() without adding of additional harmonics */
1557*e5436536SAndroid Build Coastguard Worker             adjustTimeSlotHQ_GainAndNoise(
1558*e5436536SAndroid Build Coastguard Worker                 &analysBufferReal[j][lowSubband],
1559*e5436536SAndroid Build Coastguard Worker                 &analysBufferImag[j][lowSubband], h_sbr_cal_env, pNrgs,
1560*e5436536SAndroid Build Coastguard Worker                 lowSubband, noSubbands, fMin(scale_change, DFRACT_BITS - 1),
1561*e5436536SAndroid Build Coastguard Worker                 smooth_ratio, noNoiseFlag, filtBufferNoiseShift);
1562*e5436536SAndroid Build Coastguard Worker           } else {
1563*e5436536SAndroid Build Coastguard Worker             adjustTimeSlotHQ(&analysBufferReal[j][lowSubband],
1564*e5436536SAndroid Build Coastguard Worker                              &analysBufferImag[j][lowSubband], h_sbr_cal_env,
1565*e5436536SAndroid Build Coastguard Worker                              pNrgs, lowSubband, noSubbands,
1566*e5436536SAndroid Build Coastguard Worker                              fMin(scale_change, DFRACT_BITS - 1), smooth_ratio,
1567*e5436536SAndroid Build Coastguard Worker                              noNoiseFlag, filtBufferNoiseShift);
1568*e5436536SAndroid Build Coastguard Worker           }
1569*e5436536SAndroid Build Coastguard Worker         } else {
1570*e5436536SAndroid Build Coastguard Worker           FDK_ASSERT(!iTES_enable); /* not supported */
1571*e5436536SAndroid Build Coastguard Worker           if (flags & SBRDEC_ELD_GRID) {
1572*e5436536SAndroid Build Coastguard Worker             /* FDKmemset(analysBufferReal[j], 0, 64 * sizeof(FIXP_DBL)); */
1573*e5436536SAndroid Build Coastguard Worker             adjustTimeSlot_EldGrid(
1574*e5436536SAndroid Build Coastguard Worker                 &analysBufferReal[j][lowSubband], pNrgs,
1575*e5436536SAndroid Build Coastguard Worker                 &h_sbr_cal_env->harmIndex, lowSubband, noSubbands,
1576*e5436536SAndroid Build Coastguard Worker                 fMin(scale_change, DFRACT_BITS - 1), noNoiseFlag,
1577*e5436536SAndroid Build Coastguard Worker                 &h_sbr_cal_env->phaseIndex,
1578*e5436536SAndroid Build Coastguard Worker                 fMax(EXP2SCALE(adj_e) - sbrScaleFactor->lb_scale,
1579*e5436536SAndroid Build Coastguard Worker                      -(DFRACT_BITS - 1)));
1580*e5436536SAndroid Build Coastguard Worker           } else {
1581*e5436536SAndroid Build Coastguard Worker             adjustTimeSlotLC(&analysBufferReal[j][lowSubband], pNrgs,
1582*e5436536SAndroid Build Coastguard Worker                              &h_sbr_cal_env->harmIndex, lowSubband, noSubbands,
1583*e5436536SAndroid Build Coastguard Worker                              fMin(scale_change, DFRACT_BITS - 1), noNoiseFlag,
1584*e5436536SAndroid Build Coastguard Worker                              &h_sbr_cal_env->phaseIndex);
1585*e5436536SAndroid Build Coastguard Worker           }
1586*e5436536SAndroid Build Coastguard Worker         }
1587*e5436536SAndroid Build Coastguard Worker         /* In case the envelope spans accross the no_cols border both exponents
1588*e5436536SAndroid Build Coastguard Worker          * are needed. */
1589*e5436536SAndroid Build Coastguard Worker         /* nrgGain_e[0...(noSubbands-1)] are equalized by
1590*e5436536SAndroid Build Coastguard Worker          * equalizeFiltBufferExp() */
1591*e5436536SAndroid Build Coastguard Worker         pNrgs->exponent[(j < no_cols) ? 0 : 1] =
1592*e5436536SAndroid Build Coastguard Worker             (SCHAR)((15 - sbrScaleFactor->hb_scale) + pNrgs->nrgGain_e[0] + 1 -
1593*e5436536SAndroid Build Coastguard Worker                     scale_change);
1594*e5436536SAndroid Build Coastguard Worker       } /* for */
1595*e5436536SAndroid Build Coastguard Worker 
1596*e5436536SAndroid Build Coastguard Worker       if (iTES_enable) {
1597*e5436536SAndroid Build Coastguard Worker         apply_inter_tes(
1598*e5436536SAndroid Build Coastguard Worker             analysBufferReal, /* pABufR, */
1599*e5436536SAndroid Build Coastguard Worker             analysBufferImag, /* pABufI, */
1600*e5436536SAndroid Build Coastguard Worker             sbrScaleFactor, pNrgs->exponent, hHeaderData->timeStep, start_pos,
1601*e5436536SAndroid Build Coastguard Worker             stop_pos, lowSubband, noSubbands,
1602*e5436536SAndroid Build Coastguard Worker             hFrameData
1603*e5436536SAndroid Build Coastguard Worker                 ->interTempShapeMode[i] /* frameData->interTempShapeMode[env] */
1604*e5436536SAndroid Build Coastguard Worker         );
1605*e5436536SAndroid Build Coastguard Worker 
1606*e5436536SAndroid Build Coastguard Worker         /* add additional harmonics */
1607*e5436536SAndroid Build Coastguard Worker         for (j = start_pos; j < stop_pos; j++) {
1608*e5436536SAndroid Build Coastguard Worker           /* match exponent of additional harmonics to scale change of QMF data
1609*e5436536SAndroid Build Coastguard Worker            * caused by apply_inter_tes() */
1610*e5436536SAndroid Build Coastguard Worker           scale_change = 0;
1611*e5436536SAndroid Build Coastguard Worker 
1612*e5436536SAndroid Build Coastguard Worker           if ((start_pos <= no_cols) && (stop_pos > no_cols)) {
1613*e5436536SAndroid Build Coastguard Worker             /* Scaling of analysBuffers was potentially changed within this
1614*e5436536SAndroid Build Coastguard Worker                envelope. The pNrgs->nrgSine_e match the second part of the
1615*e5436536SAndroid Build Coastguard Worker                envelope. For (j<=no_cols) the exponent of the sine energies has
1616*e5436536SAndroid Build Coastguard Worker                to be adapted. */
1617*e5436536SAndroid Build Coastguard Worker             scale_change = pNrgs->exponent[1] - pNrgs->exponent[0];
1618*e5436536SAndroid Build Coastguard Worker           }
1619*e5436536SAndroid Build Coastguard Worker 
1620*e5436536SAndroid Build Coastguard Worker           adjustTimeSlotHQ_AddHarmonics(
1621*e5436536SAndroid Build Coastguard Worker               &analysBufferReal[j][lowSubband],
1622*e5436536SAndroid Build Coastguard Worker               &analysBufferImag[j][lowSubband], h_sbr_cal_env, pNrgs,
1623*e5436536SAndroid Build Coastguard Worker               lowSubband, noSubbands,
1624*e5436536SAndroid Build Coastguard Worker               -iTES_scale_change + ((j < no_cols) ? scale_change : 0));
1625*e5436536SAndroid Build Coastguard Worker         }
1626*e5436536SAndroid Build Coastguard Worker       }
1627*e5436536SAndroid Build Coastguard Worker 
1628*e5436536SAndroid Build Coastguard Worker       if (!useLP) {
1629*e5436536SAndroid Build Coastguard Worker         /* Update time-smoothing-buffers for gains and noise levels
1630*e5436536SAndroid Build Coastguard Worker            The gains and the noise values of the current envelope are copied
1631*e5436536SAndroid Build Coastguard Worker            into the buffer. This has to be done at the end of each envelope as
1632*e5436536SAndroid Build Coastguard Worker            the values are required for a smooth transition to the next envelope.
1633*e5436536SAndroid Build Coastguard Worker          */
1634*e5436536SAndroid Build Coastguard Worker         FDKmemcpy(h_sbr_cal_env->filtBuffer, pNrgs->nrgGain,
1635*e5436536SAndroid Build Coastguard Worker                   noSubbands * sizeof(FIXP_DBL));
1636*e5436536SAndroid Build Coastguard Worker         FDKmemcpy(h_sbr_cal_env->filtBuffer_e, pNrgs->nrgGain_e,
1637*e5436536SAndroid Build Coastguard Worker                   noSubbands * sizeof(SCHAR));
1638*e5436536SAndroid Build Coastguard Worker         FDKmemcpy(h_sbr_cal_env->filtBufferNoise, pNrgs->noiseLevel,
1639*e5436536SAndroid Build Coastguard Worker                   noSubbands * sizeof(FIXP_DBL));
1640*e5436536SAndroid Build Coastguard Worker       }
1641*e5436536SAndroid Build Coastguard Worker     }
1642*e5436536SAndroid Build Coastguard Worker     C_ALLOC_SCRATCH_END(pNrgs, ENV_CALC_NRGS, 1);
1643*e5436536SAndroid Build Coastguard Worker   }
1644*e5436536SAndroid Build Coastguard Worker 
1645*e5436536SAndroid Build Coastguard Worker   /* adapt adj_e to the scale change caused by apply_inter_tes() */
1646*e5436536SAndroid Build Coastguard Worker   adj_e += iTES_scale_change;
1647*e5436536SAndroid Build Coastguard Worker 
1648*e5436536SAndroid Build Coastguard Worker   /* Rescale output samples */
1649*e5436536SAndroid Build Coastguard Worker   {
1650*e5436536SAndroid Build Coastguard Worker     FIXP_DBL maxVal;
1651*e5436536SAndroid Build Coastguard Worker     int ov_reserve, reserve;
1652*e5436536SAndroid Build Coastguard Worker 
1653*e5436536SAndroid Build Coastguard Worker     /* Determine headroom in old adjusted samples */
1654*e5436536SAndroid Build Coastguard Worker     maxVal =
1655*e5436536SAndroid Build Coastguard Worker         maxSubbandSample(analysBufferReal, (useLP) ? NULL : analysBufferImag,
1656*e5436536SAndroid Build Coastguard Worker                          lowSubband, ov_highSubband, 0, first_start);
1657*e5436536SAndroid Build Coastguard Worker 
1658*e5436536SAndroid Build Coastguard Worker     ov_reserve = fNorm(maxVal);
1659*e5436536SAndroid Build Coastguard Worker 
1660*e5436536SAndroid Build Coastguard Worker     /* Determine headroom in new adjusted samples */
1661*e5436536SAndroid Build Coastguard Worker     maxVal =
1662*e5436536SAndroid Build Coastguard Worker         maxSubbandSample(analysBufferReal, (useLP) ? NULL : analysBufferImag,
1663*e5436536SAndroid Build Coastguard Worker                          lowSubband, highSubband, first_start, no_cols);
1664*e5436536SAndroid Build Coastguard Worker 
1665*e5436536SAndroid Build Coastguard Worker     reserve = fNorm(maxVal);
1666*e5436536SAndroid Build Coastguard Worker 
1667*e5436536SAndroid Build Coastguard Worker     /* Determine common output exponent */
1668*e5436536SAndroid Build Coastguard Worker     output_e = fMax(ov_adj_e - ov_reserve, adj_e - reserve);
1669*e5436536SAndroid Build Coastguard Worker 
1670*e5436536SAndroid Build Coastguard Worker     /* Rescale old samples */
1671*e5436536SAndroid Build Coastguard Worker     rescaleSubbandSamples(analysBufferReal, (useLP) ? NULL : analysBufferImag,
1672*e5436536SAndroid Build Coastguard Worker                           lowSubband, ov_highSubband, 0, first_start,
1673*e5436536SAndroid Build Coastguard Worker                           ov_adj_e - output_e);
1674*e5436536SAndroid Build Coastguard Worker 
1675*e5436536SAndroid Build Coastguard Worker     /* Rescale new samples */
1676*e5436536SAndroid Build Coastguard Worker     rescaleSubbandSamples(analysBufferReal, (useLP) ? NULL : analysBufferImag,
1677*e5436536SAndroid Build Coastguard Worker                           lowSubband, highSubband, first_start, no_cols,
1678*e5436536SAndroid Build Coastguard Worker                           adj_e - output_e);
1679*e5436536SAndroid Build Coastguard Worker   }
1680*e5436536SAndroid Build Coastguard Worker 
1681*e5436536SAndroid Build Coastguard Worker   /* Update hb_scale */
1682*e5436536SAndroid Build Coastguard Worker   sbrScaleFactor->hb_scale = EXP2SCALE(output_e);
1683*e5436536SAndroid Build Coastguard Worker 
1684*e5436536SAndroid Build Coastguard Worker   /* Save the current final exponent for the next frame: */
1685*e5436536SAndroid Build Coastguard Worker   /* adapt final_e to the scale change caused by apply_inter_tes() */
1686*e5436536SAndroid Build Coastguard Worker   sbrScaleFactor->ov_hb_scale = EXP2SCALE(final_e + iTES_scale_change);
1687*e5436536SAndroid Build Coastguard Worker 
1688*e5436536SAndroid Build Coastguard Worker   /* We need to remember to the next frame that the transient
1689*e5436536SAndroid Build Coastguard Worker      will occur in the first envelope (if tranEnv == nEnvelopes). */
1690*e5436536SAndroid Build Coastguard Worker   if (hFrameData->frameInfo.tranEnv == hFrameData->frameInfo.nEnvelopes)
1691*e5436536SAndroid Build Coastguard Worker     h_sbr_cal_env->prevTranEnv = 0;
1692*e5436536SAndroid Build Coastguard Worker   else
1693*e5436536SAndroid Build Coastguard Worker     h_sbr_cal_env->prevTranEnv = -1;
1694*e5436536SAndroid Build Coastguard Worker 
1695*e5436536SAndroid Build Coastguard Worker   if (pvc_mode > 0) {
1696*e5436536SAndroid Build Coastguard Worker     /* Not more than just the last noise envelope reaches into the next PVC
1697*e5436536SAndroid Build Coastguard Worker        frame! This should be true because bs_noise_position is <= 15 */
1698*e5436536SAndroid Build Coastguard Worker     FDK_ASSERT(hFrameData->frameInfo
1699*e5436536SAndroid Build Coastguard Worker                    .bordersNoise[hFrameData->frameInfo.nNoiseEnvelopes - 1] <
1700*e5436536SAndroid Build Coastguard Worker                PVC_NTIMESLOT);
1701*e5436536SAndroid Build Coastguard Worker     if (hFrameData->frameInfo
1702*e5436536SAndroid Build Coastguard Worker             .bordersNoise[hFrameData->frameInfo.nNoiseEnvelopes] >
1703*e5436536SAndroid Build Coastguard Worker         PVC_NTIMESLOT) {
1704*e5436536SAndroid Build Coastguard Worker       FDK_ASSERT(noiseLevels ==
1705*e5436536SAndroid Build Coastguard Worker                  (hFrameData->sbrNoiseFloorLevel +
1706*e5436536SAndroid Build Coastguard Worker                   (hFrameData->frameInfo.nNoiseEnvelopes - 1) * noNoiseBands));
1707*e5436536SAndroid Build Coastguard Worker       h_sbr_cal_env->prevNNfb = noNoiseBands;
1708*e5436536SAndroid Build Coastguard Worker 
1709*e5436536SAndroid Build Coastguard Worker       h_sbr_cal_env->prevNSfb[0] = noSubFrameBands[0];
1710*e5436536SAndroid Build Coastguard Worker       h_sbr_cal_env->prevNSfb[1] = noSubFrameBands[1];
1711*e5436536SAndroid Build Coastguard Worker 
1712*e5436536SAndroid Build Coastguard Worker       h_sbr_cal_env->prevLoSubband = lowSubband;
1713*e5436536SAndroid Build Coastguard Worker       h_sbr_cal_env->prevHiSubband = highSubband;
1714*e5436536SAndroid Build Coastguard Worker       h_sbr_cal_env->prev_ov_highSubband = ov_highSubband;
1715*e5436536SAndroid Build Coastguard Worker 
1716*e5436536SAndroid Build Coastguard Worker       FDKmemcpy(h_sbr_cal_env->prevFreqBandTableLo, pFreqBandTable[0],
1717*e5436536SAndroid Build Coastguard Worker                 noSubFrameBands[0] + 1);
1718*e5436536SAndroid Build Coastguard Worker       FDKmemcpy(h_sbr_cal_env->prevFreqBandTableHi, pFreqBandTable[1],
1719*e5436536SAndroid Build Coastguard Worker                 noSubFrameBands[1] + 1);
1720*e5436536SAndroid Build Coastguard Worker       FDKmemcpy(h_sbr_cal_env->prevFreqBandTableNoise,
1721*e5436536SAndroid Build Coastguard Worker                 hFreq->freqBandTableNoise, sizeof(hFreq->freqBandTableNoise));
1722*e5436536SAndroid Build Coastguard Worker 
1723*e5436536SAndroid Build Coastguard Worker       FDKmemcpy(h_sbr_cal_env->prevSbrNoiseFloorLevel, noiseLevels,
1724*e5436536SAndroid Build Coastguard Worker                 MAX_NOISE_COEFFS * sizeof(FIXP_SGL));
1725*e5436536SAndroid Build Coastguard Worker     }
1726*e5436536SAndroid Build Coastguard Worker   }
1727*e5436536SAndroid Build Coastguard Worker 
1728*e5436536SAndroid Build Coastguard Worker   C_ALLOC_SCRATCH_END(useAliasReduction, UCHAR, 64)
1729*e5436536SAndroid Build Coastguard Worker }
1730*e5436536SAndroid Build Coastguard Worker 
1731*e5436536SAndroid Build Coastguard Worker /*!
1732*e5436536SAndroid Build Coastguard Worker   \brief   Create envelope instance
1733*e5436536SAndroid Build Coastguard Worker 
1734*e5436536SAndroid Build Coastguard Worker   Must be called once for each channel before calculateSbrEnvelope() can be
1735*e5436536SAndroid Build Coastguard Worker   used.
1736*e5436536SAndroid Build Coastguard Worker 
1737*e5436536SAndroid Build Coastguard Worker   \return  errorCode, 0 if successful
1738*e5436536SAndroid Build Coastguard Worker */
1739*e5436536SAndroid Build Coastguard Worker SBR_ERROR
createSbrEnvelopeCalc(HANDLE_SBR_CALCULATE_ENVELOPE hs,HANDLE_SBR_HEADER_DATA hHeaderData,const int chan,const UINT flags)1740*e5436536SAndroid Build Coastguard Worker createSbrEnvelopeCalc(
1741*e5436536SAndroid Build Coastguard Worker     HANDLE_SBR_CALCULATE_ENVELOPE hs, /*!< pointer to envelope instance */
1742*e5436536SAndroid Build Coastguard Worker     HANDLE_SBR_HEADER_DATA
1743*e5436536SAndroid Build Coastguard Worker         hHeaderData, /*!< static SBR control data, initialized with defaults */
1744*e5436536SAndroid Build Coastguard Worker     const int chan,  /*!< Channel for which to assign buffers */
1745*e5436536SAndroid Build Coastguard Worker     const UINT flags) {
1746*e5436536SAndroid Build Coastguard Worker   SBR_ERROR err = SBRDEC_OK;
1747*e5436536SAndroid Build Coastguard Worker   int i;
1748*e5436536SAndroid Build Coastguard Worker 
1749*e5436536SAndroid Build Coastguard Worker   /* Clear previous missing harmonics flags */
1750*e5436536SAndroid Build Coastguard Worker   for (i = 0; i < ADD_HARMONICS_FLAGS_SIZE; i++) {
1751*e5436536SAndroid Build Coastguard Worker     hs->harmFlagsPrev[i] = 0;
1752*e5436536SAndroid Build Coastguard Worker     hs->harmFlagsPrevActive[i] = 0;
1753*e5436536SAndroid Build Coastguard Worker   }
1754*e5436536SAndroid Build Coastguard Worker   hs->harmIndex = 0;
1755*e5436536SAndroid Build Coastguard Worker 
1756*e5436536SAndroid Build Coastguard Worker   FDKmemclear(hs->prevSbrNoiseFloorLevel, sizeof(hs->prevSbrNoiseFloorLevel));
1757*e5436536SAndroid Build Coastguard Worker   hs->prevNNfb = 0;
1758*e5436536SAndroid Build Coastguard Worker   FDKmemclear(hs->prevFreqBandTableNoise, sizeof(hs->prevFreqBandTableNoise));
1759*e5436536SAndroid Build Coastguard Worker   hs->sinusoidal_positionPrev = 0;
1760*e5436536SAndroid Build Coastguard Worker 
1761*e5436536SAndroid Build Coastguard Worker   /*
1762*e5436536SAndroid Build Coastguard Worker     Setup pointers for time smoothing.
1763*e5436536SAndroid Build Coastguard Worker     The buffer itself will be initialized later triggered by the startUp-flag.
1764*e5436536SAndroid Build Coastguard Worker   */
1765*e5436536SAndroid Build Coastguard Worker   hs->prevTranEnv = -1;
1766*e5436536SAndroid Build Coastguard Worker 
1767*e5436536SAndroid Build Coastguard Worker   /* initialization */
1768*e5436536SAndroid Build Coastguard Worker   resetSbrEnvelopeCalc(hs);
1769*e5436536SAndroid Build Coastguard Worker 
1770*e5436536SAndroid Build Coastguard Worker   if (chan == 0) { /* do this only once */
1771*e5436536SAndroid Build Coastguard Worker     err = resetFreqBandTables(hHeaderData, flags);
1772*e5436536SAndroid Build Coastguard Worker   }
1773*e5436536SAndroid Build Coastguard Worker 
1774*e5436536SAndroid Build Coastguard Worker   return err;
1775*e5436536SAndroid Build Coastguard Worker }
1776*e5436536SAndroid Build Coastguard Worker 
1777*e5436536SAndroid Build Coastguard Worker /*!
1778*e5436536SAndroid Build Coastguard Worker   \brief   Create envelope instance
1779*e5436536SAndroid Build Coastguard Worker 
1780*e5436536SAndroid Build Coastguard Worker   Must be called once for each channel before calculateSbrEnvelope() can be
1781*e5436536SAndroid Build Coastguard Worker   used.
1782*e5436536SAndroid Build Coastguard Worker 
1783*e5436536SAndroid Build Coastguard Worker   \return  errorCode, 0 if successful
1784*e5436536SAndroid Build Coastguard Worker */
deleteSbrEnvelopeCalc(HANDLE_SBR_CALCULATE_ENVELOPE hs)1785*e5436536SAndroid Build Coastguard Worker int deleteSbrEnvelopeCalc(HANDLE_SBR_CALCULATE_ENVELOPE hs) { return 0; }
1786*e5436536SAndroid Build Coastguard Worker 
1787*e5436536SAndroid Build Coastguard Worker /*!
1788*e5436536SAndroid Build Coastguard Worker   \brief   Reset envelope instance
1789*e5436536SAndroid Build Coastguard Worker 
1790*e5436536SAndroid Build Coastguard Worker   This function must be called for each channel on a change of configuration.
1791*e5436536SAndroid Build Coastguard Worker   Note that resetFreqBandTables should also be called in this case.
1792*e5436536SAndroid Build Coastguard Worker 
1793*e5436536SAndroid Build Coastguard Worker   \return  errorCode, 0 if successful
1794*e5436536SAndroid Build Coastguard Worker */
resetSbrEnvelopeCalc(HANDLE_SBR_CALCULATE_ENVELOPE hCalEnv)1795*e5436536SAndroid Build Coastguard Worker void resetSbrEnvelopeCalc(
1796*e5436536SAndroid Build Coastguard Worker     HANDLE_SBR_CALCULATE_ENVELOPE hCalEnv) /*!< pointer to envelope instance */
1797*e5436536SAndroid Build Coastguard Worker {
1798*e5436536SAndroid Build Coastguard Worker   hCalEnv->phaseIndex = 0;
1799*e5436536SAndroid Build Coastguard Worker 
1800*e5436536SAndroid Build Coastguard Worker   /* Noise exponent needs to be reset because the output exponent for the next
1801*e5436536SAndroid Build Coastguard Worker    * frame depends on it */
1802*e5436536SAndroid Build Coastguard Worker   hCalEnv->filtBufferNoise_e = 0;
1803*e5436536SAndroid Build Coastguard Worker 
1804*e5436536SAndroid Build Coastguard Worker   hCalEnv->startUp = 1;
1805*e5436536SAndroid Build Coastguard Worker }
1806*e5436536SAndroid Build Coastguard Worker 
1807*e5436536SAndroid Build Coastguard Worker /*!
1808*e5436536SAndroid Build Coastguard Worker   \brief  Equalize exponents of the buffered gain values and the new ones
1809*e5436536SAndroid Build Coastguard Worker 
1810*e5436536SAndroid Build Coastguard Worker   After equalization of exponents, the FIR-filter addition for smoothing
1811*e5436536SAndroid Build Coastguard Worker   can be performed.
1812*e5436536SAndroid Build Coastguard Worker   This function is called once for each envelope before adjusting.
1813*e5436536SAndroid Build Coastguard Worker */
equalizeFiltBufferExp(FIXP_DBL * filtBuffer,SCHAR * filtBuffer_e,FIXP_DBL * nrgGain,SCHAR * nrgGain_e,int subbands)1814*e5436536SAndroid Build Coastguard Worker static void equalizeFiltBufferExp(
1815*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *filtBuffer, /*!< bufferd gains */
1816*e5436536SAndroid Build Coastguard Worker     SCHAR *filtBuffer_e,  /*!< exponents of bufferd gains */
1817*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *nrgGain,    /*!< gains for current envelope */
1818*e5436536SAndroid Build Coastguard Worker     SCHAR *nrgGain_e,     /*!< exponents of gains for current envelope */
1819*e5436536SAndroid Build Coastguard Worker     int subbands)         /*!< Number of QMF subbands */
1820*e5436536SAndroid Build Coastguard Worker {
1821*e5436536SAndroid Build Coastguard Worker   int band;
1822*e5436536SAndroid Build Coastguard Worker   int diff;
1823*e5436536SAndroid Build Coastguard Worker 
1824*e5436536SAndroid Build Coastguard Worker   for (band = 0; band < subbands; band++) {
1825*e5436536SAndroid Build Coastguard Worker     diff = (int)(nrgGain_e[band] - filtBuffer_e[band]);
1826*e5436536SAndroid Build Coastguard Worker     if (diff > 0) {
1827*e5436536SAndroid Build Coastguard Worker       filtBuffer[band] >>=
1828*e5436536SAndroid Build Coastguard Worker           fMin(diff, DFRACT_BITS - 1); /* Compensate for the scale change by
1829*e5436536SAndroid Build Coastguard Worker                                           shifting the mantissa. */
1830*e5436536SAndroid Build Coastguard Worker       filtBuffer_e[band] += diff; /* New gain is bigger, use its exponent */
1831*e5436536SAndroid Build Coastguard Worker     } else if (diff < 0) {
1832*e5436536SAndroid Build Coastguard Worker       /* The buffered gains seem to be larger, but maybe there
1833*e5436536SAndroid Build Coastguard Worker          are some unused bits left in the mantissa */
1834*e5436536SAndroid Build Coastguard Worker 
1835*e5436536SAndroid Build Coastguard Worker       int reserve = CntLeadingZeros(fixp_abs(filtBuffer[band])) - 1;
1836*e5436536SAndroid Build Coastguard Worker 
1837*e5436536SAndroid Build Coastguard Worker       if ((-diff) <= reserve) {
1838*e5436536SAndroid Build Coastguard Worker         /* There is enough space in the buffered mantissa so
1839*e5436536SAndroid Build Coastguard Worker            that we can take the new exponent as common.
1840*e5436536SAndroid Build Coastguard Worker         */
1841*e5436536SAndroid Build Coastguard Worker         filtBuffer[band] <<= (-diff);
1842*e5436536SAndroid Build Coastguard Worker         filtBuffer_e[band] += diff; /* becomes equal to *ptrNewExp */
1843*e5436536SAndroid Build Coastguard Worker       } else {
1844*e5436536SAndroid Build Coastguard Worker         filtBuffer[band] <<=
1845*e5436536SAndroid Build Coastguard Worker             reserve; /* Shift the mantissa as far as possible: */
1846*e5436536SAndroid Build Coastguard Worker         filtBuffer_e[band] -= reserve; /* Compensate in the exponent: */
1847*e5436536SAndroid Build Coastguard Worker 
1848*e5436536SAndroid Build Coastguard Worker         /* For the remaining difference, change the new gain value */
1849*e5436536SAndroid Build Coastguard Worker         diff = -(reserve + diff);
1850*e5436536SAndroid Build Coastguard Worker         nrgGain[band] >>= fMin(diff, DFRACT_BITS - 1);
1851*e5436536SAndroid Build Coastguard Worker         nrgGain_e[band] += diff;
1852*e5436536SAndroid Build Coastguard Worker       }
1853*e5436536SAndroid Build Coastguard Worker     }
1854*e5436536SAndroid Build Coastguard Worker   }
1855*e5436536SAndroid Build Coastguard Worker }
1856*e5436536SAndroid Build Coastguard Worker 
1857*e5436536SAndroid Build Coastguard Worker /*!
1858*e5436536SAndroid Build Coastguard Worker   \brief  Shift left the mantissas of all subband samples
1859*e5436536SAndroid Build Coastguard Worker           in the giventime and frequency range by the specified number of bits.
1860*e5436536SAndroid Build Coastguard Worker 
1861*e5436536SAndroid Build Coastguard Worker   This function is used to rescale the audio data in the overlap buffer
1862*e5436536SAndroid Build Coastguard Worker   which has already been envelope adjusted with the last frame.
1863*e5436536SAndroid Build Coastguard Worker */
rescaleSubbandSamples(FIXP_DBL ** re,FIXP_DBL ** im,int lowSubband,int highSubband,int start_pos,int next_pos,int shift)1864*e5436536SAndroid Build Coastguard Worker void rescaleSubbandSamples(
1865*e5436536SAndroid Build Coastguard Worker     FIXP_DBL **re,   /*!< Real part of input and output subband samples */
1866*e5436536SAndroid Build Coastguard Worker     FIXP_DBL **im,   /*!< Imaginary part of input and output subband samples */
1867*e5436536SAndroid Build Coastguard Worker     int lowSubband,  /*!< Begin of frequency range to process */
1868*e5436536SAndroid Build Coastguard Worker     int highSubband, /*!< End of frequency range to process */
1869*e5436536SAndroid Build Coastguard Worker     int start_pos,   /*!< Begin of time rage (QMF-timeslot) */
1870*e5436536SAndroid Build Coastguard Worker     int next_pos,    /*!< End of time rage (QMF-timeslot) */
1871*e5436536SAndroid Build Coastguard Worker     int shift)       /*!< number of bits to shift */
1872*e5436536SAndroid Build Coastguard Worker {
1873*e5436536SAndroid Build Coastguard Worker   int width = highSubband - lowSubband;
1874*e5436536SAndroid Build Coastguard Worker 
1875*e5436536SAndroid Build Coastguard Worker   if ((width > 0) && (shift != 0)) {
1876*e5436536SAndroid Build Coastguard Worker     if (im != NULL) {
1877*e5436536SAndroid Build Coastguard Worker       for (int l = start_pos; l < next_pos; l++) {
1878*e5436536SAndroid Build Coastguard Worker         scaleValues(&re[l][lowSubband], width, shift);
1879*e5436536SAndroid Build Coastguard Worker         scaleValues(&im[l][lowSubband], width, shift);
1880*e5436536SAndroid Build Coastguard Worker       }
1881*e5436536SAndroid Build Coastguard Worker     } else {
1882*e5436536SAndroid Build Coastguard Worker       for (int l = start_pos; l < next_pos; l++) {
1883*e5436536SAndroid Build Coastguard Worker         scaleValues(&re[l][lowSubband], width, shift);
1884*e5436536SAndroid Build Coastguard Worker       }
1885*e5436536SAndroid Build Coastguard Worker     }
1886*e5436536SAndroid Build Coastguard Worker   }
1887*e5436536SAndroid Build Coastguard Worker }
1888*e5436536SAndroid Build Coastguard Worker 
FDK_get_maxval_real(FIXP_DBL maxVal,FIXP_DBL * reTmp,INT width)1889*e5436536SAndroid Build Coastguard Worker static inline FIXP_DBL FDK_get_maxval_real(FIXP_DBL maxVal, FIXP_DBL *reTmp,
1890*e5436536SAndroid Build Coastguard Worker                                            INT width) {
1891*e5436536SAndroid Build Coastguard Worker   maxVal = (FIXP_DBL)0;
1892*e5436536SAndroid Build Coastguard Worker   while (width-- != 0) {
1893*e5436536SAndroid Build Coastguard Worker     FIXP_DBL tmp = *(reTmp++);
1894*e5436536SAndroid Build Coastguard Worker     maxVal |= (FIXP_DBL)((LONG)(tmp) ^ ((LONG)tmp >> (DFRACT_BITS - 1)));
1895*e5436536SAndroid Build Coastguard Worker   }
1896*e5436536SAndroid Build Coastguard Worker 
1897*e5436536SAndroid Build Coastguard Worker   return maxVal;
1898*e5436536SAndroid Build Coastguard Worker }
1899*e5436536SAndroid Build Coastguard Worker 
1900*e5436536SAndroid Build Coastguard Worker /*!
1901*e5436536SAndroid Build Coastguard Worker   \brief   Determine headroom for shifting
1902*e5436536SAndroid Build Coastguard Worker 
1903*e5436536SAndroid Build Coastguard Worker   Determine by how much the spectrum can be shifted left
1904*e5436536SAndroid Build Coastguard Worker   for better accuracy in later processing.
1905*e5436536SAndroid Build Coastguard Worker 
1906*e5436536SAndroid Build Coastguard Worker   \return  Number of free bits in the biggest spectral value
1907*e5436536SAndroid Build Coastguard Worker */
1908*e5436536SAndroid Build Coastguard Worker 
maxSubbandSample(FIXP_DBL ** re,FIXP_DBL ** im,int lowSubband,int highSubband,int start_pos,int next_pos)1909*e5436536SAndroid Build Coastguard Worker FIXP_DBL maxSubbandSample(
1910*e5436536SAndroid Build Coastguard Worker     FIXP_DBL **re,   /*!< Real part of input and output subband samples */
1911*e5436536SAndroid Build Coastguard Worker     FIXP_DBL **im,   /*!< Real part of input and output subband samples */
1912*e5436536SAndroid Build Coastguard Worker     int lowSubband,  /*!< Begin of frequency range to process */
1913*e5436536SAndroid Build Coastguard Worker     int highSubband, /*!< Number of QMF bands to process */
1914*e5436536SAndroid Build Coastguard Worker     int start_pos,   /*!< Begin of time rage (QMF-timeslot) */
1915*e5436536SAndroid Build Coastguard Worker     int next_pos     /*!< End of time rage (QMF-timeslot) */
1916*e5436536SAndroid Build Coastguard Worker ) {
1917*e5436536SAndroid Build Coastguard Worker   FIXP_DBL maxVal = FL2FX_DBL(0.0f);
1918*e5436536SAndroid Build Coastguard Worker   unsigned int width = highSubband - lowSubband;
1919*e5436536SAndroid Build Coastguard Worker 
1920*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(width <= (64));
1921*e5436536SAndroid Build Coastguard Worker 
1922*e5436536SAndroid Build Coastguard Worker   if (width > 0) {
1923*e5436536SAndroid Build Coastguard Worker     if (im != NULL) {
1924*e5436536SAndroid Build Coastguard Worker       for (int l = start_pos; l < next_pos; l++) {
1925*e5436536SAndroid Build Coastguard Worker         int k = width;
1926*e5436536SAndroid Build Coastguard Worker         FIXP_DBL *reTmp = &re[l][lowSubband];
1927*e5436536SAndroid Build Coastguard Worker         FIXP_DBL *imTmp = &im[l][lowSubband];
1928*e5436536SAndroid Build Coastguard Worker         do {
1929*e5436536SAndroid Build Coastguard Worker           FIXP_DBL tmp1 = *(reTmp++);
1930*e5436536SAndroid Build Coastguard Worker           FIXP_DBL tmp2 = *(imTmp++);
1931*e5436536SAndroid Build Coastguard Worker           maxVal |=
1932*e5436536SAndroid Build Coastguard Worker               (FIXP_DBL)((LONG)(tmp1) ^ ((LONG)tmp1 >> (DFRACT_BITS - 1)));
1933*e5436536SAndroid Build Coastguard Worker           maxVal |=
1934*e5436536SAndroid Build Coastguard Worker               (FIXP_DBL)((LONG)(tmp2) ^ ((LONG)tmp2 >> (DFRACT_BITS - 1)));
1935*e5436536SAndroid Build Coastguard Worker         } while (--k != 0);
1936*e5436536SAndroid Build Coastguard Worker       }
1937*e5436536SAndroid Build Coastguard Worker     } else {
1938*e5436536SAndroid Build Coastguard Worker       for (int l = start_pos; l < next_pos; l++) {
1939*e5436536SAndroid Build Coastguard Worker         maxVal |= FDK_get_maxval_real(maxVal, &re[l][lowSubband], width);
1940*e5436536SAndroid Build Coastguard Worker       }
1941*e5436536SAndroid Build Coastguard Worker     }
1942*e5436536SAndroid Build Coastguard Worker   }
1943*e5436536SAndroid Build Coastguard Worker 
1944*e5436536SAndroid Build Coastguard Worker   if (maxVal > (FIXP_DBL)0) {
1945*e5436536SAndroid Build Coastguard Worker     /* For negative input values, maxVal is too small by 1. Add 1 only when
1946*e5436536SAndroid Build Coastguard Worker      * necessary: if maxVal is a power of 2 */
1947*e5436536SAndroid Build Coastguard Worker     FIXP_DBL lowerPow2 =
1948*e5436536SAndroid Build Coastguard Worker         (FIXP_DBL)(1 << (DFRACT_BITS - 1 - CntLeadingZeros(maxVal)));
1949*e5436536SAndroid Build Coastguard Worker     if (maxVal == lowerPow2) maxVal += (FIXP_DBL)1;
1950*e5436536SAndroid Build Coastguard Worker   }
1951*e5436536SAndroid Build Coastguard Worker 
1952*e5436536SAndroid Build Coastguard Worker   return (maxVal);
1953*e5436536SAndroid Build Coastguard Worker }
1954*e5436536SAndroid Build Coastguard Worker 
1955*e5436536SAndroid Build Coastguard Worker /* #define SHIFT_BEFORE_SQUARE (3) */ /* (7/2) */
1956*e5436536SAndroid Build Coastguard Worker /* Avoid assertion failures triggerd by overflows which occured in robustness
1957*e5436536SAndroid Build Coastguard Worker    tests. Setting the SHIFT_BEFORE_SQUARE to 4 has negligible effect on (USAC)
1958*e5436536SAndroid Build Coastguard Worker    conformance results. */
1959*e5436536SAndroid Build Coastguard Worker #define SHIFT_BEFORE_SQUARE (4) /* ((8 - 0) / 2) */
1960*e5436536SAndroid Build Coastguard Worker 
1961*e5436536SAndroid Build Coastguard Worker /*!<
1962*e5436536SAndroid Build Coastguard Worker   If the accumulator does not provide enough overflow bits or
1963*e5436536SAndroid Build Coastguard Worker   does not provide a high dynamic range, the below energy calculation
1964*e5436536SAndroid Build Coastguard Worker   requires an additional shift operation for each sample.
1965*e5436536SAndroid Build Coastguard Worker   On the other hand, doing the shift allows using a single-precision
1966*e5436536SAndroid Build Coastguard Worker   multiplication for the square (at least 16bit x 16bit).
1967*e5436536SAndroid Build Coastguard Worker   For even values of OVRFLW_BITS (0, 2, 4, 6), saturated arithmetic
1968*e5436536SAndroid Build Coastguard Worker   is required for the energy accumulation.
1969*e5436536SAndroid Build Coastguard Worker   Theoretically, the sample-squares can sum up to a value of 76,
1970*e5436536SAndroid Build Coastguard Worker   requiring 7 overflow bits. However since such situations are *very*
1971*e5436536SAndroid Build Coastguard Worker   rare, accu can be limited to 64.
1972*e5436536SAndroid Build Coastguard Worker   In case native saturated arithmetic is not available, overflows
1973*e5436536SAndroid Build Coastguard Worker   can be prevented by replacing the above #define by
1974*e5436536SAndroid Build Coastguard Worker     #define SHIFT_BEFORE_SQUARE ((8 - OVRFLW_BITS) / 2)
1975*e5436536SAndroid Build Coastguard Worker   which will result in slightly reduced accuracy.
1976*e5436536SAndroid Build Coastguard Worker */
1977*e5436536SAndroid Build Coastguard Worker 
1978*e5436536SAndroid Build Coastguard Worker /*!
1979*e5436536SAndroid Build Coastguard Worker   \brief  Estimates the mean energy of each filter-bank channel for the
1980*e5436536SAndroid Build Coastguard Worker           duration of the current envelope
1981*e5436536SAndroid Build Coastguard Worker 
1982*e5436536SAndroid Build Coastguard Worker   This function is used when interpolFreq is true.
1983*e5436536SAndroid Build Coastguard Worker */
calcNrgPerSubband(FIXP_DBL ** analysBufferReal,FIXP_DBL ** analysBufferImag,int lowSubband,int highSubband,int start_pos,int next_pos,SCHAR frameExp,FIXP_DBL * nrgEst,SCHAR * nrgEst_e)1984*e5436536SAndroid Build Coastguard Worker static void calcNrgPerSubband(
1985*e5436536SAndroid Build Coastguard Worker     FIXP_DBL **analysBufferReal, /*!< Real part of subband samples */
1986*e5436536SAndroid Build Coastguard Worker     FIXP_DBL **analysBufferImag, /*!< Imaginary part of subband samples */
1987*e5436536SAndroid Build Coastguard Worker     int lowSubband,              /*!< Begin of the SBR frequency range */
1988*e5436536SAndroid Build Coastguard Worker     int highSubband,             /*!< High end of the SBR frequency range */
1989*e5436536SAndroid Build Coastguard Worker     int start_pos,               /*!< First QMF-slot of current envelope */
1990*e5436536SAndroid Build Coastguard Worker     int next_pos,                /*!< Last QMF-slot of current envelope + 1 */
1991*e5436536SAndroid Build Coastguard Worker     SCHAR frameExp,              /*!< Common exponent for all input samples */
1992*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *nrgEst,            /*!< resulting Energy (0..1) */
1993*e5436536SAndroid Build Coastguard Worker     SCHAR *nrgEst_e)             /*!< Exponent of resulting Energy */
1994*e5436536SAndroid Build Coastguard Worker {
1995*e5436536SAndroid Build Coastguard Worker   FIXP_SGL invWidth;
1996*e5436536SAndroid Build Coastguard Worker   SCHAR preShift;
1997*e5436536SAndroid Build Coastguard Worker   SCHAR shift;
1998*e5436536SAndroid Build Coastguard Worker   FIXP_DBL sum;
1999*e5436536SAndroid Build Coastguard Worker   int k;
2000*e5436536SAndroid Build Coastguard Worker 
2001*e5436536SAndroid Build Coastguard Worker   /* Divide by width of envelope later: */
2002*e5436536SAndroid Build Coastguard Worker   invWidth = FX_DBL2FX_SGL(GetInvInt(next_pos - start_pos));
2003*e5436536SAndroid Build Coastguard Worker   /* The common exponent needs to be doubled because all mantissas are squared:
2004*e5436536SAndroid Build Coastguard Worker    */
2005*e5436536SAndroid Build Coastguard Worker   frameExp = frameExp << 1;
2006*e5436536SAndroid Build Coastguard Worker 
2007*e5436536SAndroid Build Coastguard Worker   for (k = lowSubband; k < highSubband; k++) {
2008*e5436536SAndroid Build Coastguard Worker     FIXP_DBL bufferReal[(((1024) / (32) * (4) / 2) + (3 * (4)))];
2009*e5436536SAndroid Build Coastguard Worker     FIXP_DBL bufferImag[(((1024) / (32) * (4) / 2) + (3 * (4)))];
2010*e5436536SAndroid Build Coastguard Worker     FIXP_DBL maxVal;
2011*e5436536SAndroid Build Coastguard Worker 
2012*e5436536SAndroid Build Coastguard Worker     if (analysBufferImag != NULL) {
2013*e5436536SAndroid Build Coastguard Worker       int l;
2014*e5436536SAndroid Build Coastguard Worker       maxVal = FL2FX_DBL(0.0f);
2015*e5436536SAndroid Build Coastguard Worker       for (l = start_pos; l < next_pos; l++) {
2016*e5436536SAndroid Build Coastguard Worker         bufferImag[l] = analysBufferImag[l][k];
2017*e5436536SAndroid Build Coastguard Worker         maxVal |= (FIXP_DBL)((LONG)(bufferImag[l]) ^
2018*e5436536SAndroid Build Coastguard Worker                              ((LONG)bufferImag[l] >> (DFRACT_BITS - 1)));
2019*e5436536SAndroid Build Coastguard Worker         bufferReal[l] = analysBufferReal[l][k];
2020*e5436536SAndroid Build Coastguard Worker         maxVal |= (FIXP_DBL)((LONG)(bufferReal[l]) ^
2021*e5436536SAndroid Build Coastguard Worker                              ((LONG)bufferReal[l] >> (DFRACT_BITS - 1)));
2022*e5436536SAndroid Build Coastguard Worker       }
2023*e5436536SAndroid Build Coastguard Worker     } else {
2024*e5436536SAndroid Build Coastguard Worker       int l;
2025*e5436536SAndroid Build Coastguard Worker       maxVal = FL2FX_DBL(0.0f);
2026*e5436536SAndroid Build Coastguard Worker       for (l = start_pos; l < next_pos; l++) {
2027*e5436536SAndroid Build Coastguard Worker         bufferReal[l] = analysBufferReal[l][k];
2028*e5436536SAndroid Build Coastguard Worker         maxVal |= (FIXP_DBL)((LONG)(bufferReal[l]) ^
2029*e5436536SAndroid Build Coastguard Worker                              ((LONG)bufferReal[l] >> (DFRACT_BITS - 1)));
2030*e5436536SAndroid Build Coastguard Worker       }
2031*e5436536SAndroid Build Coastguard Worker     }
2032*e5436536SAndroid Build Coastguard Worker 
2033*e5436536SAndroid Build Coastguard Worker     if (maxVal != FL2FXCONST_DBL(0.f)) {
2034*e5436536SAndroid Build Coastguard Worker       /* If the accu does not provide enough overflow bits, we cannot
2035*e5436536SAndroid Build Coastguard Worker          shift the samples up to the limit.
2036*e5436536SAndroid Build Coastguard Worker          Instead, keep up to 3 free bits in each sample, i.e. up to
2037*e5436536SAndroid Build Coastguard Worker          6 bits after calculation of square.
2038*e5436536SAndroid Build Coastguard Worker          Please note the comment on saturated arithmetic above!
2039*e5436536SAndroid Build Coastguard Worker       */
2040*e5436536SAndroid Build Coastguard Worker       FIXP_DBL accu;
2041*e5436536SAndroid Build Coastguard Worker       preShift = CntLeadingZeros(maxVal) - 1;
2042*e5436536SAndroid Build Coastguard Worker       preShift -= SHIFT_BEFORE_SQUARE;
2043*e5436536SAndroid Build Coastguard Worker 
2044*e5436536SAndroid Build Coastguard Worker       /* Limit preShift to a maximum value to prevent accumulator overflow in
2045*e5436536SAndroid Build Coastguard Worker          exceptional situations where the signal in the analysis-buffer is very
2046*e5436536SAndroid Build Coastguard Worker          small (small maxVal).
2047*e5436536SAndroid Build Coastguard Worker       */
2048*e5436536SAndroid Build Coastguard Worker       preShift = fMin(preShift, (SCHAR)25);
2049*e5436536SAndroid Build Coastguard Worker 
2050*e5436536SAndroid Build Coastguard Worker       accu = FL2FXCONST_DBL(0.0f);
2051*e5436536SAndroid Build Coastguard Worker       if (preShift >= 0) {
2052*e5436536SAndroid Build Coastguard Worker         int l;
2053*e5436536SAndroid Build Coastguard Worker         if (analysBufferImag != NULL) {
2054*e5436536SAndroid Build Coastguard Worker           for (l = start_pos; l < next_pos; l++) {
2055*e5436536SAndroid Build Coastguard Worker             FIXP_DBL temp1 = bufferReal[l] << (int)preShift;
2056*e5436536SAndroid Build Coastguard Worker             FIXP_DBL temp2 = bufferImag[l] << (int)preShift;
2057*e5436536SAndroid Build Coastguard Worker             accu = fPow2AddDiv2(accu, temp1);
2058*e5436536SAndroid Build Coastguard Worker             accu = fPow2AddDiv2(accu, temp2);
2059*e5436536SAndroid Build Coastguard Worker           }
2060*e5436536SAndroid Build Coastguard Worker         } else {
2061*e5436536SAndroid Build Coastguard Worker           for (l = start_pos; l < next_pos; l++) {
2062*e5436536SAndroid Build Coastguard Worker             FIXP_DBL temp = bufferReal[l] << (int)preShift;
2063*e5436536SAndroid Build Coastguard Worker             accu = fPow2AddDiv2(accu, temp);
2064*e5436536SAndroid Build Coastguard Worker           }
2065*e5436536SAndroid Build Coastguard Worker         }
2066*e5436536SAndroid Build Coastguard Worker       } else { /* if negative shift value */
2067*e5436536SAndroid Build Coastguard Worker         int l;
2068*e5436536SAndroid Build Coastguard Worker         int negpreShift = -preShift;
2069*e5436536SAndroid Build Coastguard Worker         if (analysBufferImag != NULL) {
2070*e5436536SAndroid Build Coastguard Worker           for (l = start_pos; l < next_pos; l++) {
2071*e5436536SAndroid Build Coastguard Worker             FIXP_DBL temp1 = bufferReal[l] >> (int)negpreShift;
2072*e5436536SAndroid Build Coastguard Worker             FIXP_DBL temp2 = bufferImag[l] >> (int)negpreShift;
2073*e5436536SAndroid Build Coastguard Worker             accu = fPow2AddDiv2(accu, temp1);
2074*e5436536SAndroid Build Coastguard Worker             accu = fPow2AddDiv2(accu, temp2);
2075*e5436536SAndroid Build Coastguard Worker           }
2076*e5436536SAndroid Build Coastguard Worker         } else {
2077*e5436536SAndroid Build Coastguard Worker           for (l = start_pos; l < next_pos; l++) {
2078*e5436536SAndroid Build Coastguard Worker             FIXP_DBL temp = bufferReal[l] >> (int)negpreShift;
2079*e5436536SAndroid Build Coastguard Worker             accu = fPow2AddDiv2(accu, temp);
2080*e5436536SAndroid Build Coastguard Worker           }
2081*e5436536SAndroid Build Coastguard Worker         }
2082*e5436536SAndroid Build Coastguard Worker       }
2083*e5436536SAndroid Build Coastguard Worker       accu <<= 1;
2084*e5436536SAndroid Build Coastguard Worker 
2085*e5436536SAndroid Build Coastguard Worker       /* Convert double precision to Mantissa/Exponent: */
2086*e5436536SAndroid Build Coastguard Worker       shift = fNorm(accu);
2087*e5436536SAndroid Build Coastguard Worker       sum = accu << (int)shift;
2088*e5436536SAndroid Build Coastguard Worker 
2089*e5436536SAndroid Build Coastguard Worker       /* Divide by width of envelope and apply frame scale: */
2090*e5436536SAndroid Build Coastguard Worker       *nrgEst++ = fMult(sum, invWidth);
2091*e5436536SAndroid Build Coastguard Worker       shift += 2 * preShift;
2092*e5436536SAndroid Build Coastguard Worker       if (analysBufferImag != NULL)
2093*e5436536SAndroid Build Coastguard Worker         *nrgEst_e++ = frameExp - shift;
2094*e5436536SAndroid Build Coastguard Worker       else
2095*e5436536SAndroid Build Coastguard Worker         *nrgEst_e++ = frameExp - shift + 1; /* +1 due to missing imag. part */
2096*e5436536SAndroid Build Coastguard Worker     }                                       /* maxVal!=0 */
2097*e5436536SAndroid Build Coastguard Worker     else {
2098*e5436536SAndroid Build Coastguard Worker       /* Prevent a zero-mantissa-number from being misinterpreted
2099*e5436536SAndroid Build Coastguard Worker          due to its exponent. */
2100*e5436536SAndroid Build Coastguard Worker       *nrgEst++ = FL2FXCONST_DBL(0.0f);
2101*e5436536SAndroid Build Coastguard Worker       *nrgEst_e++ = 0;
2102*e5436536SAndroid Build Coastguard Worker     }
2103*e5436536SAndroid Build Coastguard Worker   }
2104*e5436536SAndroid Build Coastguard Worker }
2105*e5436536SAndroid Build Coastguard Worker 
2106*e5436536SAndroid Build Coastguard Worker /*!
2107*e5436536SAndroid Build Coastguard Worker   \brief   Estimates the mean energy of each Scale factor band for the
2108*e5436536SAndroid Build Coastguard Worker            duration of the current envelope.
2109*e5436536SAndroid Build Coastguard Worker 
2110*e5436536SAndroid Build Coastguard Worker   This function is used when interpolFreq is false.
2111*e5436536SAndroid Build Coastguard Worker */
calcNrgPerSfb(FIXP_DBL ** analysBufferReal,FIXP_DBL ** analysBufferImag,int nSfb,UCHAR * freqBandTable,int start_pos,int next_pos,SCHAR input_e,FIXP_DBL * nrgEst,SCHAR * nrgEst_e)2112*e5436536SAndroid Build Coastguard Worker static void calcNrgPerSfb(
2113*e5436536SAndroid Build Coastguard Worker     FIXP_DBL **analysBufferReal, /*!< Real part of subband samples */
2114*e5436536SAndroid Build Coastguard Worker     FIXP_DBL **analysBufferImag, /*!< Imaginary part of subband samples */
2115*e5436536SAndroid Build Coastguard Worker     int nSfb,                    /*!< Number of scale factor bands */
2116*e5436536SAndroid Build Coastguard Worker     UCHAR *freqBandTable,        /*!< First Subband for each Sfb */
2117*e5436536SAndroid Build Coastguard Worker     int start_pos,               /*!< First QMF-slot of current envelope */
2118*e5436536SAndroid Build Coastguard Worker     int next_pos,                /*!< Last QMF-slot of current envelope + 1 */
2119*e5436536SAndroid Build Coastguard Worker     SCHAR input_e,               /*!< Common exponent for all input samples */
2120*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *nrgEst,            /*!< resulting Energy (0..1) */
2121*e5436536SAndroid Build Coastguard Worker     SCHAR *nrgEst_e)             /*!< Exponent of resulting Energy */
2122*e5436536SAndroid Build Coastguard Worker {
2123*e5436536SAndroid Build Coastguard Worker   FIXP_SGL invWidth;
2124*e5436536SAndroid Build Coastguard Worker   FIXP_DBL temp;
2125*e5436536SAndroid Build Coastguard Worker   SCHAR preShift;
2126*e5436536SAndroid Build Coastguard Worker   SCHAR shift, sum_e;
2127*e5436536SAndroid Build Coastguard Worker   FIXP_DBL sum;
2128*e5436536SAndroid Build Coastguard Worker 
2129*e5436536SAndroid Build Coastguard Worker   int j, k, l, li, ui;
2130*e5436536SAndroid Build Coastguard Worker   FIXP_DBL sumAll, sumLine; /* Single precision would be sufficient,
2131*e5436536SAndroid Build Coastguard Worker                              but overflow bits are required for accumulation */
2132*e5436536SAndroid Build Coastguard Worker 
2133*e5436536SAndroid Build Coastguard Worker   /* Divide by width of envelope later: */
2134*e5436536SAndroid Build Coastguard Worker   invWidth = FX_DBL2FX_SGL(GetInvInt(next_pos - start_pos));
2135*e5436536SAndroid Build Coastguard Worker   /* The common exponent needs to be doubled because all mantissas are squared:
2136*e5436536SAndroid Build Coastguard Worker    */
2137*e5436536SAndroid Build Coastguard Worker   input_e = input_e << 1;
2138*e5436536SAndroid Build Coastguard Worker 
2139*e5436536SAndroid Build Coastguard Worker   for (j = 0; j < nSfb; j++) {
2140*e5436536SAndroid Build Coastguard Worker     li = freqBandTable[j];
2141*e5436536SAndroid Build Coastguard Worker     ui = freqBandTable[j + 1];
2142*e5436536SAndroid Build Coastguard Worker 
2143*e5436536SAndroid Build Coastguard Worker     FIXP_DBL maxVal = maxSubbandSample(analysBufferReal, analysBufferImag, li,
2144*e5436536SAndroid Build Coastguard Worker                                        ui, start_pos, next_pos);
2145*e5436536SAndroid Build Coastguard Worker 
2146*e5436536SAndroid Build Coastguard Worker     if (maxVal != FL2FXCONST_DBL(0.f)) {
2147*e5436536SAndroid Build Coastguard Worker       preShift = CntLeadingZeros(maxVal) - 1;
2148*e5436536SAndroid Build Coastguard Worker 
2149*e5436536SAndroid Build Coastguard Worker       /* If the accu does not provide enough overflow bits, we cannot
2150*e5436536SAndroid Build Coastguard Worker          shift the samples up to the limit.
2151*e5436536SAndroid Build Coastguard Worker          Instead, keep up to 3 free bits in each sample, i.e. up to
2152*e5436536SAndroid Build Coastguard Worker          6 bits after calculation of square.
2153*e5436536SAndroid Build Coastguard Worker          Please note the comment on saturated arithmetic above!
2154*e5436536SAndroid Build Coastguard Worker       */
2155*e5436536SAndroid Build Coastguard Worker       preShift -= SHIFT_BEFORE_SQUARE;
2156*e5436536SAndroid Build Coastguard Worker 
2157*e5436536SAndroid Build Coastguard Worker       sumAll = FL2FXCONST_DBL(0.0f);
2158*e5436536SAndroid Build Coastguard Worker 
2159*e5436536SAndroid Build Coastguard Worker       for (k = li; k < ui; k++) {
2160*e5436536SAndroid Build Coastguard Worker         sumLine = FL2FXCONST_DBL(0.0f);
2161*e5436536SAndroid Build Coastguard Worker 
2162*e5436536SAndroid Build Coastguard Worker         if (analysBufferImag != NULL) {
2163*e5436536SAndroid Build Coastguard Worker           if (preShift >= 0) {
2164*e5436536SAndroid Build Coastguard Worker             for (l = start_pos; l < next_pos; l++) {
2165*e5436536SAndroid Build Coastguard Worker               temp = analysBufferReal[l][k] << (int)preShift;
2166*e5436536SAndroid Build Coastguard Worker               sumLine += fPow2Div2(temp);
2167*e5436536SAndroid Build Coastguard Worker               temp = analysBufferImag[l][k] << (int)preShift;
2168*e5436536SAndroid Build Coastguard Worker               sumLine += fPow2Div2(temp);
2169*e5436536SAndroid Build Coastguard Worker             }
2170*e5436536SAndroid Build Coastguard Worker           } else {
2171*e5436536SAndroid Build Coastguard Worker             for (l = start_pos; l < next_pos; l++) {
2172*e5436536SAndroid Build Coastguard Worker               temp = analysBufferReal[l][k] >> -(int)preShift;
2173*e5436536SAndroid Build Coastguard Worker               sumLine += fPow2Div2(temp);
2174*e5436536SAndroid Build Coastguard Worker               temp = analysBufferImag[l][k] >> -(int)preShift;
2175*e5436536SAndroid Build Coastguard Worker               sumLine += fPow2Div2(temp);
2176*e5436536SAndroid Build Coastguard Worker             }
2177*e5436536SAndroid Build Coastguard Worker           }
2178*e5436536SAndroid Build Coastguard Worker         } else {
2179*e5436536SAndroid Build Coastguard Worker           if (preShift >= 0) {
2180*e5436536SAndroid Build Coastguard Worker             for (l = start_pos; l < next_pos; l++) {
2181*e5436536SAndroid Build Coastguard Worker               temp = analysBufferReal[l][k] << (int)preShift;
2182*e5436536SAndroid Build Coastguard Worker               sumLine += fPow2Div2(temp);
2183*e5436536SAndroid Build Coastguard Worker             }
2184*e5436536SAndroid Build Coastguard Worker           } else {
2185*e5436536SAndroid Build Coastguard Worker             for (l = start_pos; l < next_pos; l++) {
2186*e5436536SAndroid Build Coastguard Worker               temp = analysBufferReal[l][k] >> -(int)preShift;
2187*e5436536SAndroid Build Coastguard Worker               sumLine += fPow2Div2(temp);
2188*e5436536SAndroid Build Coastguard Worker             }
2189*e5436536SAndroid Build Coastguard Worker           }
2190*e5436536SAndroid Build Coastguard Worker         }
2191*e5436536SAndroid Build Coastguard Worker 
2192*e5436536SAndroid Build Coastguard Worker         /* The number of QMF-channels per SBR bands may be up to 15.
2193*e5436536SAndroid Build Coastguard Worker            Shift right to avoid overflows in sum over all channels. */
2194*e5436536SAndroid Build Coastguard Worker         sumLine = sumLine >> (4 - 1);
2195*e5436536SAndroid Build Coastguard Worker         sumAll += sumLine;
2196*e5436536SAndroid Build Coastguard Worker       }
2197*e5436536SAndroid Build Coastguard Worker 
2198*e5436536SAndroid Build Coastguard Worker       /* Convert double precision to Mantissa/Exponent: */
2199*e5436536SAndroid Build Coastguard Worker       shift = fNorm(sumAll);
2200*e5436536SAndroid Build Coastguard Worker       sum = sumAll << (int)shift;
2201*e5436536SAndroid Build Coastguard Worker 
2202*e5436536SAndroid Build Coastguard Worker       /* Divide by width of envelope: */
2203*e5436536SAndroid Build Coastguard Worker       sum = fMult(sum, invWidth);
2204*e5436536SAndroid Build Coastguard Worker 
2205*e5436536SAndroid Build Coastguard Worker       /* Divide by width of Sfb: */
2206*e5436536SAndroid Build Coastguard Worker       sum = fMult(sum, FX_DBL2FX_SGL(GetInvInt(ui - li)));
2207*e5436536SAndroid Build Coastguard Worker 
2208*e5436536SAndroid Build Coastguard Worker       /* Set all Subband energies in the Sfb to the average energy: */
2209*e5436536SAndroid Build Coastguard Worker       if (analysBufferImag != NULL)
2210*e5436536SAndroid Build Coastguard Worker         sum_e = input_e + 4 - shift; /* -4 to compensate right-shift */
2211*e5436536SAndroid Build Coastguard Worker       else
2212*e5436536SAndroid Build Coastguard Worker         sum_e = input_e + 4 + 1 -
2213*e5436536SAndroid Build Coastguard Worker                 shift; /* -4 to compensate right-shift; +1 due to missing
2214*e5436536SAndroid Build Coastguard Worker                           imag. part */
2215*e5436536SAndroid Build Coastguard Worker 
2216*e5436536SAndroid Build Coastguard Worker       sum_e -= 2 * preShift;
2217*e5436536SAndroid Build Coastguard Worker     } /* maxVal!=0 */
2218*e5436536SAndroid Build Coastguard Worker     else {
2219*e5436536SAndroid Build Coastguard Worker       /* Prevent a zero-mantissa-number from being misinterpreted
2220*e5436536SAndroid Build Coastguard Worker          due to its exponent. */
2221*e5436536SAndroid Build Coastguard Worker       sum = FL2FXCONST_DBL(0.0f);
2222*e5436536SAndroid Build Coastguard Worker       sum_e = 0;
2223*e5436536SAndroid Build Coastguard Worker     }
2224*e5436536SAndroid Build Coastguard Worker 
2225*e5436536SAndroid Build Coastguard Worker     for (k = li; k < ui; k++) {
2226*e5436536SAndroid Build Coastguard Worker       *nrgEst++ = sum;
2227*e5436536SAndroid Build Coastguard Worker       *nrgEst_e++ = sum_e;
2228*e5436536SAndroid Build Coastguard Worker     }
2229*e5436536SAndroid Build Coastguard Worker   }
2230*e5436536SAndroid Build Coastguard Worker }
2231*e5436536SAndroid Build Coastguard Worker 
2232*e5436536SAndroid Build Coastguard Worker /*!
2233*e5436536SAndroid Build Coastguard Worker   \brief  Calculate gain, noise, and additional sine level for one subband.
2234*e5436536SAndroid Build Coastguard Worker 
2235*e5436536SAndroid Build Coastguard Worker   The resulting energy gain is given by mantissa and exponent.
2236*e5436536SAndroid Build Coastguard Worker */
calcSubbandGain(FIXP_DBL nrgRef,SCHAR nrgRef_e,ENV_CALC_NRGS * nrgs,int i,FIXP_DBL tmpNoise,SCHAR tmpNoise_e,UCHAR sinePresentFlag,UCHAR sineMapped,int noNoiseFlag)2237*e5436536SAndroid Build Coastguard Worker static void calcSubbandGain(
2238*e5436536SAndroid Build Coastguard Worker     FIXP_DBL nrgRef, /*!< Reference Energy according to envelope data */
2239*e5436536SAndroid Build Coastguard Worker     SCHAR
2240*e5436536SAndroid Build Coastguard Worker         nrgRef_e, /*!< Reference Energy according to envelope data (exponent) */
2241*e5436536SAndroid Build Coastguard Worker     ENV_CALC_NRGS *nrgs, int i, FIXP_DBL tmpNoise, /*!< Relative noise level */
2242*e5436536SAndroid Build Coastguard Worker     SCHAR tmpNoise_e,      /*!< Relative noise level (exponent) */
2243*e5436536SAndroid Build Coastguard Worker     UCHAR sinePresentFlag, /*!< Indicates if sine is present on band */
2244*e5436536SAndroid Build Coastguard Worker     UCHAR sineMapped,      /*!< Indicates if sine must be added */
2245*e5436536SAndroid Build Coastguard Worker     int noNoiseFlag)       /*!< Flag to suppress noise addition */
2246*e5436536SAndroid Build Coastguard Worker {
2247*e5436536SAndroid Build Coastguard Worker   FIXP_DBL nrgEst = nrgs->nrgEst[i]; /*!< Energy in transposed signal */
2248*e5436536SAndroid Build Coastguard Worker   SCHAR nrgEst_e =
2249*e5436536SAndroid Build Coastguard Worker       nrgs->nrgEst_e[i]; /*!< Energy in transposed signal (exponent) */
2250*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *ptrNrgGain = &nrgs->nrgGain[i]; /*!< Resulting energy gain */
2251*e5436536SAndroid Build Coastguard Worker   SCHAR *ptrNrgGain_e =
2252*e5436536SAndroid Build Coastguard Worker       &nrgs->nrgGain_e[i]; /*!< Resulting energy gain (exponent) */
2253*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *ptrNoiseLevel =
2254*e5436536SAndroid Build Coastguard Worker       &nrgs->noiseLevel[i]; /*!< Resulting absolute noise energy */
2255*e5436536SAndroid Build Coastguard Worker   SCHAR *ptrNoiseLevel_e =
2256*e5436536SAndroid Build Coastguard Worker       &nrgs->noiseLevel_e[i]; /*!< Resulting absolute noise energy (exponent) */
2257*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *ptrNrgSine = &nrgs->nrgSine[i]; /*!< Additional sine energy */
2258*e5436536SAndroid Build Coastguard Worker   SCHAR *ptrNrgSine_e =
2259*e5436536SAndroid Build Coastguard Worker       &nrgs->nrgSine_e[i]; /*!< Additional sine energy (exponent) */
2260*e5436536SAndroid Build Coastguard Worker 
2261*e5436536SAndroid Build Coastguard Worker   FIXP_DBL a, b, c;
2262*e5436536SAndroid Build Coastguard Worker   SCHAR a_e, b_e, c_e;
2263*e5436536SAndroid Build Coastguard Worker 
2264*e5436536SAndroid Build Coastguard Worker   /*
2265*e5436536SAndroid Build Coastguard Worker      This addition of 1 prevents divisions by zero in the reference code.
2266*e5436536SAndroid Build Coastguard Worker      For very small energies in nrgEst, it prevents the gains from becoming
2267*e5436536SAndroid Build Coastguard Worker      very high which could cause some trouble due to the smoothing.
2268*e5436536SAndroid Build Coastguard Worker   */
2269*e5436536SAndroid Build Coastguard Worker   b_e = (int)(nrgEst_e - 1);
2270*e5436536SAndroid Build Coastguard Worker   if (b_e >= 0) {
2271*e5436536SAndroid Build Coastguard Worker     nrgEst = (FL2FXCONST_DBL(0.5f) >> (INT)fixMin(b_e + 1, DFRACT_BITS - 1)) +
2272*e5436536SAndroid Build Coastguard Worker              (nrgEst >> 1);
2273*e5436536SAndroid Build Coastguard Worker     nrgEst_e += 1; /* shift by 1 bit to avoid overflow */
2274*e5436536SAndroid Build Coastguard Worker 
2275*e5436536SAndroid Build Coastguard Worker   } else {
2276*e5436536SAndroid Build Coastguard Worker     nrgEst = (nrgEst >> (INT)(fixMin(-b_e + 1, DFRACT_BITS - 1))) +
2277*e5436536SAndroid Build Coastguard Worker              (FL2FXCONST_DBL(0.5f) >> 1);
2278*e5436536SAndroid Build Coastguard Worker     nrgEst_e = 2; /* shift by 1 bit to avoid overflow */
2279*e5436536SAndroid Build Coastguard Worker   }
2280*e5436536SAndroid Build Coastguard Worker 
2281*e5436536SAndroid Build Coastguard Worker   /*  A = NrgRef * TmpNoise */
2282*e5436536SAndroid Build Coastguard Worker   a = fMult(nrgRef, tmpNoise);
2283*e5436536SAndroid Build Coastguard Worker   a_e = nrgRef_e + tmpNoise_e;
2284*e5436536SAndroid Build Coastguard Worker 
2285*e5436536SAndroid Build Coastguard Worker   /*  B = 1 + TmpNoise */
2286*e5436536SAndroid Build Coastguard Worker   b_e = (int)(tmpNoise_e - 1);
2287*e5436536SAndroid Build Coastguard Worker   if (b_e >= 0) {
2288*e5436536SAndroid Build Coastguard Worker     b = (FL2FXCONST_DBL(0.5f) >> (INT)fixMin(b_e + 1, DFRACT_BITS - 1)) +
2289*e5436536SAndroid Build Coastguard Worker         (tmpNoise >> 1);
2290*e5436536SAndroid Build Coastguard Worker     b_e = tmpNoise_e + 1; /* shift by 1 bit to avoid overflow */
2291*e5436536SAndroid Build Coastguard Worker   } else {
2292*e5436536SAndroid Build Coastguard Worker     b = (tmpNoise >> (INT)(fixMin(-b_e + 1, DFRACT_BITS - 1))) +
2293*e5436536SAndroid Build Coastguard Worker         (FL2FXCONST_DBL(0.5f) >> 1);
2294*e5436536SAndroid Build Coastguard Worker     b_e = 2; /* shift by 1 bit to avoid overflow */
2295*e5436536SAndroid Build Coastguard Worker   }
2296*e5436536SAndroid Build Coastguard Worker 
2297*e5436536SAndroid Build Coastguard Worker   /*  noiseLevel = A / B = (NrgRef * TmpNoise) / (1 + TmpNoise) */
2298*e5436536SAndroid Build Coastguard Worker   FDK_divide_MantExp(a, a_e, b, b_e, ptrNoiseLevel, ptrNoiseLevel_e);
2299*e5436536SAndroid Build Coastguard Worker 
2300*e5436536SAndroid Build Coastguard Worker   if (sinePresentFlag) {
2301*e5436536SAndroid Build Coastguard Worker     /*  C = (1 + TmpNoise) * NrgEst */
2302*e5436536SAndroid Build Coastguard Worker     c = fMult(b, nrgEst);
2303*e5436536SAndroid Build Coastguard Worker     c_e = b_e + nrgEst_e;
2304*e5436536SAndroid Build Coastguard Worker 
2305*e5436536SAndroid Build Coastguard Worker     /*  gain = A / C = (NrgRef * TmpNoise) / (1 + TmpNoise) * NrgEst */
2306*e5436536SAndroid Build Coastguard Worker     FDK_divide_MantExp(a, a_e, c, c_e, ptrNrgGain, ptrNrgGain_e);
2307*e5436536SAndroid Build Coastguard Worker 
2308*e5436536SAndroid Build Coastguard Worker     if (sineMapped) {
2309*e5436536SAndroid Build Coastguard Worker       /*  sineLevel = nrgRef/ (1 + TmpNoise) */
2310*e5436536SAndroid Build Coastguard Worker       FDK_divide_MantExp(nrgRef, nrgRef_e, b, b_e, ptrNrgSine, ptrNrgSine_e);
2311*e5436536SAndroid Build Coastguard Worker     }
2312*e5436536SAndroid Build Coastguard Worker   } else {
2313*e5436536SAndroid Build Coastguard Worker     if (noNoiseFlag) {
2314*e5436536SAndroid Build Coastguard Worker       /*  B = NrgEst */
2315*e5436536SAndroid Build Coastguard Worker       b = nrgEst;
2316*e5436536SAndroid Build Coastguard Worker       b_e = nrgEst_e;
2317*e5436536SAndroid Build Coastguard Worker     } else {
2318*e5436536SAndroid Build Coastguard Worker       /*  B = NrgEst * (1 + TmpNoise) */
2319*e5436536SAndroid Build Coastguard Worker       b = fMult(b, nrgEst);
2320*e5436536SAndroid Build Coastguard Worker       b_e = b_e + nrgEst_e;
2321*e5436536SAndroid Build Coastguard Worker     }
2322*e5436536SAndroid Build Coastguard Worker 
2323*e5436536SAndroid Build Coastguard Worker     /*  gain = nrgRef / B */
2324*e5436536SAndroid Build Coastguard Worker     INT result_exp = 0;
2325*e5436536SAndroid Build Coastguard Worker     *ptrNrgGain = fDivNorm(nrgRef, b, &result_exp);
2326*e5436536SAndroid Build Coastguard Worker     *ptrNrgGain_e = (SCHAR)result_exp + (nrgRef_e - b_e);
2327*e5436536SAndroid Build Coastguard Worker 
2328*e5436536SAndroid Build Coastguard Worker     /* There could be a one bit diffs. This is important to compensate,
2329*e5436536SAndroid Build Coastguard Worker        because later in the code values are compared by exponent only. */
2330*e5436536SAndroid Build Coastguard Worker     int headroom = CountLeadingBits(*ptrNrgGain);
2331*e5436536SAndroid Build Coastguard Worker     *ptrNrgGain <<= headroom;
2332*e5436536SAndroid Build Coastguard Worker     *ptrNrgGain_e -= headroom;
2333*e5436536SAndroid Build Coastguard Worker   }
2334*e5436536SAndroid Build Coastguard Worker }
2335*e5436536SAndroid Build Coastguard Worker 
2336*e5436536SAndroid Build Coastguard Worker /*!
2337*e5436536SAndroid Build Coastguard Worker   \brief  Calculate "average gain" for the specified subband range.
2338*e5436536SAndroid Build Coastguard Worker 
2339*e5436536SAndroid Build Coastguard Worker   This is rather a gain of the average magnitude than the average
2340*e5436536SAndroid Build Coastguard Worker   of gains!
2341*e5436536SAndroid Build Coastguard Worker   The result is used as a relative limit for all gains within the
2342*e5436536SAndroid Build Coastguard Worker   current "limiter band" (a certain frequency range).
2343*e5436536SAndroid Build Coastguard Worker */
calcAvgGain(ENV_CALC_NRGS * nrgs,int lowSubband,int highSubband,FIXP_DBL * ptrSumRef,SCHAR * ptrSumRef_e,FIXP_DBL * ptrAvgGain,SCHAR * ptrAvgGain_e)2344*e5436536SAndroid Build Coastguard Worker static void calcAvgGain(
2345*e5436536SAndroid Build Coastguard Worker     ENV_CALC_NRGS *nrgs, int lowSubband, /*!< Begin of the limiter band */
2346*e5436536SAndroid Build Coastguard Worker     int highSubband,                     /*!< High end of the limiter band */
2347*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *ptrSumRef, SCHAR *ptrSumRef_e,
2348*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *ptrAvgGain, /*!< Resulting overall gain (mantissa) */
2349*e5436536SAndroid Build Coastguard Worker     SCHAR *ptrAvgGain_e)  /*!< Resulting overall gain (exponent) */
2350*e5436536SAndroid Build Coastguard Worker {
2351*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *nrgRef =
2352*e5436536SAndroid Build Coastguard Worker       nrgs->nrgRef; /*!< Reference Energy according to envelope data */
2353*e5436536SAndroid Build Coastguard Worker   SCHAR *nrgRef_e =
2354*e5436536SAndroid Build Coastguard Worker       nrgs->nrgRef_e; /*!< Reference Energy according to envelope data
2355*e5436536SAndroid Build Coastguard Worker                          (exponent) */
2356*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *nrgEst = nrgs->nrgEst; /*!< Energy in transposed signal */
2357*e5436536SAndroid Build Coastguard Worker   SCHAR *nrgEst_e =
2358*e5436536SAndroid Build Coastguard Worker       nrgs->nrgEst_e; /*!< Energy in transposed signal (exponent) */
2359*e5436536SAndroid Build Coastguard Worker 
2360*e5436536SAndroid Build Coastguard Worker   FIXP_DBL sumRef = 1;
2361*e5436536SAndroid Build Coastguard Worker   FIXP_DBL sumEst = 1;
2362*e5436536SAndroid Build Coastguard Worker   SCHAR sumRef_e = -FRACT_BITS;
2363*e5436536SAndroid Build Coastguard Worker   SCHAR sumEst_e = -FRACT_BITS;
2364*e5436536SAndroid Build Coastguard Worker   int k;
2365*e5436536SAndroid Build Coastguard Worker 
2366*e5436536SAndroid Build Coastguard Worker   for (k = lowSubband; k < highSubband; k++) {
2367*e5436536SAndroid Build Coastguard Worker     /* Add nrgRef[k] to sumRef: */
2368*e5436536SAndroid Build Coastguard Worker     FDK_add_MantExp(sumRef, sumRef_e, nrgRef[k], nrgRef_e[k], &sumRef,
2369*e5436536SAndroid Build Coastguard Worker                     &sumRef_e);
2370*e5436536SAndroid Build Coastguard Worker 
2371*e5436536SAndroid Build Coastguard Worker     /* Add nrgEst[k] to sumEst: */
2372*e5436536SAndroid Build Coastguard Worker     FDK_add_MantExp(sumEst, sumEst_e, nrgEst[k], nrgEst_e[k], &sumEst,
2373*e5436536SAndroid Build Coastguard Worker                     &sumEst_e);
2374*e5436536SAndroid Build Coastguard Worker   }
2375*e5436536SAndroid Build Coastguard Worker 
2376*e5436536SAndroid Build Coastguard Worker   FDK_divide_MantExp(sumRef, sumRef_e, sumEst, sumEst_e, ptrAvgGain,
2377*e5436536SAndroid Build Coastguard Worker                      ptrAvgGain_e);
2378*e5436536SAndroid Build Coastguard Worker 
2379*e5436536SAndroid Build Coastguard Worker   *ptrSumRef = sumRef;
2380*e5436536SAndroid Build Coastguard Worker   *ptrSumRef_e = sumRef_e;
2381*e5436536SAndroid Build Coastguard Worker }
2382*e5436536SAndroid Build Coastguard Worker 
adjustTimeSlot_EldGrid(FIXP_DBL * RESTRICT ptrReal,ENV_CALC_NRGS * nrgs,UCHAR * ptrHarmIndex,int lowSubband,int noSubbands,int scale_change,int noNoiseFlag,int * ptrPhaseIndex,int scale_diff_low)2383*e5436536SAndroid Build Coastguard Worker static void adjustTimeSlot_EldGrid(
2384*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *RESTRICT
2385*e5436536SAndroid Build Coastguard Worker         ptrReal, /*!< Subband samples to be adjusted, real part */
2386*e5436536SAndroid Build Coastguard Worker     ENV_CALC_NRGS *nrgs, UCHAR *ptrHarmIndex, /*!< Harmonic index */
2387*e5436536SAndroid Build Coastguard Worker     int lowSubband, /*!< Lowest QMF-channel in the currently used SBR range. */
2388*e5436536SAndroid Build Coastguard Worker     int noSubbands, /*!< Number of QMF subbands */
2389*e5436536SAndroid Build Coastguard Worker     int scale_change,   /*!< Number of bits to shift adjusted samples */
2390*e5436536SAndroid Build Coastguard Worker     int noNoiseFlag,    /*!< Flag to suppress noise addition */
2391*e5436536SAndroid Build Coastguard Worker     int *ptrPhaseIndex, /*!< Start index to random number array */
2392*e5436536SAndroid Build Coastguard Worker     int scale_diff_low) /*!<  */
2393*e5436536SAndroid Build Coastguard Worker 
2394*e5436536SAndroid Build Coastguard Worker {
2395*e5436536SAndroid Build Coastguard Worker   int k;
2396*e5436536SAndroid Build Coastguard Worker   FIXP_DBL signalReal, sbNoise;
2397*e5436536SAndroid Build Coastguard Worker   int tone_count = 0;
2398*e5436536SAndroid Build Coastguard Worker 
2399*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *pGain = nrgs->nrgGain; /*!< Gains of current envelope */
2400*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *RESTRICT pNoiseLevel =
2401*e5436536SAndroid Build Coastguard Worker       nrgs->noiseLevel; /*!< Noise levels of current envelope */
2402*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *RESTRICT pSineLevel = nrgs->nrgSine; /*!< Sine levels */
2403*e5436536SAndroid Build Coastguard Worker 
2404*e5436536SAndroid Build Coastguard Worker   int phaseIndex = *ptrPhaseIndex;
2405*e5436536SAndroid Build Coastguard Worker   UCHAR harmIndex = *ptrHarmIndex;
2406*e5436536SAndroid Build Coastguard Worker 
2407*e5436536SAndroid Build Coastguard Worker   static const INT harmonicPhase[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
2408*e5436536SAndroid Build Coastguard Worker 
2409*e5436536SAndroid Build Coastguard Worker   static const FIXP_DBL harmonicPhaseX[4][2] = {
2410*e5436536SAndroid Build Coastguard Worker       {FL2FXCONST_DBL(2.0 * 1.245183154539139e-001),
2411*e5436536SAndroid Build Coastguard Worker        FL2FXCONST_DBL(2.0 * 1.245183154539139e-001)},
2412*e5436536SAndroid Build Coastguard Worker       {FL2FXCONST_DBL(2.0 * -1.123767859325028e-001),
2413*e5436536SAndroid Build Coastguard Worker        FL2FXCONST_DBL(2.0 * 1.123767859325028e-001)},
2414*e5436536SAndroid Build Coastguard Worker       {FL2FXCONST_DBL(2.0 * -1.245183154539139e-001),
2415*e5436536SAndroid Build Coastguard Worker        FL2FXCONST_DBL(2.0 * -1.245183154539139e-001)},
2416*e5436536SAndroid Build Coastguard Worker       {FL2FXCONST_DBL(2.0 * 1.123767859325028e-001),
2417*e5436536SAndroid Build Coastguard Worker        FL2FXCONST_DBL(2.0 * -1.123767859325028e-001)}};
2418*e5436536SAndroid Build Coastguard Worker 
2419*e5436536SAndroid Build Coastguard Worker   const FIXP_DBL *p_harmonicPhaseX = &harmonicPhaseX[harmIndex][0];
2420*e5436536SAndroid Build Coastguard Worker   const INT *p_harmonicPhase = &harmonicPhase[harmIndex][0];
2421*e5436536SAndroid Build Coastguard Worker 
2422*e5436536SAndroid Build Coastguard Worker   const FIXP_DBL max_val = MAX_VAL_NRG_HEADROOM >> scale_change;
2423*e5436536SAndroid Build Coastguard Worker   const FIXP_DBL min_val = -max_val;
2424*e5436536SAndroid Build Coastguard Worker 
2425*e5436536SAndroid Build Coastguard Worker   *(ptrReal - 1) = fAddSaturate(
2426*e5436536SAndroid Build Coastguard Worker       *(ptrReal - 1),
2427*e5436536SAndroid Build Coastguard Worker       SATURATE_SHIFT(fMultDiv2(p_harmonicPhaseX[lowSubband & 1], pSineLevel[0]),
2428*e5436536SAndroid Build Coastguard Worker                      scale_diff_low, DFRACT_BITS));
2429*e5436536SAndroid Build Coastguard Worker   FIXP_DBL pSineLevel_prev = (FIXP_DBL)0;
2430*e5436536SAndroid Build Coastguard Worker 
2431*e5436536SAndroid Build Coastguard Worker   int idx_k = lowSubband & 1;
2432*e5436536SAndroid Build Coastguard Worker 
2433*e5436536SAndroid Build Coastguard Worker   for (k = 0; k < noSubbands; k++) {
2434*e5436536SAndroid Build Coastguard Worker     FIXP_DBL sineLevel_curr = *pSineLevel++;
2435*e5436536SAndroid Build Coastguard Worker     phaseIndex = (phaseIndex + 1) & (SBR_NF_NO_RANDOM_VAL - 1);
2436*e5436536SAndroid Build Coastguard Worker 
2437*e5436536SAndroid Build Coastguard Worker     signalReal = fMax(fMin(fMultDiv2(*ptrReal, *pGain++), max_val), min_val)
2438*e5436536SAndroid Build Coastguard Worker                  << scale_change;
2439*e5436536SAndroid Build Coastguard Worker     sbNoise = *pNoiseLevel++;
2440*e5436536SAndroid Build Coastguard Worker     if (((INT)sineLevel_curr | noNoiseFlag) == 0) {
2441*e5436536SAndroid Build Coastguard Worker       signalReal +=
2442*e5436536SAndroid Build Coastguard Worker           fMult(FDK_sbrDecoder_sbr_randomPhase[phaseIndex][0], sbNoise);
2443*e5436536SAndroid Build Coastguard Worker     }
2444*e5436536SAndroid Build Coastguard Worker     signalReal += sineLevel_curr * p_harmonicPhase[0];
2445*e5436536SAndroid Build Coastguard Worker     signalReal =
2446*e5436536SAndroid Build Coastguard Worker         fMultAddDiv2(signalReal, pSineLevel_prev, p_harmonicPhaseX[idx_k]);
2447*e5436536SAndroid Build Coastguard Worker     pSineLevel_prev = sineLevel_curr;
2448*e5436536SAndroid Build Coastguard Worker     idx_k = !idx_k;
2449*e5436536SAndroid Build Coastguard Worker     if (k < noSubbands - 1) {
2450*e5436536SAndroid Build Coastguard Worker       signalReal =
2451*e5436536SAndroid Build Coastguard Worker           fMultAddDiv2(signalReal, pSineLevel[0], p_harmonicPhaseX[idx_k]);
2452*e5436536SAndroid Build Coastguard Worker     } else /* (k == noSubbands - 1)  */
2453*e5436536SAndroid Build Coastguard Worker     {
2454*e5436536SAndroid Build Coastguard Worker       if (k + lowSubband + 1 < 63) {
2455*e5436536SAndroid Build Coastguard Worker         *(ptrReal + 1) += fMultDiv2(pSineLevel_prev, p_harmonicPhaseX[idx_k]);
2456*e5436536SAndroid Build Coastguard Worker       }
2457*e5436536SAndroid Build Coastguard Worker     }
2458*e5436536SAndroid Build Coastguard Worker     *ptrReal++ = signalReal;
2459*e5436536SAndroid Build Coastguard Worker 
2460*e5436536SAndroid Build Coastguard Worker     if (pSineLevel_prev != FL2FXCONST_DBL(0.0f)) {
2461*e5436536SAndroid Build Coastguard Worker       if (++tone_count == 16) {
2462*e5436536SAndroid Build Coastguard Worker         k++;
2463*e5436536SAndroid Build Coastguard Worker         break;
2464*e5436536SAndroid Build Coastguard Worker       }
2465*e5436536SAndroid Build Coastguard Worker     }
2466*e5436536SAndroid Build Coastguard Worker   }
2467*e5436536SAndroid Build Coastguard Worker   /* Run again, if previous loop got breaked with tone_count = 16 */
2468*e5436536SAndroid Build Coastguard Worker   for (; k < noSubbands; k++) {
2469*e5436536SAndroid Build Coastguard Worker     FIXP_DBL sineLevel_curr = *pSineLevel++;
2470*e5436536SAndroid Build Coastguard Worker     phaseIndex = (phaseIndex + 1) & (SBR_NF_NO_RANDOM_VAL - 1);
2471*e5436536SAndroid Build Coastguard Worker 
2472*e5436536SAndroid Build Coastguard Worker     signalReal = fMax(fMin(fMultDiv2(*ptrReal, *pGain++), max_val), min_val)
2473*e5436536SAndroid Build Coastguard Worker                  << scale_change;
2474*e5436536SAndroid Build Coastguard Worker     sbNoise = *pNoiseLevel++;
2475*e5436536SAndroid Build Coastguard Worker     if (((INT)sineLevel_curr | noNoiseFlag) == 0) {
2476*e5436536SAndroid Build Coastguard Worker       signalReal +=
2477*e5436536SAndroid Build Coastguard Worker           fMult(FDK_sbrDecoder_sbr_randomPhase[phaseIndex][0], sbNoise);
2478*e5436536SAndroid Build Coastguard Worker     }
2479*e5436536SAndroid Build Coastguard Worker     signalReal += sineLevel_curr * p_harmonicPhase[0];
2480*e5436536SAndroid Build Coastguard Worker     *ptrReal++ = signalReal;
2481*e5436536SAndroid Build Coastguard Worker   }
2482*e5436536SAndroid Build Coastguard Worker 
2483*e5436536SAndroid Build Coastguard Worker   *ptrHarmIndex = (harmIndex + 1) & 3;
2484*e5436536SAndroid Build Coastguard Worker   *ptrPhaseIndex = phaseIndex & (SBR_NF_NO_RANDOM_VAL - 1);
2485*e5436536SAndroid Build Coastguard Worker }
2486*e5436536SAndroid Build Coastguard Worker 
2487*e5436536SAndroid Build Coastguard Worker /*!
2488*e5436536SAndroid Build Coastguard Worker   \brief   Amplify one timeslot of the signal with the calculated gains
2489*e5436536SAndroid Build Coastguard Worker            and add the noisefloor.
2490*e5436536SAndroid Build Coastguard Worker */
2491*e5436536SAndroid Build Coastguard Worker 
adjustTimeSlotLC(FIXP_DBL * ptrReal,ENV_CALC_NRGS * nrgs,UCHAR * ptrHarmIndex,int lowSubband,int noSubbands,int scale_change,int noNoiseFlag,int * ptrPhaseIndex)2492*e5436536SAndroid Build Coastguard Worker static void adjustTimeSlotLC(
2493*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *ptrReal, /*!< Subband samples to be adjusted, real part */
2494*e5436536SAndroid Build Coastguard Worker     ENV_CALC_NRGS *nrgs, UCHAR *ptrHarmIndex, /*!< Harmonic index */
2495*e5436536SAndroid Build Coastguard Worker     int lowSubband, /*!< Lowest QMF-channel in the currently used SBR range. */
2496*e5436536SAndroid Build Coastguard Worker     int noSubbands, /*!< Number of QMF subbands */
2497*e5436536SAndroid Build Coastguard Worker     int scale_change,   /*!< Number of bits to shift adjusted samples */
2498*e5436536SAndroid Build Coastguard Worker     int noNoiseFlag,    /*!< Flag to suppress noise addition */
2499*e5436536SAndroid Build Coastguard Worker     int *ptrPhaseIndex) /*!< Start index to random number array */
2500*e5436536SAndroid Build Coastguard Worker {
2501*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *pGain = nrgs->nrgGain; /*!< Gains of current envelope */
2502*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *pNoiseLevel =
2503*e5436536SAndroid Build Coastguard Worker       nrgs->noiseLevel;                 /*!< Noise levels of current envelope */
2504*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *pSineLevel = nrgs->nrgSine; /*!< Sine levels */
2505*e5436536SAndroid Build Coastguard Worker 
2506*e5436536SAndroid Build Coastguard Worker   int k;
2507*e5436536SAndroid Build Coastguard Worker   int index = *ptrPhaseIndex;
2508*e5436536SAndroid Build Coastguard Worker   UCHAR harmIndex = *ptrHarmIndex;
2509*e5436536SAndroid Build Coastguard Worker   UCHAR freqInvFlag = (lowSubband & 1);
2510*e5436536SAndroid Build Coastguard Worker   FIXP_DBL signalReal, sineLevel, sineLevelNext, sineLevelPrev;
2511*e5436536SAndroid Build Coastguard Worker   int tone_count = 0;
2512*e5436536SAndroid Build Coastguard Worker   int sineSign = 1;
2513*e5436536SAndroid Build Coastguard Worker   const FIXP_DBL max_val = MAX_VAL_NRG_HEADROOM >> scale_change;
2514*e5436536SAndroid Build Coastguard Worker   const FIXP_DBL min_val = -max_val;
2515*e5436536SAndroid Build Coastguard Worker 
2516*e5436536SAndroid Build Coastguard Worker #define C1 ((FIXP_SGL)FL2FXCONST_SGL(2.f * 0.00815f))
2517*e5436536SAndroid Build Coastguard Worker #define C1_CLDFB ((FIXP_SGL)FL2FXCONST_SGL(2.f * 0.16773f))
2518*e5436536SAndroid Build Coastguard Worker 
2519*e5436536SAndroid Build Coastguard Worker   /*
2520*e5436536SAndroid Build Coastguard Worker     First pass for k=0 pulled out of the loop:
2521*e5436536SAndroid Build Coastguard Worker   */
2522*e5436536SAndroid Build Coastguard Worker 
2523*e5436536SAndroid Build Coastguard Worker   index = (index + 1) & (SBR_NF_NO_RANDOM_VAL - 1);
2524*e5436536SAndroid Build Coastguard Worker 
2525*e5436536SAndroid Build Coastguard Worker   /*
2526*e5436536SAndroid Build Coastguard Worker     The next multiplication constitutes the actual envelope adjustment
2527*e5436536SAndroid Build Coastguard Worker     of the signal and should be carried out with full accuracy
2528*e5436536SAndroid Build Coastguard Worker     (supplying #FRACT_BITS valid bits).
2529*e5436536SAndroid Build Coastguard Worker   */
2530*e5436536SAndroid Build Coastguard Worker   signalReal = fMax(fMin(fMultDiv2(*ptrReal, *pGain++), max_val), min_val)
2531*e5436536SAndroid Build Coastguard Worker                << scale_change;
2532*e5436536SAndroid Build Coastguard Worker   sineLevel = *pSineLevel++;
2533*e5436536SAndroid Build Coastguard Worker   sineLevelNext = (noSubbands > 1) ? pSineLevel[0] : FL2FXCONST_DBL(0.0f);
2534*e5436536SAndroid Build Coastguard Worker 
2535*e5436536SAndroid Build Coastguard Worker   if (sineLevel != FL2FXCONST_DBL(0.0f))
2536*e5436536SAndroid Build Coastguard Worker     tone_count++;
2537*e5436536SAndroid Build Coastguard Worker   else if (!noNoiseFlag)
2538*e5436536SAndroid Build Coastguard Worker     /* Add noisefloor to the amplified signal */
2539*e5436536SAndroid Build Coastguard Worker     signalReal +=
2540*e5436536SAndroid Build Coastguard Worker         fMult(FDK_sbrDecoder_sbr_randomPhase[index][0], pNoiseLevel[0]);
2541*e5436536SAndroid Build Coastguard Worker 
2542*e5436536SAndroid Build Coastguard Worker   {
2543*e5436536SAndroid Build Coastguard Worker     if (!(harmIndex & 0x1)) {
2544*e5436536SAndroid Build Coastguard Worker       /* harmIndex 0,2 */
2545*e5436536SAndroid Build Coastguard Worker       signalReal += (harmIndex & 0x2) ? -sineLevel : sineLevel;
2546*e5436536SAndroid Build Coastguard Worker       *ptrReal++ = signalReal;
2547*e5436536SAndroid Build Coastguard Worker     } else {
2548*e5436536SAndroid Build Coastguard Worker       /* harmIndex 1,3 in combination with freqInvFlag */
2549*e5436536SAndroid Build Coastguard Worker       int shift = (int)(scale_change + 1);
2550*e5436536SAndroid Build Coastguard Worker       shift = (shift >= 0) ? fixMin(DFRACT_BITS - 1, shift)
2551*e5436536SAndroid Build Coastguard Worker                            : fixMax(-(DFRACT_BITS - 1), shift);
2552*e5436536SAndroid Build Coastguard Worker 
2553*e5436536SAndroid Build Coastguard Worker       FIXP_DBL tmp1 = (shift >= 0) ? (fMultDiv2(C1, sineLevel) >> shift)
2554*e5436536SAndroid Build Coastguard Worker                                    : (fMultDiv2(C1, sineLevel) << (-shift));
2555*e5436536SAndroid Build Coastguard Worker       FIXP_DBL tmp2 = fMultDiv2(C1, sineLevelNext);
2556*e5436536SAndroid Build Coastguard Worker 
2557*e5436536SAndroid Build Coastguard Worker       /* save switch and compare operations and reduce to XOR statement */
2558*e5436536SAndroid Build Coastguard Worker       if (((harmIndex >> 1) & 0x1) ^ freqInvFlag) {
2559*e5436536SAndroid Build Coastguard Worker         *(ptrReal - 1) = fAddSaturate(*(ptrReal - 1), tmp1);
2560*e5436536SAndroid Build Coastguard Worker         signalReal -= tmp2;
2561*e5436536SAndroid Build Coastguard Worker       } else {
2562*e5436536SAndroid Build Coastguard Worker         *(ptrReal - 1) = fAddSaturate(*(ptrReal - 1), -tmp1);
2563*e5436536SAndroid Build Coastguard Worker         signalReal += tmp2;
2564*e5436536SAndroid Build Coastguard Worker       }
2565*e5436536SAndroid Build Coastguard Worker       *ptrReal++ = signalReal;
2566*e5436536SAndroid Build Coastguard Worker       freqInvFlag = !freqInvFlag;
2567*e5436536SAndroid Build Coastguard Worker     }
2568*e5436536SAndroid Build Coastguard Worker   }
2569*e5436536SAndroid Build Coastguard Worker 
2570*e5436536SAndroid Build Coastguard Worker   pNoiseLevel++;
2571*e5436536SAndroid Build Coastguard Worker 
2572*e5436536SAndroid Build Coastguard Worker   if (noSubbands > 2) {
2573*e5436536SAndroid Build Coastguard Worker     if (!(harmIndex & 0x1)) {
2574*e5436536SAndroid Build Coastguard Worker       /* harmIndex 0,2 */
2575*e5436536SAndroid Build Coastguard Worker       if (!harmIndex) {
2576*e5436536SAndroid Build Coastguard Worker         sineSign = 0;
2577*e5436536SAndroid Build Coastguard Worker       }
2578*e5436536SAndroid Build Coastguard Worker 
2579*e5436536SAndroid Build Coastguard Worker       for (k = noSubbands - 2; k != 0; k--) {
2580*e5436536SAndroid Build Coastguard Worker         FIXP_DBL sinelevel = *pSineLevel++;
2581*e5436536SAndroid Build Coastguard Worker         index++;
2582*e5436536SAndroid Build Coastguard Worker         if (((signalReal = (sineSign ? -sinelevel : sinelevel)) ==
2583*e5436536SAndroid Build Coastguard Worker              FL2FXCONST_DBL(0.0f)) &&
2584*e5436536SAndroid Build Coastguard Worker             !noNoiseFlag) {
2585*e5436536SAndroid Build Coastguard Worker           /* Add noisefloor to the amplified signal */
2586*e5436536SAndroid Build Coastguard Worker           index &= (SBR_NF_NO_RANDOM_VAL - 1);
2587*e5436536SAndroid Build Coastguard Worker           signalReal +=
2588*e5436536SAndroid Build Coastguard Worker               fMult(FDK_sbrDecoder_sbr_randomPhase[index][0], pNoiseLevel[0]);
2589*e5436536SAndroid Build Coastguard Worker         }
2590*e5436536SAndroid Build Coastguard Worker 
2591*e5436536SAndroid Build Coastguard Worker         /* The next multiplication constitutes the actual envelope adjustment of
2592*e5436536SAndroid Build Coastguard Worker          * the signal. */
2593*e5436536SAndroid Build Coastguard Worker         signalReal +=
2594*e5436536SAndroid Build Coastguard Worker             fMax(fMin(fMultDiv2(*ptrReal, *pGain++), max_val), min_val)
2595*e5436536SAndroid Build Coastguard Worker             << scale_change;
2596*e5436536SAndroid Build Coastguard Worker 
2597*e5436536SAndroid Build Coastguard Worker         pNoiseLevel++;
2598*e5436536SAndroid Build Coastguard Worker         *ptrReal++ = signalReal;
2599*e5436536SAndroid Build Coastguard Worker       } /* for ... */
2600*e5436536SAndroid Build Coastguard Worker     } else {
2601*e5436536SAndroid Build Coastguard Worker       /* harmIndex 1,3 in combination with freqInvFlag */
2602*e5436536SAndroid Build Coastguard Worker       if (harmIndex == 1) freqInvFlag = !freqInvFlag;
2603*e5436536SAndroid Build Coastguard Worker 
2604*e5436536SAndroid Build Coastguard Worker       for (k = noSubbands - 2; k != 0; k--) {
2605*e5436536SAndroid Build Coastguard Worker         index++;
2606*e5436536SAndroid Build Coastguard Worker         /* The next multiplication constitutes the actual envelope adjustment of
2607*e5436536SAndroid Build Coastguard Worker          * the signal. */
2608*e5436536SAndroid Build Coastguard Worker         signalReal = fMax(fMin(fMultDiv2(*ptrReal, *pGain++), max_val), min_val)
2609*e5436536SAndroid Build Coastguard Worker                      << scale_change;
2610*e5436536SAndroid Build Coastguard Worker 
2611*e5436536SAndroid Build Coastguard Worker         if (*pSineLevel++ != FL2FXCONST_DBL(0.0f))
2612*e5436536SAndroid Build Coastguard Worker           tone_count++;
2613*e5436536SAndroid Build Coastguard Worker         else if (!noNoiseFlag) {
2614*e5436536SAndroid Build Coastguard Worker           /* Add noisefloor to the amplified signal */
2615*e5436536SAndroid Build Coastguard Worker           index &= (SBR_NF_NO_RANDOM_VAL - 1);
2616*e5436536SAndroid Build Coastguard Worker           signalReal +=
2617*e5436536SAndroid Build Coastguard Worker               fMult(FDK_sbrDecoder_sbr_randomPhase[index][0], pNoiseLevel[0]);
2618*e5436536SAndroid Build Coastguard Worker         }
2619*e5436536SAndroid Build Coastguard Worker 
2620*e5436536SAndroid Build Coastguard Worker         pNoiseLevel++;
2621*e5436536SAndroid Build Coastguard Worker 
2622*e5436536SAndroid Build Coastguard Worker         if (tone_count <= 16) {
2623*e5436536SAndroid Build Coastguard Worker           FIXP_DBL addSine = fMultDiv2((pSineLevel[-2] - pSineLevel[0]), C1);
2624*e5436536SAndroid Build Coastguard Worker           signalReal += (freqInvFlag) ? (-addSine) : (addSine);
2625*e5436536SAndroid Build Coastguard Worker         }
2626*e5436536SAndroid Build Coastguard Worker 
2627*e5436536SAndroid Build Coastguard Worker         *ptrReal++ = signalReal;
2628*e5436536SAndroid Build Coastguard Worker         freqInvFlag = !freqInvFlag;
2629*e5436536SAndroid Build Coastguard Worker       } /* for ... */
2630*e5436536SAndroid Build Coastguard Worker     }
2631*e5436536SAndroid Build Coastguard Worker   }
2632*e5436536SAndroid Build Coastguard Worker 
2633*e5436536SAndroid Build Coastguard Worker   if (noSubbands > -1) {
2634*e5436536SAndroid Build Coastguard Worker     index++;
2635*e5436536SAndroid Build Coastguard Worker     /* The next multiplication constitutes the actual envelope adjustment of the
2636*e5436536SAndroid Build Coastguard Worker      * signal. */
2637*e5436536SAndroid Build Coastguard Worker     signalReal = fMax(fMin(fMultDiv2(*ptrReal, *pGain), max_val), min_val)
2638*e5436536SAndroid Build Coastguard Worker                  << scale_change;
2639*e5436536SAndroid Build Coastguard Worker     sineLevelPrev = fMultDiv2(pSineLevel[-1], FL2FX_SGL(0.0163f));
2640*e5436536SAndroid Build Coastguard Worker     sineLevel = pSineLevel[0];
2641*e5436536SAndroid Build Coastguard Worker 
2642*e5436536SAndroid Build Coastguard Worker     if (pSineLevel[0] != FL2FXCONST_DBL(0.0f))
2643*e5436536SAndroid Build Coastguard Worker       tone_count++;
2644*e5436536SAndroid Build Coastguard Worker     else if (!noNoiseFlag) {
2645*e5436536SAndroid Build Coastguard Worker       /* Add noisefloor to the amplified signal */
2646*e5436536SAndroid Build Coastguard Worker       index &= (SBR_NF_NO_RANDOM_VAL - 1);
2647*e5436536SAndroid Build Coastguard Worker       signalReal = signalReal + fMult(FDK_sbrDecoder_sbr_randomPhase[index][0],
2648*e5436536SAndroid Build Coastguard Worker                                       pNoiseLevel[0]);
2649*e5436536SAndroid Build Coastguard Worker     }
2650*e5436536SAndroid Build Coastguard Worker 
2651*e5436536SAndroid Build Coastguard Worker     if (!(harmIndex & 0x1)) {
2652*e5436536SAndroid Build Coastguard Worker       /* harmIndex 0,2 */
2653*e5436536SAndroid Build Coastguard Worker       *ptrReal = signalReal + ((sineSign) ? -sineLevel : sineLevel);
2654*e5436536SAndroid Build Coastguard Worker     } else {
2655*e5436536SAndroid Build Coastguard Worker       /* harmIndex 1,3 in combination with freqInvFlag */
2656*e5436536SAndroid Build Coastguard Worker       if (tone_count <= 16) {
2657*e5436536SAndroid Build Coastguard Worker         if (freqInvFlag) {
2658*e5436536SAndroid Build Coastguard Worker           *ptrReal++ = signalReal - sineLevelPrev;
2659*e5436536SAndroid Build Coastguard Worker           if (noSubbands + lowSubband < 63)
2660*e5436536SAndroid Build Coastguard Worker             *ptrReal = *ptrReal + fMultDiv2(C1, sineLevel);
2661*e5436536SAndroid Build Coastguard Worker         } else {
2662*e5436536SAndroid Build Coastguard Worker           *ptrReal++ = signalReal + sineLevelPrev;
2663*e5436536SAndroid Build Coastguard Worker           if (noSubbands + lowSubband < 63)
2664*e5436536SAndroid Build Coastguard Worker             *ptrReal = *ptrReal - fMultDiv2(C1, sineLevel);
2665*e5436536SAndroid Build Coastguard Worker         }
2666*e5436536SAndroid Build Coastguard Worker       } else
2667*e5436536SAndroid Build Coastguard Worker         *ptrReal = signalReal;
2668*e5436536SAndroid Build Coastguard Worker     }
2669*e5436536SAndroid Build Coastguard Worker   }
2670*e5436536SAndroid Build Coastguard Worker   *ptrHarmIndex = (harmIndex + 1) & 3;
2671*e5436536SAndroid Build Coastguard Worker   *ptrPhaseIndex = index & (SBR_NF_NO_RANDOM_VAL - 1);
2672*e5436536SAndroid Build Coastguard Worker }
2673*e5436536SAndroid Build Coastguard Worker 
adjustTimeSlotHQ_GainAndNoise(FIXP_DBL * RESTRICT ptrReal,FIXP_DBL * RESTRICT ptrImag,HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env,ENV_CALC_NRGS * nrgs,int lowSubband,int noSubbands,int scale_change,FIXP_SGL smooth_ratio,int noNoiseFlag,int filtBufferNoiseShift)2674*e5436536SAndroid Build Coastguard Worker static void adjustTimeSlotHQ_GainAndNoise(
2675*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *RESTRICT
2676*e5436536SAndroid Build Coastguard Worker         ptrReal, /*!< Subband samples to be adjusted, real part */
2677*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *RESTRICT
2678*e5436536SAndroid Build Coastguard Worker         ptrImag, /*!< Subband samples to be adjusted, imag part */
2679*e5436536SAndroid Build Coastguard Worker     HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env, ENV_CALC_NRGS *nrgs,
2680*e5436536SAndroid Build Coastguard Worker     int lowSubband, /*!< Lowest QMF-channel in the currently used SBR range. */
2681*e5436536SAndroid Build Coastguard Worker     int noSubbands, /*!< Number of QMF subbands */
2682*e5436536SAndroid Build Coastguard Worker     int scale_change,         /*!< Number of bits to shift adjusted samples */
2683*e5436536SAndroid Build Coastguard Worker     FIXP_SGL smooth_ratio,    /*!< Impact of last envelope */
2684*e5436536SAndroid Build Coastguard Worker     int noNoiseFlag,          /*!< Start index to random number array */
2685*e5436536SAndroid Build Coastguard Worker     int filtBufferNoiseShift) /*!< Shift factor of filtBufferNoise */
2686*e5436536SAndroid Build Coastguard Worker {
2687*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *RESTRICT gain = nrgs->nrgGain; /*!< Gains of current envelope */
2688*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *RESTRICT noiseLevel =
2689*e5436536SAndroid Build Coastguard Worker       nrgs->noiseLevel; /*!< Noise levels of current envelope */
2690*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *RESTRICT pSineLevel = nrgs->nrgSine; /*!< Sine levels */
2691*e5436536SAndroid Build Coastguard Worker 
2692*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *RESTRICT filtBuffer =
2693*e5436536SAndroid Build Coastguard Worker       h_sbr_cal_env->filtBuffer; /*!< Gains of last envelope */
2694*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *RESTRICT filtBufferNoise =
2695*e5436536SAndroid Build Coastguard Worker       h_sbr_cal_env->filtBufferNoise; /*!< Noise levels of last envelope */
2696*e5436536SAndroid Build Coastguard Worker   int *RESTRICT ptrPhaseIndex =
2697*e5436536SAndroid Build Coastguard Worker       &h_sbr_cal_env->phaseIndex; /*!< Start index to random number array */
2698*e5436536SAndroid Build Coastguard Worker 
2699*e5436536SAndroid Build Coastguard Worker   int k;
2700*e5436536SAndroid Build Coastguard Worker   FIXP_DBL signalReal, signalImag;
2701*e5436536SAndroid Build Coastguard Worker   FIXP_DBL noiseReal, noiseImag;
2702*e5436536SAndroid Build Coastguard Worker   FIXP_DBL smoothedGain, smoothedNoise;
2703*e5436536SAndroid Build Coastguard Worker   FIXP_SGL direct_ratio =
2704*e5436536SAndroid Build Coastguard Worker       /*FL2FXCONST_SGL(1.0f) */ (FIXP_SGL)MAXVAL_SGL - smooth_ratio;
2705*e5436536SAndroid Build Coastguard Worker   int index = *ptrPhaseIndex;
2706*e5436536SAndroid Build Coastguard Worker   int shift;
2707*e5436536SAndroid Build Coastguard Worker   FIXP_DBL max_val_noise = 0, min_val_noise = 0;
2708*e5436536SAndroid Build Coastguard Worker   const FIXP_DBL max_val = MAX_VAL_NRG_HEADROOM >> scale_change;
2709*e5436536SAndroid Build Coastguard Worker   const FIXP_DBL min_val = -max_val;
2710*e5436536SAndroid Build Coastguard Worker 
2711*e5436536SAndroid Build Coastguard Worker   *ptrPhaseIndex = (index + noSubbands) & (SBR_NF_NO_RANDOM_VAL - 1);
2712*e5436536SAndroid Build Coastguard Worker 
2713*e5436536SAndroid Build Coastguard Worker   filtBufferNoiseShift +=
2714*e5436536SAndroid Build Coastguard Worker       1; /* due to later use of fMultDiv2 instead of fMult */
2715*e5436536SAndroid Build Coastguard Worker   if (filtBufferNoiseShift < 0) {
2716*e5436536SAndroid Build Coastguard Worker     shift = fixMin(DFRACT_BITS - 1, -filtBufferNoiseShift);
2717*e5436536SAndroid Build Coastguard Worker   } else {
2718*e5436536SAndroid Build Coastguard Worker     shift = fixMin(DFRACT_BITS - 1, filtBufferNoiseShift);
2719*e5436536SAndroid Build Coastguard Worker     max_val_noise = MAX_VAL_NRG_HEADROOM >> shift;
2720*e5436536SAndroid Build Coastguard Worker     min_val_noise = -max_val_noise;
2721*e5436536SAndroid Build Coastguard Worker   }
2722*e5436536SAndroid Build Coastguard Worker 
2723*e5436536SAndroid Build Coastguard Worker   if (smooth_ratio > FL2FXCONST_SGL(0.0f)) {
2724*e5436536SAndroid Build Coastguard Worker     for (k = 0; k < noSubbands; k++) {
2725*e5436536SAndroid Build Coastguard Worker       /*
2726*e5436536SAndroid Build Coastguard Worker         Smoothing: The old envelope has been bufferd and a certain ratio
2727*e5436536SAndroid Build Coastguard Worker         of the old gains and noise levels is used.
2728*e5436536SAndroid Build Coastguard Worker       */
2729*e5436536SAndroid Build Coastguard Worker       smoothedGain =
2730*e5436536SAndroid Build Coastguard Worker           fMult(smooth_ratio, filtBuffer[k]) + fMult(direct_ratio, gain[k]);
2731*e5436536SAndroid Build Coastguard Worker 
2732*e5436536SAndroid Build Coastguard Worker       if (filtBufferNoiseShift < 0) {
2733*e5436536SAndroid Build Coastguard Worker         smoothedNoise = (fMultDiv2(smooth_ratio, filtBufferNoise[k]) >> shift) +
2734*e5436536SAndroid Build Coastguard Worker                         fMult(direct_ratio, noiseLevel[k]);
2735*e5436536SAndroid Build Coastguard Worker       } else {
2736*e5436536SAndroid Build Coastguard Worker         smoothedNoise = fMultDiv2(smooth_ratio, filtBufferNoise[k]);
2737*e5436536SAndroid Build Coastguard Worker         smoothedNoise =
2738*e5436536SAndroid Build Coastguard Worker             (fMax(fMin(smoothedNoise, max_val_noise), min_val_noise) << shift) +
2739*e5436536SAndroid Build Coastguard Worker             fMult(direct_ratio, noiseLevel[k]);
2740*e5436536SAndroid Build Coastguard Worker       }
2741*e5436536SAndroid Build Coastguard Worker 
2742*e5436536SAndroid Build Coastguard Worker       smoothedNoise = fMax(fMin(smoothedNoise, (FIXP_DBL)(MAXVAL_DBL / 2)),
2743*e5436536SAndroid Build Coastguard Worker                            (FIXP_DBL)(MINVAL_DBL / 2));
2744*e5436536SAndroid Build Coastguard Worker 
2745*e5436536SAndroid Build Coastguard Worker       /*
2746*e5436536SAndroid Build Coastguard Worker         The next 2 multiplications constitute the actual envelope adjustment
2747*e5436536SAndroid Build Coastguard Worker         of the signal and should be carried out with full accuracy
2748*e5436536SAndroid Build Coastguard Worker         (supplying #DFRACT_BITS valid bits).
2749*e5436536SAndroid Build Coastguard Worker       */
2750*e5436536SAndroid Build Coastguard Worker       signalReal =
2751*e5436536SAndroid Build Coastguard Worker           fMax(fMin(fMultDiv2(*ptrReal, smoothedGain), max_val), min_val)
2752*e5436536SAndroid Build Coastguard Worker           << scale_change;
2753*e5436536SAndroid Build Coastguard Worker       signalImag =
2754*e5436536SAndroid Build Coastguard Worker           fMax(fMin(fMultDiv2(*ptrImag, smoothedGain), max_val), min_val)
2755*e5436536SAndroid Build Coastguard Worker           << scale_change;
2756*e5436536SAndroid Build Coastguard Worker 
2757*e5436536SAndroid Build Coastguard Worker       index++;
2758*e5436536SAndroid Build Coastguard Worker 
2759*e5436536SAndroid Build Coastguard Worker       if ((pSineLevel[k] != FL2FXCONST_DBL(0.0f)) || noNoiseFlag) {
2760*e5436536SAndroid Build Coastguard Worker         /* Just the amplified signal is saved */
2761*e5436536SAndroid Build Coastguard Worker         *ptrReal++ = signalReal;
2762*e5436536SAndroid Build Coastguard Worker         *ptrImag++ = signalImag;
2763*e5436536SAndroid Build Coastguard Worker       } else {
2764*e5436536SAndroid Build Coastguard Worker         /* Add noisefloor to the amplified signal */
2765*e5436536SAndroid Build Coastguard Worker         index &= (SBR_NF_NO_RANDOM_VAL - 1);
2766*e5436536SAndroid Build Coastguard Worker         noiseReal =
2767*e5436536SAndroid Build Coastguard Worker             fMult(FDK_sbrDecoder_sbr_randomPhase[index][0], smoothedNoise);
2768*e5436536SAndroid Build Coastguard Worker         noiseImag =
2769*e5436536SAndroid Build Coastguard Worker             fMult(FDK_sbrDecoder_sbr_randomPhase[index][1], smoothedNoise);
2770*e5436536SAndroid Build Coastguard Worker         *ptrReal++ = (signalReal + noiseReal);
2771*e5436536SAndroid Build Coastguard Worker         *ptrImag++ = (signalImag + noiseImag);
2772*e5436536SAndroid Build Coastguard Worker       }
2773*e5436536SAndroid Build Coastguard Worker     }
2774*e5436536SAndroid Build Coastguard Worker   } else {
2775*e5436536SAndroid Build Coastguard Worker     for (k = 0; k < noSubbands; k++) {
2776*e5436536SAndroid Build Coastguard Worker       smoothedGain = gain[k];
2777*e5436536SAndroid Build Coastguard Worker       signalReal =
2778*e5436536SAndroid Build Coastguard Worker           fMax(fMin(fMultDiv2(*ptrReal, smoothedGain), max_val), min_val)
2779*e5436536SAndroid Build Coastguard Worker           << scale_change;
2780*e5436536SAndroid Build Coastguard Worker       signalImag =
2781*e5436536SAndroid Build Coastguard Worker           fMax(fMin(fMultDiv2(*ptrImag, smoothedGain), max_val), min_val)
2782*e5436536SAndroid Build Coastguard Worker           << scale_change;
2783*e5436536SAndroid Build Coastguard Worker 
2784*e5436536SAndroid Build Coastguard Worker       index++;
2785*e5436536SAndroid Build Coastguard Worker 
2786*e5436536SAndroid Build Coastguard Worker       if ((pSineLevel[k] == FL2FXCONST_DBL(0.0f)) && (noNoiseFlag == 0)) {
2787*e5436536SAndroid Build Coastguard Worker         /* Add noisefloor to the amplified signal */
2788*e5436536SAndroid Build Coastguard Worker         smoothedNoise = noiseLevel[k];
2789*e5436536SAndroid Build Coastguard Worker         index &= (SBR_NF_NO_RANDOM_VAL - 1);
2790*e5436536SAndroid Build Coastguard Worker         noiseReal =
2791*e5436536SAndroid Build Coastguard Worker             fMult(FDK_sbrDecoder_sbr_randomPhase[index][0], smoothedNoise);
2792*e5436536SAndroid Build Coastguard Worker         noiseImag =
2793*e5436536SAndroid Build Coastguard Worker             fMult(FDK_sbrDecoder_sbr_randomPhase[index][1], smoothedNoise);
2794*e5436536SAndroid Build Coastguard Worker 
2795*e5436536SAndroid Build Coastguard Worker         signalReal += noiseReal;
2796*e5436536SAndroid Build Coastguard Worker         signalImag += noiseImag;
2797*e5436536SAndroid Build Coastguard Worker       }
2798*e5436536SAndroid Build Coastguard Worker       *ptrReal++ = signalReal;
2799*e5436536SAndroid Build Coastguard Worker       *ptrImag++ = signalImag;
2800*e5436536SAndroid Build Coastguard Worker     }
2801*e5436536SAndroid Build Coastguard Worker   }
2802*e5436536SAndroid Build Coastguard Worker }
2803*e5436536SAndroid Build Coastguard Worker 
adjustTimeSlotHQ_AddHarmonics(FIXP_DBL * RESTRICT ptrReal,FIXP_DBL * RESTRICT ptrImag,HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env,ENV_CALC_NRGS * nrgs,int lowSubband,int noSubbands,int scale_change)2804*e5436536SAndroid Build Coastguard Worker static void adjustTimeSlotHQ_AddHarmonics(
2805*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *RESTRICT
2806*e5436536SAndroid Build Coastguard Worker         ptrReal, /*!< Subband samples to be adjusted, real part */
2807*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *RESTRICT
2808*e5436536SAndroid Build Coastguard Worker         ptrImag, /*!< Subband samples to be adjusted, imag part */
2809*e5436536SAndroid Build Coastguard Worker     HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env, ENV_CALC_NRGS *nrgs,
2810*e5436536SAndroid Build Coastguard Worker     int lowSubband,  /*!< Lowest QMF-channel in the currently used SBR range. */
2811*e5436536SAndroid Build Coastguard Worker     int noSubbands,  /*!< Number of QMF subbands */
2812*e5436536SAndroid Build Coastguard Worker     int scale_change /*!< Scale mismatch between QMF input and sineLevel
2813*e5436536SAndroid Build Coastguard Worker                         exponent. */
2814*e5436536SAndroid Build Coastguard Worker ) {
2815*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *RESTRICT pSineLevel = nrgs->nrgSine; /*!< Sine levels */
2816*e5436536SAndroid Build Coastguard Worker   UCHAR *RESTRICT ptrHarmIndex =
2817*e5436536SAndroid Build Coastguard Worker       &h_sbr_cal_env->harmIndex; /*!< Harmonic index */
2818*e5436536SAndroid Build Coastguard Worker 
2819*e5436536SAndroid Build Coastguard Worker   int k;
2820*e5436536SAndroid Build Coastguard Worker   FIXP_DBL signalReal, signalImag;
2821*e5436536SAndroid Build Coastguard Worker   UCHAR harmIndex = *ptrHarmIndex;
2822*e5436536SAndroid Build Coastguard Worker   int freqInvFlag = (lowSubband & 1);
2823*e5436536SAndroid Build Coastguard Worker   FIXP_DBL sineLevel;
2824*e5436536SAndroid Build Coastguard Worker 
2825*e5436536SAndroid Build Coastguard Worker   *ptrHarmIndex = (harmIndex + 1) & 3;
2826*e5436536SAndroid Build Coastguard Worker 
2827*e5436536SAndroid Build Coastguard Worker   for (k = 0; k < noSubbands; k++) {
2828*e5436536SAndroid Build Coastguard Worker     sineLevel = pSineLevel[k];
2829*e5436536SAndroid Build Coastguard Worker     freqInvFlag ^= 1;
2830*e5436536SAndroid Build Coastguard Worker     if (sineLevel != FL2FXCONST_DBL(0.f)) {
2831*e5436536SAndroid Build Coastguard Worker       signalReal = ptrReal[k];
2832*e5436536SAndroid Build Coastguard Worker       signalImag = ptrImag[k];
2833*e5436536SAndroid Build Coastguard Worker       sineLevel = scaleValue(sineLevel, scale_change);
2834*e5436536SAndroid Build Coastguard Worker       if (harmIndex & 2) {
2835*e5436536SAndroid Build Coastguard Worker         /* case 2,3 */
2836*e5436536SAndroid Build Coastguard Worker         sineLevel = -sineLevel;
2837*e5436536SAndroid Build Coastguard Worker       }
2838*e5436536SAndroid Build Coastguard Worker       if (!(harmIndex & 1)) {
2839*e5436536SAndroid Build Coastguard Worker         /* case 0,2: */
2840*e5436536SAndroid Build Coastguard Worker         ptrReal[k] = signalReal + sineLevel;
2841*e5436536SAndroid Build Coastguard Worker       } else {
2842*e5436536SAndroid Build Coastguard Worker         /* case 1,3 */
2843*e5436536SAndroid Build Coastguard Worker         if (!freqInvFlag) sineLevel = -sineLevel;
2844*e5436536SAndroid Build Coastguard Worker         ptrImag[k] = signalImag + sineLevel;
2845*e5436536SAndroid Build Coastguard Worker       }
2846*e5436536SAndroid Build Coastguard Worker     }
2847*e5436536SAndroid Build Coastguard Worker   }
2848*e5436536SAndroid Build Coastguard Worker }
2849*e5436536SAndroid Build Coastguard Worker 
adjustTimeSlotHQ(FIXP_DBL * RESTRICT ptrReal,FIXP_DBL * RESTRICT ptrImag,HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env,ENV_CALC_NRGS * nrgs,int lowSubband,int noSubbands,int scale_change,FIXP_SGL smooth_ratio,int noNoiseFlag,int filtBufferNoiseShift)2850*e5436536SAndroid Build Coastguard Worker static void adjustTimeSlotHQ(
2851*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *RESTRICT
2852*e5436536SAndroid Build Coastguard Worker         ptrReal, /*!< Subband samples to be adjusted, real part */
2853*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *RESTRICT
2854*e5436536SAndroid Build Coastguard Worker         ptrImag, /*!< Subband samples to be adjusted, imag part */
2855*e5436536SAndroid Build Coastguard Worker     HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env, ENV_CALC_NRGS *nrgs,
2856*e5436536SAndroid Build Coastguard Worker     int lowSubband, /*!< Lowest QMF-channel in the currently used SBR range. */
2857*e5436536SAndroid Build Coastguard Worker     int noSubbands, /*!< Number of QMF subbands */
2858*e5436536SAndroid Build Coastguard Worker     int scale_change,         /*!< Number of bits to shift adjusted samples */
2859*e5436536SAndroid Build Coastguard Worker     FIXP_SGL smooth_ratio,    /*!< Impact of last envelope */
2860*e5436536SAndroid Build Coastguard Worker     int noNoiseFlag,          /*!< Start index to random number array */
2861*e5436536SAndroid Build Coastguard Worker     int filtBufferNoiseShift) /*!< Shift factor of filtBufferNoise */
2862*e5436536SAndroid Build Coastguard Worker {
2863*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *RESTRICT gain = nrgs->nrgGain; /*!< Gains of current envelope */
2864*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *RESTRICT noiseLevel =
2865*e5436536SAndroid Build Coastguard Worker       nrgs->noiseLevel; /*!< Noise levels of current envelope */
2866*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *RESTRICT pSineLevel = nrgs->nrgSine; /*!< Sine levels */
2867*e5436536SAndroid Build Coastguard Worker 
2868*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *RESTRICT filtBuffer =
2869*e5436536SAndroid Build Coastguard Worker       h_sbr_cal_env->filtBuffer; /*!< Gains of last envelope */
2870*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *RESTRICT filtBufferNoise =
2871*e5436536SAndroid Build Coastguard Worker       h_sbr_cal_env->filtBufferNoise; /*!< Noise levels of last envelope */
2872*e5436536SAndroid Build Coastguard Worker   UCHAR *RESTRICT ptrHarmIndex =
2873*e5436536SAndroid Build Coastguard Worker       &h_sbr_cal_env->harmIndex; /*!< Harmonic index */
2874*e5436536SAndroid Build Coastguard Worker   int *RESTRICT ptrPhaseIndex =
2875*e5436536SAndroid Build Coastguard Worker       &h_sbr_cal_env->phaseIndex; /*!< Start index to random number array */
2876*e5436536SAndroid Build Coastguard Worker 
2877*e5436536SAndroid Build Coastguard Worker   int k;
2878*e5436536SAndroid Build Coastguard Worker   FIXP_DBL signalReal, signalImag;
2879*e5436536SAndroid Build Coastguard Worker   FIXP_DBL noiseReal, noiseImag;
2880*e5436536SAndroid Build Coastguard Worker   FIXP_DBL smoothedGain, smoothedNoise;
2881*e5436536SAndroid Build Coastguard Worker   FIXP_SGL direct_ratio =
2882*e5436536SAndroid Build Coastguard Worker       /*FL2FXCONST_SGL(1.0f) */ (FIXP_SGL)MAXVAL_SGL - smooth_ratio;
2883*e5436536SAndroid Build Coastguard Worker   int index = *ptrPhaseIndex;
2884*e5436536SAndroid Build Coastguard Worker   UCHAR harmIndex = *ptrHarmIndex;
2885*e5436536SAndroid Build Coastguard Worker   int freqInvFlag = (lowSubband & 1);
2886*e5436536SAndroid Build Coastguard Worker   FIXP_DBL sineLevel;
2887*e5436536SAndroid Build Coastguard Worker   int shift;
2888*e5436536SAndroid Build Coastguard Worker   FIXP_DBL max_val_noise = 0, min_val_noise = 0;
2889*e5436536SAndroid Build Coastguard Worker   const FIXP_DBL max_val = MAX_VAL_NRG_HEADROOM >> scale_change;
2890*e5436536SAndroid Build Coastguard Worker   const FIXP_DBL min_val = -max_val;
2891*e5436536SAndroid Build Coastguard Worker 
2892*e5436536SAndroid Build Coastguard Worker   *ptrPhaseIndex = (index + noSubbands) & (SBR_NF_NO_RANDOM_VAL - 1);
2893*e5436536SAndroid Build Coastguard Worker   *ptrHarmIndex = (harmIndex + 1) & 3;
2894*e5436536SAndroid Build Coastguard Worker 
2895*e5436536SAndroid Build Coastguard Worker   /*
2896*e5436536SAndroid Build Coastguard Worker     Possible optimization:
2897*e5436536SAndroid Build Coastguard Worker     smooth_ratio and harmIndex stay constant during the loop.
2898*e5436536SAndroid Build Coastguard Worker     It might be faster to include a separate loop in each path.
2899*e5436536SAndroid Build Coastguard Worker 
2900*e5436536SAndroid Build Coastguard Worker     the check for smooth_ratio is now outside the loop and the workload
2901*e5436536SAndroid Build Coastguard Worker     of the whole function decreased by about 20 %
2902*e5436536SAndroid Build Coastguard Worker   */
2903*e5436536SAndroid Build Coastguard Worker 
2904*e5436536SAndroid Build Coastguard Worker   filtBufferNoiseShift +=
2905*e5436536SAndroid Build Coastguard Worker       1; /* due to later use of fMultDiv2 instead of fMult */
2906*e5436536SAndroid Build Coastguard Worker   if (filtBufferNoiseShift < 0) {
2907*e5436536SAndroid Build Coastguard Worker     shift = fixMin(DFRACT_BITS - 1, -filtBufferNoiseShift);
2908*e5436536SAndroid Build Coastguard Worker   } else {
2909*e5436536SAndroid Build Coastguard Worker     shift = fixMin(DFRACT_BITS - 1, filtBufferNoiseShift);
2910*e5436536SAndroid Build Coastguard Worker     max_val_noise = MAX_VAL_NRG_HEADROOM >> shift;
2911*e5436536SAndroid Build Coastguard Worker     min_val_noise = -max_val_noise;
2912*e5436536SAndroid Build Coastguard Worker   }
2913*e5436536SAndroid Build Coastguard Worker 
2914*e5436536SAndroid Build Coastguard Worker   if (smooth_ratio > FL2FXCONST_SGL(0.0f)) {
2915*e5436536SAndroid Build Coastguard Worker     for (k = 0; k < noSubbands; k++) {
2916*e5436536SAndroid Build Coastguard Worker       /*
2917*e5436536SAndroid Build Coastguard Worker         Smoothing: The old envelope has been bufferd and a certain ratio
2918*e5436536SAndroid Build Coastguard Worker         of the old gains and noise levels is used.
2919*e5436536SAndroid Build Coastguard Worker       */
2920*e5436536SAndroid Build Coastguard Worker 
2921*e5436536SAndroid Build Coastguard Worker       smoothedGain =
2922*e5436536SAndroid Build Coastguard Worker           fMult(smooth_ratio, filtBuffer[k]) + fMult(direct_ratio, gain[k]);
2923*e5436536SAndroid Build Coastguard Worker 
2924*e5436536SAndroid Build Coastguard Worker       if (filtBufferNoiseShift < 0) {
2925*e5436536SAndroid Build Coastguard Worker         smoothedNoise = (fMultDiv2(smooth_ratio, filtBufferNoise[k]) >> shift) +
2926*e5436536SAndroid Build Coastguard Worker                         fMult(direct_ratio, noiseLevel[k]);
2927*e5436536SAndroid Build Coastguard Worker       } else {
2928*e5436536SAndroid Build Coastguard Worker         smoothedNoise = fMultDiv2(smooth_ratio, filtBufferNoise[k]);
2929*e5436536SAndroid Build Coastguard Worker         smoothedNoise =
2930*e5436536SAndroid Build Coastguard Worker             (fMax(fMin(smoothedNoise, max_val_noise), min_val_noise) << shift) +
2931*e5436536SAndroid Build Coastguard Worker             fMult(direct_ratio, noiseLevel[k]);
2932*e5436536SAndroid Build Coastguard Worker       }
2933*e5436536SAndroid Build Coastguard Worker 
2934*e5436536SAndroid Build Coastguard Worker       smoothedNoise = fMax(fMin(smoothedNoise, (FIXP_DBL)(MAXVAL_DBL / 2)),
2935*e5436536SAndroid Build Coastguard Worker                            (FIXP_DBL)(MINVAL_DBL / 2));
2936*e5436536SAndroid Build Coastguard Worker 
2937*e5436536SAndroid Build Coastguard Worker       /*
2938*e5436536SAndroid Build Coastguard Worker         The next 2 multiplications constitute the actual envelope adjustment
2939*e5436536SAndroid Build Coastguard Worker         of the signal and should be carried out with full accuracy
2940*e5436536SAndroid Build Coastguard Worker         (supplying #DFRACT_BITS valid bits).
2941*e5436536SAndroid Build Coastguard Worker       */
2942*e5436536SAndroid Build Coastguard Worker       signalReal =
2943*e5436536SAndroid Build Coastguard Worker           fMax(fMin(fMultDiv2(*ptrReal, smoothedGain), max_val), min_val)
2944*e5436536SAndroid Build Coastguard Worker           << scale_change;
2945*e5436536SAndroid Build Coastguard Worker       signalImag =
2946*e5436536SAndroid Build Coastguard Worker           fMax(fMin(fMultDiv2(*ptrImag, smoothedGain), max_val), min_val)
2947*e5436536SAndroid Build Coastguard Worker           << scale_change;
2948*e5436536SAndroid Build Coastguard Worker 
2949*e5436536SAndroid Build Coastguard Worker       index++;
2950*e5436536SAndroid Build Coastguard Worker 
2951*e5436536SAndroid Build Coastguard Worker       if (pSineLevel[k] != FL2FXCONST_DBL(0.0f)) {
2952*e5436536SAndroid Build Coastguard Worker         sineLevel = pSineLevel[k];
2953*e5436536SAndroid Build Coastguard Worker 
2954*e5436536SAndroid Build Coastguard Worker         switch (harmIndex) {
2955*e5436536SAndroid Build Coastguard Worker           case 0:
2956*e5436536SAndroid Build Coastguard Worker             *ptrReal++ = (signalReal + sineLevel);
2957*e5436536SAndroid Build Coastguard Worker             *ptrImag++ = (signalImag);
2958*e5436536SAndroid Build Coastguard Worker             break;
2959*e5436536SAndroid Build Coastguard Worker           case 2:
2960*e5436536SAndroid Build Coastguard Worker             *ptrReal++ = (signalReal - sineLevel);
2961*e5436536SAndroid Build Coastguard Worker             *ptrImag++ = (signalImag);
2962*e5436536SAndroid Build Coastguard Worker             break;
2963*e5436536SAndroid Build Coastguard Worker           case 1:
2964*e5436536SAndroid Build Coastguard Worker             *ptrReal++ = (signalReal);
2965*e5436536SAndroid Build Coastguard Worker             if (freqInvFlag)
2966*e5436536SAndroid Build Coastguard Worker               *ptrImag++ = (signalImag - sineLevel);
2967*e5436536SAndroid Build Coastguard Worker             else
2968*e5436536SAndroid Build Coastguard Worker               *ptrImag++ = (signalImag + sineLevel);
2969*e5436536SAndroid Build Coastguard Worker             break;
2970*e5436536SAndroid Build Coastguard Worker           case 3:
2971*e5436536SAndroid Build Coastguard Worker             *ptrReal++ = signalReal;
2972*e5436536SAndroid Build Coastguard Worker             if (freqInvFlag)
2973*e5436536SAndroid Build Coastguard Worker               *ptrImag++ = (signalImag + sineLevel);
2974*e5436536SAndroid Build Coastguard Worker             else
2975*e5436536SAndroid Build Coastguard Worker               *ptrImag++ = (signalImag - sineLevel);
2976*e5436536SAndroid Build Coastguard Worker             break;
2977*e5436536SAndroid Build Coastguard Worker         }
2978*e5436536SAndroid Build Coastguard Worker       } else {
2979*e5436536SAndroid Build Coastguard Worker         if (noNoiseFlag) {
2980*e5436536SAndroid Build Coastguard Worker           /* Just the amplified signal is saved */
2981*e5436536SAndroid Build Coastguard Worker           *ptrReal++ = (signalReal);
2982*e5436536SAndroid Build Coastguard Worker           *ptrImag++ = (signalImag);
2983*e5436536SAndroid Build Coastguard Worker         } else {
2984*e5436536SAndroid Build Coastguard Worker           /* Add noisefloor to the amplified signal */
2985*e5436536SAndroid Build Coastguard Worker           index &= (SBR_NF_NO_RANDOM_VAL - 1);
2986*e5436536SAndroid Build Coastguard Worker           noiseReal =
2987*e5436536SAndroid Build Coastguard Worker               fMult(FDK_sbrDecoder_sbr_randomPhase[index][0], smoothedNoise);
2988*e5436536SAndroid Build Coastguard Worker           noiseImag =
2989*e5436536SAndroid Build Coastguard Worker               fMult(FDK_sbrDecoder_sbr_randomPhase[index][1], smoothedNoise);
2990*e5436536SAndroid Build Coastguard Worker           *ptrReal++ = (signalReal + noiseReal);
2991*e5436536SAndroid Build Coastguard Worker           *ptrImag++ = (signalImag + noiseImag);
2992*e5436536SAndroid Build Coastguard Worker         }
2993*e5436536SAndroid Build Coastguard Worker       }
2994*e5436536SAndroid Build Coastguard Worker       freqInvFlag ^= 1;
2995*e5436536SAndroid Build Coastguard Worker     }
2996*e5436536SAndroid Build Coastguard Worker 
2997*e5436536SAndroid Build Coastguard Worker   } else {
2998*e5436536SAndroid Build Coastguard Worker     for (k = 0; k < noSubbands; k++) {
2999*e5436536SAndroid Build Coastguard Worker       smoothedGain = gain[k];
3000*e5436536SAndroid Build Coastguard Worker       signalReal =
3001*e5436536SAndroid Build Coastguard Worker           fMax(fMin(fMultDiv2(*ptrReal, smoothedGain), max_val), min_val)
3002*e5436536SAndroid Build Coastguard Worker           << scale_change;
3003*e5436536SAndroid Build Coastguard Worker       signalImag =
3004*e5436536SAndroid Build Coastguard Worker           fMax(fMin(fMultDiv2(*ptrImag, smoothedGain), max_val), min_val)
3005*e5436536SAndroid Build Coastguard Worker           << scale_change;
3006*e5436536SAndroid Build Coastguard Worker 
3007*e5436536SAndroid Build Coastguard Worker       index++;
3008*e5436536SAndroid Build Coastguard Worker 
3009*e5436536SAndroid Build Coastguard Worker       if ((sineLevel = pSineLevel[k]) != FL2FXCONST_DBL(0.0f)) {
3010*e5436536SAndroid Build Coastguard Worker         switch (harmIndex) {
3011*e5436536SAndroid Build Coastguard Worker           case 0:
3012*e5436536SAndroid Build Coastguard Worker             signalReal += sineLevel;
3013*e5436536SAndroid Build Coastguard Worker             break;
3014*e5436536SAndroid Build Coastguard Worker           case 1:
3015*e5436536SAndroid Build Coastguard Worker             if (freqInvFlag)
3016*e5436536SAndroid Build Coastguard Worker               signalImag -= sineLevel;
3017*e5436536SAndroid Build Coastguard Worker             else
3018*e5436536SAndroid Build Coastguard Worker               signalImag += sineLevel;
3019*e5436536SAndroid Build Coastguard Worker             break;
3020*e5436536SAndroid Build Coastguard Worker           case 2:
3021*e5436536SAndroid Build Coastguard Worker             signalReal -= sineLevel;
3022*e5436536SAndroid Build Coastguard Worker             break;
3023*e5436536SAndroid Build Coastguard Worker           case 3:
3024*e5436536SAndroid Build Coastguard Worker             if (freqInvFlag)
3025*e5436536SAndroid Build Coastguard Worker               signalImag += sineLevel;
3026*e5436536SAndroid Build Coastguard Worker             else
3027*e5436536SAndroid Build Coastguard Worker               signalImag -= sineLevel;
3028*e5436536SAndroid Build Coastguard Worker             break;
3029*e5436536SAndroid Build Coastguard Worker         }
3030*e5436536SAndroid Build Coastguard Worker       } else {
3031*e5436536SAndroid Build Coastguard Worker         if (noNoiseFlag == 0) {
3032*e5436536SAndroid Build Coastguard Worker           /* Add noisefloor to the amplified signal */
3033*e5436536SAndroid Build Coastguard Worker           smoothedNoise = noiseLevel[k];
3034*e5436536SAndroid Build Coastguard Worker           index &= (SBR_NF_NO_RANDOM_VAL - 1);
3035*e5436536SAndroid Build Coastguard Worker           noiseReal =
3036*e5436536SAndroid Build Coastguard Worker               fMult(FDK_sbrDecoder_sbr_randomPhase[index][0], smoothedNoise);
3037*e5436536SAndroid Build Coastguard Worker           noiseImag =
3038*e5436536SAndroid Build Coastguard Worker               fMult(FDK_sbrDecoder_sbr_randomPhase[index][1], smoothedNoise);
3039*e5436536SAndroid Build Coastguard Worker 
3040*e5436536SAndroid Build Coastguard Worker           signalReal += noiseReal;
3041*e5436536SAndroid Build Coastguard Worker           signalImag += noiseImag;
3042*e5436536SAndroid Build Coastguard Worker         }
3043*e5436536SAndroid Build Coastguard Worker       }
3044*e5436536SAndroid Build Coastguard Worker       *ptrReal++ = signalReal;
3045*e5436536SAndroid Build Coastguard Worker       *ptrImag++ = signalImag;
3046*e5436536SAndroid Build Coastguard Worker 
3047*e5436536SAndroid Build Coastguard Worker       freqInvFlag ^= 1;
3048*e5436536SAndroid Build Coastguard Worker     }
3049*e5436536SAndroid Build Coastguard Worker   }
3050*e5436536SAndroid Build Coastguard Worker }
3051*e5436536SAndroid Build Coastguard Worker 
3052*e5436536SAndroid Build Coastguard Worker /*!
3053*e5436536SAndroid Build Coastguard Worker   \brief   Reset limiter bands.
3054*e5436536SAndroid Build Coastguard Worker 
3055*e5436536SAndroid Build Coastguard Worker   Build frequency band table for the gain limiter dependent on
3056*e5436536SAndroid Build Coastguard Worker   the previously generated transposer patch areas.
3057*e5436536SAndroid Build Coastguard Worker 
3058*e5436536SAndroid Build Coastguard Worker   \return  SBRDEC_OK if ok,  SBRDEC_UNSUPPORTED_CONFIG on error
3059*e5436536SAndroid Build Coastguard Worker */
3060*e5436536SAndroid Build Coastguard Worker SBR_ERROR
ResetLimiterBands(UCHAR * limiterBandTable,UCHAR * noLimiterBands,UCHAR * freqBandTable,int noFreqBands,const PATCH_PARAM * patchParam,int noPatches,int limiterBands,UCHAR sbrPatchingMode,int xOverQmf[MAX_NUM_PATCHES],int b41Sbr)3061*e5436536SAndroid Build Coastguard Worker ResetLimiterBands(
3062*e5436536SAndroid Build Coastguard Worker     UCHAR *limiterBandTable, /*!< Resulting band borders in QMF channels */
3063*e5436536SAndroid Build Coastguard Worker     UCHAR *noLimiterBands,   /*!< Resulting number of limiter band */
3064*e5436536SAndroid Build Coastguard Worker     UCHAR *freqBandTable,    /*!< Table with possible band borders */
3065*e5436536SAndroid Build Coastguard Worker     int noFreqBands,         /*!< Number of bands in freqBandTable */
3066*e5436536SAndroid Build Coastguard Worker     const PATCH_PARAM *patchParam, /*!< Transposer patch parameters */
3067*e5436536SAndroid Build Coastguard Worker     int noPatches,                 /*!< Number of transposer patches */
3068*e5436536SAndroid Build Coastguard Worker     int limiterBands, /*!< Selected 'band density' from bitstream */
3069*e5436536SAndroid Build Coastguard Worker     UCHAR sbrPatchingMode, int xOverQmf[MAX_NUM_PATCHES], int b41Sbr) {
3070*e5436536SAndroid Build Coastguard Worker   int i, k, isPatchBorder[2], loLimIndex, hiLimIndex, tempNoLim, nBands;
3071*e5436536SAndroid Build Coastguard Worker   UCHAR workLimiterBandTable[MAX_FREQ_COEFFS / 2 + MAX_NUM_PATCHES + 1];
3072*e5436536SAndroid Build Coastguard Worker   int patchBorders[MAX_NUM_PATCHES + 1];
3073*e5436536SAndroid Build Coastguard Worker   int kx, k2;
3074*e5436536SAndroid Build Coastguard Worker 
3075*e5436536SAndroid Build Coastguard Worker   int lowSubband = freqBandTable[0];
3076*e5436536SAndroid Build Coastguard Worker   int highSubband = freqBandTable[noFreqBands];
3077*e5436536SAndroid Build Coastguard Worker 
3078*e5436536SAndroid Build Coastguard Worker   /* 1 limiter band. */
3079*e5436536SAndroid Build Coastguard Worker   if (limiterBands == 0) {
3080*e5436536SAndroid Build Coastguard Worker     limiterBandTable[0] = 0;
3081*e5436536SAndroid Build Coastguard Worker     limiterBandTable[1] = highSubband - lowSubband;
3082*e5436536SAndroid Build Coastguard Worker     nBands = 1;
3083*e5436536SAndroid Build Coastguard Worker   } else {
3084*e5436536SAndroid Build Coastguard Worker     if (!sbrPatchingMode && xOverQmf != NULL) {
3085*e5436536SAndroid Build Coastguard Worker       noPatches = 0;
3086*e5436536SAndroid Build Coastguard Worker 
3087*e5436536SAndroid Build Coastguard Worker       if (b41Sbr == 1) {
3088*e5436536SAndroid Build Coastguard Worker         for (i = 1; i < MAX_NUM_PATCHES_HBE; i++)
3089*e5436536SAndroid Build Coastguard Worker           if (xOverQmf[i] != 0) noPatches++;
3090*e5436536SAndroid Build Coastguard Worker       } else {
3091*e5436536SAndroid Build Coastguard Worker         for (i = 1; i < MAX_STRETCH_HBE; i++)
3092*e5436536SAndroid Build Coastguard Worker           if (xOverQmf[i] != 0) noPatches++;
3093*e5436536SAndroid Build Coastguard Worker       }
3094*e5436536SAndroid Build Coastguard Worker       for (i = 0; i < noPatches; i++) {
3095*e5436536SAndroid Build Coastguard Worker         patchBorders[i] = xOverQmf[i] - lowSubband;
3096*e5436536SAndroid Build Coastguard Worker       }
3097*e5436536SAndroid Build Coastguard Worker     } else {
3098*e5436536SAndroid Build Coastguard Worker       for (i = 0; i < noPatches; i++) {
3099*e5436536SAndroid Build Coastguard Worker         patchBorders[i] = patchParam[i].guardStartBand - lowSubband;
3100*e5436536SAndroid Build Coastguard Worker       }
3101*e5436536SAndroid Build Coastguard Worker     }
3102*e5436536SAndroid Build Coastguard Worker     patchBorders[i] = highSubband - lowSubband;
3103*e5436536SAndroid Build Coastguard Worker 
3104*e5436536SAndroid Build Coastguard Worker     /* 1.2, 2, or 3 limiter bands/octave plus bandborders at patchborders. */
3105*e5436536SAndroid Build Coastguard Worker     for (k = 0; k <= noFreqBands; k++) {
3106*e5436536SAndroid Build Coastguard Worker       workLimiterBandTable[k] = freqBandTable[k] - lowSubband;
3107*e5436536SAndroid Build Coastguard Worker     }
3108*e5436536SAndroid Build Coastguard Worker     for (k = 1; k < noPatches; k++) {
3109*e5436536SAndroid Build Coastguard Worker       workLimiterBandTable[noFreqBands + k] = patchBorders[k];
3110*e5436536SAndroid Build Coastguard Worker     }
3111*e5436536SAndroid Build Coastguard Worker 
3112*e5436536SAndroid Build Coastguard Worker     tempNoLim = nBands = noFreqBands + noPatches - 1;
3113*e5436536SAndroid Build Coastguard Worker     shellsort(workLimiterBandTable, tempNoLim + 1);
3114*e5436536SAndroid Build Coastguard Worker 
3115*e5436536SAndroid Build Coastguard Worker     loLimIndex = 0;
3116*e5436536SAndroid Build Coastguard Worker     hiLimIndex = 1;
3117*e5436536SAndroid Build Coastguard Worker 
3118*e5436536SAndroid Build Coastguard Worker     while (hiLimIndex <= tempNoLim) {
3119*e5436536SAndroid Build Coastguard Worker       FIXP_DBL div_m, oct_m, temp;
3120*e5436536SAndroid Build Coastguard Worker       INT div_e = 0, oct_e = 0, temp_e = 0;
3121*e5436536SAndroid Build Coastguard Worker 
3122*e5436536SAndroid Build Coastguard Worker       k2 = workLimiterBandTable[hiLimIndex] + lowSubband;
3123*e5436536SAndroid Build Coastguard Worker       kx = workLimiterBandTable[loLimIndex] + lowSubband;
3124*e5436536SAndroid Build Coastguard Worker 
3125*e5436536SAndroid Build Coastguard Worker       div_m = fDivNorm(k2, kx, &div_e);
3126*e5436536SAndroid Build Coastguard Worker 
3127*e5436536SAndroid Build Coastguard Worker       /* calculate number of octaves */
3128*e5436536SAndroid Build Coastguard Worker       oct_m = fLog2(div_m, div_e, &oct_e);
3129*e5436536SAndroid Build Coastguard Worker 
3130*e5436536SAndroid Build Coastguard Worker       /* multiply with limiterbands per octave    */
3131*e5436536SAndroid Build Coastguard Worker       /* values 1, 1.2, 2, 3 -> scale factor of 2 */
3132*e5436536SAndroid Build Coastguard Worker       temp = fMultNorm(
3133*e5436536SAndroid Build Coastguard Worker           oct_m, FDK_sbrDecoder_sbr_limiterBandsPerOctaveDiv4_DBL[limiterBands],
3134*e5436536SAndroid Build Coastguard Worker           &temp_e);
3135*e5436536SAndroid Build Coastguard Worker 
3136*e5436536SAndroid Build Coastguard Worker       /* overall scale factor of temp ist addition of scalefactors from log2
3137*e5436536SAndroid Build Coastguard Worker          calculation, limiter bands scalefactor (2) and limiter bands
3138*e5436536SAndroid Build Coastguard Worker          multiplication */
3139*e5436536SAndroid Build Coastguard Worker       temp_e += oct_e + 2;
3140*e5436536SAndroid Build Coastguard Worker 
3141*e5436536SAndroid Build Coastguard Worker       /*    div can be a maximum of 64 (k2 = 64 and kx = 1)
3142*e5436536SAndroid Build Coastguard Worker          -> oct can be a maximum of 6
3143*e5436536SAndroid Build Coastguard Worker          -> temp can be a maximum of 18 (as limiterBandsPerOctoave is a maximum
3144*e5436536SAndroid Build Coastguard Worker          factor of 3)
3145*e5436536SAndroid Build Coastguard Worker          -> we need a scale factor of 5 for comparisson
3146*e5436536SAndroid Build Coastguard Worker       */
3147*e5436536SAndroid Build Coastguard Worker       if (temp >> (5 - temp_e) < FL2FXCONST_DBL(0.49f) >> 5) {
3148*e5436536SAndroid Build Coastguard Worker         if (workLimiterBandTable[hiLimIndex] ==
3149*e5436536SAndroid Build Coastguard Worker             workLimiterBandTable[loLimIndex]) {
3150*e5436536SAndroid Build Coastguard Worker           workLimiterBandTable[hiLimIndex] = highSubband;
3151*e5436536SAndroid Build Coastguard Worker           nBands--;
3152*e5436536SAndroid Build Coastguard Worker           hiLimIndex++;
3153*e5436536SAndroid Build Coastguard Worker           continue;
3154*e5436536SAndroid Build Coastguard Worker         }
3155*e5436536SAndroid Build Coastguard Worker         isPatchBorder[0] = isPatchBorder[1] = 0;
3156*e5436536SAndroid Build Coastguard Worker         for (k = 0; k <= noPatches; k++) {
3157*e5436536SAndroid Build Coastguard Worker           if (workLimiterBandTable[hiLimIndex] == patchBorders[k]) {
3158*e5436536SAndroid Build Coastguard Worker             isPatchBorder[1] = 1;
3159*e5436536SAndroid Build Coastguard Worker             break;
3160*e5436536SAndroid Build Coastguard Worker           }
3161*e5436536SAndroid Build Coastguard Worker         }
3162*e5436536SAndroid Build Coastguard Worker         if (!isPatchBorder[1]) {
3163*e5436536SAndroid Build Coastguard Worker           workLimiterBandTable[hiLimIndex] = highSubband;
3164*e5436536SAndroid Build Coastguard Worker           nBands--;
3165*e5436536SAndroid Build Coastguard Worker           hiLimIndex++;
3166*e5436536SAndroid Build Coastguard Worker           continue;
3167*e5436536SAndroid Build Coastguard Worker         }
3168*e5436536SAndroid Build Coastguard Worker         for (k = 0; k <= noPatches; k++) {
3169*e5436536SAndroid Build Coastguard Worker           if (workLimiterBandTable[loLimIndex] == patchBorders[k]) {
3170*e5436536SAndroid Build Coastguard Worker             isPatchBorder[0] = 1;
3171*e5436536SAndroid Build Coastguard Worker             break;
3172*e5436536SAndroid Build Coastguard Worker           }
3173*e5436536SAndroid Build Coastguard Worker         }
3174*e5436536SAndroid Build Coastguard Worker         if (!isPatchBorder[0]) {
3175*e5436536SAndroid Build Coastguard Worker           workLimiterBandTable[loLimIndex] = highSubband;
3176*e5436536SAndroid Build Coastguard Worker           nBands--;
3177*e5436536SAndroid Build Coastguard Worker         }
3178*e5436536SAndroid Build Coastguard Worker       }
3179*e5436536SAndroid Build Coastguard Worker       loLimIndex = hiLimIndex;
3180*e5436536SAndroid Build Coastguard Worker       hiLimIndex++;
3181*e5436536SAndroid Build Coastguard Worker     }
3182*e5436536SAndroid Build Coastguard Worker     shellsort(workLimiterBandTable, tempNoLim + 1);
3183*e5436536SAndroid Build Coastguard Worker 
3184*e5436536SAndroid Build Coastguard Worker     /* Test if algorithm exceeded maximum allowed limiterbands */
3185*e5436536SAndroid Build Coastguard Worker     if (nBands > MAX_NUM_LIMITERS || nBands <= 0) {
3186*e5436536SAndroid Build Coastguard Worker       return SBRDEC_UNSUPPORTED_CONFIG;
3187*e5436536SAndroid Build Coastguard Worker     }
3188*e5436536SAndroid Build Coastguard Worker 
3189*e5436536SAndroid Build Coastguard Worker     /* Restrict maximum value of limiter band table */
3190*e5436536SAndroid Build Coastguard Worker     if (workLimiterBandTable[tempNoLim] > highSubband) {
3191*e5436536SAndroid Build Coastguard Worker       return SBRDEC_UNSUPPORTED_CONFIG;
3192*e5436536SAndroid Build Coastguard Worker     }
3193*e5436536SAndroid Build Coastguard Worker 
3194*e5436536SAndroid Build Coastguard Worker     /* Copy limiterbands from working buffer into final destination */
3195*e5436536SAndroid Build Coastguard Worker     for (k = 0; k <= nBands; k++) {
3196*e5436536SAndroid Build Coastguard Worker       limiterBandTable[k] = workLimiterBandTable[k];
3197*e5436536SAndroid Build Coastguard Worker     }
3198*e5436536SAndroid Build Coastguard Worker   }
3199*e5436536SAndroid Build Coastguard Worker   *noLimiterBands = nBands;
3200*e5436536SAndroid Build Coastguard Worker 
3201*e5436536SAndroid Build Coastguard Worker   return SBRDEC_OK;
3202*e5436536SAndroid Build Coastguard Worker }
3203