• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -----------------------------------------------------------------------------
2 Software License for The Fraunhofer FDK AAC Codec Library for Android
3 
4 © Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung 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@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 
C_ALLOC_MEM_OVERLAY(QmfWorkBufferCore1,FIXP_DBL,QMF_WB_SECTION_SIZE,SECT_DATA_L1,WORKBUFFER1_TAG)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 
FDK_QmfDomain_AllocatePersistentMemory(HANDLE_FDK_QMF_DOMAIN qd)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 
FDK_QmfDomain_ClearPersistentMemory(HANDLE_FDK_QMF_DOMAIN hqd)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 */
FDK_getWorkBuffer(FIXP_DBL ** pWorkBuffer,USHORT workBufferOffset,USHORT workBufferSectSize,USHORT memSize)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 
FDK_QmfDomain_FeedWorkBuffer(HANDLE_FDK_QMF_DOMAIN qd,int ch,FIXP_DBL ** pWorkBuffer,USHORT workBufferOffset,USHORT workBufferSectSize,int size)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 
FDK_QmfDomain_IsInitialized(const HANDLE_FDK_QMF_DOMAIN qd)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 
FDK_QmfDomain_InitFilterBank(HANDLE_FDK_QMF_DOMAIN qd,UINT extra_flags)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 
FDK_QmfDomain_SaveOverlap(HANDLE_FDK_QMF_DOMAIN_IN qd_ch,int offset)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 
FDK_QmfDomain_GetSlot(const HANDLE_FDK_QMF_DOMAIN_IN qd_ch,const int ts,const int start_band,const int stop_band,FIXP_DBL * pQmfOutReal,FIXP_DBL * pQmfOutImag,const int exp_out)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 
FDK_QmfDomain_GetWorkBuffer(const HANDLE_FDK_QMF_DOMAIN_IN qd_ch,const int ts,FIXP_DBL ** ppQmfReal,FIXP_DBL ** ppQmfImag)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 
FDK_QmfDomain_WorkBuffer2ProcChannel(const HANDLE_FDK_QMF_DOMAIN_IN qd_ch)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 
FDK_QmfDomain_QmfData2HBE(HANDLE_FDK_QMF_DOMAIN_IN qd_ch,FIXP_DBL ** ppQmfReal,FIXP_DBL ** ppQmfImag)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 
FDK_QmfDomain_ClearRequested(HANDLE_FDK_QMF_DOMAIN_GC hgc)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->nBandsAnalysis_requested = 0;
790   hgc->nBandsSynthesis_requested = 0;
791   hgc->nQmfTimeSlots_requested = 0;
792   hgc->nQmfOvTimeSlots_requested = 0;
793   hgc->nQmfProcBands_requested = 0;
794   hgc->nQmfProcChannels_requested = 0;
795 }
796 
FDK_QmfDomain_ClearConfigured(HANDLE_FDK_QMF_DOMAIN_GC hgc)797 static void FDK_QmfDomain_ClearConfigured(HANDLE_FDK_QMF_DOMAIN_GC hgc) {
798   hgc->flags = 0;
799   hgc->nInputChannels = 0;
800   hgc->nOutputChannels = 0;
801   hgc->nBandsAnalysis = 0;
802   hgc->nBandsSynthesis = 0;
803   hgc->nQmfTimeSlots = 0;
804   hgc->nQmfOvTimeSlots = 0;
805   hgc->nQmfProcBands = 0;
806   hgc->nQmfProcChannels = 0;
807 }
808 
FDK_QmfDomain_ClearFilterBank(HANDLE_FDK_QMF_DOMAIN hqd)809 static void FDK_QmfDomain_ClearFilterBank(HANDLE_FDK_QMF_DOMAIN hqd) {
810   int ch;
811 
812   for (ch = 0; ch < ((8) + (1)); ch++) {
813     FDKmemclear(&hqd->QmfDomainIn[ch].fb, sizeof(hqd->QmfDomainIn[ch].fb));
814   }
815 
816   for (ch = 0; ch < ((8) + (1)); ch++) {
817     FDKmemclear(&hqd->QmfDomainOut[ch].fb, sizeof(hqd->QmfDomainIn[ch].fb));
818   }
819 }
820 
FDK_QmfDomain_Configure(HANDLE_FDK_QMF_DOMAIN hqd)821 QMF_DOMAIN_ERROR FDK_QmfDomain_Configure(HANDLE_FDK_QMF_DOMAIN hqd) {
822   FDK_ASSERT(hqd != NULL);
823   QMF_DOMAIN_ERROR err = QMF_DOMAIN_OK;
824   int i, size_main, size, size_temp = 0;
825 
826   HANDLE_FDK_QMF_DOMAIN_GC hgc = &hqd->globalConf;
827   FIXP_DBL **pWorkBuffer = hgc->pWorkBuffer;
828 
829   int hasChanged = 0;
830 
831   if ((hgc->nQmfProcChannels_requested > 0) &&
832       (hgc->nQmfProcBands_requested != 64)) {
833     return QMF_DOMAIN_INIT_ERROR;
834   }
835   if (hgc->nBandsAnalysis_requested > hgc->nQmfProcBands_requested) {
836     /* In general the output of the qmf analysis is written to QMF memory slots
837        which size is defined by nQmfProcBands. nBandsSynthesis may be larger
838        than nQmfProcBands. This is e.g. the case if the QMF based resampler is
839        used.
840     */
841     return QMF_DOMAIN_INIT_ERROR;
842   }
843 
844   /* 1. adjust change of processing channels by comparison of current and
845    * requested parameters */
846   if ((hgc->nQmfProcChannels != hgc->nQmfProcChannels_requested) ||
847       (hgc->nQmfProcBands != hgc->nQmfProcBands_requested) ||
848       (hgc->nQmfTimeSlots != hgc->nQmfTimeSlots_requested)) {
849     for (i = 0; i < hgc->nQmfProcChannels_requested; i++) {
850       hqd->QmfDomainIn[i].workBuf_nBands = hgc->nQmfProcBands_requested;
851       hgc->nQmfProcBands = hgc->nQmfProcBands_requested;
852 
853       hqd->QmfDomainIn[i].workBuf_nTimeSlots = hgc->nQmfTimeSlots_requested;
854     }
855 
856     hgc->nQmfProcChannels =
857         hgc->nQmfProcChannels_requested; /* keep highest value encountered so
858                                             far as allocated */
859 
860     hasChanged = 1;
861   }
862 
863   /* 2. reallocate persistent memory if necessary (analysis state-buffers,
864    * timeslot-pointer-array, overlap-buffers, synthesis state-buffers) */
865   if ((hgc->nInputChannels != hgc->nInputChannels_requested) ||
866       (hgc->nBandsAnalysis != hgc->nBandsAnalysis_requested) ||
867       (hgc->nQmfTimeSlots != hgc->nQmfTimeSlots_requested) ||
868       (hgc->nQmfOvTimeSlots != hgc->nQmfOvTimeSlots_requested) ||
869       (hgc->nOutputChannels != hgc->nOutputChannels_requested) ||
870       (hgc->nBandsSynthesis != hgc->nBandsSynthesis_requested) ||
871       (hgc->parkChannel != hgc->parkChannel_requested)) {
872     hgc->nInputChannels = hgc->nInputChannels_requested;
873     hgc->nBandsAnalysis = hgc->nBandsAnalysis_requested;
874     hgc->nQmfTimeSlots = hgc->nQmfTimeSlots_requested;
875     hgc->nQmfOvTimeSlots = hgc->nQmfOvTimeSlots_requested;
876     hgc->nOutputChannels = hgc->nOutputChannels_requested;
877     hgc->nBandsSynthesis = hgc->nBandsSynthesis_requested;
878     hgc->parkChannel = hgc->parkChannel_requested;
879 
880     if (FDK_QmfDomain_AllocatePersistentMemory(hqd)) {
881       err = QMF_DOMAIN_OUT_OF_MEMORY;
882       goto bail;
883     }
884 
885     /* 3. set request-flag for downsampled SBR */
886     if ((hgc->nBandsAnalysis == 32) && (hgc->nBandsSynthesis == 32) &&
887         !(hgc->flags & (QMF_FLAG_CLDFB | QMF_FLAG_MPSLDFB))) {
888       hgc->flags_requested |= QMF_FLAG_DOWNSAMPLED;
889     }
890     if ((hgc->flags_requested & QMF_FLAG_MPSLDFB) &&
891         (hgc->flags_requested & QMF_FLAG_CLDFB)) {
892       hgc->flags_requested &= ~QMF_FLAG_CLDFB;
893     }
894 
895     hasChanged = 1;
896   }
897 
898   /* 4. initialize tables and buffer for QMF-resampler */
899 
900   /* 5. set requested flags */
901   if (hgc->flags != hgc->flags_requested) {
902     hgc->flags = hgc->flags_requested;
903     hasChanged = 1;
904   }
905 
906   if (hasChanged) {
907     /* 6. recalculate and check size of required workbuffer-space */
908 
909     if (hgc->parkChannel && (hqd->globalConf.nQmfProcChannels == 1)) {
910       /* configure temp QMF buffer for parking right channel MPS212 output,
911        * (USAC stereoConfigIndex 3 only) */
912       hqd->QmfDomainIn[1].workBuf_nBands = hqd->globalConf.nBandsAnalysis;
913       hqd->QmfDomainIn[1].workBuf_nTimeSlots = hqd->globalConf.nQmfTimeSlots;
914       size_temp = hqd->QmfDomainIn[1].workBuf_nBands *
915                   hqd->QmfDomainIn[1].workBuf_nTimeSlots * CMPLX_MOD;
916     }
917 
918     size_main = hqd->QmfDomainIn[0].workBuf_nBands *
919                 hqd->QmfDomainIn[0].workBuf_nTimeSlots * CMPLX_MOD;
920 
921     size = size_main * hgc->nQmfProcChannels + size_temp;
922 
923     if (size > (QMF_MAX_WB_SECTIONS * QMF_WB_SECTION_SIZE)) {
924       err = QMF_DOMAIN_OUT_OF_MEMORY;
925       goto bail;
926     }
927 
928     /* 7. allocate additional workbuffer if necessary */
929     if ((size > 0 /* *QMF_WB_SECTION_SIZE */) && (pWorkBuffer[0] == NULL)) {
930       /* get work buffer of size QMF_WB_SECTION_SIZE */
931       pWorkBuffer[0] = GetQmfWorkBufferCore6();
932     }
933 
934     if ((size > 1 * QMF_WB_SECTION_SIZE) && (pWorkBuffer[1] == NULL)) {
935       /* get work buffer of size QMF_WB_SECTION_SIZE */
936       pWorkBuffer[1] = GetQmfWorkBufferCore1();
937     }
938 
939     if ((size > 2 * QMF_WB_SECTION_SIZE) && (pWorkBuffer[2] == NULL)) {
940       /* get work buffer of size QMF_WB_SECTION_SIZE */
941       pWorkBuffer[2] = GetQmfWorkBufferCore3();
942     }
943 
944     if ((size > 3 * QMF_WB_SECTION_SIZE) && (pWorkBuffer[3] == NULL)) {
945       /* get work buffer of size QMF_WB_SECTION_SIZE */
946       pWorkBuffer[3] = GetQmfWorkBufferCore4();
947     }
948 
949     if ((size > 4 * QMF_WB_SECTION_SIZE) && (pWorkBuffer[4] == NULL)) {
950       /* get work buffer of size QMF_WB_SECTION_SIZE */
951       pWorkBuffer[4] = GetQmfWorkBufferCore5();
952     }
953 
954     /* 8. distribute workbuffer over processing channels */
955     for (i = 0; i < hgc->nQmfProcChannels; i++) {
956       FDK_QmfDomain_FeedWorkBuffer(hqd, i, pWorkBuffer, size_main * i,
957                                    QMF_WB_SECTION_SIZE, size_main);
958     }
959     if (hgc->parkChannel) {
960       for (; i < hgc->nInputChannels; i++) {
961         FDK_QmfDomain_FeedWorkBuffer(hqd, 1, pWorkBuffer,
962                                      size_main * hgc->nQmfProcChannels,
963                                      QMF_WB_SECTION_SIZE, size_temp);
964       }
965     }
966 
967     /* 9. (re-)init filterbank */
968     for (i = 0; i < hgc->nOutputChannels; i++) {
969       if ((hqd->QmfDomainOut[i].fb.lsb == 0) &&
970           (hqd->QmfDomainOut[i].fb.usb == 0)) {
971         /* Although lsb and usb are set in the SBR module, they are initialized
972          * at this point due to the case of using MPS without SBR. */
973         hqd->QmfDomainOut[i].fb.lsb = hgc->nBandsAnalysis_requested;
974         hqd->QmfDomainOut[i].fb.usb =
975             fMin((INT)hgc->nBandsSynthesis_requested, 64);
976       }
977     }
978     if (FDK_QmfDomain_InitFilterBank(hqd, 0)) {
979       err = QMF_DOMAIN_INIT_ERROR;
980     }
981   }
982 
983 bail:
984   if (err == QMF_DOMAIN_OUT_OF_MEMORY) {
985     FDK_QmfDomain_FreePersistentMemory(hqd);
986     FDK_QmfDomain_ClearConfigured(&hqd->globalConf);
987   }
988   return err;
989 }
990 
FDK_QmfDomain_FreeWorkBuffer(HANDLE_FDK_QMF_DOMAIN hqd)991 static void FDK_QmfDomain_FreeWorkBuffer(HANDLE_FDK_QMF_DOMAIN hqd) {
992   FIXP_DBL **pWorkBuffer = hqd->globalConf.pWorkBuffer;
993 
994   if (pWorkBuffer[0]) FreeQmfWorkBufferCore6(&pWorkBuffer[0]);
995   if (pWorkBuffer[1]) FreeQmfWorkBufferCore1(&pWorkBuffer[1]);
996   if (pWorkBuffer[2]) FreeQmfWorkBufferCore3(&pWorkBuffer[2]);
997   if (pWorkBuffer[3]) FreeQmfWorkBufferCore4(&pWorkBuffer[3]);
998   if (pWorkBuffer[4]) FreeQmfWorkBufferCore5(&pWorkBuffer[4]);
999 }
1000 
FDK_QmfDomain_FreeMem(HANDLE_FDK_QMF_DOMAIN hqd)1001 void FDK_QmfDomain_FreeMem(HANDLE_FDK_QMF_DOMAIN hqd) {
1002   FDK_QmfDomain_FreeWorkBuffer(hqd);
1003 
1004   FDK_QmfDomain_FreePersistentMemory(hqd);
1005 
1006   FDK_QmfDomain_ClearFilterBank(hqd);
1007 
1008   FDK_QmfDomain_ClearConfigured(&hqd->globalConf);
1009 
1010   FDK_QmfDomain_ClearRequested(&hqd->globalConf);
1011 }
1012 
FDK_QmfDomain_Close(HANDLE_FDK_QMF_DOMAIN hqd)1013 void FDK_QmfDomain_Close(HANDLE_FDK_QMF_DOMAIN hqd) {
1014   FDK_QmfDomain_FreeWorkBuffer(hqd);
1015 
1016   FDK_QmfDomain_FreePersistentMemory(hqd);
1017 }
1018