• 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-D DRC decoder library **************************
96 
97    Author(s):
98 
99    Description:
100 
101 *******************************************************************************/
102 
103 #include "drcDec_types.h"
104 #include "drcDec_gainDecoder.h"
105 #include "drcGainDec_preprocess.h"
106 #include "drcDec_tools.h"
107 #include "FDK_matrixCalloc.h"
108 #include "drcDec_rom.h"
109 
110 #define SLOPE_FACTOR_DB_TO_LINEAR \
111   FL2FXCONST_DBL(0.1151f * (float)(1 << 3)) /* ln(10) / 20 */
112 
113 typedef struct {
114   int drcSetEffect;
115   DUCKING_MODIFICATION* pDMod;
116   GAIN_MODIFICATION* pGMod;
117   int drcCharacteristicPresent;
118   CHARACTERISTIC_FORMAT characteristicFormatSource[2];
119   const CUSTOM_DRC_CHAR* pCCharSource[2];
120   CHARACTERISTIC_FORMAT characteristicFormatTarget[2];
121   const CUSTOM_DRC_CHAR* pCCharTarget[2];
122   int slopeIsNegative;
123   int limiterPeakTargetPresent;
124   FIXP_SGL limiterPeakTarget;
125   FIXP_DBL loudnessNormalizationGainDb;
126   FIXP_SGL compress;
127   FIXP_SGL boost;
128 } NODE_MODIFICATION;
129 
_getCicpCharacteristic(const int cicpCharacteristic,CHARACTERISTIC_FORMAT pCharacteristicFormat[2],const CUSTOM_DRC_CHAR * pCCharSource[2])130 static DRC_ERROR _getCicpCharacteristic(
131     const int cicpCharacteristic,
132     CHARACTERISTIC_FORMAT pCharacteristicFormat[2],
133     const CUSTOM_DRC_CHAR* pCCharSource[2]) {
134   if ((cicpCharacteristic < 1) || (cicpCharacteristic > 11)) {
135     return DE_NOT_OK;
136   }
137 
138   if (cicpCharacteristic < 7) { /* sigmoid characteristic */
139     pCharacteristicFormat[CS_LEFT] = CF_SIGMOID;
140     pCCharSource[CS_LEFT] =
141         (const CUSTOM_DRC_CHAR*)(&cicpDrcCharSigmoidLeft[cicpCharacteristic -
142                                                          1]);
143     pCharacteristicFormat[CS_RIGHT] = CF_SIGMOID;
144     pCCharSource[CS_RIGHT] =
145         (const CUSTOM_DRC_CHAR*)(&cicpDrcCharSigmoidRight[cicpCharacteristic -
146                                                           1]);
147   } else { /* nodes characteristic */
148     pCharacteristicFormat[CS_LEFT] = CF_NODES;
149     pCCharSource[CS_LEFT] =
150         (const CUSTOM_DRC_CHAR*)(&cicpDrcCharNodesLeft[cicpCharacteristic - 7]);
151     pCharacteristicFormat[CS_RIGHT] = CF_NODES;
152     pCCharSource[CS_RIGHT] =
153         (const CUSTOM_DRC_CHAR*)(&cicpDrcCharNodesRight[cicpCharacteristic -
154                                                         7]);
155   }
156   return DE_OK;
157 }
158 
_getSign(FIXP_SGL in)159 static int _getSign(FIXP_SGL in) {
160   if (in > (FIXP_DBL)0) return 1;
161   if (in < (FIXP_DBL)0) return -1;
162   return 0;
163 }
164 
_getSlopeSign(const CHARACTERISTIC_FORMAT drcCharFormat,const CUSTOM_DRC_CHAR * pCChar,int * pSlopeSign)165 static DRC_ERROR _getSlopeSign(const CHARACTERISTIC_FORMAT drcCharFormat,
166                                const CUSTOM_DRC_CHAR* pCChar, int* pSlopeSign) {
167   if (drcCharFormat == CF_SIGMOID) {
168     *pSlopeSign = (pCChar->sigmoid.flipSign ? 1 : -1);
169   } else {
170     int k, slopeSign = 0, tmp_slopeSign;
171     for (k = 0; k < pCChar->nodes.characteristicNodeCount; k++) {
172       if (pCChar->nodes.nodeLevel[k + 1] > pCChar->nodes.nodeLevel[k]) {
173         tmp_slopeSign =
174             _getSign(pCChar->nodes.nodeGain[k + 1] - pCChar->nodes.nodeGain[k]);
175       } else {
176         tmp_slopeSign = -_getSign(pCChar->nodes.nodeGain[k + 1] -
177                                   pCChar->nodes.nodeGain[k]);
178       }
179       if ((slopeSign || tmp_slopeSign) && (slopeSign == -tmp_slopeSign))
180         return DE_NOT_OK; /* DRC characteristic is not invertible */
181       else
182         slopeSign = tmp_slopeSign;
183     }
184     *pSlopeSign = slopeSign;
185   }
186   return DE_OK;
187 }
188 
_isSlopeNegative(const CHARACTERISTIC_FORMAT drcCharFormat[2],const CUSTOM_DRC_CHAR * pCChar[2],int * pSlopeIsNegative)189 static DRC_ERROR _isSlopeNegative(const CHARACTERISTIC_FORMAT drcCharFormat[2],
190                                   const CUSTOM_DRC_CHAR* pCChar[2],
191                                   int* pSlopeIsNegative) {
192   DRC_ERROR err = DE_OK;
193   int slopeSign[2] = {0, 0};
194 
195   err = _getSlopeSign(drcCharFormat[CS_LEFT], pCChar[CS_LEFT],
196                       &slopeSign[CS_LEFT]);
197   if (err) return err;
198 
199   err = _getSlopeSign(drcCharFormat[CS_RIGHT], pCChar[CS_RIGHT],
200                       &slopeSign[CS_RIGHT]);
201   if (err) return err;
202 
203   if ((slopeSign[CS_LEFT] || slopeSign[CS_RIGHT]) &&
204       (slopeSign[CS_LEFT] == -slopeSign[CS_RIGHT]))
205     return DE_NOT_OK; /* DRC characteristic is not invertible */
206 
207   *pSlopeIsNegative = (slopeSign[CS_LEFT] < 0);
208   return DE_OK;
209 }
210 
_prepareDrcCharacteristic(const DRC_CHARACTERISTIC * pDChar,DRC_COEFFICIENTS_UNI_DRC * pCoef,const int b,NODE_MODIFICATION * pNodeMod)211 static DRC_ERROR _prepareDrcCharacteristic(const DRC_CHARACTERISTIC* pDChar,
212                                            DRC_COEFFICIENTS_UNI_DRC* pCoef,
213                                            const int b,
214                                            NODE_MODIFICATION* pNodeMod) {
215   DRC_ERROR err = DE_OK;
216   pNodeMod->drcCharacteristicPresent = pDChar->present;
217   if (pNodeMod->drcCharacteristicPresent) {
218     if (pDChar->isCICP == 1) {
219       err = _getCicpCharacteristic(pDChar->cicpIndex,
220                                    pNodeMod->characteristicFormatSource,
221                                    pNodeMod->pCCharSource);
222       if (err) return err;
223     } else {
224       pNodeMod->characteristicFormatSource[CS_LEFT] =
225           (CHARACTERISTIC_FORMAT)
226               pCoef->characteristicLeftFormat[pDChar->custom.left];
227       pNodeMod->pCCharSource[CS_LEFT] =
228           &(pCoef->customCharacteristicLeft[pDChar->custom.left]);
229       pNodeMod->characteristicFormatSource[CS_RIGHT] =
230           (CHARACTERISTIC_FORMAT)
231               pCoef->characteristicRightFormat[pDChar->custom.right];
232       pNodeMod->pCCharSource[CS_RIGHT] =
233           &(pCoef->customCharacteristicRight[pDChar->custom.right]);
234     }
235     err = _isSlopeNegative(pNodeMod->characteristicFormatSource,
236                            pNodeMod->pCCharSource, &pNodeMod->slopeIsNegative);
237     if (err) return err;
238 
239     if (pNodeMod->pGMod != NULL) {
240       if (pNodeMod->pGMod[b].targetCharacteristicLeftPresent) {
241         pNodeMod->characteristicFormatTarget[CS_LEFT] =
242             (CHARACTERISTIC_FORMAT)pCoef->characteristicLeftFormat
243                 [pNodeMod->pGMod[b].targetCharacteristicLeftIndex];
244         pNodeMod->pCCharTarget[CS_LEFT] =
245             &(pCoef->customCharacteristicLeft
246                   [pNodeMod->pGMod[b].targetCharacteristicLeftIndex]);
247       }
248       if (pNodeMod->pGMod[b].targetCharacteristicRightPresent) {
249         pNodeMod->characteristicFormatTarget[CS_RIGHT] =
250             (CHARACTERISTIC_FORMAT)pCoef->characteristicRightFormat
251                 [pNodeMod->pGMod[b].targetCharacteristicRightIndex];
252         pNodeMod->pCCharTarget[CS_RIGHT] =
253             &(pCoef->customCharacteristicRight
254                   [pNodeMod->pGMod[b].targetCharacteristicRightIndex]);
255       }
256     }
257   }
258   return DE_OK;
259 }
260 
_compressorIO_sigmoid_common(const FIXP_DBL tmp,const FIXP_DBL gainDbLimit,const FIXP_DBL exp,const int inverse,FIXP_DBL * out)261 static DRC_ERROR _compressorIO_sigmoid_common(
262     const FIXP_DBL tmp,               /* e = 7 */
263     const FIXP_DBL gainDbLimit,       /* e = 6 */
264     const FIXP_DBL exp,               /* e = 5 */
265     const int inverse, FIXP_DBL* out) /* e = 7 */
266 {
267   FIXP_DBL x, tmp1, tmp2, invExp, denom;
268   int e_x, e_tmp1, e_tmp2, e_invExp, e_denom, e_out;
269 
270   if (exp < FL2FXCONST_DBL(1.0f / (float)(1 << 5))) {
271     return DE_NOT_OK;
272   }
273 
274   /* x = tmp / gainDbLimit; */
275   x = fDivNormSigned(tmp, gainDbLimit, &e_x);
276   e_x += 7 - 6;
277   if (x < (FIXP_DBL)0) {
278     return DE_NOT_OK;
279   }
280 
281   /* out = tmp / pow(1.0f +/- pow(x, exp), 1.0f/exp); */
282   tmp1 = fPow(x, e_x, exp, 5, &e_tmp1);
283   if (inverse) tmp1 = -tmp1;
284   tmp2 = fAddNorm(FL2FXCONST_DBL(1.0f / (float)(1 << 1)), 1, tmp1, e_tmp1,
285                   &e_tmp2);
286   invExp = fDivNorm(FL2FXCONST_DBL(1.0f / (float)(1 << 1)), exp, &e_invExp);
287   e_invExp += 1 - 5;
288   denom = fPow(tmp2, e_tmp2, invExp, e_invExp, &e_denom);
289   *out = fDivNormSigned(tmp, denom, &e_out);
290   e_out += 7 - e_denom;
291   *out = scaleValueSaturate(*out, e_out - 7);
292   return DE_OK;
293 }
294 
_compressorIO_sigmoid(const CUSTOM_DRC_CHAR_SIGMOID * pCChar,const FIXP_DBL inLevelDb,FIXP_DBL * outGainDb)295 static DRC_ERROR _compressorIO_sigmoid(const CUSTOM_DRC_CHAR_SIGMOID* pCChar,
296                                        const FIXP_DBL inLevelDb, /* e = 7 */
297                                        FIXP_DBL* outGainDb)      /* e = 7 */
298 {
299   FIXP_DBL tmp;
300   FIXP_SGL exp = pCChar->exp;
301   DRC_ERROR err = DE_OK;
302 
303   tmp = fMultDiv2((DRC_INPUT_LOUDNESS_TARGET >> 1) - (inLevelDb >> 1),
304                   pCChar->ioRatio);
305   tmp = SATURATE_LEFT_SHIFT(tmp, 2 + 1 + 1, DFRACT_BITS);
306   if (exp < (FIXP_SGL)MAXVAL_SGL) {
307     /* x = tmp / gainDbLimit; */
308     /* *outGainDb = tmp / pow(1.0f + pow(x, exp), 1.0f/exp); */
309     err = _compressorIO_sigmoid_common(tmp, FX_SGL2FX_DBL(pCChar->gain),
310                                        FX_SGL2FX_DBL(exp), 0, outGainDb);
311     if (err) return err;
312   } else {
313     *outGainDb =
314         tmp; /* scaling of outGainDb (7) is equal to scaling of tmp (7) */
315   }
316   if (pCChar->flipSign == 1) {
317     *outGainDb = -*outGainDb;
318   }
319   return err;
320 }
321 
_compressorIO_sigmoid_inverse(const CUSTOM_DRC_CHAR_SIGMOID * pCChar,const FIXP_SGL gainDb,FIXP_DBL * inLev)322 static DRC_ERROR _compressorIO_sigmoid_inverse(
323     const CUSTOM_DRC_CHAR_SIGMOID* pCChar, const FIXP_SGL gainDb,
324     FIXP_DBL* inLev) {
325   DRC_ERROR err = DE_OK;
326   FIXP_SGL ioRatio = pCChar->ioRatio;
327   FIXP_SGL exp = pCChar->exp;
328   FIXP_DBL tmp = FX_SGL2FX_DBL(gainDb), tmp_out;
329   int e_out;
330 
331   if (pCChar->flipSign == 1) {
332     tmp = -tmp;
333   }
334   if (exp < (FIXP_SGL)MAXVAL_SGL) {
335     /* x = tmp / gainDbLimit; */
336     /* tmp = tmp / pow(1.0f - pow(x, exp), 1.0f / exp); */
337     err = _compressorIO_sigmoid_common(tmp, FX_SGL2FX_DBL(pCChar->gain),
338                                        FX_SGL2FX_DBL(exp), 1, &tmp);
339     if (err) return err;
340   }
341   if (ioRatio == (FIXP_SGL)0) {
342     return DE_NOT_OK;
343   }
344   tmp_out = fDivNormSigned(tmp, FX_SGL2FX_DBL(ioRatio), &e_out);
345   e_out += 7 - 2;
346   tmp_out = fAddNorm(DRC_INPUT_LOUDNESS_TARGET, 7, -tmp_out, e_out, &e_out);
347   *inLev = scaleValueSaturate(tmp_out, e_out - 7);
348 
349   return err;
350 }
351 
_compressorIO_nodes(const CUSTOM_DRC_CHAR_NODES * pCChar,const FIXP_DBL inLevelDb,FIXP_DBL * outGainDb)352 static DRC_ERROR _compressorIO_nodes(const CUSTOM_DRC_CHAR_NODES* pCChar,
353                                      const FIXP_DBL inLevelDb, /* e = 7 */
354                                      FIXP_DBL* outGainDb)      /* e = 7 */
355 {
356   int n;
357   FIXP_DBL w;
358   const FIXP_SGL* nodeLevel = pCChar->nodeLevel;
359   const FIXP_SGL* nodeGain = pCChar->nodeGain;
360 
361   if (inLevelDb < DRC_INPUT_LOUDNESS_TARGET) {
362     for (n = 0; n < pCChar->characteristicNodeCount; n++) {
363       if ((inLevelDb <= FX_SGL2FX_DBL(nodeLevel[n])) &&
364           (inLevelDb > FX_SGL2FX_DBL(nodeLevel[n + 1]))) {
365         w = fDivNorm(inLevelDb - FX_SGL2FX_DBL(nodeLevel[n + 1]),
366                      FX_SGL2FX_DBL(nodeLevel[n] - nodeLevel[n + 1]));
367         *outGainDb = fMult(w, nodeGain[n]) +
368                      fMult((FIXP_DBL)MAXVAL_DBL - w, nodeGain[n + 1]);
369         /* *outGainDb = (w * nodeGain[n] + (1.0-w) * nodeGain[n+1]); */
370         return DE_OK;
371       }
372     }
373   } else {
374     for (n = 0; n < pCChar->characteristicNodeCount; n++) {
375       if ((inLevelDb >= FX_SGL2FX_DBL(nodeLevel[n])) &&
376           (inLevelDb < FX_SGL2FX_DBL(nodeLevel[n + 1]))) {
377         w = fDivNorm(FX_SGL2FX_DBL(nodeLevel[n + 1]) - inLevelDb,
378                      FX_SGL2FX_DBL(nodeLevel[n + 1] - nodeLevel[n]));
379         *outGainDb = fMult(w, nodeGain[n]) +
380                      fMult((FIXP_DBL)MAXVAL_DBL - w, nodeGain[n + 1]);
381         /* *outGainDb = (w * nodeGain[n] + (1.0-w) * nodeGain[n+1]); */
382         return DE_OK;
383       }
384     }
385   }
386   *outGainDb = FX_SGL2FX_DBL(nodeGain[pCChar->characteristicNodeCount]);
387   return DE_OK;
388 }
389 
_compressorIO_nodes_inverse(const CUSTOM_DRC_CHAR_NODES * pCChar,const FIXP_SGL gainDb,FIXP_DBL * inLev)390 static DRC_ERROR _compressorIO_nodes_inverse(
391     const CUSTOM_DRC_CHAR_NODES* pCChar, const FIXP_SGL gainDb, /* e = 7 */
392     FIXP_DBL* inLev)                                            /* e = 7 */
393 {
394   int n;
395   int k;
396   FIXP_DBL w;
397   int gainIsNegative = 0;
398   const FIXP_SGL* nodeLevel = pCChar->nodeLevel;
399   const FIXP_SGL* nodeGain = pCChar->nodeGain;
400   int nodeCount = pCChar->characteristicNodeCount;
401   for (k = 0; k < nodeCount; k++) {
402     if (pCChar->nodeGain[k + 1] < (FIXP_SGL)0) {
403       gainIsNegative = 1;
404     }
405   }
406   if (gainIsNegative == 1) {
407     if (gainDb <= nodeGain[nodeCount]) {
408       *inLev = FX_SGL2FX_DBL(nodeLevel[nodeCount]);
409     } else {
410       if (gainDb >= (FIXP_SGL)0) {
411         *inLev = DRC_INPUT_LOUDNESS_TARGET;
412       } else {
413         for (n = 0; n < nodeCount; n++) {
414           if ((gainDb <= nodeGain[n]) && (gainDb > nodeGain[n + 1])) {
415             FIXP_SGL gainDelta = nodeGain[n] - nodeGain[n + 1];
416             if (gainDelta == (FIXP_SGL)0) {
417               *inLev = FX_SGL2FX_DBL(nodeLevel[n]);
418               return DE_OK;
419             }
420             w = fDivNorm(gainDb - nodeGain[n + 1], gainDelta);
421             *inLev = fMult(w, nodeLevel[n]) +
422                      fMult((FIXP_DBL)MAXVAL_DBL - w, nodeLevel[n + 1]);
423             /* *inLev = (w * nodeLevel[n] + (1.0-w) * nodeLevel[n+1]); */
424             return DE_OK;
425           }
426         }
427         *inLev = FX_SGL2FX_DBL(nodeLevel[nodeCount]);
428       }
429     }
430   } else {
431     if (gainDb >= nodeGain[nodeCount]) {
432       *inLev = FX_SGL2FX_DBL(nodeLevel[nodeCount]);
433     } else {
434       if (gainDb <= (FIXP_SGL)0) {
435         *inLev = DRC_INPUT_LOUDNESS_TARGET;
436       } else {
437         for (n = 0; n < nodeCount; n++) {
438           if ((gainDb >= nodeGain[n]) && (gainDb < nodeGain[n + 1])) {
439             FIXP_SGL gainDelta = nodeGain[n + 1] - nodeGain[n];
440             if (gainDelta == (FIXP_SGL)0) {
441               *inLev = FX_SGL2FX_DBL(nodeLevel[n]);
442               return DE_OK;
443             }
444             w = fDivNorm(nodeGain[n + 1] - gainDb, gainDelta);
445             *inLev = fMult(w, nodeLevel[n]) +
446                      fMult((FIXP_DBL)MAXVAL_DBL - w, nodeLevel[n + 1]);
447             /* *inLev = (w * nodeLevel[n] + (1.0-w) * nodeLevel[n+1]); */
448             return DE_OK;
449           }
450         }
451         *inLev = FX_SGL2FX_DBL(nodeLevel[nodeCount]);
452       }
453     }
454   }
455   return DE_OK;
456 }
457 
_mapGain(const CHARACTERISTIC_FORMAT pCCharFormatSource,const CUSTOM_DRC_CHAR * pCCharSource,const CHARACTERISTIC_FORMAT pCCharFormatTarget,const CUSTOM_DRC_CHAR * pCCharTarget,const FIXP_SGL gainInDb,FIXP_DBL * gainOutDb)458 static DRC_ERROR _mapGain(const CHARACTERISTIC_FORMAT pCCharFormatSource,
459                           const CUSTOM_DRC_CHAR* pCCharSource,
460                           const CHARACTERISTIC_FORMAT pCCharFormatTarget,
461                           const CUSTOM_DRC_CHAR* pCCharTarget,
462                           const FIXP_SGL gainInDb, /* e = 7 */
463                           FIXP_DBL* gainOutDb)     /* e = 7 */
464 {
465   FIXP_DBL inLevel = (FIXP_DBL)0;
466   DRC_ERROR err = DE_OK;
467 
468   switch (pCCharFormatSource) {
469     case CF_SIGMOID:
470       err = _compressorIO_sigmoid_inverse(
471           (const CUSTOM_DRC_CHAR_SIGMOID*)pCCharSource, gainInDb, &inLevel);
472       if (err) return err;
473       break;
474     case CF_NODES:
475       err = _compressorIO_nodes_inverse(
476           (const CUSTOM_DRC_CHAR_NODES*)pCCharSource, gainInDb, &inLevel);
477       if (err) return err;
478       break;
479     default:
480       return DE_NOT_OK;
481   }
482   switch (pCCharFormatTarget) {
483     case CF_SIGMOID:
484       err = _compressorIO_sigmoid((const CUSTOM_DRC_CHAR_SIGMOID*)pCCharTarget,
485                                   inLevel, gainOutDb);
486       if (err) return err;
487       break;
488     case CF_NODES:
489       err = _compressorIO_nodes((const CUSTOM_DRC_CHAR_NODES*)pCCharTarget,
490                                 inLevel, gainOutDb);
491       if (err) return err;
492       break;
493     default:
494       break;
495   }
496   return DE_OK;
497 }
498 
_toLinear(const NODE_MODIFICATION * nodeMod,const int drcBand,const FIXP_SGL gainDb,const FIXP_SGL slopeDb,FIXP_DBL * gainLin,FIXP_DBL * slopeLin)499 static DRC_ERROR _toLinear(
500     const NODE_MODIFICATION* nodeMod, const int drcBand,
501     const FIXP_SGL gainDb,  /* in: gain value in dB, e = 7 */
502     const FIXP_SGL slopeDb, /* in: slope value in dB/deltaTmin, e = 2 */
503     FIXP_DBL* gainLin,      /* out: linear gain value, e = 7 */
504     FIXP_DBL* slopeLin)     /* out: linear slope value, e = 7 */
505 {
506   FIXP_DBL gainRatio_m = FL2FXCONST_DBL(1.0f / (float)(1 << 1));
507   GAIN_MODIFICATION* pGMod = NULL;
508   DUCKING_MODIFICATION* pDMod = nodeMod->pDMod;
509   FIXP_DBL tmp_dbl, gainDb_modified, gainDb_offset, gainDb_out, gainLin_m,
510       slopeLin_m;
511   int gainLin_e, gainRatio_e = 1, gainDb_out_e;
512   if (nodeMod->pGMod != NULL) {
513     pGMod = &(nodeMod->pGMod[drcBand]);
514   }
515   if (((nodeMod->drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) == 0) &&
516       (nodeMod->drcSetEffect != EB_FADE) &&
517       (nodeMod->drcSetEffect != EB_CLIPPING)) {
518     DRC_ERROR err = DE_OK;
519     FIXP_DBL gainDbMapped;
520 
521     if ((pGMod != NULL) && (nodeMod->drcCharacteristicPresent)) {
522       if (((gainDb > (FIXP_SGL)0) && nodeMod->slopeIsNegative) ||
523           ((gainDb < (FIXP_SGL)0) && !nodeMod->slopeIsNegative)) {
524         /* left side */
525         if (pGMod->targetCharacteristicLeftPresent == 1) {
526           err = _mapGain(nodeMod->characteristicFormatSource[CS_LEFT],
527                          nodeMod->pCCharSource[CS_LEFT],
528                          nodeMod->characteristicFormatTarget[CS_LEFT],
529                          nodeMod->pCCharTarget[CS_LEFT], gainDb, &gainDbMapped);
530           if (err) return err;
531           gainRatio_m = fDivNormSigned(
532               gainDbMapped, FX_SGL2FX_DBL(gainDb),
533               &gainRatio_e); /* target characteristic in payload */
534         }
535       }
536 
537       else { /* if (((gainDb < (FIXP_SGL)0) && nodeMod->slopeIsNegative) ||
538                 ((gainDb > (FIXP_SGL)0) && !nodeMod->slopeIsNegative)) */
539 
540         /* right side */
541         if (pGMod->targetCharacteristicRightPresent == 1) {
542           err =
543               _mapGain(nodeMod->characteristicFormatSource[CS_RIGHT],
544                        nodeMod->pCCharSource[CS_RIGHT],
545                        nodeMod->characteristicFormatTarget[CS_RIGHT],
546                        nodeMod->pCCharTarget[CS_RIGHT], gainDb, &gainDbMapped);
547           if (err) return err;
548           gainRatio_m = fDivNormSigned(
549               gainDbMapped, FX_SGL2FX_DBL(gainDb),
550               &gainRatio_e); /* target characteristic in payload */
551         }
552       }
553     }
554     if (gainDb < (FIXP_SGL)0) {
555       gainRatio_m = fMultDiv2(gainRatio_m, nodeMod->compress);
556     } else {
557       gainRatio_m = fMultDiv2(gainRatio_m, nodeMod->boost);
558     }
559     gainRatio_e += 2;
560   }
561   if ((pGMod != NULL) && (pGMod->gainScalingPresent == 1)) {
562     if (gainDb < (FIXP_SGL)0) {
563       gainRatio_m = fMultDiv2(gainRatio_m, pGMod->attenuationScaling);
564     } else {
565       gainRatio_m = fMultDiv2(gainRatio_m, pGMod->amplificationScaling);
566     }
567     gainRatio_e += 3;
568   }
569   if ((pDMod != NULL) &&
570       (nodeMod->drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) &&
571       (pDMod->duckingScalingPresent == 1)) {
572     gainRatio_m = fMultDiv2(gainRatio_m, pDMod->duckingScaling);
573     gainRatio_e += 3;
574   }
575 
576   gainDb_modified =
577       fMultDiv2(gainDb, gainRatio_m); /* resulting e: 7 + gainRatio_e + 1*/
578   gainDb_offset = (FIXP_DBL)0;
579 
580   if ((pGMod != NULL) && (pGMod->gainOffsetPresent == 1)) {
581     /* *gainLin *= (float)pow(2.0, (double)(pGMod->gainOffset/6.0f)); */
582     gainDb_offset += FX_SGL2FX_DBL(pGMod->gainOffset) >> 4; /* resulting e: 8 */
583   }
584   if ((nodeMod->limiterPeakTargetPresent == 1) &&
585       (nodeMod->drcSetEffect ==
586        EB_CLIPPING)) { /* The only drcSetEffect is "clipping prevention" */
587     /* loudnessNormalizationGainModificationDb is included in
588      * loudnessNormalizationGainDb */
589     /* *gainLin *= (float)pow(2.0, max(0.0, -nodeModification->limiterPeakTarget
590      * - nodeModification->loudnessNormalizationGainDb)/6.0); */
591     gainDb_offset += fMax(
592         (FIXP_DBL)0,
593         (FX_SGL2FX_DBL(-nodeMod->limiterPeakTarget) >> 3) -
594             (nodeMod->loudnessNormalizationGainDb >> 1)); /* resulting e: 8 */
595   }
596   if (gainDb_offset != (FIXP_DBL)0) {
597     gainDb_out = fAddNorm(gainDb_modified, 7 + gainRatio_e + 1, gainDb_offset,
598                           8, &gainDb_out_e);
599   } else {
600     gainDb_out = gainDb_modified;
601     gainDb_out_e = 7 + gainRatio_e + 1;
602   }
603 
604   /* *gainLin = (float)pow(2.0, (double)(gainDb_modified[1] / 6.0f)); */
605   gainLin_m = approxDb2lin(gainDb_out, gainDb_out_e, &gainLin_e);
606   *gainLin = scaleValueSaturate(gainLin_m, gainLin_e - 7);
607 
608   /* *slopeLin = SLOPE_FACTOR_DB_TO_LINEAR * gainRatio * *gainLin * slopeDb; */
609   if (slopeDb == (FIXP_SGL)0) {
610     *slopeLin = (FIXP_DBL)0;
611   } else {
612     tmp_dbl =
613         fMult(slopeDb, SLOPE_FACTOR_DB_TO_LINEAR); /* resulting e: 2 - 3 = -1 */
614     tmp_dbl = fMult(tmp_dbl, gainRatio_m); /* resulting e: -1 + gainRatio_e */
615     if (gainDb_offset !=
616         (FIXP_DBL)0) { /* recalculate gainLin from gainDb that wasn't modified
617                           by gainOffset and limiterPeakTarget */
618       gainLin_m = approxDb2lin(gainDb_modified, 7 + gainRatio_e, &gainLin_e);
619     }
620     slopeLin_m = fMult(tmp_dbl, gainLin_m);
621     *slopeLin =
622         scaleValueSaturate(slopeLin_m, -1 + gainRatio_e + gainLin_e - 7);
623   }
624 
625   if ((nodeMod->limiterPeakTargetPresent == 1) &&
626       (nodeMod->drcSetEffect == EB_CLIPPING)) {
627     if (*gainLin >= FL2FXCONST_DBL(1.0f / (float)(1 << 7))) {
628       *gainLin = FL2FXCONST_DBL(1.0f / (float)(1 << 7));
629       *slopeLin = (FIXP_DBL)0;
630     }
631   }
632 
633   return DE_OK;
634 }
635 
636 /* prepare buffers containing linear nodes for each gain sequence */
637 DRC_ERROR
prepareDrcGain(HANDLE_DRC_GAIN_DECODER hGainDec,HANDLE_UNI_DRC_GAIN hUniDrcGain,const FIXP_SGL compress,const FIXP_SGL boost,const FIXP_DBL loudnessNormalizationGainDb,const int activeDrcIndex)638 prepareDrcGain(HANDLE_DRC_GAIN_DECODER hGainDec,
639                HANDLE_UNI_DRC_GAIN hUniDrcGain, const FIXP_SGL compress,
640                const FIXP_SGL boost, const FIXP_DBL loudnessNormalizationGainDb,
641                const int activeDrcIndex) {
642   int b, g, gainElementIndex;
643   DRC_GAIN_BUFFERS* drcGainBuffers = &(hGainDec->drcGainBuffers);
644   NODE_MODIFICATION nodeMod;
645   FDKmemclear(&nodeMod, sizeof(NODE_MODIFICATION));
646   ACTIVE_DRC* pActiveDrc = &(hGainDec->activeDrc[activeDrcIndex]);
647   DRC_INSTRUCTIONS_UNI_DRC* pInst = pActiveDrc->pInst;
648   if (pInst == NULL) return DE_NOT_OK;
649 
650   nodeMod.drcSetEffect = pInst->drcSetEffect;
651 
652   nodeMod.compress = compress;
653   nodeMod.boost = boost;
654   nodeMod.loudnessNormalizationGainDb = loudnessNormalizationGainDb;
655   nodeMod.limiterPeakTargetPresent = pInst->limiterPeakTargetPresent;
656   nodeMod.limiterPeakTarget = pInst->limiterPeakTarget;
657 
658   gainElementIndex = 0;
659   for (g = 0; g < pInst->nDrcChannelGroups; g++) {
660     int gainSetIndex = 0;
661     int nDrcBands = 0;
662     DRC_COEFFICIENTS_UNI_DRC* pCoef = pActiveDrc->pCoef;
663     if (pCoef == NULL) return DE_NOT_OK;
664 
665     if (!pActiveDrc->channelGroupIsParametricDrc[g]) {
666       gainSetIndex = pInst->gainSetIndexForChannelGroup[g];
667 
668       if (nodeMod.drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) {
669         nodeMod.pDMod = &(pActiveDrc->duckingModificationForChannelGroup[g]);
670         nodeMod.pGMod = NULL;
671       } else {
672         nodeMod.pGMod = pInst->gainModificationForChannelGroup[g];
673         nodeMod.pDMod = NULL;
674       }
675 
676       nDrcBands = pActiveDrc->bandCountForChannelGroup[g];
677       for (b = 0; b < nDrcBands; b++) {
678         DRC_ERROR err = DE_OK;
679         GAIN_SET* pGainSet = &(pCoef->gainSet[gainSetIndex]);
680         int seq = pGainSet->gainSequenceIndex[b];
681         DRC_CHARACTERISTIC* pDChar = &(pGainSet->drcCharacteristic[b]);
682 
683         /* linearNodeBuffer contains a copy of the gain sequences (consisting of
684            nodes) that are relevant for decoding. It also contains gain
685            sequences of previous frames. */
686         LINEAR_NODE_BUFFER* pLnb =
687             &(drcGainBuffers->linearNodeBuffer[pActiveDrc->activeDrcOffset +
688                                                gainElementIndex]);
689         int i, lnbp;
690         lnbp = drcGainBuffers->lnbPointer;
691         pLnb->gainInterpolationType =
692             (GAIN_INTERPOLATION_TYPE)pGainSet->gainInterpolationType;
693 
694         err = _prepareDrcCharacteristic(pDChar, pCoef, b, &nodeMod);
695         if (err) return err;
696 
697         /* copy a node buffer and convert from dB to linear */
698         pLnb->nNodes[lnbp] = fMin((int)hUniDrcGain->nNodes[seq], 16);
699         for (i = 0; i < pLnb->nNodes[lnbp]; i++) {
700           FIXP_DBL gainLin, slopeLin;
701           err = _toLinear(&nodeMod, b, hUniDrcGain->gainNode[seq][i].gainDb,
702                           (FIXP_SGL)0, &gainLin, &slopeLin);
703           if (err) return err;
704           pLnb->linearNode[lnbp][i].gainLin = gainLin;
705           pLnb->linearNode[lnbp][i].time = hUniDrcGain->gainNode[seq][i].time;
706         }
707         gainElementIndex++;
708       }
709     } else {
710       /* parametric DRC not supported */
711       gainElementIndex++;
712     }
713   }
714   return DE_OK;
715 }
716