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