/src/aac/libFDK/src/FDK_qmf_domain.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | |
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 | 198k | static int FDK_QmfDomain_FreePersistentMemory(HANDLE_FDK_QMF_DOMAIN qd) { |
200 | 198k | int err = 0; |
201 | 198k | int ch; |
202 | | |
203 | 1.98M | for (ch = 0; ch < ((8) + (1)); ch++) { |
204 | 1.78M | if (qd->QmfDomainIn[ch].pAnaQmfStates) { |
205 | 85.4k | if (qd->globalConf.nBandsAnalysis == QMF_DOMAIN_ANALYSIS_QMF_BANDS_16) { |
206 | 21.2k | FreeAnaQmfStates16(&qd->QmfDomainIn[ch].pAnaQmfStates); |
207 | 64.1k | } else if (qd->globalConf.nBandsAnalysis == |
208 | 64.1k | QMF_DOMAIN_ANALYSIS_QMF_BANDS_24) { |
209 | 12.3k | FreeAnaQmfStates24(&qd->QmfDomainIn[ch].pAnaQmfStates); |
210 | 51.8k | } else if (qd->globalConf.nBandsAnalysis == |
211 | 51.8k | QMF_DOMAIN_ANALYSIS_QMF_BANDS_32) { |
212 | 48.6k | FreeAnaQmfStates32(&qd->QmfDomainIn[ch].pAnaQmfStates); |
213 | 48.6k | } else { |
214 | 3.11k | FreeAnaQmfStates(&qd->QmfDomainIn[ch].pAnaQmfStates); |
215 | 3.11k | } |
216 | 85.4k | } |
217 | | |
218 | 1.78M | if (qd->QmfDomainIn[ch].pOverlapBuffer) { |
219 | 30.9k | if (qd->globalConf.nQmfOvTimeSlots == QMF_DOMAIN_OV_TIMESLOTS_16) { |
220 | 0 | FreeQmfOverlapBuffer16(&qd->QmfDomainIn[ch].pOverlapBuffer); |
221 | 30.9k | } else if (qd->globalConf.nQmfOvTimeSlots == QMF_DOMAIN_OV_TIMESLOTS_32) { |
222 | 26.4k | FreeQmfOverlapBuffer32(&qd->QmfDomainIn[ch].pOverlapBuffer); |
223 | 26.4k | } else { |
224 | 4.49k | FreeQmfOverlapBuffer(&qd->QmfDomainIn[ch].pOverlapBuffer); |
225 | 4.49k | } |
226 | 30.9k | } |
227 | | |
228 | 1.78M | if (qd->QmfDomainIn[ch].hQmfSlotsReal) { |
229 | 82.7k | if (qd->globalConf.nQmfTimeSlots == QMF_DOMAIN_TIMESLOTS_16) { |
230 | 11.6k | FreeQmfSlotsReal16(&qd->QmfDomainIn[ch].hQmfSlotsReal); |
231 | 71.1k | } else if (qd->globalConf.nQmfTimeSlots == QMF_DOMAIN_TIMESLOTS_32) { |
232 | 22.6k | FreeQmfSlotsReal32(&qd->QmfDomainIn[ch].hQmfSlotsReal); |
233 | 48.4k | } else { |
234 | 48.4k | FreeQmfSlotsReal(&qd->QmfDomainIn[ch].hQmfSlotsReal); |
235 | 48.4k | } |
236 | 82.7k | } |
237 | | |
238 | 1.78M | if (qd->QmfDomainIn[ch].hQmfSlotsImag) { |
239 | 82.7k | if (qd->globalConf.nQmfTimeSlots == QMF_DOMAIN_TIMESLOTS_16) { |
240 | 11.6k | FreeQmfSlotsImag16(&qd->QmfDomainIn[ch].hQmfSlotsImag); |
241 | 11.6k | } |
242 | 82.7k | if (qd->globalConf.nQmfTimeSlots == QMF_DOMAIN_TIMESLOTS_32) { |
243 | 22.6k | FreeQmfSlotsImag32(&qd->QmfDomainIn[ch].hQmfSlotsImag); |
244 | 60.1k | } else { |
245 | 60.1k | FreeQmfSlotsImag(&qd->QmfDomainIn[ch].hQmfSlotsImag); |
246 | 60.1k | } |
247 | 82.7k | } |
248 | 1.78M | } |
249 | | |
250 | 1.98M | for (ch = 0; ch < ((8) + (1)); ch++) { |
251 | 1.78M | if (qd->QmfDomainOut[ch].pSynQmfStates) { |
252 | 94.2k | FreeSynQmfStates(&qd->QmfDomainOut[ch].pSynQmfStates); |
253 | 94.2k | } |
254 | 1.78M | } |
255 | | |
256 | 198k | return err; |
257 | 198k | } |
258 | | |
259 | 40.7k | static int FDK_QmfDomain_AllocatePersistentMemory(HANDLE_FDK_QMF_DOMAIN qd) { |
260 | 40.7k | int err = 0; |
261 | 40.7k | int ch; |
262 | 40.7k | HANDLE_FDK_QMF_DOMAIN_GC gc = &qd->globalConf; |
263 | | |
264 | 40.7k | if ((gc->nInputChannels > ((8) + (1))) || (gc->nOutputChannels > ((8) + (1)))) |
265 | 0 | return err = 1; |
266 | 126k | for (ch = 0; ch < gc->nInputChannels; ch++) { |
267 | 86.1k | int size; |
268 | | |
269 | 86.1k | size = gc->nBandsAnalysis * 10; |
270 | 86.1k | if (size > 0) { |
271 | 86.1k | if (gc->nBandsAnalysis == QMF_DOMAIN_ANALYSIS_QMF_BANDS_16) { |
272 | 21.2k | if (qd->QmfDomainIn[ch].pAnaQmfStates == NULL) { |
273 | 21.2k | if (NULL == |
274 | 21.2k | (qd->QmfDomainIn[ch].pAnaQmfStates = GetAnaQmfStates16(ch))) |
275 | 0 | goto bail; |
276 | 21.2k | } |
277 | 64.8k | } else if (gc->nBandsAnalysis == QMF_DOMAIN_ANALYSIS_QMF_BANDS_24) { |
278 | 12.3k | if (qd->QmfDomainIn[ch].pAnaQmfStates == NULL) { |
279 | 12.3k | if (NULL == |
280 | 12.3k | (qd->QmfDomainIn[ch].pAnaQmfStates = GetAnaQmfStates24(ch))) |
281 | 0 | goto bail; |
282 | 12.3k | } |
283 | 52.5k | } else if (gc->nBandsAnalysis == QMF_DOMAIN_ANALYSIS_QMF_BANDS_32) { |
284 | 49.3k | if (qd->QmfDomainIn[ch].pAnaQmfStates == NULL) { |
285 | 48.6k | if (NULL == |
286 | 48.6k | (qd->QmfDomainIn[ch].pAnaQmfStates = GetAnaQmfStates32(ch))) |
287 | 0 | goto bail; |
288 | 48.6k | } |
289 | 49.3k | } else { |
290 | 3.11k | if (qd->QmfDomainIn[ch].pAnaQmfStates == NULL) { |
291 | 3.11k | if (NULL == (qd->QmfDomainIn[ch].pAnaQmfStates = GetAnaQmfStates(ch))) |
292 | 0 | goto bail; |
293 | 3.11k | } |
294 | 3.11k | } |
295 | 86.1k | } else { |
296 | 5 | qd->QmfDomainIn[ch].pAnaQmfStates = NULL; |
297 | 5 | } |
298 | | |
299 | 86.1k | size = gc->nQmfOvTimeSlots + gc->nQmfTimeSlots; |
300 | 86.1k | if (size > 0) { |
301 | 83.4k | if (gc->nQmfTimeSlots == QMF_DOMAIN_TIMESLOTS_16) { |
302 | 11.6k | if (qd->QmfDomainIn[ch].hQmfSlotsReal == NULL) { |
303 | 11.6k | if (NULL == |
304 | 11.6k | (qd->QmfDomainIn[ch].hQmfSlotsReal = GetQmfSlotsReal16(ch))) |
305 | 0 | goto bail; |
306 | 11.6k | } |
307 | 11.6k | if (qd->QmfDomainIn[ch].hQmfSlotsImag == NULL) { |
308 | 11.6k | if (NULL == |
309 | 11.6k | (qd->QmfDomainIn[ch].hQmfSlotsImag = GetQmfSlotsImag16(ch))) |
310 | 0 | goto bail; |
311 | 11.6k | } |
312 | 71.8k | } else if (gc->nQmfTimeSlots == QMF_DOMAIN_TIMESLOTS_32) { |
313 | 22.8k | if (qd->QmfDomainIn[ch].hQmfSlotsReal == NULL) { |
314 | 22.6k | if (NULL == |
315 | 22.6k | (qd->QmfDomainIn[ch].hQmfSlotsReal = GetQmfSlotsReal32(ch))) |
316 | 0 | goto bail; |
317 | 22.6k | } |
318 | 22.8k | if (qd->QmfDomainIn[ch].hQmfSlotsImag == NULL) { |
319 | 22.6k | if (NULL == |
320 | 22.6k | (qd->QmfDomainIn[ch].hQmfSlotsImag = GetQmfSlotsImag32(ch))) |
321 | 0 | goto bail; |
322 | 22.6k | } |
323 | 48.9k | } else { |
324 | 48.9k | if (qd->QmfDomainIn[ch].hQmfSlotsReal == NULL) { |
325 | 48.4k | if (NULL == (qd->QmfDomainIn[ch].hQmfSlotsReal = GetQmfSlotsReal(ch))) |
326 | 0 | goto bail; |
327 | 48.4k | } |
328 | 48.9k | if (qd->QmfDomainIn[ch].hQmfSlotsImag == NULL) { |
329 | 48.4k | if (NULL == (qd->QmfDomainIn[ch].hQmfSlotsImag = GetQmfSlotsImag(ch))) |
330 | 0 | goto bail; |
331 | 48.4k | } |
332 | 48.9k | } |
333 | 83.4k | } else { |
334 | 2.65k | qd->QmfDomainIn[ch].hQmfSlotsReal = NULL; |
335 | 2.65k | qd->QmfDomainIn[ch].hQmfSlotsImag = NULL; |
336 | 2.65k | } |
337 | | |
338 | 86.1k | size = gc->nQmfOvTimeSlots * gc->nQmfProcBands * CMPLX_MOD; |
339 | 86.1k | if (size > 0) { |
340 | 31.6k | if (gc->nQmfOvTimeSlots == QMF_DOMAIN_OV_TIMESLOTS_16) { |
341 | 0 | if (qd->QmfDomainIn[ch].pOverlapBuffer == NULL) { |
342 | 0 | if (NULL == |
343 | 0 | (qd->QmfDomainIn[ch].pOverlapBuffer = GetQmfOverlapBuffer16(ch))) |
344 | 0 | goto bail; |
345 | 0 | } |
346 | 31.6k | } else if (gc->nQmfOvTimeSlots == QMF_DOMAIN_OV_TIMESLOTS_32) { |
347 | 27.1k | if (qd->QmfDomainIn[ch].pOverlapBuffer == NULL) { |
348 | 26.4k | if (NULL == |
349 | 26.4k | (qd->QmfDomainIn[ch].pOverlapBuffer = GetQmfOverlapBuffer32(ch))) |
350 | 0 | goto bail; |
351 | 26.4k | } |
352 | 27.1k | } else { |
353 | 4.49k | if (qd->QmfDomainIn[ch].pOverlapBuffer == NULL) { |
354 | 4.49k | if (NULL == |
355 | 4.49k | (qd->QmfDomainIn[ch].pOverlapBuffer = GetQmfOverlapBuffer(ch))) |
356 | 0 | goto bail; |
357 | 4.49k | } |
358 | 4.49k | } |
359 | 54.5k | } else { |
360 | 54.5k | qd->QmfDomainIn[ch].pOverlapBuffer = NULL; |
361 | 54.5k | } |
362 | 86.1k | } |
363 | | |
364 | 135k | for (ch = 0; ch < gc->nOutputChannels; ch++) { |
365 | 95.0k | int size = gc->nBandsSynthesis * 9; |
366 | 95.0k | if (size > 0) { |
367 | 94.9k | if (qd->QmfDomainOut[ch].pSynQmfStates == NULL) { |
368 | 94.2k | if (NULL == (qd->QmfDomainOut[ch].pSynQmfStates = GetSynQmfStates(ch))) |
369 | 0 | goto bail; |
370 | 94.2k | } |
371 | 94.9k | } else { |
372 | 6 | qd->QmfDomainOut[ch].pSynQmfStates = NULL; |
373 | 6 | } |
374 | 95.0k | } |
375 | | |
376 | 40.7k | return err; |
377 | | |
378 | 0 | bail: |
379 | 0 | FDK_QmfDomain_FreePersistentMemory(qd); |
380 | 0 | return -1; |
381 | 40.7k | } |
382 | | |
383 | | QMF_DOMAIN_ERROR FDK_QmfDomain_ClearPersistentMemory( |
384 | 0 | HANDLE_FDK_QMF_DOMAIN hqd) { |
385 | 0 | QMF_DOMAIN_ERROR err = QMF_DOMAIN_OK; |
386 | 0 | int ch, size; |
387 | 0 | if (hqd) { |
388 | 0 | HANDLE_FDK_QMF_DOMAIN_GC gc = &hqd->globalConf; |
389 | |
|
390 | 0 | size = gc->nQmfOvTimeSlots * gc->nQmfProcBands * CMPLX_MOD; |
391 | 0 | for (ch = 0; ch < gc->nInputChannels; ch++) { |
392 | 0 | if (hqd->QmfDomainIn[ch].pOverlapBuffer) { |
393 | 0 | FDKmemclear(hqd->QmfDomainIn[ch].pOverlapBuffer, |
394 | 0 | size * sizeof(FIXP_DBL)); |
395 | 0 | } |
396 | 0 | } |
397 | 0 | if (FDK_QmfDomain_InitFilterBank(hqd, 0)) { |
398 | 0 | err = QMF_DOMAIN_INIT_ERROR; |
399 | 0 | } |
400 | 0 | } else { |
401 | 0 | err = QMF_DOMAIN_INIT_ERROR; |
402 | 0 | } |
403 | 0 | return err; |
404 | 0 | } |
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 | | */ |
429 | | static FIXP_DBL *FDK_getWorkBuffer(FIXP_DBL **pWorkBuffer, |
430 | | USHORT workBufferOffset, |
431 | 13.4M | USHORT workBufferSectSize, USHORT memSize) { |
432 | 13.4M | int idx1; |
433 | 13.4M | int idx2; |
434 | 13.4M | FIXP_DBL *pwb; |
435 | | |
436 | | /* a section must be a multiple of the number of processing bands (currently |
437 | | * always 64) */ |
438 | 13.4M | FDK_ASSERT((workBufferSectSize % 64) == 0); |
439 | | |
440 | | /* calculate offset within the section */ |
441 | 13.4M | idx2 = workBufferOffset % workBufferSectSize; |
442 | | /* calculate section number */ |
443 | 13.4M | idx1 = (workBufferOffset - idx2) / workBufferSectSize; |
444 | | /* maximum sectionnumber is QMF_MAX_WB_SECTIONS */ |
445 | 13.4M | FDK_ASSERT(idx1 < QMF_MAX_WB_SECTIONS); |
446 | | |
447 | | /* check, whether workbuffer is available */ |
448 | 13.4M | FDK_ASSERT(pWorkBuffer[idx1] != NULL); |
449 | | |
450 | | /* check, whether buffer fits into selected section */ |
451 | 13.4M | FDK_ASSERT((idx2 + memSize) <= workBufferSectSize); |
452 | | |
453 | | /* get requested address to workbuffer */ |
454 | 13.4M | pwb = &pWorkBuffer[idx1][idx2]; |
455 | | |
456 | 13.4M | return pwb; |
457 | 13.4M | } |
458 | | |
459 | | static int FDK_QmfDomain_FeedWorkBuffer(HANDLE_FDK_QMF_DOMAIN qd, int ch, |
460 | | FIXP_DBL **pWorkBuffer, |
461 | | USHORT workBufferOffset, |
462 | 49.5k | USHORT workBufferSectSize, int size) { |
463 | 49.5k | int err = 0; |
464 | 49.5k | int mem_needed; |
465 | | |
466 | 49.5k | mem_needed = qd->QmfDomainIn[ch].workBuf_nBands * |
467 | 49.5k | qd->QmfDomainIn[ch].workBuf_nTimeSlots * CMPLX_MOD; |
468 | 49.5k | if (mem_needed > size) { |
469 | 0 | return (err = 1); |
470 | 0 | } |
471 | 49.5k | qd->QmfDomainIn[ch].pWorkBuffer = pWorkBuffer; |
472 | 49.5k | qd->QmfDomainIn[ch].workBufferOffset = workBufferOffset; |
473 | 49.5k | qd->QmfDomainIn[ch].workBufferSectSize = workBufferSectSize; |
474 | | |
475 | 49.5k | return err; |
476 | 49.5k | } |
477 | | |
478 | 0 | int FDK_QmfDomain_IsInitialized(const HANDLE_FDK_QMF_DOMAIN qd) { |
479 | 0 | FDK_ASSERT(qd != NULL); |
480 | 0 | return ((qd->QmfDomainIn[0].pAnaQmfStates == NULL) && |
481 | 0 | (qd->QmfDomainOut[0].pSynQmfStates == NULL)) |
482 | 0 | ? 0 |
483 | 0 | : 1; |
484 | 0 | } |
485 | | |
486 | 64.1k | int FDK_QmfDomain_InitFilterBank(HANDLE_FDK_QMF_DOMAIN qd, UINT extra_flags) { |
487 | 64.1k | FDK_ASSERT(qd != NULL); |
488 | 64.1k | int err = 0; |
489 | 64.1k | int ch, ts; |
490 | 64.1k | HANDLE_FDK_QMF_DOMAIN_GC gc = &qd->globalConf; |
491 | 64.1k | int noCols = gc->nQmfTimeSlots; |
492 | 64.1k | int lsb = gc->nBandsAnalysis; |
493 | 64.1k | int usb = fMin((INT)gc->nBandsSynthesis, 64); |
494 | 64.1k | int nProcBands = gc->nQmfProcBands; |
495 | 64.1k | FDK_ASSERT(nProcBands % ALIGNMENT_DEFAULT == 0); |
496 | | |
497 | 64.1k | if (extra_flags & QMF_FLAG_MPSLDFB) { |
498 | 0 | gc->flags &= ~QMF_FLAG_CLDFB; |
499 | 0 | gc->flags |= QMF_FLAG_MPSLDFB; |
500 | 0 | } |
501 | 217k | for (ch = 0; ch < gc->nInputChannels; ch++) { |
502 | | /* distribute memory to slots array */ |
503 | 153k | FIXP_DBL *ptrOv = |
504 | 153k | qd->QmfDomainIn[ch].pOverlapBuffer; /* persistent memory for overlap */ |
505 | 153k | if ((ptrOv == NULL) && (gc->nQmfOvTimeSlots != 0)) { |
506 | 0 | err = 1; |
507 | 0 | return err; |
508 | 0 | } |
509 | | /* This assumes the workbuffer defined for ch0 is the big one being used to |
510 | | * hold one full frame of QMF data. */ |
511 | 153k | FIXP_DBL **ptr = |
512 | 153k | qd->QmfDomainIn[fMin(ch, fMax((INT)gc->nQmfProcChannels - 1, 0))] |
513 | 153k | .pWorkBuffer; /* non-persistent workbuffer */ |
514 | 153k | USHORT workBufferOffset = |
515 | 153k | qd->QmfDomainIn[fMin(ch, fMax((INT)gc->nQmfProcChannels - 1, 0))] |
516 | 153k | .workBufferOffset; |
517 | 153k | USHORT workBufferSectSize = |
518 | 153k | qd->QmfDomainIn[fMin(ch, fMax((INT)gc->nQmfProcChannels - 1, 0))] |
519 | 153k | .workBufferSectSize; |
520 | | |
521 | 153k | if ((ptr == NULL) && (gc->nQmfTimeSlots != 0)) { |
522 | 0 | err = 1; |
523 | 0 | return err; |
524 | 0 | } |
525 | | |
526 | 153k | qd->QmfDomainIn[ch].pGlobalConf = gc; |
527 | 472k | for (ts = 0; ts < gc->nQmfOvTimeSlots; ts++) { |
528 | 318k | qd->QmfDomainIn[ch].hQmfSlotsReal[ts] = ptrOv; |
529 | 318k | ptrOv += nProcBands; |
530 | 318k | qd->QmfDomainIn[ch].hQmfSlotsImag[ts] = ptrOv; |
531 | 318k | ptrOv += nProcBands; |
532 | 318k | } |
533 | 3.36M | for (; ts < (gc->nQmfOvTimeSlots + gc->nQmfTimeSlots); ts++) { |
534 | 3.21M | qd->QmfDomainIn[ch].hQmfSlotsReal[ts] = FDK_getWorkBuffer( |
535 | 3.21M | ptr, workBufferOffset, workBufferSectSize, nProcBands); |
536 | 3.21M | workBufferOffset += nProcBands; |
537 | 3.21M | qd->QmfDomainIn[ch].hQmfSlotsImag[ts] = FDK_getWorkBuffer( |
538 | 3.21M | ptr, workBufferOffset, workBufferSectSize, nProcBands); |
539 | 3.21M | workBufferOffset += nProcBands; |
540 | 3.21M | } |
541 | 153k | err |= qmfInitAnalysisFilterBank( |
542 | 153k | &qd->QmfDomainIn[ch].fb, qd->QmfDomainIn[ch].pAnaQmfStates, noCols, |
543 | 153k | (qd->QmfDomainIn[ch].fb.lsb == 0) ? lsb : qd->QmfDomainIn[ch].fb.lsb, |
544 | 153k | (qd->QmfDomainIn[ch].fb.usb == 0) ? usb : qd->QmfDomainIn[ch].fb.usb, |
545 | 153k | gc->nBandsAnalysis, gc->flags | extra_flags); |
546 | 153k | } |
547 | | |
548 | 230k | for (ch = 0; ch < gc->nOutputChannels; ch++) { |
549 | 166k | FIXP_DBL outGain_m = qd->QmfDomainOut[ch].fb.outGain_m; |
550 | 166k | int outGain_e = qd->QmfDomainOut[ch].fb.outGain_e; |
551 | 166k | int outScale = qmfGetOutScalefactor(&qd->QmfDomainOut[ch].fb); |
552 | 166k | err |= qmfInitSynthesisFilterBank( |
553 | 166k | &qd->QmfDomainOut[ch].fb, qd->QmfDomainOut[ch].pSynQmfStates, noCols, |
554 | 166k | (qd->QmfDomainOut[ch].fb.lsb == 0) ? lsb : qd->QmfDomainOut[ch].fb.lsb, |
555 | 166k | (qd->QmfDomainOut[ch].fb.usb == 0) ? usb : qd->QmfDomainOut[ch].fb.usb, |
556 | 166k | gc->nBandsSynthesis, gc->flags | extra_flags); |
557 | 166k | if (outGain_m != (FIXP_DBL)0) { |
558 | 72.0k | qmfChangeOutGain(&qd->QmfDomainOut[ch].fb, outGain_m, outGain_e); |
559 | 72.0k | } |
560 | 166k | if (outScale) { |
561 | 11.8k | qmfChangeOutScalefactor(&qd->QmfDomainOut[ch].fb, outScale); |
562 | 11.8k | } |
563 | 166k | } |
564 | | |
565 | 64.1k | return err; |
566 | 64.1k | } |
567 | | |
568 | 580k | void FDK_QmfDomain_SaveOverlap(HANDLE_FDK_QMF_DOMAIN_IN qd_ch, int offset) { |
569 | 580k | FDK_ASSERT(qd_ch != NULL); |
570 | 580k | int ts; |
571 | 580k | HANDLE_FDK_QMF_DOMAIN_GC gc = qd_ch->pGlobalConf; |
572 | 580k | int ovSlots = gc->nQmfOvTimeSlots; |
573 | 580k | int nCols = gc->nQmfTimeSlots; |
574 | 580k | int nProcBands = gc->nQmfProcBands; |
575 | 580k | FIXP_DBL **qmfReal = qd_ch->hQmfSlotsReal; |
576 | 580k | FIXP_DBL **qmfImag = qd_ch->hQmfSlotsImag; |
577 | 580k | 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 | 580k | if (qmfImag != NULL) { |
581 | 3.24M | for (ts = offset; ts < ovSlots; ts++) { |
582 | 2.66M | FDKmemcpy(qmfReal[ts], qmfReal[nCols + ts], |
583 | 2.66M | sizeof(FIXP_DBL) * nProcBands); |
584 | 2.66M | FDKmemcpy(qmfImag[ts], qmfImag[nCols + ts], |
585 | 2.66M | sizeof(FIXP_DBL) * nProcBands); |
586 | 2.66M | } |
587 | 580k | } else { |
588 | 0 | for (ts = 0; ts < ovSlots; ts++) { |
589 | 0 | FDKmemcpy(qmfReal[ts], qmfReal[nCols + ts], |
590 | 0 | sizeof(FIXP_DBL) * nProcBands); |
591 | 0 | } |
592 | 0 | } |
593 | 580k | pScaling->ov_lb_scale = pScaling->lb_scale; |
594 | 580k | } |
595 | | |
596 | | /* Convert headroom bits to exponent */ |
597 | 20.5M | #define SCALE2EXP(s) (15 - (s)) |
598 | | #define EXP2SCALE(e) (15 - (e)) |
599 | | |
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 | 10.2M | const int exp_out) { |
604 | 10.2M | FDK_ASSERT(qd_ch != NULL); |
605 | 10.2M | FDK_ASSERT(pQmfOutReal != NULL); |
606 | 10.2M | HANDLE_FDK_QMF_DOMAIN_GC gc = qd_ch->pGlobalConf; |
607 | 10.2M | const FIXP_DBL *real = qd_ch->hQmfSlotsReal[ts]; |
608 | 10.2M | const FIXP_DBL *imag = qd_ch->hQmfSlotsImag[ts]; |
609 | 10.2M | const int ovSlots = gc->nQmfOvTimeSlots; |
610 | 10.2M | const int exp_lb = SCALE2EXP((ts < ovSlots) ? qd_ch->scaling.ov_lb_scale |
611 | 10.2M | : qd_ch->scaling.lb_scale); |
612 | 10.2M | const int exp_hb = SCALE2EXP(qd_ch->scaling.hb_scale); |
613 | 10.2M | const int lsb = qd_ch->fb.lsb; |
614 | 10.2M | const int usb = qd_ch->fb.usb; |
615 | 10.2M | int b = start_band; |
616 | 10.2M | int lb_sf, hb_sf; |
617 | | |
618 | 10.2M | int target_exp = |
619 | 10.2M | ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK + qd_ch->fb.filterScale; |
620 | | |
621 | 10.2M | FDK_ASSERT(ts < (gc->nQmfTimeSlots + gc->nQmfOvTimeSlots)); |
622 | 10.2M | FDK_ASSERT(start_band >= 0); |
623 | 10.2M | FDK_ASSERT(stop_band <= gc->nQmfProcBands); |
624 | | |
625 | 10.2M | if (qd_ch->fb.no_channels == 24) { |
626 | 1.11M | target_exp -= 1; |
627 | 1.11M | } |
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 | 10.2M | lb_sf = fMax(exp_lb - target_exp - exp_out, -31); |
634 | 10.2M | FDK_ASSERT(lb_sf < 32); |
635 | 10.2M | hb_sf = fMax(exp_hb - target_exp - exp_out, -31); |
636 | 10.2M | FDK_ASSERT(hb_sf < 32); |
637 | | |
638 | 10.2M | if (pQmfOutImag == NULL) { |
639 | 0 | for (; b < fMin(lsb, stop_band); b++) { |
640 | 0 | pQmfOutReal[b] = scaleValueSaturate(real[b], lb_sf); |
641 | 0 | } |
642 | 0 | for (; b < fMin(usb, stop_band); b++) { |
643 | 0 | pQmfOutReal[b] = scaleValueSaturate(real[b], hb_sf); |
644 | 0 | } |
645 | 0 | for (; b < stop_band; b++) { |
646 | 0 | pQmfOutReal[b] = (FIXP_DBL)0; |
647 | 0 | } |
648 | 10.2M | } else { |
649 | 10.2M | FDK_ASSERT(imag != NULL); |
650 | 144M | for (; b < fMin(lsb, stop_band); b++) { |
651 | 133M | pQmfOutReal[b] = scaleValueSaturate(real[b], lb_sf); |
652 | 133M | pQmfOutImag[b] = scaleValueSaturate(imag[b], lb_sf); |
653 | 133M | } |
654 | 107M | for (; b < fMin(usb, stop_band); b++) { |
655 | 97.3M | pQmfOutReal[b] = scaleValueSaturate(real[b], hb_sf); |
656 | 97.3M | pQmfOutImag[b] = scaleValueSaturate(imag[b], hb_sf); |
657 | 97.3M | } |
658 | 108M | for (; b < stop_band; b++) { |
659 | 98.0M | pQmfOutReal[b] = (FIXP_DBL)0; |
660 | 98.0M | pQmfOutImag[b] = (FIXP_DBL)0; |
661 | 98.0M | } |
662 | 10.2M | } |
663 | 10.2M | } |
664 | | |
665 | | void FDK_QmfDomain_GetWorkBuffer(const HANDLE_FDK_QMF_DOMAIN_IN qd_ch, |
666 | | const int ts, FIXP_DBL **ppQmfReal, |
667 | 2.32M | FIXP_DBL **ppQmfImag) { |
668 | 2.32M | FDK_ASSERT(qd_ch != NULL); |
669 | 2.32M | FDK_ASSERT(ppQmfReal != NULL); |
670 | 2.32M | FDK_ASSERT(ppQmfImag != NULL); |
671 | 2.32M | const int bands = qd_ch->workBuf_nBands; |
672 | 2.32M | FIXP_DBL **pWorkBuf = qd_ch->pWorkBuffer; |
673 | 2.32M | USHORT workBufferOffset = qd_ch->workBufferOffset; |
674 | 2.32M | USHORT workBufferSectSize = qd_ch->workBufferSectSize; |
675 | | |
676 | 2.32M | FDK_ASSERT(bands > 0); |
677 | 2.32M | FDK_ASSERT(ts < qd_ch->workBuf_nTimeSlots); |
678 | | |
679 | 2.32M | *ppQmfReal = FDK_getWorkBuffer( |
680 | 2.32M | pWorkBuf, workBufferOffset + (ts * CMPLX_MOD + 0) * bands, |
681 | 2.32M | workBufferSectSize, bands); |
682 | 2.32M | *ppQmfImag = FDK_getWorkBuffer( |
683 | 2.32M | pWorkBuf, workBufferOffset + (ts * CMPLX_MOD + 1) * bands, |
684 | 2.32M | workBufferSectSize, bands); |
685 | 2.32M | } |
686 | | |
687 | | void FDK_QmfDomain_WorkBuffer2ProcChannel( |
688 | 5.39k | const HANDLE_FDK_QMF_DOMAIN_IN qd_ch) { |
689 | 5.39k | FDK_ASSERT(qd_ch != NULL); |
690 | 5.39k | HANDLE_FDK_QMF_DOMAIN_GC gc = qd_ch->pGlobalConf; |
691 | 5.39k | FIXP_DBL **pWorkBuf = qd_ch->pWorkBuffer; |
692 | 5.39k | USHORT workBufferOffset = qd_ch->workBufferOffset; |
693 | 5.39k | USHORT workBufferSectSize = qd_ch->workBufferSectSize; |
694 | | |
695 | 5.39k | if (FDK_getWorkBuffer(pWorkBuf, workBufferOffset, workBufferSectSize, |
696 | 5.39k | qd_ch->workBuf_nBands) == |
697 | 5.39k | qd_ch->hQmfSlotsReal[gc->nQmfOvTimeSlots]) { |
698 | | /* work buffer is part of processing channel => nothing to do */ |
699 | 2.69k | return; |
700 | 2.69k | } else { |
701 | | /* copy parked new QMF data to processing channel */ |
702 | 2.69k | const int bands = qd_ch->workBuf_nBands; |
703 | 2.69k | const int slots = qd_ch->workBuf_nTimeSlots; |
704 | 2.69k | int ts; |
705 | 96.9k | for (ts = 0; ts < slots; ts++) { |
706 | 94.2k | FDKmemcpy(qd_ch->hQmfSlotsReal[gc->nQmfOvTimeSlots + ts], |
707 | 94.2k | FDK_getWorkBuffer(pWorkBuf, workBufferOffset, |
708 | 94.2k | workBufferSectSize, bands), |
709 | 94.2k | sizeof(FIXP_DBL) * bands); // parkBuf_to_anaMatrix |
710 | 94.2k | workBufferOffset += bands; |
711 | 94.2k | FDKmemcpy(qd_ch->hQmfSlotsImag[gc->nQmfOvTimeSlots + ts], |
712 | 94.2k | FDK_getWorkBuffer(pWorkBuf, workBufferOffset, |
713 | 94.2k | workBufferSectSize, bands), |
714 | 94.2k | sizeof(FIXP_DBL) * bands); |
715 | 94.2k | workBufferOffset += bands; |
716 | 94.2k | } |
717 | 2.69k | } |
718 | 5.39k | } |
719 | | |
720 | | void FDK_QmfDomain_QmfData2HBE(HANDLE_FDK_QMF_DOMAIN_IN qd_ch, |
721 | 36.2k | FIXP_DBL **ppQmfReal, FIXP_DBL **ppQmfImag) { |
722 | 36.2k | FDK_ASSERT(qd_ch != NULL); |
723 | 36.2k | FDK_ASSERT(ppQmfReal != NULL); |
724 | 36.2k | FDK_ASSERT(ppQmfImag != NULL); |
725 | 36.2k | HANDLE_FDK_QMF_DOMAIN_GC gc = qd_ch->pGlobalConf; |
726 | 36.2k | FIXP_DBL **pWorkBuf = qd_ch->pWorkBuffer; |
727 | 36.2k | USHORT workBufferOffset = qd_ch->workBufferOffset; |
728 | 36.2k | USHORT workBufferSectSize = qd_ch->workBufferSectSize; |
729 | | |
730 | 36.2k | if (FDK_getWorkBuffer(pWorkBuf, workBufferOffset, workBufferSectSize, |
731 | 36.2k | qd_ch->workBuf_nBands) == |
732 | 36.2k | qd_ch->hQmfSlotsReal[gc->nQmfOvTimeSlots]) { // left channel (anaMatrix) |
733 | 18.1k | int ts; |
734 | 18.1k | const int bands = gc->nBandsAnalysis; |
735 | 18.1k | const int slots = qd_ch->workBuf_nTimeSlots; |
736 | 18.1k | FDK_ASSERT(bands <= 64); |
737 | 1.08M | for (ts = 0; ts < slots; ts++) { |
738 | | /* copy current data of processing channel */ |
739 | 1.06M | FIXP_DBL tmp[64]; // one slot |
740 | | /* real */ |
741 | 1.06M | FDKmemcpy(tmp, qd_ch->hQmfSlotsReal[gc->nQmfOvTimeSlots + ts], |
742 | 1.06M | sizeof(FIXP_DBL) * bands); // anaMatrix_to_tmp |
743 | 1.06M | FDKmemcpy(qd_ch->hQmfSlotsReal[gc->nQmfOvTimeSlots + ts], ppQmfReal[ts], |
744 | 1.06M | sizeof(FIXP_DBL) * bands); // HBE_to_anaMatrix |
745 | 1.06M | FDKmemcpy(ppQmfReal[ts], tmp, sizeof(FIXP_DBL) * bands); // tmp_to_HBE |
746 | | /* imag */ |
747 | 1.06M | FDKmemcpy(tmp, qd_ch->hQmfSlotsImag[gc->nQmfOvTimeSlots + ts], |
748 | 1.06M | sizeof(FIXP_DBL) * bands); |
749 | 1.06M | FDKmemcpy(qd_ch->hQmfSlotsImag[gc->nQmfOvTimeSlots + ts], ppQmfImag[ts], |
750 | 1.06M | sizeof(FIXP_DBL) * bands); |
751 | 1.06M | FDKmemcpy(ppQmfImag[ts], tmp, sizeof(FIXP_DBL) * bands); |
752 | 1.06M | } |
753 | 18.1k | } else { // right channel (parkBuf) |
754 | 18.1k | const int bands = qd_ch->workBuf_nBands; |
755 | 18.1k | const int slots = qd_ch->workBuf_nTimeSlots; |
756 | 18.1k | int ts; |
757 | 18.1k | FDK_ASSERT(qd_ch->workBuf_nBands == gc->nBandsAnalysis); |
758 | 1.08M | for (ts = 0; ts < slots; ts++) { |
759 | | /* copy HBE QMF data buffer to processing channel */ |
760 | 1.06M | FDKmemcpy(qd_ch->hQmfSlotsReal[gc->nQmfOvTimeSlots + ts], ppQmfReal[ts], |
761 | 1.06M | sizeof(FIXP_DBL) * bands); // HBE_to_anaMatrix |
762 | 1.06M | FDKmemcpy(qd_ch->hQmfSlotsImag[gc->nQmfOvTimeSlots + ts], ppQmfImag[ts], |
763 | 1.06M | sizeof(FIXP_DBL) * bands); |
764 | | /* copy parked new QMF data to HBE QMF data buffer */ |
765 | 1.06M | FDKmemcpy(ppQmfReal[ts], |
766 | 1.06M | FDK_getWorkBuffer(pWorkBuf, workBufferOffset, |
767 | 1.06M | workBufferSectSize, bands), |
768 | 1.06M | sizeof(FIXP_DBL) * bands); // parkBuf_to_HBE |
769 | 1.06M | workBufferOffset += bands; |
770 | 1.06M | FDKmemcpy(ppQmfImag[ts], |
771 | 1.06M | FDK_getWorkBuffer(pWorkBuf, workBufferOffset, |
772 | 1.06M | workBufferSectSize, bands), |
773 | 1.06M | sizeof(FIXP_DBL) * bands); |
774 | 1.06M | workBufferOffset += bands; |
775 | 1.06M | } |
776 | 18.1k | } |
777 | 36.2k | } |
778 | | |
779 | 198k | void FDK_QmfDomain_ClearRequested(HANDLE_FDK_QMF_DOMAIN_GC hgc) { |
780 | 198k | hgc->qmfDomainExplicitConfig = 0; |
781 | 198k | hgc->flags_requested = 0; |
782 | 198k | hgc->nInputChannels_requested = 0; |
783 | 198k | hgc->nOutputChannels_requested = 0; |
784 | 198k | hgc->parkChannel_requested = 0; |
785 | 198k | hgc->nBandsAnalysis_requested = 0; |
786 | 198k | hgc->nBandsSynthesis_requested = 0; |
787 | 198k | hgc->nQmfTimeSlots_requested = 0; |
788 | 198k | hgc->nQmfOvTimeSlots_requested = 0; |
789 | 198k | hgc->nQmfProcBands_requested = 0; |
790 | 198k | hgc->nQmfProcChannels_requested = 0; |
791 | 198k | } |
792 | | |
793 | 163k | static void FDK_QmfDomain_ClearConfigured(HANDLE_FDK_QMF_DOMAIN_GC hgc) { |
794 | 163k | hgc->flags = 0; |
795 | 163k | hgc->nInputChannels = 0; |
796 | 163k | hgc->nOutputChannels = 0; |
797 | 163k | hgc->parkChannel = 0; |
798 | 163k | hgc->nBandsAnalysis = 0; |
799 | 163k | hgc->nBandsSynthesis = 0; |
800 | 163k | hgc->nQmfTimeSlots = 0; |
801 | 163k | hgc->nQmfOvTimeSlots = 0; |
802 | 163k | hgc->nQmfProcBands = 0; |
803 | 163k | hgc->nQmfProcChannels = 0; |
804 | 163k | } |
805 | | |
806 | 163k | static void FDK_QmfDomain_ClearFilterBank(HANDLE_FDK_QMF_DOMAIN hqd) { |
807 | 163k | int ch; |
808 | | |
809 | 1.63M | for (ch = 0; ch < ((8) + (1)); ch++) { |
810 | 1.47M | FDKmemclear(&hqd->QmfDomainIn[ch].fb, sizeof(hqd->QmfDomainIn[ch].fb)); |
811 | 1.47M | } |
812 | | |
813 | 1.63M | for (ch = 0; ch < ((8) + (1)); ch++) { |
814 | 1.47M | FDKmemclear(&hqd->QmfDomainOut[ch].fb, sizeof(hqd->QmfDomainIn[ch].fb)); |
815 | 1.47M | } |
816 | 163k | } |
817 | | |
818 | 506k | QMF_DOMAIN_ERROR FDK_QmfDomain_Configure(HANDLE_FDK_QMF_DOMAIN hqd) { |
819 | 506k | FDK_ASSERT(hqd != NULL); |
820 | 506k | QMF_DOMAIN_ERROR err = QMF_DOMAIN_OK; |
821 | 506k | int i, size_main, size, size_temp = 0; |
822 | | |
823 | 506k | HANDLE_FDK_QMF_DOMAIN_GC hgc = &hqd->globalConf; |
824 | 506k | FIXP_DBL **pWorkBuffer = hgc->pWorkBuffer; |
825 | | |
826 | 506k | int hasChanged = 0; |
827 | | |
828 | 506k | if ((hgc->nQmfProcChannels_requested > 0) && |
829 | 506k | (hgc->nQmfProcBands_requested != 64)) { |
830 | 0 | return QMF_DOMAIN_INIT_ERROR; |
831 | 0 | } |
832 | 506k | 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 | 0 | return QMF_DOMAIN_INIT_ERROR; |
839 | 0 | } |
840 | | |
841 | | /* 1. adjust change of processing channels by comparison of current and |
842 | | * requested parameters */ |
843 | 506k | if ((hgc->nQmfProcChannels != hgc->nQmfProcChannels_requested) || |
844 | 506k | (hgc->nQmfProcBands != hgc->nQmfProcBands_requested) || |
845 | 506k | (hgc->nQmfTimeSlots != hgc->nQmfTimeSlots_requested)) { |
846 | 81.0k | for (i = 0; i < hgc->nQmfProcChannels_requested; i++) { |
847 | 40.5k | hqd->QmfDomainIn[i].workBuf_nBands = hgc->nQmfProcBands_requested; |
848 | 40.5k | hgc->nQmfProcBands = hgc->nQmfProcBands_requested; |
849 | | |
850 | 40.5k | hqd->QmfDomainIn[i].workBuf_nTimeSlots = hgc->nQmfTimeSlots_requested; |
851 | 40.5k | } |
852 | | |
853 | 40.5k | hgc->nQmfProcChannels = |
854 | 40.5k | hgc->nQmfProcChannels_requested; /* keep highest value encountered so |
855 | | far as allocated */ |
856 | | |
857 | 40.5k | hasChanged = 1; |
858 | 40.5k | } |
859 | | |
860 | | /* 2. reallocate persistent memory if necessary (analysis state-buffers, |
861 | | * timeslot-pointer-array, overlap-buffers, synthesis state-buffers) */ |
862 | 506k | if ((hgc->nInputChannels != hgc->nInputChannels_requested) || |
863 | 506k | (hgc->nBandsAnalysis != hgc->nBandsAnalysis_requested) || |
864 | 506k | (hgc->nQmfTimeSlots != hgc->nQmfTimeSlots_requested) || |
865 | 506k | (hgc->nQmfOvTimeSlots != hgc->nQmfOvTimeSlots_requested) || |
866 | 506k | (hgc->nOutputChannels != hgc->nOutputChannels_requested) || |
867 | 506k | (hgc->nBandsSynthesis != hgc->nBandsSynthesis_requested) || |
868 | 506k | (hgc->parkChannel != hgc->parkChannel_requested)) { |
869 | 40.7k | hgc->nInputChannels = hgc->nInputChannels_requested; |
870 | 40.7k | hgc->nBandsAnalysis = hgc->nBandsAnalysis_requested; |
871 | 40.7k | hgc->nQmfTimeSlots = hgc->nQmfTimeSlots_requested; |
872 | 40.7k | hgc->nQmfOvTimeSlots = hgc->nQmfOvTimeSlots_requested; |
873 | 40.7k | hgc->nOutputChannels = hgc->nOutputChannels_requested; |
874 | 40.7k | hgc->nBandsSynthesis = hgc->nBandsSynthesis_requested; |
875 | 40.7k | hgc->parkChannel = hgc->parkChannel_requested; |
876 | | |
877 | 40.7k | if (FDK_QmfDomain_AllocatePersistentMemory(hqd)) { |
878 | 0 | err = QMF_DOMAIN_OUT_OF_MEMORY; |
879 | 0 | goto bail; |
880 | 0 | } |
881 | | |
882 | | /* 3. set request-flag for downsampled SBR */ |
883 | 40.7k | if ((hgc->nBandsAnalysis == 32) && (hgc->nBandsSynthesis == 32) && |
884 | 40.7k | !(hgc->flags & (QMF_FLAG_CLDFB | QMF_FLAG_MPSLDFB))) { |
885 | 6.52k | hgc->flags_requested |= QMF_FLAG_DOWNSAMPLED; |
886 | 6.52k | } |
887 | | |
888 | 40.7k | hasChanged = 1; |
889 | 40.7k | } |
890 | | |
891 | | /* 4. initialize tables and buffer for QMF-resampler */ |
892 | | |
893 | | /* 5. set requested flags */ |
894 | 506k | if (hgc->flags != hgc->flags_requested) { |
895 | 23.7k | if ((hgc->flags_requested & QMF_FLAG_MPSLDFB) && |
896 | 23.7k | (hgc->flags_requested & QMF_FLAG_CLDFB)) { |
897 | 0 | hgc->flags_requested &= ~QMF_FLAG_CLDFB; |
898 | 0 | } |
899 | 23.7k | hgc->flags = hgc->flags_requested; |
900 | 23.7k | hasChanged = 1; |
901 | 23.7k | } |
902 | | |
903 | 506k | if (hasChanged) { |
904 | | /* 6. recalculate and check size of required workbuffer-space */ |
905 | | |
906 | 45.3k | if (hgc->parkChannel && (hqd->globalConf.nQmfProcChannels == 1)) { |
907 | | /* configure temp QMF buffer for parking right channel MPS212 output, |
908 | | * (USAC stereoConfigIndex 3 only) */ |
909 | 4.15k | hqd->QmfDomainIn[1].workBuf_nBands = hqd->globalConf.nBandsAnalysis; |
910 | 4.15k | hqd->QmfDomainIn[1].workBuf_nTimeSlots = hqd->globalConf.nQmfTimeSlots; |
911 | 4.15k | size_temp = hqd->QmfDomainIn[1].workBuf_nBands * |
912 | 4.15k | hqd->QmfDomainIn[1].workBuf_nTimeSlots * CMPLX_MOD; |
913 | 4.15k | } |
914 | | |
915 | 45.3k | size_main = hqd->QmfDomainIn[0].workBuf_nBands * |
916 | 45.3k | hqd->QmfDomainIn[0].workBuf_nTimeSlots * CMPLX_MOD; |
917 | | |
918 | 45.3k | size = size_main * hgc->nQmfProcChannels + size_temp; |
919 | | |
920 | 45.3k | if (size > (QMF_MAX_WB_SECTIONS * QMF_WB_SECTION_SIZE)) { |
921 | 0 | err = QMF_DOMAIN_OUT_OF_MEMORY; |
922 | 0 | goto bail; |
923 | 0 | } |
924 | | |
925 | | /* 7. allocate additional workbuffer if necessary */ |
926 | 45.3k | if ((size > 0 /* *QMF_WB_SECTION_SIZE */) && (pWorkBuffer[0] == NULL)) { |
927 | | /* get work buffer of size QMF_WB_SECTION_SIZE */ |
928 | 37.9k | pWorkBuffer[0] = GetQmfWorkBufferCore6(); |
929 | 37.9k | } |
930 | | |
931 | 45.3k | if ((size > 1 * QMF_WB_SECTION_SIZE) && (pWorkBuffer[1] == NULL)) { |
932 | | /* get work buffer of size QMF_WB_SECTION_SIZE */ |
933 | 21.4k | pWorkBuffer[1] = GetQmfWorkBufferCore1(); |
934 | 21.4k | } |
935 | | |
936 | 45.3k | if ((size > 2 * QMF_WB_SECTION_SIZE) && (pWorkBuffer[2] == NULL)) { |
937 | | /* get work buffer of size QMF_WB_SECTION_SIZE */ |
938 | 6.44k | pWorkBuffer[2] = GetQmfWorkBufferCore3(); |
939 | 6.44k | } |
940 | | |
941 | 45.3k | if ((size > 3 * QMF_WB_SECTION_SIZE) && (pWorkBuffer[3] == NULL)) { |
942 | | /* get work buffer of size QMF_WB_SECTION_SIZE */ |
943 | 3.80k | pWorkBuffer[3] = GetQmfWorkBufferCore4(); |
944 | 3.80k | } |
945 | | |
946 | 45.3k | if ((size > 4 * QMF_WB_SECTION_SIZE) && (pWorkBuffer[4] == NULL)) { |
947 | | /* get work buffer of size QMF_WB_SECTION_SIZE */ |
948 | 584 | pWorkBuffer[4] = GetQmfWorkBufferCore7(); |
949 | 584 | } |
950 | | |
951 | | /* 8. distribute workbuffer over processing channels */ |
952 | 90.6k | for (i = 0; i < hgc->nQmfProcChannels; i++) { |
953 | 45.3k | FDK_QmfDomain_FeedWorkBuffer(hqd, i, pWorkBuffer, size_main * i, |
954 | 45.3k | QMF_WB_SECTION_SIZE, size_main); |
955 | 45.3k | } |
956 | 45.3k | if (hgc->parkChannel) { |
957 | 8.30k | for (; i < hgc->nInputChannels; i++) { |
958 | 4.15k | FDK_QmfDomain_FeedWorkBuffer(hqd, 1, pWorkBuffer, |
959 | 4.15k | size_main * hgc->nQmfProcChannels, |
960 | 4.15k | QMF_WB_SECTION_SIZE, size_temp); |
961 | 4.15k | } |
962 | 4.15k | } |
963 | | |
964 | | /* 9. (re-)init filterbank */ |
965 | 149k | for (i = 0; i < hgc->nOutputChannels; i++) { |
966 | 104k | if ((hqd->QmfDomainOut[i].fb.lsb == 0) && |
967 | 104k | (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 | 94.2k | hqd->QmfDomainOut[i].fb.lsb = hgc->nBandsAnalysis_requested; |
971 | 94.2k | hqd->QmfDomainOut[i].fb.usb = |
972 | 94.2k | fMin((INT)hgc->nBandsSynthesis_requested, 64); |
973 | 94.2k | } |
974 | 104k | } |
975 | 45.3k | if (FDK_QmfDomain_InitFilterBank(hqd, 0)) { |
976 | 3 | err = QMF_DOMAIN_INIT_ERROR; |
977 | 3 | } |
978 | 45.3k | } |
979 | | |
980 | 506k | bail: |
981 | 506k | if (err) { |
982 | 3 | FDK_QmfDomain_FreeMem(hqd); |
983 | 3 | } |
984 | 506k | return err; |
985 | 506k | } |
986 | | |
987 | 198k | static void FDK_QmfDomain_FreeWorkBuffer(HANDLE_FDK_QMF_DOMAIN hqd) { |
988 | 198k | FIXP_DBL **pWorkBuffer = hqd->globalConf.pWorkBuffer; |
989 | | |
990 | 198k | if (pWorkBuffer[0]) FreeQmfWorkBufferCore6(&pWorkBuffer[0]); |
991 | 198k | if (pWorkBuffer[1]) FreeQmfWorkBufferCore1(&pWorkBuffer[1]); |
992 | 198k | if (pWorkBuffer[2]) FreeQmfWorkBufferCore3(&pWorkBuffer[2]); |
993 | 198k | if (pWorkBuffer[3]) FreeQmfWorkBufferCore4(&pWorkBuffer[3]); |
994 | 198k | if (pWorkBuffer[4]) FreeQmfWorkBufferCore7(&pWorkBuffer[4]); |
995 | 198k | } |
996 | | |
997 | 163k | void FDK_QmfDomain_FreeMem(HANDLE_FDK_QMF_DOMAIN hqd) { |
998 | 163k | FDK_QmfDomain_FreeWorkBuffer(hqd); |
999 | | |
1000 | 163k | FDK_QmfDomain_FreePersistentMemory(hqd); |
1001 | | |
1002 | 163k | FDK_QmfDomain_ClearFilterBank(hqd); |
1003 | | |
1004 | 163k | FDK_QmfDomain_ClearConfigured(&hqd->globalConf); |
1005 | | |
1006 | 163k | FDK_QmfDomain_ClearRequested(&hqd->globalConf); |
1007 | 163k | } |
1008 | | |
1009 | 34.9k | void FDK_QmfDomain_Close(HANDLE_FDK_QMF_DOMAIN hqd) { |
1010 | 34.9k | FDK_QmfDomain_FreeWorkBuffer(hqd); |
1011 | | |
1012 | 34.9k | FDK_QmfDomain_FreePersistentMemory(hqd); |
1013 | 34.9k | } |