Coverage Report

Created: 2025-10-13 06:39

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