Coverage Report

Created: 2026-05-30 06:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/aac/libFDK/src/FDK_hybrid.cpp
Line
Count
Source
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
66.2M
#define FFT_IDX_R(a) (2 * a)
109
66.2M
#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
43.9k
                          FIXP_DBL *const pHFmemory, const UINT HFmemorySize) {
207
43.9k
  INT err = 0;
208
209
  /* Save pointer to extern memory. */
210
43.9k
  hAnalysisHybFilter->pLFmemory = pLFmemory;
211
43.9k
  hAnalysisHybFilter->LFmemorySize = LFmemorySize;
212
213
43.9k
  hAnalysisHybFilter->pHFmemory = pHFmemory;
214
43.9k
  hAnalysisHybFilter->HFmemorySize = HFmemorySize;
215
216
43.9k
  return err;
217
43.9k
}
218
219
INT FDKhybridAnalysisInit(HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter,
220
                          const FDK_HYBRID_MODE mode, const INT qmfBands,
221
112k
                          const INT cplxBands, const INT initStatesFlag) {
222
112k
  int k;
223
112k
  INT err = 0;
224
112k
  FIXP_DBL *pMem = NULL;
225
112k
  HANDLE_FDK_HYBRID_SETUP setup = NULL;
226
227
112k
  switch (mode) {
228
112k
    case THREE_TO_TEN:
229
112k
      setup = &setup_3_10;
230
112k
      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
112k
  }
241
242
  /* Initialize handle. */
243
112k
  hAnalysisHybFilter->pSetup = setup;
244
112k
  if (initStatesFlag) {
245
14.0k
    hAnalysisHybFilter->bufferLFpos = setup->protoLen - 1;
246
14.0k
    hAnalysisHybFilter->bufferHFpos = 0;
247
14.0k
  }
248
112k
  hAnalysisHybFilter->nrBands = qmfBands;
249
112k
  hAnalysisHybFilter->cplxBands = cplxBands;
250
112k
  hAnalysisHybFilter->hfMode = 0;
251
252
  /* Check available memory. */
253
112k
  if (((2 * setup->nrQmfBands * setup->protoLen * sizeof(FIXP_DBL)) >
254
112k
       hAnalysisHybFilter->LFmemorySize)) {
255
0
    err = -2;
256
0
    goto bail;
257
0
  }
258
112k
  if (hAnalysisHybFilter->HFmemorySize != 0) {
259
108k
    if (((setup->filterDelay *
260
108k
          ((qmfBands - setup->nrQmfBands) + (cplxBands - setup->nrQmfBands)) *
261
108k
          sizeof(FIXP_DBL)) > hAnalysisHybFilter->HFmemorySize)) {
262
0
      err = -3;
263
0
      goto bail;
264
0
    }
265
108k
  }
266
267
  /* Distribute LF memory. */
268
112k
  pMem = hAnalysisHybFilter->pLFmemory;
269
450k
  for (k = 0; k < setup->nrQmfBands; k++) {
270
338k
    hAnalysisHybFilter->bufferLFReal[k] = pMem;
271
338k
    pMem += setup->protoLen;
272
338k
    hAnalysisHybFilter->bufferLFImag[k] = pMem;
273
338k
    pMem += setup->protoLen;
274
338k
  }
275
276
  /* Distribute HF memory. */
277
112k
  if (hAnalysisHybFilter->HFmemorySize != 0) {
278
108k
    pMem = hAnalysisHybFilter->pHFmemory;
279
762k
    for (k = 0; k < setup->filterDelay; k++) {
280
653k
      hAnalysisHybFilter->bufferHFReal[k] = pMem;
281
653k
      pMem += (qmfBands - setup->nrQmfBands);
282
653k
      hAnalysisHybFilter->bufferHFImag[k] = pMem;
283
653k
      pMem += (cplxBands - setup->nrQmfBands);
284
653k
    }
285
108k
  }
286
287
112k
  if (initStatesFlag) {
288
    /* Clear LF buffer */
289
56.1k
    for (k = 0; k < setup->nrQmfBands; k++) {
290
42.0k
      FDKmemclear(hAnalysisHybFilter->bufferLFReal[k],
291
42.0k
                  setup->protoLen * sizeof(FIXP_DBL));
292
42.0k
      FDKmemclear(hAnalysisHybFilter->bufferLFImag[k],
293
42.0k
                  setup->protoLen * sizeof(FIXP_DBL));
294
42.0k
    }
295
296
14.0k
    if (hAnalysisHybFilter->HFmemorySize != 0) {
297
10.2k
      if (qmfBands > setup->nrQmfBands) {
298
        /* Clear HF buffer */
299
71.8k
        for (k = 0; k < setup->filterDelay; k++) {
300
61.5k
          FDKmemclear(hAnalysisHybFilter->bufferHFReal[k],
301
61.5k
                      (qmfBands - setup->nrQmfBands) * sizeof(FIXP_DBL));
302
61.5k
          FDKmemclear(hAnalysisHybFilter->bufferHFImag[k],
303
61.5k
                      (cplxBands - setup->nrQmfBands) * sizeof(FIXP_DBL));
304
61.5k
        }
305
10.2k
      }
306
10.2k
    }
307
14.0k
  }
308
309
112k
bail:
310
112k
  return err;
311
112k
}
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
5.52M
                           FIXP_DBL *const pHybridImag) {
350
5.52M
  int k, hybOffset = 0;
351
5.52M
  INT err = 0;
352
5.52M
  const int nrQmfBandsLF =
353
5.52M
      hAnalysisHybFilter->pSetup
354
5.52M
          ->nrQmfBands; /* number of QMF bands to be converted to hybrid */
355
356
5.52M
  const int writIndex = hAnalysisHybFilter->bufferLFpos;
357
5.52M
  int readIndex = hAnalysisHybFilter->bufferLFpos;
358
359
5.52M
  if (++readIndex >= hAnalysisHybFilter->pSetup->protoLen) readIndex = 0;
360
5.52M
  const INT *pBufferLFreadIdx =
361
5.52M
      &hAnalysisHybFilter->pSetup->pReadIdxTable[readIndex];
362
363
  /*
364
   * LF buffer.
365
   */
366
22.0M
  for (k = 0; k < nrQmfBandsLF; k++) {
367
    /* New input sample. */
368
16.5M
    hAnalysisHybFilter->bufferLFReal[k][writIndex] = pQmfReal[k];
369
16.5M
    hAnalysisHybFilter->bufferLFImag[k][writIndex] = pQmfImag[k];
370
371
    /* Perform hybrid filtering. */
372
16.5M
    err |=
373
16.5M
        kChannelFiltering(hAnalysisHybFilter->bufferLFReal[k],
374
16.5M
                          hAnalysisHybFilter->bufferLFImag[k], pBufferLFreadIdx,
375
16.5M
                          pHybridReal + hybOffset, pHybridImag + hybOffset,
376
16.5M
                          hAnalysisHybFilter->pSetup->kHybrid[k]);
377
378
16.5M
    hybOffset += hAnalysisHybFilter->pSetup->nHybBands[k];
379
16.5M
  }
380
381
5.52M
  hAnalysisHybFilter->bufferLFpos =
382
5.52M
      readIndex; /* Index where to write next input sample. */
383
384
5.52M
  if (hAnalysisHybFilter->nrBands > nrQmfBandsLF) {
385
    /*
386
     * HF buffer.
387
     */
388
5.41M
    if (hAnalysisHybFilter->hfMode != 0) {
389
      /* HF delay compensation was applied outside. */
390
3.73M
      FDKmemcpy(
391
3.73M
          pHybridReal + hybOffset, &pQmfReal[nrQmfBandsLF],
392
3.73M
          (hAnalysisHybFilter->nrBands - nrQmfBandsLF) * sizeof(FIXP_DBL));
393
3.73M
      FDKmemcpy(
394
3.73M
          pHybridImag + hybOffset, &pQmfImag[nrQmfBandsLF],
395
3.73M
          (hAnalysisHybFilter->cplxBands - nrQmfBandsLF) * sizeof(FIXP_DBL));
396
3.73M
    } else {
397
1.67M
      FDK_ASSERT(hAnalysisHybFilter->HFmemorySize != 0);
398
      /* HF delay compensation, filterlength/2. */
399
1.67M
      FDKmemcpy(
400
1.67M
          pHybridReal + hybOffset,
401
1.67M
          hAnalysisHybFilter->bufferHFReal[hAnalysisHybFilter->bufferHFpos],
402
1.67M
          (hAnalysisHybFilter->nrBands - nrQmfBandsLF) * sizeof(FIXP_DBL));
403
1.67M
      FDKmemcpy(
404
1.67M
          pHybridImag + hybOffset,
405
1.67M
          hAnalysisHybFilter->bufferHFImag[hAnalysisHybFilter->bufferHFpos],
406
1.67M
          (hAnalysisHybFilter->cplxBands - nrQmfBandsLF) * sizeof(FIXP_DBL));
407
408
1.67M
      FDKmemcpy(
409
1.67M
          hAnalysisHybFilter->bufferHFReal[hAnalysisHybFilter->bufferHFpos],
410
1.67M
          &pQmfReal[nrQmfBandsLF],
411
1.67M
          (hAnalysisHybFilter->nrBands - nrQmfBandsLF) * sizeof(FIXP_DBL));
412
1.67M
      FDKmemcpy(
413
1.67M
          hAnalysisHybFilter->bufferHFImag[hAnalysisHybFilter->bufferHFpos],
414
1.67M
          &pQmfImag[nrQmfBandsLF],
415
1.67M
          (hAnalysisHybFilter->cplxBands - nrQmfBandsLF) * sizeof(FIXP_DBL));
416
417
1.67M
      if (++hAnalysisHybFilter->bufferHFpos >=
418
1.67M
          hAnalysisHybFilter->pSetup->filterDelay)
419
277k
        hAnalysisHybFilter->bufferHFpos = 0;
420
1.67M
    }
421
5.41M
  } /* process HF part*/
422
423
5.52M
  return err;
424
5.52M
}
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
116k
                           const INT cplxBands) {
442
116k
  INT err = 0;
443
116k
  HANDLE_FDK_HYBRID_SETUP setup = NULL;
444
445
116k
  switch (mode) {
446
116k
    case THREE_TO_TEN:
447
116k
      setup = &setup_3_10;
448
116k
      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
116k
  }
459
460
116k
  hSynthesisHybFilter->pSetup = setup;
461
116k
  hSynthesisHybFilter->nrBands = qmfBands;
462
116k
  hSynthesisHybFilter->cplxBands = cplxBands;
463
464
116k
bail:
465
116k
  return err;
466
116k
}
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
9.23M
                             FIXP_DBL *const pQmfImag) {
473
9.23M
  int k, n, hybOffset = 0;
474
9.23M
  const INT nrQmfBandsLF = hSynthesisHybFilter->pSetup->nrQmfBands;
475
476
  /*
477
   * LF buffer.
478
   */
479
36.9M
  for (k = 0; k < nrQmfBandsLF; k++) {
480
27.6M
    const int nHybBands = hSynthesisHybFilter->pSetup->nHybBands[k];
481
27.6M
    const int scale = hSynthesisHybFilter->pSetup->synHybScale[k];
482
483
27.6M
    FIXP_DBL accu1 = FL2FXCONST_DBL(0.f);
484
27.6M
    FIXP_DBL accu2 = FL2FXCONST_DBL(0.f);
485
486
    /* Perform hybrid filtering. */
487
120M
    for (n = 0; n < nHybBands; n++) {
488
92.3M
      accu1 += pHybridReal[hybOffset + n] >> scale;
489
92.3M
      accu2 += pHybridImag[hybOffset + n] >> scale;
490
92.3M
    }
491
27.6M
    pQmfReal[k] = SATURATE_LEFT_SHIFT(accu1, scale, DFRACT_BITS);
492
27.6M
    pQmfImag[k] = SATURATE_LEFT_SHIFT(accu2, scale, DFRACT_BITS);
493
494
27.6M
    hybOffset += nHybBands;
495
27.6M
  }
496
497
9.23M
  if (hSynthesisHybFilter->nrBands > nrQmfBandsLF) {
498
    /*
499
     * HF buffer.
500
     */
501
9.23M
    FDKmemcpy(&pQmfReal[nrQmfBandsLF], &pHybridReal[hybOffset],
502
9.23M
              (hSynthesisHybFilter->nrBands - nrQmfBandsLF) * sizeof(FIXP_DBL));
503
9.23M
    FDKmemcpy(
504
9.23M
        &pQmfImag[nrQmfBandsLF], &pHybridImag[hybOffset],
505
9.23M
        (hSynthesisHybFilter->cplxBands - nrQmfBandsLF) * sizeof(FIXP_DBL));
506
9.23M
  }
507
508
9.23M
  return;
509
9.23M
}
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
11.0M
                                 const INT invert) {
517
11.0M
  FIXP_DBL r1, r6;
518
11.0M
  FIXP_DBL i1, i6;
519
520
11.0M
  const FIXP_HTB f0 = HybFilterCoef2[0]; /* corresponds to p1 and p11 */
521
11.0M
  const FIXP_HTB f1 = HybFilterCoef2[1]; /* corresponds to p3 and p9  */
522
11.0M
  const FIXP_HTB f2 = HybFilterCoef2[2]; /* corresponds to p5 and p7  */
523
524
  /* symmetric filter coefficients */
525
11.0M
  r1 = fMultDiv2(f0, pQmfReal[pReadIdx[1]]) +
526
11.0M
       fMultDiv2(f0, pQmfReal[pReadIdx[11]]);
527
11.0M
  i1 = fMultDiv2(f0, pQmfImag[pReadIdx[1]]) +
528
11.0M
       fMultDiv2(f0, pQmfImag[pReadIdx[11]]);
529
11.0M
  r1 += fMultDiv2(f1, pQmfReal[pReadIdx[3]]) +
530
11.0M
        fMultDiv2(f1, pQmfReal[pReadIdx[9]]);
531
11.0M
  i1 += fMultDiv2(f1, pQmfImag[pReadIdx[3]]) +
532
11.0M
        fMultDiv2(f1, pQmfImag[pReadIdx[9]]);
533
11.0M
  r1 += fMultDiv2(f2, pQmfReal[pReadIdx[5]]) +
534
11.0M
        fMultDiv2(f2, pQmfReal[pReadIdx[7]]);
535
11.0M
  i1 += fMultDiv2(f2, pQmfImag[pReadIdx[5]]) +
536
11.0M
        fMultDiv2(f2, pQmfImag[pReadIdx[7]]);
537
538
11.0M
  r6 = pQmfReal[pReadIdx[6]] >> 2;
539
11.0M
  i6 = pQmfImag[pReadIdx[6]] >> 2;
540
541
11.0M
  FDK_ASSERT((invert == 0) || (invert == 1));
542
11.0M
  mHybridReal[0 + invert] = SATURATE_LEFT_SHIFT((r6 + r1), 1, DFRACT_BITS);
543
11.0M
  mHybridImag[0 + invert] = SATURATE_LEFT_SHIFT((i6 + i1), 1, DFRACT_BITS);
544
545
11.0M
  mHybridReal[1 - invert] = SATURATE_LEFT_SHIFT((r6 - r1), 1, DFRACT_BITS);
546
11.0M
  mHybridImag[1 - invert] = SATURATE_LEFT_SHIFT((i6 - i1), 1, DFRACT_BITS);
547
11.0M
}
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
5.52M
                                  const INT invert) {
695
5.52M
  const FIXP_HTP *p = HybFilterCoef8;
696
5.52M
  INT k, sc;
697
698
5.52M
  FIXP_DBL mfft[16 + ALIGNMENT_DEFAULT];
699
5.52M
  FIXP_DBL *pfft = (FIXP_DBL *)ALIGN_PTR(mfft);
700
701
5.52M
  FIXP_DBL accu1, accu2, accu3, accu4;
702
703
  /* pre twiddeling */
704
5.52M
  pfft[FFT_IDX_R(0)] =
705
5.52M
      pQmfReal[pReadIdx[6]] >>
706
5.52M
      (3 + 1); /* fMultDiv2(p[0].v.re, pQmfReal[pReadIdx[6]]); */
707
5.52M
  pfft[FFT_IDX_I(0)] =
708
5.52M
      pQmfImag[pReadIdx[6]] >>
709
5.52M
      (3 + 1); /* fMultDiv2(p[0].v.re, pQmfImag[pReadIdx[6]]); */
710
711
5.52M
  cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[7]], pQmfImag[pReadIdx[7]],
