/src/aac/libSACenc/src/sacenc_dmx_tdom_enh.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 | | /*********************** MPEG surround encoder library ************************* |
96 | | |
97 | | Author(s): M. Luis Valero |
98 | | |
99 | | Description: Enhanced Time Domain Downmix |
100 | | |
101 | | *******************************************************************************/ |
102 | | |
103 | | /* Includes ******************************************************************/ |
104 | | #include "sacenc_dmx_tdom_enh.h" |
105 | | |
106 | | #include "FDK_matrixCalloc.h" |
107 | | #include "FDK_trigFcts.h" |
108 | | #include "fixpoint_math.h" |
109 | | |
110 | | /* Defines *******************************************************************/ |
111 | | #define PI_FLT 3.1415926535897931f |
112 | | #define ALPHA_FLT 0.0001f |
113 | | |
114 | 0 | #define PI_E (2) |
115 | 0 | #define PI_M (FL2FXCONST_DBL(PI_FLT / (1 << PI_E))) |
116 | | |
117 | 0 | #define ALPHA_E (13) |
118 | 0 | #define ALPHA_M (FL2FXCONST_DBL(ALPHA_FLT * (1 << ALPHA_E))) |
119 | | |
120 | | enum { L = 0, R = 1 }; |
121 | | |
122 | | /* Data Types ****************************************************************/ |
123 | | typedef struct T_ENHANCED_TIME_DOMAIN_DMX { |
124 | | int maxFramelength; |
125 | | |
126 | | int framelength; |
127 | | |
128 | | FIXP_DBL prev_gain_m[2]; |
129 | | INT prev_gain_e; |
130 | | FIXP_DBL prev_H1_m[2]; |
131 | | INT prev_H1_e; |
132 | | |
133 | | FIXP_DBL *sinusWindow_m; |
134 | | SCHAR sinusWindow_e; |
135 | | |
136 | | FIXP_DBL prev_Left_m; |
137 | | INT prev_Left_e; |
138 | | FIXP_DBL prev_Right_m; |
139 | | INT prev_Right_e; |
140 | | FIXP_DBL prev_XNrg_m; |
141 | | INT prev_XNrg_e; |
142 | | |
143 | | FIXP_DBL lin_bbCld_weight_m; |
144 | | INT lin_bbCld_weight_e; |
145 | | FIXP_DBL gain_weight_m[2]; |
146 | | INT gain_weight_e; |
147 | | |
148 | | } ENHANCED_TIME_DOMAIN_DMX; |
149 | | |
150 | | /* Constants *****************************************************************/ |
151 | | |
152 | | /* Function / Class Declarations *********************************************/ |
153 | | static void calculateRatio(const FIXP_DBL sqrt_linCld_m, |
154 | | const INT sqrt_linCld_e, const FIXP_DBL lin_Cld_m, |
155 | | const INT lin_Cld_e, const FIXP_DBL Icc_m, |
156 | | const INT Icc_e, FIXP_DBL G_m[2], INT *G_e); |
157 | | |
158 | | static void calculateDmxGains(const FIXP_DBL lin_Cld_m, const INT lin_Cld_e, |
159 | | const FIXP_DBL lin_Cld2_m, const INT lin_Cld2_e, |
160 | | const FIXP_DBL Icc_m, const INT Icc_e, |
161 | | const FIXP_DBL G_m[2], const INT G_e, |
162 | | FIXP_DBL H1_m[2], INT *pH1_e); |
163 | | |
164 | | /* Function / Class Definition ***********************************************/ |
165 | | static FIXP_DBL invSqrtNorm2(const FIXP_DBL op_m, const INT op_e, |
166 | 0 | INT *const result_e) { |
167 | 0 | FIXP_DBL src_m = op_m; |
168 | 0 | int src_e = op_e; |
169 | |
|
170 | 0 | if (src_e & 1) { |
171 | 0 | src_m >>= 1; |
172 | 0 | src_e += 1; |
173 | 0 | } |
174 | |
|
175 | 0 | src_m = invSqrtNorm2(src_m, result_e); |
176 | 0 | *result_e = (*result_e) - (src_e >> 1); |
177 | |
|
178 | 0 | return src_m; |
179 | 0 | } |
180 | | |
181 | | static FIXP_DBL sqrtFixp(const FIXP_DBL op_m, const INT op_e, |
182 | 0 | INT *const result_e) { |
183 | 0 | FIXP_DBL src_m = op_m; |
184 | 0 | int src_e = op_e; |
185 | |
|
186 | 0 | if (src_e & 1) { |
187 | 0 | src_m >>= 1; |
188 | 0 | src_e += 1; |
189 | 0 | } |
190 | |
|
191 | 0 | *result_e = (src_e >> 1); |
192 | 0 | return sqrtFixp(src_m); |
193 | 0 | } |
194 | | |
195 | | static FIXP_DBL fixpAdd(const FIXP_DBL src1_m, const INT src1_e, |
196 | | const FIXP_DBL src2_m, const INT src2_e, |
197 | 0 | INT *const dst_e) { |
198 | 0 | FIXP_DBL dst_m; |
199 | |
|
200 | 0 | if (src1_m == FL2FXCONST_DBL(0.f)) { |
201 | 0 | *dst_e = src2_e; |
202 | 0 | dst_m = src2_m; |
203 | 0 | } else if (src2_m == FL2FXCONST_DBL(0.f)) { |
204 | 0 | *dst_e = src1_e; |
205 | 0 | dst_m = src1_m; |
206 | 0 | } else { |
207 | 0 | *dst_e = fixMax(src1_e, src2_e) + 1; |
208 | 0 | dst_m = |
209 | 0 | scaleValue(src1_m, fixMax((src1_e - (*dst_e)), -(DFRACT_BITS - 1))) + |
210 | 0 | scaleValue(src2_m, fixMax((src2_e - (*dst_e)), -(DFRACT_BITS - 1))); |
211 | 0 | } |
212 | 0 | return dst_m; |
213 | 0 | } |
214 | | |
215 | | /** |
216 | | * \brief Sum up fixpoint values with best possible accuracy. |
217 | | * |
218 | | * \param value1 First input value. |
219 | | * \param q1 Scaling factor of first input value. |
220 | | * \param pValue2 Pointer to second input value, will be modified on |
221 | | * return. |
222 | | * \param pQ2 Pointer to second scaling factor, will be modified on |
223 | | * return. |
224 | | * |
225 | | * \return void |
226 | | */ |
227 | | static void fixpAddNorm(const FIXP_DBL value1, const INT q1, |
228 | 0 | FIXP_DBL *const pValue2, INT *const pQ2) { |
229 | 0 | const int headroom1 = fNormz(fixp_abs(value1)) - 1; |
230 | 0 | const int headroom2 = fNormz(fixp_abs(*pValue2)) - 1; |
231 | 0 | int resultScale = fixMax(q1 - headroom1, (*pQ2) - headroom2); |
232 | |
|
233 | 0 | if ((value1 != FL2FXCONST_DBL(0.f)) && (*pValue2 != FL2FXCONST_DBL(0.f))) { |
234 | 0 | resultScale++; |
235 | 0 | } |
236 | |
|
237 | 0 | *pValue2 = |
238 | 0 | scaleValue(value1, q1 - resultScale) + |
239 | 0 | scaleValue(*pValue2, fixMax(-(DFRACT_BITS - 1), ((*pQ2) - resultScale))); |
240 | 0 | *pQ2 = (*pValue2 != (FIXP_DBL)0) ? resultScale : DFRACT_BITS - 1; |
241 | 0 | } |
242 | | |
243 | | FDK_SACENC_ERROR fdk_sacenc_open_enhancedTimeDomainDmx( |
244 | 0 | HANDLE_ENHANCED_TIME_DOMAIN_DMX *phEnhancedTimeDmx, const INT framelength) { |
245 | 0 | FDK_SACENC_ERROR error = SACENC_OK; |
246 | 0 | HANDLE_ENHANCED_TIME_DOMAIN_DMX hEnhancedTimeDmx = NULL; |
247 | |
|
248 | 0 | if (NULL == phEnhancedTimeDmx) { |
249 | 0 | error = SACENC_INVALID_HANDLE; |
250 | 0 | } else { |
251 | 0 | FDK_ALLOCATE_MEMORY_1D(hEnhancedTimeDmx, 1, ENHANCED_TIME_DOMAIN_DMX); |
252 | 0 | FDK_ALLOCATE_MEMORY_1D(hEnhancedTimeDmx->sinusWindow_m, 1 + framelength, |
253 | 0 | FIXP_DBL); |
254 | 0 | hEnhancedTimeDmx->maxFramelength = framelength; |
255 | 0 | *phEnhancedTimeDmx = hEnhancedTimeDmx; |
256 | 0 | } |
257 | 0 | return error; |
258 | | |
259 | 0 | bail: |
260 | 0 | fdk_sacenc_close_enhancedTimeDomainDmx(&hEnhancedTimeDmx); |
261 | 0 | return ((SACENC_OK == error) ? SACENC_MEMORY_ERROR : error); |
262 | 0 | } |
263 | | |
264 | | FDK_SACENC_ERROR fdk_sacenc_init_enhancedTimeDomainDmx( |
265 | | HANDLE_ENHANCED_TIME_DOMAIN_DMX hEnhancedTimeDmx, |
266 | | const FIXP_DBL *const pInputGain_m, const INT inputGain_e, |
267 | | const FIXP_DBL outputGain_m, const INT outputGain_e, |
268 | 0 | const INT framelength) { |
269 | 0 | FDK_SACENC_ERROR error = SACENC_OK; |
270 | |
|
271 | 0 | if (hEnhancedTimeDmx == NULL) { |
272 | 0 | error = SACENC_INVALID_HANDLE; |
273 | 0 | } else { |
274 | 0 | int smp; |
275 | 0 | if (framelength > hEnhancedTimeDmx->maxFramelength) { |
276 | 0 | error = SACENC_INIT_ERROR; |
277 | 0 | goto bail; |
278 | 0 | } |
279 | | |
280 | 0 | hEnhancedTimeDmx->framelength = framelength; |
281 | |
|
282 | 0 | INT deltax_e; |
283 | 0 | FIXP_DBL deltax_m; |
284 | |
|
285 | 0 | deltax_m = fDivNormHighPrec( |
286 | 0 | PI_M, (FIXP_DBL)(2 * hEnhancedTimeDmx->framelength), &deltax_e); |
287 | 0 | deltax_m = scaleValue(deltax_m, PI_E + deltax_e - (DFRACT_BITS - 1) - 1); |
288 | 0 | deltax_e = 1; |
289 | |
|
290 | 0 | for (smp = 0; smp < hEnhancedTimeDmx->framelength + 1; smp++) { |
291 | 0 | hEnhancedTimeDmx->sinusWindow_m[smp] = |
292 | 0 | fMult(ALPHA_M, fPow2(fixp_sin(smp * deltax_m, deltax_e))); |
293 | 0 | } |
294 | 0 | hEnhancedTimeDmx->sinusWindow_e = -ALPHA_E; |
295 | |
|
296 | 0 | hEnhancedTimeDmx->prev_Left_m = hEnhancedTimeDmx->prev_Right_m = |
297 | 0 | hEnhancedTimeDmx->prev_XNrg_m = FL2FXCONST_DBL(0.f); |
298 | 0 | hEnhancedTimeDmx->prev_Left_e = hEnhancedTimeDmx->prev_Right_e = |
299 | 0 | hEnhancedTimeDmx->prev_XNrg_e = DFRACT_BITS - 1; |
300 | |
|
301 | 0 | hEnhancedTimeDmx->lin_bbCld_weight_m = |
302 | 0 | fDivNormHighPrec(fPow2(pInputGain_m[L]), fPow2(pInputGain_m[R]), |
303 | 0 | &hEnhancedTimeDmx->lin_bbCld_weight_e); |
304 | |
|
305 | 0 | hEnhancedTimeDmx->gain_weight_m[L] = fMult(pInputGain_m[L], outputGain_m); |
306 | 0 | hEnhancedTimeDmx->gain_weight_m[R] = fMult(pInputGain_m[R], outputGain_m); |
307 | 0 | hEnhancedTimeDmx->gain_weight_e = |
308 | 0 | -fNorm(fixMax(hEnhancedTimeDmx->gain_weight_m[L], |
309 | 0 | hEnhancedTimeDmx->gain_weight_m[R])); |
310 | |
|
311 | 0 | hEnhancedTimeDmx->gain_weight_m[L] = scaleValue( |
312 | 0 | hEnhancedTimeDmx->gain_weight_m[L], -hEnhancedTimeDmx->gain_weight_e); |
313 | 0 | hEnhancedTimeDmx->gain_weight_m[R] = scaleValue( |
314 | 0 | hEnhancedTimeDmx->gain_weight_m[R], -hEnhancedTimeDmx->gain_weight_e); |
315 | 0 | hEnhancedTimeDmx->gain_weight_e += inputGain_e + outputGain_e; |
316 | |
|
317 | 0 | hEnhancedTimeDmx->prev_gain_m[L] = hEnhancedTimeDmx->gain_weight_m[L] >> 1; |
318 | 0 | hEnhancedTimeDmx->prev_gain_m[R] = hEnhancedTimeDmx->gain_weight_m[R] >> 1; |
319 | 0 | hEnhancedTimeDmx->prev_gain_e = hEnhancedTimeDmx->gain_weight_e + 1; |
320 | |
|
321 | 0 | hEnhancedTimeDmx->prev_H1_m[L] = |
322 | 0 | scaleValue(hEnhancedTimeDmx->gain_weight_m[L], -4); |
323 | 0 | hEnhancedTimeDmx->prev_H1_m[R] = |
324 | 0 | scaleValue(hEnhancedTimeDmx->gain_weight_m[R], -4); |
325 | 0 | hEnhancedTimeDmx->prev_H1_e = 2 + 2 + hEnhancedTimeDmx->gain_weight_e; |
326 | 0 | } |
327 | 0 | bail: |
328 | 0 | return error; |
329 | 0 | } |
330 | | |
331 | | FDK_SACENC_ERROR fdk_sacenc_apply_enhancedTimeDomainDmx( |
332 | | HANDLE_ENHANCED_TIME_DOMAIN_DMX hEnhancedTimeDmx, |
333 | | const INT_PCM *const *const inputTime, INT_PCM *const outputTimeDmx, |
334 | 0 | const INT InputDelay) { |
335 | 0 | FDK_SACENC_ERROR error = SACENC_OK; |
336 | |
|
337 | 0 | if ((NULL == hEnhancedTimeDmx) || (NULL == inputTime) || |
338 | 0 | (NULL == inputTime[L]) || (NULL == inputTime[R]) || |
339 | 0 | (NULL == outputTimeDmx)) { |
340 | 0 | error = SACENC_INVALID_HANDLE; |
341 | 0 | } else { |
342 | 0 | int smp; |
343 | 0 | FIXP_DBL lin_bbCld_m, lin_Cld_m, bbCorr_m, sqrt_linCld_m, G_m[2], H1_m[2], |
344 | 0 | gainLeft_m, gainRight_m; |
345 | 0 | FIXP_DBL bbNrgLeft_m, bbNrgRight_m, bbXNrg_m, nrgLeft_m, nrgRight_m, nrgX_m; |
346 | 0 | INT lin_bbCld_e, lin_Cld_e, bbCorr_e, sqrt_linCld_e, G_e, H1_e; |
347 | 0 | INT bbNrgLeft_e, bbNrgRight_e, bbXNrg_e, nrgLeft_e, nrgRight_e, nrgX_e; |
348 | | |
349 | | /* Increase energy time resolution with shorter processing blocks. 128 is an |
350 | | * empiric value. */ |
351 | 0 | const int granuleLength = fixMin(128, hEnhancedTimeDmx->framelength); |
352 | 0 | int granuleShift = |
353 | 0 | (granuleLength > 1) |
354 | 0 | ? ((DFRACT_BITS - 1) - fNorm((FIXP_DBL)(granuleLength - 1))) |
355 | 0 | : 0; |
356 | 0 | granuleShift = fixMax( |
357 | 0 | 3, granuleShift + |
358 | 0 | 1); /* one bit more headroom for worst case accumulation */ |
359 | |
|
360 | 0 | smp = 0; |
361 | | |
362 | | /* Prevent division by zero. */ |
363 | 0 | bbNrgLeft_m = bbNrgRight_m = bbXNrg_m = (FIXP_DBL)(1); |
364 | 0 | bbNrgLeft_e = bbNrgRight_e = bbXNrg_e = 0; |
365 | |
|
366 | 0 | do { |
367 | 0 | const int offset = smp; |
368 | 0 | FIXP_DBL partialL, partialR, partialX; |
369 | 0 | partialL = partialR = partialX = FL2FXCONST_DBL(0.f); |
370 | |
|
371 | 0 | int in_margin = FDKmin( |
372 | 0 | getScalefactorPCM( |
373 | 0 | &inputTime[L][offset], |
374 | 0 | fixMin(offset + granuleLength, hEnhancedTimeDmx->framelength) - |
375 | 0 | offset, |
376 | 0 | 1), |
377 | 0 | getScalefactorPCM( |
378 | 0 | &inputTime[R][offset], |
379 | 0 | fixMin(offset + granuleLength, hEnhancedTimeDmx->framelength) - |
380 | 0 | offset, |
381 | 0 | 1)); |
382 | | |
383 | | /* partial energy */ |
384 | 0 | for (smp = offset; |
385 | 0 | smp < fixMin(offset + granuleLength, hEnhancedTimeDmx->framelength); |
386 | 0 | smp++) { |
387 | 0 | FIXP_PCM inputL = |
388 | 0 | scaleValue((FIXP_PCM)inputTime[L][smp], in_margin - 1); |
389 | 0 | FIXP_PCM inputR = |
390 | 0 | scaleValue((FIXP_PCM)inputTime[R][smp], in_margin - 1); |
391 | |
|
392 | 0 | partialL += fPow2Div2(inputL) >> (granuleShift - 3); |
393 | 0 | partialR += fPow2Div2(inputR) >> (granuleShift - 3); |
394 | 0 | partialX += fMultDiv2(inputL, inputR) >> (granuleShift - 3); |
395 | 0 | } |
396 | |
|
397 | 0 | fixpAddNorm(partialL, granuleShift - 2 * in_margin, &bbNrgLeft_m, |
398 | 0 | &bbNrgLeft_e); |
399 | 0 | fixpAddNorm(partialR, granuleShift - 2 * in_margin, &bbNrgRight_m, |
400 | 0 | &bbNrgRight_e); |
401 | 0 | fixpAddNorm(partialX, granuleShift - 2 * in_margin, &bbXNrg_m, &bbXNrg_e); |
402 | 0 | } while (smp < hEnhancedTimeDmx->framelength); |
403 | |
|
404 | 0 | nrgLeft_m = |
405 | 0 | fixpAdd(hEnhancedTimeDmx->prev_Left_m, hEnhancedTimeDmx->prev_Left_e, |
406 | 0 | bbNrgLeft_m, bbNrgLeft_e, &nrgLeft_e); |
407 | 0 | nrgRight_m = |
408 | 0 | fixpAdd(hEnhancedTimeDmx->prev_Right_m, hEnhancedTimeDmx->prev_Right_e, |
409 | 0 | bbNrgRight_m, bbNrgRight_e, &nrgRight_e); |
410 | 0 | nrgX_m = |
411 | 0 | fixpAdd(hEnhancedTimeDmx->prev_XNrg_m, hEnhancedTimeDmx->prev_XNrg_e, |
412 | 0 | bbXNrg_m, bbXNrg_e, &nrgX_e); |
413 | |
|
414 | 0 | lin_bbCld_m = fMult(hEnhancedTimeDmx->lin_bbCld_weight_m, |
415 | 0 | fDivNorm(nrgLeft_m, nrgRight_m, &lin_bbCld_e)); |
416 | 0 | lin_bbCld_e += |
417 | 0 | hEnhancedTimeDmx->lin_bbCld_weight_e + nrgLeft_e - nrgRight_e; |
418 | |
|
419 | 0 | bbCorr_m = fMult(nrgX_m, invSqrtNorm2(fMult(nrgLeft_m, nrgRight_m), |
420 | 0 | nrgLeft_e + nrgRight_e, &bbCorr_e)); |
421 | 0 | bbCorr_e += nrgX_e; |
422 | |
|
423 | 0 | hEnhancedTimeDmx->prev_Left_m = bbNrgLeft_m; |
424 | 0 | hEnhancedTimeDmx->prev_Left_e = bbNrgLeft_e; |
425 | 0 | hEnhancedTimeDmx->prev_Right_m = bbNrgRight_m; |
426 | 0 | hEnhancedTimeDmx->prev_Right_e = bbNrgRight_e; |
427 | 0 | hEnhancedTimeDmx->prev_XNrg_m = bbXNrg_m; |
428 | 0 | hEnhancedTimeDmx->prev_XNrg_e = bbXNrg_e; |
429 | | |
430 | | /* |
431 | | bbCld = 10.f*log10(lin_bbCld) |
432 | | |
433 | | lin_Cld = pow(10,bbCld/20) |
434 | | = pow(10,10.f*log10(lin_bbCld)/20.f) |
435 | | = sqrt(lin_bbCld) |
436 | | |
437 | | lin_Cld2 = lin_Cld*lin_Cld |
438 | | = sqrt(lin_bbCld)*sqrt(lin_bbCld) |
439 | | = lin_bbCld |
440 | | */ |
441 | 0 | lin_Cld_m = sqrtFixp(lin_bbCld_m, lin_bbCld_e, &lin_Cld_e); |
442 | 0 | sqrt_linCld_m = sqrtFixp(lin_Cld_m, lin_Cld_e, &sqrt_linCld_e); |
443 | | |
444 | | /*calculate how much right and how much left signal, to avoid signal |
445 | | * cancellations*/ |
446 | 0 | calculateRatio(sqrt_linCld_m, sqrt_linCld_e, lin_Cld_m, lin_Cld_e, bbCorr_m, |
447 | 0 | bbCorr_e, G_m, &G_e); |
448 | | |
449 | | /*calculate downmix gains*/ |
450 | 0 | calculateDmxGains(lin_Cld_m, lin_Cld_e, lin_bbCld_m, lin_bbCld_e, bbCorr_m, |
451 | 0 | bbCorr_e, G_m, G_e, H1_m, &H1_e); |
452 | | |
453 | | /*adapt output gains*/ |
454 | 0 | H1_m[L] = fMult(H1_m[L], hEnhancedTimeDmx->gain_weight_m[L]); |
455 | 0 | H1_m[R] = fMult(H1_m[R], hEnhancedTimeDmx->gain_weight_m[R]); |
456 | 0 | H1_e += hEnhancedTimeDmx->gain_weight_e; |
457 | |
|
458 | 0 | gainLeft_m = hEnhancedTimeDmx->prev_gain_m[L]; |
459 | 0 | gainRight_m = hEnhancedTimeDmx->prev_gain_m[R]; |
460 | |
|
461 | 0 | INT intermediate_gain_e = |
462 | 0 | +hEnhancedTimeDmx->sinusWindow_e + H1_e - hEnhancedTimeDmx->prev_gain_e; |
463 | |
|
464 | 0 | for (smp = 0; smp < hEnhancedTimeDmx->framelength; smp++) { |
465 | 0 | const INT N = hEnhancedTimeDmx->framelength; |
466 | 0 | FIXP_DBL intermediate_gainLeft_m, intermediate_gainRight_m, tmp; |
467 | |
|
468 | 0 | intermediate_gainLeft_m = |
469 | 0 | scaleValue((fMult(hEnhancedTimeDmx->sinusWindow_m[smp], H1_m[L]) + |
470 | 0 | fMult(hEnhancedTimeDmx->sinusWindow_m[N - smp], |
471 | 0 | hEnhancedTimeDmx->prev_H1_m[L])), |
472 | 0 | intermediate_gain_e); |
473 | 0 | intermediate_gainRight_m = |
474 | 0 | scaleValue((fMult(hEnhancedTimeDmx->sinusWindow_m[smp], H1_m[R]) + |
475 | 0 | fMult(hEnhancedTimeDmx->sinusWindow_m[N - smp], |
476 | 0 | hEnhancedTimeDmx->prev_H1_m[R])), |
477 | 0 | intermediate_gain_e); |
478 | |
|
479 | 0 | gainLeft_m = intermediate_gainLeft_m + |
480 | 0 | fMult(FL2FXCONST_DBL(1.f - ALPHA_FLT), gainLeft_m); |
481 | 0 | gainRight_m = intermediate_gainRight_m + |
482 | 0 | fMult(FL2FXCONST_DBL(1.f - ALPHA_FLT), gainRight_m); |
483 | |
|
484 | 0 | tmp = fMultDiv2(gainLeft_m, (FIXP_PCM)inputTime[L][smp + InputDelay]) + |
485 | 0 | fMultDiv2(gainRight_m, (FIXP_PCM)inputTime[R][smp + InputDelay]); |
486 | 0 | outputTimeDmx[smp] = (INT_PCM)SATURATE_SHIFT( |
487 | 0 | tmp, |
488 | 0 | -(hEnhancedTimeDmx->prev_gain_e + 1 - (DFRACT_BITS - SAMPLE_BITS)), |
489 | 0 | SAMPLE_BITS); |
490 | 0 | } |
491 | |
|
492 | 0 | hEnhancedTimeDmx->prev_gain_m[L] = gainLeft_m; |
493 | 0 | hEnhancedTimeDmx->prev_gain_m[R] = gainRight_m; |
494 | |
|
495 | 0 | hEnhancedTimeDmx->prev_H1_m[L] = H1_m[L]; |
496 | 0 | hEnhancedTimeDmx->prev_H1_m[R] = H1_m[R]; |
497 | 0 | hEnhancedTimeDmx->prev_H1_e = H1_e; |
498 | 0 | } |
499 | |
|
500 | 0 | return error; |
501 | 0 | } |
502 | | |
503 | | static void calculateRatio(const FIXP_DBL sqrt_linCld_m, |
504 | | const INT sqrt_linCld_e, const FIXP_DBL lin_Cld_m, |
505 | | const INT lin_Cld_e, const FIXP_DBL Icc_m, |
506 | 0 | const INT Icc_e, FIXP_DBL G_m[2], INT *G_e) { |
507 | 0 | #define G_SCALE_FACTOR (2) |
508 | |
|
509 | 0 | if (Icc_m >= FL2FXCONST_DBL(0.f)) { |
510 | 0 | G_m[0] = G_m[1] = FL2FXCONST_DBL(1.f / (float)(1 << G_SCALE_FACTOR)); |
511 | 0 | G_e[0] = G_SCALE_FACTOR; |
512 | 0 | } else { |
513 | 0 | const FIXP_DBL max_gain_factor = |
514 | 0 | FL2FXCONST_DBL(2.f / (float)(1 << G_SCALE_FACTOR)); |
515 | 0 | FIXP_DBL tmp1_m, tmp2_m, numerator_m, denominator_m, r_m, r4_m, q; |
516 | 0 | INT tmp1_e, tmp2_e, numerator_e, denominator_e, r_e, r4_e; |
517 | | |
518 | | /* r = (lin_Cld + 1 + 2*Icc*sqrt_linCld) / (lin_Cld + 1 - |
519 | | * 2*Icc*sqrt_linCld) = (tmp1 + tmp2) / (tmp1 - tmp2) |
520 | | */ |
521 | 0 | tmp1_m = |
522 | 0 | fixpAdd(lin_Cld_m, lin_Cld_e, FL2FXCONST_DBL(1.f / 2.f), 1, &tmp1_e); |
523 | |
|
524 | 0 | tmp2_m = fMult(Icc_m, sqrt_linCld_m); |
525 | 0 | tmp2_e = 1 + Icc_e + sqrt_linCld_e; |
526 | 0 | numerator_m = fixpAdd(tmp1_m, tmp1_e, tmp2_m, tmp2_e, &numerator_e); |
527 | 0 | denominator_m = fixpAdd(tmp1_m, tmp1_e, -tmp2_m, tmp2_e, &denominator_e); |
528 | |
|
529 | 0 | if ((numerator_m > FL2FXCONST_DBL(0.f)) && |
530 | 0 | (denominator_m > FL2FXCONST_DBL(0.f))) { |
531 | 0 | r_m = fDivNorm(numerator_m, denominator_m, &r_e); |
532 | 0 | r_e += numerator_e - denominator_e; |
533 | | |
534 | | /* r_4 = sqrt( sqrt( r ) ) */ |
535 | 0 | r4_m = sqrtFixp(r_m, r_e, &r4_e); |
536 | 0 | r4_m = sqrtFixp(r4_m, r4_e, &r4_e); |
537 | |
|
538 | 0 | r4_e -= G_SCALE_FACTOR; |
539 | | |
540 | | /* q = min(r4_m, max_gain_factor) */ |
541 | 0 | q = ((r4_e >= 0) && (r4_m >= (max_gain_factor >> r4_e))) |
542 | 0 | ? max_gain_factor |
543 | 0 | : scaleValue(r4_m, r4_e); |
544 | 0 | } else { |
545 | 0 | q = FL2FXCONST_DBL(0.f); |
546 | 0 | } |
547 | |
|
548 | 0 | G_m[0] = max_gain_factor - q; |
549 | 0 | G_m[1] = q; |
550 | |
|
551 | 0 | *G_e = G_SCALE_FACTOR; |
552 | 0 | } |
553 | 0 | } |
554 | | |
555 | | static void calculateDmxGains(const FIXP_DBL lin_Cld_m, const INT lin_Cld_e, |
556 | | const FIXP_DBL lin_Cld2_m, const INT lin_Cld2_e, |
557 | | const FIXP_DBL Icc_m, const INT Icc_e, |
558 | | const FIXP_DBL G_m[2], const INT G_e, |
559 | 0 | FIXP_DBL H1_m[2], INT *pH1_e) { |
560 | 0 | #define H1_SCALE_FACTOR (2) |
561 | 0 | const FIXP_DBL max_gain_factor = |
562 | 0 | FL2FXCONST_DBL(2.f / (float)(1 << H1_SCALE_FACTOR)); |
563 | |
|
564 | 0 | FIXP_DBL nrgRight_m, nrgLeft_m, crossNrg_m, inv_weight_num_m, |
565 | 0 | inv_weight_denom_m, inverse_weight_m, inverse_weight_limited; |
566 | 0 | INT nrgRight_e, nrgLeft_e, crossNrg_e, inv_weight_num_e, inv_weight_denom_e, |
567 | 0 | inverse_weight_e; |
568 | | |
569 | | /* nrgRight = sqrt(1/(lin_Cld2 + 1) */ |
570 | 0 | nrgRight_m = fixpAdd(lin_Cld2_m, lin_Cld2_e, FL2FXCONST_DBL(1.f / 2.f), 1, |
571 | 0 | &nrgRight_e); |
572 | 0 | nrgRight_m = invSqrtNorm2(nrgRight_m, nrgRight_e, &nrgRight_e); |
573 | | |
574 | | /* nrgLeft = lin_Cld * nrgRight */ |
575 | 0 | nrgLeft_m = fMult(lin_Cld_m, nrgRight_m); |
576 | 0 | nrgLeft_e = lin_Cld_e + nrgRight_e; |
577 | | |
578 | | /* crossNrg = sqrt(nrgLeft*nrgRight) */ |
579 | 0 | crossNrg_m = sqrtFixp(fMult(nrgLeft_m, nrgRight_m), nrgLeft_e + nrgRight_e, |
580 | 0 | &crossNrg_e); |
581 | | |
582 | | /* inverse_weight = sqrt((nrgLeft + nrgRight) / ( (G[0]*G[0]*nrgLeft) + |
583 | | * (G[1]*G[1]*nrgRight) + 2*G[0]*G[1]*Icc*crossNrg)) = sqrt(inv_weight_num / |
584 | | * inv_weight_denom) |
585 | | */ |
586 | 0 | inv_weight_num_m = |
587 | 0 | fixpAdd(nrgRight_m, nrgRight_e, nrgLeft_m, nrgLeft_e, &inv_weight_num_e); |
588 | |
|
589 | 0 | inv_weight_denom_m = |
590 | 0 | fixpAdd(fMult(fPow2(G_m[0]), nrgLeft_m), 2 * G_e + nrgLeft_e, |
591 | 0 | fMult(fPow2(G_m[1]), nrgRight_m), 2 * G_e + nrgRight_e, |
592 | 0 | &inv_weight_denom_e); |
593 | |
|
594 | 0 | inv_weight_denom_m = |
595 | 0 | fixpAdd(fMult(fMult(fMult(G_m[0], G_m[1]), crossNrg_m), Icc_m), |
596 | 0 | 1 + 2 * G_e + crossNrg_e + Icc_e, inv_weight_denom_m, |
597 | 0 | inv_weight_denom_e, &inv_weight_denom_e); |
598 | |
|
599 | 0 | if (inv_weight_denom_m > FL2FXCONST_DBL(0.f)) { |
600 | 0 | inverse_weight_m = |
601 | 0 | fDivNorm(inv_weight_num_m, inv_weight_denom_m, &inverse_weight_e); |
602 | 0 | inverse_weight_m = |
603 | 0 | sqrtFixp(inverse_weight_m, |
604 | 0 | inverse_weight_e + inv_weight_num_e - inv_weight_denom_e, |
605 | 0 | &inverse_weight_e); |
606 | 0 | inverse_weight_e -= H1_SCALE_FACTOR; |
607 | | |
608 | | /* inverse_weight_limited = min(max_gain_factor, inverse_weight) */ |
609 | 0 | inverse_weight_limited = |
610 | 0 | ((inverse_weight_e >= 0) && |
611 | 0 | (inverse_weight_m >= (max_gain_factor >> inverse_weight_e))) |
612 | 0 | ? max_gain_factor |
613 | 0 | : scaleValue(inverse_weight_m, inverse_weight_e); |
614 | 0 | } else { |
615 | 0 | inverse_weight_limited = max_gain_factor; |
616 | 0 | } |
617 | |
|
618 | 0 | H1_m[0] = fMult(G_m[0], inverse_weight_limited); |
619 | 0 | H1_m[1] = fMult(G_m[1], inverse_weight_limited); |
620 | |
|
621 | 0 | *pH1_e = G_e + H1_SCALE_FACTOR; |
622 | 0 | } |
623 | | |
624 | | FDK_SACENC_ERROR fdk_sacenc_close_enhancedTimeDomainDmx( |
625 | 0 | HANDLE_ENHANCED_TIME_DOMAIN_DMX *phEnhancedTimeDmx) { |
626 | 0 | FDK_SACENC_ERROR error = SACENC_OK; |
627 | |
|
628 | 0 | if (phEnhancedTimeDmx == NULL) { |
629 | 0 | error = SACENC_INVALID_HANDLE; |
630 | 0 | } else { |
631 | 0 | if (*phEnhancedTimeDmx != NULL) { |
632 | 0 | if ((*phEnhancedTimeDmx)->sinusWindow_m != NULL) { |
633 | 0 | FDK_FREE_MEMORY_1D((*phEnhancedTimeDmx)->sinusWindow_m); |
634 | 0 | } |
635 | 0 | FDK_FREE_MEMORY_1D(*phEnhancedTimeDmx); |
636 | 0 | } |
637 | 0 | } |
638 | 0 | return error; |
639 | 0 | } |