Imported Debian version 0.1.3.1
[deb_fdk-aac.git] / libFDK / src / FDK_hybrid.cpp
1
2 /* -----------------------------------------------------------------------------------------------------------
3 Software License for The Fraunhofer FDK AAC Codec Library for Android
4
5 © Copyright 1995 - 2013 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V.
6 All rights reserved.
7
8 1. INTRODUCTION
9 The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements
10 the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio.
11 This FDK AAC Codec software is intended to be used on a wide variety of Android devices.
12
13 AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual
14 audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by
15 independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part
16 of the MPEG specifications.
17
18 Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer)
19 may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners
20 individually for the purpose of encoding or decoding bit streams in products that are compliant with
21 the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license
22 these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec
23 software may already be covered under those patent licenses when it is used for those licensed purposes only.
24
25 Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality,
26 are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional
27 applications information and documentation.
28
29 2. COPYRIGHT LICENSE
30
31 Redistribution and use in source and binary forms, with or without modification, are permitted without
32 payment of copyright license fees provided that you satisfy the following conditions:
33
34 You must retain the complete text of this software license in redistributions of the FDK AAC Codec or
35 your modifications thereto in source code form.
36
37 You must retain the complete text of this software license in the documentation and/or other materials
38 provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form.
39 You must make available free of charge copies of the complete source code of the FDK AAC Codec and your
40 modifications thereto to recipients of copies in binary form.
41
42 The name of Fraunhofer may not be used to endorse or promote products derived from this library without
43 prior written permission.
44
45 You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec
46 software or your modifications thereto.
47
48 Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software
49 and the date of any change. For modified versions of the FDK AAC Codec, the term
50 "Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term
51 "Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android."
52
53 3. NO PATENT LICENSE
54
55 NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer,
56 ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with
57 respect to this software.
58
59 You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized
60 by appropriate patent licenses.
61
62 4. DISCLAIMER
63
64 This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors
65 "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties
66 of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
67 CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages,
68 including but not limited to procurement of substitute goods or services; loss of use, data, or profits,
69 or business interruption, however caused and on any theory of liability, whether in contract, strict
70 liability, or tort (including negligence), arising in any way out of the use of this software, even if
71 advised of the possibility of such damage.
72
73 5. CONTACT INFORMATION
74
75 Fraunhofer Institute for Integrated Circuits IIS
76 Attention: Audio and Multimedia Departments - FDK AAC LL
77 Am Wolfsmantel 33
78 91058 Erlangen, Germany
79
80 www.iis.fraunhofer.de/amm
81 amm-info@iis.fraunhofer.de
82 ----------------------------------------------------------------------------------------------------------- */
83
84 /*************************** Fraunhofer IIS FDK Tools **********************
85
86 Author(s): Markus Lohwasser
87 Description: FDK Tools Hybrid Filterbank
88
89 ******************************************************************************/
90
91 #include "FDK_hybrid.h"
92
93
94 #include "fft.h"
95
96 /*--------------- defines -----------------------------*/
97 #define FFT_IDX_R(a) (2*a)
98 #define FFT_IDX_I(a) (2*a+1)
99
100 #define HYB_COEF8_0 ( 0.00746082949812f )
101 #define HYB_COEF8_1 ( 0.02270420949825f )
102 #define HYB_COEF8_2 ( 0.04546865930473f )
103 #define HYB_COEF8_3 ( 0.07266113929591f )
104 #define HYB_COEF8_4 ( 0.09885108575264f )
105 #define HYB_COEF8_5 ( 0.11793710567217f )
106 #define HYB_COEF8_6 ( 0.12500000000000f )
107 #define HYB_COEF8_7 ( HYB_COEF8_5 )
108 #define HYB_COEF8_8 ( HYB_COEF8_4 )
109 #define HYB_COEF8_9 ( HYB_COEF8_3 )
110 #define HYB_COEF8_10 ( HYB_COEF8_2 )
111 #define HYB_COEF8_11 ( HYB_COEF8_1 )
112 #define HYB_COEF8_12 ( HYB_COEF8_0 )
113
114
115 /*--------------- structure definitions ---------------*/
116
117 #if defined(ARCH_PREFER_MULT_32x16)
118 #define FIXP_HTB FIXP_SGL /* SGL data type. */
119 #define FIXP_HTP FIXP_SPK /* Packed SGL data type. */
120 #define HTC(a) (FX_DBL2FXCONST_SGL(a)) /* Cast to SGL */
121 #define FL2FXCONST_HTB FL2FXCONST_SGL
122 #else
123 #define FIXP_HTB FIXP_DBL /* SGL data type. */
124 #define FIXP_HTP FIXP_DPK /* Packed DBL data type. */
125 #define HTC(a) ((FIXP_DBL)(LONG)(a)) /* Cast to DBL */
126 #define FL2FXCONST_HTB FL2FXCONST_DBL
127 #endif
128
129 #define HTCP(real,imag) { { HTC(real), HTC(imag) } } /* How to arrange the packed values. */
130
131
132 struct FDK_HYBRID_SETUP
133 {
134 UCHAR nrQmfBands; /*!< Number of QMF bands to be converted to hybrid. */
135 UCHAR nHybBands[3]; /*!< Number of Hybrid bands generated by nrQmfBands. */
136 SCHAR kHybrid[3]; /*!< Filter configuration of each QMF band. */
137 UCHAR protoLen; /*!< Prototype filter length. */
138 UCHAR filterDelay; /*!< Delay caused by hybrid filter. */
139 const INT *pReadIdxTable; /*!< Helper table to access input data ringbuffer. */
140
141 };
142
143 /*--------------- constants ---------------------------*/
144 static const INT ringbuffIdxTab[2*13] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
145
146 static const FDK_HYBRID_SETUP setup_3_16 = { 3, { 8, 4, 4}, { 8, 4, 4}, 13, (13-1)/2, ringbuffIdxTab};
147 static const FDK_HYBRID_SETUP setup_3_12 = { 3, { 8, 2, 2}, { 8, 2, 2}, 13, (13-1)/2, ringbuffIdxTab};
148 static const FDK_HYBRID_SETUP setup_3_10 = { 3, { 6, 2, 2}, { -8, -2, 2}, 13, (13-1)/2, ringbuffIdxTab};
149
150
151 static const FIXP_HTP HybFilterCoef8[] = {
152 HTCP(0x10000000, 0x00000000), HTCP(0x0df26407, 0xfa391882), HTCP(0xff532109, 0x00acdef7), HTCP(0x08f26d36, 0xf70d92ca),
153 HTCP(0xfee34b5f, 0x02af570f), HTCP(0x038f276e, 0xf7684793), HTCP(0x00000000, 0x05d1eac2), HTCP(0x00000000, 0x05d1eac2),
154 HTCP(0x038f276e, 0x0897b86d), HTCP(0xfee34b5f, 0xfd50a8f1), HTCP(0x08f26d36, 0x08f26d36), HTCP(0xff532109, 0xff532109),
155 HTCP(0x0df26407, 0x05c6e77e)
156 };
157
158 static const FIXP_HTB HybFilterCoef2[13] = {
159 FL2FXCONST_HTB( 0.00000000000000f), FL2FXCONST_HTB( 0.01899487526049f), FL2FXCONST_HTB( 0.00000000000000f), FL2FXCONST_HTB(-0.07293139167538f), FL2FXCONST_HTB( 0.00000000000000f), FL2FXCONST_HTB( 0.30596630545168f),
160 FL2FXCONST_HTB( 0.50000000000000f), FL2FXCONST_HTB( 0.30596630545168f), FL2FXCONST_HTB( 0.00000000000000f), FL2FXCONST_HTB(-0.07293139167538f), FL2FXCONST_HTB( 0.00000000000000f), FL2FXCONST_HTB( 0.01899487526049f),
161 FL2FXCONST_HTB( 0.00000000000000f)
162 };
163
164 static const FIXP_HTB HybFilterCoef4[13] = {
165 FL2FXCONST_HTB(-0.00305151927305f), FL2FXCONST_HTB(-0.00794862316203f), FL2FXCONST_HTB( 0.0f), FL2FXCONST_HTB( 0.04318924038756f), FL2FXCONST_HTB( 0.12542448210445f), FL2FXCONST_HTB( 0.21227807049160f),
166 FL2FXCONST_HTB( 0.25f), FL2FXCONST_HTB( 0.21227807049160f), FL2FXCONST_HTB( 0.12542448210445f), FL2FXCONST_HTB( 0.04318924038756f), FL2FXCONST_HTB( 0.0f), FL2FXCONST_HTB(-0.00794862316203f),
167 FL2FXCONST_HTB(-0.00305151927305f)
168 };
169
170 /*--------------- function declarations ---------------*/
171 static INT kChannelFiltering(
172 const FIXP_DBL *const pQmfReal,
173 const FIXP_DBL *const pQmfImag,
174 const INT *const pReadIdx,
175 FIXP_DBL *const mHybridReal,
176 FIXP_DBL *const mHybridImag,
177 const SCHAR hybridConfig
178 );
179
180
181 /*--------------- function definitions ----------------*/
182
183 INT FDKhybridAnalysisOpen(
184 HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter,
185 FIXP_DBL *const pLFmemory,
186 const UINT LFmemorySize,
187 FIXP_DBL *const pHFmemory,
188 const UINT HFmemorySize
189 )
190 {
191 INT err = 0;
192
193 /* Save pointer to extern memory. */
194 hAnalysisHybFilter->pLFmemory = pLFmemory;
195 hAnalysisHybFilter->LFmemorySize = LFmemorySize;
196
197 hAnalysisHybFilter->pHFmemory = pHFmemory;
198 hAnalysisHybFilter->HFmemorySize = HFmemorySize;
199
200 return err;
201 }
202
203 INT FDKhybridAnalysisInit(
204 HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter,
205 const FDK_HYBRID_MODE mode,
206 const INT qmfBands,
207 const INT cplxBands,
208 const INT initStatesFlag
209 )
210 {
211 int k;
212 INT err = 0;
213 FIXP_DBL *pMem = NULL;
214 HANDLE_FDK_HYBRID_SETUP setup = NULL;
215
216 switch (mode) {
217 case THREE_TO_TEN: setup = (HANDLE_FDK_HYBRID_SETUP)&setup_3_10; break;
218 case THREE_TO_TWELVE: setup = (HANDLE_FDK_HYBRID_SETUP)&setup_3_12; break;
219 case THREE_TO_SIXTEEN: setup = (HANDLE_FDK_HYBRID_SETUP)&setup_3_16; break;
220 default: err = -1; goto bail;
221 }
222
223 /* Initialize handle. */
224 hAnalysisHybFilter->pSetup = setup;
225 hAnalysisHybFilter->bufferLFpos = setup->protoLen-1;
226 hAnalysisHybFilter->bufferHFpos = 0;
227 hAnalysisHybFilter->nrBands = qmfBands;
228 hAnalysisHybFilter->cplxBands = cplxBands;
229 hAnalysisHybFilter->hfMode = 0;
230
231 /* Check available memory. */
232 if ( ((2*setup->nrQmfBands*setup->protoLen*sizeof(FIXP_DBL)) > hAnalysisHybFilter->LFmemorySize)
233 || ((setup->filterDelay*((qmfBands-setup->nrQmfBands)+(cplxBands-setup->nrQmfBands))*sizeof(FIXP_DBL)) > hAnalysisHybFilter->HFmemorySize) )
234 {
235 err = -2;
236 goto bail;
237 }
238
239 /* Distribut LF memory. */
240 pMem = hAnalysisHybFilter->pLFmemory;
241 for (k=0; k<setup->nrQmfBands; k++) {
242 hAnalysisHybFilter->bufferLFReal[k] = pMem; pMem += setup->protoLen;
243 hAnalysisHybFilter->bufferLFImag[k] = pMem; pMem += setup->protoLen;
244 }
245
246 /* Distribut HF memory. */
247 pMem = hAnalysisHybFilter->pHFmemory;
248 for (k=0; k<setup->filterDelay; k++) {
249 hAnalysisHybFilter->bufferHFReal[k] = pMem; pMem += (qmfBands-setup->nrQmfBands);
250 hAnalysisHybFilter->bufferHFImag[k] = pMem; pMem += (cplxBands-setup->nrQmfBands);
251 }
252
253 if (initStatesFlag) {
254 /* Clear LF buffer */
255 for (k=0; k<setup->nrQmfBands; k++) {
256 FDKmemclear(hAnalysisHybFilter->bufferLFReal[k], setup->protoLen*sizeof(FIXP_DBL));
257 FDKmemclear(hAnalysisHybFilter->bufferLFImag[k], setup->protoLen*sizeof(FIXP_DBL));
258 }
259
260 if (qmfBands > setup->nrQmfBands) {
261 /* Clear HF buffer */
262 for (k=0; k<setup->filterDelay; k++) {
263 FDKmemclear(hAnalysisHybFilter->bufferHFReal[k], (qmfBands-setup->nrQmfBands)*sizeof(FIXP_DBL));
264 FDKmemclear(hAnalysisHybFilter->bufferHFImag[k], (cplxBands-setup->nrQmfBands)*sizeof(FIXP_DBL));
265 }
266 }
267 }
268
269 bail:
270 return err;
271 }
272
273 INT FDKhybridAnalysisScaleStates(
274 HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter,
275 const INT scalingValue
276 )
277 {
278 INT err = 0;
279
280 if (hAnalysisHybFilter==NULL) {
281 err = 1; /* invalid handle */
282 }
283 else {
284 int k;
285 HANDLE_FDK_HYBRID_SETUP setup = hAnalysisHybFilter->pSetup;
286
287 /* Scale LF buffer */
288 for (k=0; k<setup->nrQmfBands; k++) {
289 scaleValues(hAnalysisHybFilter->bufferLFReal[k], setup->protoLen, scalingValue);
290 scaleValues(hAnalysisHybFilter->bufferLFImag[k], setup->protoLen, scalingValue);
291 }
292 if (hAnalysisHybFilter->nrBands > setup->nrQmfBands) {
293 /* Scale HF buffer */
294 for (k=0; k<setup->filterDelay; k++) {
295 scaleValues(hAnalysisHybFilter->bufferHFReal[k], (hAnalysisHybFilter->nrBands-setup->nrQmfBands), scalingValue);
296 scaleValues(hAnalysisHybFilter->bufferHFImag[k], (hAnalysisHybFilter->cplxBands-setup->nrQmfBands), scalingValue);
297 }
298 }
299 }
300 return err;
301 }
302
303 INT FDKhybridAnalysisApply(
304 HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter,
305 const FIXP_DBL *const pQmfReal,
306 const FIXP_DBL *const pQmfImag,
307 FIXP_DBL *const pHybridReal,
308 FIXP_DBL *const pHybridImag)
309 {
310 int k, hybOffset = 0;
311 INT err = 0;
312 const int nrQmfBandsLF = hAnalysisHybFilter->pSetup->nrQmfBands; /* number of QMF bands to be converted to hybrid */
313
314 const int writIndex = hAnalysisHybFilter->bufferLFpos;
315 int readIndex = hAnalysisHybFilter->bufferLFpos;
316
317 if (++readIndex>=hAnalysisHybFilter->pSetup->protoLen) readIndex = 0;
318 const INT* pBufferLFreadIdx = &hAnalysisHybFilter->pSetup->pReadIdxTable[readIndex];
319
320 /*
321 * LF buffer.
322 */
323 for (k=0; k<nrQmfBandsLF; k++) {
324 /* New input sample. */
325 hAnalysisHybFilter->bufferLFReal[k][writIndex] = pQmfReal[k];
326 hAnalysisHybFilter->bufferLFImag[k][writIndex] = pQmfImag[k];
327
328 /* Perform hybrid filtering. */
329 kChannelFiltering(
330 hAnalysisHybFilter->bufferLFReal[k],
331 hAnalysisHybFilter->bufferLFImag[k],
332 pBufferLFreadIdx,
333 pHybridReal+hybOffset,
334 pHybridImag+hybOffset,
335 hAnalysisHybFilter->pSetup->kHybrid[k]);
336
337 hybOffset += hAnalysisHybFilter->pSetup->nHybBands[k];
338 }
339
340 hAnalysisHybFilter->bufferLFpos = readIndex; /* Index where to write next input sample. */
341
342 if (hAnalysisHybFilter->nrBands > nrQmfBandsLF) {
343 /*
344 * HF buffer.
345 */
346 if (hAnalysisHybFilter->hfMode!=0) {
347 /* HF delay compensation was applied outside. */
348 FDKmemcpy(pHybridReal+hybOffset, &pQmfReal[nrQmfBandsLF], (hAnalysisHybFilter->nrBands-nrQmfBandsLF)*sizeof(FIXP_DBL));
349 FDKmemcpy(pHybridImag+hybOffset, &pQmfImag[nrQmfBandsLF], (hAnalysisHybFilter->cplxBands-nrQmfBandsLF)*sizeof(FIXP_DBL));
350 }
351 else {
352 /* HF delay compensation, filterlength/2. */
353 FDKmemcpy(pHybridReal+hybOffset, hAnalysisHybFilter->bufferHFReal[hAnalysisHybFilter->bufferHFpos], (hAnalysisHybFilter->nrBands-nrQmfBandsLF)*sizeof(FIXP_DBL));
354 FDKmemcpy(pHybridImag+hybOffset, hAnalysisHybFilter->bufferHFImag[hAnalysisHybFilter->bufferHFpos], (hAnalysisHybFilter->cplxBands-nrQmfBandsLF)*sizeof(FIXP_DBL));
355
356 FDKmemcpy(hAnalysisHybFilter->bufferHFReal[hAnalysisHybFilter->bufferHFpos], &pQmfReal[nrQmfBandsLF], (hAnalysisHybFilter->nrBands-nrQmfBandsLF)*sizeof(FIXP_DBL));
357 FDKmemcpy(hAnalysisHybFilter->bufferHFImag[hAnalysisHybFilter->bufferHFpos], &pQmfImag[nrQmfBandsLF], (hAnalysisHybFilter->cplxBands-nrQmfBandsLF)*sizeof(FIXP_DBL));
358
359 if (++hAnalysisHybFilter->bufferHFpos>=hAnalysisHybFilter->pSetup->filterDelay) hAnalysisHybFilter->bufferHFpos = 0;
360 }
361 } /* process HF part*/
362
363 return err;
364 }
365
366 INT FDKhybridAnalysisClose(
367 HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter
368 )
369 {
370 INT err = 0;
371
372 if (hAnalysisHybFilter != NULL) {
373 hAnalysisHybFilter->pLFmemory = NULL;
374 hAnalysisHybFilter->pHFmemory = NULL;
375 hAnalysisHybFilter->LFmemorySize = 0;
376 hAnalysisHybFilter->HFmemorySize = 0;
377 }
378
379 return err;
380 }
381
382 INT FDKhybridSynthesisInit(
383 HANDLE_FDK_SYN_HYB_FILTER hSynthesisHybFilter,
384 const FDK_HYBRID_MODE mode,
385 const INT qmfBands,
386 const INT cplxBands
387 )
388 {
389 INT err = 0;
390 HANDLE_FDK_HYBRID_SETUP setup = NULL;
391
392 switch (mode) {
393 case THREE_TO_TEN: setup = (HANDLE_FDK_HYBRID_SETUP)&setup_3_10; break;
394 case THREE_TO_TWELVE: setup = (HANDLE_FDK_HYBRID_SETUP)&setup_3_12; break;
395 case THREE_TO_SIXTEEN: setup = (HANDLE_FDK_HYBRID_SETUP)&setup_3_16; break;
396 default: err = -1; goto bail;
397 }
398
399 hSynthesisHybFilter->pSetup = setup;
400 hSynthesisHybFilter->nrBands = qmfBands;
401 hSynthesisHybFilter->cplxBands = cplxBands;
402
403 bail:
404 return err;
405 }
406
407
408 INT FDKhybridSynthesisApply(
409 HANDLE_FDK_SYN_HYB_FILTER hSynthesisHybFilter,
410 const FIXP_DBL *const pHybridReal,
411 const FIXP_DBL *const pHybridImag,
412 FIXP_DBL *const pQmfReal,
413 FIXP_DBL *const pQmfImag
414 )
415 {
416 int k, n, hybOffset=0;
417 INT err = 0;
418 const INT nrQmfBandsLF = hSynthesisHybFilter->pSetup->nrQmfBands;
419
420 /*
421 * LF buffer.
422 */
423 for (k=0; k<nrQmfBandsLF; k++) {
424 const int nHybBands = hSynthesisHybFilter->pSetup->nHybBands[k];
425
426 FIXP_DBL accu1 = FL2FXCONST_DBL(0.f);
427 FIXP_DBL accu2 = FL2FXCONST_DBL(0.f);
428
429 /* Perform hybrid filtering. */
430 for (n=0; n<nHybBands; n++) {
431 accu1 += pHybridReal[hybOffset+n];
432 accu2 += pHybridImag[hybOffset+n];
433 }
434 pQmfReal[k] = accu1;
435 pQmfImag[k] = accu2;
436
437 hybOffset += nHybBands;
438 }
439
440 if (hSynthesisHybFilter->nrBands > nrQmfBandsLF) {
441 /*
442 * HF buffer.
443 */
444 FDKmemcpy(&pQmfReal[nrQmfBandsLF], &pHybridReal[hybOffset], (hSynthesisHybFilter->nrBands-nrQmfBandsLF)*sizeof(FIXP_DBL));
445 FDKmemcpy(&pQmfImag[nrQmfBandsLF], &pHybridImag[hybOffset], (hSynthesisHybFilter->cplxBands-nrQmfBandsLF)*sizeof(FIXP_DBL));
446 }
447
448 return err;
449 }
450
451 static void dualChannelFiltering(
452 const FIXP_DBL *const pQmfReal,
453 const FIXP_DBL *const pQmfImag,
454 const INT *const pReadIdx,
455 FIXP_DBL *const mHybridReal,
456 FIXP_DBL *const mHybridImag,
457 const INT invert
458 )
459 {
460 const FIXP_HTB *p = HybFilterCoef2;
461
462 FIXP_DBL r1, r6;
463 FIXP_DBL i1, i6;
464
465 /* symmetric filter coefficients */
466 r1 = fMultDiv2(p[1], pQmfReal[pReadIdx[1]]) + fMultDiv2(p[1], pQmfReal[pReadIdx[11]]) ;
467 i1 = fMultDiv2(p[1], pQmfImag[pReadIdx[1]]) + fMultDiv2(p[1], pQmfImag[pReadIdx[11]]) ;
468 r1 += fMultDiv2(p[3], pQmfReal[pReadIdx[3]]) + fMultDiv2(p[3], pQmfReal[pReadIdx[ 9]]) ;
469 i1 += fMultDiv2(p[3], pQmfImag[pReadIdx[3]]) + fMultDiv2(p[3], pQmfImag[pReadIdx[ 9]]) ;
470 r1 += fMultDiv2(p[5], pQmfReal[pReadIdx[5]]) + fMultDiv2(p[5], pQmfReal[pReadIdx[ 7]]) ;
471 i1 += fMultDiv2(p[5], pQmfImag[pReadIdx[5]]) + fMultDiv2(p[5], pQmfImag[pReadIdx[ 7]]) ;
472 r6 = fMultDiv2(p[6], pQmfReal[pReadIdx[6]]) ;
473 i6 = fMultDiv2(p[6], pQmfImag[pReadIdx[6]]) ;
474
475 if (invert) {
476 mHybridReal[1] = (r1 + r6) << 1;
477 mHybridImag[1] = (i1 + i6) << 1;
478
479 mHybridReal[0] = (r6 - r1) << 1;
480 mHybridImag[0] = (i6 - i1) << 1;
481 }
482 else {
483 mHybridReal[0] = (r1 + r6) << 1;
484 mHybridImag[0] = (i1 + i6) << 1;
485
486 mHybridReal[1] = (r6 - r1) << 1;
487 mHybridImag[1] = (i6 - i1) << 1;
488 }
489 }
490
491 static void fourChannelFiltering(
492 const FIXP_DBL *const pQmfReal,
493 const FIXP_DBL *const pQmfImag,
494 const INT *const pReadIdx,
495 FIXP_DBL *const mHybridReal,
496 FIXP_DBL *const mHybridImag,
497 const INT invert
498 )
499 {
500 const FIXP_HTB *p = HybFilterCoef4;
501
502 FIXP_DBL fft[8];
503
504 static const FIXP_DBL cr[13] = {
505 FL2FXCONST_DBL( 0.f), FL2FXCONST_DBL(-0.70710678118655f), FL2FXCONST_DBL( -1.f),
506 FL2FXCONST_DBL(-0.70710678118655f), FL2FXCONST_DBL( 0.f), FL2FXCONST_DBL( 0.70710678118655f),
507 FL2FXCONST_DBL( 1.f),
508 FL2FXCONST_DBL( 0.70710678118655f), FL2FXCONST_DBL( 0.f), FL2FXCONST_DBL(-0.70710678118655f),
509 FL2FXCONST_DBL( -1.f), FL2FXCONST_DBL(-0.70710678118655f), FL2FXCONST_DBL( 0.f)
510 };
511 static const FIXP_DBL ci[13] = {
512 FL2FXCONST_DBL( -1.f), FL2FXCONST_DBL(-0.70710678118655f), FL2FXCONST_DBL( 0.f),
513 FL2FXCONST_DBL( 0.70710678118655f), FL2FXCONST_DBL( 1.f), FL2FXCONST_DBL( 0.70710678118655f),
514 FL2FXCONST_DBL( 0.f),
515 FL2FXCONST_DBL(-0.70710678118655f), FL2FXCONST_DBL( -1.f), FL2FXCONST_DBL(-0.70710678118655f),
516 FL2FXCONST_DBL( 0.f), FL2FXCONST_DBL( 0.70710678118655f), FL2FXCONST_DBL( 1.f)
517 };
518
519
520 /* FIR filter. */
521 /* pre twiddeling with pre-twiddling coefficients c[n] */
522 /* multiplication with filter coefficients p[n] */
523 /* hint: (a + ib)*(c + id) = (a*c - b*d) + i(a*d + b*c) */
524 /* write to fft coefficient n' */
525 fft[FFT_IDX_R(0)] = ( fMult(p[10], ( fMultSub(fMultDiv2(cr[ 2], pQmfReal[pReadIdx[ 2]]), ci[ 2], pQmfImag[pReadIdx[ 2]]))) +
526 fMult(p[ 6], ( fMultSub(fMultDiv2(cr[ 6], pQmfReal[pReadIdx[ 6]]), ci[ 6], pQmfImag[pReadIdx[ 6]]))) +
527 fMult(p[ 2], ( fMultSub(fMultDiv2(cr[10], pQmfReal[pReadIdx[10]]), ci[10], pQmfImag[pReadIdx[10]]))) );
528 fft[FFT_IDX_I(0)] = ( fMult(p[10], ( fMultAdd(fMultDiv2(ci[ 2], pQmfReal[pReadIdx[ 2]]), cr[ 2], pQmfImag[pReadIdx[ 2]]))) +
529 fMult(p[ 6], ( fMultAdd(fMultDiv2(ci[ 6], pQmfReal[pReadIdx[ 6]]), cr[ 6], pQmfImag[pReadIdx[ 6]]))) +
530 fMult(p[ 2], ( fMultAdd(fMultDiv2(ci[10], pQmfReal[pReadIdx[10]]), cr[10], pQmfImag[pReadIdx[10]]))) );
531
532 /* twiddle dee dum */
533 fft[FFT_IDX_R(1)] = ( fMult(p[ 9], ( fMultSub(fMultDiv2(cr[ 3], pQmfReal[pReadIdx[ 3]]), ci[ 3], pQmfImag[pReadIdx[ 3]]))) +
534 fMult(p[ 5], ( fMultSub(fMultDiv2(cr[ 7], pQmfReal[pReadIdx[ 7]]), ci[ 7], pQmfImag[pReadIdx[ 7]]))) +
535 fMult(p[ 1], ( fMultSub(fMultDiv2(cr[11], pQmfReal[pReadIdx[11]]), ci[11], pQmfImag[pReadIdx[11]]))) );
536 fft[FFT_IDX_I(1)] = ( fMult(p[ 9], ( fMultAdd(fMultDiv2(ci[ 3], pQmfReal[pReadIdx[ 3]]), cr[ 3], pQmfImag[pReadIdx[ 3]]))) +
537 fMult(p[ 5], ( fMultAdd(fMultDiv2(ci[ 7], pQmfReal[pReadIdx[ 7]]), cr[ 7], pQmfImag[pReadIdx[ 7]]))) +
538 fMult(p[ 1], ( fMultAdd(fMultDiv2(ci[11], pQmfReal[pReadIdx[11]]), cr[11], pQmfImag[pReadIdx[11]]))) );
539
540 /* twiddle dee dee */
541 fft[FFT_IDX_R(2)] = ( fMult(p[12], ( fMultSub(fMultDiv2(cr[ 0], pQmfReal[pReadIdx[ 0]]), ci[ 0], pQmfImag[pReadIdx[ 0]]))) +
542 fMult(p[ 8], ( fMultSub(fMultDiv2(cr[ 4], pQmfReal[pReadIdx[ 4]]), ci[ 4], pQmfImag[pReadIdx[ 4]]))) +
543 fMult(p[ 4], ( fMultSub(fMultDiv2(cr[ 8], pQmfReal[pReadIdx[ 8]]), ci[ 8], pQmfImag[pReadIdx[ 8]]))) +
544 fMult(p[ 0], ( fMultSub(fMultDiv2(cr[12], pQmfReal[pReadIdx[12]]), ci[12], pQmfImag[pReadIdx[12]]))) );
545 fft[FFT_IDX_I(2)] = ( fMult(p[12], ( fMultAdd(fMultDiv2(ci[ 0], pQmfReal[pReadIdx[ 0]]), cr[ 0], pQmfImag[pReadIdx[ 0]]))) +
546 fMult(p[ 8], ( fMultAdd(fMultDiv2(ci[ 4], pQmfReal[pReadIdx[ 4]]), cr[ 4], pQmfImag[pReadIdx[ 4]]))) +
547 fMult(p[ 4], ( fMultAdd(fMultDiv2(ci[ 8], pQmfReal[pReadIdx[ 8]]), cr[ 8], pQmfImag[pReadIdx[ 8]]))) +
548 fMult(p[ 0], ( fMultAdd(fMultDiv2(ci[12], pQmfReal[pReadIdx[12]]), cr[12], pQmfImag[pReadIdx[12]]))) );
549
550 fft[FFT_IDX_R(3)] = ( fMult(p[11], ( fMultSub(fMultDiv2(cr[ 1], pQmfReal[pReadIdx[ 1]]), ci[ 1], pQmfImag[pReadIdx[ 1]]))) +
551 fMult(p[ 7], ( fMultSub(fMultDiv2(cr[ 5], pQmfReal[pReadIdx[ 5]]), ci[ 5], pQmfImag[pReadIdx[ 5]]))) +
552 fMult(p[ 3], ( fMultSub(fMultDiv2(cr[ 9], pQmfReal[pReadIdx[ 9]]), ci[ 9], pQmfImag[pReadIdx[ 9]]))) );
553 fft[FFT_IDX_I(3)] = ( fMult(p[11], ( fMultAdd(fMultDiv2(ci[ 1], pQmfReal[pReadIdx[ 1]]), cr[ 1], pQmfImag[pReadIdx[ 1]]))) +
554 fMult(p[ 7], ( fMultAdd(fMultDiv2(ci[ 5], pQmfReal[pReadIdx[ 5]]), cr[ 5], pQmfImag[pReadIdx[ 5]]))) +
555 fMult(p[ 3], ( fMultAdd(fMultDiv2(ci[ 9], pQmfReal[pReadIdx[ 9]]), cr[ 9], pQmfImag[pReadIdx[ 9]]))) );
556
557 /* fft modulation */
558 /* here: fast manual fft modulation for a fft of length M=4 */
559 /* fft_4{x[n]} = x[0]*exp(-i*2*pi/4*m*0) + x[1]*exp(-i*2*pi/4*m*1) +
560 x[2]*exp(-i*2*pi/4*m*2) + x[3]*exp(-i*2*pi/4*m*3) */
561
562 /*
563 fft bin m=0:
564 X[0, n] = x[0] + x[1] + x[2] + x[3]
565 */
566 mHybridReal[0] = fft[FFT_IDX_R(0)] + fft[FFT_IDX_R(1)] + fft[FFT_IDX_R(2)] + fft[FFT_IDX_R(3)];
567 mHybridImag[0] = fft[FFT_IDX_I(0)] + fft[FFT_IDX_I(1)] + fft[FFT_IDX_I(2)] + fft[FFT_IDX_I(3)];
568
569 /*
570 fft bin m=1:
571 X[1, n] = x[0] - i*x[1] - x[2] + i*x[3]
572 */
573 mHybridReal[1] = fft[FFT_IDX_R(0)] + fft[FFT_IDX_I(1)] - fft[FFT_IDX_R(2)] - fft[FFT_IDX_I(3)];
574 mHybridImag[1] = fft[FFT_IDX_I(0)] - fft[FFT_IDX_R(1)] - fft[FFT_IDX_I(2)] + fft[FFT_IDX_R(3)];
575
576 /*
577 fft bin m=2:
578 X[2, n] = x[0] - x[1] + x[2] - x[3]
579 */
580 mHybridReal[2] = fft[FFT_IDX_R(0)] - fft[FFT_IDX_R(1)] + fft[FFT_IDX_R(2)] - fft[FFT_IDX_R(3)];
581 mHybridImag[2] = fft[FFT_IDX_I(0)] - fft[FFT_IDX_I(1)] + fft[FFT_IDX_I(2)] - fft[FFT_IDX_I(3)];
582
583 /*
584 fft bin m=3:
585 X[3, n] = x[0] + j*x[1] - x[2] - j*x[3]
586 */
587 mHybridReal[3] = fft[FFT_IDX_R(0)] - fft[FFT_IDX_I(1)] - fft[FFT_IDX_R(2)] + fft[FFT_IDX_I(3)];
588 mHybridImag[3] = fft[FFT_IDX_I(0)] + fft[FFT_IDX_R(1)] - fft[FFT_IDX_I(2)] - fft[FFT_IDX_R(3)];
589 }
590
591
592 static void eightChannelFiltering(
593 const FIXP_DBL *const pQmfReal,
594 const FIXP_DBL *const pQmfImag,
595 const INT *const pReadIdx,
596 FIXP_DBL *const mHybridReal,
597 FIXP_DBL *const mHybridImag,
598 const INT invert
599 )
600 {
601 const FIXP_HTP *p = HybFilterCoef8;
602 INT k, sc;
603
604 FIXP_DBL mfft[16+ALIGNMENT_DEFAULT];
605 FIXP_DBL *pfft = (FIXP_DBL*)ALIGN_PTR(mfft);
606
607 FIXP_DBL accu1, accu2, accu3, accu4;
608
609 /* pre twiddeling */
610 pfft[FFT_IDX_R(0)] = fMultDiv2(p[0].v.re, pQmfReal[pReadIdx[6]]);
611 pfft[FFT_IDX_I(0)] = fMultDiv2(p[0].v.re, pQmfImag[pReadIdx[6]]);
612
613 cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[7]], pQmfImag[pReadIdx[7]], p[1]);
614 pfft[FFT_IDX_R(1)] = accu1;
615 pfft[FFT_IDX_I(1)] = accu2;
616
617 cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[0]], pQmfImag[pReadIdx[0]], p[2]);
618 cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[8]], pQmfImag[pReadIdx[8]], p[3]);
619 pfft[FFT_IDX_R(2)] = accu1 + accu3;
620 pfft[FFT_IDX_I(2)] = accu2 + accu4;
621
622 cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[1]], pQmfImag[pReadIdx[1]], p[4]);
623 cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[9]], pQmfImag[pReadIdx[9]], p[5]);
624 pfft[FFT_IDX_R(3)] = accu1 + accu3;
625 pfft[FFT_IDX_I(3)] = accu2 + accu4;
626
627 pfft[FFT_IDX_R(4)] = fMultDiv2(pQmfImag[pReadIdx[10]], p[7].v.im) - fMultDiv2(pQmfImag[pReadIdx[ 2]], p[6].v.im);
628 pfft[FFT_IDX_I(4)] = fMultDiv2(pQmfReal[pReadIdx[ 2]], p[6].v.im) - fMultDiv2(pQmfReal[pReadIdx[10]], p[7].v.im);
629
630 cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[ 3]], pQmfImag[pReadIdx[ 3]], p[8]);
631 cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[11]], pQmfImag[pReadIdx[11]], p[9]);
632 pfft[FFT_IDX_R(5)] = accu1 + accu3;
633 pfft[FFT_IDX_I(5)] = accu2 + accu4;
634
635 cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[ 4]], pQmfImag[pReadIdx[ 4]], p[10]);
636 cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[12]], pQmfImag[pReadIdx[12]], p[11]);
637 pfft[FFT_IDX_R(6)] = accu1 + accu3;
638 pfft[FFT_IDX_I(6)] = accu2 + accu4;
639
640 cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[ 5]], pQmfImag[pReadIdx[ 5]], p[12]);
641 pfft[FFT_IDX_R(7)] = accu1;
642 pfft[FFT_IDX_I(7)] = accu2;
643
644 /* fft modulation */
645 fft_8 (pfft);
646 sc = 1 + 2;
647
648 if (invert) {
649 mHybridReal[0] = pfft[FFT_IDX_R(7)] << sc;
650 mHybridImag[0] = pfft[FFT_IDX_I(7)] << sc;
651 mHybridReal[1] = pfft[FFT_IDX_R(0)] << sc;
652 mHybridImag[1] = pfft[FFT_IDX_I(0)] << sc;
653
654 mHybridReal[2] = pfft[FFT_IDX_R(6)] << sc;
655 mHybridImag[2] = pfft[FFT_IDX_I(6)] << sc;
656 mHybridReal[3] = pfft[FFT_IDX_R(1)] << sc;
657 mHybridImag[3] = pfft[FFT_IDX_I(1)] << sc;
658
659 mHybridReal[4] = pfft[FFT_IDX_R(2)] << sc;
660 mHybridReal[4] += pfft[FFT_IDX_R(5)] << sc;
661 mHybridImag[4] = pfft[FFT_IDX_I(2)] << sc;
662 mHybridImag[4] += pfft[FFT_IDX_I(5)] << sc;
663
664 mHybridReal[5] = pfft[FFT_IDX_R(3)] << sc;
665 mHybridReal[5] += pfft[FFT_IDX_R(4)] << sc;
666 mHybridImag[5] = pfft[FFT_IDX_I(3)] << sc;
667 mHybridImag[5] += pfft[FFT_IDX_I(4)] << sc;
668 }
669 else {
670 for(k=0; k<8;k++ ) {
671 mHybridReal[k] = pfft[FFT_IDX_R(k)] << sc;
672 mHybridImag[k] = pfft[FFT_IDX_I(k)] << sc;
673 }
674 }
675 }
676
677 static INT kChannelFiltering(
678 const FIXP_DBL *const pQmfReal,
679 const FIXP_DBL *const pQmfImag,
680 const INT *const pReadIdx,
681 FIXP_DBL *const mHybridReal,
682 FIXP_DBL *const mHybridImag,
683 const SCHAR hybridConfig
684 )
685 {
686 INT err = 0;
687
688 switch (hybridConfig) {
689 case 2:
690 case -2:
691 dualChannelFiltering(pQmfReal, pQmfImag, pReadIdx, mHybridReal, mHybridImag, (hybridConfig<0) ? 1 : 0 );
692 break;
693 case 4:
694 case -4:
695 fourChannelFiltering(pQmfReal, pQmfImag, pReadIdx, mHybridReal, mHybridImag, (hybridConfig<0) ? 1 : 0 );
696 break;
697 case 8:
698 case -8:
699 eightChannelFiltering(pQmfReal, pQmfImag, pReadIdx, mHybridReal, mHybridImag, (hybridConfig<0) ? 1 : 0 );
700 break;
701 default:
702 err = -1;
703 }
704
705 return err;
706 }
707
708
709