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 
FDKhybridAnalysisOpen(HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter,FIXP_DBL * const pLFmemory,const UINT LFmemorySize,FIXP_DBL * const pHFmemory,const UINT HFmemorySize)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 
FDKhybridAnalysisInit(HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter,const FDK_HYBRID_MODE mode,const INT qmfBands,const INT cplxBands,const INT initStatesFlag)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 
FDKhybridAnalysisScaleStates(HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter,const INT scalingValue)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 
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)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 
FDKhybridAnalysisClose(HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter)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 
FDKhybridSynthesisInit(HANDLE_FDK_SYN_HYB_FILTER hSynthesisHybFilter,const FDK_HYBRID_MODE mode,const INT qmfBands,const INT cplxBands)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 
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)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 
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)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 
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)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 
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)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 
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)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 
710