Home | History | Annotate | Download | only in src
      1 
      2 /* -----------------------------------------------------------------------------------------------------------
      3 Software License for The Fraunhofer FDK AAC Codec Library for Android
      4 
      5  Copyright  1995 - 2013 Fraunhofer-Gesellschaft zur Frderung der angewandten Forschung e.V.
      6   All rights reserved.
      7 
      8  1.    INTRODUCTION
      9 The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements
     10 the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio.
     11 This FDK AAC Codec software is intended to be used on a wide variety of Android devices.
     12 
     13 AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual
     14 audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by
     15 independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part
     16 of the MPEG specifications.
     17 
     18 Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer)
     19 may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners
     20 individually for the purpose of encoding or decoding bit streams in products that are compliant with
     21 the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license
     22 these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec
     23 software may already be covered under those patent licenses when it is used for those licensed purposes only.
     24 
     25 Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality,
     26 are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional
     27 applications information and documentation.
     28 
     29 2.    COPYRIGHT LICENSE
     30 
     31 Redistribution and use in source and binary forms, with or without modification, are permitted without
     32 payment of copyright license fees provided that you satisfy the following conditions:
     33 
     34 You must retain the complete text of this software license in redistributions of the FDK AAC Codec or
     35 your modifications thereto in source code form.
     36 
     37 You must retain the complete text of this software license in the documentation and/or other materials
     38 provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form.
     39 You must make available free of charge copies of the complete source code of the FDK AAC Codec and your
     40 modifications thereto to recipients of copies in binary form.
     41 
     42 The name of Fraunhofer may not be used to endorse or promote products derived from this library without
     43 prior written permission.
     44 
     45 You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec
     46 software or your modifications thereto.
     47 
     48 Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software
     49 and the date of any change. For modified versions of the FDK AAC Codec, the term
     50 "Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term
     51 "Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android."
     52 
     53 3.    NO PATENT LICENSE
     54 
     55 NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer,
     56 ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with
     57 respect to this software.
     58 
     59 You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized
     60 by appropriate patent licenses.
     61 
     62 4.    DISCLAIMER
     63 
     64 This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors
     65 "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties
     66 of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
     67 CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages,
     68 including but not limited to procurement of substitute goods or services; loss of use, data, or profits,
     69 or business interruption, however caused and on any theory of liability, whether in contract, strict
     70 liability, or tort (including negligence), arising in any way out of the use of this software, even if
     71 advised of the possibility of such damage.
     72 
     73 5.    CONTACT INFORMATION
     74 
     75 Fraunhofer Institute for Integrated Circuits IIS
     76 Attention: Audio and Multimedia Departments - FDK AAC LL
     77 Am Wolfsmantel 33
     78 91058 Erlangen, Germany
     79 
     80 www.iis.fraunhofer.de/amm
     81 amm-info (at) iis.fraunhofer.de
     82 ----------------------------------------------------------------------------------------------------------- */
     83 
     84 /*****************************  MPEG Audio Encoder  ***************************
     85 
     86    Initial Authors:      M. Multrus
     87    Contents/Description: PS Wrapper, Downmix
     88 
     89 ******************************************************************************/
     90 
     91 #include "ps_main.h"
     92 
     93 
     94 /* Includes ******************************************************************/
     95 
     96 #include "ps_const.h"
     97 #include "ps_bitenc.h"
     98 
     99 #include "sbr_ram.h"
    100 
    101 /*--------------- function declarations --------------------*/
    102 static void psFindBestScaling(
    103         HANDLE_PARAMETRIC_STEREO  hParametricStereo,
    104         FIXP_DBL                 *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2],
    105         UCHAR                    *dynBandScale,
    106         FIXP_QMF                 *maxBandValue,
    107         SCHAR                    *dmxScale
    108         );
    109 
    110 /*------------- function definitions ----------------*/
    111 FDK_PSENC_ERROR PSEnc_Create(
    112         HANDLE_PARAMETRIC_STEREO *phParametricStereo
    113         )
    114 {
    115   FDK_PSENC_ERROR error = PSENC_OK;
    116 
    117   if (phParametricStereo==NULL) {
    118     error = PSENC_INVALID_HANDLE;
    119   }
    120   else {
    121     int i;
    122     HANDLE_PARAMETRIC_STEREO hParametricStereo = NULL;
    123 
    124     if (NULL==(hParametricStereo = GetRam_ParamStereo())) {
    125       error = PSENC_MEMORY_ERROR;
    126       goto bail;
    127     }
    128     FDKmemclear(hParametricStereo, sizeof(PARAMETRIC_STEREO));
    129 
    130     if (PSENC_OK != (error = FDKsbrEnc_CreatePSEncode(&hParametricStereo->hPsEncode))) {
    131       goto bail;
    132     }
    133 
    134     for (i=0; i<MAX_PS_CHANNELS; i++) {
    135       if (FDKhybridAnalysisOpen(
    136             &hParametricStereo->fdkHybAnaFilter[i],
    137              hParametricStereo->__staticHybAnaStatesLF[i],
    138              sizeof(hParametricStereo->__staticHybAnaStatesLF[i]),
    139              hParametricStereo->__staticHybAnaStatesHF[i],
    140              sizeof(hParametricStereo->__staticHybAnaStatesHF[i])
    141              ) !=0 )
    142       {
    143         error = PSENC_MEMORY_ERROR;
    144         goto bail;
    145       }
    146     }
    147 
    148     *phParametricStereo = hParametricStereo; /* return allocated handle */
    149   }
    150 bail:
    151   return error;
    152 }
    153 
    154 FDK_PSENC_ERROR PSEnc_Init(
    155         HANDLE_PARAMETRIC_STEREO  hParametricStereo,
    156         const HANDLE_PSENC_CONFIG hPsEncConfig,
    157         INT                       noQmfSlots,
    158         INT                       noQmfBands
    159        ,UCHAR                    *dynamic_RAM
    160         )
    161 {
    162   FDK_PSENC_ERROR error = PSENC_OK;
    163 
    164   if ( (NULL==hParametricStereo) || (NULL==hPsEncConfig) ) {
    165     error = PSENC_INVALID_HANDLE;
    166   }
    167   else {
    168     int ch, i;
    169 
    170     hParametricStereo->initPS = 1;
    171     hParametricStereo->noQmfSlots = noQmfSlots;
    172     hParametricStereo->noQmfBands = noQmfBands;
    173 
    174     /* clear delay lines */
    175     FDKmemclear(hParametricStereo->qmfDelayLines, sizeof(hParametricStereo->qmfDelayLines));
    176 
    177     hParametricStereo->qmfDelayScale = FRACT_BITS-1;
    178 
    179     /* create configuration for hybrid filter bank */
    180     for (ch=0; ch<MAX_PS_CHANNELS; ch++) {
    181       FDKhybridAnalysisInit(
    182             &hParametricStereo->fdkHybAnaFilter[ch],
    183              THREE_TO_TEN,
    184              QMF_CHANNELS,
    185              QMF_CHANNELS,
    186              1
    187              );
    188     } /* ch */
    189 
    190     FDKhybridSynthesisInit(
    191           &hParametricStereo->fdkHybSynFilter,
    192            THREE_TO_TEN,
    193            QMF_CHANNELS,
    194            QMF_CHANNELS
    195            );
    196 
    197     /* determine average delay */
    198     hParametricStereo->psDelay = (HYBRID_FILTER_DELAY*hParametricStereo->noQmfBands);
    199 
    200     if ( (hPsEncConfig->maxEnvelopes < PSENC_NENV_1) || (hPsEncConfig->maxEnvelopes > PSENC_NENV_MAX) ) {
    201       hPsEncConfig->maxEnvelopes = PSENC_NENV_DEFAULT;
    202     }
    203     hParametricStereo->maxEnvelopes = hPsEncConfig->maxEnvelopes;
    204 
    205     if (PSENC_OK != (error = FDKsbrEnc_InitPSEncode(hParametricStereo->hPsEncode, (PS_BANDS) hPsEncConfig->nStereoBands, hPsEncConfig->iidQuantErrorThreshold))){
    206       goto bail;
    207     }
    208 
    209     for (ch = 0; ch<MAX_PS_CHANNELS; ch ++) {
    210       FIXP_DBL *pDynReal = GetRam_Sbr_envRBuffer (ch, dynamic_RAM);
    211       FIXP_DBL *pDynImag = GetRam_Sbr_envIBuffer (ch, dynamic_RAM);
    212 
    213       for (i=0; i<HYBRID_FRAMESIZE; i++) {
    214         hParametricStereo->pHybridData[i+HYBRID_READ_OFFSET][ch][0] = &pDynReal[i*MAX_HYBRID_BANDS];
    215         hParametricStereo->pHybridData[i+HYBRID_READ_OFFSET][ch][1] = &pDynImag[i*MAX_HYBRID_BANDS];;
    216       }
    217 
    218       for (i=0; i<HYBRID_READ_OFFSET; i++) {
    219         hParametricStereo->pHybridData[i][ch][0] = hParametricStereo->__staticHybridData[i][ch][0];
    220         hParametricStereo->pHybridData[i][ch][1] = hParametricStereo->__staticHybridData[i][ch][1];
    221       }
    222     } /* ch */
    223 
    224     /* clear static hybrid buffer */
    225     FDKmemclear(hParametricStereo->__staticHybridData, sizeof(hParametricStereo->__staticHybridData));
    226 
    227     /* clear bs buffer */
    228     FDKmemclear(hParametricStereo->psOut, sizeof(hParametricStereo->psOut));
    229 
    230     hParametricStereo->psOut[0].enablePSHeader = 1; /* write ps header in first frame */
    231 
    232     /* clear scaling buffer */
    233     FDKmemclear(hParametricStereo->dynBandScale, sizeof(UCHAR)*PS_MAX_BANDS);
    234     FDKmemclear(hParametricStereo->maxBandValue, sizeof(FIXP_QMF)*PS_MAX_BANDS);
    235 
    236   } /* valid handle */
    237 bail:
    238   return error;
    239 }
    240 
    241 
    242 FDK_PSENC_ERROR PSEnc_Destroy(
    243         HANDLE_PARAMETRIC_STEREO *phParametricStereo
    244         )
    245 {
    246   FDK_PSENC_ERROR error = PSENC_OK;
    247 
    248   if (NULL!=phParametricStereo) {
    249     HANDLE_PARAMETRIC_STEREO hParametricStereo = *phParametricStereo;
    250     if(hParametricStereo != NULL){
    251       FDKsbrEnc_DestroyPSEncode(&hParametricStereo->hPsEncode);
    252       FreeRam_ParamStereo(phParametricStereo);
    253     }
    254   }
    255 
    256   return error;
    257 }
    258 
    259 static FDK_PSENC_ERROR ExtractPSParameters(
    260         HANDLE_PARAMETRIC_STEREO  hParametricStereo,
    261         const int                 sendHeader,
    262         FIXP_DBL                 *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2]
    263         )
    264 {
    265   FDK_PSENC_ERROR error = PSENC_OK;
    266 
    267   if (hParametricStereo == NULL) {
    268     error = PSENC_INVALID_HANDLE;
    269   }
    270   else {
    271     /* call ps encode function */
    272     if (hParametricStereo->initPS){
    273       hParametricStereo->psOut[1] = hParametricStereo->psOut[0];
    274     }
    275     hParametricStereo->psOut[0] = hParametricStereo->psOut[1];
    276 
    277     if (PSENC_OK != (error = FDKsbrEnc_PSEncode(
    278             hParametricStereo->hPsEncode,
    279            &hParametricStereo->psOut[1],
    280             hParametricStereo->dynBandScale,
    281             hParametricStereo->maxEnvelopes,
    282             hybridData,
    283             hParametricStereo->noQmfSlots,
    284             sendHeader)))
    285     {
    286       goto bail;
    287     }
    288 
    289     if (hParametricStereo->initPS) {
    290       hParametricStereo->psOut[0] = hParametricStereo->psOut[1];
    291       hParametricStereo->initPS = 0;
    292     }
    293   }
    294 bail:
    295   return error;
    296 }
    297 
    298 
    299 static FDK_PSENC_ERROR DownmixPSQmfData(
    300        HANDLE_PARAMETRIC_STEREO  hParametricStereo,
    301        HANDLE_QMF_FILTER_BANK    sbrSynthQmf,
    302        FIXP_QMF       **RESTRICT mixRealQmfData,
    303        FIXP_QMF       **RESTRICT mixImagQmfData,
    304        INT_PCM                  *downsampledOutSignal,
    305        FIXP_DBL                 *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2],
    306        const INT                 noQmfSlots,
    307        const INT                 psQmfScale[MAX_PS_CHANNELS],
    308        SCHAR                    *qmfScale
    309        )
    310 {
    311   FDK_PSENC_ERROR error = PSENC_OK;
    312 
    313   if(hParametricStereo == NULL){
    314     error = PSENC_INVALID_HANDLE;
    315   }
    316   else {
    317     int n, k;
    318     C_AALLOC_SCRATCH_START(pWorkBuffer, FIXP_QMF, 2*QMF_CHANNELS)
    319 
    320     /* define scalings */
    321     int dynQmfScale = fixMax(0, hParametricStereo->dmxScale-1); /* scale one bit more for addition of left and right */
    322     int downmixScale = psQmfScale[0] - dynQmfScale;
    323     const FIXP_DBL maxStereoScaleFactor = MAXVAL_DBL; /* 2.f/2.f */
    324 
    325     for (n = 0; n<noQmfSlots; n++) {
    326 
    327       FIXP_DBL tmpHybrid[2][MAX_HYBRID_BANDS];
    328 
    329       for(k = 0; k<71; k++){
    330           int dynScale, sc; /* scaling */
    331           FIXP_QMF tmpLeftReal, tmpRightReal, tmpLeftImag, tmpRightImag;
    332           FIXP_DBL tmpScaleFactor, stereoScaleFactor;
    333 
    334           tmpLeftReal  = hybridData[n][0][0][k];
    335           tmpLeftImag  = hybridData[n][0][1][k];
    336           tmpRightReal = hybridData[n][1][0][k];
    337           tmpRightImag = hybridData[n][1][1][k];
    338 
    339           sc = fixMax(0,CntLeadingZeros( fixMax(fixMax(fixp_abs(tmpLeftReal),fixp_abs(tmpLeftImag)),fixMax(fixp_abs(tmpRightReal),fixp_abs(tmpRightImag))) )-2);
    340 
    341           tmpLeftReal  <<= sc; tmpLeftImag  <<= sc;
    342           tmpRightReal <<= sc; tmpRightImag <<= sc;
    343           dynScale = fixMin(sc-dynQmfScale,DFRACT_BITS-1);
    344 
    345           /* calc stereo scale factor to avoid loss of energy in bands                                                 */
    346           /* stereo scale factor = min(2.0f, sqrt( (abs(l(k, n)^2 + abs(r(k, n)^2 )))/(0.5f*abs(l(k, n) + r(k, n))) )) */
    347           stereoScaleFactor = fPow2Div2(tmpLeftReal)  + fPow2Div2(tmpLeftImag)
    348                             + fPow2Div2(tmpRightReal) + fPow2Div2(tmpRightImag) ;
    349 
    350           /* might be that tmpScaleFactor becomes negative, so fabs(.) */
    351           tmpScaleFactor    = fixp_abs(stereoScaleFactor + fMult(tmpLeftReal,tmpRightReal) + fMult(tmpLeftImag,tmpRightImag));
    352 
    353           /* min(2.0f, sqrt(stereoScaleFactor/(0.5f*tmpScaleFactor)))  */
    354           if ( (stereoScaleFactor>>1) < fMult(maxStereoScaleFactor,tmpScaleFactor) ) {
    355 
    356               int sc_num   = CountLeadingBits(stereoScaleFactor) ;
    357               int sc_denum = CountLeadingBits(tmpScaleFactor) ;
    358               sc       = -(sc_num-sc_denum);
    359 
    360               tmpScaleFactor = schur_div((stereoScaleFactor<<(sc_num))>>1,
    361                                           tmpScaleFactor<<sc_denum,
    362                                           16) ;
    363 
    364               /* prevent odd scaling for next sqrt calculation */
    365               if (sc&0x1) {
    366                 sc++;
    367                 tmpScaleFactor>>=1;
    368               }
    369               stereoScaleFactor = sqrtFixp(tmpScaleFactor);
    370               stereoScaleFactor <<= (sc>>1);
    371           }
    372           else {
    373               stereoScaleFactor = maxStereoScaleFactor;
    374           }
    375 
    376           /* write data to hybrid output */
    377           tmpHybrid[0][k] = fMultDiv2(stereoScaleFactor, (FIXP_QMF)(tmpLeftReal + tmpRightReal))>>dynScale;
    378           tmpHybrid[1][k] = fMultDiv2(stereoScaleFactor, (FIXP_QMF)(tmpLeftImag + tmpRightImag))>>dynScale;
    379 
    380       } /* hybrid bands - k */
    381 
    382       FDKhybridSynthesisApply(
    383             &hParametricStereo->fdkHybSynFilter,
    384              tmpHybrid[0],
    385              tmpHybrid[1],
    386              mixRealQmfData[n],
    387              mixImagQmfData[n]);
    388 
    389       qmfSynthesisFilteringSlot(
    390             sbrSynthQmf,
    391             mixRealQmfData[n],
    392             mixImagQmfData[n],
    393             downmixScale-7,
    394             downmixScale-7,
    395             downsampledOutSignal+(n*sbrSynthQmf->no_channels),
    396             1,
    397             pWorkBuffer);
    398 
    399     } /* slots */
    400 
    401     *qmfScale = -downmixScale + 7;
    402 
    403     C_AALLOC_SCRATCH_END(pWorkBuffer, FIXP_QMF, 2*QMF_CHANNELS)
    404 
    405   {
    406     const INT noQmfSlots2 = hParametricStereo->noQmfSlots>>1;
    407     const int noQmfBands  = hParametricStereo->noQmfBands;
    408 
    409     INT scale, i, j, slotOffset;
    410 
    411     FIXP_QMF tmp[2][QMF_CHANNELS];
    412 
    413     for (i=0; i<noQmfSlots2; i++) {
    414       FDKmemcpy(tmp[0], hParametricStereo->qmfDelayLines[0][i], noQmfBands*sizeof(FIXP_QMF));
    415       FDKmemcpy(tmp[1], hParametricStereo->qmfDelayLines[1][i], noQmfBands*sizeof(FIXP_QMF));
    416 
    417       FDKmemcpy(hParametricStereo->qmfDelayLines[0][i], mixRealQmfData[i+noQmfSlots2], noQmfBands*sizeof(FIXP_QMF));
    418       FDKmemcpy(hParametricStereo->qmfDelayLines[1][i], mixImagQmfData[i+noQmfSlots2], noQmfBands*sizeof(FIXP_QMF));
    419 
    420       FDKmemcpy(mixRealQmfData[i+noQmfSlots2], mixRealQmfData[i], noQmfBands*sizeof(FIXP_QMF));
    421       FDKmemcpy(mixImagQmfData[i+noQmfSlots2], mixImagQmfData[i], noQmfBands*sizeof(FIXP_QMF));
    422 
    423       FDKmemcpy(mixRealQmfData[i], tmp[0], noQmfBands*sizeof(FIXP_QMF));
    424       FDKmemcpy(mixImagQmfData[i], tmp[1], noQmfBands*sizeof(FIXP_QMF));
    425     }
    426 
    427     if (hParametricStereo->qmfDelayScale > *qmfScale) {
    428       scale = hParametricStereo->qmfDelayScale - *qmfScale;
    429       slotOffset = 0;
    430     }
    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 = FDKmin(*qmfScale, hParametricStereo->qmfDelayScale);
    445     hParametricStereo->qmfDelayScale = scale;
    446   }
    447 
    448   } /* valid handle */
    449 
    450   return error;
    451 }
    452 
    453 
    454 INT FDKsbrEnc_PSEnc_WritePSData(
    455         HANDLE_PARAMETRIC_STEREO  hParametricStereo,
    456         HANDLE_FDK_BITSTREAM      hBitstream
    457         )
    458 {
    459   return ( (hParametricStereo!=NULL) ? FDKsbrEnc_WritePSBitstream(&hParametricStereo->psOut[0], hBitstream) : 0 );
    460 }
    461 
    462 
    463 FDK_PSENC_ERROR FDKsbrEnc_PSEnc_ParametricStereoProcessing(
    464         HANDLE_PARAMETRIC_STEREO  hParametricStereo,
    465         INT_PCM                  *samples[2],
    466         UINT                      timeInStride,
    467         QMF_FILTER_BANK         **hQmfAnalysis,
    468         FIXP_QMF **RESTRICT       downmixedRealQmfData,
    469         FIXP_QMF **RESTRICT       downmixedImagQmfData,
    470         INT_PCM                  *downsampledOutSignal,
    471         HANDLE_QMF_FILTER_BANK    sbrSynthQmf,
    472         SCHAR                    *qmfScale,
    473         const int                 sendHeader
    474         )
    475 {
    476   FDK_PSENC_ERROR error = PSENC_OK;
    477   INT psQmfScale[MAX_PS_CHANNELS] = {0};
    478   int psCh, i;
    479   C_AALLOC_SCRATCH_START(pWorkBuffer, FIXP_QMF, 4*QMF_CHANNELS)
    480 
    481   for (psCh = 0; psCh<MAX_PS_CHANNELS; psCh ++) {
    482 
    483     for (i = 0; i < hQmfAnalysis[psCh]->no_col; i++) {
    484 
    485       qmfAnalysisFilteringSlot(
    486           hQmfAnalysis[psCh],
    487          &pWorkBuffer[2*QMF_CHANNELS], /* qmfReal[QMF_CHANNELS] */
    488          &pWorkBuffer[3*QMF_CHANNELS], /* qmfImag[QMF_CHANNELS] */
    489           samples[psCh]+i*(hQmfAnalysis[psCh]->no_channels*timeInStride),
    490           timeInStride,
    491          &pWorkBuffer[0*QMF_CHANNELS]  /* qmf workbuffer 2*QMF_CHANNELS */
    492           );
    493 
    494       FDKhybridAnalysisApply(
    495          &hParametricStereo->fdkHybAnaFilter[psCh],
    496          &pWorkBuffer[2*QMF_CHANNELS],  /* qmfReal[QMF_CHANNELS] */
    497          &pWorkBuffer[3*QMF_CHANNELS],  /* qmfImag[QMF_CHANNELS] */
    498           hParametricStereo->pHybridData[i+HYBRID_READ_OFFSET][psCh][0],
    499           hParametricStereo->pHybridData[i+HYBRID_READ_OFFSET][psCh][1]
    500           );
    501 
    502     } /* no_col loop  i  */
    503 
    504     psQmfScale[psCh] = hQmfAnalysis[psCh]->outScalefactor;
    505 
    506   } /* for psCh */
    507 
    508   C_AALLOC_SCRATCH_END(pWorkBuffer, FIXP_QMF, 4*QMF_CHANNELS)
    509 
    510   /* find best scaling in new QMF and Hybrid data */
    511   psFindBestScaling( hParametricStereo,
    512                     &hParametricStereo->pHybridData[HYBRID_READ_OFFSET],
    513                      hParametricStereo->dynBandScale,
    514                      hParametricStereo->maxBandValue,
    515                     &hParametricStereo->dmxScale ) ;
    516 
    517 
    518   /* extract the ps parameters */
    519   if(PSENC_OK != (error = ExtractPSParameters(hParametricStereo, sendHeader, &hParametricStereo->pHybridData[0]))){
    520     goto bail;
    521   }
    522 
    523   /* save hybrid date for next frame */
    524   for (i=0; i<HYBRID_READ_OFFSET; i++) {
    525     FDKmemcpy(hParametricStereo->pHybridData[i][0][0], hParametricStereo->pHybridData[HYBRID_FRAMESIZE+i][0][0], MAX_HYBRID_BANDS*sizeof(FIXP_DBL)); /* left, real */
    526     FDKmemcpy(hParametricStereo->pHybridData[i][0][1], hParametricStereo->pHybridData[HYBRID_FRAMESIZE+i][0][1], MAX_HYBRID_BANDS*sizeof(FIXP_DBL)); /* left, imag */
    527     FDKmemcpy(hParametricStereo->pHybridData[i][1][0], hParametricStereo->pHybridData[HYBRID_FRAMESIZE+i][1][0], MAX_HYBRID_BANDS*sizeof(FIXP_DBL)); /* right, real */
    528     FDKmemcpy(hParametricStereo->pHybridData[i][1][1], hParametricStereo->pHybridData[HYBRID_FRAMESIZE+i][1][1], MAX_HYBRID_BANDS*sizeof(FIXP_DBL)); /* right, imag */
    529   }
    530 
    531   /* downmix and hybrid synthesis */
    532   if (PSENC_OK != (error = DownmixPSQmfData(hParametricStereo, sbrSynthQmf, downmixedRealQmfData, downmixedImagQmfData, downsampledOutSignal, &hParametricStereo->pHybridData[HYBRID_READ_OFFSET], hParametricStereo->noQmfSlots, psQmfScale, qmfScale))) {
    533     goto bail;
    534   }
    535 
    536 bail:
    537 
    538   return error;
    539 }
    540 
    541 static void psFindBestScaling(
    542         HANDLE_PARAMETRIC_STEREO  hParametricStereo,
    543         FIXP_DBL                 *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2],
    544         UCHAR                    *dynBandScale,
    545         FIXP_QMF                 *maxBandValue,
    546         SCHAR                    *dmxScale
    547         )
    548 {
    549   HANDLE_PS_ENCODE hPsEncode      =  hParametricStereo->hPsEncode;
    550 
    551   INT group, bin, col, band;
    552   const INT frameSize  = hParametricStereo->noQmfSlots;
    553   const INT psBands    = (INT) hPsEncode->psEncMode;
    554   const INT nIidGroups = hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups;
    555 
    556   /* group wise scaling */
    557   FIXP_QMF maxVal [2][PS_MAX_BANDS];
    558   FIXP_QMF maxValue = FL2FXCONST_DBL(0.f);
    559 
    560   FDKmemclear(maxVal, sizeof(maxVal));
    561 
    562   /* start with hybrid data */
    563   for (group=0; group < nIidGroups; group++) {
    564     /* Translate group to bin */
    565     bin = hPsEncode->subband2parameterIndex[group];
    566 
    567     /* Translate from 20 bins to 10 bins */
    568     if (hPsEncode->psEncMode == PS_BANDS_COARSE) {
    569       bin >>= 1;
    570     }
    571 
    572     /* QMF downmix scaling */
    573     {
    574       FIXP_QMF tmp = maxVal[0][bin];
    575       int i;
    576       for (col=0; col<frameSize-HYBRID_READ_OFFSET; col++) {
    577         for (i = hPsEncode->iidGroupBorders[group]; i < hPsEncode->iidGroupBorders[group+1]; i++) {
    578           tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(hybridData[col][0][0][i]));
    579           tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(hybridData[col][0][1][i]));
    580           tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(hybridData[col][1][0][i]));
    581           tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(hybridData[col][1][1][i]));
    582         }
    583       }
    584       maxVal[0][bin] = tmp;
    585 
    586       tmp = maxVal[1][bin];
    587       for (col=frameSize-HYBRID_READ_OFFSET; col<frameSize; col++) {
    588         for (i = hPsEncode->iidGroupBorders[group]; i < hPsEncode->iidGroupBorders[group+1]; i++) {
    589           tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(hybridData[col][0][0][i]));
    590           tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(hybridData[col][0][1][i]));
    591           tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(hybridData[col][1][0][i]));
    592           tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(hybridData[col][1][1][i]));
    593         }
    594       }
    595       maxVal[1][bin] = tmp;
    596     }
    597   } /* nIidGroups */
    598 
    599   /* convert maxSpec to maxScaling, find scaling space */
    600   for (band=0; band<psBands; band++) {
    601 #ifndef MULT_16x16
    602     dynBandScale[band] = CountLeadingBits(fixMax(maxVal[0][band],maxBandValue[band]));
    603 #else
    604     dynBandScale[band] = fixMax(0,CountLeadingBits(fixMax(maxVal[0][band],maxBandValue[band]))-FRACT_BITS);
    605 #endif
    606     maxValue = fixMax(maxValue,fixMax(maxVal[0][band],maxVal[1][band]));
    607     maxBandValue[band] = fixMax(maxVal[0][band], maxVal[1][band]);
    608   }
    609 
    610   /* calculate maximal scaling for QMF downmix */
    611 #ifndef MULT_16x16
    612   *dmxScale = fixMin(DFRACT_BITS, CountLeadingBits(maxValue));
    613 #else
    614   *dmxScale = fixMax(0,fixMin(FRACT_BITS, CountLeadingBits(FX_QMF2FX_DBL(maxValue))));
    615 #endif
    616 
    617 }
    618 
    619