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