712
5.52M
               p[1]);
713
5.52M
  pfft[FFT_IDX_R(1)] = accu1;
714
5.52M
  pfft[FFT_IDX_I(1)] = accu2;
715
716
5.52M
  cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[0]], pQmfImag[pReadIdx[0]],
717
5.52M
               p[2]);
718
5.52M
  cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[8]], pQmfImag[pReadIdx[8]],
719
5.52M
               p[3]);
720
5.52M
  pfft[FFT_IDX_R(2)] = accu1 + accu3;
721
5.52M
  pfft[FFT_IDX_I(2)] = accu2 + accu4;
722
723
5.52M
  cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[1]], pQmfImag[pReadIdx[1]],
724
5.52M
               p[4]);
725
5.52M
  cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[9]], pQmfImag[pReadIdx[9]],
726
5.52M
               p[5]);
727
5.52M
  pfft[FFT_IDX_R(3)] = accu1 + accu3;
728
5.52M
  pfft[FFT_IDX_I(3)] = accu2 + accu4;
729
730
5.52M
  pfft[FFT_IDX_R(4)] = fMultDiv2(pQmfImag[pReadIdx[10]], p[7].v.im) -
731
5.52M
                       fMultDiv2(pQmfImag[pReadIdx[2]], p[6].v.im);
