Coverage Report

Created: 2025-10-10 07:00

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