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