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