1/* -----------------------------------------------------------------------------
2Software License for The Fraunhofer FDK AAC Codec Library for Android
3
4© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
5Forschung e.V. All rights reserved.
6
7 1.    INTRODUCTION
8The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software
9that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding
10scheme for digital audio. This FDK AAC Codec software is intended to be used on
11a wide variety of Android devices.
12
13AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient
14general perceptual audio codecs. AAC-ELD is considered the best-performing
15full-bandwidth communications codec by independent studies and is widely
16deployed. AAC has been standardized by ISO and IEC as part of the MPEG
17specifications.
18
19Patent licenses for necessary patent claims for the FDK AAC Codec (including
20those of Fraunhofer) may be obtained through Via Licensing
21(www.vialicensing.com) or through the respective patent owners individually for
22the purpose of encoding or decoding bit streams in products that are compliant
23with the ISO/IEC MPEG audio standards. Please note that most manufacturers of
24Android devices already license these patent claims through Via Licensing or
25directly from the patent owners, and therefore FDK AAC Codec software may
26already be covered under those patent licenses when it is used for those
27licensed purposes only.
28
29Commercially-licensed AAC software libraries, including floating-point versions
30with enhanced sound quality, are also available from Fraunhofer. Users are
31encouraged to check the Fraunhofer website for additional applications
32information and documentation.
33
342.    COPYRIGHT LICENSE
35
36Redistribution and use in source and binary forms, with or without modification,
37are permitted without payment of copyright license fees provided that you
38satisfy the following conditions:
39
40You must retain the complete text of this software license in redistributions of
41the FDK AAC Codec or your modifications thereto in source code form.
42
43You must retain the complete text of this software license in the documentation
44and/or other materials provided with redistributions of the FDK AAC Codec or
45your modifications thereto in binary form. You must make available free of
46charge copies of the complete source code of the FDK AAC Codec and your
47modifications thereto to recipients of copies in binary form.
48
49The name of Fraunhofer may not be used to endorse or promote products derived
50from this library without prior written permission.
51
52You may not charge copyright license fees for anyone to use, copy or distribute
53the FDK AAC Codec software or your modifications thereto.
54
55Your modified versions of the FDK AAC Codec must carry prominent notices stating
56that you changed the software and the date of any change. For modified versions
57of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android"
58must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK
59AAC Codec Library for Android."
60
613.    NO PATENT LICENSE
62
63NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without
64limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE.
65Fraunhofer provides no warranty of patent non-infringement with respect to this
66software.
67
68You may use this FDK AAC Codec software or modifications thereto only for
69purposes that are authorized by appropriate patent licenses.
70
714.    DISCLAIMER
72
73This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright
74holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
75including but not limited to the implied warranties of merchantability and
76fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
77CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary,
78or consequential damages, including but not limited to procurement of substitute
79goods or services; loss of use, data, or profits, or business interruption,
80however caused and on any theory of liability, whether in contract, strict
81liability, or tort (including negligence), arising in any way out of the use of
82this software, even if advised of the possibility of such damage.
83
845.    CONTACT INFORMATION
85
86Fraunhofer Institute for Integrated Circuits IIS
87Attention: Audio and Multimedia Departments - FDK AAC LL
88Am Wolfsmantel 33
8991058 Erlangen, Germany
90
91www.iis.fraunhofer.de/amm
92amm-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
144struct 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 ---------------------------*/
155static 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
159static const FDK_HYBRID_SETUP setup_3_16 = {3,  {8, 4, 4},    {8, 4, 4},
160                                            13, (13 - 1) / 2, ringbuffIdxTab};
161static const FDK_HYBRID_SETUP setup_3_12 = {3,  {8, 2, 2},    {8, 2, 2},
162                                            13, (13 - 1) / 2, ringbuffIdxTab};
163static const FDK_HYBRID_SETUP setup_3_10 = {3,  {6, 2, 2},    {-8, -2, 2},
164                                            13, (13 - 1) / 2, ringbuffIdxTab};
165
166static 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
175static const FIXP_HTB HybFilterCoef2[3] = {FL2FXCONST_HTB(0.01899487526049f),
176                                           FL2FXCONST_HTB(-0.07293139167538f),
177                                           FL2FXCONST_HTB(0.30596630545168f)};
178
179static 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 ---------------*/
194static 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
203INT 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
218INT 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
308bail:
309  return err;
310}
311
312INT 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
344INT 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
425INT 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
438INT 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
463bail:
464  return err;
465}
466
467void 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
509static 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
547static 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
687static 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
784static 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