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