xref: /aosp_15_r20/external/aac/libSBRenc/src/tran_det.cpp (revision e54365361535b070c2db7374cec45c159c7d0e7a)
1*e5436536SAndroid Build Coastguard Worker /* -----------------------------------------------------------------------------
2*e5436536SAndroid Build Coastguard Worker Software License for The Fraunhofer FDK AAC Codec Library for Android
3*e5436536SAndroid Build Coastguard Worker 
4*e5436536SAndroid Build Coastguard Worker © Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
5*e5436536SAndroid Build Coastguard Worker Forschung e.V. All rights reserved.
6*e5436536SAndroid Build Coastguard Worker 
7*e5436536SAndroid Build Coastguard Worker  1.    INTRODUCTION
8*e5436536SAndroid Build Coastguard Worker The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software
9*e5436536SAndroid Build Coastguard Worker that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding
10*e5436536SAndroid Build Coastguard Worker scheme for digital audio. This FDK AAC Codec software is intended to be used on
11*e5436536SAndroid Build Coastguard Worker a wide variety of Android devices.
12*e5436536SAndroid Build Coastguard Worker 
13*e5436536SAndroid Build Coastguard Worker AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient
14*e5436536SAndroid Build Coastguard Worker general perceptual audio codecs. AAC-ELD is considered the best-performing
15*e5436536SAndroid Build Coastguard Worker full-bandwidth communications codec by independent studies and is widely
16*e5436536SAndroid Build Coastguard Worker deployed. AAC has been standardized by ISO and IEC as part of the MPEG
17*e5436536SAndroid Build Coastguard Worker specifications.
18*e5436536SAndroid Build Coastguard Worker 
19*e5436536SAndroid Build Coastguard Worker Patent licenses for necessary patent claims for the FDK AAC Codec (including
20*e5436536SAndroid Build Coastguard Worker those of Fraunhofer) may be obtained through Via Licensing
21*e5436536SAndroid Build Coastguard Worker (www.vialicensing.com) or through the respective patent owners individually for
22*e5436536SAndroid Build Coastguard Worker the purpose of encoding or decoding bit streams in products that are compliant
23*e5436536SAndroid Build Coastguard Worker with the ISO/IEC MPEG audio standards. Please note that most manufacturers of
24*e5436536SAndroid Build Coastguard Worker Android devices already license these patent claims through Via Licensing or
25*e5436536SAndroid Build Coastguard Worker directly from the patent owners, and therefore FDK AAC Codec software may
26*e5436536SAndroid Build Coastguard Worker already be covered under those patent licenses when it is used for those
27*e5436536SAndroid Build Coastguard Worker licensed purposes only.
28*e5436536SAndroid Build Coastguard Worker 
29*e5436536SAndroid Build Coastguard Worker Commercially-licensed AAC software libraries, including floating-point versions
30*e5436536SAndroid Build Coastguard Worker with enhanced sound quality, are also available from Fraunhofer. Users are
31*e5436536SAndroid Build Coastguard Worker encouraged to check the Fraunhofer website for additional applications
32*e5436536SAndroid Build Coastguard Worker information and documentation.
33*e5436536SAndroid Build Coastguard Worker 
34*e5436536SAndroid Build Coastguard Worker 2.    COPYRIGHT LICENSE
35*e5436536SAndroid Build Coastguard Worker 
36*e5436536SAndroid Build Coastguard Worker Redistribution and use in source and binary forms, with or without modification,
37*e5436536SAndroid Build Coastguard Worker are permitted without payment of copyright license fees provided that you
38*e5436536SAndroid Build Coastguard Worker satisfy the following conditions:
39*e5436536SAndroid Build Coastguard Worker 
40*e5436536SAndroid Build Coastguard Worker You must retain the complete text of this software license in redistributions of
41*e5436536SAndroid Build Coastguard Worker the FDK AAC Codec or your modifications thereto in source code form.
42*e5436536SAndroid Build Coastguard Worker 
43*e5436536SAndroid Build Coastguard Worker You must retain the complete text of this software license in the documentation
44*e5436536SAndroid Build Coastguard Worker and/or other materials provided with redistributions of the FDK AAC Codec or
45*e5436536SAndroid Build Coastguard Worker your modifications thereto in binary form. You must make available free of
46*e5436536SAndroid Build Coastguard Worker charge copies of the complete source code of the FDK AAC Codec and your
47*e5436536SAndroid Build Coastguard Worker modifications thereto to recipients of copies in binary form.
48*e5436536SAndroid Build Coastguard Worker 
49*e5436536SAndroid Build Coastguard Worker The name of Fraunhofer may not be used to endorse or promote products derived
50*e5436536SAndroid Build Coastguard Worker from this library without prior written permission.
51*e5436536SAndroid Build Coastguard Worker 
52*e5436536SAndroid Build Coastguard Worker You may not charge copyright license fees for anyone to use, copy or distribute
53*e5436536SAndroid Build Coastguard Worker the FDK AAC Codec software or your modifications thereto.
54*e5436536SAndroid Build Coastguard Worker 
55*e5436536SAndroid Build Coastguard Worker Your modified versions of the FDK AAC Codec must carry prominent notices stating
56*e5436536SAndroid Build Coastguard Worker that you changed the software and the date of any change. For modified versions
57*e5436536SAndroid Build Coastguard Worker of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android"
58*e5436536SAndroid Build Coastguard Worker must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK
59*e5436536SAndroid Build Coastguard Worker AAC Codec Library for Android."
60*e5436536SAndroid Build Coastguard Worker 
61*e5436536SAndroid Build Coastguard Worker 3.    NO PATENT LICENSE
62*e5436536SAndroid Build Coastguard Worker 
63*e5436536SAndroid Build Coastguard Worker NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without
64*e5436536SAndroid Build Coastguard Worker limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE.
65*e5436536SAndroid Build Coastguard Worker Fraunhofer provides no warranty of patent non-infringement with respect to this
66*e5436536SAndroid Build Coastguard Worker software.
67*e5436536SAndroid Build Coastguard Worker 
68*e5436536SAndroid Build Coastguard Worker You may use this FDK AAC Codec software or modifications thereto only for
69*e5436536SAndroid Build Coastguard Worker purposes that are authorized by appropriate patent licenses.
70*e5436536SAndroid Build Coastguard Worker 
71*e5436536SAndroid Build Coastguard Worker 4.    DISCLAIMER
72*e5436536SAndroid Build Coastguard Worker 
73*e5436536SAndroid Build Coastguard Worker This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright
74*e5436536SAndroid Build Coastguard Worker holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
75*e5436536SAndroid Build Coastguard Worker including but not limited to the implied warranties of merchantability and
76*e5436536SAndroid Build Coastguard Worker fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
77*e5436536SAndroid Build Coastguard Worker CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary,
78*e5436536SAndroid Build Coastguard Worker or consequential damages, including but not limited to procurement of substitute
79*e5436536SAndroid Build Coastguard Worker goods or services; loss of use, data, or profits, or business interruption,
80*e5436536SAndroid Build Coastguard Worker however caused and on any theory of liability, whether in contract, strict
81*e5436536SAndroid Build Coastguard Worker liability, or tort (including negligence), arising in any way out of the use of
82*e5436536SAndroid Build Coastguard Worker this software, even if advised of the possibility of such damage.
83*e5436536SAndroid Build Coastguard Worker 
84*e5436536SAndroid Build Coastguard Worker 5.    CONTACT INFORMATION
85*e5436536SAndroid Build Coastguard Worker 
86*e5436536SAndroid Build Coastguard Worker Fraunhofer Institute for Integrated Circuits IIS
87*e5436536SAndroid Build Coastguard Worker Attention: Audio and Multimedia Departments - FDK AAC LL
88*e5436536SAndroid Build Coastguard Worker Am Wolfsmantel 33
89*e5436536SAndroid Build Coastguard Worker 91058 Erlangen, Germany
90*e5436536SAndroid Build Coastguard Worker 
91*e5436536SAndroid Build Coastguard Worker www.iis.fraunhofer.de/amm
92*e5436536SAndroid Build Coastguard Worker [email protected]
93*e5436536SAndroid Build Coastguard Worker ----------------------------------------------------------------------------- */
94*e5436536SAndroid Build Coastguard Worker 
95*e5436536SAndroid Build Coastguard Worker /**************************** SBR encoder library ******************************
96*e5436536SAndroid Build Coastguard Worker 
97*e5436536SAndroid Build Coastguard Worker    Author(s):   Tobias Chalupka
98*e5436536SAndroid Build Coastguard Worker 
99*e5436536SAndroid Build Coastguard Worker    Description: SBR encoder transient detector
100*e5436536SAndroid Build Coastguard Worker 
101*e5436536SAndroid Build Coastguard Worker *******************************************************************************/
102*e5436536SAndroid Build Coastguard Worker 
103*e5436536SAndroid Build Coastguard Worker #include "tran_det.h"
104*e5436536SAndroid Build Coastguard Worker 
105*e5436536SAndroid Build Coastguard Worker #include "fram_gen.h"
106*e5436536SAndroid Build Coastguard Worker #include "sbrenc_ram.h"
107*e5436536SAndroid Build Coastguard Worker #include "sbr_misc.h"
108*e5436536SAndroid Build Coastguard Worker 
109*e5436536SAndroid Build Coastguard Worker #include "genericStds.h"
110*e5436536SAndroid Build Coastguard Worker 
111*e5436536SAndroid Build Coastguard Worker #define NORM_QMF_ENERGY 9.31322574615479E-10 /* 2^-30 */
112*e5436536SAndroid Build Coastguard Worker 
113*e5436536SAndroid Build Coastguard Worker /* static FIXP_DBL ABS_THRES = fixMax( FL2FXCONST_DBL(1.28e5 *
114*e5436536SAndroid Build Coastguard Worker  * NORM_QMF_ENERGY), (FIXP_DBL)1)  Minimum threshold for detecting changes */
115*e5436536SAndroid Build Coastguard Worker #define ABS_THRES ((FIXP_DBL)16)
116*e5436536SAndroid Build Coastguard Worker 
117*e5436536SAndroid Build Coastguard Worker /*******************************************************************************
118*e5436536SAndroid Build Coastguard Worker  Functionname:  spectralChange
119*e5436536SAndroid Build Coastguard Worker  *******************************************************************************
120*e5436536SAndroid Build Coastguard Worker  \brief   Calculates a measure for the spectral change within the frame
121*e5436536SAndroid Build Coastguard Worker 
122*e5436536SAndroid Build Coastguard Worker  The function says how good it would be to split the frame at the given border
123*e5436536SAndroid Build Coastguard Worker  position into 2 envelopes.
124*e5436536SAndroid Build Coastguard Worker 
125*e5436536SAndroid Build Coastguard Worker  The return value delta_sum is scaled with the factor 1/64
126*e5436536SAndroid Build Coastguard Worker 
127*e5436536SAndroid Build Coastguard Worker  \return  calculated value
128*e5436536SAndroid Build Coastguard Worker *******************************************************************************/
129*e5436536SAndroid Build Coastguard Worker #define NRG_SHIFT 3 /* for energy summation */
130*e5436536SAndroid Build Coastguard Worker 
spectralChange(FIXP_DBL Energies[NUMBER_TIME_SLOTS_2304][MAX_FREQ_COEFFS],INT * scaleEnergies,FIXP_DBL EnergyTotal,INT nSfb,INT start,INT border,INT YBufferWriteOffset,INT stop,INT * result_e)131*e5436536SAndroid Build Coastguard Worker static FIXP_DBL spectralChange(
132*e5436536SAndroid Build Coastguard Worker     FIXP_DBL Energies[NUMBER_TIME_SLOTS_2304][MAX_FREQ_COEFFS],
133*e5436536SAndroid Build Coastguard Worker     INT *scaleEnergies, FIXP_DBL EnergyTotal, INT nSfb, INT start, INT border,
134*e5436536SAndroid Build Coastguard Worker     INT YBufferWriteOffset, INT stop, INT *result_e) {
135*e5436536SAndroid Build Coastguard Worker   INT i, j;
136*e5436536SAndroid Build Coastguard Worker   INT len1, len2;
137*e5436536SAndroid Build Coastguard Worker   SCHAR energies_e_diff[NUMBER_TIME_SLOTS_2304], energies_e, energyTotal_e = 19,
138*e5436536SAndroid Build Coastguard Worker                                                              energies_e_add;
139*e5436536SAndroid Build Coastguard Worker   SCHAR prevEnergies_e_diff, newEnergies_e_diff;
140*e5436536SAndroid Build Coastguard Worker   FIXP_DBL tmp0, tmp1;
141*e5436536SAndroid Build Coastguard Worker   FIXP_DBL delta, delta_sum;
142*e5436536SAndroid Build Coastguard Worker   INT accu_e, tmp_e;
143*e5436536SAndroid Build Coastguard Worker 
144*e5436536SAndroid Build Coastguard Worker   delta_sum = FL2FXCONST_DBL(0.0f);
145*e5436536SAndroid Build Coastguard Worker   *result_e = 0;
146*e5436536SAndroid Build Coastguard Worker 
147*e5436536SAndroid Build Coastguard Worker   len1 = border - start;
148*e5436536SAndroid Build Coastguard Worker   len2 = stop - border;
149*e5436536SAndroid Build Coastguard Worker 
150*e5436536SAndroid Build Coastguard Worker   /* prefer borders near the middle of the frame */
151*e5436536SAndroid Build Coastguard Worker   FIXP_DBL pos_weight;
152*e5436536SAndroid Build Coastguard Worker   pos_weight = FL2FXCONST_DBL(0.5f) - (len1 * GetInvInt(len1 + len2));
153*e5436536SAndroid Build Coastguard Worker   pos_weight = /*FL2FXCONST_DBL(1.0)*/ (FIXP_DBL)MAXVAL_DBL -
154*e5436536SAndroid Build Coastguard Worker                (fMult(pos_weight, pos_weight) << 2);
155*e5436536SAndroid Build Coastguard Worker 
156*e5436536SAndroid Build Coastguard Worker   /*** Calc scaling for energies ***/
157*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(scaleEnergies[0] >= 0);
158*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(scaleEnergies[1] >= 0);
159*e5436536SAndroid Build Coastguard Worker 
160*e5436536SAndroid Build Coastguard Worker   energies_e = 19 - fMin(scaleEnergies[0], scaleEnergies[1]);
161*e5436536SAndroid Build Coastguard Worker 
162*e5436536SAndroid Build Coastguard Worker   /* limit shift for energy accumulation, energies_e can be -10 min. */
163*e5436536SAndroid Build Coastguard Worker   if (energies_e < -10) {
164*e5436536SAndroid Build Coastguard Worker     energies_e_add = -10 - energies_e;
165*e5436536SAndroid Build Coastguard Worker     energies_e = -10;
166*e5436536SAndroid Build Coastguard Worker   } else if (energies_e > 17) {
167*e5436536SAndroid Build Coastguard Worker     energies_e_add = energies_e - 17;
168*e5436536SAndroid Build Coastguard Worker     energies_e = 17;
169*e5436536SAndroid Build Coastguard Worker   } else {
170*e5436536SAndroid Build Coastguard Worker     energies_e_add = 0;
171*e5436536SAndroid Build Coastguard Worker   }
172*e5436536SAndroid Build Coastguard Worker 
173*e5436536SAndroid Build Coastguard Worker   /* compensate scaling differences between scaleEnergies[0] and
174*e5436536SAndroid Build Coastguard Worker    * scaleEnergies[1]  */
175*e5436536SAndroid Build Coastguard Worker   prevEnergies_e_diff = scaleEnergies[0] -
176*e5436536SAndroid Build Coastguard Worker                         fMin(scaleEnergies[0], scaleEnergies[1]) +
177*e5436536SAndroid Build Coastguard Worker                         energies_e_add + NRG_SHIFT;
178*e5436536SAndroid Build Coastguard Worker   newEnergies_e_diff = scaleEnergies[1] -
179*e5436536SAndroid Build Coastguard Worker                        fMin(scaleEnergies[0], scaleEnergies[1]) +
180*e5436536SAndroid Build Coastguard Worker                        energies_e_add + NRG_SHIFT;
181*e5436536SAndroid Build Coastguard Worker 
182*e5436536SAndroid Build Coastguard Worker   prevEnergies_e_diff = fMin(prevEnergies_e_diff, DFRACT_BITS - 1);
183*e5436536SAndroid Build Coastguard Worker   newEnergies_e_diff = fMin(newEnergies_e_diff, DFRACT_BITS - 1);
184*e5436536SAndroid Build Coastguard Worker 
185*e5436536SAndroid Build Coastguard Worker   for (i = start; i < YBufferWriteOffset; i++) {
186*e5436536SAndroid Build Coastguard Worker     energies_e_diff[i] = prevEnergies_e_diff;
187*e5436536SAndroid Build Coastguard Worker   }
188*e5436536SAndroid Build Coastguard Worker   for (i = YBufferWriteOffset; i < stop; i++) {
189*e5436536SAndroid Build Coastguard Worker     energies_e_diff[i] = newEnergies_e_diff;
190*e5436536SAndroid Build Coastguard Worker   }
191*e5436536SAndroid Build Coastguard Worker 
192*e5436536SAndroid Build Coastguard Worker   /* Sum up energies of all QMF-timeslots for both halfs */
193*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(len1 <= 8); /* otherwise an overflow is possible */
194*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(len2 <= 8); /* otherwise an overflow is possible */
195*e5436536SAndroid Build Coastguard Worker 
196*e5436536SAndroid Build Coastguard Worker   for (j = 0; j < nSfb; j++) {
197*e5436536SAndroid Build Coastguard Worker     FIXP_DBL accu1 = FL2FXCONST_DBL(0.f);
198*e5436536SAndroid Build Coastguard Worker     FIXP_DBL accu2 = FL2FXCONST_DBL(0.f);
199*e5436536SAndroid Build Coastguard Worker     accu_e = energies_e + 3;
200*e5436536SAndroid Build Coastguard Worker 
201*e5436536SAndroid Build Coastguard Worker     /* Sum up energies in first half */
202*e5436536SAndroid Build Coastguard Worker     for (i = start; i < border; i++) {
203*e5436536SAndroid Build Coastguard Worker       accu1 += scaleValue(Energies[i][j], -energies_e_diff[i]);
204*e5436536SAndroid Build Coastguard Worker     }
205*e5436536SAndroid Build Coastguard Worker 
206*e5436536SAndroid Build Coastguard Worker     /* Sum up energies in second half */
207*e5436536SAndroid Build Coastguard Worker     for (i = border; i < stop; i++) {
208*e5436536SAndroid Build Coastguard Worker       accu2 += scaleValue(Energies[i][j], -energies_e_diff[i]);
209*e5436536SAndroid Build Coastguard Worker     }
210*e5436536SAndroid Build Coastguard Worker 
211*e5436536SAndroid Build Coastguard Worker     /* Ensure certain energy to prevent division by zero and to prevent
212*e5436536SAndroid Build Coastguard Worker      * splitting for very low levels */
213*e5436536SAndroid Build Coastguard Worker     accu1 = fMax(accu1, (FIXP_DBL)len1);
214*e5436536SAndroid Build Coastguard Worker     accu2 = fMax(accu2, (FIXP_DBL)len2);
215*e5436536SAndroid Build Coastguard Worker 
216*e5436536SAndroid Build Coastguard Worker /* Energy change in current band */
217*e5436536SAndroid Build Coastguard Worker #define LN2 FL2FXCONST_DBL(0.6931471806f) /* ln(2) */
218*e5436536SAndroid Build Coastguard Worker     tmp0 = fLog2(accu2, accu_e) - fLog2(accu1, accu_e);
219*e5436536SAndroid Build Coastguard Worker     tmp1 = fLog2((FIXP_DBL)len1, 31) - fLog2((FIXP_DBL)len2, 31);
220*e5436536SAndroid Build Coastguard Worker     delta = fMult(LN2, (tmp0 + tmp1));
221*e5436536SAndroid Build Coastguard Worker     delta = (FIXP_DBL)fAbs(delta);
222*e5436536SAndroid Build Coastguard Worker 
223*e5436536SAndroid Build Coastguard Worker     /* Weighting with amplitude ratio of this band */
224*e5436536SAndroid Build Coastguard Worker     accu_e++; /* scale at least one bit due to (accu1+accu2) */
225*e5436536SAndroid Build Coastguard Worker     accu1 >>= 1;
226*e5436536SAndroid Build Coastguard Worker     accu2 >>= 1;
227*e5436536SAndroid Build Coastguard Worker 
228*e5436536SAndroid Build Coastguard Worker     if (accu_e & 1) {
229*e5436536SAndroid Build Coastguard Worker       accu_e++; /* for a defined square result exponent, the exponent has to be
230*e5436536SAndroid Build Coastguard Worker                    even */
231*e5436536SAndroid Build Coastguard Worker       accu1 >>= 1;
232*e5436536SAndroid Build Coastguard Worker       accu2 >>= 1;
233*e5436536SAndroid Build Coastguard Worker     }
234*e5436536SAndroid Build Coastguard Worker 
235*e5436536SAndroid Build Coastguard Worker     delta_sum += fMult(sqrtFixp(accu1 + accu2), delta);
236*e5436536SAndroid Build Coastguard Worker     *result_e = ((accu_e >> 1) + LD_DATA_SHIFT);
237*e5436536SAndroid Build Coastguard Worker   }
238*e5436536SAndroid Build Coastguard Worker 
239*e5436536SAndroid Build Coastguard Worker   if (energyTotal_e & 1) {
240*e5436536SAndroid Build Coastguard Worker     energyTotal_e += 1; /* for a defined square result exponent, the exponent
241*e5436536SAndroid Build Coastguard Worker                            has to be even */
242*e5436536SAndroid Build Coastguard Worker     EnergyTotal >>= 1;
243*e5436536SAndroid Build Coastguard Worker   }
244*e5436536SAndroid Build Coastguard Worker 
245*e5436536SAndroid Build Coastguard Worker   delta_sum = fMult(delta_sum, invSqrtNorm2(EnergyTotal, &tmp_e));
246*e5436536SAndroid Build Coastguard Worker   *result_e = *result_e + (tmp_e - (energyTotal_e >> 1));
247*e5436536SAndroid Build Coastguard Worker 
248*e5436536SAndroid Build Coastguard Worker   return fMult(delta_sum, pos_weight);
249*e5436536SAndroid Build Coastguard Worker }
250*e5436536SAndroid Build Coastguard Worker 
251*e5436536SAndroid Build Coastguard Worker /*******************************************************************************
252*e5436536SAndroid Build Coastguard Worker  Functionname:  addLowbandEnergies
253*e5436536SAndroid Build Coastguard Worker  *******************************************************************************
254*e5436536SAndroid Build Coastguard Worker  \brief   Calculates total lowband energy
255*e5436536SAndroid Build Coastguard Worker 
256*e5436536SAndroid Build Coastguard Worker  The input values Energies[0] (low-band) are scaled by the factor
257*e5436536SAndroid Build Coastguard Worker  2^(14-*scaleEnergies[0])
258*e5436536SAndroid Build Coastguard Worker  The input values Energies[1] (high-band) are scaled by the factor
259*e5436536SAndroid Build Coastguard Worker  2^(14-*scaleEnergies[1])
260*e5436536SAndroid Build Coastguard Worker 
261*e5436536SAndroid Build Coastguard Worker  \return  total energy in the lowband, scaled by the factor 2^19
262*e5436536SAndroid Build Coastguard Worker *******************************************************************************/
addLowbandEnergies(FIXP_DBL ** Energies,int * scaleEnergies,int YBufferWriteOffset,int nrgSzShift,int tran_off,UCHAR * freqBandTable,int slots)263*e5436536SAndroid Build Coastguard Worker static FIXP_DBL addLowbandEnergies(FIXP_DBL **Energies, int *scaleEnergies,
264*e5436536SAndroid Build Coastguard Worker                                    int YBufferWriteOffset, int nrgSzShift,
265*e5436536SAndroid Build Coastguard Worker                                    int tran_off, UCHAR *freqBandTable,
266*e5436536SAndroid Build Coastguard Worker                                    int slots) {
267*e5436536SAndroid Build Coastguard Worker   INT nrgTotal_e;
268*e5436536SAndroid Build Coastguard Worker   FIXP_DBL nrgTotal_m;
269*e5436536SAndroid Build Coastguard Worker   FIXP_DBL accu1 = FL2FXCONST_DBL(0.0f);
270*e5436536SAndroid Build Coastguard Worker   FIXP_DBL accu2 = FL2FXCONST_DBL(0.0f);
271*e5436536SAndroid Build Coastguard Worker   int tran_offdiv2 = tran_off >> nrgSzShift;
272*e5436536SAndroid Build Coastguard Worker   const int sc1 =
273*e5436536SAndroid Build Coastguard Worker       DFRACT_BITS -
274*e5436536SAndroid Build Coastguard Worker       fNormz((FIXP_DBL)fMax(
275*e5436536SAndroid Build Coastguard Worker           1, (freqBandTable[0] * (YBufferWriteOffset - tran_offdiv2) - 1)));
276*e5436536SAndroid Build Coastguard Worker   const int sc2 =
277*e5436536SAndroid Build Coastguard Worker       DFRACT_BITS -
278*e5436536SAndroid Build Coastguard Worker       fNormz((FIXP_DBL)fMax(
279*e5436536SAndroid Build Coastguard Worker           1, (freqBandTable[0] *
280*e5436536SAndroid Build Coastguard Worker                   (tran_offdiv2 + (slots >> nrgSzShift) - YBufferWriteOffset) -
281*e5436536SAndroid Build Coastguard Worker               1)));
282*e5436536SAndroid Build Coastguard Worker   int ts, k;
283*e5436536SAndroid Build Coastguard Worker 
284*e5436536SAndroid Build Coastguard Worker   /* Sum up lowband energy from one frame at offset tran_off */
285*e5436536SAndroid Build Coastguard Worker   /* freqBandTable[LORES] has MAX_FREQ_COEFFS/2 +1 coeefs max. */
286*e5436536SAndroid Build Coastguard Worker   for (ts = tran_offdiv2; ts < YBufferWriteOffset; ts++) {
287*e5436536SAndroid Build Coastguard Worker     for (k = 0; k < freqBandTable[0]; k++) {
288*e5436536SAndroid Build Coastguard Worker       accu1 += Energies[ts][k] >> sc1;
289*e5436536SAndroid Build Coastguard Worker     }
290*e5436536SAndroid Build Coastguard Worker   }
291*e5436536SAndroid Build Coastguard Worker   for (; ts < tran_offdiv2 + (slots >> nrgSzShift); ts++) {
292*e5436536SAndroid Build Coastguard Worker     for (k = 0; k < freqBandTable[0]; k++) {
293*e5436536SAndroid Build Coastguard Worker       accu2 += Energies[ts][k] >> sc2;
294*e5436536SAndroid Build Coastguard Worker     }
295*e5436536SAndroid Build Coastguard Worker   }
296*e5436536SAndroid Build Coastguard Worker 
297*e5436536SAndroid Build Coastguard Worker   nrgTotal_m = fAddNorm(accu1, (sc1 - 5) - scaleEnergies[0], accu2,
298*e5436536SAndroid Build Coastguard Worker                         (sc2 - 5) - scaleEnergies[1], &nrgTotal_e);
299*e5436536SAndroid Build Coastguard Worker   nrgTotal_m = scaleValueSaturate(nrgTotal_m, nrgTotal_e);
300*e5436536SAndroid Build Coastguard Worker 
301*e5436536SAndroid Build Coastguard Worker   return (nrgTotal_m);
302*e5436536SAndroid Build Coastguard Worker }
303*e5436536SAndroid Build Coastguard Worker 
304*e5436536SAndroid Build Coastguard Worker /*******************************************************************************
305*e5436536SAndroid Build Coastguard Worker  Functionname:  addHighbandEnergies
306*e5436536SAndroid Build Coastguard Worker  *******************************************************************************
307*e5436536SAndroid Build Coastguard Worker  \brief   Add highband energies
308*e5436536SAndroid Build Coastguard Worker 
309*e5436536SAndroid Build Coastguard Worker  Highband energies are mapped to an array with smaller dimension:
310*e5436536SAndroid Build Coastguard Worker  Its time resolution is only 1 SBR-timeslot and its frequency resolution
311*e5436536SAndroid Build Coastguard Worker  is 1 SBR-band. Therefore the data to be fed into the spectralChange
312*e5436536SAndroid Build Coastguard Worker  function is reduced.
313*e5436536SAndroid Build Coastguard Worker 
314*e5436536SAndroid Build Coastguard Worker  The values EnergiesM are scaled by the factor (2^19-scaleEnergies[0]) for
315*e5436536SAndroid Build Coastguard Worker  slots<YBufferWriteOffset and by the factor (2^19-scaleEnergies[1]) for
316*e5436536SAndroid Build Coastguard Worker  slots>=YBufferWriteOffset.
317*e5436536SAndroid Build Coastguard Worker 
318*e5436536SAndroid Build Coastguard Worker  \return  total energy in the highband, scaled by factor 2^19
319*e5436536SAndroid Build Coastguard Worker *******************************************************************************/
320*e5436536SAndroid Build Coastguard Worker 
addHighbandEnergies(FIXP_DBL ** RESTRICT Energies,INT * scaleEnergies,INT YBufferWriteOffset,FIXP_DBL EnergiesM[NUMBER_TIME_SLOTS_2304][MAX_FREQ_COEFFS],UCHAR * RESTRICT freqBandTable,INT nSfb,INT sbrSlots,INT timeStep)321*e5436536SAndroid Build Coastguard Worker static FIXP_DBL addHighbandEnergies(
322*e5436536SAndroid Build Coastguard Worker     FIXP_DBL **RESTRICT Energies, /*!< input */
323*e5436536SAndroid Build Coastguard Worker     INT *scaleEnergies, INT YBufferWriteOffset,
324*e5436536SAndroid Build Coastguard Worker     FIXP_DBL EnergiesM[NUMBER_TIME_SLOTS_2304]
325*e5436536SAndroid Build Coastguard Worker                       [MAX_FREQ_COEFFS], /*!< Combined output */
326*e5436536SAndroid Build Coastguard Worker     UCHAR *RESTRICT freqBandTable, INT nSfb, INT sbrSlots, INT timeStep) {
327*e5436536SAndroid Build Coastguard Worker   INT i, j, k, slotIn, slotOut, scale[2];
328*e5436536SAndroid Build Coastguard Worker   INT li, ui;
329*e5436536SAndroid Build Coastguard Worker   FIXP_DBL nrgTotal;
330*e5436536SAndroid Build Coastguard Worker   FIXP_DBL accu = FL2FXCONST_DBL(0.0f);
331*e5436536SAndroid Build Coastguard Worker 
332*e5436536SAndroid Build Coastguard Worker   /* Combine QMF-timeslots to SBR-timeslots,
333*e5436536SAndroid Build Coastguard Worker      combine QMF-bands to SBR-bands,
334*e5436536SAndroid Build Coastguard Worker      combine Left and Right channel */
335*e5436536SAndroid Build Coastguard Worker   for (slotOut = 0; slotOut < sbrSlots; slotOut++) {
336*e5436536SAndroid Build Coastguard Worker     /* Note: Below slotIn = slotOut and not slotIn = timeStep*slotOut
337*e5436536SAndroid Build Coastguard Worker        because the Energies[] time resolution is always the SBR slot resolution
338*e5436536SAndroid Build Coastguard Worker        regardless of the timeStep. */
339*e5436536SAndroid Build Coastguard Worker     slotIn = slotOut;
340*e5436536SAndroid Build Coastguard Worker 
341*e5436536SAndroid Build Coastguard Worker     for (j = 0; j < nSfb; j++) {
342*e5436536SAndroid Build Coastguard Worker       accu = FL2FXCONST_DBL(0.0f);
343*e5436536SAndroid Build Coastguard Worker 
344*e5436536SAndroid Build Coastguard Worker       li = freqBandTable[j];
345*e5436536SAndroid Build Coastguard Worker       ui = freqBandTable[j + 1];
346*e5436536SAndroid Build Coastguard Worker 
347*e5436536SAndroid Build Coastguard Worker       for (k = li; k < ui; k++) {
348*e5436536SAndroid Build Coastguard Worker         for (i = 0; i < timeStep; i++) {
349*e5436536SAndroid Build Coastguard Worker           accu += Energies[slotIn][k] >> 5;
350*e5436536SAndroid Build Coastguard Worker         }
351*e5436536SAndroid Build Coastguard Worker       }
352*e5436536SAndroid Build Coastguard Worker       EnergiesM[slotOut][j] = accu;
353*e5436536SAndroid Build Coastguard Worker     }
354*e5436536SAndroid Build Coastguard Worker   }
355*e5436536SAndroid Build Coastguard Worker 
356*e5436536SAndroid Build Coastguard Worker   /* scale energies down before add up */
357*e5436536SAndroid Build Coastguard Worker   scale[0] = fixMin(8, scaleEnergies[0]);
358*e5436536SAndroid Build Coastguard Worker   scale[1] = fixMin(8, scaleEnergies[1]);
359*e5436536SAndroid Build Coastguard Worker 
360*e5436536SAndroid Build Coastguard Worker   if ((scaleEnergies[0] - scale[0]) > (DFRACT_BITS - 1) ||
361*e5436536SAndroid Build Coastguard Worker       (scaleEnergies[1] - scale[1]) > (DFRACT_BITS - 1))
362*e5436536SAndroid Build Coastguard Worker     nrgTotal = FL2FXCONST_DBL(0.0f);
363*e5436536SAndroid Build Coastguard Worker   else {
364*e5436536SAndroid Build Coastguard Worker     /* Now add all energies */
365*e5436536SAndroid Build Coastguard Worker     accu = FL2FXCONST_DBL(0.0f);
366*e5436536SAndroid Build Coastguard Worker 
367*e5436536SAndroid Build Coastguard Worker     for (slotOut = 0; slotOut < YBufferWriteOffset; slotOut++) {
368*e5436536SAndroid Build Coastguard Worker       for (j = 0; j < nSfb; j++) {
369*e5436536SAndroid Build Coastguard Worker         accu += (EnergiesM[slotOut][j] >> scale[0]);
370*e5436536SAndroid Build Coastguard Worker       }
371*e5436536SAndroid Build Coastguard Worker     }
372*e5436536SAndroid Build Coastguard Worker     nrgTotal = accu >> (scaleEnergies[0] - scale[0]);
373*e5436536SAndroid Build Coastguard Worker 
374*e5436536SAndroid Build Coastguard Worker     for (slotOut = YBufferWriteOffset; slotOut < sbrSlots; slotOut++) {
375*e5436536SAndroid Build Coastguard Worker       for (j = 0; j < nSfb; j++) {
376*e5436536SAndroid Build Coastguard Worker         accu += (EnergiesM[slotOut][j] >> scale[0]);
377*e5436536SAndroid Build Coastguard Worker       }
378*e5436536SAndroid Build Coastguard Worker     }
379*e5436536SAndroid Build Coastguard Worker     nrgTotal = fAddSaturate(nrgTotal, accu >> (scaleEnergies[1] - scale[1]));
380*e5436536SAndroid Build Coastguard Worker   }
381*e5436536SAndroid Build Coastguard Worker 
382*e5436536SAndroid Build Coastguard Worker   return (nrgTotal);
383*e5436536SAndroid Build Coastguard Worker }
384*e5436536SAndroid Build Coastguard Worker 
385*e5436536SAndroid Build Coastguard Worker /*******************************************************************************
386*e5436536SAndroid Build Coastguard Worker  Functionname:  FDKsbrEnc_frameSplitter
387*e5436536SAndroid Build Coastguard Worker  *******************************************************************************
388*e5436536SAndroid Build Coastguard Worker  \brief   Decides if a FIXFIX-frame shall be splitted into 2 envelopes
389*e5436536SAndroid Build Coastguard Worker 
390*e5436536SAndroid Build Coastguard Worker  If no transient has been detected before, the frame can still be splitted
391*e5436536SAndroid Build Coastguard Worker  into 2 envelopes.
392*e5436536SAndroid Build Coastguard Worker *******************************************************************************/
FDKsbrEnc_frameSplitter(FIXP_DBL ** Energies,INT * scaleEnergies,HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTransientDetector,UCHAR * freqBandTable,UCHAR * tran_vector,int YBufferWriteOffset,int YBufferSzShift,int nSfb,int timeStep,int no_cols,FIXP_DBL * tonality)393*e5436536SAndroid Build Coastguard Worker void FDKsbrEnc_frameSplitter(
394*e5436536SAndroid Build Coastguard Worker     FIXP_DBL **Energies, INT *scaleEnergies,
395*e5436536SAndroid Build Coastguard Worker     HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTransientDetector, UCHAR *freqBandTable,
396*e5436536SAndroid Build Coastguard Worker     UCHAR *tran_vector, int YBufferWriteOffset, int YBufferSzShift, int nSfb,
397*e5436536SAndroid Build Coastguard Worker     int timeStep, int no_cols, FIXP_DBL *tonality) {
398*e5436536SAndroid Build Coastguard Worker   if (tran_vector[1] == 0) /* no transient was detected */
399*e5436536SAndroid Build Coastguard Worker   {
400*e5436536SAndroid Build Coastguard Worker     FIXP_DBL delta;
401*e5436536SAndroid Build Coastguard Worker     INT delta_e;
402*e5436536SAndroid Build Coastguard Worker     FIXP_DBL(*EnergiesM)[MAX_FREQ_COEFFS];
403*e5436536SAndroid Build Coastguard Worker     FIXP_DBL EnergyTotal, newLowbandEnergy, newHighbandEnergy;
404*e5436536SAndroid Build Coastguard Worker     INT border;
405*e5436536SAndroid Build Coastguard Worker     INT sbrSlots = fMultI(GetInvInt(timeStep), no_cols);
406*e5436536SAndroid Build Coastguard Worker     C_ALLOC_SCRATCH_START(_EnergiesM, FIXP_DBL,
407*e5436536SAndroid Build Coastguard Worker                           NUMBER_TIME_SLOTS_2304 * MAX_FREQ_COEFFS)
408*e5436536SAndroid Build Coastguard Worker 
409*e5436536SAndroid Build Coastguard Worker     FDK_ASSERT(sbrSlots * timeStep == no_cols);
410*e5436536SAndroid Build Coastguard Worker 
411*e5436536SAndroid Build Coastguard Worker     EnergiesM = (FIXP_DBL(*)[MAX_FREQ_COEFFS])_EnergiesM;
412*e5436536SAndroid Build Coastguard Worker 
413*e5436536SAndroid Build Coastguard Worker     /*
414*e5436536SAndroid Build Coastguard Worker       Get Lowband-energy over a range of 2 frames (Look half a frame back and
415*e5436536SAndroid Build Coastguard Worker       ahead).
416*e5436536SAndroid Build Coastguard Worker     */
417*e5436536SAndroid Build Coastguard Worker     newLowbandEnergy = addLowbandEnergies(
418*e5436536SAndroid Build Coastguard Worker         Energies, scaleEnergies, YBufferWriteOffset, YBufferSzShift,
419*e5436536SAndroid Build Coastguard Worker         h_sbrTransientDetector->tran_off, freqBandTable, no_cols);
420*e5436536SAndroid Build Coastguard Worker 
421*e5436536SAndroid Build Coastguard Worker     newHighbandEnergy =
422*e5436536SAndroid Build Coastguard Worker         addHighbandEnergies(Energies, scaleEnergies, YBufferWriteOffset,
423*e5436536SAndroid Build Coastguard Worker                             EnergiesM, freqBandTable, nSfb, sbrSlots, timeStep);
424*e5436536SAndroid Build Coastguard Worker 
425*e5436536SAndroid Build Coastguard Worker     {
426*e5436536SAndroid Build Coastguard Worker       /* prevLowBandEnergy: Corresponds to 1 frame, starting with half a frame
427*e5436536SAndroid Build Coastguard Worker          look-behind newLowbandEnergy:  Corresponds to 1 frame, starting in the
428*e5436536SAndroid Build Coastguard Worker          middle of the current frame */
429*e5436536SAndroid Build Coastguard Worker       EnergyTotal = (newLowbandEnergy >> 1) +
430*e5436536SAndroid Build Coastguard Worker                     (h_sbrTransientDetector->prevLowBandEnergy >>
431*e5436536SAndroid Build Coastguard Worker                      1); /* mean of new and prev LB NRG */
432*e5436536SAndroid Build Coastguard Worker       EnergyTotal =
433*e5436536SAndroid Build Coastguard Worker           fAddSaturate(EnergyTotal, newHighbandEnergy); /* Add HB NRG */
434*e5436536SAndroid Build Coastguard Worker       /* The below border should specify the same position as the middle border
435*e5436536SAndroid Build Coastguard Worker          of a FIXFIX-frame with 2 envelopes. */
436*e5436536SAndroid Build Coastguard Worker       border = (sbrSlots + 1) >> 1;
437*e5436536SAndroid Build Coastguard Worker 
438*e5436536SAndroid Build Coastguard Worker       if ((INT)EnergyTotal & 0xffffffe0 &&
439*e5436536SAndroid Build Coastguard Worker           (scaleEnergies[0] < 32 || scaleEnergies[1] < 32)) /* i.e. > 31 */ {
440*e5436536SAndroid Build Coastguard Worker         delta = spectralChange(EnergiesM, scaleEnergies, EnergyTotal, nSfb, 0,
441*e5436536SAndroid Build Coastguard Worker                                border, YBufferWriteOffset, sbrSlots, &delta_e);
442*e5436536SAndroid Build Coastguard Worker       } else {
443*e5436536SAndroid Build Coastguard Worker         delta = FL2FXCONST_DBL(0.0f);
444*e5436536SAndroid Build Coastguard Worker         delta_e = 0;
445*e5436536SAndroid Build Coastguard Worker 
446*e5436536SAndroid Build Coastguard Worker         /* set tonality to 0 when energy is very low, since the amplitude
447*e5436536SAndroid Build Coastguard Worker            resolution should then be low as well                          */
448*e5436536SAndroid Build Coastguard Worker         *tonality = FL2FXCONST_DBL(0.0f);
449*e5436536SAndroid Build Coastguard Worker       }
450*e5436536SAndroid Build Coastguard Worker 
451*e5436536SAndroid Build Coastguard Worker       if (fIsLessThan(h_sbrTransientDetector->split_thr_m,
452*e5436536SAndroid Build Coastguard Worker                       h_sbrTransientDetector->split_thr_e, delta, delta_e)) {
453*e5436536SAndroid Build Coastguard Worker         tran_vector[0] = 1; /* Set flag for splitting */
454*e5436536SAndroid Build Coastguard Worker       } else {
455*e5436536SAndroid Build Coastguard Worker         tran_vector[0] = 0;
456*e5436536SAndroid Build Coastguard Worker       }
457*e5436536SAndroid Build Coastguard Worker     }
458*e5436536SAndroid Build Coastguard Worker 
459*e5436536SAndroid Build Coastguard Worker     /* Update prevLowBandEnergy */
460*e5436536SAndroid Build Coastguard Worker     h_sbrTransientDetector->prevLowBandEnergy = newLowbandEnergy;
461*e5436536SAndroid Build Coastguard Worker     h_sbrTransientDetector->prevHighBandEnergy = newHighbandEnergy;
462*e5436536SAndroid Build Coastguard Worker     C_ALLOC_SCRATCH_END(_EnergiesM, FIXP_DBL,
463*e5436536SAndroid Build Coastguard Worker                         NUMBER_TIME_SLOTS_2304 * MAX_FREQ_COEFFS)
464*e5436536SAndroid Build Coastguard Worker   }
465*e5436536SAndroid Build Coastguard Worker }
466*e5436536SAndroid Build Coastguard Worker 
467*e5436536SAndroid Build Coastguard Worker /*
468*e5436536SAndroid Build Coastguard Worker  * Calculate transient energy threshold for each QMF band
469*e5436536SAndroid Build Coastguard Worker  */
calculateThresholds(FIXP_DBL ** RESTRICT Energies,INT * RESTRICT scaleEnergies,FIXP_DBL * RESTRICT thresholds,int YBufferWriteOffset,int YBufferSzShift,int noCols,int noRows,int tran_off)470*e5436536SAndroid Build Coastguard Worker static void calculateThresholds(FIXP_DBL **RESTRICT Energies,
471*e5436536SAndroid Build Coastguard Worker                                 INT *RESTRICT scaleEnergies,
472*e5436536SAndroid Build Coastguard Worker                                 FIXP_DBL *RESTRICT thresholds,
473*e5436536SAndroid Build Coastguard Worker                                 int YBufferWriteOffset, int YBufferSzShift,
474*e5436536SAndroid Build Coastguard Worker                                 int noCols, int noRows, int tran_off) {
475*e5436536SAndroid Build Coastguard Worker   FIXP_DBL mean_val, std_val, temp;
476*e5436536SAndroid Build Coastguard Worker   FIXP_DBL i_noCols;
477*e5436536SAndroid Build Coastguard Worker   FIXP_DBL i_noCols1;
478*e5436536SAndroid Build Coastguard Worker   FIXP_DBL accu, accu0, accu1;
479*e5436536SAndroid Build Coastguard Worker   int scaleFactor0, scaleFactor1, commonScale;
480*e5436536SAndroid Build Coastguard Worker   int i, j;
481*e5436536SAndroid Build Coastguard Worker 
482*e5436536SAndroid Build Coastguard Worker   i_noCols = GetInvInt(noCols + tran_off) << YBufferSzShift;
483*e5436536SAndroid Build Coastguard Worker   i_noCols1 = GetInvInt(noCols + tran_off - 1) << YBufferSzShift;
484*e5436536SAndroid Build Coastguard Worker 
485*e5436536SAndroid Build Coastguard Worker   /* calc minimum scale of energies of previous and current frame */
486*e5436536SAndroid Build Coastguard Worker   commonScale = fixMin(scaleEnergies[0], scaleEnergies[1]);
487*e5436536SAndroid Build Coastguard Worker 
488*e5436536SAndroid Build Coastguard Worker   /* calc scalefactors to adapt energies to common scale */
489*e5436536SAndroid Build Coastguard Worker   scaleFactor0 = fixMin((scaleEnergies[0] - commonScale), (DFRACT_BITS - 1));
490*e5436536SAndroid Build Coastguard Worker   scaleFactor1 = fixMin((scaleEnergies[1] - commonScale), (DFRACT_BITS - 1));
491*e5436536SAndroid Build Coastguard Worker 
492*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT((scaleFactor0 >= 0) && (scaleFactor1 >= 0));
493*e5436536SAndroid Build Coastguard Worker 
494*e5436536SAndroid Build Coastguard Worker   /* calculate standard deviation in every subband */
495*e5436536SAndroid Build Coastguard Worker   for (i = 0; i < noRows; i++) {
496*e5436536SAndroid Build Coastguard Worker     int startEnergy = (tran_off >> YBufferSzShift);
497*e5436536SAndroid Build Coastguard Worker     int endEnergy = ((noCols >> YBufferSzShift) + tran_off);
498*e5436536SAndroid Build Coastguard Worker     int shift;
499*e5436536SAndroid Build Coastguard Worker 
500*e5436536SAndroid Build Coastguard Worker     /* calculate mean value over decimated energy values (downsampled by 2). */
501*e5436536SAndroid Build Coastguard Worker     accu0 = accu1 = FL2FXCONST_DBL(0.0f);
502*e5436536SAndroid Build Coastguard Worker 
503*e5436536SAndroid Build Coastguard Worker     for (j = startEnergy; j < YBufferWriteOffset; j++)
504*e5436536SAndroid Build Coastguard Worker       accu0 = fMultAddDiv2(accu0, Energies[j][i], i_noCols);
505*e5436536SAndroid Build Coastguard Worker     for (; j < endEnergy; j++)
506*e5436536SAndroid Build Coastguard Worker       accu1 = fMultAddDiv2(accu1, Energies[j][i], i_noCols);
507*e5436536SAndroid Build Coastguard Worker 
508*e5436536SAndroid Build Coastguard Worker     mean_val = ((accu0 << 1) >> scaleFactor0) +
509*e5436536SAndroid Build Coastguard Worker                ((accu1 << 1) >> scaleFactor1); /* average */
510*e5436536SAndroid Build Coastguard Worker     shift = fixMax(
511*e5436536SAndroid Build Coastguard Worker         0, CountLeadingBits(mean_val) -
512*e5436536SAndroid Build Coastguard Worker                6); /* -6 to keep room for accumulating upto N = 24 values */
513*e5436536SAndroid Build Coastguard Worker 
514*e5436536SAndroid Build Coastguard Worker     /* calculate standard deviation */
515*e5436536SAndroid Build Coastguard Worker     accu = FL2FXCONST_DBL(0.0f);
516*e5436536SAndroid Build Coastguard Worker 
517*e5436536SAndroid Build Coastguard Worker     /* summe { ((mean_val-nrg)^2) * i_noCols1 } */
518*e5436536SAndroid Build Coastguard Worker     for (j = startEnergy; j < YBufferWriteOffset; j++) {
519*e5436536SAndroid Build Coastguard Worker       temp = ((FIXP_DBL)mean_val - ((FIXP_DBL)Energies[j][i] >> scaleFactor0))
520*e5436536SAndroid Build Coastguard Worker              << shift;
521*e5436536SAndroid Build Coastguard Worker       temp = fPow2Div2(temp);
522*e5436536SAndroid Build Coastguard Worker       accu = fMultAddDiv2(accu, temp, i_noCols1);
523*e5436536SAndroid Build Coastguard Worker     }
524*e5436536SAndroid Build Coastguard Worker     for (; j < endEnergy; j++) {
525*e5436536SAndroid Build Coastguard Worker       temp = ((FIXP_DBL)mean_val - ((FIXP_DBL)Energies[j][i] >> scaleFactor1))
526*e5436536SAndroid Build Coastguard Worker              << shift;
527*e5436536SAndroid Build Coastguard Worker       temp = fPow2Div2(temp);
528*e5436536SAndroid Build Coastguard Worker       accu = fMultAddDiv2(accu, temp, i_noCols1);
529*e5436536SAndroid Build Coastguard Worker     }
530*e5436536SAndroid Build Coastguard Worker     accu <<= 2;
531*e5436536SAndroid Build Coastguard Worker     std_val = sqrtFixp(accu) >> shift; /* standard deviation */
532*e5436536SAndroid Build Coastguard Worker 
533*e5436536SAndroid Build Coastguard Worker     /*
534*e5436536SAndroid Build Coastguard Worker     Take new threshold as average of calculated standard deviation ratio
535*e5436536SAndroid Build Coastguard Worker     and old threshold if greater than absolute threshold
536*e5436536SAndroid Build Coastguard Worker     */
537*e5436536SAndroid Build Coastguard Worker     temp = (commonScale <= (DFRACT_BITS - 1))
538*e5436536SAndroid Build Coastguard Worker                ? fMult(FL2FXCONST_DBL(0.66f), thresholds[i]) +
539*e5436536SAndroid Build Coastguard Worker                      (fMult(FL2FXCONST_DBL(0.34f), std_val) >> commonScale)
540*e5436536SAndroid Build Coastguard Worker                : (FIXP_DBL)0;
541*e5436536SAndroid Build Coastguard Worker 
542*e5436536SAndroid Build Coastguard Worker     thresholds[i] = fixMax(ABS_THRES, temp);
543*e5436536SAndroid Build Coastguard Worker 
544*e5436536SAndroid Build Coastguard Worker     FDK_ASSERT(commonScale >= 0);
545*e5436536SAndroid Build Coastguard Worker   }
546*e5436536SAndroid Build Coastguard Worker }
547*e5436536SAndroid Build Coastguard Worker 
548*e5436536SAndroid Build Coastguard Worker /*
549*e5436536SAndroid Build Coastguard Worker  * Calculate transient levels for each QMF time slot.
550*e5436536SAndroid Build Coastguard Worker  */
extractTransientCandidates(FIXP_DBL ** RESTRICT Energies,INT * RESTRICT scaleEnergies,FIXP_DBL * RESTRICT thresholds,FIXP_DBL * RESTRICT transients,int YBufferWriteOffset,int YBufferSzShift,int noCols,int start_band,int stop_band,int tran_off,int addPrevSamples)551*e5436536SAndroid Build Coastguard Worker static void extractTransientCandidates(
552*e5436536SAndroid Build Coastguard Worker     FIXP_DBL **RESTRICT Energies, INT *RESTRICT scaleEnergies,
553*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *RESTRICT thresholds, FIXP_DBL *RESTRICT transients,
554*e5436536SAndroid Build Coastguard Worker     int YBufferWriteOffset, int YBufferSzShift, int noCols, int start_band,
555*e5436536SAndroid Build Coastguard Worker     int stop_band, int tran_off, int addPrevSamples) {
556*e5436536SAndroid Build Coastguard Worker   FIXP_DBL i_thres;
557*e5436536SAndroid Build Coastguard Worker   C_ALLOC_SCRATCH_START(EnergiesTemp, FIXP_DBL, 2 * 32)
558*e5436536SAndroid Build Coastguard Worker   int tmpScaleEnergies0, tmpScaleEnergies1;
559*e5436536SAndroid Build Coastguard Worker   int endCond;
560*e5436536SAndroid Build Coastguard Worker   int startEnerg, endEnerg;
561*e5436536SAndroid Build Coastguard Worker   int i, j, jIndex, jpBM;
562*e5436536SAndroid Build Coastguard Worker 
563*e5436536SAndroid Build Coastguard Worker   tmpScaleEnergies0 = scaleEnergies[0];
564*e5436536SAndroid Build Coastguard Worker   tmpScaleEnergies1 = scaleEnergies[1];
565*e5436536SAndroid Build Coastguard Worker 
566*e5436536SAndroid Build Coastguard Worker   /* Scale value for first energies, upto YBufferWriteOffset */
567*e5436536SAndroid Build Coastguard Worker   tmpScaleEnergies0 = fixMin(tmpScaleEnergies0, MAX_SHIFT_DBL);
568*e5436536SAndroid Build Coastguard Worker   /* Scale value for first energies, from YBufferWriteOffset upwards */
569*e5436536SAndroid Build Coastguard Worker   tmpScaleEnergies1 = fixMin(tmpScaleEnergies1, MAX_SHIFT_DBL);
570*e5436536SAndroid Build Coastguard Worker 
571*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT((tmpScaleEnergies0 >= 0) && (tmpScaleEnergies1 >= 0));
572*e5436536SAndroid Build Coastguard Worker 
573*e5436536SAndroid Build Coastguard Worker   /* Keep addPrevSamples extra previous transient candidates. */
574*e5436536SAndroid Build Coastguard Worker   FDKmemmove(transients, transients + noCols - addPrevSamples,
575*e5436536SAndroid Build Coastguard Worker              (tran_off + addPrevSamples) * sizeof(FIXP_DBL));
576*e5436536SAndroid Build Coastguard Worker   FDKmemclear(transients + tran_off + addPrevSamples,
577*e5436536SAndroid Build Coastguard Worker               noCols * sizeof(FIXP_DBL));
578*e5436536SAndroid Build Coastguard Worker 
579*e5436536SAndroid Build Coastguard Worker   endCond = noCols; /* Amount of new transient values to be calculated. */
580*e5436536SAndroid Build Coastguard Worker   startEnerg = (tran_off - 3) >> YBufferSzShift; /* >>YBufferSzShift because of
581*e5436536SAndroid Build Coastguard Worker                                                     amount of energy values. -3
582*e5436536SAndroid Build Coastguard Worker                                                     because of neighbors being
583*e5436536SAndroid Build Coastguard Worker                                                     watched. */
584*e5436536SAndroid Build Coastguard Worker   endEnerg =
585*e5436536SAndroid Build Coastguard Worker       ((noCols + (YBufferWriteOffset << YBufferSzShift)) - 1) >>
586*e5436536SAndroid Build Coastguard Worker       YBufferSzShift; /* YBufferSzShift shifts because of half energy values. */
587*e5436536SAndroid Build Coastguard Worker 
588*e5436536SAndroid Build Coastguard Worker   /* Compute differential values with two different weightings in every subband
589*e5436536SAndroid Build Coastguard Worker    */
590*e5436536SAndroid Build Coastguard Worker   for (i = start_band; i < stop_band; i++) {
591*e5436536SAndroid Build Coastguard Worker     FIXP_DBL thres = thresholds[i];
592*e5436536SAndroid Build Coastguard Worker 
593*e5436536SAndroid Build Coastguard Worker     if ((LONG)thresholds[i] >= 256)
594*e5436536SAndroid Build Coastguard Worker       i_thres = (LONG)((LONG)MAXVAL_DBL / ((((LONG)thresholds[i])) + 1))
595*e5436536SAndroid Build Coastguard Worker                 << (32 - 24);
596*e5436536SAndroid Build Coastguard Worker     else
597*e5436536SAndroid Build Coastguard Worker       i_thres = (LONG)MAXVAL_DBL;
598*e5436536SAndroid Build Coastguard Worker 
599*e5436536SAndroid Build Coastguard Worker     /* Copy one timeslot and de-scale and de-squish */
600*e5436536SAndroid Build Coastguard Worker     if (YBufferSzShift == 1) {
601*e5436536SAndroid Build Coastguard Worker       for (j = startEnerg; j < YBufferWriteOffset; j++) {
602*e5436536SAndroid Build Coastguard Worker         FIXP_DBL tmp = Energies[j][i];
603*e5436536SAndroid Build Coastguard Worker         EnergiesTemp[(j << 1) + 1] = EnergiesTemp[j << 1] =
604*e5436536SAndroid Build Coastguard Worker             tmp >> tmpScaleEnergies0;
605*e5436536SAndroid Build Coastguard Worker       }
606*e5436536SAndroid Build Coastguard Worker       for (; j <= endEnerg; j++) {
607*e5436536SAndroid Build Coastguard Worker         FIXP_DBL tmp = Energies[j][i];
608*e5436536SAndroid Build Coastguard Worker         EnergiesTemp[(j << 1) + 1] = EnergiesTemp[j << 1] =
609*e5436536SAndroid Build Coastguard Worker             tmp >> tmpScaleEnergies1;
610*e5436536SAndroid Build Coastguard Worker       }
611*e5436536SAndroid Build Coastguard Worker     } else {
612*e5436536SAndroid Build Coastguard Worker       for (j = startEnerg; j < YBufferWriteOffset; j++) {
613*e5436536SAndroid Build Coastguard Worker         FIXP_DBL tmp = Energies[j][i];
614*e5436536SAndroid Build Coastguard Worker         EnergiesTemp[j] = tmp >> tmpScaleEnergies0;
615*e5436536SAndroid Build Coastguard Worker       }
616*e5436536SAndroid Build Coastguard Worker       for (; j <= endEnerg; j++) {
617*e5436536SAndroid Build Coastguard Worker         FIXP_DBL tmp = Energies[j][i];
618*e5436536SAndroid Build Coastguard Worker         EnergiesTemp[j] = tmp >> tmpScaleEnergies1;
619*e5436536SAndroid Build Coastguard Worker       }
620*e5436536SAndroid Build Coastguard Worker     }
621*e5436536SAndroid Build Coastguard Worker 
622*e5436536SAndroid Build Coastguard Worker     /* Detect peaks in energy values. */
623*e5436536SAndroid Build Coastguard Worker 
624*e5436536SAndroid Build Coastguard Worker     jIndex = tran_off;
625*e5436536SAndroid Build Coastguard Worker     jpBM = jIndex + addPrevSamples;
626*e5436536SAndroid Build Coastguard Worker 
627*e5436536SAndroid Build Coastguard Worker     for (j = endCond; j--; jIndex++, jpBM++) {
628*e5436536SAndroid Build Coastguard Worker       FIXP_DBL delta, tran;
629*e5436536SAndroid Build Coastguard Worker       int d;
630*e5436536SAndroid Build Coastguard Worker 
631*e5436536SAndroid Build Coastguard Worker       delta = (FIXP_DBL)0;
632*e5436536SAndroid Build Coastguard Worker       tran = (FIXP_DBL)0;
633*e5436536SAndroid Build Coastguard Worker 
634*e5436536SAndroid Build Coastguard Worker       for (d = 1; d < 4; d++) {
635*e5436536SAndroid Build Coastguard Worker         delta += EnergiesTemp[jIndex + d]; /* R */
636*e5436536SAndroid Build Coastguard Worker         delta -= EnergiesTemp[jIndex - d]; /* L */
637*e5436536SAndroid Build Coastguard Worker         delta -= thres;
638*e5436536SAndroid Build Coastguard Worker 
639*e5436536SAndroid Build Coastguard Worker         if (delta > (FIXP_DBL)0) {
640*e5436536SAndroid Build Coastguard Worker           tran = fMultAddDiv2(tran, i_thres, delta);
641*e5436536SAndroid Build Coastguard Worker         }
642*e5436536SAndroid Build Coastguard Worker       }
643*e5436536SAndroid Build Coastguard Worker       transients[jpBM] += (tran << 1);
644*e5436536SAndroid Build Coastguard Worker     }
645*e5436536SAndroid Build Coastguard Worker   }
646*e5436536SAndroid Build Coastguard Worker   C_ALLOC_SCRATCH_END(EnergiesTemp, FIXP_DBL, 2 * 32)
647*e5436536SAndroid Build Coastguard Worker }
648*e5436536SAndroid Build Coastguard Worker 
FDKsbrEnc_transientDetect(HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTran,FIXP_DBL ** Energies,INT * scaleEnergies,UCHAR * transient_info,int YBufferWriteOffset,int YBufferSzShift,int timeStep,int frameMiddleBorder)649*e5436536SAndroid Build Coastguard Worker void FDKsbrEnc_transientDetect(HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTran,
650*e5436536SAndroid Build Coastguard Worker                                FIXP_DBL **Energies, INT *scaleEnergies,
651*e5436536SAndroid Build Coastguard Worker                                UCHAR *transient_info, int YBufferWriteOffset,
652*e5436536SAndroid Build Coastguard Worker                                int YBufferSzShift, int timeStep,
653*e5436536SAndroid Build Coastguard Worker                                int frameMiddleBorder) {
654*e5436536SAndroid Build Coastguard Worker   int no_cols = h_sbrTran->no_cols;
655*e5436536SAndroid Build Coastguard Worker   int qmfStartSample;
656*e5436536SAndroid Build Coastguard Worker   int addPrevSamples;
657*e5436536SAndroid Build Coastguard Worker   int timeStepShift = 0;
658*e5436536SAndroid Build Coastguard Worker   int i, cond;
659*e5436536SAndroid Build Coastguard Worker 
660*e5436536SAndroid Build Coastguard Worker   /* Where to start looking for transients in the transient candidate buffer */
661*e5436536SAndroid Build Coastguard Worker   qmfStartSample = timeStep * frameMiddleBorder;
662*e5436536SAndroid Build Coastguard Worker   /* We need to look one value backwards in the transients, so we might need one
663*e5436536SAndroid Build Coastguard Worker    * more previous value. */
664*e5436536SAndroid Build Coastguard Worker   addPrevSamples = (qmfStartSample > 0) ? 0 : 1;
665*e5436536SAndroid Build Coastguard Worker 
666*e5436536SAndroid Build Coastguard Worker   switch (timeStep) {
667*e5436536SAndroid Build Coastguard Worker     case 1:
668*e5436536SAndroid Build Coastguard Worker       timeStepShift = 0;
669*e5436536SAndroid Build Coastguard Worker       break;
670*e5436536SAndroid Build Coastguard Worker     case 2:
671*e5436536SAndroid Build Coastguard Worker       timeStepShift = 1;
672*e5436536SAndroid Build Coastguard Worker       break;
673*e5436536SAndroid Build Coastguard Worker     case 4:
674*e5436536SAndroid Build Coastguard Worker       timeStepShift = 2;
675*e5436536SAndroid Build Coastguard Worker       break;
676*e5436536SAndroid Build Coastguard Worker   }
677*e5436536SAndroid Build Coastguard Worker 
678*e5436536SAndroid Build Coastguard Worker   calculateThresholds(Energies, scaleEnergies, h_sbrTran->thresholds,
679*e5436536SAndroid Build Coastguard Worker                       YBufferWriteOffset, YBufferSzShift, h_sbrTran->no_cols,
680*e5436536SAndroid Build Coastguard Worker                       h_sbrTran->no_rows, h_sbrTran->tran_off);
681*e5436536SAndroid Build Coastguard Worker 
682*e5436536SAndroid Build Coastguard Worker   extractTransientCandidates(
683*e5436536SAndroid Build Coastguard Worker       Energies, scaleEnergies, h_sbrTran->thresholds, h_sbrTran->transients,
684*e5436536SAndroid Build Coastguard Worker       YBufferWriteOffset, YBufferSzShift, h_sbrTran->no_cols, 0,
685*e5436536SAndroid Build Coastguard Worker       h_sbrTran->no_rows, h_sbrTran->tran_off, addPrevSamples);
686*e5436536SAndroid Build Coastguard Worker 
687*e5436536SAndroid Build Coastguard Worker   transient_info[0] = 0;
688*e5436536SAndroid Build Coastguard Worker   transient_info[1] = 0;
689*e5436536SAndroid Build Coastguard Worker   transient_info[2] = 0;
690*e5436536SAndroid Build Coastguard Worker 
691*e5436536SAndroid Build Coastguard Worker   /* Offset by the amount of additional previous transient candidates being
692*e5436536SAndroid Build Coastguard Worker    * kept. */
693*e5436536SAndroid Build Coastguard Worker   qmfStartSample += addPrevSamples;
694*e5436536SAndroid Build Coastguard Worker 
695*e5436536SAndroid Build Coastguard Worker   /* Check for transients in second granule (pick the last value of subsequent
696*e5436536SAndroid Build Coastguard Worker    * values)  */
697*e5436536SAndroid Build Coastguard Worker   for (i = qmfStartSample; i < qmfStartSample + no_cols; i++) {
698*e5436536SAndroid Build Coastguard Worker     cond = (h_sbrTran->transients[i] <
699*e5436536SAndroid Build Coastguard Worker             fMult(FL2FXCONST_DBL(0.9f), h_sbrTran->transients[i - 1])) &&
700*e5436536SAndroid Build Coastguard Worker            (h_sbrTran->transients[i - 1] > h_sbrTran->tran_thr);
701*e5436536SAndroid Build Coastguard Worker 
702*e5436536SAndroid Build Coastguard Worker     if (cond) {
703*e5436536SAndroid Build Coastguard Worker       transient_info[0] = (i - qmfStartSample) >> timeStepShift;
704*e5436536SAndroid Build Coastguard Worker       transient_info[1] = 1;
705*e5436536SAndroid Build Coastguard Worker       break;
706*e5436536SAndroid Build Coastguard Worker     }
707*e5436536SAndroid Build Coastguard Worker   }
708*e5436536SAndroid Build Coastguard Worker 
709*e5436536SAndroid Build Coastguard Worker   if (h_sbrTran->frameShift != 0) {
710*e5436536SAndroid Build Coastguard Worker     /* transient prediction for LDSBR */
711*e5436536SAndroid Build Coastguard Worker     /* Check for transients in first <frameShift> qmf-slots of second frame */
712*e5436536SAndroid Build Coastguard Worker     for (i = qmfStartSample + no_cols;
713*e5436536SAndroid Build Coastguard Worker          i < qmfStartSample + no_cols + h_sbrTran->frameShift; i++) {
714*e5436536SAndroid Build Coastguard Worker       cond = (h_sbrTran->transients[i] <
715*e5436536SAndroid Build Coastguard Worker               fMult(FL2FXCONST_DBL(0.9f), h_sbrTran->transients[i - 1])) &&
716*e5436536SAndroid Build Coastguard Worker              (h_sbrTran->transients[i - 1] > h_sbrTran->tran_thr);
717*e5436536SAndroid Build Coastguard Worker 
718*e5436536SAndroid Build Coastguard Worker       if (cond) {
719*e5436536SAndroid Build Coastguard Worker         int pos = (int)((i - qmfStartSample - no_cols) >> timeStepShift);
720*e5436536SAndroid Build Coastguard Worker         if ((pos < 3) && (transient_info[1] == 0)) {
721*e5436536SAndroid Build Coastguard Worker           transient_info[2] = 1;
722*e5436536SAndroid Build Coastguard Worker         }
723*e5436536SAndroid Build Coastguard Worker         break;
724*e5436536SAndroid Build Coastguard Worker       }
725*e5436536SAndroid Build Coastguard Worker     }
726*e5436536SAndroid Build Coastguard Worker   }
727*e5436536SAndroid Build Coastguard Worker }
728*e5436536SAndroid Build Coastguard Worker 
FDKsbrEnc_InitSbrTransientDetector(HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTransientDetector,UINT sbrSyntaxFlags,INT frameSize,INT sampleFreq,sbrConfigurationPtr params,int tran_fc,int no_cols,int no_rows,int YBufferWriteOffset,int YBufferSzShift,int frameShift,int tran_off)729*e5436536SAndroid Build Coastguard Worker int FDKsbrEnc_InitSbrTransientDetector(
730*e5436536SAndroid Build Coastguard Worker     HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTransientDetector,
731*e5436536SAndroid Build Coastguard Worker     UINT sbrSyntaxFlags, /* SBR syntax flags derived from AOT. */
732*e5436536SAndroid Build Coastguard Worker     INT frameSize, INT sampleFreq, sbrConfigurationPtr params, int tran_fc,
733*e5436536SAndroid Build Coastguard Worker     int no_cols, int no_rows, int YBufferWriteOffset, int YBufferSzShift,
734*e5436536SAndroid Build Coastguard Worker     int frameShift, int tran_off) {
735*e5436536SAndroid Build Coastguard Worker   INT totalBitrate =
736*e5436536SAndroid Build Coastguard Worker       params->codecSettings.standardBitrate * params->codecSettings.nChannels;
737*e5436536SAndroid Build Coastguard Worker   INT codecBitrate = params->codecSettings.bitRate;
738*e5436536SAndroid Build Coastguard Worker   FIXP_DBL bitrateFactor_m, framedur_fix;
739*e5436536SAndroid Build Coastguard Worker   INT bitrateFactor_e, tmp_e;
740*e5436536SAndroid Build Coastguard Worker 
741*e5436536SAndroid Build Coastguard Worker   FDKmemclear(h_sbrTransientDetector, sizeof(SBR_TRANSIENT_DETECTOR));
742*e5436536SAndroid Build Coastguard Worker 
743*e5436536SAndroid Build Coastguard Worker   h_sbrTransientDetector->frameShift = frameShift;
744*e5436536SAndroid Build Coastguard Worker   h_sbrTransientDetector->tran_off = tran_off;
745*e5436536SAndroid Build Coastguard Worker 
746*e5436536SAndroid Build Coastguard Worker   if (codecBitrate) {
747*e5436536SAndroid Build Coastguard Worker     bitrateFactor_m = fDivNorm((FIXP_DBL)totalBitrate,
748*e5436536SAndroid Build Coastguard Worker                                (FIXP_DBL)(codecBitrate << 2), &bitrateFactor_e);
749*e5436536SAndroid Build Coastguard Worker     bitrateFactor_e += 2;
750*e5436536SAndroid Build Coastguard Worker   } else {
751*e5436536SAndroid Build Coastguard Worker     bitrateFactor_m = FL2FXCONST_DBL(1.0 / 4.0);
752*e5436536SAndroid Build Coastguard Worker     bitrateFactor_e = 2;
753*e5436536SAndroid Build Coastguard Worker   }
754*e5436536SAndroid Build Coastguard Worker 
755*e5436536SAndroid Build Coastguard Worker   framedur_fix = fDivNorm(frameSize, sampleFreq);
756*e5436536SAndroid Build Coastguard Worker 
757*e5436536SAndroid Build Coastguard Worker   /* The longer the frames, the more often should the FIXFIX-
758*e5436536SAndroid Build Coastguard Worker   case transmit 2 envelopes instead of 1.
759*e5436536SAndroid Build Coastguard Worker   Frame durations below 10 ms produce the highest threshold
760*e5436536SAndroid Build Coastguard Worker   so that practically always only 1 env is transmitted. */
761*e5436536SAndroid Build Coastguard Worker   FIXP_DBL tmp = framedur_fix - FL2FXCONST_DBL(0.010);
762*e5436536SAndroid Build Coastguard Worker 
763*e5436536SAndroid Build Coastguard Worker   tmp = fixMax(tmp, FL2FXCONST_DBL(0.0001));
764*e5436536SAndroid Build Coastguard Worker   tmp = fDivNorm(FL2FXCONST_DBL(0.000075), fPow2(tmp), &tmp_e);
765*e5436536SAndroid Build Coastguard Worker 
766*e5436536SAndroid Build Coastguard Worker   bitrateFactor_e = (tmp_e + bitrateFactor_e);
767*e5436536SAndroid Build Coastguard Worker 
768*e5436536SAndroid Build Coastguard Worker   if (sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) {
769*e5436536SAndroid Build Coastguard Worker     bitrateFactor_e--; /* divide by 2 */
770*e5436536SAndroid Build Coastguard Worker   }
771*e5436536SAndroid Build Coastguard Worker 
772*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(no_cols <= 32);
773*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(no_rows <= 64);
774*e5436536SAndroid Build Coastguard Worker 
775*e5436536SAndroid Build Coastguard Worker   h_sbrTransientDetector->no_cols = no_cols;
776*e5436536SAndroid Build Coastguard Worker   h_sbrTransientDetector->tran_thr =
777*e5436536SAndroid Build Coastguard Worker       (FIXP_DBL)((params->tran_thr << (32 - 24 - 1)) / no_rows);
778*e5436536SAndroid Build Coastguard Worker   h_sbrTransientDetector->tran_fc = tran_fc;
779*e5436536SAndroid Build Coastguard Worker   h_sbrTransientDetector->split_thr_m = fMult(tmp, bitrateFactor_m);
780*e5436536SAndroid Build Coastguard Worker   h_sbrTransientDetector->split_thr_e = bitrateFactor_e;
781*e5436536SAndroid Build Coastguard Worker   h_sbrTransientDetector->no_rows = no_rows;
782*e5436536SAndroid Build Coastguard Worker   h_sbrTransientDetector->mode = params->tran_det_mode;
783*e5436536SAndroid Build Coastguard Worker   h_sbrTransientDetector->prevLowBandEnergy = FL2FXCONST_DBL(0.0f);
784*e5436536SAndroid Build Coastguard Worker 
785*e5436536SAndroid Build Coastguard Worker   return (0);
786*e5436536SAndroid Build Coastguard Worker }
787*e5436536SAndroid Build Coastguard Worker 
788*e5436536SAndroid Build Coastguard Worker #define ENERGY_SCALING_SIZE 32
789*e5436536SAndroid Build Coastguard Worker 
FDKsbrEnc_InitSbrFastTransientDetector(HANDLE_FAST_TRAN_DET h_sbrFastTransientDetector,const INT time_slots_per_frame,const INT bandwidth_qmf_slot,const INT no_qmf_channels,const INT sbr_qmf_1st_band)790*e5436536SAndroid Build Coastguard Worker INT FDKsbrEnc_InitSbrFastTransientDetector(
791*e5436536SAndroid Build Coastguard Worker     HANDLE_FAST_TRAN_DET h_sbrFastTransientDetector,
792*e5436536SAndroid Build Coastguard Worker     const INT time_slots_per_frame, const INT bandwidth_qmf_slot,
793*e5436536SAndroid Build Coastguard Worker     const INT no_qmf_channels, const INT sbr_qmf_1st_band) {
794*e5436536SAndroid Build Coastguard Worker   int i;
795*e5436536SAndroid Build Coastguard Worker   int buff_size;
796*e5436536SAndroid Build Coastguard Worker   FIXP_DBL myExp;
797*e5436536SAndroid Build Coastguard Worker   FIXP_DBL myExpSlot;
798*e5436536SAndroid Build Coastguard Worker 
799*e5436536SAndroid Build Coastguard Worker   h_sbrFastTransientDetector->lookahead = TRAN_DET_LOOKAHEAD;
800*e5436536SAndroid Build Coastguard Worker   h_sbrFastTransientDetector->nTimeSlots = time_slots_per_frame;
801*e5436536SAndroid Build Coastguard Worker 
802*e5436536SAndroid Build Coastguard Worker   buff_size = h_sbrFastTransientDetector->nTimeSlots +
803*e5436536SAndroid Build Coastguard Worker               h_sbrFastTransientDetector->lookahead;
804*e5436536SAndroid Build Coastguard Worker 
805*e5436536SAndroid Build Coastguard Worker   for (i = 0; i < buff_size; i++) {
806*e5436536SAndroid Build Coastguard Worker     h_sbrFastTransientDetector->delta_energy[i] = FL2FXCONST_DBL(0.0f);
807*e5436536SAndroid Build Coastguard Worker     h_sbrFastTransientDetector->energy_timeSlots[i] = FL2FXCONST_DBL(0.0f);
808*e5436536SAndroid Build Coastguard Worker     h_sbrFastTransientDetector->lowpass_energy[i] = FL2FXCONST_DBL(0.0f);
809*e5436536SAndroid Build Coastguard Worker     h_sbrFastTransientDetector->transientCandidates[i] = 0;
810*e5436536SAndroid Build Coastguard Worker   }
811*e5436536SAndroid Build Coastguard Worker 
812*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(bandwidth_qmf_slot > 0.f);
813*e5436536SAndroid Build Coastguard Worker   h_sbrFastTransientDetector->stopBand =
814*e5436536SAndroid Build Coastguard Worker       fMin(TRAN_DET_STOP_FREQ / bandwidth_qmf_slot, no_qmf_channels);
815*e5436536SAndroid Build Coastguard Worker   h_sbrFastTransientDetector->startBand =
816*e5436536SAndroid Build Coastguard Worker       fMin(sbr_qmf_1st_band,
817*e5436536SAndroid Build Coastguard Worker            h_sbrFastTransientDetector->stopBand - TRAN_DET_MIN_QMFBANDS);
818*e5436536SAndroid Build Coastguard Worker 
819*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(h_sbrFastTransientDetector->startBand < no_qmf_channels);
820*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(h_sbrFastTransientDetector->startBand <
821*e5436536SAndroid Build Coastguard Worker              h_sbrFastTransientDetector->stopBand);
822*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(h_sbrFastTransientDetector->startBand > 1);
823*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(h_sbrFastTransientDetector->stopBand > 1);
824*e5436536SAndroid Build Coastguard Worker 
825*e5436536SAndroid Build Coastguard Worker   /* the energy weighting and adding up has a headroom of 6 Bits,
826*e5436536SAndroid Build Coastguard Worker      so up to 64 bands can be added without potential overflow. */
827*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(h_sbrFastTransientDetector->stopBand -
828*e5436536SAndroid Build Coastguard Worker                  h_sbrFastTransientDetector->startBand <=
829*e5436536SAndroid Build Coastguard Worker              64);
830*e5436536SAndroid Build Coastguard Worker 
831*e5436536SAndroid Build Coastguard Worker /* QMF_HP_dB_SLOPE_FIX says that we want a 20 dB per 16 kHz HP filter.
832*e5436536SAndroid Build Coastguard Worker    The following lines map this to the QMF bandwidth. */
833*e5436536SAndroid Build Coastguard Worker #define EXP_E 7 /* 64 (=64) multiplications max, max. allowed sum is 0.5 */
834*e5436536SAndroid Build Coastguard Worker   myExp = fMultNorm(QMF_HP_dBd_SLOPE_FIX, 0, (FIXP_DBL)bandwidth_qmf_slot,
835*e5436536SAndroid Build Coastguard Worker                     DFRACT_BITS - 1, EXP_E);
836*e5436536SAndroid Build Coastguard Worker   myExpSlot = myExp;
837*e5436536SAndroid Build Coastguard Worker 
838*e5436536SAndroid Build Coastguard Worker   for (i = 0; i < 64; i++) {
839*e5436536SAndroid Build Coastguard Worker     /* Calculate dBf over all qmf bands:
840*e5436536SAndroid Build Coastguard Worker        dBf = (10^(0.002266f/10*bw(slot)))^(band) =
841*e5436536SAndroid Build Coastguard Worker            = 2^(log2(10)*0.002266f/10*bw(slot)*band) =
842*e5436536SAndroid Build Coastguard Worker            = 2^(0.00075275f*bw(slot)*band)                                   */
843*e5436536SAndroid Build Coastguard Worker 
844*e5436536SAndroid Build Coastguard Worker     FIXP_DBL dBf_m; /* dBf mantissa        */
845*e5436536SAndroid Build Coastguard Worker     INT dBf_e;      /* dBf exponent        */
846*e5436536SAndroid Build Coastguard Worker     INT tmp;
847*e5436536SAndroid Build Coastguard Worker 
848*e5436536SAndroid Build Coastguard Worker     INT dBf_int;        /* dBf integer part    */
849*e5436536SAndroid Build Coastguard Worker     FIXP_DBL dBf_fract; /* dBf fractional part */
850*e5436536SAndroid Build Coastguard Worker 
851*e5436536SAndroid Build Coastguard Worker     /* myExp*(i+1) = myExp_int - myExp_fract
852*e5436536SAndroid Build Coastguard Worker        myExp*(i+1) is split up here for better accuracy of CalcInvLdData(),
853*e5436536SAndroid Build Coastguard Worker        for its result can be split up into an integer and a fractional part */
854*e5436536SAndroid Build Coastguard Worker 
855*e5436536SAndroid Build Coastguard Worker     /* Round up to next integer */
856*e5436536SAndroid Build Coastguard Worker     FIXP_DBL myExp_int =
857*e5436536SAndroid Build Coastguard Worker         (myExpSlot & (FIXP_DBL)0xfe000000) + (FIXP_DBL)0x02000000;
858*e5436536SAndroid Build Coastguard Worker 
859*e5436536SAndroid Build Coastguard Worker     /* This is the fractional part that needs to be substracted */
860*e5436536SAndroid Build Coastguard Worker     FIXP_DBL myExp_fract = myExp_int - myExpSlot;
861*e5436536SAndroid Build Coastguard Worker 
862*e5436536SAndroid Build Coastguard Worker     /* Calc integer part */
863*e5436536SAndroid Build Coastguard Worker     dBf_int = CalcInvLdData(myExp_int);
864*e5436536SAndroid Build Coastguard Worker     /* The result needs to be re-scaled. The ld(myExp_int) had been scaled by
865*e5436536SAndroid Build Coastguard Worker        EXP_E, the CalcInvLdData expects the operand to be scaled by
866*e5436536SAndroid Build Coastguard Worker        LD_DATA_SHIFT. Therefore, the correctly scaled result is
867*e5436536SAndroid Build Coastguard Worker        dBf_int^(2^(EXP_E-LD_DATA_SHIFT)), which is dBf_int^2 */
868*e5436536SAndroid Build Coastguard Worker 
869*e5436536SAndroid Build Coastguard Worker     if (dBf_int <=
870*e5436536SAndroid Build Coastguard Worker         46340) { /* compare with maximum allowed value for signed integer
871*e5436536SAndroid Build Coastguard Worker                     multiplication, 46340 =
872*e5436536SAndroid Build Coastguard Worker                     (INT)floor(sqrt((double)(((UINT)1<<(DFRACT_BITS-1))-1))) */
873*e5436536SAndroid Build Coastguard Worker       dBf_int *= dBf_int;
874*e5436536SAndroid Build Coastguard Worker 
875*e5436536SAndroid Build Coastguard Worker       /* Calc fractional part */
876*e5436536SAndroid Build Coastguard Worker       dBf_fract = CalcInvLdData(-myExp_fract);
877*e5436536SAndroid Build Coastguard Worker       /* The result needs to be re-scaled. The ld(myExp_fract) had been scaled
878*e5436536SAndroid Build Coastguard Worker          by EXP_E, the CalcInvLdData expects the operand to be scaled by
879*e5436536SAndroid Build Coastguard Worker          LD_DATA_SHIFT. Therefore, the correctly scaled result is
880*e5436536SAndroid Build Coastguard Worker          dBf_fract^(2^(EXP_E-LD_DATA_SHIFT)), which is dBf_fract^2 */
881*e5436536SAndroid Build Coastguard Worker       dBf_fract = fMultNorm(dBf_fract, dBf_fract, &tmp);
882*e5436536SAndroid Build Coastguard Worker 
883*e5436536SAndroid Build Coastguard Worker       /* Get worst case scaling of multiplication result */
884*e5436536SAndroid Build Coastguard Worker       dBf_e = (DFRACT_BITS - 1 - tmp) - CountLeadingBits(dBf_int);
885*e5436536SAndroid Build Coastguard Worker 
886*e5436536SAndroid Build Coastguard Worker       /* Now multiply integer with fractional part of the result, thus resulting
887*e5436536SAndroid Build Coastguard Worker          in the overall accurate fractional result */
888*e5436536SAndroid Build Coastguard Worker       dBf_m = fMultNorm(dBf_int, DFRACT_BITS - 1, dBf_fract, tmp, dBf_e);
889*e5436536SAndroid Build Coastguard Worker 
890*e5436536SAndroid Build Coastguard Worker       myExpSlot += myExp;
891*e5436536SAndroid Build Coastguard Worker     } else {
892*e5436536SAndroid Build Coastguard Worker       dBf_m = (FIXP_DBL)0;
893*e5436536SAndroid Build Coastguard Worker       dBf_e = 0;
894*e5436536SAndroid Build Coastguard Worker     }
895*e5436536SAndroid Build Coastguard Worker 
896*e5436536SAndroid Build Coastguard Worker     /* Keep the results */
897*e5436536SAndroid Build Coastguard Worker     h_sbrFastTransientDetector->dBf_m[i] = dBf_m;
898*e5436536SAndroid Build Coastguard Worker     h_sbrFastTransientDetector->dBf_e[i] = dBf_e;
899*e5436536SAndroid Build Coastguard Worker   }
900*e5436536SAndroid Build Coastguard Worker 
901*e5436536SAndroid Build Coastguard Worker   /* Make sure that dBf is greater than 1.0 (because it should be a highpass) */
902*e5436536SAndroid Build Coastguard Worker   /* ... */
903*e5436536SAndroid Build Coastguard Worker 
904*e5436536SAndroid Build Coastguard Worker   return 0;
905*e5436536SAndroid Build Coastguard Worker }
906*e5436536SAndroid Build Coastguard Worker 
FDKsbrEnc_fastTransientDetect(const HANDLE_FAST_TRAN_DET h_sbrFastTransientDetector,const FIXP_DBL * const * Energies,const int * const scaleEnergies,const INT YBufferWriteOffset,UCHAR * const tran_vector)907*e5436536SAndroid Build Coastguard Worker void FDKsbrEnc_fastTransientDetect(
908*e5436536SAndroid Build Coastguard Worker     const HANDLE_FAST_TRAN_DET h_sbrFastTransientDetector,
909*e5436536SAndroid Build Coastguard Worker     const FIXP_DBL *const *Energies, const int *const scaleEnergies,
910*e5436536SAndroid Build Coastguard Worker     const INT YBufferWriteOffset, UCHAR *const tran_vector) {
911*e5436536SAndroid Build Coastguard Worker   int timeSlot, band;
912*e5436536SAndroid Build Coastguard Worker 
913*e5436536SAndroid Build Coastguard Worker   FIXP_DBL max_delta_energy; /* helper to store maximum energy ratio          */
914*e5436536SAndroid Build Coastguard Worker   int max_delta_energy_scale; /* helper to store scale of maximum energy ratio
915*e5436536SAndroid Build Coastguard Worker                                */
916*e5436536SAndroid Build Coastguard Worker   int ind_max = 0; /* helper to store index of maximum energy ratio */
917*e5436536SAndroid Build Coastguard Worker   int isTransientInFrame = 0;
918*e5436536SAndroid Build Coastguard Worker 
919*e5436536SAndroid Build Coastguard Worker   const int nTimeSlots = h_sbrFastTransientDetector->nTimeSlots;
920*e5436536SAndroid Build Coastguard Worker   const int lookahead = h_sbrFastTransientDetector->lookahead;
921*e5436536SAndroid Build Coastguard Worker   const int startBand = h_sbrFastTransientDetector->startBand;
922*e5436536SAndroid Build Coastguard Worker   const int stopBand = h_sbrFastTransientDetector->stopBand;
923*e5436536SAndroid Build Coastguard Worker 
924*e5436536SAndroid Build Coastguard Worker   int *transientCandidates = h_sbrFastTransientDetector->transientCandidates;
925*e5436536SAndroid Build Coastguard Worker 
926*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *energy_timeSlots = h_sbrFastTransientDetector->energy_timeSlots;
927*e5436536SAndroid Build Coastguard Worker   int *energy_timeSlots_scale =
928*e5436536SAndroid Build Coastguard Worker       h_sbrFastTransientDetector->energy_timeSlots_scale;
929*e5436536SAndroid Build Coastguard Worker 
930*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *delta_energy = h_sbrFastTransientDetector->delta_energy;
931*e5436536SAndroid Build Coastguard Worker   int *delta_energy_scale = h_sbrFastTransientDetector->delta_energy_scale;
932*e5436536SAndroid Build Coastguard Worker 
933*e5436536SAndroid Build Coastguard Worker   const FIXP_DBL thr = TRAN_DET_THRSHLD;
934*e5436536SAndroid Build Coastguard Worker   const INT thr_scale = TRAN_DET_THRSHLD_SCALE;
935*e5436536SAndroid Build Coastguard Worker 
936*e5436536SAndroid Build Coastguard Worker   /*reset transient info*/
937*e5436536SAndroid Build Coastguard Worker   tran_vector[2] = 0;
938*e5436536SAndroid Build Coastguard Worker 
939*e5436536SAndroid Build Coastguard Worker   /* reset transient candidates */
940*e5436536SAndroid Build Coastguard Worker   FDKmemclear(transientCandidates + lookahead, nTimeSlots * sizeof(int));
941*e5436536SAndroid Build Coastguard Worker 
942*e5436536SAndroid Build Coastguard Worker   for (timeSlot = lookahead; timeSlot < nTimeSlots + lookahead; timeSlot++) {
943*e5436536SAndroid Build Coastguard Worker     int i, norm;
944*e5436536SAndroid Build Coastguard Worker     FIXP_DBL tmpE = FL2FXCONST_DBL(0.0f);
945*e5436536SAndroid Build Coastguard Worker     int headroomEnSlot = DFRACT_BITS - 1;
946*e5436536SAndroid Build Coastguard Worker 
947*e5436536SAndroid Build Coastguard Worker     FIXP_DBL smallNRG = FL2FXCONST_DBL(1e-2f);
948*e5436536SAndroid Build Coastguard Worker     FIXP_DBL denominator;
949*e5436536SAndroid Build Coastguard Worker     INT denominator_scale;
950*e5436536SAndroid Build Coastguard Worker 
951*e5436536SAndroid Build Coastguard Worker     /* determine minimum headroom of energy values for this timeslot */
952*e5436536SAndroid Build Coastguard Worker     for (band = startBand; band < stopBand; band++) {
953*e5436536SAndroid Build Coastguard Worker       int tmp_headroom = fNormz(Energies[timeSlot][band]) - 1;
954*e5436536SAndroid Build Coastguard Worker       if (tmp_headroom < headroomEnSlot) {
955*e5436536SAndroid Build Coastguard Worker         headroomEnSlot = tmp_headroom;
956*e5436536SAndroid Build Coastguard Worker       }
957*e5436536SAndroid Build Coastguard Worker     }
958*e5436536SAndroid Build Coastguard Worker 
959*e5436536SAndroid Build Coastguard Worker     for (i = 0, band = startBand; band < stopBand; band++, i++) {
960*e5436536SAndroid Build Coastguard Worker       /* energy is weighted by weightingfactor stored in dBf_m array */
961*e5436536SAndroid Build Coastguard Worker       /* dBf_m index runs from 0 to stopBand-startband               */
962*e5436536SAndroid Build Coastguard Worker       /* energy shifted by calculated headroom for maximum precision */
963*e5436536SAndroid Build Coastguard Worker       FIXP_DBL weightedEnergy =
964*e5436536SAndroid Build Coastguard Worker           fMult(Energies[timeSlot][band] << headroomEnSlot,
965*e5436536SAndroid Build Coastguard Worker                 h_sbrFastTransientDetector->dBf_m[i]);
966*e5436536SAndroid Build Coastguard Worker 
967*e5436536SAndroid Build Coastguard Worker       /* energy is added up                                                */
968*e5436536SAndroid Build Coastguard Worker       /* shift by 6 to have a headroom for maximum 64 additions            */
969*e5436536SAndroid Build Coastguard Worker       /* shift by dBf_e to handle weighting factor dependent scale factors */
970*e5436536SAndroid Build Coastguard Worker       tmpE +=
971*e5436536SAndroid Build Coastguard Worker           weightedEnergy >> (6 + (10 - h_sbrFastTransientDetector->dBf_e[i]));
972*e5436536SAndroid Build Coastguard Worker     }
973*e5436536SAndroid Build Coastguard Worker 
974*e5436536SAndroid Build Coastguard Worker     /* store calculated energy for timeslot */
975*e5436536SAndroid Build Coastguard Worker     energy_timeSlots[timeSlot] = tmpE;
976*e5436536SAndroid Build Coastguard Worker 
977*e5436536SAndroid Build Coastguard Worker     /* calculate overall scale factor for energy of this timeslot */
978*e5436536SAndroid Build Coastguard Worker     /* =   original scale factor of energies
979*e5436536SAndroid Build Coastguard Worker      * (-scaleEnergies[0]+2*QMF_SCALE_OFFSET or
980*e5436536SAndroid Build Coastguard Worker      * -scaleEnergies[1]+2*QMF_SCALE_OFFSET    */
981*e5436536SAndroid Build Coastguard Worker     /*     depending on YBufferWriteOffset) */
982*e5436536SAndroid Build Coastguard Worker     /*   + weighting factor scale            (10) */
983*e5436536SAndroid Build Coastguard Worker     /*   + adding up scale factor            ( 6) */
984*e5436536SAndroid Build Coastguard Worker     /*   - headroom of energy value          (headroomEnSlot) */
985*e5436536SAndroid Build Coastguard Worker     if (timeSlot < YBufferWriteOffset) {
986*e5436536SAndroid Build Coastguard Worker       energy_timeSlots_scale[timeSlot] =
987*e5436536SAndroid Build Coastguard Worker           (-scaleEnergies[0] + 2 * QMF_SCALE_OFFSET) + (10 + 6) -
988*e5436536SAndroid Build Coastguard Worker           headroomEnSlot;
989*e5436536SAndroid Build Coastguard Worker     } else {
990*e5436536SAndroid Build Coastguard Worker       energy_timeSlots_scale[timeSlot] =
991*e5436536SAndroid Build Coastguard Worker           (-scaleEnergies[1] + 2 * QMF_SCALE_OFFSET) + (10 + 6) -
992*e5436536SAndroid Build Coastguard Worker           headroomEnSlot;
993*e5436536SAndroid Build Coastguard Worker     }
994*e5436536SAndroid Build Coastguard Worker 
995*e5436536SAndroid Build Coastguard Worker     /* Add a small energy to the denominator, thus making the transient
996*e5436536SAndroid Build Coastguard Worker        detection energy-dependent. Loud transients are being detected,
997*e5436536SAndroid Build Coastguard Worker        silent ones not. */
998*e5436536SAndroid Build Coastguard Worker 
999*e5436536SAndroid Build Coastguard Worker     /* make sure that smallNRG does not overflow */
1000*e5436536SAndroid Build Coastguard Worker     if (-energy_timeSlots_scale[timeSlot - 1] + 1 > 5) {
1001*e5436536SAndroid Build Coastguard Worker       denominator = smallNRG;
1002*e5436536SAndroid Build Coastguard Worker       denominator_scale = 0;
1003*e5436536SAndroid Build Coastguard Worker     } else {
1004*e5436536SAndroid Build Coastguard Worker       /* Leave an additional headroom of 1 bit for this addition. */
1005*e5436536SAndroid Build Coastguard Worker       smallNRG =
1006*e5436536SAndroid Build Coastguard Worker           scaleValue(smallNRG, -(energy_timeSlots_scale[timeSlot - 1] + 1));
1007*e5436536SAndroid Build Coastguard Worker       denominator = (energy_timeSlots[timeSlot - 1] >> 1) + smallNRG;
1008*e5436536SAndroid Build Coastguard Worker       denominator_scale = energy_timeSlots_scale[timeSlot - 1] + 1;
1009*e5436536SAndroid Build Coastguard Worker     }
1010*e5436536SAndroid Build Coastguard Worker 
1011*e5436536SAndroid Build Coastguard Worker     delta_energy[timeSlot] =
1012*e5436536SAndroid Build Coastguard Worker         fDivNorm(energy_timeSlots[timeSlot], denominator, &norm);
1013*e5436536SAndroid Build Coastguard Worker     delta_energy_scale[timeSlot] =
1014*e5436536SAndroid Build Coastguard Worker         energy_timeSlots_scale[timeSlot] - denominator_scale + norm;
1015*e5436536SAndroid Build Coastguard Worker   }
1016*e5436536SAndroid Build Coastguard Worker 
1017*e5436536SAndroid Build Coastguard Worker   /*get transient candidates*/
1018*e5436536SAndroid Build Coastguard Worker   /* For every timeslot, check if delta(E) exceeds the threshold. If it did,
1019*e5436536SAndroid Build Coastguard Worker      it could potentially be marked as a transient candidate. However, the 2
1020*e5436536SAndroid Build Coastguard Worker      slots before the current one must not be transients with an energy higher
1021*e5436536SAndroid Build Coastguard Worker      than 1.4*E(current). If both aren't transients or if the energy of the
1022*e5436536SAndroid Build Coastguard Worker      current timesolot is more than 1.4 times higher than the energy in the
1023*e5436536SAndroid Build Coastguard Worker      last or the one before the last slot, it is marked as a transient.*/
1024*e5436536SAndroid Build Coastguard Worker 
1025*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(lookahead >= 2);
1026*e5436536SAndroid Build Coastguard Worker   for (timeSlot = lookahead; timeSlot < nTimeSlots + lookahead; timeSlot++) {
1027*e5436536SAndroid Build Coastguard Worker     FIXP_DBL energy_cur_slot_weighted =
1028*e5436536SAndroid Build Coastguard Worker         fMult(energy_timeSlots[timeSlot], FL2FXCONST_DBL(1.0f / 1.4f));
1029*e5436536SAndroid Build Coastguard Worker     if (!fIsLessThan(delta_energy[timeSlot], delta_energy_scale[timeSlot], thr,
1030*e5436536SAndroid Build Coastguard Worker                      thr_scale) &&
1031*e5436536SAndroid Build Coastguard Worker         (((transientCandidates[timeSlot - 2] == 0) &&
1032*e5436536SAndroid Build Coastguard Worker           (transientCandidates[timeSlot - 1] == 0)) ||
1033*e5436536SAndroid Build Coastguard Worker          !fIsLessThan(energy_cur_slot_weighted,
1034*e5436536SAndroid Build Coastguard Worker                       energy_timeSlots_scale[timeSlot],
1035*e5436536SAndroid Build Coastguard Worker                       energy_timeSlots[timeSlot - 1],
1036*e5436536SAndroid Build Coastguard Worker                       energy_timeSlots_scale[timeSlot - 1]) ||
1037*e5436536SAndroid Build Coastguard Worker          !fIsLessThan(energy_cur_slot_weighted,
1038*e5436536SAndroid Build Coastguard Worker                       energy_timeSlots_scale[timeSlot],
1039*e5436536SAndroid Build Coastguard Worker                       energy_timeSlots[timeSlot - 2],
1040*e5436536SAndroid Build Coastguard Worker                       energy_timeSlots_scale[timeSlot - 2]))) {
1041*e5436536SAndroid Build Coastguard Worker       /* in case of strong transients, subsequent
1042*e5436536SAndroid Build Coastguard Worker        * qmf slots might be recognized as transients. */
1043*e5436536SAndroid Build Coastguard Worker       transientCandidates[timeSlot] = 1;
1044*e5436536SAndroid Build Coastguard Worker     }
1045*e5436536SAndroid Build Coastguard Worker   }
1046*e5436536SAndroid Build Coastguard Worker 
1047*e5436536SAndroid Build Coastguard Worker   /*get transient with max energy*/
1048*e5436536SAndroid Build Coastguard Worker   max_delta_energy = FL2FXCONST_DBL(0.0f);
1049*e5436536SAndroid Build Coastguard Worker   max_delta_energy_scale = 0;
1050*e5436536SAndroid Build Coastguard Worker   ind_max = 0;
1051*e5436536SAndroid Build Coastguard Worker   isTransientInFrame = 0;
1052*e5436536SAndroid Build Coastguard Worker   for (timeSlot = 0; timeSlot < nTimeSlots; timeSlot++) {
1053*e5436536SAndroid Build Coastguard Worker     int scale = fMax(delta_energy_scale[timeSlot], max_delta_energy_scale);
1054*e5436536SAndroid Build Coastguard Worker     if (transientCandidates[timeSlot] &&
1055*e5436536SAndroid Build Coastguard Worker         ((delta_energy[timeSlot] >> (scale - delta_energy_scale[timeSlot])) >
1056*e5436536SAndroid Build Coastguard Worker          (max_delta_energy >> (scale - max_delta_energy_scale)))) {
1057*e5436536SAndroid Build Coastguard Worker       max_delta_energy = delta_energy[timeSlot];
1058*e5436536SAndroid Build Coastguard Worker       max_delta_energy_scale = scale;
1059*e5436536SAndroid Build Coastguard Worker       ind_max = timeSlot;
1060*e5436536SAndroid Build Coastguard Worker       isTransientInFrame = 1;
1061*e5436536SAndroid Build Coastguard Worker     }
1062*e5436536SAndroid Build Coastguard Worker   }
1063*e5436536SAndroid Build Coastguard Worker 
1064*e5436536SAndroid Build Coastguard Worker   /*from all transient candidates take the one with the biggest energy*/
1065*e5436536SAndroid Build Coastguard Worker   if (isTransientInFrame) {
1066*e5436536SAndroid Build Coastguard Worker     tran_vector[0] = ind_max;
1067*e5436536SAndroid Build Coastguard Worker     tran_vector[1] = 1;
1068*e5436536SAndroid Build Coastguard Worker   } else {
1069*e5436536SAndroid Build Coastguard Worker     /*reset transient info*/
1070*e5436536SAndroid Build Coastguard Worker     tran_vector[0] = tran_vector[1] = 0;
1071*e5436536SAndroid Build Coastguard Worker   }
1072*e5436536SAndroid Build Coastguard Worker 
1073*e5436536SAndroid Build Coastguard Worker   /*check for transients in lookahead*/
1074*e5436536SAndroid Build Coastguard Worker   for (timeSlot = nTimeSlots; timeSlot < nTimeSlots + lookahead; timeSlot++) {
1075*e5436536SAndroid Build Coastguard Worker     if (transientCandidates[timeSlot]) {
1076*e5436536SAndroid Build Coastguard Worker       tran_vector[2] = 1;
1077*e5436536SAndroid Build Coastguard Worker     }
1078*e5436536SAndroid Build Coastguard Worker   }
1079*e5436536SAndroid Build Coastguard Worker 
1080*e5436536SAndroid Build Coastguard Worker   /*update buffers*/
1081*e5436536SAndroid Build Coastguard Worker   for (timeSlot = 0; timeSlot < lookahead; timeSlot++) {
1082*e5436536SAndroid Build Coastguard Worker     transientCandidates[timeSlot] = transientCandidates[nTimeSlots + timeSlot];
1083*e5436536SAndroid Build Coastguard Worker 
1084*e5436536SAndroid Build Coastguard Worker     /* fixpoint stuff */
1085*e5436536SAndroid Build Coastguard Worker     energy_timeSlots[timeSlot] = energy_timeSlots[nTimeSlots + timeSlot];
1086*e5436536SAndroid Build Coastguard Worker     energy_timeSlots_scale[timeSlot] =
1087*e5436536SAndroid Build Coastguard Worker         energy_timeSlots_scale[nTimeSlots + timeSlot];
1088*e5436536SAndroid Build Coastguard Worker 
1089*e5436536SAndroid Build Coastguard Worker     delta_energy[timeSlot] = delta_energy[nTimeSlots + timeSlot];
1090*e5436536SAndroid Build Coastguard Worker     delta_energy_scale[timeSlot] = delta_energy_scale[nTimeSlots + timeSlot];
1091*e5436536SAndroid Build Coastguard Worker   }
1092*e5436536SAndroid Build Coastguard Worker }
1093