Coverage Report

Created: 2025-07-11 06:54

/src/aac/libFDK/src/FDK_hybrid.cpp
Line
Count
Source (jump to first uncovered line)
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
86.6M
#define FFT_IDX_R(a) (2 * a)
109
86.6M
#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
204
INT FDKhybridAnalysisOpen(HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter,
205
                          FIXP_DBL *const pLFmemory, const UINT LFmemorySize,
206
54.2k
                          FIXP_DBL *const pHFmemory, const UINT HFmemorySize) {
207
54.2k
  INT err = 0;
208
209
  /* Save pointer to extern memory. */
210
54.2k
  hAnalysisHybFilter->pLFmemory = pLFmemory;
211
54.2k
  hAnalysisHybFilter->LFmemorySize = LFmemorySize;
212
213
54.2k
  hAnalysisHybFilter->pHFmemory = pHFmemory;
214
54.2k
  hAnalysisHybFilter->HFmemorySize = HFmemorySize;
215
216
54.2k
  return err;
217
54.2k
}
218
219
INT FDKhybridAnalysisInit(HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter,
220
                          const FDK_HYBRID_MODE mode, const INT qmfBands,
221
141k
                          const INT cplxBands, const INT initStatesFlag) {
222
141k
  int k;
223
141k
  INT err = 0;
224
141k
  FIXP_DBL *pMem = NULL;
225
141k
  HANDLE_FDK_HYBRID_SETUP setup = NULL;
226
227
141k
  switch (mode) {
228
141k
    case THREE_TO_TEN:
229
141k
      setup = &setup_3_10;
230
141k
      break;
231
0
    case THREE_TO_TWELVE:
232
0
      setup = &setup_3_12;
233
0
      break;
234
0
    case THREE_TO_SIXTEEN:
235
0
      setup = &setup_3_16;
236
0
      break;
237
0
    default:
238
0
      err = -1;
239
0
      goto bail;
240
141k
  }
241
242
  /* Initialize handle. */
243
141k
  hAnalysisHybFilter->pSetup = setup;
244
141k
  if (initStatesFlag) {
245
17.3k
    hAnalysisHybFilter->bufferLFpos = setup->protoLen - 1;
246
17.3k
    hAnalysisHybFilter->bufferHFpos = 0;
247
17.3k
  }
248
141k
  hAnalysisHybFilter->nrBands = qmfBands;
249
141k
  hAnalysisHybFilter->cplxBands = cplxBands;
250
141k
  hAnalysisHybFilter->hfMode = 0;
251
252
  /* Check available memory. */
253
141k
  if (((2 * setup->nrQmfBands * setup->protoLen * sizeof(FIXP_DBL)) >
254
141k
       hAnalysisHybFilter->LFmemorySize)) {
255
0
    err = -2;
256
0
    goto bail;
257
0
  }
258
141k
  if (hAnalysisHybFilter->HFmemorySize != 0) {
259
137k
    if (((setup->filterDelay *
260
137k
          ((qmfBands - setup->nrQmfBands) + (cplxBands - setup->nrQmfBands)) *
261
137k
          sizeof(FIXP_DBL)) > hAnalysisHybFilter->HFmemorySize)) {
262
0
      err = -3;
263
0
      goto bail;
264
0
    }
265
137k
  }
266
267
  /* Distribute LF memory. */
268
141k
  pMem = hAnalysisHybFilter->pLFmemory;
269
565k
  for (k = 0; k < setup->nrQmfBands; k++) {
270
424k
    hAnalysisHybFilter->bufferLFReal[k] = pMem;
271
424k
    pMem += setup->protoLen;
272
424k
    hAnalysisHybFilter->bufferLFImag[k] = pMem;
273
424k
    pMem += setup->protoLen;
274
424k
  }
275
276
  /* Distribute HF memory. */
277
141k
  if (hAnalysisHybFilter->HFmemorySize != 0) {
278
137k
    pMem = hAnalysisHybFilter->pHFmemory;
279
960k
    for (k = 0; k < setup->filterDelay; k++) {
280
823k
      hAnalysisHybFilter->bufferHFReal[k] = pMem;
281
823k
      pMem += (qmfBands - setup->nrQmfBands);
282
823k
      hAnalysisHybFilter->bufferHFImag[k] = pMem;
283
823k
      pMem += (cplxBands - setup->nrQmfBands);
284
823k
    }
285
137k
  }
286
287
141k
  if (initStatesFlag) {
288
    /* Clear LF buffer */
289
69.4k
    for (k = 0; k < setup->nrQmfBands; k++) {
290
52.0k
      FDKmemclear(hAnalysisHybFilter->bufferLFReal[k],
291
52.0k
                  setup->protoLen * sizeof(FIXP_DBL));
292
52.0k
      FDKmemclear(hAnalysisHybFilter->bufferLFImag[k],
293
52.0k
                  setup->protoLen * sizeof(FIXP_DBL));
294
52.0k
    }
295
296
17.3k
    if (hAnalysisHybFilter->HFmemorySize != 0) {
297
13.2k
      if (qmfBands > setup->nrQmfBands) {
298
        /* Clear HF buffer */
299
92.4k
        for (k = 0; k < setup->filterDelay; k++) {
300
79.2k
          FDKmemclear(hAnalysisHybFilter->bufferHFReal[k],
301
79.2k
                      (qmfBands - setup->nrQmfBands) * sizeof(FIXP_DBL));
302
79.2k
          FDKmemclear(hAnalysisHybFilter->bufferHFImag[k],
303
79.2k
                      (cplxBands - setup->nrQmfBands) * sizeof(FIXP_DBL));
304
79.2k
        }
305
13.2k
      }
306
13.2k
    }
307
17.3k
  }
308
309
141k
bail:
310
141k
  return err;
311
141k
}
312
313
INT FDKhybridAnalysisScaleStates(HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter,
314
0
                                 const INT scalingValue) {
315
0
  INT err = 0;
316
317
0
  if (hAnalysisHybFilter == NULL) {
318
0
    err = 1; /* invalid handle */
319
0
  } else {
320
0
    int k;
321
0
    HANDLE_FDK_HYBRID_SETUP setup = hAnalysisHybFilter->pSetup;
322
323
    /* Scale LF buffer */
324
0
    for (k = 0; k < setup->nrQmfBands; k++) {
325
0
      scaleValues(hAnalysisHybFilter->bufferLFReal[k], setup->protoLen,
326
0
                  scalingValue);
327
0
      scaleValues(hAnalysisHybFilter->bufferLFImag[k], setup->protoLen,
328
0
                  scalingValue);
329
0
    }
330
0
    if (hAnalysisHybFilter->nrBands > setup->nrQmfBands) {
331
      /* Scale HF buffer */
332
0
      for (k = 0; k < setup->filterDelay; k++) {
333
0
        scaleValues(hAnalysisHybFilter->bufferHFReal[k],
334
0
                    (hAnalysisHybFilter->nrBands - setup->nrQmfBands),
335
0
                    scalingValue);
336
0
        scaleValues(hAnalysisHybFilter->bufferHFImag[k],
337
0
                    (hAnalysisHybFilter->cplxBands - setup->nrQmfBands),
338
0
                    scalingValue);
339
0
      }
340
0
    }
341
0
  }
342
0
  return err;
343
0
}
344
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
7.21M
                           FIXP_DBL *const pHybridImag) {
350
7.21M
  int k, hybOffset = 0;
351
7.21M
  INT err = 0;
352
7.21M
  const int nrQmfBandsLF =
353
7.21M
      hAnalysisHybFilter->pSetup
354
7.21M
          ->nrQmfBands; /* number of QMF bands to be converted to hybrid */
355
356
7.21M
  const int writIndex = hAnalysisHybFilter->bufferLFpos;
357
7.21M
  int readIndex = hAnalysisHybFilter->bufferLFpos;
358
359
7.21M
  if (++readIndex >= hAnalysisHybFilter->pSetup->protoLen) readIndex = 0;
360
7.21M
  const INT *pBufferLFreadIdx =
361
7.21M
      &hAnalysisHybFilter->pSetup->pReadIdxTable[readIndex];
362
363
  /*
364
   * LF buffer.
365
   */
366
28.8M
  for (k = 0; k < nrQmfBandsLF; k++) {
367
    /* New input sample. */
368
21.6M
    hAnalysisHybFilter->bufferLFReal[k][writIndex] = pQmfReal[k];
369
21.6M
    hAnalysisHybFilter->bufferLFImag[k][writIndex] = pQmfImag[k];
370
371
    /* Perform hybrid filtering. */
372
21.6M
    err |=
373
21.6M
        kChannelFiltering(hAnalysisHybFilter->bufferLFReal[k],
374
21.6M
                          hAnalysisHybFilter->bufferLFImag[k], pBufferLFreadIdx,
375
21.6M
                          pHybridReal + hybOffset, pHybridImag + hybOffset,
376
21.6M
                          hAnalysisHybFilter->pSetup->kHybrid[k]);
377
378
21.6M
    hybOffset += hAnalysisHybFilter->pSetup->nHybBands[k];
379
21.6M
  }
380
381
7.21M
  hAnalysisHybFilter->bufferLFpos =
382
7.21M
      readIndex; /* Index where to write next input sample. */
383
384
7.21M
  if (hAnalysisHybFilter->nrBands > nrQmfBandsLF) {
385
    /*
386
     * HF buffer.
387
     */
388
7.10M
    if (hAnalysisHybFilter->hfMode != 0) {
389
      /* HF delay compensation was applied outside. */
390
4.90M
      FDKmemcpy(
391
4.90M
          pHybridReal + hybOffset, &pQmfReal[nrQmfBandsLF],
392
4.90M
          (hAnalysisHybFilter->nrBands - nrQmfBandsLF) * sizeof(FIXP_DBL));
393
4.90M
      FDKmemcpy(
394
4.90M
          pHybridImag + hybOffset, &pQmfImag[nrQmfBandsLF],
395
4.90M
          (hAnalysisHybFilter->cplxBands - nrQmfBandsLF) * sizeof(FIXP_DBL));
396
4.90M
    } else {
397
2.19M
      FDK_ASSERT(hAnalysisHybFilter->HFmemorySize != 0);
398
      /* HF delay compensation, filterlength/2. */
399
2.19M
      FDKmemcpy(
400
2.19M
          pHybridReal + hybOffset,
401
2.19M
          hAnalysisHybFilter->bufferHFReal[hAnalysisHybFilter->bufferHFpos],
402
2.19M
          (hAnalysisHybFilter->nrBands - nrQmfBandsLF) * sizeof(FIXP_DBL));
403
2.19M
      FDKmemcpy(
404
2.19M
          pHybridImag + hybOffset,
405
2.19M
          hAnalysisHybFilter->bufferHFImag[hAnalysisHybFilter->bufferHFpos],
406
2.19M
          (hAnalysisHybFilter->cplxBands - nrQmfBandsLF) * sizeof(FIXP_DBL));
407
408
2.19M
      FDKmemcpy(
409
2.19M
          hAnalysisHybFilter->bufferHFReal[hAnalysisHybFilter->bufferHFpos],
410
2.19M
          &pQmfReal[nrQmfBandsLF],
411
2.19M
          (hAnalysisHybFilter->nrBands - nrQmfBandsLF) * sizeof(FIXP_DBL));
412
2.19M
      FDKmemcpy(
413
2.19M
          hAnalysisHybFilter->bufferHFImag[hAnalysisHybFilter->bufferHFpos],
414
2.19M
          &pQmfImag[nrQmfBandsLF],
415
2.19M
          (hAnalysisHybFilter->cplxBands - nrQmfBandsLF) * sizeof(FIXP_DBL));
416
417
2.19M
      if (++hAnalysisHybFilter->bufferHFpos >=
418
2.19M
          hAnalysisHybFilter->pSetup->filterDelay)
419
363k
        hAnalysisHybFilter->bufferHFpos = 0;
420
2.19M
    }
421
7.10M
  } /* process HF part*/
422
423
7.21M
  return err;
424
7.21M
}
425
426
0
INT FDKhybridAnalysisClose(HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter) {
427
0
  INT err = 0;
428
429
0
  if (hAnalysisHybFilter != NULL) {
430
0
    hAnalysisHybFilter->pLFmemory = NULL;
431
0
    hAnalysisHybFilter->pHFmemory = NULL;
432
0
    hAnalysisHybFilter->LFmemorySize = 0;
433
0
    hAnalysisHybFilter->HFmemorySize = 0;
434
0
  }
435
436
0
  return err;
437
0
}
438
439
INT FDKhybridSynthesisInit(HANDLE_FDK_SYN_HYB_FILTER hSynthesisHybFilter,
440
                           const FDK_HYBRID_MODE mode, const INT qmfBands,
441
145k
                           const INT cplxBands) {
442
145k
  INT err = 0;
443
145k
  HANDLE_FDK_HYBRID_SETUP setup = NULL;
444
445
145k
  switch (mode) {
446
145k
    case THREE_TO_TEN:
447
145k
      setup = &setup_3_10;
448
145k
      break;
449
0
    case THREE_TO_TWELVE:
450
0
      setup = &setup_3_12;
451
0
      break;
452
0
    case THREE_TO_SIXTEEN:
453
0
      setup = &setup_3_16;
454
0
      break;
455
0
    default:
456
0
      err = -1;
457
0
      goto bail;
458
145k
  }
459
460
145k
  hSynthesisHybFilter->pSetup = setup;
461
145k
  hSynthesisHybFilter->nrBands = qmfBands;
462
145k
  hSynthesisHybFilter->cplxBands = cplxBands;
463
464
145k
bail:
465
145k
  return err;
466
145k
}
467
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
12.1M
                             FIXP_DBL *const pQmfImag) {
473
12.1M
  int k, n, hybOffset = 0;
474
12.1M
  const INT nrQmfBandsLF = hSynthesisHybFilter->pSetup->nrQmfBands;
475
476
  /*
477
   * LF buffer.
478
   */
479
48.5M
  for (k = 0; k < nrQmfBandsLF; k++) {
480
36.4M
    const int nHybBands = hSynthesisHybFilter->pSetup->nHybBands[k];
481
36.4M
    const int scale = hSynthesisHybFilter->pSetup->synHybScale[k];
482
483
36.4M
    FIXP_DBL accu1 = FL2FXCONST_DBL(0.f);
484
36.4M
    FIXP_DBL accu2 = FL2FXCONST_DBL(0.f);
485
486
    /* Perform hybrid filtering. */
487
157M
    for (n = 0; n < nHybBands; n++) {
488
121M
      accu1 += pHybridReal[hybOffset + n] >> scale;
489
121M
      accu2 += pHybridImag[hybOffset + n] >> scale;
490
121M
    }
491
36.4M
    pQmfReal[k] = SATURATE_LEFT_SHIFT(accu1, scale, DFRACT_BITS);
492
36.4M
    pQmfImag[k] = SATURATE_LEFT_SHIFT(accu2, scale, DFRACT_BITS);
493
494
36.4M
    hybOffset += nHybBands;
495
36.4M
  }
496
497
12.1M
  if (hSynthesisHybFilter->nrBands > nrQmfBandsLF) {
498
    /*
499
     * HF buffer.
500
     */
501
12.1M
    FDKmemcpy(&pQmfReal[nrQmfBandsLF], &pHybridReal[hybOffset],
502
12.1M
              (hSynthesisHybFilter->nrBands - nrQmfBandsLF) * sizeof(FIXP_DBL));
503
12.1M
    FDKmemcpy(
504
12.1M
        &pQmfImag[nrQmfBandsLF], &pHybridImag[hybOffset],
505
12.1M
        (hSynthesisHybFilter->cplxBands - nrQmfBandsLF) * sizeof(FIXP_DBL));
506
12.1M
  }
507
508
12.1M
  return;
509
12.1M
}
510
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
14.4M
                                 const INT invert) {
517
14.4M
  FIXP_DBL r1, r6;
518
14.4M
  FIXP_DBL i1, i6;
519
520
14.4M
  const FIXP_HTB f0 = HybFilterCoef2[0]; /* corresponds to p1 and p11 */
521
14.4M
  const FIXP_HTB f1 = HybFilterCoef2[1]; /* corresponds to p3 and p9  */
522
14.4M
  const FIXP_HTB f2 = HybFilterCoef2[2]; /* corresponds to p5 and p7  */
523
524
  /* symmetric filter coefficients */
525
14.4M
  r1 = fMultDiv2(f0, pQmfReal[pReadIdx[1]]) +
526
14.4M
       fMultDiv2(f0, pQmfReal[pReadIdx[11]]);
527
14.4M
  i1 = fMultDiv2(f0, pQmfImag[pReadIdx[1]]) +
528
14.4M
       fMultDiv2(f0, pQmfImag[pReadIdx[11]]);
529
14.4M
  r1 += fMultDiv2(f1, pQmfReal[pReadIdx[3]]) +
530
14.4M
        fMultDiv2(f1, pQmfReal[pReadIdx[9]]);
531
14.4M
  i1 += fMultDiv2(f1, pQmfImag[pReadIdx[3]]) +
532
14.4M
        fMultDiv2(f1, pQmfImag[pReadIdx[9]]);
533
14.4M
  r1 += fMultDiv2(f2, pQmfReal[pReadIdx[5]]) +
534
14.4M
        fMultDiv2(f2, pQmfReal[pReadIdx[7]]);
535
14.4M
  i1 += fMultDiv2(f2, pQmfImag[pReadIdx[5]]) +
536
14.4M
        fMultDiv2(f2, pQmfImag[pReadIdx[7]]);
537
538
14.4M
  r6 = pQmfReal[pReadIdx[6]] >> 2;
539
14.4M
  i6 = pQmfImag[pReadIdx[6]] >> 2;
540
541
14.4M
  FDK_ASSERT((invert == 0) || (invert == 1));
542
14.4M
  mHybridReal[0 + invert] = SATURATE_LEFT_SHIFT((r6 + r1), 1, DFRACT_BITS);
543
14.4M
  mHybridImag[0 + invert] = SATURATE_LEFT_SHIFT((i6 + i1), 1, DFRACT_BITS);
544
545
14.4M
  mHybridReal[1 - invert] = SATURATE_LEFT_SHIFT((r6 - r1), 1, DFRACT_BITS);
546
14.4M
  mHybridImag[1 - invert] = SATURATE_LEFT_SHIFT((i6 - i1), 1, DFRACT_BITS);
547
14.4M
}
548
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
0
                                 const INT invert) {
555
0
  const FIXP_HTB *p = HybFilterCoef4;
556
557
0
  FIXP_DBL fft[8];
558
559
0
  static const FIXP_DBL cr[13] = {
560
0
      FL2FXCONST_DBL(0.f),  FL2FXCONST_DBL(-0.70710678118655f),
561
0
      FL2FXCONST_DBL(-1.f), FL2FXCONST_DBL(-0.70710678118655f),
562
0
      FL2FXCONST_DBL(0.f),  FL2FXCONST_DBL(0.70710678118655f),
563
0
      FL2FXCONST_DBL(1.f),  FL2FXCONST_DBL(0.70710678118655f),
564
0
      FL2FXCONST_DBL(0.f),  FL2FXCONST_DBL(-0.70710678118655f),
565
0
      FL2FXCONST_DBL(-1.f), FL2FXCONST_DBL(-0.70710678118655f),
566
0
      FL2FXCONST_DBL(0.f)};
567
0
  static const FIXP_DBL ci[13] = {
568
0
      FL2FXCONST_DBL(-1.f), FL2FXCONST_DBL(-0.70710678118655f),
569
0
      FL2FXCONST_DBL(0.f),  FL2FXCONST_DBL(0.70710678118655f),
570
0
      FL2FXCONST_DBL(1.f),  FL2FXCONST_DBL(0.70710678118655f),
571
0
      FL2FXCONST_DBL(0.f),  FL2FXCONST_DBL(-0.70710678118655f),
572
0
      FL2FXCONST_DBL(-1.f), FL2FXCONST_DBL(-0.70710678118655f),
573
0
      FL2FXCONST_DBL(0.f),  FL2FXCONST_DBL(0.70710678118655f),
574
0
      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
0
  fft[FFT_IDX_R(0)] =
582
0
      (fMult(p[10], (fMultSub(fMultDiv2(cr[2], pQmfReal[pReadIdx[2]]), ci[2],
583
0
                              pQmfImag[pReadIdx[2]]))) +
584
0
       fMult(p[6], (fMultSub(fMultDiv2(cr[6], pQmfReal[pReadIdx[6]]), ci[6],
585
0
                             pQmfImag[pReadIdx[6]]))) +
586
0
       fMult(p[2], (fMultSub(fMultDiv2(cr[10], pQmfReal[pReadIdx[10]]), ci[10],
587
0
                             pQmfImag[pReadIdx[10]]))));
588
0
  fft[FFT_IDX_I(0)] =
589
0
      (fMult(p[10], (fMultAdd(fMultDiv2(ci[2], pQmfReal[pReadIdx[2]]), cr[2],
590
0
                              pQmfImag[pReadIdx[2]]))) +
591
0
       fMult(p[6], (fMultAdd(fMultDiv2(ci[6], pQmfReal[pReadIdx[6]]), cr[6],
592
0
                             pQmfImag[pReadIdx[6]]))) +
593
0
       fMult(p[2], (fMultAdd(fMultDiv2(ci[10], pQmfReal[pReadIdx[10]]), cr[10],
594
0
                             pQmfImag[pReadIdx[10]]))));
595
596
  /* twiddle dee dum */
597
0
  fft[FFT_IDX_R(1)] =
598
0
      (fMult(p[9], (fMultSub(fMultDiv2(cr[3], pQmfReal[pReadIdx[3]]), ci[3],
599
0
                             pQmfImag[pReadIdx[3]]))) +
600
0
       fMult(p[5], (fMultSub(fMultDiv2(cr[7], pQmfReal[pReadIdx[7]]), ci[7],
601
0
                             pQmfImag[pReadIdx[7]]))) +
602
0
       fMult(p[1], (fMultSub(fMultDiv2(cr[11], pQmfReal[pReadIdx[11]]), ci[11],
603
0
                             pQmfImag[pReadIdx[11]]))));
604
0
  fft[FFT_IDX_I(1)] =
605
0
      (fMult(p[9], (fMultAdd(fMultDiv2(ci[3], pQmfReal[pReadIdx[3]]), cr[3],
606
0
                             pQmfImag[pReadIdx[3]]))) +
607
0
       fMult(p[5], (fMultAdd(fMultDiv2(ci[7], pQmfReal[pReadIdx[7]]), cr[7],
608
0
                             pQmfImag[pReadIdx[7]]))) +
609
0
       fMult(p[1], (fMultAdd(fMultDiv2(ci[11], pQmfReal[pReadIdx[11]]), cr[11],
610
0
                             pQmfImag[pReadIdx[11]]))));
611
612
  /* twiddle dee dee */
613
0
  fft[FFT_IDX_R(2)] =
614
0
      (fMult(p[12], (fMultSub(fMultDiv2(cr[0], pQmfReal[pReadIdx[0]]), ci[0],
615
0
                              pQmfImag[pReadIdx[0]]))) +
616
0
       fMult(p[8], (fMultSub(fMultDiv2(cr[4], pQmfReal[pReadIdx[4]]), ci[4],
617
0
                             pQmfImag[pReadIdx[4]]))) +
618
0
       fMult(p[4], (fMultSub(fMultDiv2(cr[8], pQmfReal[pReadIdx[8]]), ci[8],
619
0
                             pQmfImag[pReadIdx[8]]))) +
620
0
       fMult(p[0], (fMultSub(fMultDiv2(cr[12], pQmfReal[pReadIdx[12]]), ci[12],
621
0
                             pQmfImag[pReadIdx[12]]))));
622
0
  fft[FFT_IDX_I(2)] =
623
0
      (fMult(p[12], (fMultAdd(fMultDiv2(ci[0], pQmfReal[pReadIdx[0]]), cr[0],
624
0
                              pQmfImag[pReadIdx[0]]))) +
625
0
       fMult(p[8], (fMultAdd(fMultDiv2(ci[4], pQmfReal[pReadIdx[4]]), cr[4],
626
0
                             pQmfImag[pReadIdx[4]]))) +
627
0
       fMult(p[4], (fMultAdd(fMultDiv2(ci[8], pQmfReal[pReadIdx[8]]), cr[8],
628
0
                             pQmfImag[pReadIdx[8]]))) +
629
0
       fMult(p[0], (fMultAdd(fMultDiv2(ci[12], pQmfReal[pReadIdx[12]]), cr[12],
630
0
                             pQmfImag[pReadIdx[12]]))));
631
632
0
  fft[FFT_IDX_R(3)] =
633
0
      (fMult(p[11], (fMultSub(fMultDiv2(cr[1], pQmfReal[pReadIdx[1]]), ci[1],
634
0
                              pQmfImag[pReadIdx[1]]))) +
635
0
       fMult(p[7], (fMultSub(fMultDiv2(cr[5], pQmfReal[pReadIdx[5]]), ci[5],
636
0
                             pQmfImag[pReadIdx[5]]))) +
637
0
       fMult(p[3], (fMultSub(fMultDiv2(cr[9], pQmfReal[pReadIdx[9]]), ci[9],
638
0
                             pQmfImag[pReadIdx[9]]))));
639
0
  fft[FFT_IDX_I(3)] =
640
0
      (fMult(p[11], (fMultAdd(fMultDiv2(ci[1], pQmfReal[pReadIdx[1]]), cr[1],
641
0
                              pQmfImag[pReadIdx[1]]))) +
642
0
       fMult(p[7], (fMultAdd(fMultDiv2(ci[5], pQmfReal[pReadIdx[5]]), cr[5],
643
0
                             pQmfImag[pReadIdx[5]]))) +
644
0
       fMult(p[3], (fMultAdd(fMultDiv2(ci[9], pQmfReal[pReadIdx[9]]), cr[9],
645
0
                             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
0
  mHybridReal[0] = fft[FFT_IDX_R(0)] + fft[FFT_IDX_R(1)] + fft[FFT_IDX_R(2)] +
657
0
                   fft[FFT_IDX_R(3)];
658
0
  mHybridImag[0] = fft[FFT_IDX_I(0)] + fft[FFT_IDX_I(1)] + fft[FFT_IDX_I(2)] +
659
0
                   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
0
  mHybridReal[1] = fft[FFT_IDX_R(0)] + fft[FFT_IDX_I(1)] - fft[FFT_IDX_R(2)] -
666
0
                   fft[FFT_IDX_I(3)];
667
0
  mHybridImag[1] = fft[FFT_IDX_I(0)] - fft[FFT_IDX_R(1)] - fft[FFT_IDX_I(2)] +
668
0
                   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
0
  mHybridReal[2] = fft[FFT_IDX_R(0)] - fft[FFT_IDX_R(1)] + fft[FFT_IDX_R(2)] -
675
0
                   fft[FFT_IDX_R(3)];
676
0
  mHybridImag[2] = fft[FFT_IDX_I(0)] - fft[FFT_IDX_I(1)] + fft[FFT_IDX_I(2)] -
677
0
                   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
0
  mHybridReal[3] = fft[FFT_IDX_R(0)] - fft[FFT_IDX_I(1)] - fft[FFT_IDX_R(2)] +
684
0
                   fft[FFT_IDX_I(3)];
685
0
  mHybridImag[3] = fft[FFT_IDX_I(0)] + fft[FFT_IDX_R(1)] - fft[FFT_IDX_I(2)] -
686
0
                   fft[FFT_IDX_R(3)];
687
0
}
688
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
7.21M
                                  const INT invert) {
695
7.21M
  const FIXP_HTP *p = HybFilterCoef8;
696
7.21M
  INT k, sc;
697
698
7.21M
  FIXP_DBL mfft[16 + ALIGNMENT_DEFAULT];
699
7.21M
  FIXP_DBL *pfft = (FIXP_DBL *)ALIGN_PTR(mfft);
700
701
7.21M
  FIXP_DBL accu1, accu2, accu3, accu4;
702
703
  /* pre twiddeling */
704
7.21M
  pfft[FFT_IDX_R(0)] =
705
7.21M
      pQmfReal[pReadIdx[6]] >>
706
7.21M
      (3 + 1); /* fMultDiv2(p[0].v.re, pQmfReal[pReadIdx[6]]); */
707
7.21M
  pfft[FFT_IDX_I(0)] =
708
7.21M
      pQmfImag[pReadIdx[6]] >>
709
7.21M
      (3 + 1); /* fMultDiv2(p[0].v.re, pQmfImag[pReadIdx[6]]); */
710
711
7.21M
  cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[7]], pQmfImag[pReadIdx[7]],
712
7.21M
               p[1]);
713
7.21M
  pfft[FFT_IDX_R(1)] = accu1;
714
7.21M
  pfft[FFT_IDX_I(1)] = accu2;
715
716
7.21M
  cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[0]], pQmfImag[pReadIdx[0]],
717
7.21M
               p[2]);
718
7.21M
  cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[8]], pQmfImag[pReadIdx[8]],
