xref: /aosp_15_r20/external/aac/libDRCdec/src/drcGainDec_preprocess.cpp (revision e54365361535b070c2db7374cec45c159c7d0e7a)
1 /* -----------------------------------------------------------------------------
2 Software License for The Fraunhofer FDK AAC Codec Library for Android
3 
4 © Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
5 Forschung e.V. All rights reserved.
6 
7  1.    INTRODUCTION
8 The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software
9 that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding
10 scheme for digital audio. This FDK AAC Codec software is intended to be used on
11 a wide variety of Android devices.
12 
13 AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient
14 general perceptual audio codecs. AAC-ELD is considered the best-performing
15 full-bandwidth communications codec by independent studies and is widely
16 deployed. AAC has been standardized by ISO and IEC as part of the MPEG
17 specifications.
18 
19 Patent licenses for necessary patent claims for the FDK AAC Codec (including
20 those of Fraunhofer) may be obtained through Via Licensing
21 (www.vialicensing.com) or through the respective patent owners individually for
22 the purpose of encoding or decoding bit streams in products that are compliant
23 with the ISO/IEC MPEG audio standards. Please note that most manufacturers of
24 Android devices already license these patent claims through Via Licensing or
25 directly from the patent owners, and therefore FDK AAC Codec software may
26 already be covered under those patent licenses when it is used for those
27 licensed purposes only.
28 
29 Commercially-licensed AAC software libraries, including floating-point versions
30 with enhanced sound quality, are also available from Fraunhofer. Users are
31 encouraged to check the Fraunhofer website for additional applications
32 information and documentation.
33 
34 2.    COPYRIGHT LICENSE
35 
36 Redistribution and use in source and binary forms, with or without modification,
37 are permitted without payment of copyright license fees provided that you
38 satisfy the following conditions:
39 
40 You must retain the complete text of this software license in redistributions of
41 the FDK AAC Codec or your modifications thereto in source code form.
42 
43 You must retain the complete text of this software license in the documentation
44 and/or other materials provided with redistributions of the FDK AAC Codec or
45 your modifications thereto in binary form. You must make available free of
46 charge copies of the complete source code of the FDK AAC Codec and your
47 modifications thereto to recipients of copies in binary form.
48 
49 The name of Fraunhofer may not be used to endorse or promote products derived
50 from this library without prior written permission.
51 
52 You may not charge copyright license fees for anyone to use, copy or distribute
53 the FDK AAC Codec software or your modifications thereto.
54 
55 Your modified versions of the FDK AAC Codec must carry prominent notices stating
56 that you changed the software and the date of any change. For modified versions
57 of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android"
58 must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK
59 AAC Codec Library for Android."
60 
61 3.    NO PATENT LICENSE
62 
63 NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without
64 limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE.
65 Fraunhofer provides no warranty of patent non-infringement with respect to this
66 software.
67 
68 You may use this FDK AAC Codec software or modifications thereto only for
69 purposes that are authorized by appropriate patent licenses.
70 
71 4.    DISCLAIMER
72 
73 This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright
74 holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
75 including but not limited to the implied warranties of merchantability and
76 fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
77 CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary,
78 or consequential damages, including but not limited to procurement of substitute
79 goods or services; loss of use, data, or profits, or business interruption,
80 however caused and on any theory of liability, whether in contract, strict
81 liability, or tort (including negligence), arising in any way out of the use of
82 this software, even if advised of the possibility of such damage.
83 
84 5.    CONTACT INFORMATION
85 
86 Fraunhofer Institute for Integrated Circuits IIS
87 Attention: Audio and Multimedia Departments - FDK AAC LL
88 Am Wolfsmantel 33
89 91058 Erlangen, Germany
90 
91 www.iis.fraunhofer.de/amm
92 [email protected]
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   if (tmp2 < (FIXP_DBL)0) {
289     return DE_NOT_OK;
290   }
291   denom = fPow(tmp2, e_tmp2, invExp, e_invExp, &e_denom);
292   *out = fDivNormSigned(tmp, denom, &e_out);
293   e_out += 7 - e_denom;
294   *out = scaleValueSaturate(*out, e_out - 7);
295   return DE_OK;
296 }
297 
_compressorIO_sigmoid(const CUSTOM_DRC_CHAR_SIGMOID * pCChar,const FIXP_DBL inLevelDb,FIXP_DBL * outGainDb)298 static DRC_ERROR _compressorIO_sigmoid(const CUSTOM_DRC_CHAR_SIGMOID* pCChar,
299                                        const FIXP_DBL inLevelDb, /* e = 7 */
300                                        FIXP_DBL* outGainDb)      /* e = 7 */
301 {
302   FIXP_DBL tmp;
303   FIXP_SGL exp = pCChar->exp;
304   DRC_ERROR err = DE_OK;
305 
306   tmp = fMultDiv2((DRC_INPUT_LOUDNESS_TARGET >> 1) - (inLevelDb >> 1),
307                   pCChar->ioRatio);
308   tmp = SATURATE_LEFT_SHIFT(tmp, 2 + 1 + 1, DFRACT_BITS);
309   if (exp < (FIXP_SGL)MAXVAL_SGL) {
310     /* x = tmp / gainDbLimit; */
311     /* *outGainDb = tmp / pow(1.0f + pow(x, exp), 1.0f/exp); */
312     err = _compressorIO_sigmoid_common(tmp, FX_SGL2FX_DBL(pCChar->gain),
313                                        FX_SGL2FX_DBL(exp), 0, outGainDb);
314     if (err) return err;
315   } else {
316     *outGainDb =
317         tmp; /* scaling of outGainDb (7) is equal to scaling of tmp (7) */
318   }
319   if (pCChar->flipSign == 1) {
320     *outGainDb = -*outGainDb;
321   }
322   return err;
323 }
324 
_compressorIO_sigmoid_inverse(const CUSTOM_DRC_CHAR_SIGMOID * pCChar,const FIXP_SGL gainDb,FIXP_DBL * inLev)325 static DRC_ERROR _compressorIO_sigmoid_inverse(
326     const CUSTOM_DRC_CHAR_SIGMOID* pCChar, const FIXP_SGL gainDb,
327     FIXP_DBL* inLev) {
328   DRC_ERROR err = DE_OK;
329   FIXP_SGL ioRatio = pCChar->ioRatio;
330   FIXP_SGL exp = pCChar->exp;
331   FIXP_DBL tmp = FX_SGL2FX_DBL(gainDb), tmp_out;
332   int e_out;
333 
334   if (pCChar->flipSign == 1) {
335     tmp = -tmp;
336   }
337   if (exp < (FIXP_SGL)MAXVAL_SGL) {
338     /* x = tmp / gainDbLimit; */
339     /* tmp = tmp / pow(1.0f - pow(x, exp), 1.0f / exp); */
340     err = _compressorIO_sigmoid_common(tmp, FX_SGL2FX_DBL(pCChar->gain),
341                                        FX_SGL2FX_DBL(exp), 1, &tmp);
342     if (err) return err;
343   }
344   if (ioRatio == (FIXP_SGL)0) {
345     return DE_NOT_OK;
346   }
347   tmp_out = fDivNormSigned(tmp, FX_SGL2FX_DBL(ioRatio), &e_out);
348   e_out += 7 - 2;
349   tmp_out = fAddNorm(DRC_INPUT_LOUDNESS_TARGET, 7, -tmp_out, e_out, &e_out);
350   *inLev = scaleValueSaturate(tmp_out, e_out - 7);
351 
352   return err;
353 }
354 
_compressorIO_nodes(const CUSTOM_DRC_CHAR_NODES * pCChar,const FIXP_DBL inLevelDb,FIXP_DBL * outGainDb)355 static DRC_ERROR _compressorIO_nodes(const CUSTOM_DRC_CHAR_NODES* pCChar,
356                                      const FIXP_DBL inLevelDb, /* e = 7 */
357                                      FIXP_DBL* outGainDb)      /* e = 7 */
358 {
359   int n;
360   FIXP_DBL w;
361   const FIXP_SGL* nodeLevel = pCChar->nodeLevel;
362   const FIXP_SGL* nodeGain = pCChar->nodeGain;
363 
364   if (inLevelDb < DRC_INPUT_LOUDNESS_TARGET) {
365     for (n = 0; n < pCChar->characteristicNodeCount; n++) {
366       if ((inLevelDb <= FX_SGL2FX_DBL(nodeLevel[n])) &&
367           (inLevelDb > FX_SGL2FX_DBL(nodeLevel[n + 1]))) {
368         w = fDivNorm(inLevelDb - FX_SGL2FX_DBL(nodeLevel[n + 1]),
369                      FX_SGL2FX_DBL(nodeLevel[n] - nodeLevel[n + 1]));
370         *outGainDb = fMult(w, nodeGain[n]) +
371                      fMult((FIXP_DBL)MAXVAL_DBL - w, nodeGain[n + 1]);
372         /* *outGainDb = (w * nodeGain[n] + (1.0-w) * nodeGain[n+1]); */
373         return DE_OK;
374       }
375     }
376   } else {
377     for (n = 0; n < pCChar->characteristicNodeCount; n++) {
378       if ((inLevelDb >= FX_SGL2FX_DBL(nodeLevel[n])) &&
379           (inLevelDb < FX_SGL2FX_DBL(nodeLevel[n + 1]))) {
380         w = fDivNorm(FX_SGL2FX_DBL(nodeLevel[n + 1]) - inLevelDb,
381                      FX_SGL2FX_DBL(nodeLevel[n + 1] - nodeLevel[n]));
382         *outGainDb = fMult(w, nodeGain[n]) +
383                      fMult((FIXP_DBL)MAXVAL_DBL - w, nodeGain[n + 1]);
384         /* *outGainDb = (w * nodeGain[n] + (1.0-w) * nodeGain[n+1]); */
385         return DE_OK;
386       }
387     }
388   }
389   *outGainDb = FX_SGL2FX_DBL(nodeGain[pCChar->characteristicNodeCount]);
390   return DE_OK;
391 }
392 
_compressorIO_nodes_inverse(const CUSTOM_DRC_CHAR_NODES * pCChar,const FIXP_SGL gainDb,FIXP_DBL * inLev)393 static DRC_ERROR _compressorIO_nodes_inverse(
394     const CUSTOM_DRC_CHAR_NODES* pCChar, const FIXP_SGL gainDb, /* e = 7 */
395     FIXP_DBL* inLev)                                            /* e = 7 */
396 {
397   int n;
398   int k;
399   FIXP_DBL w;
400   int gainIsNegative = 0;
401   const FIXP_SGL* nodeLevel = pCChar->nodeLevel;
402   const FIXP_SGL* nodeGain = pCChar->nodeGain;
403   int nodeCount = pCChar->characteristicNodeCount;
404   for (k = 0; k < nodeCount; k++) {
405     if (pCChar->nodeGain[k + 1] < (FIXP_SGL)0) {
406       gainIsNegative = 1;
407     }
408   }
409   if (gainIsNegative == 1) {
410     if (gainDb <= nodeGain[nodeCount]) {
411       *inLev = FX_SGL2FX_DBL(nodeLevel[nodeCount]);
412     } else {
413       if (gainDb >= (FIXP_SGL)0) {
414         *inLev = DRC_INPUT_LOUDNESS_TARGET;
415       } else {
416         for (n = 0; n < nodeCount; n++) {
417           if ((gainDb <= nodeGain[n]) && (gainDb > nodeGain[n + 1])) {
418             FIXP_SGL gainDelta = nodeGain[n] - nodeGain[n + 1];
419             if (gainDelta == (FIXP_SGL)0) {
420               *inLev = FX_SGL2FX_DBL(nodeLevel[n]);
421               return DE_OK;
422             }
423             w = fDivNorm(gainDb - nodeGain[n + 1], gainDelta);
424             *inLev = fMult(w, nodeLevel[n]) +
425                      fMult((FIXP_DBL)MAXVAL_DBL - w, nodeLevel[n + 1]);
426             /* *inLev = (w * nodeLevel[n] + (1.0-w) * nodeLevel[n+1]); */
427             return DE_OK;
428           }
429         }
430         *inLev = FX_SGL2FX_DBL(nodeLevel[nodeCount]);
431       }
432     }
433   } else {
434     if (gainDb >= nodeGain[nodeCount]) {
435       *inLev = FX_SGL2FX_DBL(nodeLevel[nodeCount]);
436     } else {
437       if (gainDb <= (FIXP_SGL)0) {
438         *inLev = DRC_INPUT_LOUDNESS_TARGET;
439       } else {
440         for (n = 0; n < nodeCount; n++) {
441           if ((gainDb >= nodeGain[n]) && (gainDb < nodeGain[n + 1])) {
442             FIXP_SGL gainDelta = nodeGain[n + 1] - nodeGain[n];
443             if (gainDelta == (FIXP_SGL)0) {
444               *inLev = FX_SGL2FX_DBL(nodeLevel[n]);
445               return DE_OK;
446             }
447             w = fDivNorm(nodeGain[n + 1] - gainDb, gainDelta);
448             *inLev = fMult(w, nodeLevel[n]) +
449                      fMult((FIXP_DBL)MAXVAL_DBL - w, nodeLevel[n + 1]);
450             /* *inLev = (w * nodeLevel[n] + (1.0-w) * nodeLevel[n+1]); */
451             return DE_OK;
452           }
453         }
454         *inLev = FX_SGL2FX_DBL(nodeLevel[nodeCount]);
455       }
456     }
457   }
458   return DE_OK;
459 }
460 
_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)461 static DRC_ERROR _mapGain(const CHARACTERISTIC_FORMAT pCCharFormatSource,
462                           const CUSTOM_DRC_CHAR* pCCharSource,
463                           const CHARACTERISTIC_FORMAT pCCharFormatTarget,
464                           const CUSTOM_DRC_CHAR* pCCharTarget,
465                           const FIXP_SGL gainInDb, /* e = 7 */
466                           FIXP_DBL* gainOutDb)     /* e = 7 */
467 {
468   FIXP_DBL inLevel = (FIXP_DBL)0;
469   DRC_ERROR err = DE_OK;
470 
471   switch (pCCharFormatSource) {
472     case CF_SIGMOID:
473       err = _compressorIO_sigmoid_inverse(
474           (const CUSTOM_DRC_CHAR_SIGMOID*)pCCharSource, gainInDb, &inLevel);
475       if (err) return err;
476       break;
477     case CF_NODES:
478       err = _compressorIO_nodes_inverse(
479           (const CUSTOM_DRC_CHAR_NODES*)pCCharSource, gainInDb, &inLevel);
480       if (err) return err;
481       break;
482     default:
483       return DE_NOT_OK;
484   }
485   switch (pCCharFormatTarget) {
486     case CF_SIGMOID:
487       err = _compressorIO_sigmoid((const CUSTOM_DRC_CHAR_SIGMOID*)pCCharTarget,
488                                   inLevel, gainOutDb);
489       if (err) return err;
490       break;
491     case CF_NODES:
492       err = _compressorIO_nodes((const CUSTOM_DRC_CHAR_NODES*)pCCharTarget,
493                                 inLevel, gainOutDb);
494       if (err) return err;
495       break;
496     default:
497       break;
498   }
499   return DE_OK;
500 }
501 
_toLinear(const NODE_MODIFICATION * nodeMod,const int drcBand,const FIXP_SGL gainDb,const FIXP_SGL slopeDb,FIXP_DBL * gainLin,FIXP_DBL * slopeLin)502 static DRC_ERROR _toLinear(
503     const NODE_MODIFICATION* nodeMod, const int drcBand,
504     const FIXP_SGL gainDb,  /* in: gain value in dB, e = 7 */
505     const FIXP_SGL slopeDb, /* in: slope value in dB/deltaTmin, e = 2 */
506     FIXP_DBL* gainLin,      /* out: linear gain value, e = 7 */
507     FIXP_DBL* slopeLin)     /* out: linear slope value, e = 7 */
508 {
509   FIXP_DBL gainRatio_m = FL2FXCONST_DBL(1.0f / (float)(1 << 1));
510   GAIN_MODIFICATION* pGMod = NULL;
511   DUCKING_MODIFICATION* pDMod = nodeMod->pDMod;
512   FIXP_DBL tmp_dbl, gainDb_modified, gainDb_offset, gainDb_out, gainLin_m,
513       slopeLin_m;
514   int gainLin_e, gainRatio_e = 1, gainDb_out_e;
515   if (nodeMod->pGMod != NULL) {
516     pGMod = &(nodeMod->pGMod[drcBand]);
517   }
518   if (((nodeMod->drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) == 0) &&
519       (nodeMod->drcSetEffect != EB_FADE) &&
520       (nodeMod->drcSetEffect != EB_CLIPPING)) {
521     DRC_ERROR err = DE_OK;
522     FIXP_DBL gainDbMapped;
523 
524     if ((pGMod != NULL) && (nodeMod->drcCharacteristicPresent)) {
525       if (((gainDb > (FIXP_SGL)0) && nodeMod->slopeIsNegative) ||
526           ((gainDb < (FIXP_SGL)0) && !nodeMod->slopeIsNegative)) {
527         /* left side */
528         if (pGMod->targetCharacteristicLeftPresent == 1) {
529           err = _mapGain(nodeMod->characteristicFormatSource[CS_LEFT],
530                          nodeMod->pCCharSource[CS_LEFT],
531                          nodeMod->characteristicFormatTarget[CS_LEFT],
532                          nodeMod->pCCharTarget[CS_LEFT], gainDb, &gainDbMapped);
533           if (err) return err;
534           gainRatio_m = fDivNormSigned(
535               gainDbMapped, FX_SGL2FX_DBL(gainDb),
536               &gainRatio_e); /* target characteristic in payload */
537         }
538       }
539 
540       else { /* if (((gainDb < (FIXP_SGL)0) && nodeMod->slopeIsNegative) ||
541                 ((gainDb > (FIXP_SGL)0) && !nodeMod->slopeIsNegative)) */
542 
543         /* right side */
544         if (pGMod->targetCharacteristicRightPresent == 1) {
545           err =
546               _mapGain(nodeMod->characteristicFormatSource[CS_RIGHT],
547                        nodeMod->pCCharSource[CS_RIGHT],
548                        nodeMod->characteristicFormatTarget[CS_RIGHT],
549                        nodeMod->pCCharTarget[CS_RIGHT], gainDb, &gainDbMapped);
550           if (err) return err;
551           gainRatio_m = fDivNormSigned(
552               gainDbMapped, FX_SGL2FX_DBL(gainDb),
553               &gainRatio_e); /* target characteristic in payload */
554         }
555       }
556     }
557     if (gainDb < (FIXP_SGL)0) {
558       gainRatio_m = fMultDiv2(gainRatio_m, nodeMod->compress);
559     } else {
560       gainRatio_m = fMultDiv2(gainRatio_m, nodeMod->boost);
561     }
562     gainRatio_e += 2;
563   }
564   if ((pGMod != NULL) && (pGMod->gainScalingPresent == 1)) {
565     if (gainDb < (FIXP_SGL)0) {
566       gainRatio_m = fMultDiv2(gainRatio_m, pGMod->attenuationScaling);
567     } else {
568       gainRatio_m = fMultDiv2(gainRatio_m, pGMod->amplificationScaling);
569     }
570     gainRatio_e += 3;
571   }
572   if ((pDMod != NULL) &&
573       (nodeMod->drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) &&
574       (pDMod->duckingScalingPresent == 1)) {
575     gainRatio_m = fMultDiv2(gainRatio_m, pDMod->duckingScaling);
576     gainRatio_e += 3;
577   }
578 
579   gainDb_modified =
580       fMultDiv2(gainDb, gainRatio_m); /* resulting e: 7 + gainRatio_e + 1*/
581   gainDb_offset = (FIXP_DBL)0;
582 
583   if ((pGMod != NULL) && (pGMod->gainOffsetPresent == 1)) {
584     /* *gainLin *= (float)pow(2.0, (double)(pGMod->gainOffset/6.0f)); */
585     gainDb_offset += FX_SGL2FX_DBL(pGMod->gainOffset) >> 4; /* resulting e: 8 */
586   }
587   if ((nodeMod->limiterPeakTargetPresent == 1) &&
588       (nodeMod->drcSetEffect ==
589        EB_CLIPPING)) { /* The only drcSetEffect is "clipping prevention" */
590     /* loudnessNormalizationGainModificationDb is included in
591      * loudnessNormalizationGainDb */
592     /* *gainLin *= (float)pow(2.0, max(0.0, -nodeModification->limiterPeakTarget
593      * - nodeModification->loudnessNormalizationGainDb)/6.0); */
594     gainDb_offset += fMax(
595         (FIXP_DBL)0,
596         (FX_SGL2FX_DBL(-nodeMod->limiterPeakTarget) >> 3) -
597             (nodeMod->loudnessNormalizationGainDb >> 1)); /* resulting e: 8 */
598   }
599   if (gainDb_offset != (FIXP_DBL)0) {
600     gainDb_out = fAddNorm(gainDb_modified, 7 + gainRatio_e + 1, gainDb_offset,
601                           8, &gainDb_out_e);
602   } else {
603     gainDb_out = gainDb_modified;
604     gainDb_out_e = 7 + gainRatio_e + 1;
605   }
606 
607   /* *gainLin = (float)pow(2.0, (double)(gainDb_modified[1] / 6.0f)); */
608   gainLin_m = approxDb2lin(gainDb_out, gainDb_out_e, &gainLin_e);
609   *gainLin = scaleValueSaturate(gainLin_m, gainLin_e - 7);
610 
611   /* *slopeLin = SLOPE_FACTOR_DB_TO_LINEAR * gainRatio * *gainLin * slopeDb; */
612   if (slopeDb == (FIXP_SGL)0) {
613     *slopeLin = (FIXP_DBL)0;
614   } else {
615     tmp_dbl =
616         fMult(slopeDb, SLOPE_FACTOR_DB_TO_LINEAR); /* resulting e: 2 - 3 = -1 */
617     tmp_dbl = fMult(tmp_dbl, gainRatio_m); /* resulting e: -1 + gainRatio_e */
618     if (gainDb_offset !=
619         (FIXP_DBL)0) { /* recalculate gainLin from gainDb that wasn't modified
620                           by gainOffset and limiterPeakTarget */
621       gainLin_m = approxDb2lin(gainDb_modified, 7 + gainRatio_e, &gainLin_e);
622     }
623     slopeLin_m = fMult(tmp_dbl, gainLin_m);
624     *slopeLin =
625         scaleValueSaturate(slopeLin_m, -1 + gainRatio_e + gainLin_e - 7);
626   }
627 
628   if ((nodeMod->limiterPeakTargetPresent == 1) &&
629       (nodeMod->drcSetEffect == EB_CLIPPING)) {
630     if (*gainLin >= FL2FXCONST_DBL(1.0f / (float)(1 << 7))) {
631       *gainLin = FL2FXCONST_DBL(1.0f / (float)(1 << 7));
632       *slopeLin = (FIXP_DBL)0;
633     }
634   }
635 
636   return DE_OK;
637 }
638 
639 /* prepare buffers containing linear nodes for each gain sequence */
640 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)641 prepareDrcGain(HANDLE_DRC_GAIN_DECODER hGainDec,
642                HANDLE_UNI_DRC_GAIN hUniDrcGain, const FIXP_SGL compress,
643                const FIXP_SGL boost, const FIXP_DBL loudnessNormalizationGainDb,
644                const int activeDrcIndex) {
645   int b, g, gainElementIndex;
646   DRC_GAIN_BUFFERS* drcGainBuffers = &(hGainDec->drcGainBuffers);
647   NODE_MODIFICATION nodeMod;
648   FDKmemclear(&nodeMod, sizeof(NODE_MODIFICATION));
649   ACTIVE_DRC* pActiveDrc = &(hGainDec->activeDrc[activeDrcIndex]);
650   DRC_INSTRUCTIONS_UNI_DRC* pInst = pActiveDrc->pInst;
651   if (pInst == NULL) return DE_NOT_OK;
652 
653   nodeMod.drcSetEffect = pInst->drcSetEffect;
654 
655   nodeMod.compress = compress;
656   nodeMod.boost = boost;
657   nodeMod.loudnessNormalizationGainDb = loudnessNormalizationGainDb;
658   nodeMod.limiterPeakTargetPresent = pInst->limiterPeakTargetPresent;
659   nodeMod.limiterPeakTarget = pInst->limiterPeakTarget;
660 
661   gainElementIndex = 0;
662   for (g = 0; g < pInst->nDrcChannelGroups; g++) {
663     int gainSetIndex = 0;
664     int nDrcBands = 0;
665     DRC_COEFFICIENTS_UNI_DRC* pCoef = pActiveDrc->pCoef;
666     if (pCoef == NULL) return DE_NOT_OK;
667 
668     if (!pActiveDrc->channelGroupIsParametricDrc[g]) {
669       gainSetIndex = pInst->gainSetIndexForChannelGroup[g];
670 
671       if (nodeMod.drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) {
672         nodeMod.pDMod = &(pActiveDrc->duckingModificationForChannelGroup[g]);
673         nodeMod.pGMod = NULL;
674       } else {
675         nodeMod.pGMod = pInst->gainModificationForChannelGroup[g];
676         nodeMod.pDMod = NULL;
677       }
678 
679       nDrcBands = pActiveDrc->bandCountForChannelGroup[g];
680       for (b = 0; b < nDrcBands; b++) {
681         DRC_ERROR err = DE_OK;
682         GAIN_SET* pGainSet = &(pCoef->gainSet[gainSetIndex]);
683         int seq = pGainSet->gainSequenceIndex[b];
684         DRC_CHARACTERISTIC* pDChar = &(pGainSet->drcCharacteristic[b]);
685 
686         /* linearNodeBuffer contains a copy of the gain sequences (consisting of
687            nodes) that are relevant for decoding. It also contains gain
688            sequences of previous frames. */
689         LINEAR_NODE_BUFFER* pLnb =
690             &(drcGainBuffers->linearNodeBuffer[pActiveDrc->activeDrcOffset +
691                                                gainElementIndex]);
692         int i, lnbp;
693         lnbp = drcGainBuffers->lnbPointer;
694         pLnb->gainInterpolationType =
695             (GAIN_INTERPOLATION_TYPE)pGainSet->gainInterpolationType;
696 
697         err = _prepareDrcCharacteristic(pDChar, pCoef, b, &nodeMod);
698         if (err) return err;
699 
700         /* copy a node buffer and convert from dB to linear */
701         pLnb->nNodes[lnbp] = fMin((int)hUniDrcGain->nNodes[seq], 16);
702         for (i = 0; i < pLnb->nNodes[lnbp]; i++) {
703           FIXP_DBL gainLin, slopeLin;
704           err = _toLinear(&nodeMod, b, hUniDrcGain->gainNode[seq][i].gainDb,
705                           (FIXP_SGL)0, &gainLin, &slopeLin);
706           if (err) return err;
707           pLnb->linearNode[lnbp][i].gainLin = gainLin;
708           pLnb->linearNode[lnbp][i].time = hUniDrcGain->gainNode[seq][i].time;
709         }
710         gainElementIndex++;
711       }
712     } else {
713       /* parametric DRC not supported */
714       gainElementIndex++;
715     }
716   }
717   return DE_OK;
718 }
719