/src/aac/libAACenc/src/intensity.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 - 2019 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 | | /**************************** AAC encoder library ****************************** |
96 | | |
97 | | Author(s): A. Horndasch (code originally from lwr) / Josef Hoepfl (FDK) |
98 | | |
99 | | Description: intensity stereo processing |
100 | | |
101 | | *******************************************************************************/ |
102 | | |
103 | | #include "intensity.h" |
104 | | |
105 | | #include "interface.h" |
106 | | #include "psy_configuration.h" |
107 | | #include "psy_const.h" |
108 | | #include "qc_main.h" |
109 | | #include "bit_cnt.h" |
110 | | |
111 | | /* only set an IS seed it left/right channel correlation is above IS_CORR_THRESH |
112 | | */ |
113 | 0 | #define IS_CORR_THRESH FL2FXCONST_DBL(0.95f) |
114 | | |
115 | | /* when expanding the IS region to more SFBs only accept an error that is |
116 | | * not more than IS_TOTAL_ERROR_THRESH overall and |
117 | | * not more than IS_LOCAL_ERROR_THRESH for the current SFB */ |
118 | 0 | #define IS_TOTAL_ERROR_THRESH FL2FXCONST_DBL(0.04f) |
119 | 0 | #define IS_LOCAL_ERROR_THRESH FL2FXCONST_DBL(0.01f) |
120 | | |
121 | | /* the maximum allowed change of the intensity direction (unit: IS scale) - |
122 | | * scaled with factor 0.25 - */ |
123 | 0 | #define IS_DIRECTION_DEVIATION_THRESH_SF 2 |
124 | | #define IS_DIRECTION_DEVIATION_THRESH \ |
125 | 0 | FL2FXCONST_DBL(2.0f / (1 << IS_DIRECTION_DEVIATION_THRESH_SF)) |
126 | | |
127 | | /* IS regions need to have a minimal percentage of the overall loudness, e.g. |
128 | | * 0.06 == 6% */ |
129 | 0 | #define IS_REGION_MIN_LOUDNESS FL2FXCONST_DBL(0.1f) |
130 | | |
131 | | /* only perform IS if IS_MIN_SFBS neighboring SFBs can be processed */ |
132 | 0 | #define IS_MIN_SFBS 6 |
133 | | |
134 | | /* only do IS if |
135 | | * if IS_LEFT_RIGHT_RATIO_THRESH < sfbEnergyLeft[sfb]/sfbEnergyRight[sfb] < 1 / |
136 | | * IS_LEFT_RIGHT_RATIO_THRESH |
137 | | * -> no IS if the panning angle is not far from the middle, MS will do */ |
138 | | /* this is equivalent to a scale of +/-1.02914634566 */ |
139 | 0 | #define IS_LEFT_RIGHT_RATIO_THRESH FL2FXCONST_DBL(0.7f) |
140 | | |
141 | | /* scalefactor of realScale */ |
142 | 0 | #define REAL_SCALE_SF 1 |
143 | | |
144 | | /* scalefactor overallLoudness */ |
145 | 0 | #define OVERALL_LOUDNESS_SF 6 |
146 | | |
147 | | /* scalefactor for sum over max samples per goup */ |
148 | 0 | #define MAX_SFB_PER_GROUP_SF 6 |
149 | | |
150 | | /* scalefactor for sum of mdct spectrum */ |
151 | 0 | #define MDCT_SPEC_SF 6 |
152 | | |
153 | | typedef struct { |
154 | | FIXP_DBL corr_thresh; /*!< Only set an IS seed it left/right channel |
155 | | correlation is above corr_thresh */ |
156 | | |
157 | | FIXP_DBL total_error_thresh; /*!< When expanding the IS region to more SFBs |
158 | | only accept an error that is not more than |
159 | | 'total_error_thresh' overall. */ |
160 | | |
161 | | FIXP_DBL local_error_thresh; /*!< When expanding the IS region to more SFBs |
162 | | only accept an error that is not more than |
163 | | 'local_error_thresh' for the current SFB. */ |
164 | | |
165 | | FIXP_DBL direction_deviation_thresh; /*!< The maximum allowed change of the |
166 | | intensity direction (unit: IS scale) |
167 | | */ |
168 | | |
169 | | FIXP_DBL is_region_min_loudness; /*!< IS regions need to have a minimal |
170 | | percentage of the overall loudness, e.g. |
171 | | 0.06 == 6% */ |
172 | | |
173 | | INT min_is_sfbs; /*!< Only perform IS if 'min_is_sfbs' neighboring SFBs can be |
174 | | processed */ |
175 | | |
176 | | FIXP_DBL left_right_ratio_threshold; /*!< No IS if the panning angle is not |
177 | | far from the middle, MS will do */ |
178 | | |
179 | | } INTENSITY_PARAMETERS; |
180 | | |
181 | | /***************************************************************************** |
182 | | |
183 | | functionname: calcSfbMaxScale |
184 | | |
185 | | description: Calc max value in scalefactor band |
186 | | |
187 | | input: *mdctSpectrum |
188 | | l1 |
189 | | l2 |
190 | | |
191 | | output: none |
192 | | |
193 | | returns: scalefactor |
194 | | |
195 | | *****************************************************************************/ |
196 | | static INT calcSfbMaxScale(const FIXP_DBL *mdctSpectrum, const INT l1, |
197 | 0 | const INT l2) { |
198 | 0 | INT i; |
199 | 0 | INT sfbMaxScale; |
200 | 0 | FIXP_DBL maxSpc; |
201 | |
|
202 | 0 | maxSpc = FL2FXCONST_DBL(0.0); |
203 | 0 | for (i = l1; i < l2; i++) { |
204 | 0 | FIXP_DBL tmp = fixp_abs((FIXP_DBL)mdctSpectrum[i]); |
205 | 0 | maxSpc = fixMax(maxSpc, tmp); |
206 | 0 | } |
207 | 0 | sfbMaxScale = (maxSpc == FL2FXCONST_DBL(0.0)) ? (DFRACT_BITS - 2) |
208 | 0 | : CntLeadingZeros(maxSpc) - 1; |
209 | |
|
210 | 0 | return sfbMaxScale; |
211 | 0 | } |
212 | | |
213 | | /***************************************************************************** |
214 | | |
215 | | functionname: FDKaacEnc_initIsParams |
216 | | |
217 | | description: Initialization of intensity parameters |
218 | | |
219 | | input: isParams |
220 | | |
221 | | output: isParams |
222 | | |
223 | | returns: none |
224 | | |
225 | | *****************************************************************************/ |
226 | 0 | static void FDKaacEnc_initIsParams(INTENSITY_PARAMETERS *isParams) { |
227 | 0 | isParams->corr_thresh = IS_CORR_THRESH; |
228 | 0 | isParams->total_error_thresh = IS_TOTAL_ERROR_THRESH; |
229 | 0 | isParams->local_error_thresh = IS_LOCAL_ERROR_THRESH; |
230 | 0 | isParams->direction_deviation_thresh = IS_DIRECTION_DEVIATION_THRESH; |
231 | 0 | isParams->is_region_min_loudness = IS_REGION_MIN_LOUDNESS; |
232 | 0 | isParams->min_is_sfbs = IS_MIN_SFBS; |
233 | 0 | isParams->left_right_ratio_threshold = IS_LEFT_RIGHT_RATIO_THRESH; |
234 | 0 | } |
235 | | |
236 | | /***************************************************************************** |
237 | | |
238 | | functionname: FDKaacEnc_prepareIntensityDecision |
239 | | |
240 | | description: Prepares intensity decision |
241 | | |
242 | | input: sfbEnergyLeft |
243 | | sfbEnergyRight |
244 | | sfbEnergyLdDataLeft |
245 | | sfbEnergyLdDataRight |
246 | | mdctSpectrumLeft |
247 | | sfbEnergyLdDataRight |
248 | | isParams |
249 | | |
250 | | output: hrrErr scale: none |
251 | | isMask scale: none |
252 | | realScale scale: LD_DATA_SHIFT + REAL_SCALE_SF |
253 | | normSfbLoudness scale: none |
254 | | |
255 | | returns: none |
256 | | |
257 | | *****************************************************************************/ |
258 | | static void FDKaacEnc_prepareIntensityDecision( |
259 | | const FIXP_DBL *sfbEnergyLeft, const FIXP_DBL *sfbEnergyRight, |
260 | | const FIXP_DBL *sfbEnergyLdDataLeft, const FIXP_DBL *sfbEnergyLdDataRight, |
261 | | const FIXP_DBL *mdctSpectrumLeft, const FIXP_DBL *mdctSpectrumRight, |
262 | | const INTENSITY_PARAMETERS *isParams, FIXP_DBL *hrrErr, INT *isMask, |
263 | | FIXP_DBL *realScale, FIXP_DBL *normSfbLoudness, const INT sfbCnt, |
264 | 0 | const INT sfbPerGroup, const INT maxSfbPerGroup, const INT *sfbOffset) { |
265 | 0 | INT j, sfb, sfboffs; |
266 | 0 | INT grpCounter; |
267 | | |
268 | | /* temporary variables to compute loudness */ |
269 | 0 | FIXP_DBL overallLoudness[MAX_NO_OF_GROUPS]; |
270 | | |
271 | | /* temporary variables to compute correlation */ |
272 | 0 | FIXP_DBL channelCorr[MAX_GROUPED_SFB]; |
273 | 0 | FIXP_DBL ml, mr; |
274 | 0 | FIXP_DBL prod_lr; |
275 | 0 | FIXP_DBL square_l, square_r; |
276 | 0 | FIXP_DBL tmp_l, tmp_r; |
277 | 0 | FIXP_DBL inv_n; |
278 | |
|
279 | 0 | FDKmemclear(channelCorr, MAX_GROUPED_SFB * sizeof(FIXP_DBL)); |
280 | 0 | FDKmemclear(normSfbLoudness, MAX_GROUPED_SFB * sizeof(FIXP_DBL)); |
281 | 0 | FDKmemclear(overallLoudness, MAX_NO_OF_GROUPS * sizeof(FIXP_DBL)); |
282 | 0 | FDKmemclear(realScale, MAX_GROUPED_SFB * sizeof(FIXP_DBL)); |
283 | |
|
284 | 0 | for (grpCounter = 0, sfboffs = 0; sfboffs < sfbCnt; |
285 | 0 | sfboffs += sfbPerGroup, grpCounter++) { |
286 | 0 | overallLoudness[grpCounter] = FL2FXCONST_DBL(0.0f); |
287 | 0 | for (sfb = 0; sfb < maxSfbPerGroup; sfb++) { |
288 | 0 | INT sL, sR, s; |
289 | 0 | FIXP_DBL isValue = sfbEnergyLdDataLeft[sfb + sfboffs] - |
290 | 0 | sfbEnergyLdDataRight[sfb + sfboffs]; |
291 | | |
292 | | /* delimitate intensity scale value to representable range */ |
293 | 0 | realScale[sfb + sfboffs] = fixMin( |
294 | 0 | FL2FXCONST_DBL(60.f / (1 << (REAL_SCALE_SF + LD_DATA_SHIFT))), |
295 | 0 | fixMax(FL2FXCONST_DBL(-60.f / (1 << (REAL_SCALE_SF + LD_DATA_SHIFT))), |
296 | 0 | isValue)); |
297 | |
|
298 | 0 | sL = fixMax(0, (CntLeadingZeros(sfbEnergyLeft[sfb + sfboffs]) - 1)); |
299 | 0 | sR = fixMax(0, (CntLeadingZeros(sfbEnergyRight[sfb + sfboffs]) - 1)); |
300 | 0 | s = (fixMin(sL, sR) >> 2) << 2; |
301 | 0 | normSfbLoudness[sfb + sfboffs] = |
302 | 0 | sqrtFixp(sqrtFixp(((sfbEnergyLeft[sfb + sfboffs] << s) >> 1) + |
303 | 0 | ((sfbEnergyRight[sfb + sfboffs] << s) >> 1))) >> |
304 | 0 | (s >> 2); |
305 | |
|
306 | 0 | overallLoudness[grpCounter] += |
307 | 0 | normSfbLoudness[sfb + sfboffs] >> OVERALL_LOUDNESS_SF; |
308 | | /* don't do intensity if |
309 | | * - panning angle is too close to the middle or |
310 | | * - one channel is non-existent or |
311 | | * - if it is dual mono */ |
312 | 0 | if ((sfbEnergyLeft[sfb + sfboffs] >= |
313 | 0 | fMult(isParams->left_right_ratio_threshold, |
314 | 0 | sfbEnergyRight[sfb + sfboffs])) && |
315 | 0 | (fMult(isParams->left_right_ratio_threshold, |
316 | 0 | sfbEnergyLeft[sfb + sfboffs]) <= |
317 | 0 | sfbEnergyRight[sfb + sfboffs])) { |
318 | | /* this will prevent post processing from considering this SFB for |
319 | | * merging */ |
320 | 0 | hrrErr[sfb + sfboffs] = FL2FXCONST_DBL(1.0 / 8.0); |
321 | 0 | } |
322 | 0 | } |
323 | 0 | } |
324 | |
|
325 | 0 | for (grpCounter = 0, sfboffs = 0; sfboffs < sfbCnt; |
326 | 0 | sfboffs += sfbPerGroup, grpCounter++) { |
327 | 0 | INT invOverallLoudnessSF; |
328 | 0 | FIXP_DBL invOverallLoudness; |
329 | |
|
330 | 0 | if (overallLoudness[grpCounter] == FL2FXCONST_DBL(0.0)) { |
331 | 0 | invOverallLoudness = FL2FXCONST_DBL(0.0); |
332 | 0 | invOverallLoudnessSF = 0; |
333 | 0 | } else { |
334 | 0 | invOverallLoudness = |
335 | 0 | fDivNorm((FIXP_DBL)MAXVAL_DBL, overallLoudness[grpCounter], |
336 | 0 | &invOverallLoudnessSF); |
337 | 0 | invOverallLoudnessSF = |
338 | 0 | invOverallLoudnessSF - OVERALL_LOUDNESS_SF + |
339 | 0 | 1; /* +1: compensate fMultDiv2() in subsequent loop */ |
340 | 0 | } |
341 | 0 | invOverallLoudnessSF = fixMin( |
342 | 0 | fixMax(invOverallLoudnessSF, -(DFRACT_BITS - 1)), DFRACT_BITS - 1); |
343 | |
|
344 | 0 | for (sfb = 0; sfb < maxSfbPerGroup; sfb++) { |
345 | 0 | FIXP_DBL tmp; |
346 | |
|
347 | 0 | tmp = fMultDiv2((normSfbLoudness[sfb + sfboffs] >> OVERALL_LOUDNESS_SF) |
348 | 0 | << OVERALL_LOUDNESS_SF, |
349 | 0 | invOverallLoudness); |
350 | |
|
351 | 0 | normSfbLoudness[sfb + sfboffs] = scaleValue(tmp, invOverallLoudnessSF); |
352 | |
|
353 | 0 | channelCorr[sfb + sfboffs] = FL2FXCONST_DBL(0.0f); |
354 | | |
355 | | /* max width of scalefactorband is 96; width's are always even */ |
356 | | /* inv_n is scaled with factor 2 to compensate fMultDiv2() in subsequent |
357 | | * loops */ |
358 | 0 | inv_n = GetInvInt( |
359 | 0 | (sfbOffset[sfb + sfboffs + 1] - sfbOffset[sfb + sfboffs]) >> 1); |
360 | |
|
361 | 0 | if (inv_n > FL2FXCONST_DBL(0.0f)) { |
362 | 0 | INT s, sL, sR; |
363 | | |
364 | | /* correlation := Pearson's product-moment coefficient */ |
365 | | /* compute correlation between channels and check if it is over |
366 | | * threshold */ |
367 | 0 | ml = FL2FXCONST_DBL(0.0f); |
368 | 0 | mr = FL2FXCONST_DBL(0.0f); |
369 | 0 | prod_lr = FL2FXCONST_DBL(0.0f); |
370 | 0 | square_l = FL2FXCONST_DBL(0.0f); |
371 | 0 | square_r = FL2FXCONST_DBL(0.0f); |
372 | |
|
373 | 0 | sL = calcSfbMaxScale(mdctSpectrumLeft, sfbOffset[sfb + sfboffs], |
374 | 0 | sfbOffset[sfb + sfboffs + 1]); |
375 | 0 | sR = calcSfbMaxScale(mdctSpectrumRight, sfbOffset[sfb + sfboffs], |
376 | 0 | sfbOffset[sfb + sfboffs + 1]); |
377 | 0 | s = fixMin(sL, sR); |
378 | |
|
379 | 0 | for (j = sfbOffset[sfb + sfboffs]; j < sfbOffset[sfb + sfboffs + 1]; |
380 | 0 | j++) { |
381 | 0 | ml += fMultDiv2((mdctSpectrumLeft[j] << s), |
382 | 0 | inv_n); // scaled with mdctScale - s + inv_n |
383 | 0 | mr += fMultDiv2((mdctSpectrumRight[j] << s), |
384 | 0 | inv_n); // scaled with mdctScale - s + inv_n |
385 | 0 | } |
386 | 0 | ml = fMultDiv2(ml, inv_n); // scaled with mdctScale - s + inv_n |
387 | 0 | mr = fMultDiv2(mr, inv_n); // scaled with mdctScale - s + inv_n |
388 | |
|
389 | 0 | for (j = sfbOffset[sfb + sfboffs]; j < sfbOffset[sfb + sfboffs + 1]; |
390 | 0 | j++) { |
391 | 0 | tmp_l = fMultDiv2((mdctSpectrumLeft[j] << s), inv_n) - |
392 | 0 | ml; // scaled with mdctScale - s + inv_n |
393 | 0 | tmp_r = fMultDiv2((mdctSpectrumRight[j] << s), inv_n) - |
394 | 0 | mr; // scaled with mdctScale - s + inv_n |
395 | |
|
396 | 0 | prod_lr += fMultDiv2( |
397 | 0 | tmp_l, tmp_r); // scaled with 2*(mdctScale - s + inv_n) + 1 |
398 | 0 | square_l += |
399 | 0 | fPow2Div2(tmp_l); // scaled with 2*(mdctScale - s + inv_n) + 1 |
400 | 0 | square_r += |
401 | 0 | fPow2Div2(tmp_r); // scaled with 2*(mdctScale - s + inv_n) + 1 |
402 | 0 | } |
403 | 0 | prod_lr = prod_lr << 1; // scaled with 2*(mdctScale - s + inv_n) |
404 | 0 | square_l = square_l << 1; // scaled with 2*(mdctScale - s + inv_n) |
405 | 0 | square_r = square_r << 1; // scaled with 2*(mdctScale - s + inv_n) |
406 | |
|
407 | 0 | if (square_l > FL2FXCONST_DBL(0.0f) && |
408 | 0 | square_r > FL2FXCONST_DBL(0.0f)) { |
409 | 0 | INT channelCorrSF = 0; |
410 | | |
411 | | /* local scaling of square_l and square_r is compensated after sqrt |
412 | | * calculation */ |
413 | 0 | sL = fixMax(0, (CntLeadingZeros(square_l) - 1)); |
414 | 0 | sR = fixMax(0, (CntLeadingZeros(square_r) - 1)); |
415 | 0 | s = ((sL + sR) >> 1) << 1; |
416 | 0 | sL = fixMin(sL, s); |
417 | 0 | sR = s - sL; |
418 | 0 | tmp = fMult(square_l << sL, square_r << sR); |
419 | 0 | tmp = sqrtFixp(tmp); |
420 | |
|
421 | 0 | FDK_ASSERT(tmp > FL2FXCONST_DBL(0.0f)); |
422 | | |
423 | | /* numerator and denominator have the same scaling */ |
424 | 0 | if (prod_lr < FL2FXCONST_DBL(0.0f)) { |
425 | 0 | channelCorr[sfb + sfboffs] = |
426 | 0 | -(fDivNorm(-prod_lr, tmp, &channelCorrSF)); |
427 | |
|
428 | 0 | } else { |
429 | 0 | channelCorr[sfb + sfboffs] = |
430 | 0 | (fDivNorm(prod_lr, tmp, &channelCorrSF)); |
431 | 0 | } |
432 | 0 | channelCorrSF = fixMin( |
433 | 0 | fixMax((channelCorrSF + ((sL + sR) >> 1)), -(DFRACT_BITS - 1)), |
434 | 0 | DFRACT_BITS - 1); |
435 | |
|
436 | 0 | if (channelCorrSF < 0) { |
437 | 0 | channelCorr[sfb + sfboffs] = |
438 | 0 | channelCorr[sfb + sfboffs] >> (-channelCorrSF); |
439 | 0 | } else { |
440 | | /* avoid overflows due to limited computational accuracy */ |
441 | 0 | if (fAbs(channelCorr[sfb + sfboffs]) > |
442 | 0 | (((FIXP_DBL)MAXVAL_DBL) >> channelCorrSF)) { |
443 | 0 | if (channelCorr[sfb + sfboffs] < FL2FXCONST_DBL(0.0f)) |
444 | 0 | channelCorr[sfb + sfboffs] = -(FIXP_DBL)MAXVAL_DBL; |
445 | 0 | else |
446 | 0 | channelCorr[sfb + sfboffs] = (FIXP_DBL)MAXVAL_DBL; |
447 | 0 | } else { |
448 | 0 | channelCorr[sfb + sfboffs] = channelCorr[sfb + sfboffs] |
449 | 0 | << channelCorrSF; |
450 | 0 | } |
451 | 0 | } |
452 | 0 | } |
453 | 0 | } |
454 | | |
455 | | /* for post processing: hrrErr is the error in terms of (too little) |
456 | | * correlation weighted with the loudness of the SFB; SFBs with small |
457 | | * hrrErr can be merged */ |
458 | 0 | if (hrrErr[sfb + sfboffs] == FL2FXCONST_DBL(1.0 / 8.0)) { |
459 | 0 | continue; |
460 | 0 | } |
461 | | |
462 | 0 | hrrErr[sfb + sfboffs] = |
463 | 0 | fMultDiv2((FL2FXCONST_DBL(0.25f) - (channelCorr[sfb + sfboffs] >> 2)), |
464 | 0 | normSfbLoudness[sfb + sfboffs]); |
465 | | |
466 | | /* set IS mask/vector to 1, if correlation is high enough */ |
467 | 0 | if (fAbs(channelCorr[sfb + sfboffs]) >= isParams->corr_thresh) { |
468 | 0 | isMask[sfb + sfboffs] = 1; |
469 | 0 | } |
470 | 0 | } |
471 | 0 | } |
472 | 0 | } |
473 | | |
474 | | /***************************************************************************** |
475 | | |
476 | | functionname: FDKaacEnc_finalizeIntensityDecision |
477 | | |
478 | | description: Finalizes intensity decision |
479 | | |
480 | | input: isParams scale: none |
481 | | hrrErr scale: none |
482 | | realIsScale scale: LD_DATA_SHIFT + REAL_SCALE_SF |
483 | | normSfbLoudness scale: none |
484 | | |
485 | | output: isMask scale: none |
486 | | |
487 | | returns: none |
488 | | |
489 | | *****************************************************************************/ |
490 | | static void FDKaacEnc_finalizeIntensityDecision( |
491 | | const FIXP_DBL *hrrErr, INT *isMask, const FIXP_DBL *realIsScale, |
492 | | const FIXP_DBL *normSfbLoudness, const INTENSITY_PARAMETERS *isParams, |
493 | 0 | const INT sfbCnt, const INT sfbPerGroup, const INT maxSfbPerGroup) { |
494 | 0 | INT sfb, sfboffs, j; |
495 | 0 | FIXP_DBL isScaleLast = FL2FXCONST_DBL(0.0f); |
496 | 0 | INT isStartValueFound = 0; |
497 | |
|
498 | 0 | for (sfboffs = 0; sfboffs < sfbCnt; sfboffs += sfbPerGroup) { |
499 | 0 | INT startIsSfb = 0; |
500 | 0 | INT inIsBlock = 0; |
501 | 0 | INT currentIsSfbCount = 0; |
502 | 0 | FIXP_DBL overallHrrError = FL2FXCONST_DBL(0.0f); |
503 | 0 | FIXP_DBL isRegionLoudness = FL2FXCONST_DBL(0.0f); |
504 | |
|
505 | 0 | for (sfb = 0; sfb < maxSfbPerGroup; sfb++) { |
506 | 0 | if (isMask[sfboffs + sfb] == 1) { |
507 | 0 | if (currentIsSfbCount == 0) { |
508 | 0 | startIsSfb = sfboffs + sfb; |
509 | 0 | } |
510 | 0 | if (isStartValueFound == 0) { |
511 | 0 | isScaleLast = realIsScale[sfboffs + sfb]; |
512 | 0 | isStartValueFound = 1; |
513 | 0 | } |
514 | 0 | inIsBlock = 1; |
515 | 0 | currentIsSfbCount++; |
516 | 0 | overallHrrError += hrrErr[sfboffs + sfb] >> (MAX_SFB_PER_GROUP_SF - 3); |
517 | 0 | isRegionLoudness += |
518 | 0 | normSfbLoudness[sfboffs + sfb] >> MAX_SFB_PER_GROUP_SF; |
519 | 0 | } else { |
520 | | /* based on correlation, IS should not be used |
521 | | * -> use it anyway, if overall error is below threshold |
522 | | * and if local error does not exceed threshold |
523 | | * otherwise: check if there are enough IS SFBs |
524 | | */ |
525 | 0 | if (inIsBlock) { |
526 | 0 | overallHrrError += |
527 | 0 | hrrErr[sfboffs + sfb] >> (MAX_SFB_PER_GROUP_SF - 3); |
528 | 0 | isRegionLoudness += |
529 | 0 | normSfbLoudness[sfboffs + sfb] >> MAX_SFB_PER_GROUP_SF; |
530 | |
|
531 | 0 | if ((hrrErr[sfboffs + sfb] < (isParams->local_error_thresh >> 3)) && |
532 | 0 | (overallHrrError < |
533 | 0 | (isParams->total_error_thresh >> MAX_SFB_PER_GROUP_SF))) { |
534 | 0 | currentIsSfbCount++; |
535 | | /* overwrite correlation based decision */ |
536 | 0 | isMask[sfboffs + sfb] = 1; |
537 | 0 | } else { |
538 | 0 | inIsBlock = 0; |
539 | 0 | } |
540 | 0 | } |
541 | 0 | } |
542 | | /* check for large direction deviation */ |
543 | 0 | if (inIsBlock) { |
544 | 0 | if (fAbs(isScaleLast - realIsScale[sfboffs + sfb]) < |
545 | 0 | (isParams->direction_deviation_thresh >> |
546 | 0 | (REAL_SCALE_SF + LD_DATA_SHIFT - |
547 | 0 | IS_DIRECTION_DEVIATION_THRESH_SF))) { |
548 | 0 | isScaleLast = realIsScale[sfboffs + sfb]; |
549 | 0 | } else { |
550 | 0 | isMask[sfboffs + sfb] = 0; |
551 | 0 | inIsBlock = 0; |
552 | 0 | currentIsSfbCount--; |
553 | 0 | } |
554 | 0 | } |
555 | |
|
556 | 0 | if (currentIsSfbCount > 0 && (!inIsBlock || sfb == maxSfbPerGroup - 1)) { |
557 | | /* not enough SFBs -> do not use IS */ |
558 | 0 | if (currentIsSfbCount < isParams->min_is_sfbs || |
559 | 0 | (isRegionLoudness<isParams->is_region_min_loudness>> |
560 | 0 | MAX_SFB_PER_GROUP_SF)) { |
561 | 0 | for (j = startIsSfb; j <= sfboffs + sfb; j++) { |
562 | 0 | isMask[j] = 0; |
563 | 0 | } |
564 | 0 | isScaleLast = FL2FXCONST_DBL(0.0f); |
565 | 0 | isStartValueFound = 0; |
566 | 0 | for (j = 0; j < startIsSfb; j++) { |
567 | 0 | if (isMask[j] != 0) { |
568 | 0 | isScaleLast = realIsScale[j]; |
569 | 0 | isStartValueFound = 1; |
570 | 0 | } |
571 | 0 | } |
572 | 0 | } |
573 | 0 | currentIsSfbCount = 0; |
574 | 0 | overallHrrError = FL2FXCONST_DBL(0.0f); |
575 | 0 | isRegionLoudness = FL2FXCONST_DBL(0.0f); |
576 | 0 | } |
577 | 0 | } |
578 | 0 | } |
579 | 0 | } |
580 | | |
581 | | /***************************************************************************** |
582 | | |
583 | | functionname: FDKaacEnc_IntensityStereoProcessing |
584 | | |
585 | | description: Intensity stereo processing tool |
586 | | |
587 | | input: sfbEnergyLeft |
588 | | sfbEnergyRight |
589 | | mdctSpectrumLeft |
590 | | mdctSpectrumRight |
591 | | sfbThresholdLeft |
592 | | sfbThresholdRight |
593 | | sfbSpreadEnLeft |
594 | | sfbSpreadEnRight |
595 | | sfbEnergyLdDataLeft |
596 | | sfbEnergyLdDataRight |
597 | | |
598 | | output: isBook |
599 | | isScale |
600 | | pnsData->pnsFlag |
601 | | msDigest zeroed from start to sfbCnt |
602 | | msMask zeroed from start to sfbCnt |
603 | | mdctSpectrumRight zeroed where isBook!=0 |
604 | | sfbEnergyRight zeroed where isBook!=0 |
605 | | sfbSpreadEnRight zeroed where isBook!=0 |
606 | | sfbThresholdRight zeroed where isBook!=0 |
607 | | sfbEnergyLdDataRight FL2FXCONST_DBL(-1.0) where isBook!=0 |
608 | | sfbThresholdLdDataRight FL2FXCONST_DBL(-0.515625f) where |
609 | | isBook!=0 |
610 | | |
611 | | returns: none |
612 | | |
613 | | *****************************************************************************/ |
614 | | void FDKaacEnc_IntensityStereoProcessing( |
615 | | FIXP_DBL *sfbEnergyLeft, FIXP_DBL *sfbEnergyRight, |
616 | | FIXP_DBL *mdctSpectrumLeft, FIXP_DBL *mdctSpectrumRight, |
617 | | FIXP_DBL *sfbThresholdLeft, FIXP_DBL *sfbThresholdRight, |
618 | | FIXP_DBL *sfbThresholdLdDataRight, FIXP_DBL *sfbSpreadEnLeft, |
619 | | FIXP_DBL *sfbSpreadEnRight, FIXP_DBL *sfbEnergyLdDataLeft, |
620 | | FIXP_DBL *sfbEnergyLdDataRight, INT *msDigest, INT *msMask, |
621 | | const INT sfbCnt, const INT sfbPerGroup, const INT maxSfbPerGroup, |
622 | | const INT *sfbOffset, const INT allowIS, INT *isBook, INT *isScale, |
623 | 0 | PNS_DATA *RESTRICT pnsData[2]) { |
624 | 0 | INT sfb, sfboffs, j; |
625 | 0 | FIXP_DBL scale; |
626 | 0 | FIXP_DBL lr; |
627 | 0 | FIXP_DBL hrrErr[MAX_GROUPED_SFB]; |
628 | 0 | FIXP_DBL normSfbLoudness[MAX_GROUPED_SFB]; |
629 | 0 | FIXP_DBL realIsScale[MAX_GROUPED_SFB]; |
630 | 0 | INTENSITY_PARAMETERS isParams; |
631 | 0 | INT isMask[MAX_GROUPED_SFB]; |
632 | |
|
633 | 0 | FDKmemclear((void *)isBook, sfbCnt * sizeof(INT)); |
634 | 0 | FDKmemclear((void *)isMask, sfbCnt * sizeof(INT)); |
635 | 0 | FDKmemclear((void *)realIsScale, sfbCnt * sizeof(FIXP_DBL)); |
636 | 0 | FDKmemclear((void *)isScale, sfbCnt * sizeof(INT)); |
637 | 0 | FDKmemclear((void *)hrrErr, sfbCnt * sizeof(FIXP_DBL)); |
638 | |
|
639 | 0 | if (!allowIS) return; |
640 | | |
641 | 0 | FDKaacEnc_initIsParams(&isParams); |
642 | | |
643 | | /* compute / set the following values per SFB: |
644 | | * - left/right ratio between channels |
645 | | * - normalized loudness |
646 | | * + loudness == average of energy in channels to 0.25 |
647 | | * + normalization: division by sum of all SFB loudnesses |
648 | | * - isMask (is set to 0 if channels are the same or one is 0) |
649 | | */ |
650 | 0 | FDKaacEnc_prepareIntensityDecision( |
651 | 0 | sfbEnergyLeft, sfbEnergyRight, sfbEnergyLdDataLeft, sfbEnergyLdDataRight, |
652 | 0 | mdctSpectrumLeft, mdctSpectrumRight, &isParams, hrrErr, isMask, |
653 | 0 | realIsScale, normSfbLoudness, sfbCnt, sfbPerGroup, maxSfbPerGroup, |
654 | 0 | sfbOffset); |
655 | |
|
656 | 0 | FDKaacEnc_finalizeIntensityDecision(hrrErr, isMask, realIsScale, |
657 | 0 | normSfbLoudness, &isParams, sfbCnt, |
658 | 0 | sfbPerGroup, maxSfbPerGroup); |
659 | |
|
660 | 0 | for (sfb = 0; sfb < sfbCnt; sfb += sfbPerGroup) { |
661 | 0 | for (sfboffs = 0; sfboffs < maxSfbPerGroup; sfboffs++) { |
662 | 0 | INT sL, sR; |
663 | 0 | FIXP_DBL inv_n; |
664 | 0 | INT mdct_spec_sf = MDCT_SPEC_SF; |
665 | |
|
666 | 0 | msMask[sfb + sfboffs] = 0; |
667 | 0 | if (isMask[sfb + sfboffs] == 0) { |
668 | 0 | continue; |
669 | 0 | } |
670 | | |
671 | 0 | if ((sfbEnergyLeft[sfb + sfboffs] < sfbThresholdLeft[sfb + sfboffs]) && |
672 | 0 | (fMult(FL2FXCONST_DBL(1.0f / 1.5f), sfbEnergyRight[sfb + sfboffs]) > |
673 | 0 | sfbThresholdRight[sfb + sfboffs])) { |
674 | 0 | continue; |
675 | 0 | } |
676 | | /* NEW: if there is a big-enough IS region, switch off PNS */ |
677 | 0 | if (pnsData[0]) { |
678 | 0 | if (pnsData[0]->pnsFlag[sfb + sfboffs]) { |
679 | 0 | pnsData[0]->pnsFlag[sfb + sfboffs] = 0; |
680 | 0 | } |
681 | 0 | if (pnsData[1]->pnsFlag[sfb + sfboffs]) { |
682 | 0 | pnsData[1]->pnsFlag[sfb + sfboffs] = 0; |
683 | 0 | } |
684 | 0 | } |
685 | |
|
686 | 0 | if (sfbOffset[sfb + sfboffs + 1] - sfbOffset[sfb + sfboffs] > |
687 | 0 | 1 << mdct_spec_sf) { |
688 | 0 | mdct_spec_sf++; /* This is for rare cases where the number of bins in a |
689 | | scale factor band is > 64 */ |
690 | 0 | } |
691 | |
|
692 | 0 | inv_n = GetInvInt( |
693 | 0 | (sfbOffset[sfb + sfboffs + 1] - sfbOffset[sfb + sfboffs]) >> |
694 | 0 | 1); // scaled with 2 to compensate fMultDiv2() in subsequent loop |
695 | 0 | sL = calcSfbMaxScale(mdctSpectrumLeft, sfbOffset[sfb + sfboffs], |
696 | 0 | sfbOffset[sfb + sfboffs + 1]); |
697 | 0 | sR = calcSfbMaxScale(mdctSpectrumRight, sfbOffset[sfb + sfboffs], |
698 | 0 | sfbOffset[sfb + sfboffs + 1]); |
699 | |
|
700 | 0 | lr = FL2FXCONST_DBL(0.0f); |
701 | 0 | for (j = sfbOffset[sfb + sfboffs]; j < sfbOffset[sfb + sfboffs + 1]; j++) |
702 | 0 | lr += fMultDiv2( |
703 | 0 | fMultDiv2(mdctSpectrumLeft[j] << sL, mdctSpectrumRight[j] << sR), |
704 | 0 | inv_n); |
705 | 0 | lr = lr << 1; |
706 | |
|
707 | 0 | if (lr < FL2FXCONST_DBL(0.0f)) { |
708 | | /* This means OUT OF phase intensity stereo, cf. standard */ |
709 | 0 | INT s0, s1, s2; |
710 | 0 | FIXP_DBL tmp, d, ed = FL2FXCONST_DBL(0.0f); |
711 | |
|
712 | 0 | s0 = fixMin(sL, sR); |
713 | 0 | for (j = sfbOffset[sfb + sfboffs]; j < sfbOffset[sfb + sfboffs + 1]; |
714 | 0 | j++) { |
715 | 0 | d = ((mdctSpectrumLeft[j] << s0) >> 1) - |
716 | 0 | ((mdctSpectrumRight[j] << s0) >> 1); |
717 | 0 | ed += fMultDiv2(d, d) >> (mdct_spec_sf - 1); |
718 | 0 | } |
719 | 0 | msMask[sfb + sfboffs] = 1; |
720 | 0 | tmp = fDivNorm(sfbEnergyLeft[sfb + sfboffs], ed, &s1); |
721 | 0 | s2 = (s1) + (2 * s0) - 2 - mdct_spec_sf; |
722 | 0 | if (s2 & 1) { |
723 | 0 | tmp = tmp >> 1; |
724 | 0 | s2 = s2 + 1; |
725 | 0 | } |
726 | 0 | s2 = (s2 >> 1) + 1; // +1 compensate fMultDiv2() in subsequent loop |
727 | 0 | s2 = fixMin(fixMax(s2, -(DFRACT_BITS - 1)), (DFRACT_BITS - 1)); |
728 | 0 | scale = sqrtFixp(tmp); |
729 | 0 | if (s2 < 0) { |
730 | 0 | s2 = -s2; |
731 | 0 | for (j = sfbOffset[sfb + sfboffs]; j < sfbOffset[sfb + sfboffs + 1]; |
732 | 0 | j++) { |
733 | 0 | mdctSpectrumLeft[j] = (fMultDiv2(mdctSpectrumLeft[j], scale) - |
734 | 0 | fMultDiv2(mdctSpectrumRight[j], scale)) >> |
735 | 0 | s2; |
736 | 0 | mdctSpectrumRight[j] = FL2FXCONST_DBL(0.0f); |
737 | 0 | } |
738 | 0 | } else { |
739 | 0 | for (j = sfbOffset[sfb + sfboffs]; j < sfbOffset[sfb + sfboffs + 1]; |
740 | 0 | j++) { |
741 | 0 | mdctSpectrumLeft[j] = (fMultDiv2(mdctSpectrumLeft[j], scale) - |
742 | 0 | fMultDiv2(mdctSpectrumRight[j], scale)) |
743 | 0 | << s2; |
744 | 0 | mdctSpectrumRight[j] = FL2FXCONST_DBL(0.0f); |
745 | 0 | } |
746 | 0 | } |
747 | 0 | } else { |
748 | | /* This means IN phase intensity stereo, cf. standard */ |
749 | 0 | INT s0, s1, s2; |
750 | 0 | FIXP_DBL tmp, s, es = FL2FXCONST_DBL(0.0f); |
751 | |
|
752 | 0 | s0 = fixMin(sL, sR); |
753 | 0 | for (j = sfbOffset[sfb + sfboffs]; j < sfbOffset[sfb + sfboffs + 1]; |
754 | 0 | j++) { |
755 | 0 | s = ((mdctSpectrumLeft[j] << s0) >> 1) + |
756 | 0 | ((mdctSpectrumRight[j] << s0) >> 1); |
757 | 0 | es += fMultDiv2(s, s) >> |
758 | 0 | (mdct_spec_sf - |
759 | 0 | 1); // scaled 2*(mdctScale - s0 + 1) + mdct_spec_sf |
760 | 0 | } |
761 | 0 | msMask[sfb + sfboffs] = 0; |
762 | 0 | tmp = fDivNorm(sfbEnergyLeft[sfb + sfboffs], es, &s1); |
763 | 0 | s2 = (s1) + (2 * s0) - 2 - mdct_spec_sf; |
764 | 0 | if (s2 & 1) { |
765 | 0 | tmp = tmp >> 1; |
766 | 0 | s2 = s2 + 1; |
767 | 0 | } |
768 | 0 | s2 = (s2 >> 1) + 1; // +1 compensate fMultDiv2() in subsequent loop |
769 | 0 | s2 = fixMin(fixMax(s2, -(DFRACT_BITS - 1)), (DFRACT_BITS - 1)); |
770 | 0 | scale = sqrtFixp(tmp); |
771 | 0 | if (s2 < 0) { |
772 | 0 | s2 = -s2; |
773 | 0 | for (j = sfbOffset[sfb + sfboffs]; j < sfbOffset[sfb + sfboffs + 1]; |
774 | 0 | j++) { |
775 | 0 | mdctSpectrumLeft[j] = (fMultDiv2(mdctSpectrumLeft[j], scale) + |
776 | 0 | fMultDiv2(mdctSpectrumRight[j], scale)) >> |
777 | 0 | s2; |
778 | 0 | mdctSpectrumRight[j] = FL2FXCONST_DBL(0.0f); |
779 | 0 | } |
780 | 0 | } else { |
781 | 0 | for (j = sfbOffset[sfb + sfboffs]; j < sfbOffset[sfb + sfboffs + 1]; |
782 | 0 | j++) { |
783 | 0 | mdctSpectrumLeft[j] = (fMultDiv2(mdctSpectrumLeft[j], scale) + |
784 | 0 | fMultDiv2(mdctSpectrumRight[j], scale)) |
785 | 0 | << s2; |
786 | 0 | mdctSpectrumRight[j] = FL2FXCONST_DBL(0.0f); |
787 | 0 | } |
788 | 0 | } |
789 | 0 | } |
790 | |
|
791 | 0 | isBook[sfb + sfboffs] = CODE_BOOK_IS_IN_PHASE_NO; |
792 | |
|
793 | 0 | if (realIsScale[sfb + sfboffs] < FL2FXCONST_DBL(0.0f)) { |
794 | 0 | isScale[sfb + sfboffs] = |
795 | 0 | (INT)(((realIsScale[sfb + sfboffs] >> 1) - |
796 | 0 | FL2FXCONST_DBL( |
797 | 0 | 0.5f / (1 << (REAL_SCALE_SF + LD_DATA_SHIFT + 1)))) >> |
798 | 0 | (DFRACT_BITS - 1 - REAL_SCALE_SF - LD_DATA_SHIFT - 1)) + |
799 | 0 | 1; |
800 | 0 | } else { |
801 | 0 | isScale[sfb + sfboffs] = |
802 | 0 | (INT)(((realIsScale[sfb + sfboffs] >> 1) + |
803 | 0 | FL2FXCONST_DBL( |
804 | 0 | 0.5f / (1 << (REAL_SCALE_SF + LD_DATA_SHIFT + 1)))) >> |
805 | 0 | (DFRACT_BITS - 1 - REAL_SCALE_SF - LD_DATA_SHIFT - 1)); |
806 | 0 | } |
807 | |
|
808 | 0 | sfbEnergyRight[sfb + sfboffs] = FL2FXCONST_DBL(0.0f); |
809 | 0 | sfbEnergyLdDataRight[sfb + sfboffs] = FL2FXCONST_DBL(-1.0f); |
810 | 0 | sfbThresholdRight[sfb + sfboffs] = FL2FXCONST_DBL(0.0f); |
811 | 0 | sfbThresholdLdDataRight[sfb + sfboffs] = FL2FXCONST_DBL(-0.515625f); |
812 | 0 | sfbSpreadEnRight[sfb + sfboffs] = FL2FXCONST_DBL(0.0f); |
813 | |
|
814 | 0 | *msDigest = MS_SOME; |
815 | 0 | } |
816 | 0 | } |
817 | 0 | } |