719
7.21M
               p[3]);
720
7.21M
  pfft[FFT_IDX_R(2)] = accu1 + accu3;
721
7.21M
  pfft[FFT_IDX_I(2)] = accu2 + accu4;
722
723
7.21M
  cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[1]], pQmfImag[pReadIdx[1]],
724
7.21M
               p[4]);
725
7.21M
  cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[9]], pQmfImag[pReadIdx[9]],
726
7.21M
               p[5]);
727
7.21M
  pfft[FFT_IDX_R(3)] = accu1 + accu3;
728
7.21M
  pfft[FFT_IDX_I(3)] = accu2 + accu4;
729
730
7.21M
  pfft[FFT_IDX_R(4)] = fMultDiv2(pQmfImag[pReadIdx[10]], p[7].v.im) -
731
7.21M
                       fMultDiv2(pQmfImag[pReadIdx[2]], p[6].v.im);
732
7.21M
  pfft[FFT_IDX_I(4)] = fMultDiv2(pQmfReal[pReadIdx[2]], p[6].v.im) -
733
7.21M
                       fMultDiv2(pQmfReal[pReadIdx[10]], p[7].v.im);
734
735
7.21M
  cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[3]], pQmfImag[pReadIdx[3]],
736
7.21M
               p[8]);
737
7.21M
  cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[11]], pQmfImag[pReadIdx[11]],