732
5.52M
  pfft[FFT_IDX_I(4)] = fMultDiv2(pQmfReal[pReadIdx[2]], p[6].v.im) -
733
5.52M
                       fMultDiv2(pQmfReal[pReadIdx[10]], p[7].v.im);
734
735
5.52M
  cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[3]], pQmfImag[pReadIdx[3]],
736
5.52M
               p[8]);
737
5.52M
  cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[11]], pQmfImag[pReadIdx[11]],
738
5.52M
               p[9]);
739
5.52M
  pfft[FFT_IDX_R(5)] = accu1 + accu3;
740
5.52M
  pfft[FFT_IDX_I(5)] = accu2 + accu4;
741
742
5.52M
  cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[4]], pQmfImag[pReadIdx[4]],
743
5.52M
               p[10]);
744
5.52M
  cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[12]], pQmfImag[pReadIdx[12]],
745
5.52M
               p[11]);
746
5.52M
  pfft[FFT_IDX_R(6)] = accu1 + accu3;
747
5.52M
  pfft[FFT_IDX_I(6)] = accu2 + accu4;
748
749
5.52M
  cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[5]], pQmfImag[pReadIdx[5]],
750
5.52M
               p[12]);
751
5.52M
  pfft[FFT_IDX_R(7)] = accu1;
