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