• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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