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):   Matthias Hildenbrand
     98 
     99    Description: Module to efficiently handle QMF data for multiple channels and
    100                 to share the data between e.g. SBR and MPS
    101 
    102 *******************************************************************************/
    103 
    104 #include "FDK_qmf_domain.h"
    105 
    106 #include "common_fix.h"
    107 
    108 #define WORKBUFFER1_TAG 0
    109 #define WORKBUFFER2_TAG 1
    110 
    111 #define WORKBUFFER3_TAG 4
    112 #define WORKBUFFER4_TAG 5
    113 #define WORKBUFFER5_TAG 6
    114 #define WORKBUFFER6_TAG 7
    115 
    116 C_ALLOC_MEM_OVERLAY(QmfWorkBufferCore1, FIXP_DBL, QMF_WB_SECTION_SIZE,
    117                     SECT_DATA_L1, WORKBUFFER1_TAG)
    118 C_ALLOC_MEM_OVERLAY(QmfWorkBufferCore2, FIXP_DBL, QMF_WB_SECTION_SIZE,
    119                     SECT_DATA_L2, WORKBUFFER2_TAG)
    120 C_ALLOC_MEM_OVERLAY(QmfWorkBufferCore3, FIXP_DBL, QMF_WB_SECTION_SIZE,
    121                     SECT_DATA_L2, WORKBUFFER3_TAG)
    122 C_ALLOC_MEM_OVERLAY(QmfWorkBufferCore4, FIXP_DBL, QMF_WB_SECTION_SIZE,
    123                     SECT_DATA_L2, WORKBUFFER4_TAG)
    124 C_ALLOC_MEM_OVERLAY(QmfWorkBufferCore5, FIXP_DBL, QMF_WB_SECTION_SIZE,
    125                     SECT_DATA_L2, WORKBUFFER5_TAG)
    126 C_ALLOC_MEM_OVERLAY(QmfWorkBufferCore6, FIXP_DBL, QMF_WB_SECTION_SIZE,
    127                     SECT_DATA_L2, WORKBUFFER6_TAG)
    128 
    129 /*! Analysis states buffer. <br>
    130     Dimension: #((8) + (1))                                                   */
    131 C_ALLOC_MEM2(AnaQmfStates, FIXP_QAS, 10 * QMF_DOMAIN_MAX_ANALYSIS_QMF_BANDS,
    132              ((8) + (1)))
    133 
    134 /*! Synthesis states buffer. <br>
    135     Dimension: #((8) + (1))                                                  */
    136 C_ALLOC_MEM2(SynQmfStates, FIXP_QSS, 9 * QMF_DOMAIN_MAX_SYNTHESIS_QMF_BANDS,
    137              ((8) + (1)))
    138 
    139 /*! Pointer to real qmf data for each time slot. <br>
    140     Dimension: #((8) + (1))                                                   */
    141 C_ALLOC_MEM2(QmfSlotsReal, FIXP_DBL *,
    142              QMF_DOMAIN_MAX_TIMESLOTS + QMF_DOMAIN_MAX_OV_TIMESLOTS,
    143              ((8) + (1)))
    144 
    145 /*! Pointer to imaginary qmf data for each time slot. <br>
    146     Dimension: #((8) + (1))                                                   */
    147 C_ALLOC_MEM2(QmfSlotsImag, FIXP_DBL *,
    148              QMF_DOMAIN_MAX_TIMESLOTS + QMF_DOMAIN_MAX_OV_TIMESLOTS,
    149              ((8) + (1)))
    150 
    151 /*! QMF overlap buffer. <br>
    152     Dimension: #((8) + (1))                                                   */
    153 C_AALLOC_MEM2(QmfOverlapBuffer, FIXP_DBL,
    154               2 * QMF_DOMAIN_MAX_OV_TIMESLOTS * QMF_DOMAIN_MAX_QMF_PROC_BANDS,
    155               ((8) + (1)))
    156 
    157 /*! Analysis states buffer. <br>
    158     Dimension: #((8) + (1))                                                   */
    159 C_ALLOC_MEM2(AnaQmfStates16, FIXP_QAS, 10 * QMF_DOMAIN_ANALYSIS_QMF_BANDS_16,
    160              ((8) + (1)))
    161 
    162 /*! Analysis states buffer. <br>
    163     Dimension: #((8) + (1))                                                   */
    164 C_ALLOC_MEM2(AnaQmfStates24, FIXP_QAS, 10 * QMF_DOMAIN_ANALYSIS_QMF_BANDS_24,
    165              ((8) + (1)))
    166 
    167 /*! Analysis states buffer. <br>
    168     Dimension: #((8) + (1))                                                   */
    169 C_ALLOC_MEM2(AnaQmfStates32, FIXP_QAS, 10 * QMF_DOMAIN_ANALYSIS_QMF_BANDS_32,
    170              ((8) + (1)))
    171 
    172 /*! Pointer to real qmf data for each time slot. <br>
    173     Dimension: #((8) + (1))                                                   */
    174 C_ALLOC_MEM2(QmfSlotsReal16, FIXP_DBL *,
    175              QMF_DOMAIN_TIMESLOTS_16 + QMF_DOMAIN_OV_TIMESLOTS_16, ((8) + (1)))
    176 
    177 /*! Pointer to real qmf data for each time slot. <br>
    178     Dimension: #((8) + (1))                                                   */
    179 C_ALLOC_MEM2(QmfSlotsReal32, FIXP_DBL *,
    180              QMF_DOMAIN_TIMESLOTS_32 + QMF_DOMAIN_OV_TIMESLOTS_32, ((8) + (1)))
    181 
    182 /*! Pointer to imaginary qmf data for each time slot. <br>
    183     Dimension: #((8) + (1))                                                   */
    184 C_ALLOC_MEM2(QmfSlotsImag16, FIXP_DBL *,
    185              QMF_DOMAIN_TIMESLOTS_16 + QMF_DOMAIN_OV_TIMESLOTS_16, ((8) + (1)))
    186 
    187 /*! Pointer to imaginary qmf data for each time slot. <br>
    188     Dimension: #((8) + (1))                                                   */
    189 C_ALLOC_MEM2(QmfSlotsImag32, FIXP_DBL *,
    190              QMF_DOMAIN_TIMESLOTS_32 + QMF_DOMAIN_OV_TIMESLOTS_32, ((8) + (1)))
    191 
    192 /*! QMF overlap buffer. <br>
    193     Dimension: #((8) + (1))                                                   */
    194 C_AALLOC_MEM2(QmfOverlapBuffer16, FIXP_DBL,
    195               2 * QMF_DOMAIN_OV_TIMESLOTS_16 * QMF_DOMAIN_MAX_QMF_PROC_BANDS,
    196               ((8) + (1)))
    197 
    198 /*! QMF overlap buffer. <br>
    199     Dimension: #((8) + (1))                                                   */
    200 C_AALLOC_MEM2(QmfOverlapBuffer32, FIXP_DBL,
    201               2 * QMF_DOMAIN_OV_TIMESLOTS_32 * QMF_DOMAIN_MAX_QMF_PROC_BANDS,
    202               ((8) + (1)))
    203 
    204 static int FDK_QmfDomain_FreePersistentMemory(HANDLE_FDK_QMF_DOMAIN qd) {
    205   int err = 0;
    206   int ch;
    207 
    208   for (ch = 0; ch < ((8) + (1)); ch++) {
    209     if (qd->QmfDomainIn[ch].pAnaQmfStates) {
    210       if (qd->globalConf.nBandsAnalysis == QMF_DOMAIN_ANALYSIS_QMF_BANDS_16) {
    211         FreeAnaQmfStates16(&qd->QmfDomainIn[ch].pAnaQmfStates);
    212       } else if (qd->globalConf.nBandsAnalysis ==
    213                  QMF_DOMAIN_ANALYSIS_QMF_BANDS_24) {
    214         FreeAnaQmfStates24(&qd->QmfDomainIn[ch].pAnaQmfStates);
    215       } else if (qd->globalConf.nBandsAnalysis ==
    216                  QMF_DOMAIN_ANALYSIS_QMF_BANDS_32) {
    217         FreeAnaQmfStates32(&qd->QmfDomainIn[ch].pAnaQmfStates);
    218       } else {
    219         FreeAnaQmfStates(&qd->QmfDomainIn[ch].pAnaQmfStates);
    220       }
    221     }
    222 
    223     if (qd->QmfDomainIn[ch].pOverlapBuffer) {
    224       if (qd->globalConf.nQmfOvTimeSlots == QMF_DOMAIN_OV_TIMESLOTS_16) {
    225         FreeQmfOverlapBuffer16(&qd->QmfDomainIn[ch].pOverlapBuffer);
    226       } else if (qd->globalConf.nQmfOvTimeSlots == QMF_DOMAIN_OV_TIMESLOTS_32) {
    227         FreeQmfOverlapBuffer32(&qd->QmfDomainIn[ch].pOverlapBuffer);
    228       } else {
    229         FreeQmfOverlapBuffer(&qd->QmfDomainIn[ch].pOverlapBuffer);
    230       }
    231     }
    232 
    233     if (qd->QmfDomainIn[ch].hQmfSlotsReal) {
    234       if (qd->globalConf.nQmfTimeSlots == QMF_DOMAIN_TIMESLOTS_16) {
    235         FreeQmfSlotsReal16(&qd->QmfDomainIn[ch].hQmfSlotsReal);
    236       } else if (qd->globalConf.nQmfTimeSlots == QMF_DOMAIN_TIMESLOTS_32) {
    237         FreeQmfSlotsReal32(&qd->QmfDomainIn[ch].hQmfSlotsReal);
    238       } else {
    239         FreeQmfSlotsReal(&qd->QmfDomainIn[ch].hQmfSlotsReal);
    240       }
    241     }
    242 
    243     if (qd->QmfDomainIn[ch].hQmfSlotsImag) {
    244       if (qd->globalConf.nQmfTimeSlots == QMF_DOMAIN_TIMESLOTS_16) {
    245         FreeQmfSlotsImag16(&qd->QmfDomainIn[ch].hQmfSlotsImag);
    246       }
    247       if (qd->globalConf.nQmfTimeSlots == QMF_DOMAIN_TIMESLOTS_32) {
    248         FreeQmfSlotsImag32(&qd->QmfDomainIn[ch].hQmfSlotsImag);
    249       } else {
    250         FreeQmfSlotsImag(&qd->QmfDomainIn[ch].hQmfSlotsImag);
    251       }
    252     }
    253   }
    254 
    255   for (ch = 0; ch < ((8) + (1)); ch++) {
    256     if (qd->QmfDomainOut[ch].pSynQmfStates) {
    257       FreeSynQmfStates(&qd->QmfDomainOut[ch].pSynQmfStates);
    258     }
    259   }
    260 
    261   return err;
    262 }
    263 
    264 static int FDK_QmfDomain_AllocatePersistentMemory(HANDLE_FDK_QMF_DOMAIN qd) {
    265   int err = 0;
    266   int ch;
    267   HANDLE_FDK_QMF_DOMAIN_GC gc = &qd->globalConf;
    268 
    269   if ((gc->nInputChannels > ((8) + (1))) || (gc->nOutputChannels > ((8) + (1))))
    270     return err = 1;
    271   for (ch = 0; ch < gc->nInputChannels; ch++) {
    272     int size;
    273 
    274     size = gc->nBandsAnalysis * 10;
    275     if (size > 0) {
    276       if (gc->nBandsAnalysis == QMF_DOMAIN_ANALYSIS_QMF_BANDS_16) {
    277         if (qd->QmfDomainIn[ch].pAnaQmfStates == NULL) {
    278           if (NULL ==
    279               (qd->QmfDomainIn[ch].pAnaQmfStates = GetAnaQmfStates16(ch)))
    280             goto bail;
    281         }
    282       } else if (gc->nBandsAnalysis == QMF_DOMAIN_ANALYSIS_QMF_BANDS_24) {
    283         if (qd->QmfDomainIn[ch].pAnaQmfStates == NULL) {
    284           if (NULL ==
    285               (qd->QmfDomainIn[ch].pAnaQmfStates = GetAnaQmfStates24(ch)))
    286             goto bail;
    287         }
    288       } else if (gc->nBandsAnalysis == QMF_DOMAIN_ANALYSIS_QMF_BANDS_32) {
    289         if (qd->QmfDomainIn[ch].pAnaQmfStates == NULL) {
    290           if (NULL ==
    291               (qd->QmfDomainIn[ch].pAnaQmfStates = GetAnaQmfStates32(ch)))
    292             goto bail;
    293         }
    294       } else {
    295         if (qd->QmfDomainIn[ch].pAnaQmfStates == NULL) {
    296           if (NULL == (qd->QmfDomainIn[ch].pAnaQmfStates = GetAnaQmfStates(ch)))
    297             goto bail;
    298         }
    299       }
    300     } else {
    301       qd->QmfDomainIn[ch].pAnaQmfStates = NULL;
    302     }
    303 
    304     size = gc->nQmfOvTimeSlots + gc->nQmfTimeSlots;
    305     if (size > 0) {
    306       if (gc->nQmfTimeSlots == QMF_DOMAIN_TIMESLOTS_16) {
    307         if (qd->QmfDomainIn[ch].hQmfSlotsReal == NULL) {
    308           if (NULL ==
    309               (qd->QmfDomainIn[ch].hQmfSlotsReal = GetQmfSlotsReal16(ch)))
    310             goto bail;
    311         }
    312         if (qd->QmfDomainIn[ch].hQmfSlotsImag == NULL) {
    313           if (NULL ==
    314               (qd->QmfDomainIn[ch].hQmfSlotsImag = GetQmfSlotsImag16(ch)))
    315             goto bail;
    316         }
    317       } else if (gc->nQmfTimeSlots == QMF_DOMAIN_TIMESLOTS_32) {
    318         if (qd->QmfDomainIn[ch].hQmfSlotsReal == NULL) {
    319           if (NULL ==
    320               (qd->QmfDomainIn[ch].hQmfSlotsReal = GetQmfSlotsReal32(ch)))
    321             goto bail;
    322         }
    323         if (qd->QmfDomainIn[ch].hQmfSlotsImag == NULL) {
    324           if (NULL ==
    325               (qd->QmfDomainIn[ch].hQmfSlotsImag = GetQmfSlotsImag32(ch)))
    326             goto bail;
    327         }
    328       } else {
    329         if (qd->QmfDomainIn[ch].hQmfSlotsReal == NULL) {
    330           if (NULL == (qd->QmfDomainIn[ch].hQmfSlotsReal = GetQmfSlotsReal(ch)))
    331             goto bail;
    332         }
    333         if (qd->QmfDomainIn[ch].hQmfSlotsImag == NULL) {
    334           if (NULL == (qd->QmfDomainIn[ch].hQmfSlotsImag = GetQmfSlotsImag(ch)))
    335             goto bail;
    336         }
    337       }
    338     } else {
    339       qd->QmfDomainIn[ch].hQmfSlotsReal = NULL;
    340       qd->QmfDomainIn[ch].hQmfSlotsImag = NULL;
    341     }
    342 
    343     size = gc->nQmfOvTimeSlots * gc->nQmfProcBands * CMPLX_MOD;
    344     if (size > 0) {
    345       if (gc->nQmfOvTimeSlots == QMF_DOMAIN_OV_TIMESLOTS_16) {
    346         if (qd->QmfDomainIn[ch].pOverlapBuffer == NULL) {
    347           if (NULL ==
    348               (qd->QmfDomainIn[ch].pOverlapBuffer = GetQmfOverlapBuffer16(ch)))
    349             goto bail;
    350         }
    351       } else if (gc->nQmfOvTimeSlots == QMF_DOMAIN_OV_TIMESLOTS_32) {
    352         if (qd->QmfDomainIn[ch].pOverlapBuffer == NULL) {
    353           if (NULL ==
    354               (qd->QmfDomainIn[ch].pOverlapBuffer = GetQmfOverlapBuffer32(ch)))
    355             goto bail;
    356         }
    357       } else {
    358         if (qd->QmfDomainIn[ch].pOverlapBuffer == NULL) {
    359           if (NULL ==
    360               (qd->QmfDomainIn[ch].pOverlapBuffer = GetQmfOverlapBuffer(ch)))
    361             goto bail;
    362         }
    363       }
    364     } else {
    365       qd->QmfDomainIn[ch].pOverlapBuffer = NULL;
    366     }
    367   }
    368 
    369   for (ch = 0; ch < gc->nOutputChannels; ch++) {
    370     int size = gc->nBandsSynthesis * 9;
    371     if (size > 0) {
    372       if (qd->QmfDomainOut[ch].pSynQmfStates == NULL) {
    373         if (NULL == (qd->QmfDomainOut[ch].pSynQmfStates = GetSynQmfStates(ch)))
    374           goto bail;
    375       }
    376     } else {
    377       qd->QmfDomainOut[ch].pSynQmfStates = NULL;
    378     }
    379   }
    380 
    381   return err;
    382 
    383 bail:
    384   FDK_QmfDomain_FreePersistentMemory(qd);
    385   return -1;
    386 }
    387 
    388 QMF_DOMAIN_ERROR FDK_QmfDomain_ClearPersistentMemory(
    389     HANDLE_FDK_QMF_DOMAIN hqd) {
    390   QMF_DOMAIN_ERROR err = QMF_DOMAIN_OK;
    391   int ch, size;
    392   if (hqd) {
    393     HANDLE_FDK_QMF_DOMAIN_GC gc = &hqd->globalConf;
    394 
    395     size = gc->nQmfOvTimeSlots * gc->nQmfProcBands * CMPLX_MOD;
    396     for (ch = 0; ch < gc->nInputChannels; ch++) {
    397       if (hqd->QmfDomainIn[ch].pOverlapBuffer) {
    398         FDKmemclear(hqd->QmfDomainIn[ch].pOverlapBuffer,
    399                     size * sizeof(FIXP_DBL));
    400       }
    401     }
    402     if (FDK_QmfDomain_InitFilterBank(hqd, 0)) {
    403       err = QMF_DOMAIN_INIT_ERROR;
    404     }
    405   } else {
    406     err = QMF_DOMAIN_INIT_ERROR;
    407   }
    408   return err;
    409 }
    410 
    411 /*
    412    FDK_getWorkBuffer
    413 
    414     Parameters:
    415 
    416     pWorkBuffer        i: array of pointers which point to different workbuffer
    417    sections workBufferOffset   i: offset in the workbuffer to the requested
    418    memory memSize            i: size of requested memory
    419 
    420     Function:
    421 
    422     The functions returns the address to the requested memory in the workbuffer.
    423 
    424     The overall workbuffer is divided into several sections. There are
    425    QMF_MAX_WB_SECTIONS sections of size QMF_WB_SECTION_SIZE. The function
    426    selects the workbuffer section with the help of the workBufferOffset and than
    427    it verifies whether the requested amount of memory fits into the selected
    428    workbuffer section.
    429 
    430     Returns:
    431 
    432     address to workbuffer
    433 */
    434 static FIXP_DBL *FDK_getWorkBuffer(FIXP_DBL **pWorkBuffer,
    435                                    USHORT workBufferOffset,
    436                                    USHORT workBufferSectSize, USHORT memSize) {
    437   int idx1;
    438   int idx2;
    439   FIXP_DBL *pwb;
    440 
    441   /* a section must be a multiple of the number of processing bands (currently
    442    * always 64) */
    443   FDK_ASSERT((workBufferSectSize % 64) == 0);
    444 
    445   /* calculate offset within the section */
    446   idx2 = workBufferOffset % workBufferSectSize;
    447   /* calculate section number */
    448   idx1 = (workBufferOffset - idx2) / workBufferSectSize;
    449   /* maximum sectionnumber is QMF_MAX_WB_SECTIONS */
    450   FDK_ASSERT(idx1 < QMF_MAX_WB_SECTIONS);
    451 
    452   /* check, whether workbuffer is available  */
    453   FDK_ASSERT(pWorkBuffer[idx1] != NULL);
    454 
    455   /* check, whether buffer fits into selected section */
    456   FDK_ASSERT((idx2 + memSize) <= workBufferSectSize);
    457 
    458   /* get requested address to workbuffer */
    459   pwb = &pWorkBuffer[idx1][idx2];
    460 
    461   return pwb;
    462 }
    463 
    464 static int FDK_QmfDomain_FeedWorkBuffer(HANDLE_FDK_QMF_DOMAIN qd, int ch,
    465                                         FIXP_DBL **pWorkBuffer,
    466                                         USHORT workBufferOffset,
    467                                         USHORT workBufferSectSize, int size) {
    468   int err = 0;
    469   int mem_needed;
    470 
    471   mem_needed = qd->QmfDomainIn[ch].workBuf_nBands *
    472                qd->QmfDomainIn[ch].workBuf_nTimeSlots * CMPLX_MOD;
    473   if (mem_needed > size) {
    474     return (err = 1);
    475   }
    476   qd->QmfDomainIn[ch].pWorkBuffer = pWorkBuffer;
    477   qd->QmfDomainIn[ch].workBufferOffset = workBufferOffset;
    478   qd->QmfDomainIn[ch].workBufferSectSize = workBufferSectSize;
    479 
    480   return err;
    481 }
    482 
    483 int FDK_QmfDomain_IsInitialized(const HANDLE_FDK_QMF_DOMAIN qd) {
    484   FDK_ASSERT(qd != NULL);
    485   return ((qd->QmfDomainIn[0].pAnaQmfStates == NULL) &&
    486           (qd->QmfDomainOut[0].pSynQmfStates == NULL))
    487              ? 0
    488              : 1;
    489 }
    490 
    491 int FDK_QmfDomain_InitFilterBank(HANDLE_FDK_QMF_DOMAIN qd, UINT extra_flags) {
    492   FDK_ASSERT(qd != NULL);
    493   int err = 0;
    494   int ch, ts;
    495   HANDLE_FDK_QMF_DOMAIN_GC gc = &qd->globalConf;
    496   int noCols = gc->nQmfTimeSlots;
    497   int lsb = gc->nBandsAnalysis;
    498   int usb = fMin((INT)gc->nBandsSynthesis, 64);
    499   int nProcBands = gc->nQmfProcBands;
    500   FDK_ASSERT(nProcBands % ALIGNMENT_DEFAULT == 0);
    501 
    502   if (extra_flags & QMF_FLAG_MPSLDFB) {
    503     gc->flags &= ~QMF_FLAG_CLDFB;
    504     gc->flags |= QMF_FLAG_MPSLDFB;
    505   }
    506   for (ch = 0; ch < gc->nInputChannels; ch++) {
    507     /* distribute memory to slots array */
    508     FIXP_DBL *ptrOv =
    509         qd->QmfDomainIn[ch].pOverlapBuffer; /* persistent memory for overlap */
    510     if ((ptrOv == NULL) && (gc->nQmfOvTimeSlots != 0)) {
    511       err = 1;
    512       return err;
    513     }
    514     /* This assumes the workbuffer defined for ch0 is the big one being used to
    515      * hold one full frame of QMF data. */
    516     FIXP_DBL **ptr =
    517         qd->QmfDomainIn[fMin(ch, fMax((INT)gc->nQmfProcChannels - 1, 0))]
    518             .pWorkBuffer; /* non-persistent workbuffer */
    519     USHORT workBufferOffset =
    520         qd->QmfDomainIn[fMin(ch, fMax((INT)gc->nQmfProcChannels - 1, 0))]
    521             .workBufferOffset;
    522     USHORT workBufferSectSize =
    523         qd->QmfDomainIn[fMin(ch, fMax((INT)gc->nQmfProcChannels - 1, 0))]
    524             .workBufferSectSize;
    525 
    526     if ((ptr == NULL) && (gc->nQmfTimeSlots != 0)) {
    527       err = 1;
    528       return err;
    529     }
    530 
    531     qd->QmfDomainIn[ch].pGlobalConf = gc;
    532     for (ts = 0; ts < gc->nQmfOvTimeSlots; ts++) {
    533       qd->QmfDomainIn[ch].hQmfSlotsReal[ts] = ptrOv;
    534       ptrOv += nProcBands;
    535       qd->QmfDomainIn[ch].hQmfSlotsImag[ts] = ptrOv;
    536       ptrOv += nProcBands;
    537     }
    538     for (; ts < (gc->nQmfOvTimeSlots + gc->nQmfTimeSlots); ts++) {
    539       qd->QmfDomainIn[ch].hQmfSlotsReal[ts] = FDK_getWorkBuffer(
    540           ptr, workBufferOffset, workBufferSectSize, nProcBands);
    541       workBufferOffset += nProcBands;
    542       qd->QmfDomainIn[ch].hQmfSlotsImag[ts] = FDK_getWorkBuffer(
    543           ptr, workBufferOffset, workBufferSectSize, nProcBands);
    544       workBufferOffset += nProcBands;
    545     }
    546     err |= qmfInitAnalysisFilterBank(
    547         &qd->QmfDomainIn[ch].fb, qd->QmfDomainIn[ch].pAnaQmfStates, noCols,
    548         (qd->QmfDomainIn[ch].fb.lsb == 0) ? lsb : qd->QmfDomainIn[ch].fb.lsb,
    549         (qd->QmfDomainIn[ch].fb.usb == 0) ? usb : qd->QmfDomainIn[ch].fb.usb,
    550         gc->nBandsAnalysis, gc->flags | extra_flags);
    551   }
    552 
    553   for (ch = 0; ch < gc->nOutputChannels; ch++) {
    554     FIXP_DBL outGain_m = qd->QmfDomainOut[ch].fb.outGain_m;
    555     int outGain_e = qd->QmfDomainOut[ch].fb.outGain_e;
    556     int outScale = qmfGetOutScalefactor(&qd->QmfDomainOut[ch].fb);
    557     err |= qmfInitSynthesisFilterBank(
    558         &qd->QmfDomainOut[ch].fb, qd->QmfDomainOut[ch].pSynQmfStates, noCols,
    559         (qd->QmfDomainOut[ch].fb.lsb == 0) ? lsb : qd->QmfDomainOut[ch].fb.lsb,
    560         (qd->QmfDomainOut[ch].fb.usb == 0) ? usb : qd->QmfDomainOut[ch].fb.usb,
    561         gc->nBandsSynthesis, gc->flags | extra_flags);
    562     if (outGain_m != (FIXP_DBL)0) {
    563       qmfChangeOutGain(&qd->QmfDomainOut[ch].fb, outGain_m, outGain_e);
    564     }
    565     if (outScale) {
    566       qmfChangeOutScalefactor(&qd->QmfDomainOut[ch].fb, outScale);
    567     }
    568   }
    569 
    570   return err;
    571 }
    572 
    573 void FDK_QmfDomain_SaveOverlap(HANDLE_FDK_QMF_DOMAIN_IN qd_ch, int offset) {
    574   FDK_ASSERT(qd_ch != NULL);
    575   int ts;
    576   HANDLE_FDK_QMF_DOMAIN_GC gc = qd_ch->pGlobalConf;
    577   int ovSlots = gc->nQmfOvTimeSlots;
    578   int nCols = gc->nQmfTimeSlots;
    579   int nProcBands = gc->nQmfProcBands;
    580   FIXP_DBL **qmfReal = qd_ch->hQmfSlotsReal;
    581   FIXP_DBL **qmfImag = qd_ch->hQmfSlotsImag;
    582   QMF_SCALE_FACTOR *pScaling = &qd_ch->scaling;
    583 
    584   /* for high part it would be enough to save only used part of overlap area */
    585   if (qmfImag != NULL) {
    586     for (ts = offset; ts < ovSlots; ts++) {
    587       FDKmemcpy(qmfReal[ts], qmfReal[nCols + ts],
    588                 sizeof(FIXP_DBL) * nProcBands);
    589       FDKmemcpy(qmfImag[ts], qmfImag[nCols + ts],
    590                 sizeof(FIXP_DBL) * nProcBands);
    591     }
    592   } else {
    593     for (ts = 0; ts < ovSlots; ts++) {
    594       FDKmemcpy(qmfReal[ts], qmfReal[nCols + ts],
    595                 sizeof(FIXP_DBL) * nProcBands);
    596     }
    597   }
    598   pScaling->ov_lb_scale = pScaling->lb_scale;
    599 }
    600 
    601   /* Convert headroom bits to exponent */
    602 #define SCALE2EXP(s) (15 - (s))
    603 #define EXP2SCALE(e) (15 - (e))
    604 
    605 void FDK_QmfDomain_GetSlot(const HANDLE_FDK_QMF_DOMAIN_IN qd_ch, const int ts,
    606                            const int start_band, const int stop_band,
    607                            FIXP_DBL *pQmfOutReal, FIXP_DBL *pQmfOutImag,
    608                            const int exp_out) {
    609   FDK_ASSERT(qd_ch != NULL);
    610   FDK_ASSERT(pQmfOutReal != NULL);
    611   HANDLE_FDK_QMF_DOMAIN_GC gc = qd_ch->pGlobalConf;
    612   const FIXP_DBL *real = qd_ch->hQmfSlotsReal[ts];
    613   const FIXP_DBL *imag = qd_ch->hQmfSlotsImag[ts];
    614   const int ovSlots = gc->nQmfOvTimeSlots;
    615   const int exp_lb = SCALE2EXP((ts < ovSlots) ? qd_ch->scaling.ov_lb_scale
    616                                               : qd_ch->scaling.lb_scale);
    617   const int exp_hb = SCALE2EXP(qd_ch->scaling.hb_scale);
    618   const int lsb = qd_ch->fb.lsb;
    619   const int usb = qd_ch->fb.usb;
    620   int b = start_band;
    621   int lb_sf, hb_sf;
    622 
    623   int target_exp =
    624       ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK + qd_ch->fb.filterScale;
    625 
    626   FDK_ASSERT(ts < (gc->nQmfTimeSlots + gc->nQmfOvTimeSlots));
    627   FDK_ASSERT(start_band >= 0);
    628   FDK_ASSERT(stop_band <= gc->nQmfProcBands);
    629 
    630   if (qd_ch->fb.no_channels == 24) {
    631     target_exp -= 1;
    632   }
    633 
    634   /* Limit scaling factors to maximum negative value to avoid faulty behaviour
    635      due to right-shifts. Corresponding asserts were observed during robustness
    636      testing.
    637    */
    638   lb_sf = fMax(exp_lb - target_exp - exp_out, -31);
    639   FDK_ASSERT(lb_sf < 32);
    640   hb_sf = fMax(exp_hb - target_exp - exp_out, -31);
    641   FDK_ASSERT(hb_sf < 32);
    642 
    643   if (pQmfOutImag == NULL) {
    644     for (; b < fMin(lsb, stop_band); b++) {
    645       pQmfOutReal[b] = scaleValue(real[b], lb_sf);
    646     }
    647     for (; b < fMin(usb, stop_band); b++) {
    648       pQmfOutReal[b] = scaleValue(real[b], hb_sf);
    649     }
    650     for (; b < stop_band; b++) {
    651       pQmfOutReal[b] = (FIXP_DBL)0;
    652     }
    653   } else {
    654     FDK_ASSERT(imag != NULL);
    655     for (; b < fMin(lsb, stop_band); b++) {
    656       pQmfOutReal[b] = scaleValue(real[b], lb_sf);
    657       pQmfOutImag[b] = scaleValue(imag[b], lb_sf);
    658     }
    659     for (; b < fMin(usb, stop_band); b++) {
    660       pQmfOutReal[b] = scaleValue(real[b], hb_sf);
    661       pQmfOutImag[b] = scaleValue(imag[b], hb_sf);
    662     }
    663     for (; b < stop_band; b++) {
    664       pQmfOutReal[b] = (FIXP_DBL)0;
    665       pQmfOutImag[b] = (FIXP_DBL)0;
    666     }
    667   }
    668 }
    669 
    670 void FDK_QmfDomain_GetWorkBuffer(const HANDLE_FDK_QMF_DOMAIN_IN qd_ch,
    671                                  const int ts, FIXP_DBL **ppQmfReal,
    672                                  FIXP_DBL **ppQmfImag) {
    673   FDK_ASSERT(qd_ch != NULL);
    674   FDK_ASSERT(ppQmfReal != NULL);
    675   FDK_ASSERT(ppQmfImag != NULL);
    676   const int bands = qd_ch->workBuf_nBands;
    677   FIXP_DBL **pWorkBuf = qd_ch->pWorkBuffer;
    678   USHORT workBufferOffset = qd_ch->workBufferOffset;
    679   USHORT workBufferSectSize = qd_ch->workBufferSectSize;
    680 
    681   FDK_ASSERT(bands > 0);
    682   FDK_ASSERT(ts < qd_ch->workBuf_nTimeSlots);
    683 
    684   *ppQmfReal = FDK_getWorkBuffer(
    685       pWorkBuf, workBufferOffset + (ts * CMPLX_MOD + 0) * bands,
    686       workBufferSectSize, bands);
    687   *ppQmfImag = FDK_getWorkBuffer(
    688       pWorkBuf, workBufferOffset + (ts * CMPLX_MOD + 1) * bands,
    689       workBufferSectSize, bands);
    690 }
    691 
    692 void FDK_QmfDomain_WorkBuffer2ProcChannel(
    693     const HANDLE_FDK_QMF_DOMAIN_IN qd_ch) {
    694   FDK_ASSERT(qd_ch != NULL);
    695   HANDLE_FDK_QMF_DOMAIN_GC gc = qd_ch->pGlobalConf;
    696   FIXP_DBL **pWorkBuf = qd_ch->pWorkBuffer;
    697   USHORT workBufferOffset = qd_ch->workBufferOffset;
    698   USHORT workBufferSectSize = qd_ch->workBufferSectSize;
    699 
    700   if (FDK_getWorkBuffer(pWorkBuf, workBufferOffset, workBufferSectSize,
    701                         qd_ch->workBuf_nBands) ==
    702       qd_ch->hQmfSlotsReal[gc->nQmfOvTimeSlots]) {
    703     /* work buffer is part of processing channel => nothing to do */
    704     return;
    705   } else {
    706     /* copy parked new QMF data to processing channel */
    707     const int bands = qd_ch->workBuf_nBands;
    708     const int slots = qd_ch->workBuf_nTimeSlots;
    709     int ts;
    710     for (ts = 0; ts < slots; ts++) {
    711       FDKmemcpy(qd_ch->hQmfSlotsReal[gc->nQmfOvTimeSlots + ts],
    712                 FDK_getWorkBuffer(pWorkBuf, workBufferOffset,
    713                                   workBufferSectSize, bands),
    714                 sizeof(FIXP_DBL) * bands);  // parkBuf_to_anaMatrix
    715       workBufferOffset += bands;
    716       FDKmemcpy(qd_ch->hQmfSlotsImag[gc->nQmfOvTimeSlots + ts],
    717                 FDK_getWorkBuffer(pWorkBuf, workBufferOffset,
    718                                   workBufferSectSize, bands),
    719                 sizeof(FIXP_DBL) * bands);
    720       workBufferOffset += bands;
    721     }
    722   }
    723 }
    724 
    725 void FDK_QmfDomain_QmfData2HBE(HANDLE_FDK_QMF_DOMAIN_IN qd_ch,
    726                                FIXP_DBL **ppQmfReal, FIXP_DBL **ppQmfImag) {
    727   FDK_ASSERT(qd_ch != NULL);
    728   FDK_ASSERT(ppQmfReal != NULL);
    729   FDK_ASSERT(ppQmfImag != NULL);
    730   HANDLE_FDK_QMF_DOMAIN_GC gc = qd_ch->pGlobalConf;
    731   FIXP_DBL **pWorkBuf = qd_ch->pWorkBuffer;
    732   USHORT workBufferOffset = qd_ch->workBufferOffset;
    733   USHORT workBufferSectSize = qd_ch->workBufferSectSize;
    734 
    735   if (FDK_getWorkBuffer(pWorkBuf, workBufferOffset, workBufferSectSize,
    736                         qd_ch->workBuf_nBands) ==
    737       qd_ch->hQmfSlotsReal[gc->nQmfOvTimeSlots]) {  // left channel (anaMatrix)
    738     int ts;
    739     const int bands = gc->nBandsAnalysis;
    740     const int slots = qd_ch->workBuf_nTimeSlots;
    741     FDK_ASSERT(bands <= 64);
    742     for (ts = 0; ts < slots; ts++) {
    743       /* copy current data of processing channel */
    744       FIXP_DBL tmp[64];  // one slot
    745       /* real */
    746       FDKmemcpy(tmp, qd_ch->hQmfSlotsReal[gc->nQmfOvTimeSlots + ts],
    747                 sizeof(FIXP_DBL) * bands);  // anaMatrix_to_tmp
    748       FDKmemcpy(qd_ch->hQmfSlotsReal[gc->nQmfOvTimeSlots + ts], ppQmfReal[ts],
    749                 sizeof(FIXP_DBL) * bands);  // HBE_to_anaMatrix
    750       FDKmemcpy(ppQmfReal[ts], tmp, sizeof(FIXP_DBL) * bands);  // tmp_to_HBE
    751       /* imag */
    752       FDKmemcpy(tmp, qd_ch->hQmfSlotsImag[gc->nQmfOvTimeSlots + ts],
    753                 sizeof(FIXP_DBL) * bands);
    754       FDKmemcpy(qd_ch->hQmfSlotsImag[gc->nQmfOvTimeSlots + ts], ppQmfImag[ts],
    755                 sizeof(FIXP_DBL) * bands);
    756       FDKmemcpy(ppQmfImag[ts], tmp, sizeof(FIXP_DBL) * bands);
    757     }
    758   } else {  // right channel (parkBuf)
    759     const int bands = qd_ch->workBuf_nBands;
    760     const int slots = qd_ch->workBuf_nTimeSlots;
    761     int ts;
    762     FDK_ASSERT(qd_ch->workBuf_nBands == gc->nBandsAnalysis);
    763     for (ts = 0; ts < slots; ts++) {
    764       /* copy HBE QMF data buffer to processing channel */
    765       FDKmemcpy(qd_ch->hQmfSlotsReal[gc->nQmfOvTimeSlots + ts], ppQmfReal[ts],
    766                 sizeof(FIXP_DBL) * bands);  // HBE_to_anaMatrix
    767       FDKmemcpy(qd_ch->hQmfSlotsImag[gc->nQmfOvTimeSlots + ts], ppQmfImag[ts],
    768                 sizeof(FIXP_DBL) * bands);
    769       /* copy parked new QMF data to HBE QMF data buffer */
    770       FDKmemcpy(ppQmfReal[ts],
    771                 FDK_getWorkBuffer(pWorkBuf, workBufferOffset,
    772                                   workBufferSectSize, bands),
    773                 sizeof(FIXP_DBL) * bands);  // parkBuf_to_HBE
    774       workBufferOffset += bands;
    775       FDKmemcpy(ppQmfImag[ts],
    776                 FDK_getWorkBuffer(pWorkBuf, workBufferOffset,
    777                                   workBufferSectSize, bands),
    778                 sizeof(FIXP_DBL) * bands);
    779       workBufferOffset += bands;
    780     }
    781   }
    782 }
    783 
    784 void FDK_QmfDomain_ClearRequested(HANDLE_FDK_QMF_DOMAIN_GC hgc) {
    785   hgc->qmfDomainExplicitConfig = 0;
    786   hgc->flags_requested = 0;
    787   hgc->nInputChannels_requested = 0;
    788   hgc->nOutputChannels_requested = 0;
    789   hgc->parkChannel_requested = 0;
    790   hgc->nBandsAnalysis_requested = 0;
    791   hgc->nBandsSynthesis_requested = 0;
    792   hgc->nQmfTimeSlots_requested = 0;
    793   hgc->nQmfOvTimeSlots_requested = 0;
    794   hgc->nQmfProcBands_requested = 0;
    795   hgc->nQmfProcChannels_requested = 0;
    796 }
    797 
    798 static void FDK_QmfDomain_ClearConfigured(HANDLE_FDK_QMF_DOMAIN_GC hgc) {
    799   hgc->flags = 0;
    800   hgc->nInputChannels = 0;
    801   hgc->nOutputChannels = 0;
    802   hgc->parkChannel = 0;
    803   hgc->nBandsAnalysis = 0;
    804   hgc->nBandsSynthesis = 0;
    805   hgc->nQmfTimeSlots = 0;
    806   hgc->nQmfOvTimeSlots = 0;
    807   hgc->nQmfProcBands = 0;
    808   hgc->nQmfProcChannels = 0;
    809 }
    810 
    811 static void FDK_QmfDomain_ClearFilterBank(HANDLE_FDK_QMF_DOMAIN hqd) {
    812   int ch;
    813 
    814   for (ch = 0; ch < ((8) + (1)); ch++) {
    815     FDKmemclear(&hqd->QmfDomainIn[ch].fb, sizeof(hqd->QmfDomainIn[ch].fb));
    816   }
    817 
    818   for (ch = 0; ch < ((8) + (1)); ch++) {
    819     FDKmemclear(&hqd->QmfDomainOut[ch].fb, sizeof(hqd->QmfDomainIn[ch].fb));
    820   }
    821 }
    822 
    823 QMF_DOMAIN_ERROR FDK_QmfDomain_Configure(HANDLE_FDK_QMF_DOMAIN hqd) {
    824   FDK_ASSERT(hqd != NULL);
    825   QMF_DOMAIN_ERROR err = QMF_DOMAIN_OK;
    826   int i, size_main, size, size_temp = 0;
    827 
    828   HANDLE_FDK_QMF_DOMAIN_GC hgc = &hqd->globalConf;
    829   FIXP_DBL **pWorkBuffer = hgc->pWorkBuffer;
    830 
    831   int hasChanged = 0;
    832 
    833   if ((hgc->nQmfProcChannels_requested > 0) &&
    834       (hgc->nQmfProcBands_requested != 64)) {
    835     return QMF_DOMAIN_INIT_ERROR;
    836   }
    837   if (hgc->nBandsAnalysis_requested > hgc->nQmfProcBands_requested) {
    838     /* In general the output of the qmf analysis is written to QMF memory slots
    839        which size is defined by nQmfProcBands. nBandsSynthesis may be larger
    840        than nQmfProcBands. This is e.g. the case if the QMF based resampler is
    841        used.
    842     */
    843     return QMF_DOMAIN_INIT_ERROR;
    844   }
    845 
    846   /* 1. adjust change of processing channels by comparison of current and
    847    * requested parameters */
    848   if ((hgc->nQmfProcChannels != hgc->nQmfProcChannels_requested) ||
    849       (hgc->nQmfProcBands != hgc->nQmfProcBands_requested) ||
    850       (hgc->nQmfTimeSlots != hgc->nQmfTimeSlots_requested)) {
    851     for (i = 0; i < hgc->nQmfProcChannels_requested; i++) {
    852       hqd->QmfDomainIn[i].workBuf_nBands = hgc->nQmfProcBands_requested;
    853       hgc->nQmfProcBands = hgc->nQmfProcBands_requested;
    854 
    855       hqd->QmfDomainIn[i].workBuf_nTimeSlots = hgc->nQmfTimeSlots_requested;
    856     }
    857 
    858     hgc->nQmfProcChannels =
    859         hgc->nQmfProcChannels_requested; /* keep highest value encountered so
    860                                             far as allocated */
    861 
    862     hasChanged = 1;
    863   }
    864 
    865   /* 2. reallocate persistent memory if necessary (analysis state-buffers,
    866    * timeslot-pointer-array, overlap-buffers, synthesis state-buffers) */
    867   if ((hgc->nInputChannels != hgc->nInputChannels_requested) ||
    868       (hgc->nBandsAnalysis != hgc->nBandsAnalysis_requested) ||
    869       (hgc->nQmfTimeSlots != hgc->nQmfTimeSlots_requested) ||
    870       (hgc->nQmfOvTimeSlots != hgc->nQmfOvTimeSlots_requested) ||
    871       (hgc->nOutputChannels != hgc->nOutputChannels_requested) ||
    872       (hgc->nBandsSynthesis != hgc->nBandsSynthesis_requested) ||
    873       (hgc->parkChannel != hgc->parkChannel_requested)) {
    874     hgc->nInputChannels = hgc->nInputChannels_requested;
    875     hgc->nBandsAnalysis = hgc->nBandsAnalysis_requested;
    876     hgc->nQmfTimeSlots = hgc->nQmfTimeSlots_requested;
    877     hgc->nQmfOvTimeSlots = hgc->nQmfOvTimeSlots_requested;
    878     hgc->nOutputChannels = hgc->nOutputChannels_requested;
    879     hgc->nBandsSynthesis = hgc->nBandsSynthesis_requested;
    880     hgc->parkChannel = hgc->parkChannel_requested;
    881 
    882     if (FDK_QmfDomain_AllocatePersistentMemory(hqd)) {
    883       err = QMF_DOMAIN_OUT_OF_MEMORY;
    884       goto bail;
    885     }
    886 
    887     /* 3. set request-flag for downsampled SBR */
    888     if ((hgc->nBandsAnalysis == 32) && (hgc->nBandsSynthesis == 32) &&
    889         !(hgc->flags & (QMF_FLAG_CLDFB | QMF_FLAG_MPSLDFB))) {
    890       hgc->flags_requested |= QMF_FLAG_DOWNSAMPLED;
    891     }
    892 
    893     hasChanged = 1;
    894   }
    895 
    896   /* 4. initialize tables and buffer for QMF-resampler */
    897 
    898   /* 5. set requested flags */
    899   if (hgc->flags != hgc->flags_requested) {
    900     if ((hgc->flags_requested & QMF_FLAG_MPSLDFB) &&
    901         (hgc->flags_requested & QMF_FLAG_CLDFB)) {
    902       hgc->flags_requested &= ~QMF_FLAG_CLDFB;
    903     }
    904     hgc->flags = hgc->flags_requested;
    905     hasChanged = 1;
    906   }
    907 
    908   if (hasChanged) {
    909     /* 6. recalculate and check size of required workbuffer-space */
    910 
    911     if (hgc->parkChannel && (hqd->globalConf.nQmfProcChannels == 1)) {
    912       /* configure temp QMF buffer for parking right channel MPS212 output,
    913        * (USAC stereoConfigIndex 3 only) */
    914       hqd->QmfDomainIn[1].workBuf_nBands = hqd->globalConf.nBandsAnalysis;
    915       hqd->QmfDomainIn[1].workBuf_nTimeSlots = hqd->globalConf.nQmfTimeSlots;
    916       size_temp = hqd->QmfDomainIn[1].workBuf_nBands *
    917                   hqd->QmfDomainIn[1].workBuf_nTimeSlots * CMPLX_MOD;
    918     }
    919 
    920     size_main = hqd->QmfDomainIn[0].workBuf_nBands *
    921                 hqd->QmfDomainIn[0].workBuf_nTimeSlots * CMPLX_MOD;
    922 
    923     size = size_main * hgc->nQmfProcChannels + size_temp;
    924 
    925     if (size > (QMF_MAX_WB_SECTIONS * QMF_WB_SECTION_SIZE)) {
    926       err = QMF_DOMAIN_OUT_OF_MEMORY;
    927       goto bail;
    928     }
    929 
    930     /* 7. allocate additional workbuffer if necessary */
    931     if ((size > 0 /* *QMF_WB_SECTION_SIZE */) && (pWorkBuffer[0] == NULL)) {
    932       /* get work buffer of size QMF_WB_SECTION_SIZE */
    933       pWorkBuffer[0] = GetQmfWorkBufferCore6();
    934     }
    935 
    936     if ((size > 1 * QMF_WB_SECTION_SIZE) && (pWorkBuffer[1] == NULL)) {
    937       /* get work buffer of size QMF_WB_SECTION_SIZE */
    938       pWorkBuffer[1] = GetQmfWorkBufferCore1();
    939     }
    940 
    941     if ((size > 2 * QMF_WB_SECTION_SIZE) && (pWorkBuffer[2] == NULL)) {
    942       /* get work buffer of size QMF_WB_SECTION_SIZE */
    943       pWorkBuffer[2] = GetQmfWorkBufferCore3();
    944     }
    945 
    946     if ((size > 3 * QMF_WB_SECTION_SIZE) && (pWorkBuffer[3] == NULL)) {
    947       /* get work buffer of size QMF_WB_SECTION_SIZE */
    948       pWorkBuffer[3] = GetQmfWorkBufferCore4();
    949     }
    950 
    951     if ((size > 4 * QMF_WB_SECTION_SIZE) && (pWorkBuffer[4] == NULL)) {
    952       /* get work buffer of size QMF_WB_SECTION_SIZE */
    953       pWorkBuffer[4] = GetQmfWorkBufferCore5();
    954     }
    955 
    956     /* 8. distribute workbuffer over processing channels */
    957     for (i = 0; i < hgc->nQmfProcChannels; i++) {
    958       FDK_QmfDomain_FeedWorkBuffer(hqd, i, pWorkBuffer, size_main * i,
    959                                    QMF_WB_SECTION_SIZE, size_main);
    960     }
    961     if (hgc->parkChannel) {
    962       for (; i < hgc->nInputChannels; i++) {
    963         FDK_QmfDomain_FeedWorkBuffer(hqd, 1, pWorkBuffer,
    964                                      size_main * hgc->nQmfProcChannels,
    965                                      QMF_WB_SECTION_SIZE, size_temp);
    966       }
    967     }
    968 
    969     /* 9. (re-)init filterbank */
    970     for (i = 0; i < hgc->nOutputChannels; i++) {
    971       if ((hqd->QmfDomainOut[i].fb.lsb == 0) &&
    972           (hqd->QmfDomainOut[i].fb.usb == 0)) {
    973         /* Although lsb and usb are set in the SBR module, they are initialized
    974          * at this point due to the case of using MPS without SBR. */
    975         hqd->QmfDomainOut[i].fb.lsb = hgc->nBandsAnalysis_requested;
    976         hqd->QmfDomainOut[i].fb.usb =
    977             fMin((INT)hgc->nBandsSynthesis_requested, 64);
    978       }
    979     }
    980     if (FDK_QmfDomain_InitFilterBank(hqd, 0)) {
    981       err = QMF_DOMAIN_INIT_ERROR;
    982     }
    983   }
    984 
    985 bail:
    986   if (err) {
    987     FDK_QmfDomain_FreeMem(hqd);
    988   }
    989   return err;
    990 }
    991 
    992 static void FDK_QmfDomain_FreeWorkBuffer(HANDLE_FDK_QMF_DOMAIN hqd) {
    993   FIXP_DBL **pWorkBuffer = hqd->globalConf.pWorkBuffer;
    994 
    995   if (pWorkBuffer[0]) FreeQmfWorkBufferCore6(&pWorkBuffer[0]);
    996   if (pWorkBuffer[1]) FreeQmfWorkBufferCore1(&pWorkBuffer[1]);
    997   if (pWorkBuffer[2]) FreeQmfWorkBufferCore3(&pWorkBuffer[2]);
    998   if (pWorkBuffer[3]) FreeQmfWorkBufferCore4(&pWorkBuffer[3]);
    999   if (pWorkBuffer[4]) FreeQmfWorkBufferCore5(&pWorkBuffer[4]);
   1000 }
   1001 
   1002 void FDK_QmfDomain_FreeMem(HANDLE_FDK_QMF_DOMAIN hqd) {
   1003   FDK_QmfDomain_FreeWorkBuffer(hqd);
   1004 
   1005   FDK_QmfDomain_FreePersistentMemory(hqd);
   1006 
   1007   FDK_QmfDomain_ClearFilterBank(hqd);
   1008 
   1009   FDK_QmfDomain_ClearConfigured(&hqd->globalConf);
   1010 
   1011   FDK_QmfDomain_ClearRequested(&hqd->globalConf);
   1012 }
   1013 
   1014 void FDK_QmfDomain_Close(HANDLE_FDK_QMF_DOMAIN hqd) {
   1015   FDK_QmfDomain_FreeWorkBuffer(hqd);
   1016 
   1017   FDK_QmfDomain_FreePersistentMemory(hqd);
   1018 }
   1019