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 #define PI_E (2)
115 #define PI_M (FL2FXCONST_DBL(PI_FLT / (1 << PI_E)))
116
117 #define ALPHA_E (13)
118 #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 ***********************************************/
invSqrtNorm2(const FIXP_DBL op_m,const INT op_e,INT * const result_e)165 static FIXP_DBL invSqrtNorm2(const FIXP_DBL op_m, const INT op_e,
166 INT *const result_e) {
167 FIXP_DBL src_m = op_m;
168 int src_e = op_e;
169
170 if (src_e & 1) {
171 src_m >>= 1;
172 src_e += 1;
173 }
174
175 src_m = invSqrtNorm2(src_m, result_e);
176 *result_e = (*result_e) - (src_e >> 1);
177
178 return src_m;
179 }
180
sqrtFixp(const FIXP_DBL op_m,const INT op_e,INT * const result_e)181 static FIXP_DBL sqrtFixp(const FIXP_DBL op_m, const INT op_e,
182 INT *const result_e) {
183 FIXP_DBL src_m = op_m;
184 int src_e = op_e;
185
186 if (src_e & 1) {
187 src_m >>= 1;
188 src_e += 1;
189 }
190
191 *result_e = (src_e >> 1);
192 return sqrtFixp(src_m);
193 }
194
fixpAdd(const FIXP_DBL src1_m,const INT src1_e,const FIXP_DBL src2_m,const INT src2_e,INT * const dst_e)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 INT *const dst_e) {
198 FIXP_DBL dst_m;
199
200 if (src1_m == FL2FXCONST_DBL(0.f)) {
201 *dst_e = src2_e;
202 dst_m = src2_m;
203 } else if (src2_m == FL2FXCONST_DBL(0.f)) {
204 *dst_e = src1_e;
205 dst_m = src1_m;
206 } else {
207 *dst_e = fixMax(src1_e, src2_e) + 1;
208 dst_m =
209 scaleValue(src1_m, fixMax((src1_e - (*dst_e)), -(DFRACT_BITS - 1))) +
210 scaleValue(src2_m, fixMax((src2_e - (*dst_e)), -(DFRACT_BITS - 1)));
211 }
212 return dst_m;
213 }
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 */
fixpAddNorm(const FIXP_DBL value1,const INT q1,FIXP_DBL * const pValue2,INT * const pQ2)227 static void fixpAddNorm(const FIXP_DBL value1, const INT q1,
228 FIXP_DBL *const pValue2, INT *const pQ2) {
229 const int headroom1 = fNormz(fixp_abs(value1)) - 1;
230 const int headroom2 = fNormz(fixp_abs(*pValue2)) - 1;
231 int resultScale = fixMax(q1 - headroom1, (*pQ2) - headroom2);
232
233 if ((value1 != FL2FXCONST_DBL(0.f)) && (*pValue2 != FL2FXCONST_DBL(0.f))) {
234 resultScale++;
235 }
236
237 *pValue2 =
238 scaleValue(value1, q1 - resultScale) +
239 scaleValue(*pValue2, fixMax(-(DFRACT_BITS - 1), ((*pQ2) - resultScale)));
240 *pQ2 = (*pValue2 != (FIXP_DBL)0) ? resultScale : DFRACT_BITS - 1;
241 }
242
fdk_sacenc_open_enhancedTimeDomainDmx(HANDLE_ENHANCED_TIME_DOMAIN_DMX * phEnhancedTimeDmx,const INT framelength)243 FDK_SACENC_ERROR fdk_sacenc_open_enhancedTimeDomainDmx(
244 HANDLE_ENHANCED_TIME_DOMAIN_DMX *phEnhancedTimeDmx, const INT framelength) {
245 FDK_SACENC_ERROR error = SACENC_OK;
246 HANDLE_ENHANCED_TIME_DOMAIN_DMX hEnhancedTimeDmx = NULL;
247
248 if (NULL == phEnhancedTimeDmx) {
249 error = SACENC_INVALID_HANDLE;
250 } else {
251 FDK_ALLOCATE_MEMORY_1D(hEnhancedTimeDmx, 1, ENHANCED_TIME_DOMAIN_DMX);
252 FDK_ALLOCATE_MEMORY_1D(hEnhancedTimeDmx->sinusWindow_m, 1 + framelength,
253 FIXP_DBL);
254 hEnhancedTimeDmx->maxFramelength = framelength;
255 *phEnhancedTimeDmx = hEnhancedTimeDmx;
256 }
257 return error;
258
259 bail:
260 fdk_sacenc_close_enhancedTimeDomainDmx(&hEnhancedTimeDmx);
261 return ((SACENC_OK == error) ? SACENC_MEMORY_ERROR : error);
262 }
263
fdk_sacenc_init_enhancedTimeDomainDmx(HANDLE_ENHANCED_TIME_DOMAIN_DMX hEnhancedTimeDmx,const FIXP_DBL * const pInputGain_m,const INT inputGain_e,const FIXP_DBL outputGain_m,const INT outputGain_e,const INT framelength)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 const INT framelength) {
269 FDK_SACENC_ERROR error = SACENC_OK;
270
271 if (hEnhancedTimeDmx == NULL) {
272 error = SACENC_INVALID_HANDLE;
273 } else {
274 int smp;
275 if (framelength > hEnhancedTimeDmx->maxFramelength) {
276 error = SACENC_INIT_ERROR;
277 goto bail;
278 }
279
280 hEnhancedTimeDmx->framelength = framelength;
281
282 INT deltax_e;
283 FIXP_DBL deltax_m;
284
285 deltax_m = fDivNormHighPrec(
286 PI_M, (FIXP_DBL)(2 * hEnhancedTimeDmx->framelength), &deltax_e);
287 deltax_m = scaleValue(deltax_m, PI_E + deltax_e - (DFRACT_BITS - 1) - 1);
288 deltax_e = 1;
289
290 for (smp = 0; smp < hEnhancedTimeDmx->framelength + 1; smp++) {
291 hEnhancedTimeDmx->sinusWindow_m[smp] =
292 fMult(ALPHA_M, fPow2(fixp_sin(smp * deltax_m, deltax_e)));
293 }
294 hEnhancedTimeDmx->sinusWindow_e = -ALPHA_E;
295
296 hEnhancedTimeDmx->prev_Left_m = hEnhancedTimeDmx->prev_Right_m =
297 hEnhancedTimeDmx->prev_XNrg_m = FL2FXCONST_DBL(0.f);
298 hEnhancedTimeDmx->prev_Left_e = hEnhancedTimeDmx->prev_Right_e =
299 hEnhancedTimeDmx->prev_XNrg_e = DFRACT_BITS - 1;
300
301 hEnhancedTimeDmx->lin_bbCld_weight_m =
302 fDivNormHighPrec(fPow2(pInputGain_m[L]), fPow2(pInputGain_m[R]),
303 &hEnhancedTimeDmx->lin_bbCld_weight_e);
304
305 hEnhancedTimeDmx->gain_weight_m[L] = fMult(pInputGain_m[L], outputGain_m);
306 hEnhancedTimeDmx->gain_weight_m[R] = fMult(pInputGain_m[R], outputGain_m);
307 hEnhancedTimeDmx->gain_weight_e =
308 -fNorm(fixMax(hEnhancedTimeDmx->gain_weight_m[L],
309 hEnhancedTimeDmx->gain_weight_m[R]));
310
311 hEnhancedTimeDmx->gain_weight_m[L] = scaleValue(
312 hEnhancedTimeDmx->gain_weight_m[L], -hEnhancedTimeDmx->gain_weight_e);
313 hEnhancedTimeDmx->gain_weight_m[R] = scaleValue(
314 hEnhancedTimeDmx->gain_weight_m[R], -hEnhancedTimeDmx->gain_weight_e);
315 hEnhancedTimeDmx->gain_weight_e += inputGain_e + outputGain_e;
316
317 hEnhancedTimeDmx->prev_gain_m[L] = hEnhancedTimeDmx->gain_weight_m[L] >> 1;
318 hEnhancedTimeDmx->prev_gain_m[R] = hEnhancedTimeDmx->gain_weight_m[R] >> 1;
319 hEnhancedTimeDmx->prev_gain_e = hEnhancedTimeDmx->gain_weight_e + 1;
320
321 hEnhancedTimeDmx->prev_H1_m[L] =
322 scaleValue(hEnhancedTimeDmx->gain_weight_m[L], -4);
323 hEnhancedTimeDmx->prev_H1_m[R] =
324 scaleValue(hEnhancedTimeDmx->gain_weight_m[R], -4);
325 hEnhancedTimeDmx->prev_H1_e = 2 + 2 + hEnhancedTimeDmx->gain_weight_e;
326 }
327 bail:
328 return error;
329 }
330
fdk_sacenc_apply_enhancedTimeDomainDmx(HANDLE_ENHANCED_TIME_DOMAIN_DMX hEnhancedTimeDmx,const INT_PCM * const * const inputTime,INT_PCM * const outputTimeDmx,const INT InputDelay)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 const INT InputDelay) {
335 FDK_SACENC_ERROR error = SACENC_OK;
336
337 if ((NULL == hEnhancedTimeDmx) || (NULL == inputTime) ||
338 (NULL == inputTime[L]) || (NULL == inputTime[R]) ||
339 (NULL == outputTimeDmx)) {
340 error = SACENC_INVALID_HANDLE;
341 } else {
342 int smp;
343 FIXP_DBL lin_bbCld_m, lin_Cld_m, bbCorr_m, sqrt_linCld_m, G_m[2], H1_m[2],
344 gainLeft_m, gainRight_m;
345 FIXP_DBL bbNrgLeft_m, bbNrgRight_m, bbXNrg_m, nrgLeft_m, nrgRight_m, nrgX_m;
346 INT lin_bbCld_e, lin_Cld_e, bbCorr_e, sqrt_linCld_e, G_e, H1_e;
347 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 const int granuleLength = fixMin(128, hEnhancedTimeDmx->framelength);
352 int granuleShift =
353 (granuleLength > 1)
354 ? ((DFRACT_BITS - 1) - fNorm((FIXP_DBL)(granuleLength - 1)))
355 : 0;
356 granuleShift = fixMax(
357 3, granuleShift +
358 1); /* one bit more headroom for worst case accumulation */
359
360 smp = 0;
361
362 /* Prevent division by zero. */
363 bbNrgLeft_m = bbNrgRight_m = bbXNrg_m = (FIXP_DBL)(1);
364 bbNrgLeft_e = bbNrgRight_e = bbXNrg_e = 0;
365
366 do {
367 const int offset = smp;
368 FIXP_DBL partialL, partialR, partialX;
369 partialL = partialR = partialX = FL2FXCONST_DBL(0.f);
370
371 int in_margin = FDKmin(
372 getScalefactorPCM(
373 &inputTime[L][offset],
374 fixMin(offset + granuleLength, hEnhancedTimeDmx->framelength) -
375 offset,
376 1),
377 getScalefactorPCM(
378 &inputTime[R][offset],
379 fixMin(offset + granuleLength, hEnhancedTimeDmx->framelength) -
380 offset,
381 1));
382
383 /* partial energy */
384 for (smp = offset;
385 smp < fixMin(offset + granuleLength, hEnhancedTimeDmx->framelength);
386 smp++) {
387 FIXP_PCM inputL =
388 scaleValue((FIXP_PCM)inputTime[L][smp], in_margin - 1);
389 FIXP_PCM inputR =
390 scaleValue((FIXP_PCM)inputTime[R][smp], in_margin - 1);
391
392 partialL += fPow2Div2(inputL) >> (granuleShift - 3);
393 partialR += fPow2Div2(inputR) >> (granuleShift - 3);
394 partialX += fMultDiv2(inputL, inputR) >> (granuleShift - 3);
395 }
396
397 fixpAddNorm(partialL, granuleShift - 2 * in_margin, &bbNrgLeft_m,
398 &bbNrgLeft_e);
399 fixpAddNorm(partialR, granuleShift - 2 * in_margin, &bbNrgRight_m,
400 &bbNrgRight_e);
401 fixpAddNorm(partialX, granuleShift - 2 * in_margin, &bbXNrg_m, &bbXNrg_e);
402 } while (smp < hEnhancedTimeDmx->framelength);
403
404 nrgLeft_m =
405 fixpAdd(hEnhancedTimeDmx->prev_Left_m, hEnhancedTimeDmx->prev_Left_e,
406 bbNrgLeft_m, bbNrgLeft_e, &nrgLeft_e);
407 nrgRight_m =
408 fixpAdd(hEnhancedTimeDmx->prev_Right_m, hEnhancedTimeDmx->prev_Right_e,
409 bbNrgRight_m, bbNrgRight_e, &nrgRight_e);
410 nrgX_m =
411 fixpAdd(hEnhancedTimeDmx->prev_XNrg_m, hEnhancedTimeDmx->prev_XNrg_e,
412 bbXNrg_m, bbXNrg_e, &nrgX_e);
413
414 lin_bbCld_m = fMult(hEnhancedTimeDmx->lin_bbCld_weight_m,
415 fDivNorm(nrgLeft_m, nrgRight_m, &lin_bbCld_e));
416 lin_bbCld_e +=
417 hEnhancedTimeDmx->lin_bbCld_weight_e + nrgLeft_e - nrgRight_e;
418
419 bbCorr_m = fMult(nrgX_m, invSqrtNorm2(fMult(nrgLeft_m, nrgRight_m),
420 nrgLeft_e + nrgRight_e, &bbCorr_e));
421 bbCorr_e += nrgX_e;
422
423 hEnhancedTimeDmx->prev_Left_m = bbNrgLeft_m;
424 hEnhancedTimeDmx->prev_Left_e = bbNrgLeft_e;
425 hEnhancedTimeDmx->prev_Right_m = bbNrgRight_m;
426 hEnhancedTimeDmx->prev_Right_e = bbNrgRight_e;
427 hEnhancedTimeDmx->prev_XNrg_m = bbXNrg_m;
428 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 lin_Cld_m = sqrtFixp(lin_bbCld_m, lin_bbCld_e, &lin_Cld_e);
442 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 calculateRatio(sqrt_linCld_m, sqrt_linCld_e, lin_Cld_m, lin_Cld_e, bbCorr_m,
447 bbCorr_e, G_m, &G_e);
448
449 /*calculate downmix gains*/
450 calculateDmxGains(lin_Cld_m, lin_Cld_e, lin_bbCld_m, lin_bbCld_e, bbCorr_m,
451 bbCorr_e, G_m, G_e, H1_m, &H1_e);
452
453 /*adapt output gains*/
454 H1_m[L] = fMult(H1_m[L], hEnhancedTimeDmx->gain_weight_m[L]);
455 H1_m[R] = fMult(H1_m[R], hEnhancedTimeDmx->gain_weight_m[R]);
456 H1_e += hEnhancedTimeDmx->gain_weight_e;
457
458 gainLeft_m = hEnhancedTimeDmx->prev_gain_m[L];
459 gainRight_m = hEnhancedTimeDmx->prev_gain_m[R];
460
461 INT intermediate_gain_e =
462 +hEnhancedTimeDmx->sinusWindow_e + H1_e - hEnhancedTimeDmx->prev_gain_e;
463
464 for (smp = 0; smp < hEnhancedTimeDmx->framelength; smp++) {
465 const INT N = hEnhancedTimeDmx->framelength;
466 FIXP_DBL intermediate_gainLeft_m, intermediate_gainRight_m, tmp;
467
468 intermediate_gainLeft_m =
469 scaleValue((fMult(hEnhancedTimeDmx->sinusWindow_m[smp], H1_m[L]) +
470 fMult(hEnhancedTimeDmx->sinusWindow_m[N - smp],
471 hEnhancedTimeDmx->prev_H1_m[L])),
472 intermediate_gain_e);
473 intermediate_gainRight_m =
474 scaleValue((fMult(hEnhancedTimeDmx->sinusWindow_m[smp], H1_m[R]) +
475 fMult(hEnhancedTimeDmx->sinusWindow_m[N - smp],
476 hEnhancedTimeDmx->prev_H1_m[R])),
477 intermediate_gain_e);
478
479 gainLeft_m = intermediate_gainLeft_m +
480 fMult(FL2FXCONST_DBL(1.f - ALPHA_FLT), gainLeft_m);
481 gainRight_m = intermediate_gainRight_m +
482 fMult(FL2FXCONST_DBL(1.f - ALPHA_FLT), gainRight_m);
483
484 tmp = fMultDiv2(gainLeft_m, (FIXP_PCM)inputTime[L][smp + InputDelay]) +
485 fMultDiv2(gainRight_m, (FIXP_PCM)inputTime[R][smp + InputDelay]);
486 outputTimeDmx[smp] = (INT_PCM)SATURATE_SHIFT(
487 tmp,
488 -(hEnhancedTimeDmx->prev_gain_e + 1 - (DFRACT_BITS - SAMPLE_BITS)),
489 SAMPLE_BITS);
490 }
491
492 hEnhancedTimeDmx->prev_gain_m[L] = gainLeft_m;
493 hEnhancedTimeDmx->prev_gain_m[R] = gainRight_m;
494
495 hEnhancedTimeDmx->prev_H1_m[L] = H1_m[L];
496 hEnhancedTimeDmx->prev_H1_m[R] = H1_m[R];
497 hEnhancedTimeDmx->prev_H1_e = H1_e;
498 }
499
500 return error;
501 }
502
calculateRatio(const FIXP_DBL sqrt_linCld_m,const INT sqrt_linCld_e,const FIXP_DBL lin_Cld_m,const INT lin_Cld_e,const FIXP_DBL Icc_m,const INT Icc_e,FIXP_DBL G_m[2],INT * G_e)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 const INT Icc_e, FIXP_DBL G_m[2], INT *G_e) {
507 #define G_SCALE_FACTOR (2)
508
509 if (Icc_m >= FL2FXCONST_DBL(0.f)) {
510 G_m[0] = G_m[1] = FL2FXCONST_DBL(1.f / (float)(1 << G_SCALE_FACTOR));
511 G_e[0] = G_SCALE_FACTOR;
512 } else {
513 const FIXP_DBL max_gain_factor =
514 FL2FXCONST_DBL(2.f / (float)(1 << G_SCALE_FACTOR));
515 FIXP_DBL tmp1_m, tmp2_m, numerator_m, denominator_m, r_m, r4_m, q;
516 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 tmp1_m =
522 fixpAdd(lin_Cld_m, lin_Cld_e, FL2FXCONST_DBL(1.f / 2.f), 1, &tmp1_e);
523
524 tmp2_m = fMult(Icc_m, sqrt_linCld_m);
525 tmp2_e = 1 + Icc_e + sqrt_linCld_e;
526 numerator_m = fixpAdd(tmp1_m, tmp1_e, tmp2_m, tmp2_e, &numerator_e);
527 denominator_m = fixpAdd(tmp1_m, tmp1_e, -tmp2_m, tmp2_e, &denominator_e);
528
529 if ((numerator_m > FL2FXCONST_DBL(0.f)) &&
530 (denominator_m > FL2FXCONST_DBL(0.f))) {
531 r_m = fDivNorm(numerator_m, denominator_m, &r_e);
532 r_e += numerator_e - denominator_e;
533
534 /* r_4 = sqrt( sqrt( r ) ) */
535 r4_m = sqrtFixp(r_m, r_e, &r4_e);
536 r4_m = sqrtFixp(r4_m, r4_e, &r4_e);
537
538 r4_e -= G_SCALE_FACTOR;
539
540 /* q = min(r4_m, max_gain_factor) */
541 q = ((r4_e >= 0) && (r4_m >= (max_gain_factor >> r4_e)))
542 ? max_gain_factor
543 : scaleValue(r4_m, r4_e);
544 } else {
545 q = FL2FXCONST_DBL(0.f);
546 }
547
548 G_m[0] = max_gain_factor - q;
549 G_m[1] = q;
550
551 *G_e = G_SCALE_FACTOR;
552 }
553 }
554
calculateDmxGains(const FIXP_DBL lin_Cld_m,const INT lin_Cld_e,const FIXP_DBL lin_Cld2_m,const INT lin_Cld2_e,const FIXP_DBL Icc_m,const INT Icc_e,const FIXP_DBL G_m[2],const INT G_e,FIXP_DBL H1_m[2],INT * pH1_e)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 FIXP_DBL H1_m[2], INT *pH1_e) {
560 #define H1_SCALE_FACTOR (2)
561 const FIXP_DBL max_gain_factor =
562 FL2FXCONST_DBL(2.f / (float)(1 << H1_SCALE_FACTOR));
563
564 FIXP_DBL nrgRight_m, nrgLeft_m, crossNrg_m, inv_weight_num_m,
565 inv_weight_denom_m, inverse_weight_m, inverse_weight_limited;
566 INT nrgRight_e, nrgLeft_e, crossNrg_e, inv_weight_num_e, inv_weight_denom_e,
567 inverse_weight_e;
568
569 /* nrgRight = sqrt(1/(lin_Cld2 + 1) */
570 nrgRight_m = fixpAdd(lin_Cld2_m, lin_Cld2_e, FL2FXCONST_DBL(1.f / 2.f), 1,
571 &nrgRight_e);
572 nrgRight_m = invSqrtNorm2(nrgRight_m, nrgRight_e, &nrgRight_e);
573
574 /* nrgLeft = lin_Cld * nrgRight */
575 nrgLeft_m = fMult(lin_Cld_m, nrgRight_m);
576 nrgLeft_e = lin_Cld_e + nrgRight_e;
577
578 /* crossNrg = sqrt(nrgLeft*nrgRight) */
579 crossNrg_m = sqrtFixp(fMult(nrgLeft_m, nrgRight_m), nrgLeft_e + nrgRight_e,
580 &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 inv_weight_num_m =
587 fixpAdd(nrgRight_m, nrgRight_e, nrgLeft_m, nrgLeft_e, &inv_weight_num_e);
588
589 inv_weight_denom_m =
590 fixpAdd(fMult(fPow2(G_m[0]), nrgLeft_m), 2 * G_e + nrgLeft_e,
591 fMult(fPow2(G_m[1]), nrgRight_m), 2 * G_e + nrgRight_e,
592 &inv_weight_denom_e);
593
594 inv_weight_denom_m =
595 fixpAdd(fMult(fMult(fMult(G_m[0], G_m[1]), crossNrg_m), Icc_m),
596 1 + 2 * G_e + crossNrg_e + Icc_e, inv_weight_denom_m,
597 inv_weight_denom_e, &inv_weight_denom_e);
598
599 if (inv_weight_denom_m > FL2FXCONST_DBL(0.f)) {
600 inverse_weight_m =
601 fDivNorm(inv_weight_num_m, inv_weight_denom_m, &inverse_weight_e);
602 inverse_weight_m =
603 sqrtFixp(inverse_weight_m,
604 inverse_weight_e + inv_weight_num_e - inv_weight_denom_e,
605 &inverse_weight_e);
606 inverse_weight_e -= H1_SCALE_FACTOR;
607
608 /* inverse_weight_limited = min(max_gain_factor, inverse_weight) */
609 inverse_weight_limited =
610 ((inverse_weight_e >= 0) &&
611 (inverse_weight_m >= (max_gain_factor >> inverse_weight_e)))
612 ? max_gain_factor
613 : scaleValue(inverse_weight_m, inverse_weight_e);
614 } else {
615 inverse_weight_limited = max_gain_factor;
616 }
617
618 H1_m[0] = fMult(G_m[0], inverse_weight_limited);
619 H1_m[1] = fMult(G_m[1], inverse_weight_limited);
620
621 *pH1_e = G_e + H1_SCALE_FACTOR;
622 }
623
fdk_sacenc_close_enhancedTimeDomainDmx(HANDLE_ENHANCED_TIME_DOMAIN_DMX * phEnhancedTimeDmx)624 FDK_SACENC_ERROR fdk_sacenc_close_enhancedTimeDomainDmx(
625 HANDLE_ENHANCED_TIME_DOMAIN_DMX *phEnhancedTimeDmx) {
626 FDK_SACENC_ERROR error = SACENC_OK;
627
628 if (phEnhancedTimeDmx == NULL) {
629 error = SACENC_INVALID_HANDLE;
630 } else {
631 if (*phEnhancedTimeDmx != NULL) {
632 if ((*phEnhancedTimeDmx)->sinusWindow_m != NULL) {
633 FDK_FREE_MEMORY_1D((*phEnhancedTimeDmx)->sinusWindow_m);
634 }
635 FDK_FREE_MEMORY_1D(*phEnhancedTimeDmx);
636 }
637 }
638 return error;
639 }
640