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