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 /**************************** SBR encoder library ******************************
     96 
     97    Author(s):   M. Multrus
     98 
     99    Description: PS Wrapper, Downmix
    100 
    101 *******************************************************************************/
    102 
    103 #include "ps_main.h"
    104 
    105 /* Includes ******************************************************************/
    106 #include "ps_bitenc.h"
    107 #include "sbrenc_ram.h"
    108 
    109 /*--------------- function declarations --------------------*/
    110 static void psFindBestScaling(
    111     HANDLE_PARAMETRIC_STEREO hParametricStereo,
    112     FIXP_DBL *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2],
    113     UCHAR *dynBandScale, FIXP_DBL *maxBandValue, SCHAR *dmxScale);
    114 
    115 /*------------- function definitions ----------------*/
    116 FDK_PSENC_ERROR PSEnc_Create(HANDLE_PARAMETRIC_STEREO *phParametricStereo) {
    117   FDK_PSENC_ERROR error = PSENC_OK;
    118   HANDLE_PARAMETRIC_STEREO hParametricStereo = NULL;
    119 
    120   if (phParametricStereo == NULL) {
    121     error = PSENC_INVALID_HANDLE;
    122   } else {
    123     int i;
    124 
    125     if (NULL == (hParametricStereo = GetRam_ParamStereo())) {
    126       error = PSENC_MEMORY_ERROR;
    127       goto bail;
    128     }
    129     FDKmemclear(hParametricStereo, sizeof(PARAMETRIC_STEREO));
    130 
    131     if (PSENC_OK !=
    132         (error = FDKsbrEnc_CreatePSEncode(&hParametricStereo->hPsEncode))) {
    133       error = PSENC_MEMORY_ERROR;
    134       goto bail;
    135     }
    136 
    137     for (i = 0; i < MAX_PS_CHANNELS; i++) {
    138       if (FDKhybridAnalysisOpen(
    139               &hParametricStereo->fdkHybAnaFilter[i],
    140               hParametricStereo->__staticHybAnaStatesLF[i],
    141               sizeof(hParametricStereo->__staticHybAnaStatesLF[i]),
    142               hParametricStereo->__staticHybAnaStatesHF[i],
    143               sizeof(hParametricStereo->__staticHybAnaStatesHF[i])) != 0) {
    144         error = PSENC_MEMORY_ERROR;
    145         goto bail;
    146       }
    147     }
    148   }
    149 
    150 bail:
    151   if (phParametricStereo != NULL) {
    152     *phParametricStereo = hParametricStereo; /* return allocated handle */
    153   }
    154 
    155   if (error != PSENC_OK) {
    156     PSEnc_Destroy(phParametricStereo);
    157   }
    158   return error;
    159 }
    160 
    161 FDK_PSENC_ERROR PSEnc_Init(HANDLE_PARAMETRIC_STEREO hParametricStereo,
    162                            const HANDLE_PSENC_CONFIG hPsEncConfig,
    163                            INT noQmfSlots, INT noQmfBands, UCHAR *dynamic_RAM) {
    164   FDK_PSENC_ERROR error = PSENC_OK;
    165 
    166   if ((NULL == hParametricStereo) || (NULL == hPsEncConfig)) {
    167     error = PSENC_INVALID_HANDLE;
    168   } else {
    169     int ch, i;
    170 
    171     hParametricStereo->initPS = 1;
    172     hParametricStereo->noQmfSlots = noQmfSlots;
    173     hParametricStereo->noQmfBands = noQmfBands;
    174 
    175     /* clear delay lines */
    176     FDKmemclear(hParametricStereo->qmfDelayLines,
    177                 sizeof(hParametricStereo->qmfDelayLines));
    178 
    179     hParametricStereo->qmfDelayScale = FRACT_BITS - 1;
    180 
    181     /* create configuration for hybrid filter bank */
    182     for (ch = 0; ch < MAX_PS_CHANNELS; ch++) {
    183       FDKhybridAnalysisInit(&hParametricStereo->fdkHybAnaFilter[ch],
    184                             THREE_TO_TEN, 64, 64, 1);
    185     } /* ch */
    186 
    187     FDKhybridSynthesisInit(&hParametricStereo->fdkHybSynFilter, THREE_TO_TEN,
    188                            64, 64);
    189 
    190     /* determine average delay */
    191     hParametricStereo->psDelay =
    192         (HYBRID_FILTER_DELAY * hParametricStereo->noQmfBands);
    193 
    194     if ((hPsEncConfig->maxEnvelopes < PSENC_NENV_1) ||
    195         (hPsEncConfig->maxEnvelopes > PSENC_NENV_MAX)) {
    196       hPsEncConfig->maxEnvelopes = PSENC_NENV_DEFAULT;
    197     }
    198     hParametricStereo->maxEnvelopes = hPsEncConfig->maxEnvelopes;
    199 
    200     if (PSENC_OK !=
    201         (error = FDKsbrEnc_InitPSEncode(
    202              hParametricStereo->hPsEncode, (PS_BANDS)hPsEncConfig->nStereoBands,
    203              hPsEncConfig->iidQuantErrorThreshold))) {
    204       goto bail;
    205     }
    206 
    207     for (ch = 0; ch < MAX_PS_CHANNELS; ch++) {
    208       FIXP_DBL *pDynReal = GetRam_Sbr_envRBuffer(ch, dynamic_RAM);
    209       FIXP_DBL *pDynImag = GetRam_Sbr_envIBuffer(ch, dynamic_RAM);
    210 
    211       for (i = 0; i < HYBRID_FRAMESIZE; i++) {
    212         hParametricStereo->pHybridData[i + HYBRID_READ_OFFSET][ch][0] =
    213             &pDynReal[i * MAX_HYBRID_BANDS];
    214         hParametricStereo->pHybridData[i + HYBRID_READ_OFFSET][ch][1] =
    215             &pDynImag[i * MAX_HYBRID_BANDS];
    216         ;
    217       }
    218 
    219       for (i = 0; i < HYBRID_READ_OFFSET; i++) {
    220         hParametricStereo->pHybridData[i][ch][0] =
    221             hParametricStereo->__staticHybridData[i][ch][0];
    222         hParametricStereo->pHybridData[i][ch][1] =
    223             hParametricStereo->__staticHybridData[i][ch][1];
    224       }
    225     } /* ch */
    226 
    227     /* clear static hybrid buffer */
    228     FDKmemclear(hParametricStereo->__staticHybridData,
    229                 sizeof(hParametricStereo->__staticHybridData));
    230 
    231     /* clear bs buffer */
    232     FDKmemclear(hParametricStereo->psOut, sizeof(hParametricStereo->psOut));
    233 
    234     hParametricStereo->psOut[0].enablePSHeader =
    235         1; /* write ps header in first frame */
    236 
    237     /* clear scaling buffer */
    238     FDKmemclear(hParametricStereo->dynBandScale, sizeof(UCHAR) * PS_MAX_BANDS);
    239     FDKmemclear(hParametricStereo->maxBandValue,
    240                 sizeof(FIXP_DBL) * PS_MAX_BANDS);
    241 
    242   } /* valid handle */
    243 bail:
    244   return error;
    245 }
    246 
    247 FDK_PSENC_ERROR PSEnc_Destroy(HANDLE_PARAMETRIC_STEREO *phParametricStereo) {
    248   FDK_PSENC_ERROR error = PSENC_OK;
    249 
    250   if (NULL != phParametricStereo) {
    251     HANDLE_PARAMETRIC_STEREO hParametricStereo = *phParametricStereo;
    252     if (hParametricStereo != NULL) {
    253       FDKsbrEnc_DestroyPSEncode(&hParametricStereo->hPsEncode);
    254       FreeRam_ParamStereo(phParametricStereo);
    255     }
    256   }
    257 
    258   return error;
    259 }
    260 
    261 static FDK_PSENC_ERROR ExtractPSParameters(
    262     HANDLE_PARAMETRIC_STEREO hParametricStereo, const int sendHeader,
    263     FIXP_DBL *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2]) {
    264   FDK_PSENC_ERROR error = PSENC_OK;
    265 
    266   if (hParametricStereo == NULL) {
    267     error = PSENC_INVALID_HANDLE;
    268   } else {
    269     /* call ps encode function */
    270     if (hParametricStereo->initPS) {
    271       hParametricStereo->psOut[1] = hParametricStereo->psOut[0];
    272     }
    273     hParametricStereo->psOut[0] = hParametricStereo->psOut[1];
    274 
    275     if (PSENC_OK !=
    276         (error = FDKsbrEnc_PSEncode(
    277              hParametricStereo->hPsEncode, &hParametricStereo->psOut[1],
    278              hParametricStereo->dynBandScale, hParametricStereo->maxEnvelopes,
    279              hybridData, hParametricStereo->noQmfSlots, sendHeader))) {
    280       goto bail;
    281     }
    282 
    283     if (hParametricStereo->initPS) {
    284       hParametricStereo->psOut[0] = hParametricStereo->psOut[1];
    285       hParametricStereo->initPS = 0;
    286     }
    287   }
    288 bail:
    289   return error;
    290 }
    291 
    292 static FDK_PSENC_ERROR DownmixPSQmfData(
    293     HANDLE_PARAMETRIC_STEREO hParametricStereo,
    294     HANDLE_QMF_FILTER_BANK sbrSynthQmf, FIXP_DBL **RESTRICT mixRealQmfData,
    295     FIXP_DBL **RESTRICT mixImagQmfData, INT_PCM *downsampledOutSignal,
    296     const UINT downsampledOutSignalBufSize,
    297     FIXP_DBL *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2],
    298     const INT noQmfSlots, const INT psQmfScale[MAX_PS_CHANNELS],
    299     SCHAR *qmfScale) {
    300   FDK_PSENC_ERROR error = PSENC_OK;
    301 
    302   if (hParametricStereo == NULL) {
    303     error = PSENC_INVALID_HANDLE;
    304   } else {
    305     int n, k;
    306     C_AALLOC_SCRATCH_START(pWorkBuffer, FIXP_DBL, 2 * 64)
    307 
    308     /* define scalings */
    309     int dynQmfScale = fixMax(
    310         0, hParametricStereo->dmxScale -
    311                1); /* scale one bit more for addition of left and right */
    312     int downmixScale = psQmfScale[0] - dynQmfScale;
    313     const FIXP_DBL maxStereoScaleFactor = MAXVAL_DBL; /* 2.f/2.f */
    314 
    315     for (n = 0; n < noQmfSlots; n++) {
    316       FIXP_DBL tmpHybrid[2][MAX_HYBRID_BANDS];
    317 
    318       for (k = 0; k < 71; k++) {
    319         int dynScale, sc; /* scaling */
    320         FIXP_DBL tmpLeftReal, tmpRightReal, tmpLeftImag, tmpRightImag;
    321         FIXP_DBL tmpScaleFactor, stereoScaleFactor;
    322 
    323         tmpLeftReal = hybridData[n][0][0][k];
    324         tmpLeftImag = hybridData[n][0][1][k];
    325         tmpRightReal = hybridData[n][1][0][k];
    326         tmpRightImag = hybridData[n][1][1][k];
    327 
    328         sc = fixMax(
    329             0, CntLeadingZeros(fixMax(
    330                    fixMax(fixp_abs(tmpLeftReal), fixp_abs(tmpLeftImag)),
    331                    fixMax(fixp_abs(tmpRightReal), fixp_abs(tmpRightImag)))) -
    332                    2);
    333 
    334         tmpLeftReal <<= sc;
    335         tmpLeftImag <<= sc;
    336         tmpRightReal <<= sc;
    337         tmpRightImag <<= sc;
    338         dynScale = fixMin(sc - dynQmfScale, DFRACT_BITS - 1);
    339 
    340         /* calc stereo scale factor to avoid loss of energy in bands */
    341         /* stereo scale factor = min(2.0f, sqrt( (abs(l(k, n)^2 + abs(r(k, n)^2
    342          * )))/(0.5f*abs(l(k, n) + r(k, n))) )) */
    343         stereoScaleFactor = fPow2Div2(tmpLeftReal) + fPow2Div2(tmpLeftImag) +
    344                             fPow2Div2(tmpRightReal) + fPow2Div2(tmpRightImag);
    345 
    346         /* might be that tmpScaleFactor becomes negative, so fabs(.) */
    347         tmpScaleFactor =
    348             fixp_abs(stereoScaleFactor + fMult(tmpLeftReal, tmpRightReal) +
    349                      fMult(tmpLeftImag, tmpRightImag));
    350 
    351         /* min(2.0f, sqrt(stereoScaleFactor/(0.5f*tmpScaleFactor)))  */
    352         if ((stereoScaleFactor >> 1) <
    353             fMult(maxStereoScaleFactor, tmpScaleFactor)) {
    354           int sc_num = CountLeadingBits(stereoScaleFactor);
    355           int sc_denum = CountLeadingBits(tmpScaleFactor);
    356           sc = -(sc_num - sc_denum);
    357 
    358           tmpScaleFactor = schur_div((stereoScaleFactor << (sc_num)) >> 1,
    359                                      tmpScaleFactor << sc_denum, 16);
    360 
    361           /* prevent odd scaling for next sqrt calculation */
    362           if (sc & 0x1) {
    363             sc++;
    364             tmpScaleFactor >>= 1;
    365           }
    366           stereoScaleFactor = sqrtFixp(tmpScaleFactor);
    367           stereoScaleFactor <<= (sc >> 1);
    368         } else {
    369           stereoScaleFactor = maxStereoScaleFactor;
    370         }
    371 
    372         /* write data to hybrid output */
    373         tmpHybrid[0][k] = fMultDiv2(stereoScaleFactor,
    374                                     (FIXP_DBL)(tmpLeftReal + tmpRightReal)) >>
    375                           dynScale;
    376         tmpHybrid[1][k] = fMultDiv2(stereoScaleFactor,
    377                                     (FIXP_DBL)(tmpLeftImag + tmpRightImag)) >>
    378                           dynScale;
    379 
    380       } /* hybrid bands - k */
    381 
    382       FDKhybridSynthesisApply(&hParametricStereo->fdkHybSynFilter, tmpHybrid[0],
    383                               tmpHybrid[1], mixRealQmfData[n],
    384                               mixImagQmfData[n]);
    385 
    386       qmfSynthesisFilteringSlot(
    387           sbrSynthQmf, mixRealQmfData[n], mixImagQmfData[n], downmixScale - 7,
    388           downmixScale - 7,
    389           downsampledOutSignal + (n * sbrSynthQmf->no_channels), 1,
    390           pWorkBuffer);
    391 
    392     } /* slots */
    393 
    394     *qmfScale = -downmixScale + 7;
    395 
    396     C_AALLOC_SCRATCH_END(pWorkBuffer, FIXP_DBL, 2 * 64)
    397 
    398     {
    399       const INT noQmfSlots2 = hParametricStereo->noQmfSlots >> 1;
    400       const int noQmfBands = hParametricStereo->noQmfBands;
    401 
    402       INT scale, i, j, slotOffset;
    403 
    404       FIXP_DBL tmp[2][64];
    405 
    406       for (i = 0; i < noQmfSlots2; i++) {
    407         FDKmemcpy(tmp[0], hParametricStereo->qmfDelayLines[0][i],
    408                   noQmfBands * sizeof(FIXP_DBL));
    409         FDKmemcpy(tmp[1], hParametricStereo->qmfDelayLines[1][i],
    410                   noQmfBands * sizeof(FIXP_DBL));
    411 
    412         FDKmemcpy(hParametricStereo->qmfDelayLines[0][i],
    413                   mixRealQmfData[i + noQmfSlots2],
    414                   noQmfBands * sizeof(FIXP_DBL));
    415         FDKmemcpy(hParametricStereo->qmfDelayLines[1][i],
    416                   mixImagQmfData[i + noQmfSlots2],
    417                   noQmfBands * sizeof(FIXP_DBL));
    418 
    419         FDKmemcpy(mixRealQmfData[i + noQmfSlots2], mixRealQmfData[i],
    420                   noQmfBands * sizeof(FIXP_DBL));
    421         FDKmemcpy(mixImagQmfData[i + noQmfSlots2], mixImagQmfData[i],
    422                   noQmfBands * sizeof(FIXP_DBL));
    423 
    424         FDKmemcpy(mixRealQmfData[i], tmp[0], noQmfBands * sizeof(FIXP_DBL));
    425         FDKmemcpy(mixImagQmfData[i], tmp[1], noQmfBands * sizeof(FIXP_DBL));
    426       }
    427 
    428       if (hParametricStereo->qmfDelayScale > *qmfScale) {
    429         scale = hParametricStereo->qmfDelayScale - *qmfScale;
    430         slotOffset = 0;
    431       } else {
    432         scale = *qmfScale - hParametricStereo->qmfDelayScale;
    433         slotOffset = noQmfSlots2;
    434       }
    435 
    436       for (i = 0; i < noQmfSlots2; i++) {
    437         for (j = 0; j < noQmfBands; j++) {
    438           mixRealQmfData[i + slotOffset][j] >>= scale;
    439           mixImagQmfData[i + slotOffset][j] >>= scale;
    440         }
    441       }
    442 
    443       scale = *qmfScale;
    444       *qmfScale = fMin(*qmfScale, hParametricStereo->qmfDelayScale);
    445       hParametricStereo->qmfDelayScale = scale;
    446     }
    447 
    448   } /* valid handle */
    449 
    450   return error;
    451 }
    452 
    453 INT FDKsbrEnc_PSEnc_WritePSData(HANDLE_PARAMETRIC_STEREO hParametricStereo,
    454                                 HANDLE_FDK_BITSTREAM hBitstream) {
    455   return (
    456       (hParametricStereo != NULL)
    457           ? FDKsbrEnc_WritePSBitstream(&hParametricStereo->psOut[0], hBitstream)
    458           : 0);
    459 }
    460 
    461 FDK_PSENC_ERROR FDKsbrEnc_PSEnc_ParametricStereoProcessing(
    462     HANDLE_PARAMETRIC_STEREO hParametricStereo, INT_PCM *samples[2],
    463     UINT samplesBufSize, QMF_FILTER_BANK **hQmfAnalysis,
    464     FIXP_DBL **RESTRICT downmixedRealQmfData,
    465     FIXP_DBL **RESTRICT downmixedImagQmfData, INT_PCM *downsampledOutSignal,
    466     HANDLE_QMF_FILTER_BANK sbrSynthQmf, SCHAR *qmfScale, const int sendHeader) {
    467   FDK_PSENC_ERROR error = PSENC_OK;
    468   INT psQmfScale[MAX_PS_CHANNELS] = {0};
    469   int psCh, i;
    470   C_AALLOC_SCRATCH_START(pWorkBuffer, FIXP_DBL, 4 * 64)
    471 
    472   for (psCh = 0; psCh < MAX_PS_CHANNELS; psCh++) {
    473     for (i = 0; i < hQmfAnalysis[psCh]->no_col; i++) {
    474       qmfAnalysisFilteringSlot(
    475           hQmfAnalysis[psCh], &pWorkBuffer[2 * 64], /* qmfReal[64] */
    476           &pWorkBuffer[3 * 64],                     /* qmfImag[64] */
    477           samples[psCh] + i * hQmfAnalysis[psCh]->no_channels, 1,
    478           &pWorkBuffer[0 * 64] /* qmf workbuffer 2*64 */
    479       );
    480 
    481       FDKhybridAnalysisApply(
    482           &hParametricStereo->fdkHybAnaFilter[psCh],
    483           &pWorkBuffer[2 * 64], /* qmfReal[64] */
    484           &pWorkBuffer[3 * 64], /* qmfImag[64] */
    485           hParametricStereo->pHybridData[i + HYBRID_READ_OFFSET][psCh][0],
    486           hParametricStereo->pHybridData[i + HYBRID_READ_OFFSET][psCh][1]);
    487 
    488     } /* no_col loop  i  */
    489 
    490     psQmfScale[psCh] = hQmfAnalysis[psCh]->outScalefactor;
    491 
    492   } /* for psCh */
    493 
    494   C_AALLOC_SCRATCH_END(pWorkBuffer, FIXP_DBL, 4 * 64)
    495 
    496   /* find best scaling in new QMF and Hybrid data */
    497   psFindBestScaling(
    498       hParametricStereo, &hParametricStereo->pHybridData[HYBRID_READ_OFFSET],
    499       hParametricStereo->dynBandScale, hParametricStereo->maxBandValue,
    500       &hParametricStereo->dmxScale);
    501 
    502   /* extract the ps parameters */
    503   if (PSENC_OK !=
    504       (error = ExtractPSParameters(hParametricStereo, sendHeader,
    505                                    &hParametricStereo->pHybridData[0]))) {
    506     goto bail;
    507   }
    508 
    509   /* save hybrid date for next frame */
    510   for (i = 0; i < HYBRID_READ_OFFSET; i++) {
    511     FDKmemcpy(
    512         hParametricStereo->pHybridData[i][0][0],
    513         hParametricStereo->pHybridData[hParametricStereo->noQmfSlots + i][0][0],
    514         MAX_HYBRID_BANDS * sizeof(FIXP_DBL)); /* left, real */
    515     FDKmemcpy(
    516         hParametricStereo->pHybridData[i][0][1],
    517         hParametricStereo->pHybridData[hParametricStereo->noQmfSlots + i][0][1],
    518         MAX_HYBRID_BANDS * sizeof(FIXP_DBL)); /* left, imag */
    519     FDKmemcpy(
    520         hParametricStereo->pHybridData[i][1][0],
    521         hParametricStereo->pHybridData[hParametricStereo->noQmfSlots + i][1][0],
    522         MAX_HYBRID_BANDS * sizeof(FIXP_DBL)); /* right, real */
    523     FDKmemcpy(
    524         hParametricStereo->pHybridData[i][1][1],
    525         hParametricStereo->pHybridData[hParametricStereo->noQmfSlots + i][1][1],
    526         MAX_HYBRID_BANDS * sizeof(FIXP_DBL)); /* right, imag */
    527   }
    528 
    529   /* downmix and hybrid synthesis */
    530   if (PSENC_OK !=
    531       (error = DownmixPSQmfData(
    532            hParametricStereo, sbrSynthQmf, downmixedRealQmfData,
    533            downmixedImagQmfData, downsampledOutSignal, samplesBufSize,
    534            &hParametricStereo->pHybridData[HYBRID_READ_OFFSET],
    535            hParametricStereo->noQmfSlots, psQmfScale, qmfScale))) {
    536     goto bail;
    537   }
    538 
    539 bail:
    540 
    541   return error;
    542 }
    543 
    544 static void psFindBestScaling(
    545     HANDLE_PARAMETRIC_STEREO hParametricStereo,
    546     FIXP_DBL *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2],
    547     UCHAR *dynBandScale, FIXP_DBL *maxBandValue, SCHAR *dmxScale) {
    548   HANDLE_PS_ENCODE hPsEncode = hParametricStereo->hPsEncode;
    549 
    550   INT group, bin, col, band;
    551   const INT frameSize = hParametricStereo->noQmfSlots;
    552   const INT psBands = (INT)hPsEncode->psEncMode;
    553   const INT nIidGroups = hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups;
    554 
    555   /* group wise scaling */
    556   FIXP_DBL maxVal[2][PS_MAX_BANDS];
    557   FIXP_DBL maxValue = FL2FXCONST_DBL(0.f);
    558 
    559   FDKmemclear(maxVal, sizeof(maxVal));
    560 
    561   /* start with hybrid data */
    562   for (group = 0; group < nIidGroups; group++) {
    563     /* Translate group to bin */
    564     bin = hPsEncode->subband2parameterIndex[group];
    565 
    566     /* Translate from 20 bins to 10 bins */
    567     if (hPsEncode->psEncMode == PS_BANDS_COARSE) {
    568       bin >>= 1;
    569     }
    570 
    571     /* QMF downmix scaling */
    572     for (col = 0; col < frameSize; col++) {
    573       int i, section = (col < frameSize - HYBRID_READ_OFFSET) ? 0 : 1;
    574       FIXP_DBL tmp = maxVal[section][bin];
    575       for (i = hPsEncode->iidGroupBorders[group];
    576            i < hPsEncode->iidGroupBorders[group + 1]; i++) {
    577         tmp = fixMax(tmp, (FIXP_DBL)fixp_abs(hybridData[col][0][0][i]));
    578         tmp = fixMax(tmp, (FIXP_DBL)fixp_abs(hybridData[col][0][1][i]));
    579         tmp = fixMax(tmp, (FIXP_DBL)fixp_abs(hybridData[col][1][0][i]));
    580         tmp = fixMax(tmp, (FIXP_DBL)fixp_abs(hybridData[col][1][1][i]));
    581       }
    582       maxVal[section][bin] = tmp;
    583     }
    584   } /* nIidGroups */
    585 
    586   /* convert maxSpec to maxScaling, find scaling space */
    587   for (band = 0; band < psBands; band++) {
    588 #ifndef MULT_16x16
    589     dynBandScale[band] =
    590         CountLeadingBits(fixMax(maxVal[0][band], maxBandValue[band]));
    591 #else
    592     dynBandScale[band] = fixMax(
    593         0, CountLeadingBits(fixMax(maxVal[0][band], maxBandValue[band])) -
    594                FRACT_BITS);
    595 #endif
    596     maxValue = fixMax(maxValue, fixMax(maxVal[0][band], maxVal[1][band]));
    597     maxBandValue[band] = fixMax(maxVal[0][band], maxVal[1][band]);
    598   }
    599 
    600     /* calculate maximal scaling for QMF downmix */
    601 #ifndef MULT_16x16
    602   *dmxScale = fixMin(DFRACT_BITS, CountLeadingBits(maxValue));
    603 #else
    604   *dmxScale = fixMax(0, fixMin(FRACT_BITS, CountLeadingBits((maxValue))));
    605 #endif
    606 }
    607