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 #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 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
FDKhybridAnalysisOpen(HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter,FIXP_DBL * const pLFmemory,const UINT LFmemorySize,FIXP_DBL * const pHFmemory,const UINT HFmemorySize)204 INT FDKhybridAnalysisOpen(HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter,
205 FIXP_DBL *const pLFmemory, const UINT LFmemorySize,
206 FIXP_DBL *const pHFmemory, const UINT HFmemorySize) {
207 INT err = 0;
208
209 /* Save pointer to extern memory. */
210 hAnalysisHybFilter->pLFmemory = pLFmemory;
211 hAnalysisHybFilter->LFmemorySize = LFmemorySize;
212
213 hAnalysisHybFilter->pHFmemory = pHFmemory;
214 hAnalysisHybFilter->HFmemorySize = HFmemorySize;
215
216 return err;
217 }
218
FDKhybridAnalysisInit(HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter,const FDK_HYBRID_MODE mode,const INT qmfBands,const INT cplxBands,const INT initStatesFlag)219 INT FDKhybridAnalysisInit(HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter,
220 const FDK_HYBRID_MODE mode, const INT qmfBands,
221 const INT cplxBands, const INT initStatesFlag) {
222 int k;
223 INT err = 0;
224 FIXP_DBL *pMem = NULL;
225 HANDLE_FDK_HYBRID_SETUP setup = NULL;
226
227 switch (mode) {
228 case THREE_TO_TEN:
229 setup = &setup_3_10;
230 break;
231 case THREE_TO_TWELVE:
232 setup = &setup_3_12;
233 break;
234 case THREE_TO_SIXTEEN:
235 setup = &setup_3_16;
236 break;
237 default:
238 err = -1;
239 goto bail;
240 }
241
242 /* Initialize handle. */
243 hAnalysisHybFilter->pSetup = setup;
244 if (initStatesFlag) {
245 hAnalysisHybFilter->bufferLFpos = setup->protoLen - 1;
246 hAnalysisHybFilter->bufferHFpos = 0;
247 }
248 hAnalysisHybFilter->nrBands = qmfBands;
249 hAnalysisHybFilter->cplxBands = cplxBands;
250 hAnalysisHybFilter->hfMode = 0;
251
252 /* Check available memory. */
253 if (((2 * setup->nrQmfBands * setup->protoLen * sizeof(FIXP_DBL)) >
254 hAnalysisHybFilter->LFmemorySize)) {
255 err = -2;
256 goto bail;
257 }
258 if (hAnalysisHybFilter->HFmemorySize != 0) {
259 if (((setup->filterDelay *
260 ((qmfBands - setup->nrQmfBands) + (cplxBands - setup->nrQmfBands)) *
261 sizeof(FIXP_DBL)) > hAnalysisHybFilter->HFmemorySize)) {
262 err = -3;
263 goto bail;
264 }
265 }
266
267 /* Distribute LF memory. */
268 pMem = hAnalysisHybFilter->pLFmemory;
269 for (k = 0; k < setup->nrQmfBands; k++) {
270 hAnalysisHybFilter->bufferLFReal[k] = pMem;
271 pMem += setup->protoLen;
272 hAnalysisHybFilter->bufferLFImag[k] = pMem;
273 pMem += setup->protoLen;
274 }
275
276 /* Distribute HF memory. */
277 if (hAnalysisHybFilter->HFmemorySize != 0) {
278 pMem = hAnalysisHybFilter->pHFmemory;
279 for (k = 0; k < setup->filterDelay; k++) {
280 hAnalysisHybFilter->bufferHFReal[k] = pMem;
281 pMem += (qmfBands - setup->nrQmfBands);
282 hAnalysisHybFilter->bufferHFImag[k] = pMem;
283 pMem += (cplxBands - setup->nrQmfBands);
284 }
285 }
286
287 if (initStatesFlag) {
288 /* Clear LF buffer */
289 for (k = 0; k < setup->nrQmfBands; k++) {
290 FDKmemclear(hAnalysisHybFilter->bufferLFReal[k],
291 setup->protoLen * sizeof(FIXP_DBL));
292 FDKmemclear(hAnalysisHybFilter->bufferLFImag[k],
293 setup->protoLen * sizeof(FIXP_DBL));
294 }
295
296 if (hAnalysisHybFilter->HFmemorySize != 0) {
297 if (qmfBands > setup->nrQmfBands) {
298 /* Clear HF buffer */
299 for (k = 0; k < setup->filterDelay; k++) {
300 FDKmemclear(hAnalysisHybFilter->bufferHFReal[k],
301 (qmfBands - setup->nrQmfBands) * sizeof(FIXP_DBL));
302 FDKmemclear(hAnalysisHybFilter->bufferHFImag[k],
303 (cplxBands - setup->nrQmfBands) * sizeof(FIXP_DBL));
304 }
305 }
306 }
307 }
308
309 bail:
310 return err;
311 }
312
FDKhybridAnalysisScaleStates(HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter,const INT scalingValue)313 INT FDKhybridAnalysisScaleStates(HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter,
314 const INT scalingValue) {
315 INT err = 0;
316
317 if (hAnalysisHybFilter == NULL) {
318 err = 1; /* invalid handle */
319 } else {
320 int k;
321 HANDLE_FDK_HYBRID_SETUP setup = hAnalysisHybFilter->pSetup;
322
323 /* Scale LF buffer */
324 for (k = 0; k < setup->nrQmfBands; k++) {
325 scaleValues(hAnalysisHybFilter->bufferLFReal[k], setup->protoLen,
326 scalingValue);
327 scaleValues(hAnalysisHybFilter->bufferLFImag[k], setup->protoLen,
328 scalingValue);
329 }
330 if (hAnalysisHybFilter->nrBands > setup->nrQmfBands) {
331 /* Scale HF buffer */
332 for (k = 0; k < setup->filterDelay; k++) {
333 scaleValues(hAnalysisHybFilter->bufferHFReal[k],
334 (hAnalysisHybFilter->nrBands - setup->nrQmfBands),
335 scalingValue);
336 scaleValues(hAnalysisHybFilter->bufferHFImag[k],
337 (hAnalysisHybFilter->cplxBands - setup->nrQmfBands),
338 scalingValue);
339 }
340 }
341 }
342 return err;
343 }
344
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)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 FIXP_DBL *const pHybridImag) {
350 int k, hybOffset = 0;
351 INT err = 0;
352 const int nrQmfBandsLF =
353 hAnalysisHybFilter->pSetup
354 ->nrQmfBands; /* number of QMF bands to be converted to hybrid */
355
356 const int writIndex = hAnalysisHybFilter->bufferLFpos;
357 int readIndex = hAnalysisHybFilter->bufferLFpos;
358
359 if (++readIndex >= hAnalysisHybFilter->pSetup->protoLen) readIndex = 0;
360 const INT *pBufferLFreadIdx =
361 &hAnalysisHybFilter->pSetup->pReadIdxTable[readIndex];
362
363 /*
364 * LF buffer.
365 */
366 for (k = 0; k < nrQmfBandsLF; k++) {
367 /* New input sample. */
368 hAnalysisHybFilter->bufferLFReal[k][writIndex] = pQmfReal[k];
369 hAnalysisHybFilter->bufferLFImag[k][writIndex] = pQmfImag[k];
370
371 /* Perform hybrid filtering. */
372 err |=
373 kChannelFiltering(hAnalysisHybFilter->bufferLFReal[k],
374 hAnalysisHybFilter->bufferLFImag[k], pBufferLFreadIdx,
375 pHybridReal + hybOffset, pHybridImag + hybOffset,
376 hAnalysisHybFilter->pSetup->kHybrid[k]);
377
378 hybOffset += hAnalysisHybFilter->pSetup->nHybBands[k];
379 }
380
381 hAnalysisHybFilter->bufferLFpos =
382 readIndex; /* Index where to write next input sample. */
383
384 if (hAnalysisHybFilter->nrBands > nrQmfBandsLF) {
385 /*
386 * HF buffer.
387 */
388 if (hAnalysisHybFilter->hfMode != 0) {
389 /* HF delay compensation was applied outside. */
390 FDKmemcpy(
391 pHybridReal + hybOffset, &pQmfReal[nrQmfBandsLF],
392 (hAnalysisHybFilter->nrBands - nrQmfBandsLF) * sizeof(FIXP_DBL));
393 FDKmemcpy(
394 pHybridImag + hybOffset, &pQmfImag[nrQmfBandsLF],
395 (hAnalysisHybFilter->cplxBands - nrQmfBandsLF) * sizeof(FIXP_DBL));
396 } else {
397 FDK_ASSERT(hAnalysisHybFilter->HFmemorySize != 0);
398 /* HF delay compensation, filterlength/2. */
399 FDKmemcpy(
400 pHybridReal + hybOffset,
401 hAnalysisHybFilter->bufferHFReal[hAnalysisHybFilter->bufferHFpos],
402 (hAnalysisHybFilter->nrBands - nrQmfBandsLF) * sizeof(FIXP_DBL));
403 FDKmemcpy(
404 pHybridImag + hybOffset,
405 hAnalysisHybFilter->bufferHFImag[hAnalysisHybFilter->bufferHFpos],
406 (hAnalysisHybFilter->cplxBands - nrQmfBandsLF) * sizeof(FIXP_DBL));
407
408 FDKmemcpy(
409 hAnalysisHybFilter->bufferHFReal[hAnalysisHybFilter->bufferHFpos],
410 &pQmfReal[nrQmfBandsLF],
411 (hAnalysisHybFilter->nrBands - nrQmfBandsLF) * sizeof(FIXP_DBL));
412 FDKmemcpy(
413 hAnalysisHybFilter->bufferHFImag[hAnalysisHybFilter->bufferHFpos],
414 &pQmfImag[nrQmfBandsLF],
415 (hAnalysisHybFilter->cplxBands - nrQmfBandsLF) * sizeof(FIXP_DBL));
416
417 if (++hAnalysisHybFilter->bufferHFpos >=
418 hAnalysisHybFilter->pSetup->filterDelay)
419 hAnalysisHybFilter->bufferHFpos = 0;
420 }
421 } /* process HF part*/
422
423 return err;
424 }
425
FDKhybridAnalysisClose(HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter)426 INT FDKhybridAnalysisClose(HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter) {
427 INT err = 0;
428
429 if (hAnalysisHybFilter != NULL) {
430 hAnalysisHybFilter->pLFmemory = NULL;
431 hAnalysisHybFilter->pHFmemory = NULL;
432 hAnalysisHybFilter->LFmemorySize = 0;
433 hAnalysisHybFilter->HFmemorySize = 0;
434 }
435
436 return err;
437 }
438
FDKhybridSynthesisInit(HANDLE_FDK_SYN_HYB_FILTER hSynthesisHybFilter,const FDK_HYBRID_MODE mode,const INT qmfBands,const INT cplxBands)439 INT FDKhybridSynthesisInit(HANDLE_FDK_SYN_HYB_FILTER hSynthesisHybFilter,
440 const FDK_HYBRID_MODE mode, const INT qmfBands,
441 const INT cplxBands) {
442 INT err = 0;
443 HANDLE_FDK_HYBRID_SETUP setup = NULL;
444
445 switch (mode) {
446 case THREE_TO_TEN:
447 setup = &setup_3_10;
448 break;
449 case THREE_TO_TWELVE:
450 setup = &setup_3_12;
451 break;
452 case THREE_TO_SIXTEEN:
453 setup = &setup_3_16;
454 break;
455 default:
456 err = -1;
457 goto bail;
458 }
459
460 hSynthesisHybFilter->pSetup = setup;
461 hSynthesisHybFilter->nrBands = qmfBands;
462 hSynthesisHybFilter->cplxBands = cplxBands;
463
464 bail:
465 return err;
466 }
467
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)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 FIXP_DBL *const pQmfImag) {
473 int k, n, hybOffset = 0;
474 const INT nrQmfBandsLF = hSynthesisHybFilter->pSetup->nrQmfBands;
475
476 /*
477 * LF buffer.
478 */
479 for (k = 0; k < nrQmfBandsLF; k++) {
480 const int nHybBands = hSynthesisHybFilter->pSetup->nHybBands[k];
481 const int scale = hSynthesisHybFilter->pSetup->synHybScale[k];
482
483 FIXP_DBL accu1 = FL2FXCONST_DBL(0.f);
484 FIXP_DBL accu2 = FL2FXCONST_DBL(0.f);
485
486 /* Perform hybrid filtering. */
487 for (n = 0; n < nHybBands; n++) {
488 accu1 += pHybridReal[hybOffset + n] >> scale;
489 accu2 += pHybridImag[hybOffset + n] >> scale;
490 }
491 pQmfReal[k] = SATURATE_LEFT_SHIFT(accu1, scale, DFRACT_BITS);
492 pQmfImag[k] = SATURATE_LEFT_SHIFT(accu2, scale, DFRACT_BITS);
493
494 hybOffset += nHybBands;
495 }
496
497 if (hSynthesisHybFilter->nrBands > nrQmfBandsLF) {
498 /*
499 * HF buffer.
500 */
501 FDKmemcpy(&pQmfReal[nrQmfBandsLF], &pHybridReal[hybOffset],
502 (hSynthesisHybFilter->nrBands - nrQmfBandsLF) * sizeof(FIXP_DBL));
503 FDKmemcpy(
504 &pQmfImag[nrQmfBandsLF], &pHybridImag[hybOffset],
505 (hSynthesisHybFilter->cplxBands - nrQmfBandsLF) * sizeof(FIXP_DBL));
506 }
507
508 return;
509 }
510
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)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 const INT invert) {
517 FIXP_DBL r1, r6;
518 FIXP_DBL i1, i6;
519
520 const FIXP_HTB f0 = HybFilterCoef2[0]; /* corresponds to p1 and p11 */
521 const FIXP_HTB f1 = HybFilterCoef2[1]; /* corresponds to p3 and p9 */
522 const FIXP_HTB f2 = HybFilterCoef2[2]; /* corresponds to p5 and p7 */
523
524 /* symmetric filter coefficients */
525 r1 = fMultDiv2(f0, pQmfReal[pReadIdx[1]]) +
526 fMultDiv2(f0, pQmfReal[pReadIdx[11]]);
527 i1 = fMultDiv2(f0, pQmfImag[pReadIdx[1]]) +
528 fMultDiv2(f0, pQmfImag[pReadIdx[11]]);
529 r1 += fMultDiv2(f1, pQmfReal[pReadIdx[3]]) +
530 fMultDiv2(f1, pQmfReal[pReadIdx[9]]);
531 i1 += fMultDiv2(f1, pQmfImag[pReadIdx[3]]) +
532 fMultDiv2(f1, pQmfImag[pReadIdx[9]]);
533 r1 += fMultDiv2(f2, pQmfReal[pReadIdx[5]]) +
534 fMultDiv2(f2, pQmfReal[pReadIdx[7]]);
535 i1 += fMultDiv2(f2, pQmfImag[pReadIdx[5]]) +
536 fMultDiv2(f2, pQmfImag[pReadIdx[7]]);
537
538 r6 = pQmfReal[pReadIdx[6]] >> 2;
539 i6 = pQmfImag[pReadIdx[6]] >> 2;
540
541 FDK_ASSERT((invert == 0) || (invert == 1));
542 mHybridReal[0 + invert] = SATURATE_LEFT_SHIFT((r6 + r1), 1, DFRACT_BITS);
543 mHybridImag[0 + invert] = SATURATE_LEFT_SHIFT((i6 + i1), 1, DFRACT_BITS);
544
545 mHybridReal[1 - invert] = SATURATE_LEFT_SHIFT((r6 - r1), 1, DFRACT_BITS);
546 mHybridImag[1 - invert] = SATURATE_LEFT_SHIFT((i6 - i1), 1, DFRACT_BITS);
547 }
548
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)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 const INT invert) {
555 const FIXP_HTB *p = HybFilterCoef4;
556
557 FIXP_DBL fft[8];
558
559 static const FIXP_DBL cr[13] = {
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), FL2FXCONST_DBL(-0.70710678118655f),
565 FL2FXCONST_DBL(-1.f), FL2FXCONST_DBL(-0.70710678118655f),
566 FL2FXCONST_DBL(0.f)};
567 static const FIXP_DBL ci[13] = {
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), FL2FXCONST_DBL(-0.70710678118655f),
573 FL2FXCONST_DBL(0.f), FL2FXCONST_DBL(0.70710678118655f),
574 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 fft[FFT_IDX_R(0)] =
582 (fMult(p[10], (fMultSub(fMultDiv2(cr[2], pQmfReal[pReadIdx[2]]), ci[2],
583 pQmfImag[pReadIdx[2]]))) +
584 fMult(p[6], (fMultSub(fMultDiv2(cr[6], pQmfReal[pReadIdx[6]]), ci[6],
585 pQmfImag[pReadIdx[6]]))) +
586 fMult(p[2], (fMultSub(fMultDiv2(cr[10], pQmfReal[pReadIdx[10]]), ci[10],
587 pQmfImag[pReadIdx[10]]))));
588 fft[FFT_IDX_I(0)] =
589 (fMult(p[10], (fMultAdd(fMultDiv2(ci[2], pQmfReal[pReadIdx[2]]), cr[2],
590 pQmfImag[pReadIdx[2]]))) +
591 fMult(p[6], (fMultAdd(fMultDiv2(ci[6], pQmfReal[pReadIdx[6]]), cr[6],
592 pQmfImag[pReadIdx[6]]))) +
593 fMult(p[2], (fMultAdd(fMultDiv2(ci[10], pQmfReal[pReadIdx[10]]), cr[10],
594 pQmfImag[pReadIdx[10]]))));
595
596 /* twiddle dee dum */
597 fft[FFT_IDX_R(1)] =
598 (fMult(p[9], (fMultSub(fMultDiv2(cr[3], pQmfReal[pReadIdx[3]]), ci[3],
599 pQmfImag[pReadIdx[3]]))) +
600 fMult(p[5], (fMultSub(fMultDiv2(cr[7], pQmfReal[pReadIdx[7]]), ci[7],
601 pQmfImag[pReadIdx[7]]))) +
602 fMult(p[1], (fMultSub(fMultDiv2(cr[11], pQmfReal[pReadIdx[11]]), ci[11],
603 pQmfImag[pReadIdx[11]]))));
604 fft[FFT_IDX_I(1)] =
605 (fMult(p[9], (fMultAdd(fMultDiv2(ci[3], pQmfReal[pReadIdx[3]]), cr[3],
606 pQmfImag[pReadIdx[3]]))) +
607 fMult(p[5], (fMultAdd(fMultDiv2(ci[7], pQmfReal[pReadIdx[7]]), cr[7],
608 pQmfImag[pReadIdx[7]]))) +
609 fMult(p[1], (fMultAdd(fMultDiv2(ci[11], pQmfReal[pReadIdx[11]]), cr[11],
610 pQmfImag[pReadIdx[11]]))));
611
612 /* twiddle dee dee */
613 fft[FFT_IDX_R(2)] =
614 (fMult(p[12], (fMultSub(fMultDiv2(cr[0], pQmfReal[pReadIdx[0]]), ci[0],
615 pQmfImag[pReadIdx[0]]))) +
616 fMult(p[8], (fMultSub(fMultDiv2(cr[4], pQmfReal[pReadIdx[4]]), ci[4],
617 pQmfImag[pReadIdx[4]]))) +
618 fMult(p[4], (fMultSub(fMultDiv2(cr[8], pQmfReal[pReadIdx[8]]), ci[8],
619 pQmfImag[pReadIdx[8]]))) +
620 fMult(p[0], (fMultSub(fMultDiv2(cr[12], pQmfReal[pReadIdx[12]]), ci[12],
621 pQmfImag[pReadIdx[12]]))));
622 fft[FFT_IDX_I(2)] =
623 (fMult(p[12], (fMultAdd(fMultDiv2(ci[0], pQmfReal[pReadIdx[0]]), cr[0],
624 pQmfImag[pReadIdx[0]]))) +
625 fMult(p[8], (fMultAdd(fMultDiv2(ci[4], pQmfReal[pReadIdx[4]]), cr[4],
626 pQmfImag[pReadIdx[4]]))) +
627 fMult(p[4], (fMultAdd(fMultDiv2(ci[8], pQmfReal[pReadIdx[8]]), cr[8],
628 pQmfImag[pReadIdx[8]]))) +
629 fMult(p[0], (fMultAdd(fMultDiv2(ci[12], pQmfReal[pReadIdx[12]]), cr[12],
630 pQmfImag[pReadIdx[12]]))));
631
632 fft[FFT_IDX_R(3)] =
633 (fMult(p[11], (fMultSub(fMultDiv2(cr[1], pQmfReal[pReadIdx[1]]), ci[1],
634 pQmfImag[pReadIdx[1]]))) +
635 fMult(p[7], (fMultSub(fMultDiv2(cr[5], pQmfReal[pReadIdx[5]]), ci[5],
636 pQmfImag[pReadIdx[5]]))) +
637 fMult(p[3], (fMultSub(fMultDiv2(cr[9], pQmfReal[pReadIdx[9]]), ci[9],
638 pQmfImag[pReadIdx[9]]))));
639 fft[FFT_IDX_I(3)] =
640 (fMult(p[11], (fMultAdd(fMultDiv2(ci[1], pQmfReal[pReadIdx[1]]), cr[1],
641 pQmfImag[pReadIdx[1]]))) +
642 fMult(p[7], (fMultAdd(fMultDiv2(ci[5], pQmfReal[pReadIdx[5]]), cr[5],
643 pQmfImag[pReadIdx[5]]))) +
644 fMult(p[3], (fMultAdd(fMultDiv2(ci[9], pQmfReal[pReadIdx[9]]), cr[9],
645 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 mHybridReal[0] = fft[FFT_IDX_R(0)] + fft[FFT_IDX_R(1)] + fft[FFT_IDX_R(2)] +
657 fft[FFT_IDX_R(3)];
658 mHybridImag[0] = fft[FFT_IDX_I(0)] + fft[FFT_IDX_I(1)] + fft[FFT_IDX_I(2)] +
659 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 mHybridReal[1] = fft[FFT_IDX_R(0)] + fft[FFT_IDX_I(1)] - fft[FFT_IDX_R(2)] -
666 fft[FFT_IDX_I(3)];
667 mHybridImag[1] = fft[FFT_IDX_I(0)] - fft[FFT_IDX_R(1)] - fft[FFT_IDX_I(2)] +
668 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 mHybridReal[2] = fft[FFT_IDX_R(0)] - fft[FFT_IDX_R(1)] + fft[FFT_IDX_R(2)] -
675 fft[FFT_IDX_R(3)];
676 mHybridImag[2] = fft[FFT_IDX_I(0)] - fft[FFT_IDX_I(1)] + fft[FFT_IDX_I(2)] -
677 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 mHybridReal[3] = fft[FFT_IDX_R(0)] - fft[FFT_IDX_I(1)] - fft[FFT_IDX_R(2)] +
684 fft[FFT_IDX_I(3)];
685 mHybridImag[3] = fft[FFT_IDX_I(0)] + fft[FFT_IDX_R(1)] - fft[FFT_IDX_I(2)] -
686 fft[FFT_IDX_R(3)];
687 }
688
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)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 const INT invert) {
695 const FIXP_HTP *p = HybFilterCoef8;
696 INT k, sc;
697
698 FIXP_DBL mfft[16 + ALIGNMENT_DEFAULT];
699 FIXP_DBL *pfft = (FIXP_DBL *)ALIGN_PTR(mfft);
700
701 FIXP_DBL accu1, accu2, accu3, accu4;
702
703 /* pre twiddeling */
704 pfft[FFT_IDX_R(0)] =
705 pQmfReal[pReadIdx[6]] >>
706 (3 + 1); /* fMultDiv2(p[0].v.re, pQmfReal[pReadIdx[6]]); */
707 pfft[FFT_IDX_I(0)] =
708 pQmfImag[pReadIdx[6]] >>
709 (3 + 1); /* fMultDiv2(p[0].v.re, pQmfImag[pReadIdx[6]]); */
710
711 cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[7]], pQmfImag[pReadIdx[7]],
712 p[1]);
713 pfft[FFT_IDX_R(1)] = accu1;
714 pfft[FFT_IDX_I(1)] = accu2;
715
716 cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[0]], pQmfImag[pReadIdx[0]],
717 p[2]);
718 cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[8]], pQmfImag[pReadIdx[8]],
719 p[3]);
720 pfft[FFT_IDX_R(2)] = accu1 + accu3;
721 pfft[FFT_IDX_I(2)] = accu2 + accu4;
722
723 cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[1]], pQmfImag[pReadIdx[1]],
724 p[4]);
725 cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[9]], pQmfImag[pReadIdx[9]],
726 p[5]);
727 pfft[FFT_IDX_R(3)] = accu1 + accu3;
728 pfft[FFT_IDX_I(3)] = accu2 + accu4;
729
730 pfft[FFT_IDX_R(4)] = fMultDiv2(pQmfImag[pReadIdx[10]], p[7].v.im) -
731 fMultDiv2(pQmfImag[pReadIdx[2]], p[6].v.im);
732 pfft[FFT_IDX_I(4)] = fMultDiv2(pQmfReal[pReadIdx[2]], p[6].v.im) -
733 fMultDiv2(pQmfReal[pReadIdx[10]], p[7].v.im);
734
735 cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[3]], pQmfImag[pReadIdx[3]],
736 p[8]);
737 cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[11]], pQmfImag[pReadIdx[11]],
738 p[9]);
739 pfft[FFT_IDX_R(5)] = accu1 + accu3;
740 pfft[FFT_IDX_I(5)] = accu2 + accu4;
741
742 cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[4]], pQmfImag[pReadIdx[4]],
743 p[10]);
744 cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[12]], pQmfImag[pReadIdx[12]],
745 p[11]);
746 pfft[FFT_IDX_R(6)] = accu1 + accu3;
747 pfft[FFT_IDX_I(6)] = accu2 + accu4;
748
749 cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[5]], pQmfImag[pReadIdx[5]],
750 p[12]);
751 pfft[FFT_IDX_R(7)] = accu1;
752 pfft[FFT_IDX_I(7)] = accu2;
753
754 /* fft modulation */
755 fft_8(pfft);
756 sc = 1 + 2;
757
758 if (invert) {
759 mHybridReal[0] = pfft[FFT_IDX_R(7)] << sc;
760 mHybridImag[0] = pfft[FFT_IDX_I(7)] << sc;
761 mHybridReal[1] = pfft[FFT_IDX_R(0)] << sc;
762 mHybridImag[1] = pfft[FFT_IDX_I(0)] << sc;
763
764 mHybridReal[2] = pfft[FFT_IDX_R(6)] << sc;
765 mHybridImag[2] = pfft[FFT_IDX_I(6)] << sc;
766 mHybridReal[3] = pfft[FFT_IDX_R(1)] << sc;
767 mHybridImag[3] = pfft[FFT_IDX_I(1)] << sc;
768
769 mHybridReal[4] = SATURATE_LEFT_SHIFT(
770 (pfft[FFT_IDX_R(2)] + pfft[FFT_IDX_R(5)]), sc, DFRACT_BITS);
771 mHybridImag[4] = SATURATE_LEFT_SHIFT(
772 (pfft[FFT_IDX_I(2)] + pfft[FFT_IDX_I(5)]), sc, DFRACT_BITS);
773
774 mHybridReal[5] = SATURATE_LEFT_SHIFT(
775 (pfft[FFT_IDX_R(3)] + pfft[FFT_IDX_R(4)]), sc, DFRACT_BITS);
776 mHybridImag[5] = SATURATE_LEFT_SHIFT(
777 (pfft[FFT_IDX_I(3)] + pfft[FFT_IDX_I(4)]), sc, DFRACT_BITS);
778 } else {
779 for (k = 0; k < 8; k++) {
780 mHybridReal[k] = pfft[FFT_IDX_R(k)] << sc;
781 mHybridImag[k] = pfft[FFT_IDX_I(k)] << sc;
782 }
783 }
784 }
785
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)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 const SCHAR hybridConfig) {
792 INT err = 0;
793
794 switch (hybridConfig) {
795 case 2:
796 case -2:
797 dualChannelFiltering(pQmfReal, pQmfImag, pReadIdx, mHybridReal,
798 mHybridImag, (hybridConfig < 0) ? 1 : 0);
799 break;
800 case 4:
801 case -4:
802 fourChannelFiltering(pQmfReal, pQmfImag, pReadIdx, mHybridReal,
803 mHybridImag, (hybridConfig < 0) ? 1 : 0);
804 break;
805 case 8:
806 case -8:
807 eightChannelFiltering(pQmfReal, pQmfImag, pReadIdx, mHybridReal,
808 mHybridImag, (hybridConfig < 0) ? 1 : 0);
809 break;
810 default:
811 err = -1;
812 }
813
814 return err;
815 }
816