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 /***************************  Fraunhofer IIS FDK Tools  **********************
     85 
     86    Author(s): Markus Lohwasser
     87    Description: FDK Tools Hybrid Filterbank
     88 
     89 ******************************************************************************/
     90 
     91 #include "FDK_hybrid.h"
     92 
     93 
     94 #include "fft.h"
     95 
     96 /*--------------- defines -----------------------------*/
     97 #define FFT_IDX_R(a)  (2*a)
     98 #define FFT_IDX_I(a)  (2*a+1)
     99 
    100 #define HYB_COEF8_0  ( 0.00746082949812f )
    101 #define HYB_COEF8_1  ( 0.02270420949825f )
    102 #define HYB_COEF8_2  ( 0.04546865930473f )
    103 #define HYB_COEF8_3  ( 0.07266113929591f )
    104 #define HYB_COEF8_4  ( 0.09885108575264f )
    105 #define HYB_COEF8_5  ( 0.11793710567217f )
    106 #define HYB_COEF8_6  ( 0.12500000000000f )
    107 #define HYB_COEF8_7  ( HYB_COEF8_5 )
    108 #define HYB_COEF8_8  ( HYB_COEF8_4 )
    109 #define HYB_COEF8_9  ( HYB_COEF8_3 )
    110 #define HYB_COEF8_10 ( HYB_COEF8_2 )
    111 #define HYB_COEF8_11 ( HYB_COEF8_1 )
    112 #define HYB_COEF8_12 ( HYB_COEF8_0 )
    113 
    114 
    115 /*--------------- structure definitions ---------------*/
    116 
    117 #if defined(ARCH_PREFER_MULT_32x16)
    118   #define FIXP_HTB FIXP_SGL               /* SGL data type. */
    119   #define FIXP_HTP FIXP_SPK               /* Packed SGL data type. */
    120   #define HTC(a) (FX_DBL2FXCONST_SGL(a))  /* Cast to SGL */
    121   #define FL2FXCONST_HTB FL2FXCONST_SGL
    122 #else
    123   #define FIXP_HTB FIXP_DBL               /* SGL data type. */
    124   #define FIXP_HTP FIXP_DPK               /* Packed DBL data type. */
    125   #define HTC(a) ((FIXP_DBL)(LONG)(a))    /* Cast to DBL */
    126   #define FL2FXCONST_HTB FL2FXCONST_DBL
    127 #endif
    128 
    129 #define HTCP(real,imag) { { HTC(real), HTC(imag) } } /* How to arrange the packed values. */
    130 
    131 
    132 struct FDK_HYBRID_SETUP
    133 {
    134     UCHAR               nrQmfBands;          /*!< Number of QMF bands to be converted to hybrid. */
    135     UCHAR               nHybBands[3];        /*!< Number of Hybrid bands generated by nrQmfBands. */
    136     SCHAR               kHybrid[3];          /*!< Filter configuration of each QMF band. */
    137     UCHAR               protoLen;            /*!< Prototype filter length. */
    138     UCHAR               filterDelay;         /*!< Delay caused by hybrid filter. */
    139     const INT          *pReadIdxTable;       /*!< Helper table to access input data ringbuffer. */
    140 
    141 };
    142 
    143 /*--------------- constants ---------------------------*/
    144 static const INT ringbuffIdxTab[2*13] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
    145 
    146 static const FDK_HYBRID_SETUP setup_3_16 = { 3, { 8, 4, 4}, {  8,  4,  4}, 13, (13-1)/2, ringbuffIdxTab};
    147 static const FDK_HYBRID_SETUP setup_3_12 = { 3, { 8, 2, 2}, {  8,  2,  2}, 13, (13-1)/2, ringbuffIdxTab};
    148 static const FDK_HYBRID_SETUP setup_3_10 = { 3, { 6, 2, 2}, { -8, -2,  2}, 13, (13-1)/2, ringbuffIdxTab};
    149 
    150 
    151 static const FIXP_HTP HybFilterCoef8[] = {
    152   HTCP(0x10000000, 0x00000000), HTCP(0x0df26407, 0xfa391882), HTCP(0xff532109, 0x00acdef7), HTCP(0x08f26d36, 0xf70d92ca),
    153   HTCP(0xfee34b5f, 0x02af570f), HTCP(0x038f276e, 0xf7684793), HTCP(0x00000000, 0x05d1eac2), HTCP(0x00000000, 0x05d1eac2),
    154   HTCP(0x038f276e, 0x0897b86d), HTCP(0xfee34b5f, 0xfd50a8f1), HTCP(0x08f26d36, 0x08f26d36), HTCP(0xff532109, 0xff532109),
    155   HTCP(0x0df26407, 0x05c6e77e)
    156 };
    157 
    158 static const FIXP_HTB HybFilterCoef2[13] = {
    159   FL2FXCONST_HTB( 0.00000000000000f), FL2FXCONST_HTB( 0.01899487526049f), FL2FXCONST_HTB( 0.00000000000000f), FL2FXCONST_HTB(-0.07293139167538f), FL2FXCONST_HTB( 0.00000000000000f), FL2FXCONST_HTB( 0.30596630545168f),
    160   FL2FXCONST_HTB( 0.50000000000000f), FL2FXCONST_HTB( 0.30596630545168f), FL2FXCONST_HTB( 0.00000000000000f), FL2FXCONST_HTB(-0.07293139167538f), FL2FXCONST_HTB( 0.00000000000000f), FL2FXCONST_HTB( 0.01899487526049f),
    161   FL2FXCONST_HTB( 0.00000000000000f)
    162 };
    163 
    164 static const FIXP_HTB HybFilterCoef4[13] = {
    165   FL2FXCONST_HTB(-0.00305151927305f), FL2FXCONST_HTB(-0.00794862316203f), FL2FXCONST_HTB(              0.0f), FL2FXCONST_HTB( 0.04318924038756f), FL2FXCONST_HTB( 0.12542448210445f), FL2FXCONST_HTB( 0.21227807049160f),
    166   FL2FXCONST_HTB(             0.25f), FL2FXCONST_HTB( 0.21227807049160f), FL2FXCONST_HTB( 0.12542448210445f), FL2FXCONST_HTB( 0.04318924038756f), FL2FXCONST_HTB(              0.0f), FL2FXCONST_HTB(-0.00794862316203f),
    167   FL2FXCONST_HTB(-0.00305151927305f)
    168 };
    169 
    170 /*--------------- function declarations ---------------*/
    171 static INT kChannelFiltering(
    172         const FIXP_DBL *const      pQmfReal,
    173         const FIXP_DBL *const      pQmfImag,
    174         const INT *const           pReadIdx,
    175         FIXP_DBL *const            mHybridReal,
    176         FIXP_DBL *const            mHybridImag,
    177         const SCHAR                hybridConfig
    178         );
    179 
    180 
    181 /*--------------- function definitions ----------------*/
    182 
    183 INT FDKhybridAnalysisOpen(
    184         HANDLE_FDK_ANA_HYB_FILTER  hAnalysisHybFilter,
    185         FIXP_DBL *const            pLFmemory,
    186         const UINT                 LFmemorySize,
    187         FIXP_DBL *const            pHFmemory,
    188         const UINT                 HFmemorySize
    189         )
    190 {
    191   INT err = 0;
    192 
    193   /* Save pointer to extern memory. */
    194   hAnalysisHybFilter->pLFmemory    = pLFmemory;
    195   hAnalysisHybFilter->LFmemorySize = LFmemorySize;
    196 
    197   hAnalysisHybFilter->pHFmemory    = pHFmemory;
    198   hAnalysisHybFilter->HFmemorySize = HFmemorySize;
    199 
    200   return err;
    201 }
    202 
    203 INT FDKhybridAnalysisInit(
    204         HANDLE_FDK_ANA_HYB_FILTER  hAnalysisHybFilter,
    205         const FDK_HYBRID_MODE      mode,
    206         const INT                  qmfBands,
    207         const INT                  cplxBands,
    208         const INT                  initStatesFlag
    209         )
    210 {
    211     int k;
    212     INT err = 0;
    213     FIXP_DBL *pMem = NULL;
    214     HANDLE_FDK_HYBRID_SETUP setup = NULL;
    215 
    216     switch (mode) {
    217       case THREE_TO_TEN:     setup = (HANDLE_FDK_HYBRID_SETUP)&setup_3_10; break;
    218       case THREE_TO_TWELVE:  setup = (HANDLE_FDK_HYBRID_SETUP)&setup_3_12; break;
    219       case THREE_TO_SIXTEEN: setup = (HANDLE_FDK_HYBRID_SETUP)&setup_3_16; break;
    220       default:               err = -1; goto bail;
    221     }
    222 
    223     /* Initialize handle. */
    224     hAnalysisHybFilter->pSetup      = setup;
    225     hAnalysisHybFilter->bufferLFpos = setup->protoLen-1;
    226     hAnalysisHybFilter->bufferHFpos = 0;
    227     hAnalysisHybFilter->nrBands     = qmfBands;
    228     hAnalysisHybFilter->cplxBands   = cplxBands;
    229     hAnalysisHybFilter->hfMode      = 0;
    230 
    231     /* Check available memory. */
    232     if ( ((2*setup->nrQmfBands*setup->protoLen*sizeof(FIXP_DBL)) > hAnalysisHybFilter->LFmemorySize)
    233       || ((setup->filterDelay*((qmfBands-setup->nrQmfBands)+(cplxBands-setup->nrQmfBands))*sizeof(FIXP_DBL)) > hAnalysisHybFilter->HFmemorySize) )
    234     {
    235       err = -2;
    236       goto bail;
    237     }
    238 
    239     /* Distribut LF memory. */
    240     pMem = hAnalysisHybFilter->pLFmemory;
    241     for (k=0; k<setup->nrQmfBands; k++) {
    242       hAnalysisHybFilter->bufferLFReal[k] = pMem; pMem += setup->protoLen;
    243       hAnalysisHybFilter->bufferLFImag[k] = pMem; pMem += setup->protoLen;
    244     }
    245 
    246     /* Distribut HF memory. */
    247     pMem = hAnalysisHybFilter->pHFmemory;
    248     for (k=0; k<setup->filterDelay; k++) {
    249       hAnalysisHybFilter->bufferHFReal[k] = pMem; pMem += (qmfBands-setup->nrQmfBands);
    250       hAnalysisHybFilter->bufferHFImag[k] = pMem; pMem += (cplxBands-setup->nrQmfBands);
    251     }
    252 
    253     if (initStatesFlag) {
    254       /* Clear LF buffer */
    255       for (k=0; k<setup->nrQmfBands; k++) {
    256         FDKmemclear(hAnalysisHybFilter->bufferLFReal[k], setup->protoLen*sizeof(FIXP_DBL));
    257         FDKmemclear(hAnalysisHybFilter->bufferLFImag[k], setup->protoLen*sizeof(FIXP_DBL));
    258       }
    259 
    260       if (qmfBands > setup->nrQmfBands) {
    261       /* Clear HF buffer */
    262       for (k=0; k<setup->filterDelay; k++) {
    263         FDKmemclear(hAnalysisHybFilter->bufferHFReal[k], (qmfBands-setup->nrQmfBands)*sizeof(FIXP_DBL));
    264         FDKmemclear(hAnalysisHybFilter->bufferHFImag[k], (cplxBands-setup->nrQmfBands)*sizeof(FIXP_DBL));
    265       }
    266     }
    267     }
    268 
    269 bail:
    270     return err;
    271 }
    272 
    273 INT FDKhybridAnalysisScaleStates(
    274         HANDLE_FDK_ANA_HYB_FILTER  hAnalysisHybFilter,
    275         const INT                  scalingValue
    276         )
    277 {
    278     INT err = 0;
    279 
    280     if (hAnalysisHybFilter==NULL) {
    281       err = 1; /* invalid handle */
    282     }
    283     else {
    284       int k;
    285       HANDLE_FDK_HYBRID_SETUP setup = hAnalysisHybFilter->pSetup;
    286 
    287       /* Scale LF buffer */
    288       for (k=0; k<setup->nrQmfBands; k++) {
    289         scaleValues(hAnalysisHybFilter->bufferLFReal[k], setup->protoLen, scalingValue);
    290         scaleValues(hAnalysisHybFilter->bufferLFImag[k], setup->protoLen, scalingValue);
    291       }
    292       if (hAnalysisHybFilter->nrBands > setup->nrQmfBands) {
    293         /* Scale HF buffer */
    294         for (k=0; k<setup->filterDelay; k++) {
    295           scaleValues(hAnalysisHybFilter->bufferHFReal[k], (hAnalysisHybFilter->nrBands-setup->nrQmfBands), scalingValue);
    296           scaleValues(hAnalysisHybFilter->bufferHFImag[k], (hAnalysisHybFilter->cplxBands-setup->nrQmfBands), scalingValue);
    297         }
    298       }
    299     }
    300     return err;
    301 }
    302 
    303 INT FDKhybridAnalysisApply(
    304         HANDLE_FDK_ANA_HYB_FILTER  hAnalysisHybFilter,
    305         const FIXP_DBL *const      pQmfReal,
    306         const FIXP_DBL *const      pQmfImag,
    307         FIXP_DBL *const            pHybridReal,
    308         FIXP_DBL *const            pHybridImag)
    309 {
    310     int k, hybOffset = 0;
    311     INT err = 0;
    312     const int nrQmfBandsLF = hAnalysisHybFilter->pSetup->nrQmfBands; /* number of QMF bands to be converted to hybrid */
    313 
    314     const int writIndex = hAnalysisHybFilter->bufferLFpos;
    315     int readIndex = hAnalysisHybFilter->bufferLFpos;
    316 
    317     if (++readIndex>=hAnalysisHybFilter->pSetup->protoLen) readIndex = 0;
    318     const INT* pBufferLFreadIdx = &hAnalysisHybFilter->pSetup->pReadIdxTable[readIndex];
    319 
    320     /*
    321      * LF buffer.
    322      */
    323     for (k=0; k<nrQmfBandsLF; k++) {
    324         /* New input sample. */
    325         hAnalysisHybFilter->bufferLFReal[k][writIndex] = pQmfReal[k];
    326         hAnalysisHybFilter->bufferLFImag[k][writIndex] = pQmfImag[k];
    327 
    328     /* Perform hybrid filtering. */
    329         kChannelFiltering(
    330                 hAnalysisHybFilter->bufferLFReal[k],
    331                 hAnalysisHybFilter->bufferLFImag[k],
    332                 pBufferLFreadIdx,
    333                 pHybridReal+hybOffset,
    334                 pHybridImag+hybOffset,
    335                 hAnalysisHybFilter->pSetup->kHybrid[k]);
    336 
    337         hybOffset += hAnalysisHybFilter->pSetup->nHybBands[k];
    338     }
    339 
    340     hAnalysisHybFilter->bufferLFpos = readIndex; /* Index where to write next input sample. */
    341 
    342     if (hAnalysisHybFilter->nrBands > nrQmfBandsLF) {
    343     /*
    344      * HF buffer.
    345      */
    346     if (hAnalysisHybFilter->hfMode!=0) {
    347         /* HF delay compensation was applied outside. */
    348         FDKmemcpy(pHybridReal+hybOffset, &pQmfReal[nrQmfBandsLF], (hAnalysisHybFilter->nrBands-nrQmfBandsLF)*sizeof(FIXP_DBL));
    349         FDKmemcpy(pHybridImag+hybOffset, &pQmfImag[nrQmfBandsLF], (hAnalysisHybFilter->cplxBands-nrQmfBandsLF)*sizeof(FIXP_DBL));
    350     }
    351     else {
    352         /* HF delay compensation, filterlength/2. */
    353     FDKmemcpy(pHybridReal+hybOffset, hAnalysisHybFilter->bufferHFReal[hAnalysisHybFilter->bufferHFpos], (hAnalysisHybFilter->nrBands-nrQmfBandsLF)*sizeof(FIXP_DBL));
    354     FDKmemcpy(pHybridImag+hybOffset, hAnalysisHybFilter->bufferHFImag[hAnalysisHybFilter->bufferHFpos], (hAnalysisHybFilter->cplxBands-nrQmfBandsLF)*sizeof(FIXP_DBL));
    355 
    356     FDKmemcpy(hAnalysisHybFilter->bufferHFReal[hAnalysisHybFilter->bufferHFpos], &pQmfReal[nrQmfBandsLF], (hAnalysisHybFilter->nrBands-nrQmfBandsLF)*sizeof(FIXP_DBL));
    357     FDKmemcpy(hAnalysisHybFilter->bufferHFImag[hAnalysisHybFilter->bufferHFpos], &pQmfImag[nrQmfBandsLF], (hAnalysisHybFilter->cplxBands-nrQmfBandsLF)*sizeof(FIXP_DBL));
    358 
    359     if (++hAnalysisHybFilter->bufferHFpos>=hAnalysisHybFilter->pSetup->filterDelay) hAnalysisHybFilter->bufferHFpos = 0;
    360     }
    361     } /* process HF part*/
    362 
    363     return err;
    364 }
    365 
    366 INT FDKhybridAnalysisClose(
    367         HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter
    368         )
    369 {
    370   INT err = 0;
    371 
    372   if (hAnalysisHybFilter != NULL) {
    373     hAnalysisHybFilter->pLFmemory    = NULL;
    374     hAnalysisHybFilter->pHFmemory    = NULL;
    375     hAnalysisHybFilter->LFmemorySize = 0;
    376     hAnalysisHybFilter->HFmemorySize = 0;
    377   }
    378 
    379   return err;
    380 }
    381 
    382 INT FDKhybridSynthesisInit(
    383         HANDLE_FDK_SYN_HYB_FILTER  hSynthesisHybFilter,
    384         const FDK_HYBRID_MODE      mode,
    385         const INT                  qmfBands,
    386         const INT                  cplxBands
    387         )
    388 {
    389     INT err = 0;
    390     HANDLE_FDK_HYBRID_SETUP setup = NULL;
    391 
    392     switch (mode) {
    393       case THREE_TO_TEN:     setup = (HANDLE_FDK_HYBRID_SETUP)&setup_3_10; break;
    394       case THREE_TO_TWELVE:  setup = (HANDLE_FDK_HYBRID_SETUP)&setup_3_12; break;
    395       case THREE_TO_SIXTEEN: setup = (HANDLE_FDK_HYBRID_SETUP)&setup_3_16; break;
    396       default:               err = -1; goto bail;
    397     }
    398 
    399     hSynthesisHybFilter->pSetup      = setup;
    400     hSynthesisHybFilter->nrBands     = qmfBands;
    401     hSynthesisHybFilter->cplxBands   = cplxBands;
    402 
    403 bail:
    404     return err;
    405 }
    406 
    407 
    408 INT FDKhybridSynthesisApply(
    409         HANDLE_FDK_SYN_HYB_FILTER  hSynthesisHybFilter,
    410         const FIXP_DBL *const      pHybridReal,
    411         const FIXP_DBL *const      pHybridImag,
    412         FIXP_DBL *const            pQmfReal,
    413         FIXP_DBL *const            pQmfImag
    414         )
    415 {
    416     int k, n, hybOffset=0;
    417     INT err = 0;
    418     const INT nrQmfBandsLF = hSynthesisHybFilter->pSetup->nrQmfBands;
    419 
    420     /*
    421      * LF buffer.
    422      */
    423     for (k=0; k<nrQmfBandsLF; k++) {
    424       const int nHybBands = hSynthesisHybFilter->pSetup->nHybBands[k];
    425 
    426       FIXP_DBL accu1 = FL2FXCONST_DBL(0.f);
    427       FIXP_DBL accu2 = FL2FXCONST_DBL(0.f);
    428 
    429       /* Perform hybrid filtering. */
    430       for (n=0; n<nHybBands; n++) {
    431           accu1 += pHybridReal[hybOffset+n];
    432           accu2 += pHybridImag[hybOffset+n];
    433       }
    434       pQmfReal[k] = accu1;
    435       pQmfImag[k] = accu2;
    436 
    437       hybOffset += nHybBands;
    438     }
    439 
    440     if (hSynthesisHybFilter->nrBands > nrQmfBandsLF) {
    441       /*
    442        * HF buffer.
    443        */
    444     FDKmemcpy(&pQmfReal[nrQmfBandsLF], &pHybridReal[hybOffset], (hSynthesisHybFilter->nrBands-nrQmfBandsLF)*sizeof(FIXP_DBL));
    445     FDKmemcpy(&pQmfImag[nrQmfBandsLF], &pHybridImag[hybOffset], (hSynthesisHybFilter->cplxBands-nrQmfBandsLF)*sizeof(FIXP_DBL));
    446     }
    447 
    448     return err;
    449 }
    450 
    451 static void dualChannelFiltering(
    452         const FIXP_DBL *const      pQmfReal,
    453         const FIXP_DBL *const      pQmfImag,
    454         const INT *const           pReadIdx,
    455         FIXP_DBL *const            mHybridReal,
    456         FIXP_DBL *const            mHybridImag,
    457         const INT                  invert
    458         )
    459 {
    460     const FIXP_HTB *p = HybFilterCoef2;
    461 
    462     FIXP_DBL  r1, r6;
    463     FIXP_DBL  i1, i6;
    464 
    465     /* symmetric filter coefficients */
    466     r1  = fMultDiv2(p[1], pQmfReal[pReadIdx[1]]) + fMultDiv2(p[1], pQmfReal[pReadIdx[11]]) ;
    467     i1  = fMultDiv2(p[1], pQmfImag[pReadIdx[1]]) + fMultDiv2(p[1], pQmfImag[pReadIdx[11]]) ;
    468     r1 += fMultDiv2(p[3], pQmfReal[pReadIdx[3]]) + fMultDiv2(p[3], pQmfReal[pReadIdx[ 9]]) ;
    469     i1 += fMultDiv2(p[3], pQmfImag[pReadIdx[3]]) + fMultDiv2(p[3], pQmfImag[pReadIdx[ 9]]) ;
    470     r1 += fMultDiv2(p[5], pQmfReal[pReadIdx[5]]) + fMultDiv2(p[5], pQmfReal[pReadIdx[ 7]]) ;
    471     i1 += fMultDiv2(p[5], pQmfImag[pReadIdx[5]]) + fMultDiv2(p[5], pQmfImag[pReadIdx[ 7]]) ;
    472     r6  = fMultDiv2(p[6], pQmfReal[pReadIdx[6]]) ;
    473     i6  = fMultDiv2(p[6], pQmfImag[pReadIdx[6]]) ;
    474 
    475     if (invert) {
    476       mHybridReal[1] = (r1 + r6) << 1;
    477       mHybridImag[1] = (i1 + i6) << 1;
    478 
    479       mHybridReal[0] = (r6 - r1) << 1;
    480       mHybridImag[0] = (i6 - i1) << 1;
    481     }
    482     else {
    483       mHybridReal[0] = (r1 + r6) << 1;
    484       mHybridImag[0] = (i1 + i6) << 1;
    485 
    486       mHybridReal[1] = (r6 - r1) << 1;
    487       mHybridImag[1] = (i6 - i1) << 1;
    488     }
    489 }
    490 
    491 static void fourChannelFiltering(
    492         const FIXP_DBL *const      pQmfReal,
    493         const FIXP_DBL *const      pQmfImag,
    494         const INT *const           pReadIdx,
    495         FIXP_DBL *const            mHybridReal,
    496         FIXP_DBL *const            mHybridImag,
    497         const INT                  invert
    498         )
    499 {
    500     const FIXP_HTB *p = HybFilterCoef4;
    501 
    502     FIXP_DBL fft[8];
    503 
    504     static const FIXP_DBL  cr[13] = {
    505       FL2FXCONST_DBL(               0.f), FL2FXCONST_DBL(-0.70710678118655f), FL2FXCONST_DBL(              -1.f),
    506       FL2FXCONST_DBL(-0.70710678118655f), FL2FXCONST_DBL(               0.f), FL2FXCONST_DBL( 0.70710678118655f),
    507       FL2FXCONST_DBL(               1.f),
    508       FL2FXCONST_DBL( 0.70710678118655f), FL2FXCONST_DBL(               0.f), FL2FXCONST_DBL(-0.70710678118655f),
    509       FL2FXCONST_DBL(              -1.f), FL2FXCONST_DBL(-0.70710678118655f), FL2FXCONST_DBL(               0.f)
    510     };
    511     static const FIXP_DBL  ci[13] = {
    512       FL2FXCONST_DBL(              -1.f), FL2FXCONST_DBL(-0.70710678118655f), FL2FXCONST_DBL(               0.f),
    513       FL2FXCONST_DBL( 0.70710678118655f), FL2FXCONST_DBL(               1.f), FL2FXCONST_DBL( 0.70710678118655f),
    514       FL2FXCONST_DBL(               0.f),
    515       FL2FXCONST_DBL(-0.70710678118655f), FL2FXCONST_DBL(              -1.f), FL2FXCONST_DBL(-0.70710678118655f),
    516       FL2FXCONST_DBL(               0.f), FL2FXCONST_DBL( 0.70710678118655f), FL2FXCONST_DBL(               1.f)
    517     };
    518 
    519 
    520     /* FIR filter. */
    521     /* pre twiddeling with pre-twiddling coefficients c[n]  */
    522     /* multiplication with filter coefficients p[n]         */
    523     /* hint: (a + ib)*(c + id) = (a*c - b*d) + i(a*d + b*c) */
    524     /* write to fft coefficient n'                          */
    525     fft[FFT_IDX_R(0)] =  ( fMult(p[10], ( fMultSub(fMultDiv2(cr[ 2], pQmfReal[pReadIdx[ 2]]), ci[ 2], pQmfImag[pReadIdx[ 2]]))) +
    526                            fMult(p[ 6], ( fMultSub(fMultDiv2(cr[ 6], pQmfReal[pReadIdx[ 6]]), ci[ 6], pQmfImag[pReadIdx[ 6]]))) +
    527                            fMult(p[ 2], ( fMultSub(fMultDiv2(cr[10], pQmfReal[pReadIdx[10]]), ci[10], pQmfImag[pReadIdx[10]]))) );
    528     fft[FFT_IDX_I(0)] =  ( fMult(p[10], ( fMultAdd(fMultDiv2(ci[ 2], pQmfReal[pReadIdx[ 2]]), cr[ 2], pQmfImag[pReadIdx[ 2]]))) +
    529                            fMult(p[ 6], ( fMultAdd(fMultDiv2(ci[ 6], pQmfReal[pReadIdx[ 6]]), cr[ 6], pQmfImag[pReadIdx[ 6]]))) +
    530                            fMult(p[ 2], ( fMultAdd(fMultDiv2(ci[10], pQmfReal[pReadIdx[10]]), cr[10], pQmfImag[pReadIdx[10]]))) );
    531 
    532     /* twiddle dee dum */
    533     fft[FFT_IDX_R(1)] =  ( fMult(p[ 9], ( fMultSub(fMultDiv2(cr[ 3], pQmfReal[pReadIdx[ 3]]), ci[ 3], pQmfImag[pReadIdx[ 3]]))) +
    534                            fMult(p[ 5], ( fMultSub(fMultDiv2(cr[ 7], pQmfReal[pReadIdx[ 7]]), ci[ 7], pQmfImag[pReadIdx[ 7]]))) +
    535                            fMult(p[ 1], ( fMultSub(fMultDiv2(cr[11], pQmfReal[pReadIdx[11]]), ci[11], pQmfImag[pReadIdx[11]]))) );
    536     fft[FFT_IDX_I(1)] =  ( fMult(p[ 9], ( fMultAdd(fMultDiv2(ci[ 3], pQmfReal[pReadIdx[ 3]]), cr[ 3], pQmfImag[pReadIdx[ 3]]))) +
    537                            fMult(p[ 5], ( fMultAdd(fMultDiv2(ci[ 7], pQmfReal[pReadIdx[ 7]]), cr[ 7], pQmfImag[pReadIdx[ 7]]))) +
    538                            fMult(p[ 1], ( fMultAdd(fMultDiv2(ci[11], pQmfReal[pReadIdx[11]]), cr[11], pQmfImag[pReadIdx[11]]))) );
    539 
    540     /* twiddle dee dee */
    541     fft[FFT_IDX_R(2)] =  ( fMult(p[12], ( fMultSub(fMultDiv2(cr[ 0], pQmfReal[pReadIdx[ 0]]), ci[ 0], pQmfImag[pReadIdx[ 0]]))) +
    542                            fMult(p[ 8], ( fMultSub(fMultDiv2(cr[ 4], pQmfReal[pReadIdx[ 4]]), ci[ 4], pQmfImag[pReadIdx[ 4]]))) +
    543                            fMult(p[ 4], ( fMultSub(fMultDiv2(cr[ 8], pQmfReal[pReadIdx[ 8]]), ci[ 8], pQmfImag[pReadIdx[ 8]]))) +
    544                            fMult(p[ 0], ( fMultSub(fMultDiv2(cr[12], pQmfReal[pReadIdx[12]]), ci[12], pQmfImag[pReadIdx[12]]))) );
    545     fft[FFT_IDX_I(2)] =  ( fMult(p[12], ( fMultAdd(fMultDiv2(ci[ 0], pQmfReal[pReadIdx[ 0]]), cr[ 0], pQmfImag[pReadIdx[ 0]]))) +
    546                            fMult(p[ 8], ( fMultAdd(fMultDiv2(ci[ 4], pQmfReal[pReadIdx[ 4]]), cr[ 4], pQmfImag[pReadIdx[ 4]]))) +
    547                            fMult(p[ 4], ( fMultAdd(fMultDiv2(ci[ 8], pQmfReal[pReadIdx[ 8]]), cr[ 8], pQmfImag[pReadIdx[ 8]]))) +
    548                            fMult(p[ 0], ( fMultAdd(fMultDiv2(ci[12], pQmfReal[pReadIdx[12]]), cr[12], pQmfImag[pReadIdx[12]]))) );
    549 
    550     fft[FFT_IDX_R(3)] =  ( fMult(p[11], ( fMultSub(fMultDiv2(cr[ 1], pQmfReal[pReadIdx[ 1]]), ci[ 1], pQmfImag[pReadIdx[ 1]]))) +
    551                            fMult(p[ 7], ( fMultSub(fMultDiv2(cr[ 5], pQmfReal[pReadIdx[ 5]]), ci[ 5], pQmfImag[pReadIdx[ 5]]))) +
    552                            fMult(p[ 3], ( fMultSub(fMultDiv2(cr[ 9], pQmfReal[pReadIdx[ 9]]), ci[ 9], pQmfImag[pReadIdx[ 9]]))) );
    553     fft[FFT_IDX_I(3)] =  ( fMult(p[11], ( fMultAdd(fMultDiv2(ci[ 1], pQmfReal[pReadIdx[ 1]]), cr[ 1], pQmfImag[pReadIdx[ 1]]))) +
    554                            fMult(p[ 7], ( fMultAdd(fMultDiv2(ci[ 5], pQmfReal[pReadIdx[ 5]]), cr[ 5], pQmfImag[pReadIdx[ 5]]))) +
    555                            fMult(p[ 3], ( fMultAdd(fMultDiv2(ci[ 9], pQmfReal[pReadIdx[ 9]]), cr[ 9], pQmfImag[pReadIdx[ 9]]))) );
    556 
    557     /* fft modulation                                                    */
    558     /* here: fast manual fft modulation for a fft of length M=4          */
    559     /* fft_4{x[n]} = x[0]*exp(-i*2*pi/4*m*0) + x[1]*exp(-i*2*pi/4*m*1) +
    560     x[2]*exp(-i*2*pi/4*m*2) + x[3]*exp(-i*2*pi/4*m*3)   */
    561 
    562     /*
    563     fft bin m=0:
    564     X[0, n] = x[0] +   x[1] + x[2] +   x[3]
    565     */
    566     mHybridReal[0] = fft[FFT_IDX_R(0)] + fft[FFT_IDX_R(1)] + fft[FFT_IDX_R(2)] + fft[FFT_IDX_R(3)];
    567     mHybridImag[0] = fft[FFT_IDX_I(0)] + fft[FFT_IDX_I(1)] + fft[FFT_IDX_I(2)] + fft[FFT_IDX_I(3)];
    568 
    569     /*
    570     fft bin m=1:
    571     X[1, n] = x[0] - i*x[1] - x[2] + i*x[3]
    572     */
    573     mHybridReal[1] = fft[FFT_IDX_R(0)] + fft[FFT_IDX_I(1)] - fft[FFT_IDX_R(2)] - fft[FFT_IDX_I(3)];
    574     mHybridImag[1] = fft[FFT_IDX_I(0)] - fft[FFT_IDX_R(1)] - fft[FFT_IDX_I(2)] + fft[FFT_IDX_R(3)];
    575 
    576     /*
    577     fft bin m=2:
    578     X[2, n] = x[0] -   x[1] + x[2] -   x[3]
    579     */
    580     mHybridReal[2] = fft[FFT_IDX_R(0)] - fft[FFT_IDX_R(1)] + fft[FFT_IDX_R(2)] - fft[FFT_IDX_R(3)];
    581     mHybridImag[2] = fft[FFT_IDX_I(0)] - fft[FFT_IDX_I(1)] + fft[FFT_IDX_I(2)] - fft[FFT_IDX_I(3)];
    582 
    583     /*
    584     fft bin m=3:
    585     X[3, n] = x[0] + j*x[1] - x[2] - j*x[3]
    586     */
    587     mHybridReal[3] = fft[FFT_IDX_R(0)] - fft[FFT_IDX_I(1)] - fft[FFT_IDX_R(2)] + fft[FFT_IDX_I(3)];
    588     mHybridImag[3] = fft[FFT_IDX_I(0)] + fft[FFT_IDX_R(1)] - fft[FFT_IDX_I(2)] - fft[FFT_IDX_R(3)];
    589 }
    590 
    591 
    592 static void eightChannelFiltering(
    593         const FIXP_DBL *const      pQmfReal,
    594         const FIXP_DBL *const      pQmfImag,
    595         const INT *const           pReadIdx,
    596         FIXP_DBL *const            mHybridReal,
    597         FIXP_DBL *const            mHybridImag,
    598         const INT                  invert
    599         )
    600 {
    601     const FIXP_HTP *p = HybFilterCoef8;
    602     INT k, sc;
    603 
    604     FIXP_DBL mfft[16+ALIGNMENT_DEFAULT];
    605     FIXP_DBL *pfft = (FIXP_DBL*)ALIGN_PTR(mfft);
    606 
    607     FIXP_DBL accu1, accu2, accu3, accu4;
    608 
    609     /* pre twiddeling */
    610     pfft[FFT_IDX_R(0)] = fMultDiv2(p[0].v.re, pQmfReal[pReadIdx[6]]);
    611     pfft[FFT_IDX_I(0)] = fMultDiv2(p[0].v.re, pQmfImag[pReadIdx[6]]);
    612 
    613     cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[7]], pQmfImag[pReadIdx[7]], p[1]);
    614     pfft[FFT_IDX_R(1)] = accu1;
    615     pfft[FFT_IDX_I(1)] = accu2;
    616 
    617     cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[0]], pQmfImag[pReadIdx[0]], p[2]);
    618     cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[8]], pQmfImag[pReadIdx[8]], p[3]);
    619     pfft[FFT_IDX_R(2)] = accu1 + accu3;
    620     pfft[FFT_IDX_I(2)] = accu2 + accu4;
    621 
    622     cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[1]], pQmfImag[pReadIdx[1]], p[4]);
    623     cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[9]], pQmfImag[pReadIdx[9]], p[5]);
    624     pfft[FFT_IDX_R(3)] = accu1 + accu3;
    625     pfft[FFT_IDX_I(3)] = accu2 + accu4;
    626 
    627     pfft[FFT_IDX_R(4)] = fMultDiv2(pQmfImag[pReadIdx[10]], p[7].v.im) - fMultDiv2(pQmfImag[pReadIdx[ 2]], p[6].v.im);
    628     pfft[FFT_IDX_I(4)] = fMultDiv2(pQmfReal[pReadIdx[ 2]], p[6].v.im) - fMultDiv2(pQmfReal[pReadIdx[10]], p[7].v.im);
    629 
    630     cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[ 3]], pQmfImag[pReadIdx[ 3]], p[8]);
    631     cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[11]], pQmfImag[pReadIdx[11]], p[9]);
    632     pfft[FFT_IDX_R(5)] = accu1 + accu3;
    633     pfft[FFT_IDX_I(5)] = accu2 + accu4;
    634 
    635     cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[ 4]], pQmfImag[pReadIdx[ 4]], p[10]);
    636     cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[12]], pQmfImag[pReadIdx[12]], p[11]);
    637     pfft[FFT_IDX_R(6)] = accu1 + accu3;
    638     pfft[FFT_IDX_I(6)] = accu2 + accu4;
    639 
    640     cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[ 5]], pQmfImag[pReadIdx[ 5]], p[12]);
    641     pfft[FFT_IDX_R(7)] = accu1;
    642     pfft[FFT_IDX_I(7)] = accu2;
    643 
    644     /* fft modulation */
    645     fft_8 (pfft);
    646     sc = 1 + 2;
    647 
    648     if (invert) {
    649       mHybridReal[0]  = pfft[FFT_IDX_R(7)] << sc;
    650       mHybridImag[0]  = pfft[FFT_IDX_I(7)] << sc;
    651       mHybridReal[1]  = pfft[FFT_IDX_R(0)] << sc;
    652       mHybridImag[1]  = pfft[FFT_IDX_I(0)] << sc;
    653 
    654       mHybridReal[2]  = pfft[FFT_IDX_R(6)] << sc;
    655       mHybridImag[2]  = pfft[FFT_IDX_I(6)] << sc;
    656       mHybridReal[3]  = pfft[FFT_IDX_R(1)] << sc;
    657       mHybridImag[3]  = pfft[FFT_IDX_I(1)] << sc;
    658 
    659       mHybridReal[4]  = pfft[FFT_IDX_R(2)] << sc;
    660       mHybridReal[4] += pfft[FFT_IDX_R(5)] << sc;
    661       mHybridImag[4]  = pfft[FFT_IDX_I(2)] << sc;
    662       mHybridImag[4] += pfft[FFT_IDX_I(5)] << sc;
    663 
    664       mHybridReal[5]  = pfft[FFT_IDX_R(3)] << sc;
    665       mHybridReal[5] += pfft[FFT_IDX_R(4)] << sc;
    666       mHybridImag[5]  = pfft[FFT_IDX_I(3)] << sc;
    667       mHybridImag[5] += pfft[FFT_IDX_I(4)] << sc;
    668     }
    669     else {
    670       for(k=0; k<8;k++ ) {
    671         mHybridReal[k] = pfft[FFT_IDX_R(k)] << sc;
    672         mHybridImag[k] = pfft[FFT_IDX_I(k)] << sc;
    673       }
    674     }
    675 }
    676 
    677 static INT kChannelFiltering(
    678         const FIXP_DBL *const      pQmfReal,
    679         const FIXP_DBL *const      pQmfImag,
    680         const INT *const           pReadIdx,
    681         FIXP_DBL *const            mHybridReal,
    682         FIXP_DBL *const            mHybridImag,
    683         const SCHAR                hybridConfig
    684         )
    685 {
    686     INT err = 0;
    687 
    688     switch (hybridConfig) {
    689       case  2:
    690       case -2:
    691         dualChannelFiltering(pQmfReal, pQmfImag, pReadIdx, mHybridReal, mHybridImag, (hybridConfig<0) ? 1 : 0 );
    692         break;
    693       case  4:
    694       case -4:
    695         fourChannelFiltering(pQmfReal, pQmfImag, pReadIdx, mHybridReal, mHybridImag, (hybridConfig<0) ? 1 : 0 );
    696         break;
    697       case  8:
    698       case -8:
    699         eightChannelFiltering(pQmfReal, pQmfImag, pReadIdx, mHybridReal, mHybridImag, (hybridConfig<0) ? 1 : 0 );
    700         break;
    701       default:
    702         err = -1;
    703     }
    704 
    705     return err;
    706 }
    707 
    708 
    709 
    710