/src/aac/libFDK/src/FDK_hybrid.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 - 2020 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): Markus Lohwasser |
98 | | |
99 | | Description: FDK Tools Hybrid Filterbank |
100 | | |
101 | | *******************************************************************************/ |
102 | | |
103 | | #include "FDK_hybrid.h" |
104 | | |
105 | | #include "fft.h" |
106 | | |
107 | | /*--------------- defines -----------------------------*/ |
108 | 86.6M | #define FFT_IDX_R(a) (2 * a) |
109 | 86.6M | #define FFT_IDX_I(a) (2 * a + 1) |
110 | | |
111 | | #define HYB_COEF8_0 (0.00746082949812f) |
112 | | #define HYB_COEF8_1 (0.02270420949825f) |
113 | | #define HYB_COEF8_2 (0.04546865930473f) |
114 | | #define HYB_COEF8_3 (0.07266113929591f) |
115 | | #define HYB_COEF8_4 (0.09885108575264f) |
116 | | #define HYB_COEF8_5 (0.11793710567217f) |
117 | | #define HYB_COEF8_6 (0.12500000000000f) |
118 | | #define HYB_COEF8_7 (HYB_COEF8_5) |
119 | | #define HYB_COEF8_8 (HYB_COEF8_4) |
120 | | #define HYB_COEF8_9 (HYB_COEF8_3) |
121 | | #define HYB_COEF8_10 (HYB_COEF8_2) |
122 | | #define HYB_COEF8_11 (HYB_COEF8_1) |
123 | | #define HYB_COEF8_12 (HYB_COEF8_0) |
124 | | |
125 | | /*--------------- structure definitions ---------------*/ |
126 | | |
127 | | #if defined(ARCH_PREFER_MULT_32x16) |
128 | | #define FIXP_HTB FIXP_SGL /* SGL data type. */ |
129 | | #define FIXP_HTP FIXP_SPK /* Packed SGL data type. */ |
130 | | #define HTC(a) (FX_DBL2FXCONST_SGL(a)) /* Cast to SGL */ |
131 | | #define FL2FXCONST_HTB FL2FXCONST_SGL |
132 | | #else |
133 | | #define FIXP_HTB FIXP_DBL /* SGL data type. */ |
134 | | #define FIXP_HTP FIXP_DPK /* Packed DBL data type. */ |
135 | | #define HTC(a) ((FIXP_DBL)(LONG)(a)) /* Cast to DBL */ |
136 | | #define FL2FXCONST_HTB FL2FXCONST_DBL |
137 | | #endif |
138 | | |
139 | | #define HTCP(real, imag) \ |
140 | | { \ |
141 | | { HTC(real), HTC(imag) } \ |
142 | | } /* How to arrange the packed values. */ |
143 | | |
144 | | struct FDK_HYBRID_SETUP { |
145 | | UCHAR nrQmfBands; /*!< Number of QMF bands to be converted to hybrid. */ |
146 | | UCHAR nHybBands[3]; /*!< Number of Hybrid bands generated by nrQmfBands. */ |
147 | | UCHAR synHybScale[3]; /*!< Headroom needed in hybrid synthesis filterbank. */ |
148 | | SCHAR kHybrid[3]; /*!< Filter configuration of each QMF band. */ |
149 | | UCHAR protoLen; /*!< Prototype filter length. */ |
150 | | UCHAR filterDelay; /*!< Delay caused by hybrid filter. */ |
151 | | const INT |
152 | | *pReadIdxTable; /*!< Helper table to access input data ringbuffer. */ |
153 | | }; |
154 | | |
155 | | /*--------------- constants ---------------------------*/ |
156 | | static const INT ringbuffIdxTab[2 * 13] = {0, 1, 2, 3, 4, 5, 6, 7, 8, |
157 | | 9, 10, 11, 12, 0, 1, 2, 3, 4, |
158 | | 5, 6, 7, 8, 9, 10, 11, 12}; |
159 | | |
160 | | static const FDK_HYBRID_SETUP setup_3_16 = { |
161 | | 3, {8, 4, 4}, {4, 3, 3}, {8, 4, 4}, 13, (13 - 1) / 2, ringbuffIdxTab}; |
162 | | static const FDK_HYBRID_SETUP setup_3_12 = { |
163 | | 3, {8, 2, 2}, {4, 2, 2}, {8, 2, 2}, 13, (13 - 1) / 2, ringbuffIdxTab}; |
164 | | static const FDK_HYBRID_SETUP setup_3_10 = { |
165 | | 3, {6, 2, 2}, {3, 2, 2}, {-8, -2, 2}, 13, (13 - 1) / 2, ringbuffIdxTab}; |
166 | | |
167 | | static const FIXP_HTP HybFilterCoef8[] = { |
168 | | HTCP(0x10000000, 0x00000000), HTCP(0x0df26407, 0xfa391882), |
169 | | HTCP(0xff532109, 0x00acdef7), HTCP(0x08f26d36, 0xf70d92ca), |
170 | | HTCP(0xfee34b5f, 0x02af570f), HTCP(0x038f276e, 0xf7684793), |
171 | | HTCP(0x00000000, 0x05d1eac2), HTCP(0x00000000, 0x05d1eac2), |
172 | | HTCP(0x038f276e, 0x0897b86d), HTCP(0xfee34b5f, 0xfd50a8f1), |
173 | | HTCP(0x08f26d36, 0x08f26d36), HTCP(0xff532109, 0xff532109), |
174 | | HTCP(0x0df26407, 0x05c6e77e)}; |
175 | | |
176 | | static const FIXP_HTB HybFilterCoef2[3] = {FL2FXCONST_HTB(0.01899487526049f), |
177 | | FL2FXCONST_HTB(-0.07293139167538f), |
178 | | FL2FXCONST_HTB(0.30596630545168f)}; |
179 | | |
180 | | static const FIXP_HTB HybFilterCoef4[13] = {FL2FXCONST_HTB(-0.00305151927305f), |
181 | | FL2FXCONST_HTB(-0.00794862316203f), |
182 | | FL2FXCONST_HTB(0.0f), |
183 | | FL2FXCONST_HTB(0.04318924038756f), |
184 | | FL2FXCONST_HTB(0.12542448210445f), |
185 | | FL2FXCONST_HTB(0.21227807049160f), |
186 | | FL2FXCONST_HTB(0.25f), |
187 | | FL2FXCONST_HTB(0.21227807049160f), |
188 | | FL2FXCONST_HTB(0.12542448210445f), |
189 | | FL2FXCONST_HTB(0.04318924038756f), |
190 | | FL2FXCONST_HTB(0.0f), |
191 | | FL2FXCONST_HTB(-0.00794862316203f), |
192 | | FL2FXCONST_HTB(-0.00305151927305f)}; |
193 | | |
194 | | /*--------------- function declarations ---------------*/ |
195 | | static INT kChannelFiltering(const FIXP_DBL *const pQmfReal, |
196 | | const FIXP_DBL *const pQmfImag, |
197 | | const INT *const pReadIdx, |
198 | | FIXP_DBL *const mHybridReal, |
199 | | FIXP_DBL *const mHybridImag, |
200 | | const SCHAR hybridConfig); |
201 | | |
202 | | /*--------------- function definitions ----------------*/ |
203 | | |
204 | | INT FDKhybridAnalysisOpen(HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter, |
205 | | FIXP_DBL *const pLFmemory, const UINT LFmemorySize, |
206 | 54.2k | FIXP_DBL *const pHFmemory, const UINT HFmemorySize) { |
207 | 54.2k | INT err = 0; |
208 | | |
209 | | /* Save pointer to extern memory. */ |
210 | 54.2k | hAnalysisHybFilter->pLFmemory = pLFmemory; |
211 | 54.2k | hAnalysisHybFilter->LFmemorySize = LFmemorySize; |
212 | | |
213 | 54.2k | hAnalysisHybFilter->pHFmemory = pHFmemory; |
214 | 54.2k | hAnalysisHybFilter->HFmemorySize = HFmemorySize; |
215 | | |
216 | 54.2k | return err; |
217 | 54.2k | } |
218 | | |
219 | | INT FDKhybridAnalysisInit(HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter, |
220 | | const FDK_HYBRID_MODE mode, const INT qmfBands, |
221 | 141k | const INT cplxBands, const INT initStatesFlag) { |
222 | 141k | int k; |
223 | 141k | INT err = 0; |
224 | 141k | FIXP_DBL *pMem = NULL; |
225 | 141k | HANDLE_FDK_HYBRID_SETUP setup = NULL; |
226 | | |
227 | 141k | switch (mode) { |
228 | 141k | case THREE_TO_TEN: |
229 | 141k | setup = &setup_3_10; |
230 | 141k | break; |
231 | 0 | case THREE_TO_TWELVE: |
232 | 0 | setup = &setup_3_12; |
233 | 0 | break; |
234 | 0 | case THREE_TO_SIXTEEN: |
235 | 0 | setup = &setup_3_16; |
236 | 0 | break; |
237 | 0 | default: |
238 | 0 | err = -1; |
239 | 0 | goto bail; |
240 | 141k | } |
241 | | |
242 | | /* Initialize handle. */ |
243 | 141k | hAnalysisHybFilter->pSetup = setup; |
244 | 141k | if (initStatesFlag) { |
245 | 17.3k | hAnalysisHybFilter->bufferLFpos = setup->protoLen - 1; |
246 | 17.3k | hAnalysisHybFilter->bufferHFpos = 0; |
247 | 17.3k | } |
248 | 141k | hAnalysisHybFilter->nrBands = qmfBands; |
249 | 141k | hAnalysisHybFilter->cplxBands = cplxBands; |
250 | 141k | hAnalysisHybFilter->hfMode = 0; |
251 | | |
252 | | /* Check available memory. */ |
253 | 141k | if (((2 * setup->nrQmfBands * setup->protoLen * sizeof(FIXP_DBL)) > |
254 | 141k | hAnalysisHybFilter->LFmemorySize)) { |
255 | 0 | err = -2; |
256 | 0 | goto bail; |
257 | 0 | } |
258 | 141k | if (hAnalysisHybFilter->HFmemorySize != 0) { |
259 | 137k | if (((setup->filterDelay * |
260 | 137k | ((qmfBands - setup->nrQmfBands) + (cplxBands - setup->nrQmfBands)) * |
261 | 137k | sizeof(FIXP_DBL)) > hAnalysisHybFilter->HFmemorySize)) { |
262 | 0 | err = -3; |
263 | 0 | goto bail; |
264 | 0 | } |
265 | 137k | } |
266 | | |
267 | | /* Distribute LF memory. */ |
268 | 141k | pMem = hAnalysisHybFilter->pLFmemory; |
269 | 565k | for (k = 0; k < setup->nrQmfBands; k++) { |
270 | 424k | hAnalysisHybFilter->bufferLFReal[k] = pMem; |
271 | 424k | pMem += setup->protoLen; |
272 | 424k | hAnalysisHybFilter->bufferLFImag[k] = pMem; |
273 | 424k | pMem += setup->protoLen; |
274 | 424k | } |
275 | | |
276 | | /* Distribute HF memory. */ |
277 | 141k | if (hAnalysisHybFilter->HFmemorySize != 0) { |
278 | 137k | pMem = hAnalysisHybFilter->pHFmemory; |
279 | 960k | for (k = 0; k < setup->filterDelay; k++) { |
280 | 823k | hAnalysisHybFilter->bufferHFReal[k] = pMem; |
281 | 823k | pMem += (qmfBands - setup->nrQmfBands); |
282 | 823k | hAnalysisHybFilter->bufferHFImag[k] = pMem; |
283 | 823k | pMem += (cplxBands - setup->nrQmfBands); |
284 | 823k | } |
285 | 137k | } |
286 | | |
287 | 141k | if (initStatesFlag) { |
288 | | /* Clear LF buffer */ |
289 | 69.4k | for (k = 0; k < setup->nrQmfBands; k++) { |
290 | 52.0k | FDKmemclear(hAnalysisHybFilter->bufferLFReal[k], |
291 | 52.0k | setup->protoLen * sizeof(FIXP_DBL)); |
292 | 52.0k | FDKmemclear(hAnalysisHybFilter->bufferLFImag[k], |
293 | 52.0k | setup->protoLen * sizeof(FIXP_DBL)); |
294 | 52.0k | } |
295 | | |
296 | 17.3k | if (hAnalysisHybFilter->HFmemorySize != 0) { |
297 | 13.2k | if (qmfBands > setup->nrQmfBands) { |
298 | | /* Clear HF buffer */ |
299 | 92.4k | for (k = 0; k < setup->filterDelay; k++) { |
300 | 79.2k | FDKmemclear(hAnalysisHybFilter->bufferHFReal[k], |
301 | 79.2k | (qmfBands - setup->nrQmfBands) * sizeof(FIXP_DBL)); |
302 | 79.2k | FDKmemclear(hAnalysisHybFilter->bufferHFImag[k], |
303 | 79.2k | (cplxBands - setup->nrQmfBands) * sizeof(FIXP_DBL)); |
304 | 79.2k | } |
305 | 13.2k | } |
306 | 13.2k | } |
307 | 17.3k | } |
308 | | |
309 | 141k | bail: |
310 | 141k | return err; |
311 | 141k | } |
312 | | |
313 | | INT FDKhybridAnalysisScaleStates(HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter, |
314 | 0 | const INT scalingValue) { |
315 | 0 | INT err = 0; |
316 | |
|
317 | 0 | if (hAnalysisHybFilter == NULL) { |
318 | 0 | err = 1; /* invalid handle */ |
319 | 0 | } else { |
320 | 0 | int k; |
321 | 0 | HANDLE_FDK_HYBRID_SETUP setup = hAnalysisHybFilter->pSetup; |
322 | | |
323 | | /* Scale LF buffer */ |
324 | 0 | for (k = 0; k < setup->nrQmfBands; k++) { |
325 | 0 | scaleValues(hAnalysisHybFilter->bufferLFReal[k], setup->protoLen, |
326 | 0 | scalingValue); |
327 | 0 | scaleValues(hAnalysisHybFilter->bufferLFImag[k], setup->protoLen, |
328 | 0 | scalingValue); |
329 | 0 | } |
330 | 0 | if (hAnalysisHybFilter->nrBands > setup->nrQmfBands) { |
331 | | /* Scale HF buffer */ |
332 | 0 | for (k = 0; k < setup->filterDelay; k++) { |
333 | 0 | scaleValues(hAnalysisHybFilter->bufferHFReal[k], |
334 | 0 | (hAnalysisHybFilter->nrBands - setup->nrQmfBands), |
335 | 0 | scalingValue); |
336 | 0 | scaleValues(hAnalysisHybFilter->bufferHFImag[k], |
337 | 0 | (hAnalysisHybFilter->cplxBands - setup->nrQmfBands), |
338 | 0 | scalingValue); |
339 | 0 | } |
340 | 0 | } |
341 | 0 | } |
342 | 0 | return err; |
343 | 0 | } |
344 | | |
345 | | INT FDKhybridAnalysisApply(HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter, |
346 | | const FIXP_DBL *const pQmfReal, |
347 | | const FIXP_DBL *const pQmfImag, |
348 | | FIXP_DBL *const pHybridReal, |
349 | 7.21M | FIXP_DBL *const pHybridImag) { |
350 | 7.21M | int k, hybOffset = 0; |
351 | 7.21M | INT err = 0; |
352 | 7.21M | const int nrQmfBandsLF = |
353 | 7.21M | hAnalysisHybFilter->pSetup |
354 | 7.21M | ->nrQmfBands; /* number of QMF bands to be converted to hybrid */ |
355 | | |
356 | 7.21M | const int writIndex = hAnalysisHybFilter->bufferLFpos; |
357 | 7.21M | int readIndex = hAnalysisHybFilter->bufferLFpos; |
358 | | |
359 | 7.21M | if (++readIndex >= hAnalysisHybFilter->pSetup->protoLen) readIndex = 0; |
360 | 7.21M | const INT *pBufferLFreadIdx = |
361 | 7.21M | &hAnalysisHybFilter->pSetup->pReadIdxTable[readIndex]; |
362 | | |
363 | | /* |
364 | | * LF buffer. |
365 | | */ |
366 | 28.8M | for (k = 0; k < nrQmfBandsLF; k++) { |
367 | | /* New input sample. */ |
368 | 21.6M | hAnalysisHybFilter->bufferLFReal[k][writIndex] = pQmfReal[k]; |
369 | 21.6M | hAnalysisHybFilter->bufferLFImag[k][writIndex] = pQmfImag[k]; |
370 | | |
371 | | /* Perform hybrid filtering. */ |
372 | 21.6M | err |= |
373 | 21.6M | kChannelFiltering(hAnalysisHybFilter->bufferLFReal[k], |
374 | 21.6M | hAnalysisHybFilter->bufferLFImag[k], pBufferLFreadIdx, |
375 | 21.6M | pHybridReal + hybOffset, pHybridImag + hybOffset, |
376 | 21.6M | hAnalysisHybFilter->pSetup->kHybrid[k]); |
377 | | |
378 | 21.6M | hybOffset += hAnalysisHybFilter->pSetup->nHybBands[k]; |
379 | 21.6M | } |
380 | | |
381 | 7.21M | hAnalysisHybFilter->bufferLFpos = |
382 | 7.21M | readIndex; /* Index where to write next input sample. */ |
383 | | |
384 | 7.21M | if (hAnalysisHybFilter->nrBands > nrQmfBandsLF) { |
385 | | /* |
386 | | * HF buffer. |
387 | | */ |
388 | 7.10M | if (hAnalysisHybFilter->hfMode != 0) { |
389 | | /* HF delay compensation was applied outside. */ |
390 | 4.90M | FDKmemcpy( |
391 | 4.90M | pHybridReal + hybOffset, &pQmfReal[nrQmfBandsLF], |
392 | 4.90M | (hAnalysisHybFilter->nrBands - nrQmfBandsLF) * sizeof(FIXP_DBL)); |
393 | 4.90M | FDKmemcpy( |
394 | 4.90M | pHybridImag + hybOffset, &pQmfImag[nrQmfBandsLF], |
395 | 4.90M | (hAnalysisHybFilter->cplxBands - nrQmfBandsLF) * sizeof(FIXP_DBL)); |
396 | 4.90M | } else { |
397 | 2.19M | FDK_ASSERT(hAnalysisHybFilter->HFmemorySize != 0); |
398 | | /* HF delay compensation, filterlength/2. */ |
399 | 2.19M | FDKmemcpy( |
400 | 2.19M | pHybridReal + hybOffset, |
401 | 2.19M | hAnalysisHybFilter->bufferHFReal[hAnalysisHybFilter->bufferHFpos], |
402 | 2.19M | (hAnalysisHybFilter->nrBands - nrQmfBandsLF) * sizeof(FIXP_DBL)); |
403 | 2.19M | FDKmemcpy( |
404 | 2.19M | pHybridImag + hybOffset, |
405 | 2.19M | hAnalysisHybFilter->bufferHFImag[hAnalysisHybFilter->bufferHFpos], |
406 | 2.19M | (hAnalysisHybFilter->cplxBands - nrQmfBandsLF) * sizeof(FIXP_DBL)); |
407 | | |
408 | 2.19M | FDKmemcpy( |
409 | 2.19M | hAnalysisHybFilter->bufferHFReal[hAnalysisHybFilter->bufferHFpos], |
410 | 2.19M | &pQmfReal[nrQmfBandsLF], |
411 | 2.19M | (hAnalysisHybFilter->nrBands - nrQmfBandsLF) * sizeof(FIXP_DBL)); |
412 | 2.19M | FDKmemcpy( |
413 | 2.19M | hAnalysisHybFilter->bufferHFImag[hAnalysisHybFilter->bufferHFpos], |
414 | 2.19M | &pQmfImag[nrQmfBandsLF], |
415 | 2.19M | (hAnalysisHybFilter->cplxBands - nrQmfBandsLF) * sizeof(FIXP_DBL)); |
416 | | |
417 | 2.19M | if (++hAnalysisHybFilter->bufferHFpos >= |
418 | 2.19M | hAnalysisHybFilter->pSetup->filterDelay) |
419 | 363k | hAnalysisHybFilter->bufferHFpos = 0; |
420 | 2.19M | } |
421 | 7.10M | } /* process HF part*/ |
422 | | |
423 | 7.21M | return err; |
424 | 7.21M | } |
425 | | |
426 | 0 | INT FDKhybridAnalysisClose(HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter) { |
427 | 0 | INT err = 0; |
428 | |
|
429 | 0 | if (hAnalysisHybFilter != NULL) { |
430 | 0 | hAnalysisHybFilter->pLFmemory = NULL; |
431 | 0 | hAnalysisHybFilter->pHFmemory = NULL; |
432 | 0 | hAnalysisHybFilter->LFmemorySize = 0; |
433 | 0 | hAnalysisHybFilter->HFmemorySize = 0; |
434 | 0 | } |
435 | |
|
436 | 0 | return err; |
437 | 0 | } |
438 | | |
439 | | INT FDKhybridSynthesisInit(HANDLE_FDK_SYN_HYB_FILTER hSynthesisHybFilter, |
440 | | const FDK_HYBRID_MODE mode, const INT qmfBands, |
441 | 145k | const INT cplxBands) { |
442 | 145k | INT err = 0; |
443 | 145k | HANDLE_FDK_HYBRID_SETUP setup = NULL; |
444 | | |
445 | 145k | switch (mode) { |
446 | 145k | case THREE_TO_TEN: |
447 | 145k | setup = &setup_3_10; |
448 | 145k | break; |
449 | 0 | case THREE_TO_TWELVE: |
450 | 0 | setup = &setup_3_12; |
451 | 0 | break; |
452 | 0 | case THREE_TO_SIXTEEN: |
453 | 0 | setup = &setup_3_16; |
454 | 0 | break; |
455 | 0 | default: |
456 | 0 | err = -1; |
457 | 0 | goto bail; |
458 | 145k | } |
459 | | |
460 | 145k | hSynthesisHybFilter->pSetup = setup; |
461 | 145k | hSynthesisHybFilter->nrBands = qmfBands; |
462 | 145k | hSynthesisHybFilter->cplxBands = cplxBands; |
463 | | |
464 | 145k | bail: |
465 | 145k | return err; |
466 | 145k | } |
467 | | |
468 | | void FDKhybridSynthesisApply(HANDLE_FDK_SYN_HYB_FILTER hSynthesisHybFilter, |
469 | | const FIXP_DBL *const pHybridReal, |
470 | | const FIXP_DBL *const pHybridImag, |
471 | | FIXP_DBL *const pQmfReal, |
472 | 12.1M | FIXP_DBL *const pQmfImag) { |
473 | 12.1M | int k, n, hybOffset = 0; |
474 | 12.1M | const INT nrQmfBandsLF = hSynthesisHybFilter->pSetup->nrQmfBands; |
475 | | |
476 | | /* |
477 | | * LF buffer. |
478 | | */ |
479 | 48.5M | for (k = 0; k < nrQmfBandsLF; k++) { |
480 | 36.4M | const int nHybBands = hSynthesisHybFilter->pSetup->nHybBands[k]; |
481 | 36.4M | const int scale = hSynthesisHybFilter->pSetup->synHybScale[k]; |
482 | | |
483 | 36.4M | FIXP_DBL accu1 = FL2FXCONST_DBL(0.f); |
484 | 36.4M | FIXP_DBL accu2 = FL2FXCONST_DBL(0.f); |
485 | | |
486 | | /* Perform hybrid filtering. */ |
487 | 157M | for (n = 0; n < nHybBands; n++) { |
488 | 121M | accu1 += pHybridReal[hybOffset + n] >> scale; |
489 | 121M | accu2 += pHybridImag[hybOffset + n] >> scale; |
490 | 121M | } |
491 | 36.4M | pQmfReal[k] = SATURATE_LEFT_SHIFT(accu1, scale, DFRACT_BITS); |
492 | 36.4M | pQmfImag[k] = SATURATE_LEFT_SHIFT(accu2, scale, DFRACT_BITS); |
493 | | |
494 | 36.4M | hybOffset += nHybBands; |
495 | 36.4M | } |
496 | | |
497 | 12.1M | if (hSynthesisHybFilter->nrBands > nrQmfBandsLF) { |
498 | | /* |
499 | | * HF buffer. |
500 | | */ |
501 | 12.1M | FDKmemcpy(&pQmfReal[nrQmfBandsLF], &pHybridReal[hybOffset], |
502 | 12.1M | (hSynthesisHybFilter->nrBands - nrQmfBandsLF) * sizeof(FIXP_DBL)); |
503 | 12.1M | FDKmemcpy( |
504 | 12.1M | &pQmfImag[nrQmfBandsLF], &pHybridImag[hybOffset], |
505 | 12.1M | (hSynthesisHybFilter->cplxBands - nrQmfBandsLF) * sizeof(FIXP_DBL)); |
506 | 12.1M | } |
507 | | |
508 | 12.1M | return; |
509 | 12.1M | } |
510 | | |
511 | | static void dualChannelFiltering(const FIXP_DBL *const pQmfReal, |
512 | | const FIXP_DBL *const pQmfImag, |
513 | | const INT *const pReadIdx, |
514 | | FIXP_DBL *const mHybridReal, |
515 | | FIXP_DBL *const mHybridImag, |
516 | 14.4M | const INT invert) { |
517 | 14.4M | FIXP_DBL r1, r6; |
518 | 14.4M | FIXP_DBL i1, i6; |
519 | | |
520 | 14.4M | const FIXP_HTB f0 = HybFilterCoef2[0]; /* corresponds to p1 and p11 */ |
521 | 14.4M | const FIXP_HTB f1 = HybFilterCoef2[1]; /* corresponds to p3 and p9 */ |
522 | 14.4M | const FIXP_HTB f2 = HybFilterCoef2[2]; /* corresponds to p5 and p7 */ |
523 | | |
524 | | /* symmetric filter coefficients */ |
525 | 14.4M | r1 = fMultDiv2(f0, pQmfReal[pReadIdx[1]]) + |
526 | 14.4M | fMultDiv2(f0, pQmfReal[pReadIdx[11]]); |
527 | 14.4M | i1 = fMultDiv2(f0, pQmfImag[pReadIdx[1]]) + |
528 | 14.4M | fMultDiv2(f0, pQmfImag[pReadIdx[11]]); |
529 | 14.4M | r1 += fMultDiv2(f1, pQmfReal[pReadIdx[3]]) + |
530 | 14.4M | fMultDiv2(f1, pQmfReal[pReadIdx[9]]); |
531 | 14.4M | i1 += fMultDiv2(f1, pQmfImag[pReadIdx[3]]) + |
532 | 14.4M | fMultDiv2(f1, pQmfImag[pReadIdx[9]]); |
533 | 14.4M | r1 += fMultDiv2(f2, pQmfReal[pReadIdx[5]]) + |
534 | 14.4M | fMultDiv2(f2, pQmfReal[pReadIdx[7]]); |
535 | 14.4M | i1 += fMultDiv2(f2, pQmfImag[pReadIdx[5]]) + |
536 | 14.4M | fMultDiv2(f2, pQmfImag[pReadIdx[7]]); |
537 | | |
538 | 14.4M | r6 = pQmfReal[pReadIdx[6]] >> 2; |
539 | 14.4M | i6 = pQmfImag[pReadIdx[6]] >> 2; |
540 | | |
541 | 14.4M | FDK_ASSERT((invert == 0) || (invert == 1)); |
542 | 14.4M | mHybridReal[0 + invert] = SATURATE_LEFT_SHIFT((r6 + r1), 1, DFRACT_BITS); |
543 | 14.4M | mHybridImag[0 + invert] = SATURATE_LEFT_SHIFT((i6 + i1), 1, DFRACT_BITS); |
544 | | |
545 | 14.4M | mHybridReal[1 - invert] = SATURATE_LEFT_SHIFT((r6 - r1), 1, DFRACT_BITS); |
546 | 14.4M | mHybridImag[1 - invert] = SATURATE_LEFT_SHIFT((i6 - i1), 1, DFRACT_BITS); |
547 | 14.4M | } |
548 | | |
549 | | static void fourChannelFiltering(const FIXP_DBL *const pQmfReal, |
550 | | const FIXP_DBL *const pQmfImag, |
551 | | const INT *const pReadIdx, |
552 | | FIXP_DBL *const mHybridReal, |
553 | | FIXP_DBL *const mHybridImag, |
554 | 0 | const INT invert) { |
555 | 0 | const FIXP_HTB *p = HybFilterCoef4; |
556 | |
|
557 | 0 | FIXP_DBL fft[8]; |
558 | |
|
559 | 0 | static const FIXP_DBL cr[13] = { |
560 | 0 | FL2FXCONST_DBL(0.f), FL2FXCONST_DBL(-0.70710678118655f), |
561 | 0 | FL2FXCONST_DBL(-1.f), FL2FXCONST_DBL(-0.70710678118655f), |
562 | 0 | FL2FXCONST_DBL(0.f), FL2FXCONST_DBL(0.70710678118655f), |
563 | 0 | FL2FXCONST_DBL(1.f), FL2FXCONST_DBL(0.70710678118655f), |
564 | 0 | FL2FXCONST_DBL(0.f), FL2FXCONST_DBL(-0.70710678118655f), |
565 | 0 | FL2FXCONST_DBL(-1.f), FL2FXCONST_DBL(-0.70710678118655f), |
566 | 0 | FL2FXCONST_DBL(0.f)}; |
567 | 0 | static const FIXP_DBL ci[13] = { |
568 | 0 | FL2FXCONST_DBL(-1.f), FL2FXCONST_DBL(-0.70710678118655f), |
569 | 0 | FL2FXCONST_DBL(0.f), FL2FXCONST_DBL(0.70710678118655f), |
570 | 0 | FL2FXCONST_DBL(1.f), FL2FXCONST_DBL(0.70710678118655f), |
571 | 0 | FL2FXCONST_DBL(0.f), FL2FXCONST_DBL(-0.70710678118655f), |
572 | 0 | FL2FXCONST_DBL(-1.f), FL2FXCONST_DBL(-0.70710678118655f), |
573 | 0 | FL2FXCONST_DBL(0.f), FL2FXCONST_DBL(0.70710678118655f), |
574 | 0 | FL2FXCONST_DBL(1.f)}; |
575 | | |
576 | | /* FIR filter. */ |
577 | | /* pre twiddeling with pre-twiddling coefficients c[n] */ |
578 | | /* multiplication with filter coefficients p[n] */ |
579 | | /* hint: (a + ib)*(c + id) = (a*c - b*d) + i(a*d + b*c) */ |
580 | | /* write to fft coefficient n' */ |
581 | 0 | fft[FFT_IDX_R(0)] = |
582 | 0 | (fMult(p[10], (fMultSub(fMultDiv2(cr[2], pQmfReal[pReadIdx[2]]), ci[2], |
583 | 0 | pQmfImag[pReadIdx[2]]))) + |
584 | 0 | fMult(p[6], (fMultSub(fMultDiv2(cr[6], pQmfReal[pReadIdx[6]]), ci[6], |
585 | 0 | pQmfImag[pReadIdx[6]]))) + |
586 | 0 | fMult(p[2], (fMultSub(fMultDiv2(cr[10], pQmfReal[pReadIdx[10]]), ci[10], |
587 | 0 | pQmfImag[pReadIdx[10]])))); |
588 | 0 | fft[FFT_IDX_I(0)] = |
589 | 0 | (fMult(p[10], (fMultAdd(fMultDiv2(ci[2], pQmfReal[pReadIdx[2]]), cr[2], |
590 | 0 | pQmfImag[pReadIdx[2]]))) + |
591 | 0 | fMult(p[6], (fMultAdd(fMultDiv2(ci[6], pQmfReal[pReadIdx[6]]), cr[6], |
592 | 0 | pQmfImag[pReadIdx[6]]))) + |
593 | 0 | fMult(p[2], (fMultAdd(fMultDiv2(ci[10], pQmfReal[pReadIdx[10]]), cr[10], |
594 | 0 | pQmfImag[pReadIdx[10]])))); |
595 | | |
596 | | /* twiddle dee dum */ |
597 | 0 | fft[FFT_IDX_R(1)] = |
598 | 0 | (fMult(p[9], (fMultSub(fMultDiv2(cr[3], pQmfReal[pReadIdx[3]]), ci[3], |
599 | 0 | pQmfImag[pReadIdx[3]]))) + |
600 | 0 | fMult(p[5], (fMultSub(fMultDiv2(cr[7], pQmfReal[pReadIdx[7]]), ci[7], |
601 | 0 | pQmfImag[pReadIdx[7]]))) + |
602 | 0 | fMult(p[1], (fMultSub(fMultDiv2(cr[11], pQmfReal[pReadIdx[11]]), ci[11], |
603 | 0 | pQmfImag[pReadIdx[11]])))); |
604 | 0 | fft[FFT_IDX_I(1)] = |
605 | 0 | (fMult(p[9], (fMultAdd(fMultDiv2(ci[3], pQmfReal[pReadIdx[3]]), cr[3], |
606 | 0 | pQmfImag[pReadIdx[3]]))) + |
607 | 0 | fMult(p[5], (fMultAdd(fMultDiv2(ci[7], pQmfReal[pReadIdx[7]]), cr[7], |
608 | 0 | pQmfImag[pReadIdx[7]]))) + |
609 | 0 | fMult(p[1], (fMultAdd(fMultDiv2(ci[11], pQmfReal[pReadIdx[11]]), cr[11], |
610 | 0 | pQmfImag[pReadIdx[11]])))); |
611 | | |
612 | | /* twiddle dee dee */ |
613 | 0 | fft[FFT_IDX_R(2)] = |
614 | 0 | (fMult(p[12], (fMultSub(fMultDiv2(cr[0], pQmfReal[pReadIdx[0]]), ci[0], |
615 | 0 | pQmfImag[pReadIdx[0]]))) + |
616 | 0 | fMult(p[8], (fMultSub(fMultDiv2(cr[4], pQmfReal[pReadIdx[4]]), ci[4], |
617 | 0 | pQmfImag[pReadIdx[4]]))) + |
618 | 0 | fMult(p[4], (fMultSub(fMultDiv2(cr[8], pQmfReal[pReadIdx[8]]), ci[8], |
619 | 0 | pQmfImag[pReadIdx[8]]))) + |
620 | 0 | fMult(p[0], (fMultSub(fMultDiv2(cr[12], pQmfReal[pReadIdx[12]]), ci[12], |
621 | 0 | pQmfImag[pReadIdx[12]])))); |
622 | 0 | fft[FFT_IDX_I(2)] = |
623 | 0 | (fMult(p[12], (fMultAdd(fMultDiv2(ci[0], pQmfReal[pReadIdx[0]]), cr[0], |
624 | 0 | pQmfImag[pReadIdx[0]]))) + |
625 | 0 | fMult(p[8], (fMultAdd(fMultDiv2(ci[4], pQmfReal[pReadIdx[4]]), cr[4], |
626 | 0 | pQmfImag[pReadIdx[4]]))) + |
627 | 0 | fMult(p[4], (fMultAdd(fMultDiv2(ci[8], pQmfReal[pReadIdx[8]]), cr[8], |
628 | 0 | pQmfImag[pReadIdx[8]]))) + |
629 | 0 | fMult(p[0], (fMultAdd(fMultDiv2(ci[12], pQmfReal[pReadIdx[12]]), cr[12], |
630 | 0 | pQmfImag[pReadIdx[12]])))); |
631 | |
|
632 | 0 | fft[FFT_IDX_R(3)] = |
633 | 0 | (fMult(p[11], (fMultSub(fMultDiv2(cr[1], pQmfReal[pReadIdx[1]]), ci[1], |
634 | 0 | pQmfImag[pReadIdx[1]]))) + |
635 | 0 | fMult(p[7], (fMultSub(fMultDiv2(cr[5], pQmfReal[pReadIdx[5]]), ci[5], |
636 | 0 | pQmfImag[pReadIdx[5]]))) + |
637 | 0 | fMult(p[3], (fMultSub(fMultDiv2(cr[9], pQmfReal[pReadIdx[9]]), ci[9], |
638 | 0 | pQmfImag[pReadIdx[9]])))); |
639 | 0 | fft[FFT_IDX_I(3)] = |
640 | 0 | (fMult(p[11], (fMultAdd(fMultDiv2(ci[1], pQmfReal[pReadIdx[1]]), cr[1], |
641 | 0 | pQmfImag[pReadIdx[1]]))) + |
642 | 0 | fMult(p[7], (fMultAdd(fMultDiv2(ci[5], pQmfReal[pReadIdx[5]]), cr[5], |
643 | 0 | pQmfImag[pReadIdx[5]]))) + |
644 | 0 | fMult(p[3], (fMultAdd(fMultDiv2(ci[9], pQmfReal[pReadIdx[9]]), cr[9], |
645 | 0 | pQmfImag[pReadIdx[9]])))); |
646 | | |
647 | | /* fft modulation */ |
648 | | /* here: fast manual fft modulation for a fft of length M=4 */ |
649 | | /* fft_4{x[n]} = x[0]*exp(-i*2*pi/4*m*0) + x[1]*exp(-i*2*pi/4*m*1) + |
650 | | x[2]*exp(-i*2*pi/4*m*2) + x[3]*exp(-i*2*pi/4*m*3) */ |
651 | | |
652 | | /* |
653 | | fft bin m=0: |
654 | | X[0, n] = x[0] + x[1] + x[2] + x[3] |
655 | | */ |
656 | 0 | mHybridReal[0] = fft[FFT_IDX_R(0)] + fft[FFT_IDX_R(1)] + fft[FFT_IDX_R(2)] + |
657 | 0 | fft[FFT_IDX_R(3)]; |
658 | 0 | mHybridImag[0] = fft[FFT_IDX_I(0)] + fft[FFT_IDX_I(1)] + fft[FFT_IDX_I(2)] + |
659 | 0 | fft[FFT_IDX_I(3)]; |
660 | | |
661 | | /* |
662 | | fft bin m=1: |
663 | | X[1, n] = x[0] - i*x[1] - x[2] + i*x[3] |
664 | | */ |
665 | 0 | mHybridReal[1] = fft[FFT_IDX_R(0)] + fft[FFT_IDX_I(1)] - fft[FFT_IDX_R(2)] - |
666 | 0 | fft[FFT_IDX_I(3)]; |
667 | 0 | mHybridImag[1] = fft[FFT_IDX_I(0)] - fft[FFT_IDX_R(1)] - fft[FFT_IDX_I(2)] + |
668 | 0 | fft[FFT_IDX_R(3)]; |
669 | | |
670 | | /* |
671 | | fft bin m=2: |
672 | | X[2, n] = x[0] - x[1] + x[2] - x[3] |
673 | | */ |
674 | 0 | mHybridReal[2] = fft[FFT_IDX_R(0)] - fft[FFT_IDX_R(1)] + fft[FFT_IDX_R(2)] - |
675 | 0 | fft[FFT_IDX_R(3)]; |
676 | 0 | mHybridImag[2] = fft[FFT_IDX_I(0)] - fft[FFT_IDX_I(1)] + fft[FFT_IDX_I(2)] - |
677 | 0 | fft[FFT_IDX_I(3)]; |
678 | | |
679 | | /* |
680 | | fft bin m=3: |
681 | | X[3, n] = x[0] + j*x[1] - x[2] - j*x[3] |
682 | | */ |
683 | 0 | mHybridReal[3] = fft[FFT_IDX_R(0)] - fft[FFT_IDX_I(1)] - fft[FFT_IDX_R(2)] + |
684 | 0 | fft[FFT_IDX_I(3)]; |
685 | 0 | mHybridImag[3] = fft[FFT_IDX_I(0)] + fft[FFT_IDX_R(1)] - fft[FFT_IDX_I(2)] - |
686 | 0 | fft[FFT_IDX_R(3)]; |
687 | 0 | } |
688 | | |
689 | | static void eightChannelFiltering(const FIXP_DBL *const pQmfReal, |
690 | | const FIXP_DBL *const pQmfImag, |
691 | | const INT *const pReadIdx, |
692 | | FIXP_DBL *const mHybridReal, |
693 | | FIXP_DBL *const mHybridImag, |
694 | 7.21M | const INT invert) { |
695 | 7.21M | const FIXP_HTP *p = HybFilterCoef8; |
696 | 7.21M | INT k, sc; |
697 | | |
698 | 7.21M | FIXP_DBL mfft[16 + ALIGNMENT_DEFAULT]; |
699 | 7.21M | FIXP_DBL *pfft = (FIXP_DBL *)ALIGN_PTR(mfft); |
700 | | |
701 | 7.21M | FIXP_DBL accu1, accu2, accu3, accu4; |
702 | | |
703 | | /* pre twiddeling */ |
704 | 7.21M | pfft[FFT_IDX_R(0)] = |
705 | 7.21M | pQmfReal[pReadIdx[6]] >> |
706 | 7.21M | (3 + 1); /* fMultDiv2(p[0].v.re, pQmfReal[pReadIdx[6]]); */ |
707 | 7.21M | pfft[FFT_IDX_I(0)] = |
708 | 7.21M | pQmfImag[pReadIdx[6]] >> |
709 | 7.21M | (3 + 1); /* fMultDiv2(p[0].v.re, pQmfImag[pReadIdx[6]]); */ |
710 | | |
711 | 7.21M | cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[7]], pQmfImag[pReadIdx[7]], |
712 | 7.21M | p[1]); |
713 | 7.21M | pfft[FFT_IDX_R(1)] = accu1; |
714 | 7.21M | pfft[FFT_IDX_I(1)] = accu2; |
715 | | |
716 | 7.21M | cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[0]], pQmfImag[pReadIdx[0]], |
717 | 7.21M | p[2]); |
718 | 7.21M | cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[8]], pQmfImag[pReadIdx[8]], |
719 | 7.21M | p[3]); |
720 | 7.21M | pfft[FFT_IDX_R(2)] = accu1 + accu3; |
721 | 7.21M | pfft[FFT_IDX_I(2)] = accu2 + accu4; |
722 | | |
723 | 7.21M | cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[1]], pQmfImag[pReadIdx[1]], |
724 | 7.21M | p[4]); |
725 | 7.21M | cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[9]], pQmfImag[pReadIdx[9]], |
726 | 7.21M | p[5]); |
727 | 7.21M | pfft[FFT_IDX_R(3)] = accu1 + accu3; |
728 | 7.21M | pfft[FFT_IDX_I(3)] = accu2 + accu4; |
729 | | |
730 | 7.21M | pfft[FFT_IDX_R(4)] = fMultDiv2(pQmfImag[pReadIdx[10]], p[7].v.im) - |
731 | 7.21M | fMultDiv2(pQmfImag[pReadIdx[2]], p[6].v.im); |
732 | 7.21M | pfft[FFT_IDX_I(4)] = fMultDiv2(pQmfReal[pReadIdx[2]], p[6].v.im) - |
733 | 7.21M | fMultDiv2(pQmfReal[pReadIdx[10]], p[7].v.im); |
734 | | |
735 | 7.21M | cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[3]], pQmfImag[pReadIdx[3]], |
736 | 7.21M | p[8]); |
737 | 7.21M | cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[11]], pQmfImag[pReadIdx[11]], |
738 | 7.21M | p[9]); |
739 | 7.21M | pfft[FFT_IDX_R(5)] = accu1 + accu3; |
740 | 7.21M | pfft[FFT_IDX_I(5)] = accu2 + accu4; |
741 | | |
742 | 7.21M | cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[4]], pQmfImag[pReadIdx[4]], |
743 | 7.21M | p[10]); |
744 | 7.21M | cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[12]], pQmfImag[pReadIdx[12]], |
745 | 7.21M | p[11]); |
746 | 7.21M | pfft[FFT_IDX_R(6)] = accu1 + accu3; |
747 | 7.21M | pfft[FFT_IDX_I(6)] = accu2 + accu4; |
748 | | |
749 | 7.21M | cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[5]], pQmfImag[pReadIdx[5]], |
750 | 7.21M | p[12]); |
751 | 7.21M | pfft[FFT_IDX_R(7)] = accu1; |
752 | 7.21M | pfft[FFT_IDX_I(7)] = accu2; |
753 | | |
754 | | /* fft modulation */ |
755 | 7.21M | fft_8(pfft); |
756 | 7.21M | sc = 1 + 2; |
757 | | |
758 | 7.21M | if (invert) { |
759 | 7.21M | mHybridReal[0] = pfft[FFT_IDX_R(7)] << sc; |
760 | 7.21M | mHybridImag[0] = pfft[FFT_IDX_I(7)] << sc; |
761 | 7.21M | mHybridReal[1] = pfft[FFT_IDX_R(0)] << sc; |
762 | 7.21M | mHybridImag[1] = pfft[FFT_IDX_I(0)] << sc; |
763 | | |
764 | 7.21M | mHybridReal[2] = pfft[FFT_IDX_R(6)] << sc; |
765 | 7.21M | mHybridImag[2] = pfft[FFT_IDX_I(6)] << sc; |
766 | 7.21M | mHybridReal[3] = pfft[FFT_IDX_R(1)] << sc; |
767 | 7.21M | mHybridImag[3] = pfft[FFT_IDX_I(1)] << sc; |
768 | | |
769 | 7.21M | mHybridReal[4] = SATURATE_LEFT_SHIFT( |
770 | 7.21M | (pfft[FFT_IDX_R(2)] + pfft[FFT_IDX_R(5)]), sc, DFRACT_BITS); |
771 | 7.21M | mHybridImag[4] = SATURATE_LEFT_SHIFT( |
772 | 7.21M | (pfft[FFT_IDX_I(2)] + pfft[FFT_IDX_I(5)]), sc, DFRACT_BITS); |
773 | | |
774 | 7.21M | mHybridReal[5] = SATURATE_LEFT_SHIFT( |
775 | 7.21M | (pfft[FFT_IDX_R(3)] + pfft[FFT_IDX_R(4)]), sc, DFRACT_BITS); |
776 | 7.21M | mHybridImag[5] = SATURATE_LEFT_SHIFT( |
777 | 7.21M | (pfft[FFT_IDX_I(3)] + pfft[FFT_IDX_I(4)]), sc, DFRACT_BITS); |
778 | 7.21M | } else { |
779 | 0 | for (k = 0; k < 8; k++) { |
780 | 0 | mHybridReal[k] = pfft[FFT_IDX_R(k)] << sc; |
781 | 0 | mHybridImag[k] = pfft[FFT_IDX_I(k)] << sc; |
782 | 0 | } |
783 | 0 | } |
784 | 7.21M | } |
785 | | |
786 | | static INT kChannelFiltering(const FIXP_DBL *const pQmfReal, |
787 | | const FIXP_DBL *const pQmfImag, |
788 | | const INT *const pReadIdx, |
789 | | FIXP_DBL *const mHybridReal, |
790 | | FIXP_DBL *const mHybridImag, |
791 | 21.6M | const SCHAR hybridConfig) { |
792 | 21.6M | INT err = 0; |
793 | | |
794 | 21.6M | switch (hybridConfig) { |
795 | 7.21M | case 2: |
796 | 14.4M | case -2: |
797 | 14.4M | dualChannelFiltering(pQmfReal, pQmfImag, pReadIdx, mHybridReal, |
798 | 14.4M | mHybridImag, (hybridConfig < 0) ? 1 : 0); |
799 | 14.4M | break; |
800 | 0 | case 4: |
801 | 0 | case -4: |
802 | 0 | fourChannelFiltering(pQmfReal, pQmfImag, pReadIdx, mHybridReal, |
803 | 0 | mHybridImag, (hybridConfig < 0) ? 1 : 0); |
804 | 0 | break; |
805 | 0 | case 8: |
806 | 7.21M | case -8: |
807 | 7.21M | eightChannelFiltering(pQmfReal, pQmfImag, pReadIdx, mHybridReal, |
808 | 7.21M | mHybridImag, (hybridConfig < 0) ? 1 : 0); |
809 | 7.21M | break; |
810 | 0 | default: |
811 | 0 | err = -1; |
812 | 21.6M | } |
813 | | |
814 | 21.6M | return err; |
815 | 21.6M | } |