752
5.52M
  pfft[FFT_IDX_I(7)] = accu2;
753
754
  /* fft modulation */
755
5.52M
  fft_8(pfft);
756
5.52M
  sc = 1 + 2;
757
758
5.52M
  if (invert) {
759
5.52M
    mHybridReal[0] = pfft[FFT_IDX_R(7)] << sc;
760
5.52M
    mHybridImag[0] = pfft[FFT_IDX_I(7)] << sc;
761
5.52M
    mHybridReal[1] = pfft[FFT_IDX_R(0)] << sc;
762
5.52M
    mHybridImag[1] = pfft[FFT_IDX_I(0)] << sc;
763
764
5.52M
    mHybridReal[2] = pfft[FFT_IDX_R(6)] << sc;
765
5.52M
    mHybridImag[2] = pfft[FFT_IDX_I(6)] << sc;
766
5.52M
    mHybridReal[3] = pfft[FFT_IDX_R(1)] << sc;
767
5.52M
    mHybridImag[3] = pfft[FFT_IDX_I(1)] << sc;
768
769
5.52M
    mHybridReal[4] = SATURATE_LEFT_SHIFT(
770
5.52M
        (pfft[FFT_IDX_R(2)] + pfft[FFT_IDX_R(5)]), sc, DFRACT_BITS);
771
5.52M
    mHybridImag[4] = SATURATE_LEFT_SHIFT(
772
5.52M
        (pfft[FFT_IDX_I(2)] + pfft[FFT_IDX_I(5)]), sc, DFRACT_BITS);
773
774
5.52M
    mHybridReal[5] = SATURATE_LEFT_SHIFT(
775
5.52M
        (pfft[FFT_IDX_R(3)] + pfft[FFT_IDX_R(4)]), sc, DFRACT_BITS);
776
5.52M
    mHybridImag[5] = SATURATE_LEFT_SHIFT(
777
5.52M
        (pfft[FFT_IDX_I(3)] + pfft[FFT_IDX_I(4)]), sc, DFRACT_BITS);
778
5.52M
  } 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
5.52M
}
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
16.5M
                             const SCHAR hybridConfig) {
792
16.5M
  INT err = 0;
793
794
16.5M
  switch (hybridConfig) {
795
5.52M
    case 2:
796
11.0M
    case -2:
797
11.0M
      dualChannelFiltering(pQmfReal, pQmfImag, pReadIdx, mHybridReal,
798
11.0M
                           mHybridImag, (hybridConfig < 0) ? 1 : 0);
799
11.0M
      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
5.52M
    case -8:
807
5.52M
      eightChannelFiltering(pQmfReal, pQmfImag, pReadIdx, mHybridReal,
808
5.52M
                            mHybridImag, (hybridConfig < 0) ? 1 : 0);
809
5.52M
      break;
810
0
    default:
811
0
      err = -1;
812
16.5M
  }
813
814
16.5M
  return err;
815
16.5M
}