1
2/* -----------------------------------------------------------------------------------------------------------
3Software License for The Fraunhofer FDK AAC Codec Library for Android
4
5© Copyright  1995 - 2012 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V.
6  All rights reserved.
7
8 1.    INTRODUCTION
9The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements
10the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio.
11This FDK AAC Codec software is intended to be used on a wide variety of Android devices.
12
13AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual
14audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by
15independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part
16of the MPEG specifications.
17
18Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer)
19may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners
20individually for the purpose of encoding or decoding bit streams in products that are compliant with
21the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license
22these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec
23software may already be covered under those patent licenses when it is used for those licensed purposes only.
24
25Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality,
26are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional
27applications information and documentation.
28
292.    COPYRIGHT LICENSE
30
31Redistribution and use in source and binary forms, with or without modification, are permitted without
32payment of copyright license fees provided that you satisfy the following conditions:
33
34You must retain the complete text of this software license in redistributions of the FDK AAC Codec or
35your modifications thereto in source code form.
36
37You must retain the complete text of this software license in the documentation and/or other materials
38provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form.
39You must make available free of charge copies of the complete source code of the FDK AAC Codec and your
40modifications thereto to recipients of copies in binary form.
41
42The name of Fraunhofer may not be used to endorse or promote products derived from this library without
43prior written permission.
44
45You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec
46software or your modifications thereto.
47
48Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software
49and 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
533.    NO PATENT LICENSE
54
55NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer,
56ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with
57respect to this software.
58
59You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized
60by appropriate patent licenses.
61
624.    DISCLAIMER
63
64This 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
66of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
67CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages,
68including but not limited to procurement of substitute goods or services; loss of use, data, or profits,
69or business interruption, however caused and on any theory of liability, whether in contract, strict
70liability, or tort (including negligence), arising in any way out of the use of this software, even if
71advised of the possibility of such damage.
72
735.    CONTACT INFORMATION
74
75Fraunhofer Institute for Integrated Circuits IIS
76Attention: Audio and Multimedia Departments - FDK AAC LL
77Am Wolfsmantel 33
7891058 Erlangen, Germany
79
80www.iis.fraunhofer.de/amm
81amm-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
132struct 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 ---------------------------*/
144static 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
146static const FDK_HYBRID_SETUP setup_3_16 = { 3, { 8, 4, 4}, {  8,  4,  4}, 13, (13-1)/2, ringbuffIdxTab};
147static const FDK_HYBRID_SETUP setup_3_12 = { 3, { 8, 2, 2}, {  8,  2,  2}, 13, (13-1)/2, ringbuffIdxTab};
148static const FDK_HYBRID_SETUP setup_3_10 = { 3, { 6, 2, 2}, { -8, -2,  2}, 13, (13-1)/2, ringbuffIdxTab};
149
150
151static 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
158static 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
164static 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 ---------------*/
171static 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
183INT 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
203INT 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
269bail:
270    return err;
271}
272
273INT 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
303INT 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
366INT 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
382INT 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
403bail:
404    return err;
405}
406
407
408INT 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
451static 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
491static 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
592static 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
677static 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
710