1/* -----------------------------------------------------------------------------
2Software License for The Fraunhofer FDK AAC Codec Library for Android
3
4© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
5Forschung e.V. All rights reserved.
6
7 1.    INTRODUCTION
8The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software
9that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding
10scheme for digital audio. This FDK AAC Codec software is intended to be used on
11a wide variety of Android devices.
12
13AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient
14general perceptual audio codecs. AAC-ELD is considered the best-performing
15full-bandwidth communications codec by independent studies and is widely
16deployed. AAC has been standardized by ISO and IEC as part of the MPEG
17specifications.
18
19Patent licenses for necessary patent claims for the FDK AAC Codec (including
20those of Fraunhofer) may be obtained through Via Licensing
21(www.vialicensing.com) or through the respective patent owners individually for
22the purpose of encoding or decoding bit streams in products that are compliant
23with the ISO/IEC MPEG audio standards. Please note that most manufacturers of
24Android devices already license these patent claims through Via Licensing or
25directly from the patent owners, and therefore FDK AAC Codec software may
26already be covered under those patent licenses when it is used for those
27licensed purposes only.
28
29Commercially-licensed AAC software libraries, including floating-point versions
30with enhanced sound quality, are also available from Fraunhofer. Users are
31encouraged to check the Fraunhofer website for additional applications
32information and documentation.
33
342.    COPYRIGHT LICENSE
35
36Redistribution and use in source and binary forms, with or without modification,
37are permitted without payment of copyright license fees provided that you
38satisfy the following conditions:
39
40You must retain the complete text of this software license in redistributions of
41the FDK AAC Codec or your modifications thereto in source code form.
42
43You must retain the complete text of this software license in the documentation
44and/or other materials provided with redistributions of the FDK AAC Codec or
45your modifications thereto in binary form. You must make available free of
46charge copies of the complete source code of the FDK AAC Codec and your
47modifications thereto to recipients of copies in binary form.
48
49The name of Fraunhofer may not be used to endorse or promote products derived
50from this library without prior written permission.
51
52You may not charge copyright license fees for anyone to use, copy or distribute
53the FDK AAC Codec software or your modifications thereto.
54
55Your modified versions of the FDK AAC Codec must carry prominent notices stating
56that you changed the software and the date of any change. For modified versions
57of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android"
58must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK
59AAC Codec Library for Android."
60
613.    NO PATENT LICENSE
62
63NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without
64limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE.
65Fraunhofer provides no warranty of patent non-infringement with respect to this
66software.
67
68You may use this FDK AAC Codec software or modifications thereto only for
69purposes that are authorized by appropriate patent licenses.
70
714.    DISCLAIMER
72
73This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright
74holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
75including but not limited to the implied warranties of merchantability and
76fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
77CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary,
78or consequential damages, including but not limited to procurement of substitute
79goods or services; loss of use, data, or profits, or business interruption,
80however caused and on any theory of liability, whether in contract, strict
81liability, or tort (including negligence), arising in any way out of the use of
82this software, even if advised of the possibility of such damage.
83
845.    CONTACT INFORMATION
85
86Fraunhofer Institute for Integrated Circuits IIS
87Attention: Audio and Multimedia Departments - FDK AAC LL
88Am Wolfsmantel 33
8991058 Erlangen, Germany
90
91www.iis.fraunhofer.de/amm
92amm-info@iis.fraunhofer.de
93----------------------------------------------------------------------------- */
94
95/******************* Library for basic calculation routines ********************
96
97   Author(s):   Markus Lohwasser, Josef Hoepfl, Manuel Jander
98
99   Description: QMF filterbank
100
101*******************************************************************************/
102
103/*!
104  \file
105  \brief  Complex qmf analysis/synthesis
106  This module contains the qmf filterbank for analysis [
107  cplxAnalysisQmfFiltering() ] and synthesis [ cplxSynthesisQmfFiltering() ]. It
108  is a polyphase implementation of a complex exponential modulated filter bank.
109  The analysis part usually runs at half the sample rate than the synthesis
110  part. (So called "dual-rate" mode.)
111
112  The coefficients of the prototype filter are specified in #qmf_pfilt640 (in
113  sbr_rom.cpp). Thus only a 64 channel version (32 on the analysis side) with a
114  640 tap prototype filter are used.
115
116  \anchor PolyphaseFiltering <h2>About polyphase filtering</h2>
117  The polyphase implementation of a filterbank requires filtering at the input
118  and output. This is implemented as part of cplxAnalysisQmfFiltering() and
119  cplxSynthesisQmfFiltering(). The implementation requires the filter
120  coefficients in a specific structure as described in #sbr_qmf_64_640_qmf (in
121  sbr_rom.cpp).
122
123  This module comprises the computationally most expensive functions of the SBR
124  decoder. The accuracy of computations is also important and has a direct
125  impact on the overall sound quality. Therefore a special test program is
126  available which can be used to only test the filterbank: main_audio.cpp
127
128  This modules also uses scaling of data to provide better SNR on fixed-point
129  processors. See #QMF_SCALE_FACTOR (in sbr_scale.h) for details. An interesting
130  note: The function getScalefactor() can constitute a significant amount of
131  computational complexity - very much depending on the bitrate. Since it is a
132  rather small function, effective assembler optimization might be possible.
133
134*/
135
136#include "qmf.h"
137
138#include "FDK_trigFcts.h"
139#include "fixpoint_math.h"
140#include "dct.h"
141
142#define QSSCALE (0)
143#define FX_DBL2FX_QSS(x) (x)
144#define FX_QSS2FX_DBL(x) (x)
145
146/* moved to qmf_pcm.h: -> qmfSynPrototypeFirSlot */
147/* moved to qmf_pcm.h: -> qmfSynPrototypeFirSlot_NonSymmetric */
148/* moved to qmf_pcm.h: -> qmfSynthesisFilteringSlot */
149
150#ifndef FUNCTION_qmfAnaPrototypeFirSlot
151/*!
152  \brief Perform Analysis Prototype Filtering on a single slot of input data.
153*/
154static void qmfAnaPrototypeFirSlot(
155    FIXP_DBL *analysisBuffer,
156    INT no_channels, /*!< Number channels of analysis filter */
157    const FIXP_PFT *p_filter, INT p_stride, /*!< Stride of analysis filter    */
158    FIXP_QAS *RESTRICT pFilterStates) {
159  INT k;
160
161  FIXP_DBL accu;
162  const FIXP_PFT *RESTRICT p_flt = p_filter;
163  FIXP_DBL *RESTRICT pData_0 = analysisBuffer + 2 * no_channels - 1;
164  FIXP_DBL *RESTRICT pData_1 = analysisBuffer;
165
166  FIXP_QAS *RESTRICT sta_0 = (FIXP_QAS *)pFilterStates;
167  FIXP_QAS *RESTRICT sta_1 =
168      (FIXP_QAS *)pFilterStates + (2 * QMF_NO_POLY * no_channels) - 1;
169  INT pfltStep = QMF_NO_POLY * (p_stride);
170  INT staStep1 = no_channels << 1;
171  INT staStep2 = (no_channels << 3) - 1; /* Rewind one less */
172
173  /* FIR filters 127..64 0..63 */
174  for (k = 0; k < no_channels; k++) {
175    accu = fMultDiv2(p_flt[0], *sta_1);
176    sta_1 -= staStep1;
177    accu += fMultDiv2(p_flt[1], *sta_1);
178    sta_1 -= staStep1;
179    accu += fMultDiv2(p_flt[2], *sta_1);
180    sta_1 -= staStep1;
181    accu += fMultDiv2(p_flt[3], *sta_1);
182    sta_1 -= staStep1;
183    accu += fMultDiv2(p_flt[4], *sta_1);
184    *pData_1++ = (accu << 1);
185    sta_1 += staStep2;
186
187    p_flt += pfltStep;
188    accu = fMultDiv2(p_flt[0], *sta_0);
189    sta_0 += staStep1;
190    accu += fMultDiv2(p_flt[1], *sta_0);
191    sta_0 += staStep1;
192    accu += fMultDiv2(p_flt[2], *sta_0);
193    sta_0 += staStep1;
194    accu += fMultDiv2(p_flt[3], *sta_0);
195    sta_0 += staStep1;
196    accu += fMultDiv2(p_flt[4], *sta_0);
197    *pData_0-- = (accu << 1);
198    sta_0 -= staStep2;
199  }
200}
201#endif /* !defined(FUNCTION_qmfAnaPrototypeFirSlot) */
202
203#ifndef FUNCTION_qmfAnaPrototypeFirSlot_NonSymmetric
204/*!
205  \brief Perform Analysis Prototype Filtering on a single slot of input data.
206*/
207static void qmfAnaPrototypeFirSlot_NonSymmetric(
208    FIXP_DBL *analysisBuffer,
209    int no_channels, /*!< Number channels of analysis filter */
210    const FIXP_PFT *p_filter, int p_stride, /*!< Stride of analysis filter    */
211    FIXP_QAS *RESTRICT pFilterStates) {
212  const FIXP_PFT *RESTRICT p_flt = p_filter;
213  int p, k;
214
215  for (k = 0; k < 2 * no_channels; k++) {
216    FIXP_DBL accu = (FIXP_DBL)0;
217
218    p_flt += QMF_NO_POLY * (p_stride - 1);
219
220    /*
221      Perform FIR-Filter
222    */
223    for (p = 0; p < QMF_NO_POLY; p++) {
224      accu += fMultDiv2(*p_flt++, pFilterStates[2 * no_channels * p]);
225    }
226    analysisBuffer[2 * no_channels - 1 - k] = (accu << 1);
227    pFilterStates++;
228  }
229}
230#endif /* FUNCTION_qmfAnaPrototypeFirSlot_NonSymmetric */
231
232/*!
233 *
234 * \brief Perform real-valued forward modulation of the time domain
235 *        data of timeIn and stores the real part of the subband
236 *        samples in rSubband
237 *
238 */
239static void qmfForwardModulationLP_even(
240    HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank  */
241    FIXP_DBL *timeIn,              /*!< Time Signal */
242    FIXP_DBL *rSubband)            /*!< Real Output */
243{
244  int i;
245  int L = anaQmf->no_channels;
246  int M = L >> 1;
247  int scale;
248  FIXP_DBL accu;
249
250  const FIXP_DBL *timeInTmp1 = (FIXP_DBL *)&timeIn[3 * M];
251  const FIXP_DBL *timeInTmp2 = timeInTmp1;
252  FIXP_DBL *rSubbandTmp = rSubband;
253
254  rSubband[0] = timeIn[3 * M] >> 1;
255
256  for (i = M - 1; i != 0; i--) {
257    accu = ((*--timeInTmp1) >> 1) + ((*++timeInTmp2) >> 1);
258    *++rSubbandTmp = accu;
259  }
260
261  timeInTmp1 = &timeIn[2 * M];
262  timeInTmp2 = &timeIn[0];
263  rSubbandTmp = &rSubband[M];
264
265  for (i = L - M; i != 0; i--) {
266    accu = ((*timeInTmp1--) >> 1) - ((*timeInTmp2++) >> 1);
267    *rSubbandTmp++ = accu;
268  }
269
270  dct_III(rSubband, timeIn, L, &scale);
271}
272
273#if !defined(FUNCTION_qmfForwardModulationLP_odd)
274static void qmfForwardModulationLP_odd(
275    HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank  */
276    const FIXP_DBL *timeIn,        /*!< Time Signal */
277    FIXP_DBL *rSubband)            /*!< Real Output */
278{
279  int i;
280  int L = anaQmf->no_channels;
281  int M = L >> 1;
282  int shift = (anaQmf->no_channels >> 6) + 1;
283
284  for (i = 0; i < M; i++) {
285    rSubband[M + i] = (timeIn[L - 1 - i] >> 1) - (timeIn[i] >> shift);
286    rSubband[M - 1 - i] =
287        (timeIn[L + i] >> 1) + (timeIn[2 * L - 1 - i] >> shift);
288  }
289
290  dct_IV(rSubband, L, &shift);
291}
292#endif /* !defined(FUNCTION_qmfForwardModulationLP_odd) */
293
294/*!
295 *
296 * \brief Perform complex-valued forward modulation of the time domain
297 *        data of timeIn and stores the real part of the subband
298 *        samples in rSubband, and the imaginary part in iSubband
299 *
300 *
301 */
302#if !defined(FUNCTION_qmfForwardModulationHQ)
303static void qmfForwardModulationHQ(
304    HANDLE_QMF_FILTER_BANK anaQmf,   /*!< Handle of Qmf Analysis Bank  */
305    const FIXP_DBL *RESTRICT timeIn, /*!< Time Signal */
306    FIXP_DBL *RESTRICT rSubband,     /*!< Real Output */
307    FIXP_DBL *RESTRICT iSubband      /*!< Imaginary Output */
308) {
309  int i;
310  int L = anaQmf->no_channels;
311  int L2 = L << 1;
312  int shift = 0;
313
314  /* Time advance by one sample, which is equivalent to the complex
315     rotation at the end of the analysis. Works only for STD mode. */
316  if ((L == 64) && !(anaQmf->flags & (QMF_FLAG_CLDFB | QMF_FLAG_MPSLDFB))) {
317    FIXP_DBL x, y;
318
319    /*rSubband[0] = u[1] + u[0]*/
320    /*iSubband[0] = u[1] - u[0]*/
321    x = timeIn[1] >> 1;
322    y = timeIn[0];
323    rSubband[0] = x + (y >> 1);
324    iSubband[0] = x - (y >> 1);
325
326    /*rSubband[n] = u[n+1] - u[2M-n], n=1,...,M-1*/
327    /*iSubband[n] = u[n+1] + u[2M-n], n=1,...,M-1*/
328    for (i = 1; i < L; i++) {
329      x = timeIn[i + 1] >> 1; /*u[n+1]  */
330      y = timeIn[L2 - i];     /*u[2M-n] */
331      rSubband[i] = x - (y >> 1);
332      iSubband[i] = x + (y >> 1);
333    }
334  } else {
335    for (i = 0; i < L; i += 2) {
336      FIXP_DBL x0, x1, y0, y1;
337
338      x0 = timeIn[i + 0] >> 1;
339      x1 = timeIn[i + 1] >> 1;
340      y0 = timeIn[L2 - 1 - i];
341      y1 = timeIn[L2 - 2 - i];
342
343      rSubband[i + 0] = x0 - (y0 >> 1);
344      rSubband[i + 1] = x1 - (y1 >> 1);
345      iSubband[i + 0] = x0 + (y0 >> 1);
346      iSubband[i + 1] = x1 + (y1 >> 1);
347    }
348  }
349
350  dct_IV(rSubband, L, &shift);
351  dst_IV(iSubband, L, &shift);
352
353  /* Do the complex rotation except for the case of 64 bands (in STD mode). */
354  if ((L != 64) || (anaQmf->flags & (QMF_FLAG_CLDFB | QMF_FLAG_MPSLDFB))) {
355    if (anaQmf->flags & QMF_FLAG_MPSLDFB_OPTIMIZE_MODULATION) {
356      FIXP_DBL iBand;
357      for (i = 0; i < fMin(anaQmf->lsb, L); i += 2) {
358        iBand = rSubband[i];
359        rSubband[i] = -iSubband[i];
360        iSubband[i] = iBand;
361
362        iBand = -rSubband[i + 1];
363        rSubband[i + 1] = iSubband[i + 1];
364        iSubband[i + 1] = iBand;
365      }
366    } else {
367      const FIXP_QTW *sbr_t_cos;
368      const FIXP_QTW *sbr_t_sin;
369      const int len = L; /* was len = fMin(anaQmf->lsb, L) but in case of USAC
370                            the signal above lsb is actually needed in some
371                            cases (HBE?) */
372      sbr_t_cos = anaQmf->t_cos;
373      sbr_t_sin = anaQmf->t_sin;
374
375      for (i = 0; i < len; i++) {
376        cplxMult(&iSubband[i], &rSubband[i], iSubband[i], rSubband[i],
377                 sbr_t_cos[i], sbr_t_sin[i]);
378      }
379    }
380  }
381}
382#endif /* FUNCTION_qmfForwardModulationHQ */
383
384/*
385 * \brief Perform one QMF slot analysis of the time domain data of timeIn
386 *        with specified stride and stores the real part of the subband
387 *        samples in rSubband, and the imaginary part in iSubband
388 *
389 *        Note: anaQmf->lsb can be greater than anaQmf->no_channels in case
390 *        of implicit resampling (USAC with reduced 3/4 core frame length).
391 */
392#if (SAMPLE_BITS != DFRACT_BITS) && (QAS_BITS == DFRACT_BITS)
393void qmfAnalysisFilteringSlot(
394    HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Synthesis Bank  */
395    FIXP_DBL *qmfReal,             /*!< Low and High band, real */
396    FIXP_DBL *qmfImag,             /*!< Low and High band, imag */
397    const LONG *RESTRICT timeIn,   /*!< Pointer to input */
398    const int stride,              /*!< stride factor of input */
399    FIXP_DBL *pWorkBuffer          /*!< pointer to temporal working buffer */
400) {
401  int offset = anaQmf->no_channels * (QMF_NO_POLY * 2 - 1);
402  /*
403    Feed time signal into oldest anaQmf->no_channels states
404  */
405  {
406    FIXP_DBL *FilterStatesAnaTmp = ((FIXP_DBL *)anaQmf->FilterStates) + offset;
407
408    /* Feed and scale actual time in slot */
409    for (int i = anaQmf->no_channels >> 1; i != 0; i--) {
410      /* Place INT_PCM value left aligned in scaledTimeIn */
411
412      *FilterStatesAnaTmp++ = (FIXP_QAS)*timeIn;
413      timeIn += stride;
414      *FilterStatesAnaTmp++ = (FIXP_QAS)*timeIn;
415      timeIn += stride;
416    }
417  }
418
419  if (anaQmf->flags & QMF_FLAG_NONSYMMETRIC) {
420    qmfAnaPrototypeFirSlot_NonSymmetric(pWorkBuffer, anaQmf->no_channels,
421                                        anaQmf->p_filter, anaQmf->p_stride,
422                                        (FIXP_QAS *)anaQmf->FilterStates);
423  } else {
424    qmfAnaPrototypeFirSlot(pWorkBuffer, anaQmf->no_channels, anaQmf->p_filter,
425                           anaQmf->p_stride, (FIXP_QAS *)anaQmf->FilterStates);
426  }
427
428  if (anaQmf->flags & QMF_FLAG_LP) {
429    if (anaQmf->flags & QMF_FLAG_CLDFB)
430      qmfForwardModulationLP_odd(anaQmf, pWorkBuffer, qmfReal);
431    else
432      qmfForwardModulationLP_even(anaQmf, pWorkBuffer, qmfReal);
433
434  } else {
435    qmfForwardModulationHQ(anaQmf, pWorkBuffer, qmfReal, qmfImag);
436  }
437  /*
438    Shift filter states
439
440    Should be realized with modulo adressing on a DSP instead of a true buffer
441    shift
442  */
443  FDKmemmove(anaQmf->FilterStates,
444             (FIXP_QAS *)anaQmf->FilterStates + anaQmf->no_channels,
445             offset * sizeof(FIXP_QAS));
446}
447#endif
448
449void qmfAnalysisFilteringSlot(
450    HANDLE_QMF_FILTER_BANK anaQmf,  /*!< Handle of Qmf Synthesis Bank  */
451    FIXP_DBL *qmfReal,              /*!< Low and High band, real */
452    FIXP_DBL *qmfImag,              /*!< Low and High band, imag */
453    const INT_PCM *RESTRICT timeIn, /*!< Pointer to input */
454    const int stride,               /*!< stride factor of input */
455    FIXP_DBL *pWorkBuffer           /*!< pointer to temporal working buffer */
456) {
457  int offset = anaQmf->no_channels * (QMF_NO_POLY * 2 - 1);
458  /*
459    Feed time signal into oldest anaQmf->no_channels states
460  */
461  {
462    FIXP_QAS *FilterStatesAnaTmp = ((FIXP_QAS *)anaQmf->FilterStates) + offset;
463
464    /* Feed and scale actual time in slot */
465    for (int i = anaQmf->no_channels >> 1; i != 0; i--) {
466    /* Place INT_PCM value left aligned in scaledTimeIn */
467#if (QAS_BITS == SAMPLE_BITS)
468      *FilterStatesAnaTmp++ = (FIXP_QAS)*timeIn;
469      timeIn += stride;
470      *FilterStatesAnaTmp++ = (FIXP_QAS)*timeIn;
471      timeIn += stride;
472#elif (QAS_BITS > SAMPLE_BITS)
473      *FilterStatesAnaTmp++ = ((FIXP_QAS)*timeIn) << (QAS_BITS - SAMPLE_BITS);
474      timeIn += stride;
475      *FilterStatesAnaTmp++ = ((FIXP_QAS)*timeIn) << (QAS_BITS - SAMPLE_BITS);
476      timeIn += stride;
477#else
478      *FilterStatesAnaTmp++ = (FIXP_QAS)((*timeIn) >> (SAMPLE_BITS - QAS_BITS));
479      timeIn += stride;
480      *FilterStatesAnaTmp++ = (FIXP_QAS)((*timeIn) >> (SAMPLE_BITS - QAS_BITS));
481      timeIn += stride;
482#endif
483    }
484  }
485
486  if (anaQmf->flags & QMF_FLAG_NONSYMMETRIC) {
487    qmfAnaPrototypeFirSlot_NonSymmetric(pWorkBuffer, anaQmf->no_channels,
488                                        anaQmf->p_filter, anaQmf->p_stride,
489                                        (FIXP_QAS *)anaQmf->FilterStates);
490  } else {
491    qmfAnaPrototypeFirSlot(pWorkBuffer, anaQmf->no_channels, anaQmf->p_filter,
492                           anaQmf->p_stride, (FIXP_QAS *)anaQmf->FilterStates);
493  }
494
495  if (anaQmf->flags & QMF_FLAG_LP) {
496    if (anaQmf->flags & QMF_FLAG_CLDFB)
497      qmfForwardModulationLP_odd(anaQmf, pWorkBuffer, qmfReal);
498    else
499      qmfForwardModulationLP_even(anaQmf, pWorkBuffer, qmfReal);
500
501  } else {
502    qmfForwardModulationHQ(anaQmf, pWorkBuffer, qmfReal, qmfImag);
503  }
504  /*
505    Shift filter states
506
507    Should be realized with modulo adressing on a DSP instead of a true buffer
508    shift
509  */
510  FDKmemmove(anaQmf->FilterStates,
511             (FIXP_QAS *)anaQmf->FilterStates + anaQmf->no_channels,
512             offset * sizeof(FIXP_QAS));
513}
514
515/*!
516 *
517 * \brief Perform complex-valued subband filtering of the time domain
518 *        data of timeIn and stores the real part of the subband
519 *        samples in rAnalysis, and the imaginary part in iAnalysis
520 * The qmf coefficient table is symmetric. The symmetry is expoited by
521 * shrinking the coefficient table to half the size. The addressing mode
522 * takes care of the symmetries.
523 *
524 *
525 * \sa PolyphaseFiltering
526 */
527#if (SAMPLE_BITS != DFRACT_BITS) && (QAS_BITS == DFRACT_BITS)
528void qmfAnalysisFiltering(
529    HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank */
530    FIXP_DBL **qmfReal,            /*!< Pointer to real subband slots */
531    FIXP_DBL **qmfImag,            /*!< Pointer to imag subband slots */
532    QMF_SCALE_FACTOR *scaleFactor, const LONG *timeIn, /*!< Time signal */
533    const int timeIn_e, const int stride,
534    FIXP_DBL *pWorkBuffer /*!< pointer to temporal working buffer */
535) {
536  int i;
537  int no_channels = anaQmf->no_channels;
538
539  scaleFactor->lb_scale =
540      -ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK - timeIn_e;
541  scaleFactor->lb_scale -= anaQmf->filterScale;
542
543  for (i = 0; i < anaQmf->no_col; i++) {
544    FIXP_DBL *qmfImagSlot = NULL;
545
546    if (!(anaQmf->flags & QMF_FLAG_LP)) {
547      qmfImagSlot = qmfImag[i];
548    }
549
550    qmfAnalysisFilteringSlot(anaQmf, qmfReal[i], qmfImagSlot, timeIn, stride,
551                             pWorkBuffer);
552
553    timeIn += no_channels * stride;
554
555  } /* no_col loop  i  */
556}
557#endif
558
559void qmfAnalysisFiltering(
560    HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank */
561    FIXP_DBL **qmfReal,            /*!< Pointer to real subband slots */
562    FIXP_DBL **qmfImag,            /*!< Pointer to imag subband slots */
563    QMF_SCALE_FACTOR *scaleFactor, const INT_PCM *timeIn, /*!< Time signal */
564    const int timeIn_e, const int stride,
565    FIXP_DBL *pWorkBuffer /*!< pointer to temporal working buffer */
566) {
567  int i;
568  int no_channels = anaQmf->no_channels;
569
570  scaleFactor->lb_scale =
571      -ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK - timeIn_e;
572  scaleFactor->lb_scale -= anaQmf->filterScale;
573
574  for (i = 0; i < anaQmf->no_col; i++) {
575    FIXP_DBL *qmfImagSlot = NULL;
576
577    if (!(anaQmf->flags & QMF_FLAG_LP)) {
578      qmfImagSlot = qmfImag[i];
579    }
580
581    qmfAnalysisFilteringSlot(anaQmf, qmfReal[i], qmfImagSlot, timeIn, stride,
582                             pWorkBuffer);
583
584    timeIn += no_channels * stride;
585
586  } /* no_col loop  i  */
587}
588
589/*!
590 *
591 * \brief Perform low power inverse modulation of the subband
592 *        samples stored in rSubband (real part) and iSubband (imaginary
593 *        part) and stores the result in pWorkBuffer.
594 *
595 */
596inline static void qmfInverseModulationLP_even(
597    HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank  */
598    const FIXP_DBL *qmfReal, /*!< Pointer to qmf real subband slot (input) */
599    const int scaleFactorLowBand,  /*!< Scalefactor for Low band */
600    const int scaleFactorHighBand, /*!< Scalefactor for High band */
601    FIXP_DBL *pTimeOut             /*!< Pointer to qmf subband slot (output)*/
602) {
603  int i;
604  int L = synQmf->no_channels;
605  int M = L >> 1;
606  int scale;
607  FIXP_DBL tmp;
608  FIXP_DBL *RESTRICT tReal = pTimeOut;
609  FIXP_DBL *RESTRICT tImag = pTimeOut + L;
610
611  /* Move input to output vector with offset */
612  scaleValues(&tReal[0], &qmfReal[0], synQmf->lsb, (int)scaleFactorLowBand);
613  scaleValues(&tReal[0 + synQmf->lsb], &qmfReal[0 + synQmf->lsb],
614              synQmf->usb - synQmf->lsb, (int)scaleFactorHighBand);
615  FDKmemclear(&tReal[0 + synQmf->usb], (L - synQmf->usb) * sizeof(FIXP_DBL));
616
617  /* Dct type-2 transform */
618  dct_II(tReal, tImag, L, &scale);
619
620  /* Expand output and replace inplace the output buffers */
621  tImag[0] = tReal[M];
622  tImag[M] = (FIXP_DBL)0;
623  tmp = tReal[0];
624  tReal[0] = tReal[M];
625  tReal[M] = tmp;
626
627  for (i = 1; i < M / 2; i++) {
628    /* Imag */
629    tmp = tReal[L - i];
630    tImag[M - i] = tmp;
631    tImag[i + M] = -tmp;
632
633    tmp = tReal[M + i];
634    tImag[i] = tmp;
635    tImag[L - i] = -tmp;
636
637    /* Real */
638    tReal[M + i] = tReal[i];
639    tReal[L - i] = tReal[M - i];
640    tmp = tReal[i];
641    tReal[i] = tReal[M - i];
642    tReal[M - i] = tmp;
643  }
644  /* Remaining odd terms */
645  tmp = tReal[M + M / 2];
646  tImag[M / 2] = tmp;
647  tImag[M / 2 + M] = -tmp;
648
649  tReal[M + M / 2] = tReal[M / 2];
650}
651
652inline static void qmfInverseModulationLP_odd(
653    HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank  */
654    const FIXP_DBL *qmfReal, /*!< Pointer to qmf real subband slot (input) */
655    const int scaleFactorLowBand,  /*!< Scalefactor for Low band */
656    const int scaleFactorHighBand, /*!< Scalefactor for High band */
657    FIXP_DBL *pTimeOut             /*!< Pointer to qmf subband slot (output)*/
658) {
659  int i;
660  int L = synQmf->no_channels;
661  int M = L >> 1;
662  int shift = 0;
663
664  /* Move input to output vector with offset */
665  scaleValues(pTimeOut + M, qmfReal, synQmf->lsb, scaleFactorLowBand);
666  scaleValues(pTimeOut + M + synQmf->lsb, qmfReal + synQmf->lsb,
667              synQmf->usb - synQmf->lsb, scaleFactorHighBand);
668  FDKmemclear(pTimeOut + M + synQmf->usb, (L - synQmf->usb) * sizeof(FIXP_DBL));
669
670  dct_IV(pTimeOut + M, L, &shift);
671  for (i = 0; i < M; i++) {
672    pTimeOut[i] = pTimeOut[L - 1 - i];
673    pTimeOut[2 * L - 1 - i] = -pTimeOut[L + i];
674  }
675}
676
677#ifndef FUNCTION_qmfInverseModulationHQ
678/*!
679 *
680 * \brief Perform complex-valued inverse modulation of the subband
681 *        samples stored in rSubband (real part) and iSubband (imaginary
682 *        part) and stores the result in pWorkBuffer.
683 *
684 */
685inline static void qmfInverseModulationHQ(
686    HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank     */
687    const FIXP_DBL *qmfReal,       /*!< Pointer to qmf real subband slot */
688    const FIXP_DBL *qmfImag,       /*!< Pointer to qmf imag subband slot */
689    const int scaleFactorLowBand,  /*!< Scalefactor for Low band         */
690    const int scaleFactorHighBand, /*!< Scalefactor for High band        */
691    FIXP_DBL *pWorkBuffer          /*!< WorkBuffer (output)              */
692) {
693  int i;
694  int L = synQmf->no_channels;
695  int M = L >> 1;
696  int shift = 0;
697  FIXP_DBL *RESTRICT tReal = pWorkBuffer;
698  FIXP_DBL *RESTRICT tImag = pWorkBuffer + L;
699
700  if (synQmf->flags & QMF_FLAG_CLDFB) {
701    for (i = 0; i < synQmf->lsb; i++) {
702      cplxMult(&tImag[i], &tReal[i], scaleValue(qmfImag[i], scaleFactorLowBand),
703               scaleValue(qmfReal[i], scaleFactorLowBand), synQmf->t_cos[i],
704               synQmf->t_sin[i]);
705    }
706    for (; i < synQmf->usb; i++) {
707      cplxMult(&tImag[i], &tReal[i],
708               scaleValue(qmfImag[i], scaleFactorHighBand),
709               scaleValue(qmfReal[i], scaleFactorHighBand), synQmf->t_cos[i],
710               synQmf->t_sin[i]);
711    }
712  }
713
714  if ((synQmf->flags & QMF_FLAG_CLDFB) == 0) {
715    scaleValues(&tReal[0], &qmfReal[0], synQmf->lsb, (int)scaleFactorLowBand);
716    scaleValues(&tReal[0 + synQmf->lsb], &qmfReal[0 + synQmf->lsb],
717                synQmf->usb - synQmf->lsb, (int)scaleFactorHighBand);
718    scaleValues(&tImag[0], &qmfImag[0], synQmf->lsb, (int)scaleFactorLowBand);
719    scaleValues(&tImag[0 + synQmf->lsb], &qmfImag[0 + synQmf->lsb],
720                synQmf->usb - synQmf->lsb, (int)scaleFactorHighBand);
721  }
722
723  FDKmemclear(&tReal[synQmf->usb],
724              (synQmf->no_channels - synQmf->usb) * sizeof(FIXP_DBL));
725  FDKmemclear(&tImag[synQmf->usb],
726              (synQmf->no_channels - synQmf->usb) * sizeof(FIXP_DBL));
727
728  dct_IV(tReal, L, &shift);
729  dst_IV(tImag, L, &shift);
730
731  if (synQmf->flags & QMF_FLAG_CLDFB) {
732    for (i = 0; i < M; i++) {
733      FIXP_DBL r1, i1, r2, i2;
734      r1 = tReal[i];
735      i2 = tImag[L - 1 - i];
736      r2 = tReal[L - i - 1];
737      i1 = tImag[i];
738
739      tReal[i] = (r1 - i1) >> 1;
740      tImag[L - 1 - i] = -(r1 + i1) >> 1;
741      tReal[L - i - 1] = (r2 - i2) >> 1;
742      tImag[i] = -(r2 + i2) >> 1;
743    }
744  } else {
745    /* The array accesses are negative to compensate the missing minus sign in
746     * the low and hi band gain. */
747    /* 26 cycles on ARM926 */
748    for (i = 0; i < M; i++) {
749      FIXP_DBL r1, i1, r2, i2;
750      r1 = -tReal[i];
751      i2 = -tImag[L - 1 - i];
752      r2 = -tReal[L - i - 1];
753      i1 = -tImag[i];
754
755      tReal[i] = (r1 - i1) >> 1;
756      tImag[L - 1 - i] = -(r1 + i1) >> 1;
757      tReal[L - i - 1] = (r2 - i2) >> 1;
758      tImag[i] = -(r2 + i2) >> 1;
759    }
760  }
761}
762#endif /* #ifndef FUNCTION_qmfInverseModulationHQ */
763
764/*!
765 *
766 * \brief Create QMF filter bank instance
767 *
768 * \return 0 if successful
769 *
770 */
771static int qmfInitFilterBank(
772    HANDLE_QMF_FILTER_BANK h_Qmf, /*!< Handle to return */
773    void *pFilterStates,          /*!< Handle to filter states */
774    int noCols,                   /*!< Number of timeslots per frame */
775    int lsb,                      /*!< Lower end of QMF frequency range */
776    int usb,                      /*!< Upper end of QMF frequency range */
777    int no_channels,              /*!< Number of channels (bands) */
778    UINT flags,                   /*!< flags */
779    int synflag)                  /*!< 1: synthesis; 0: analysis */
780{
781  FDKmemclear(h_Qmf, sizeof(QMF_FILTER_BANK));
782
783  if (flags & QMF_FLAG_MPSLDFB) {
784    flags |= QMF_FLAG_NONSYMMETRIC;
785    flags |= QMF_FLAG_MPSLDFB_OPTIMIZE_MODULATION;
786
787    h_Qmf->t_cos = NULL;
788    h_Qmf->t_sin = NULL;
789    h_Qmf->filterScale = QMF_MPSLDFB_PFT_SCALE;
790    h_Qmf->p_stride = 1;
791
792    switch (no_channels) {
793      case 64:
794        h_Qmf->p_filter = qmf_mpsldfb_640;
795        h_Qmf->FilterSize = 640;
796        break;
797      case 32:
798        h_Qmf->p_filter = qmf_mpsldfb_320;
799        h_Qmf->FilterSize = 320;
800        break;
801      default:
802        return -1;
803    }
804  }
805
806  if (!(flags & QMF_FLAG_MPSLDFB) && (flags & QMF_FLAG_CLDFB)) {
807    flags |= QMF_FLAG_NONSYMMETRIC;
808    h_Qmf->filterScale = QMF_CLDFB_PFT_SCALE;
809
810    h_Qmf->p_stride = 1;
811    switch (no_channels) {
812      case 64:
813        h_Qmf->t_cos = qmf_phaseshift_cos64_cldfb;
814        h_Qmf->t_sin = qmf_phaseshift_sin64_cldfb;
815        h_Qmf->p_filter = qmf_cldfb_640;
816        h_Qmf->FilterSize = 640;
817        break;
818      case 32:
819        h_Qmf->t_cos = (synflag) ? qmf_phaseshift_cos32_cldfb_syn
820                                 : qmf_phaseshift_cos32_cldfb_ana;
821        h_Qmf->t_sin = qmf_phaseshift_sin32_cldfb;
822        h_Qmf->p_filter = qmf_cldfb_320;
823        h_Qmf->FilterSize = 320;
824        break;
825      case 16:
826        h_Qmf->t_cos = (synflag) ? qmf_phaseshift_cos16_cldfb_syn
827                                 : qmf_phaseshift_cos16_cldfb_ana;
828        h_Qmf->t_sin = qmf_phaseshift_sin16_cldfb;
829        h_Qmf->p_filter = qmf_cldfb_160;
830        h_Qmf->FilterSize = 160;
831        break;
832      case 8:
833        h_Qmf->t_cos = (synflag) ? qmf_phaseshift_cos8_cldfb_syn
834                                 : qmf_phaseshift_cos8_cldfb_ana;
835        h_Qmf->t_sin = qmf_phaseshift_sin8_cldfb;
836        h_Qmf->p_filter = qmf_cldfb_80;
837        h_Qmf->FilterSize = 80;
838        break;
839      default:
840        return -1;
841    }
842  }
843
844  if (!(flags & QMF_FLAG_MPSLDFB) && ((flags & QMF_FLAG_CLDFB) == 0)) {
845    switch (no_channels) {
846      case 64:
847        h_Qmf->p_filter = qmf_pfilt640;
848        h_Qmf->t_cos = qmf_phaseshift_cos64;
849        h_Qmf->t_sin = qmf_phaseshift_sin64;
850        h_Qmf->p_stride = 1;
851        h_Qmf->FilterSize = 640;
852        h_Qmf->filterScale = 0;
853        break;
854      case 40:
855        if (synflag) {
856          break;
857        } else {
858          h_Qmf->p_filter = qmf_pfilt400; /* Scaling factor 0.8 */
859          h_Qmf->t_cos = qmf_phaseshift_cos40;
860          h_Qmf->t_sin = qmf_phaseshift_sin40;
861          h_Qmf->filterScale = 1;
862          h_Qmf->p_stride = 1;
863          h_Qmf->FilterSize = no_channels * 10;
864        }
865        break;
866      case 32:
867        h_Qmf->p_filter = qmf_pfilt640;
868        if (flags & QMF_FLAG_DOWNSAMPLED) {
869          h_Qmf->t_cos = qmf_phaseshift_cos_downsamp32;
870          h_Qmf->t_sin = qmf_phaseshift_sin_downsamp32;
871        } else {
872          h_Qmf->t_cos = qmf_phaseshift_cos32;
873          h_Qmf->t_sin = qmf_phaseshift_sin32;
874        }
875        h_Qmf->p_stride = 2;
876        h_Qmf->FilterSize = 640;
877        h_Qmf->filterScale = 0;
878        break;
879      case 20:
880        h_Qmf->p_filter = qmf_pfilt200;
881        h_Qmf->p_stride = 1;
882        h_Qmf->FilterSize = 200;
883        h_Qmf->filterScale = 0;
884        break;
885      case 12:
886        h_Qmf->p_filter = qmf_pfilt120;
887        h_Qmf->p_stride = 1;
888        h_Qmf->FilterSize = 120;
889        h_Qmf->filterScale = 0;
890        break;
891      case 8:
892        h_Qmf->p_filter = qmf_pfilt640;
893        h_Qmf->p_stride = 8;
894        h_Qmf->FilterSize = 640;
895        h_Qmf->filterScale = 0;
896        break;
897      case 16:
898        h_Qmf->p_filter = qmf_pfilt640;
899        h_Qmf->t_cos = qmf_phaseshift_cos16;
900        h_Qmf->t_sin = qmf_phaseshift_sin16;
901        h_Qmf->p_stride = 4;
902        h_Qmf->FilterSize = 640;
903        h_Qmf->filterScale = 0;
904        break;
905      case 24:
906        h_Qmf->p_filter = qmf_pfilt240;
907        h_Qmf->t_cos = qmf_phaseshift_cos24;
908        h_Qmf->t_sin = qmf_phaseshift_sin24;
909        h_Qmf->p_stride = 1;
910        h_Qmf->FilterSize = 240;
911        h_Qmf->filterScale = 1;
912        break;
913      default:
914        return -1;
915    }
916  }
917
918  h_Qmf->synScalefactor = h_Qmf->filterScale;
919  // DCT|DST dependency
920  switch (no_channels) {
921    case 128:
922      h_Qmf->synScalefactor += ALGORITHMIC_SCALING_IN_SYNTHESIS_FILTERBANK + 1;
923      break;
924    case 40: {
925      h_Qmf->synScalefactor += ALGORITHMIC_SCALING_IN_SYNTHESIS_FILTERBANK - 1;
926    } break;
927    case 64:
928      h_Qmf->synScalefactor += ALGORITHMIC_SCALING_IN_SYNTHESIS_FILTERBANK;
929      break;
930    case 8:
931      h_Qmf->synScalefactor += ALGORITHMIC_SCALING_IN_SYNTHESIS_FILTERBANK - 3;
932      break;
933    case 12:
934      h_Qmf->synScalefactor += ALGORITHMIC_SCALING_IN_SYNTHESIS_FILTERBANK;
935      break;
936    case 20:
937      h_Qmf->synScalefactor += ALGORITHMIC_SCALING_IN_SYNTHESIS_FILTERBANK + 1;
938      break;
939    case 32:
940      h_Qmf->synScalefactor += ALGORITHMIC_SCALING_IN_SYNTHESIS_FILTERBANK - 1;
941      break;
942    case 16:
943      h_Qmf->synScalefactor += ALGORITHMIC_SCALING_IN_SYNTHESIS_FILTERBANK - 2;
944      break;
945    case 24:
946      h_Qmf->synScalefactor += ALGORITHMIC_SCALING_IN_SYNTHESIS_FILTERBANK - 1;
947      break;
948    default:
949      return -1;
950  }
951
952  h_Qmf->flags = flags;
953
954  h_Qmf->no_channels = no_channels;
955  h_Qmf->no_col = noCols;
956
957  h_Qmf->lsb = fMin(lsb, h_Qmf->no_channels);
958  h_Qmf->usb = synflag
959                   ? fMin(usb, h_Qmf->no_channels)
960                   : usb; /* was: h_Qmf->usb = fMin(usb, h_Qmf->no_channels); */
961
962  h_Qmf->FilterStates = (void *)pFilterStates;
963
964  h_Qmf->outScalefactor =
965      (ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK + h_Qmf->filterScale) +
966      h_Qmf->synScalefactor;
967
968  h_Qmf->outGain_m =
969      (FIXP_DBL)0x80000000; /* default init value will be not applied */
970  h_Qmf->outGain_e = 0;
971
972  return (0);
973}
974
975/*!
976 *
977 * \brief Adjust synthesis qmf filter states
978 *
979 * \return void
980 *
981 */
982static inline void qmfAdaptFilterStates(
983    HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Filter Bank */
984    int scaleFactorDiff)           /*!< Scale factor difference to be applied */
985{
986  if (synQmf == NULL || synQmf->FilterStates == NULL) {
987    return;
988  }
989  if (scaleFactorDiff > 0) {
990    scaleValuesSaturate((FIXP_QSS *)synQmf->FilterStates,
991                        synQmf->no_channels * (QMF_NO_POLY * 2 - 1),
992                        scaleFactorDiff);
993  } else {
994    scaleValues((FIXP_QSS *)synQmf->FilterStates,
995                synQmf->no_channels * (QMF_NO_POLY * 2 - 1), scaleFactorDiff);
996  }
997}
998
999/*!
1000 *
1001 * \brief Create QMF filter bank instance
1002 *
1003 *
1004 * \return 0 if succesful
1005 *
1006 */
1007int qmfInitAnalysisFilterBank(
1008    HANDLE_QMF_FILTER_BANK h_Qmf, /*!< Returns handle */
1009    FIXP_QAS *pFilterStates,      /*!< Handle to filter states */
1010    int noCols,                   /*!< Number of timeslots per frame */
1011    int lsb,                      /*!< lower end of QMF */
1012    int usb,                      /*!< upper end of QMF */
1013    int no_channels,              /*!< Number of channels (bands) */
1014    int flags)                    /*!< Low Power flag */
1015{
1016  int err = qmfInitFilterBank(h_Qmf, pFilterStates, noCols, lsb, usb,
1017                              no_channels, flags, 0);
1018  if (!(flags & QMF_FLAG_KEEP_STATES) && (h_Qmf->FilterStates != NULL)) {
1019    FDKmemclear(h_Qmf->FilterStates,
1020                (2 * QMF_NO_POLY - 1) * h_Qmf->no_channels * sizeof(FIXP_QAS));
1021  }
1022
1023  FDK_ASSERT(h_Qmf->no_channels >= h_Qmf->lsb);
1024
1025  return err;
1026}
1027
1028/*!
1029 *
1030 * \brief Create QMF filter bank instance
1031 *
1032 *
1033 * \return 0 if succesful
1034 *
1035 */
1036int qmfInitSynthesisFilterBank(
1037    HANDLE_QMF_FILTER_BANK h_Qmf, /*!< Returns handle */
1038    FIXP_QSS *pFilterStates,      /*!< Handle to filter states */
1039    int noCols,                   /*!< Number of timeslots per frame */
1040    int lsb,                      /*!< lower end of QMF */
1041    int usb,                      /*!< upper end of QMF */
1042    int no_channels,              /*!< Number of channels (bands) */
1043    int flags)                    /*!< Low Power flag */
1044{
1045  int oldOutScale = h_Qmf->outScalefactor;
1046  int err = qmfInitFilterBank(h_Qmf, pFilterStates, noCols, lsb, usb,
1047                              no_channels, flags, 1);
1048  if (h_Qmf->FilterStates != NULL) {
1049    if (!(flags & QMF_FLAG_KEEP_STATES)) {
1050      FDKmemclear(
1051          h_Qmf->FilterStates,
1052          (2 * QMF_NO_POLY - 1) * h_Qmf->no_channels * sizeof(FIXP_QSS));
1053    } else {
1054      qmfAdaptFilterStates(h_Qmf, oldOutScale - h_Qmf->outScalefactor);
1055    }
1056  }
1057
1058  FDK_ASSERT(h_Qmf->no_channels >= h_Qmf->lsb);
1059  FDK_ASSERT(h_Qmf->no_channels >= h_Qmf->usb);
1060
1061  return err;
1062}
1063
1064/*!
1065 *
1066 * \brief Change scale factor for output data and adjust qmf filter states
1067 *
1068 * \return void
1069 *
1070 */
1071void qmfChangeOutScalefactor(
1072    HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank */
1073    int outScalefactor             /*!< New scaling factor for output data */
1074) {
1075  if (synQmf == NULL) {
1076    return;
1077  }
1078
1079  /* Add internal filterbank scale */
1080  outScalefactor +=
1081      (ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK + synQmf->filterScale) +
1082      synQmf->synScalefactor;
1083
1084  /* adjust filter states when scale factor has been changed */
1085  if (synQmf->outScalefactor != outScalefactor) {
1086    int diff;
1087
1088    diff = synQmf->outScalefactor - outScalefactor;
1089
1090    qmfAdaptFilterStates(synQmf, diff);
1091
1092    /* save new scale factor */
1093    synQmf->outScalefactor = outScalefactor;
1094  }
1095}
1096
1097/*!
1098 *
1099 * \brief Get scale factor change which was set by qmfChangeOutScalefactor()
1100 *
1101 * \return scaleFactor
1102 *
1103 */
1104int qmfGetOutScalefactor(
1105    HANDLE_QMF_FILTER_BANK synQmf) /*!< Handle of Qmf Synthesis Bank */
1106{
1107  int scaleFactor = synQmf->outScalefactor
1108                        ? (synQmf->outScalefactor -
1109                           (ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK +
1110                            synQmf->filterScale + synQmf->synScalefactor))
1111                        : 0;
1112  return scaleFactor;
1113}
1114
1115/*!
1116 *
1117 * \brief Change gain for output data
1118 *
1119 * \return void
1120 *
1121 */
1122void qmfChangeOutGain(
1123    HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank */
1124    FIXP_DBL outputGain,           /*!< New gain for output data (mantissa) */
1125    int outputGainScale            /*!< New gain for output data (exponent) */
1126) {
1127  synQmf->outGain_m = outputGain;
1128  synQmf->outGain_e = outputGainScale;
1129}
1130
1131/* When QMF_16IN_32OUT is set, synthesis functions for 16 and 32 bit parallel
1132 * output is compiled */
1133#define INT_PCM_QMFOUT INT_PCM
1134#define SAMPLE_BITS_QMFOUT SAMPLE_BITS
1135#include "qmf_pcm.h"
1136