Home | History | Annotate | Download | only in src
      1 /* -----------------------------------------------------------------------------
      2 Software License for The Fraunhofer FDK AAC Codec Library for Android
      3 
      4  Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Frderung 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 (at) 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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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
    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