738
7.21M
               p[9]);
739
7.21M
  pfft[FFT_IDX_R(5)] = accu1 + accu3;
740
7.21M
  pfft[FFT_IDX_I(5)] = accu2 + accu4;
741
742
7.21M
  cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[4]], pQmfImag[pReadIdx[4]],
743
7.21M
               p[10]);
744
7.21M
  cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[12]], pQmfImag[pReadIdx[12]],
745
7.21M
               p[11]);
746
7.21M
  pfft[FFT_IDX_R(6)] = accu1 + accu3;
747
7.21M
  pfft[FFT_IDX_I(6)] = accu2 + accu4;
748
749
7.21M
  cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[5]], pQmfImag[pReadIdx[5]],
750
7.21M
               p[12]);
751
7.21M
  pfft[FFT_IDX_R(7)] = accu1;
752
7.21M
  pfft[FFT_IDX_I(7)] = accu2;
753
754
  /* fft modulation */
755
7.21M
  fft_8(pfft);
756
7.21M
  sc = 1 + 2;
757
758
7.21M
  if (invert) {
759
7.21M
    mHybridReal[0] = pfft[FFT_IDX_R(7)] << sc;
760
7.21M
    mHybridImag[0] = pfft[FFT_IDX_I(7)] << sc;
761
7.21M
    mHybridReal[1] = pfft[FFT_IDX_R(0)] << sc;
762
7.21M
    mHybridImag[1] = pfft[FFT_IDX_I(0)] << sc;
763
764
7.21M
    mHybridReal[2] = pfft[FFT_IDX_R(6)] << sc;
765
7.21M
    mHybridImag[2] = pfft[FFT_IDX_I(6)] << sc;
766
7.21M
    mHybridReal[3] = pfft[FFT_IDX_R(1)] << sc;
767
7.21M
    mHybridImag[3] = pfft[FFT_IDX_I(1)] << sc;
768
769
7.21M
    mHybridReal[4] = SATURATE_LEFT_SHIFT(
770
7.21M
        (pfft[FFT_IDX_R(2)] + pfft[FFT_IDX_R(5)]), sc, DFRACT_BITS);
771
7.21M
    mHybridImag[4] = SATURATE_LEFT_SHIFT(
772
7.21M
        (pfft[FFT_IDX_I(2)] + pfft[FFT_IDX_I(5)]), sc, DFRACT_BITS);
773
774
7.21M
    mHybridReal[5] = SATURATE_LEFT_SHIFT(
775
7.21M
        (pfft[FFT_IDX_R(3)] + pfft[FFT_IDX_R(4)]), sc, DFRACT_BITS);
776
7.21M
    mHybridImag[5] = SATURATE_LEFT_SHIFT(
777
7.21M
        (pfft[FFT_IDX_I(3)] + pfft[FFT_IDX_I(4)]), sc, DFRACT_BITS);
778
7.21M
  } else {
779
0
    for (k = 0; k < 8; k++) {
780
0
      mHybridReal[k] = pfft[FFT_IDX_R(k)] << sc;
781
0
      mHybridImag[k] = pfft[FFT_IDX_I(k)] << sc;
782
0
    }
783
0
  }
784
7.21M
}
785
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
21.6M
                             const SCHAR hybridConfig) {
792
21.6M
  INT err = 0;
793
794
21.6M
  switch (hybridConfig) {
795
7.21M
    case 2:
796
14.4M
    case -2:
797
14.4M
      dualChannelFiltering(pQmfReal, pQmfImag, pReadIdx, mHybridReal,
798
14.4M
                           mHybridImag, (hybridConfig < 0) ? 1 : 0);
799
14.4M
      break;
800
0
    case 4:
801
0
    case -4:
802
0
      fourChannelFiltering(pQmfReal, pQmfImag, pReadIdx, mHybridReal,
803
0
                           mHybridImag, (hybridConfig < 0) ? 1 : 0);
804
0
      break;
805
0
    case 8:
806
7.21M
    case -8:
807
7.21M
      eightChannelFiltering(pQmfReal, pQmfImag, pReadIdx, mHybridReal,
808
7.21M
                            mHybridImag, (hybridConfig < 0) ? 1 : 0);
809
7.21M
      break;
810
0
    default:
811
0
      err = -1;
812
21.6M
  }
813
814
21.6M
  return err;
815
21.6M
}