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