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