aboutsummaryrefslogtreecommitdiffstats
path: root/libFDK/src/qmf.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libFDK/src/qmf.cpp')
-rw-r--r--libFDK/src/qmf.cpp1493
1 files changed, 716 insertions, 777 deletions
diff --git a/libFDK/src/qmf.cpp b/libFDK/src/qmf.cpp
index 54526dd..6fca043 100644
--- a/libFDK/src/qmf.cpp
+++ b/libFDK/src/qmf.cpp
@@ -1,74 +1,85 @@
-
-/* -----------------------------------------------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
Software License for The Fraunhofer FDK AAC Codec Library for Android
-© Copyright 1995 - 2013 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V.
- All rights reserved.
+© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+Forschung e.V. All rights reserved.
1. INTRODUCTION
-The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements
-the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio.
-This FDK AAC Codec software is intended to be used on a wide variety of Android devices.
-
-AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual
-audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by
-independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part
-of the MPEG specifications.
-
-Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer)
-may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners
-individually for the purpose of encoding or decoding bit streams in products that are compliant with
-the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license
-these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec
-software may already be covered under those patent licenses when it is used for those licensed purposes only.
-
-Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality,
-are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional
-applications information and documentation.
+The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software
+that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding
+scheme for digital audio. This FDK AAC Codec software is intended to be used on
+a wide variety of Android devices.
+
+AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient
+general perceptual audio codecs. AAC-ELD is considered the best-performing
+full-bandwidth communications codec by independent studies and is widely
+deployed. AAC has been standardized by ISO and IEC as part of the MPEG
+specifications.
+
+Patent licenses for necessary patent claims for the FDK AAC Codec (including
+those of Fraunhofer) may be obtained through Via Licensing
+(www.vialicensing.com) or through the respective patent owners individually for
+the purpose of encoding or decoding bit streams in products that are compliant
+with the ISO/IEC MPEG audio standards. Please note that most manufacturers of
+Android devices already license these patent claims through Via Licensing or
+directly from the patent owners, and therefore FDK AAC Codec software may
+already be covered under those patent licenses when it is used for those
+licensed purposes only.
+
+Commercially-licensed AAC software libraries, including floating-point versions
+with enhanced sound quality, are also available from Fraunhofer. Users are
+encouraged to check the Fraunhofer website for additional applications
+information and documentation.
2. COPYRIGHT LICENSE
-Redistribution and use in source and binary forms, with or without modification, are permitted without
-payment of copyright license fees provided that you satisfy the following conditions:
+Redistribution and use in source and binary forms, with or without modification,
+are permitted without payment of copyright license fees provided that you
+satisfy the following conditions:
-You must retain the complete text of this software license in redistributions of the FDK AAC Codec or
-your modifications thereto in source code form.
+You must retain the complete text of this software license in redistributions of
+the FDK AAC Codec or your modifications thereto in source code form.
-You must retain the complete text of this software license in the documentation and/or other materials
-provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form.
-You must make available free of charge copies of the complete source code of the FDK AAC Codec and your
+You must retain the complete text of this software license in the documentation
+and/or other materials provided with redistributions of the FDK AAC Codec or
+your modifications thereto in binary form. You must make available free of
+charge copies of the complete source code of the FDK AAC Codec and your
modifications thereto to recipients of copies in binary form.
-The name of Fraunhofer may not be used to endorse or promote products derived from this library without
-prior written permission.
+The name of Fraunhofer may not be used to endorse or promote products derived
+from this library without prior written permission.
-You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec
-software or your modifications thereto.
+You may not charge copyright license fees for anyone to use, copy or distribute
+the FDK AAC Codec software or your modifications thereto.
-Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software
-and the date of any change. For modified versions of the FDK AAC Codec, the term
-"Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term
-"Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android."
+Your modified versions of the FDK AAC Codec must carry prominent notices stating
+that you changed the software and the date of any change. For modified versions
+of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android"
+must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK
+AAC Codec Library for Android."
3. NO PATENT LICENSE
-NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer,
-ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with
-respect to this software.
+NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without
+limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE.
+Fraunhofer provides no warranty of patent non-infringement with respect to this
+software.
-You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized
-by appropriate patent licenses.
+You may use this FDK AAC Codec software or modifications thereto only for
+purposes that are authorized by appropriate patent licenses.
4. DISCLAIMER
-This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors
-"AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties
-of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
-CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages,
-including but not limited to procurement of substitute goods or services; loss of use, data, or profits,
-or business interruption, however caused and on any theory of liability, whether in contract, strict
-liability, or tort (including negligence), arising in any way out of the use of this software, even if
-advised of the possibility of such damage.
+This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright
+holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
+including but not limited to the implied warranties of merchantability and
+fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary,
+or consequential damages, including but not limited to procurement of substitute
+goods or services; loss of use, data, or profits, or business interruption,
+however caused and on any theory of liability, whether in contract, strict
+liability, or tort (including negligence), arising in any way out of the use of
+this software, even if advised of the possibility of such damage.
5. CONTACT INFORMATION
@@ -79,317 +90,129 @@ Am Wolfsmantel 33
www.iis.fraunhofer.de/amm
amm-info@iis.fraunhofer.de
------------------------------------------------------------------------------------------------------------ */
+----------------------------------------------------------------------------- */
-/******************************** Fraunhofer IIS ***************************
+/******************* Library for basic calculation routines ********************
Author(s): Markus Lohwasser, Josef Hoepfl, Manuel Jander
+
Description: QMF filterbank
-******************************************************************************/
+*******************************************************************************/
/*!
\file
- \brief Complex qmf analysis/synthesis,
- This module contains the qmf filterbank for analysis [ cplxAnalysisQmfFiltering() ] and
- synthesis [ cplxSynthesisQmfFiltering() ]. It is a polyphase implementation of a complex
- exponential modulated filter bank. The analysis part usually runs at half the sample rate
- than the synthesis part. (So called "dual-rate" mode.)
+ \brief Complex qmf analysis/synthesis
+ This module contains the qmf filterbank for analysis [
+ cplxAnalysisQmfFiltering() ] and synthesis [ cplxSynthesisQmfFiltering() ]. It
+ is a polyphase implementation of a complex exponential modulated filter bank.
+ The analysis part usually runs at half the sample rate than the synthesis
+ part. (So called "dual-rate" mode.)
- The coefficients of the prototype filter are specified in #sbr_qmf_64_640 (in sbr_rom.cpp).
- Thus only a 64 channel version (32 on the analysis side) with a 640 tap prototype filter
- are used.
+ The coefficients of the prototype filter are specified in #qmf_pfilt640 (in
+ sbr_rom.cpp). Thus only a 64 channel version (32 on the analysis side) with a
+ 640 tap prototype filter are used.
\anchor PolyphaseFiltering <h2>About polyphase filtering</h2>
- The polyphase implementation of a filterbank requires filtering at the input and output.
- This is implemented as part of cplxAnalysisQmfFiltering() and cplxSynthesisQmfFiltering().
- The implementation requires the filter coefficients in a specific structure as described in
- #sbr_qmf_64_640_qmf (in sbr_rom.cpp).
-
- This module comprises the computationally most expensive functions of the SBR decoder. The accuracy of
- computations is also important and has a direct impact on the overall sound quality. Therefore a special
- test program is available which can be used to only test the filterbank: main_audio.cpp
-
- This modules also uses scaling of data to provide better SNR on fixed-point processors. See #QMF_SCALE_FACTOR (in sbr_scale.h) for details.
- An interesting note: The function getScalefactor() can constitute a significant amount of computational complexity - very much depending on the
- bitrate. Since it is a rather small function, effective assembler optimization might be possible.
+ The polyphase implementation of a filterbank requires filtering at the input
+ and output. This is implemented as part of cplxAnalysisQmfFiltering() and
+ cplxSynthesisQmfFiltering(). The implementation requires the filter
+ coefficients in a specific structure as described in #sbr_qmf_64_640_qmf (in
+ sbr_rom.cpp).
+
+ This module comprises the computationally most expensive functions of the SBR
+ decoder. The accuracy of computations is also important and has a direct
+ impact on the overall sound quality. Therefore a special test program is
+ available which can be used to only test the filterbank: main_audio.cpp
+
+ This modules also uses scaling of data to provide better SNR on fixed-point
+ processors. See #QMF_SCALE_FACTOR (in sbr_scale.h) for details. An interesting
+ note: The function getScalefactor() can constitute a significant amount of
+ computational complexity - very much depending on the bitrate. Since it is a
+ rather small function, effective assembler optimization might be possible.
*/
#include "qmf.h"
-
+#include "FDK_trigFcts.h"
#include "fixpoint_math.h"
#include "dct.h"
-#ifdef QMFSYN_STATES_16BIT
-#define QSSCALE (7)
-#define FX_DBL2FX_QSS(x) ((FIXP_QSS) ((x)>>(DFRACT_BITS-QSS_BITS-QSSCALE) ))
-#define FX_QSS2FX_DBL(x) ((FIXP_DBL)((LONG)x)<<(DFRACT_BITS-QSS_BITS-QSSCALE))
-#else
#define QSSCALE (0)
#define FX_DBL2FX_QSS(x) (x)
#define FX_QSS2FX_DBL(x) (x)
-#endif
-
-
-#if defined(__arm__)
-#include "arm/qmf_arm.cpp"
-
-#endif
-
-/*!
- * \brief Algorithmic scaling in sbrForwardModulation()
- *
- * The scaling in sbrForwardModulation() is caused by:
- *
- * \li 1 R_SHIFT in sbrForwardModulation()
- * \li 5/6 R_SHIFT in dct3() if using 32/64 Bands
- * \li 1 ommited gain of 2.0 in qmfForwardModulation()
- */
-#define ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK 7
-
-/*!
- * \brief Algorithmic scaling in cplxSynthesisQmfFiltering()
- *
- * The scaling in cplxSynthesisQmfFiltering() is caused by:
- *
- * \li 5/6 R_SHIFT in dct2() if using 32/64 Bands
- * \li 1 ommited gain of 2.0 in qmfInverseModulation()
- * \li -6 division by 64 in synthesis filterbank
- * \li x bits external influence
- */
-#define ALGORITHMIC_SCALING_IN_SYNTHESIS_FILTERBANK 1
-
-/*!
- \brief Perform Synthesis Prototype Filtering on a single slot of input data.
-
- The filter takes 2 * qmf->no_channels of input data and
- generates qmf->no_channels time domain output samples.
-*/
-static
-#ifndef FUNCTION_qmfSynPrototypeFirSlot
-void qmfSynPrototypeFirSlot(
-#else
-void qmfSynPrototypeFirSlot_fallback(
-#endif
- HANDLE_QMF_FILTER_BANK qmf,
- FIXP_QMF *RESTRICT realSlot, /*!< Input: Pointer to real Slot */
- FIXP_QMF *RESTRICT imagSlot, /*!< Input: Pointer to imag Slot */
- INT_PCM *RESTRICT timeOut, /*!< Time domain data */
- int stride
- )
-{
- FIXP_QSS* FilterStates = (FIXP_QSS*)qmf->FilterStates;
- int no_channels = qmf->no_channels;
- const FIXP_PFT *p_Filter = qmf->p_filter;
- int p_stride = qmf->p_stride;
- int j;
- FIXP_QSS *RESTRICT sta = FilterStates;
- const FIXP_PFT *RESTRICT p_flt, *RESTRICT p_fltm;
- int scale = ((DFRACT_BITS-SAMPLE_BITS)-1-qmf->outScalefactor);
-
- p_flt = p_Filter+p_stride*QMF_NO_POLY; /* 5-ter von 330 */
- p_fltm = p_Filter+(qmf->FilterSize/2)-p_stride*QMF_NO_POLY; /* 5 + (320 - 2*5) = 315-ter von 330 */
-
- FDK_ASSERT(SAMPLE_BITS-1-qmf->outScalefactor >= 0); // (DFRACT_BITS-SAMPLE_BITS)-1-qmf->outScalefactor >= 0);
-
- for (j = no_channels-1; j >= 0; j--) { /* ---- läuft ueber alle Linien eines Slots ---- */
- FIXP_QMF imag = imagSlot[j]; // no_channels-1 .. 0
- FIXP_QMF real = realSlot[j]; // ~~"~~
- {
- INT_PCM tmp;
- FIXP_DBL Are = FX_QSS2FX_DBL(sta[0]) + fMultDiv2( p_fltm[0] , real);
-
- if (qmf->outGain!=(FIXP_DBL)0x80000000) {
- Are = fMult(Are,qmf->outGain);
- }
-
- #if SAMPLE_BITS > 16
- tmp = (INT_PCM)(SATURATE_SHIFT(fAbs(Are), scale, SAMPLE_BITS));
- #else
- tmp = (INT_PCM)(SATURATE_RIGHT_SHIFT(fAbs(Are), scale, SAMPLE_BITS));
- #endif
- if (Are < (FIXP_QMF)0) {
- tmp = -tmp;
- }
- timeOut[ (j)*stride ] = tmp;
- }
-
- sta[0] = sta[1] + FX_DBL2FX_QSS(fMultDiv2( p_flt [4] , imag ));
- sta[1] = sta[2] + FX_DBL2FX_QSS(fMultDiv2( p_fltm[1] , real ));
- sta[2] = sta[3] + FX_DBL2FX_QSS(fMultDiv2( p_flt [3] , imag ));
- sta[3] = sta[4] + FX_DBL2FX_QSS(fMultDiv2( p_fltm[2] , real ));
- sta[4] = sta[5] + FX_DBL2FX_QSS(fMultDiv2( p_flt [2] , imag ));
- sta[5] = sta[6] + FX_DBL2FX_QSS(fMultDiv2( p_fltm[3] , real ));
- sta[6] = sta[7] + FX_DBL2FX_QSS(fMultDiv2( p_flt [1] , imag ));
- sta[7] = sta[8] + FX_DBL2FX_QSS(fMultDiv2( p_fltm[4] , real ));
- sta[8] = FX_DBL2FX_QSS(fMultDiv2( p_flt [0] , imag ));
-
- p_flt += (p_stride*QMF_NO_POLY);
- p_fltm -= (p_stride*QMF_NO_POLY);
- sta += 9; // = (2*QMF_NO_POLY-1);
- }
-}
-
-#ifndef FUNCTION_qmfSynPrototypeFirSlot_NonSymmetric
-/*!
- \brief Perform Synthesis Prototype Filtering on a single slot of input data.
-
- The filter takes 2 * qmf->no_channels of input data and
- generates qmf->no_channels time domain output samples.
-*/
-static
-void qmfSynPrototypeFirSlot_NonSymmetric(
- HANDLE_QMF_FILTER_BANK qmf,
- FIXP_QMF *RESTRICT realSlot, /*!< Input: Pointer to real Slot */
- FIXP_QMF *RESTRICT imagSlot, /*!< Input: Pointer to imag Slot */
- INT_PCM *RESTRICT timeOut, /*!< Time domain data */
- int stride
- )
-{
- FIXP_QSS* FilterStates = (FIXP_QSS*)qmf->FilterStates;
- int no_channels = qmf->no_channels;
- const FIXP_PFT *p_Filter = qmf->p_filter;
- int p_stride = qmf->p_stride;
- int j;
- FIXP_QSS *RESTRICT sta = FilterStates;
- const FIXP_PFT *RESTRICT p_flt, *RESTRICT p_fltm;
- int scale = ((DFRACT_BITS-SAMPLE_BITS)-1-qmf->outScalefactor);
-
- p_flt = p_Filter; /*!< Pointer to first half of filter coefficients */
- p_fltm = &p_flt[qmf->FilterSize/2]; /* at index 320, overall 640 coefficients */
-
- FDK_ASSERT(SAMPLE_BITS-1-qmf->outScalefactor >= 0); // (DFRACT_BITS-SAMPLE_BITS)-1-qmf->outScalefactor >= 0);
-
- for (j = no_channels-1; j >= 0; j--) { /* ---- läuft ueber alle Linien eines Slots ---- */
-
- FIXP_QMF imag = imagSlot[j]; // no_channels-1 .. 0
- FIXP_QMF real = realSlot[j]; // ~~"~~
- {
- INT_PCM tmp;
- FIXP_QMF Are = sta[0] + FX_DBL2FX_QSS(fMultDiv2( p_fltm[4] , real ));
-
- #if SAMPLE_BITS > 16
- tmp = (INT_PCM)(SATURATE_SHIFT(fAbs(Are), scale, SAMPLE_BITS));
- #else
- tmp = (INT_PCM)(SATURATE_RIGHT_SHIFT(fAbs(Are), scale, SAMPLE_BITS));
- #endif
- if (Are < (FIXP_QMF)0) {
- tmp = -tmp;
- }
- timeOut[j*stride] = tmp;
- }
-
- sta[0] = sta[1] + FX_DBL2FX_QSS(fMultDiv2( p_flt [4] , imag ));
- sta[1] = sta[2] + FX_DBL2FX_QSS(fMultDiv2( p_fltm[3] , real ));
- sta[2] = sta[3] + FX_DBL2FX_QSS(fMultDiv2( p_flt [3] , imag ));
-
- sta[3] = sta[4] + FX_DBL2FX_QSS(fMultDiv2( p_fltm[2] , real ));
- sta[4] = sta[5] + FX_DBL2FX_QSS(fMultDiv2( p_flt [2] , imag ));
- sta[5] = sta[6] + FX_DBL2FX_QSS(fMultDiv2( p_fltm[1] , real ));
- sta[6] = sta[7] + FX_DBL2FX_QSS(fMultDiv2( p_flt [1] , imag ));
-
- sta[7] = sta[8] + FX_DBL2FX_QSS(fMultDiv2( p_fltm[0] , real ));
- sta[8] = FX_DBL2FX_QSS(fMultDiv2( p_flt [0] , imag ));
-
- p_flt += (p_stride*QMF_NO_POLY);
- p_fltm += (p_stride*QMF_NO_POLY);
- sta += 9; // = (2*QMF_NO_POLY-1);
- }
-
-}
-#endif /* FUNCTION_qmfSynPrototypeFirSlot_NonSymmetric */
+/* moved to qmf_pcm.h: -> qmfSynPrototypeFirSlot */
+/* moved to qmf_pcm.h: -> qmfSynPrototypeFirSlot_NonSymmetric */
+/* moved to qmf_pcm.h: -> qmfSynthesisFilteringSlot */
#ifndef FUNCTION_qmfAnaPrototypeFirSlot
/*!
\brief Perform Analysis Prototype Filtering on a single slot of input data.
*/
-static
-void qmfAnaPrototypeFirSlot( FIXP_QMF *analysisBuffer,
- int no_channels, /*!< Number channels of analysis filter */
- const FIXP_PFT *p_filter,
- int p_stride, /*!< Stide of analysis filter */
- FIXP_QAS *RESTRICT pFilterStates
- )
-{
- int k;
-
- FIXP_DBL accu;
- const FIXP_PFT *RESTRICT p_flt = p_filter;
- FIXP_QMF *RESTRICT pData_0 = analysisBuffer + 2*no_channels - 1;
- FIXP_QMF *RESTRICT pData_1 = analysisBuffer;
-
- FIXP_QAS *RESTRICT sta_0 = (FIXP_QAS *)pFilterStates;
- FIXP_QAS *RESTRICT sta_1 = (FIXP_QAS *)pFilterStates + (2*QMF_NO_POLY*no_channels) - 1;
- int pfltStep = QMF_NO_POLY * (p_stride);
- int staStep1 = no_channels<<1;
- int staStep2 = (no_channels<<3) - 1; /* Rewind one less */
-
- /* FIR filter 0 */
- accu = fMultDiv2( p_flt[0], *sta_1); sta_1 -= staStep1;
- accu += fMultDiv2( p_flt[1], *sta_1); sta_1 -= staStep1;
- accu += fMultDiv2( p_flt[2], *sta_1); sta_1 -= staStep1;
- accu += fMultDiv2( p_flt[3], *sta_1); sta_1 -= staStep1;
- accu += fMultDiv2( p_flt[4], *sta_1);
- *pData_1++ = FX_DBL2FX_QMF(accu<<1);
+static void qmfAnaPrototypeFirSlot(
+ FIXP_DBL *analysisBuffer,
+ INT no_channels, /*!< Number channels of analysis filter */
+ const FIXP_PFT *p_filter, INT p_stride, /*!< Stride of analysis filter */
+ FIXP_QAS *RESTRICT pFilterStates) {
+ INT k;
+
+ FIXP_DBL accu;
+ const FIXP_PFT *RESTRICT p_flt = p_filter;
+ FIXP_DBL *RESTRICT pData_0 = analysisBuffer + 2 * no_channels - 1;
+ FIXP_DBL *RESTRICT pData_1 = analysisBuffer;
+
+ FIXP_QAS *RESTRICT sta_0 = (FIXP_QAS *)pFilterStates;
+ FIXP_QAS *RESTRICT sta_1 =
+ (FIXP_QAS *)pFilterStates + (2 * QMF_NO_POLY * no_channels) - 1;
+ INT pfltStep = QMF_NO_POLY * (p_stride);
+ INT staStep1 = no_channels << 1;
+ INT staStep2 = (no_channels << 3) - 1; /* Rewind one less */
+
+ /* FIR filters 127..64 0..63 */
+ for (k = 0; k < no_channels; k++) {
+ accu = fMultDiv2(p_flt[0], *sta_1);
+ sta_1 -= staStep1;
+ accu += fMultDiv2(p_flt[1], *sta_1);
+ sta_1 -= staStep1;
+ accu += fMultDiv2(p_flt[2], *sta_1);
+ sta_1 -= staStep1;
+ accu += fMultDiv2(p_flt[3], *sta_1);
+ sta_1 -= staStep1;
+ accu += fMultDiv2(p_flt[4], *sta_1);
+ *pData_1++ = (accu << 1);
sta_1 += staStep2;
p_flt += pfltStep;
-
- /* FIR filters 1..63 127..65 */
- for (k=0; k<no_channels-1; k++)
- {
- accu = fMultDiv2( p_flt[0], *sta_0); sta_0 += staStep1;
- accu += fMultDiv2( p_flt[1], *sta_0); sta_0 += staStep1;
- accu += fMultDiv2( p_flt[2], *sta_0); sta_0 += staStep1;
- accu += fMultDiv2( p_flt[3], *sta_0); sta_0 += staStep1;
- accu += fMultDiv2( p_flt[4], *sta_0);
- *pData_0-- = FX_DBL2FX_QMF(accu<<1);
- sta_0 -= staStep2;
-
- accu = fMultDiv2( p_flt[0], *sta_1); sta_1 -= staStep1;
- accu += fMultDiv2( p_flt[1], *sta_1); sta_1 -= staStep1;
- accu += fMultDiv2( p_flt[2], *sta_1); sta_1 -= staStep1;
- accu += fMultDiv2( p_flt[3], *sta_1); sta_1 -= staStep1;
- accu += fMultDiv2( p_flt[4], *sta_1);
- *pData_1++ = FX_DBL2FX_QMF(accu<<1);
- sta_1 += staStep2;
-
- p_flt += pfltStep;
- }
-
- /* FIR filter 64 */
- accu = fMultDiv2( p_flt[0], *sta_0); sta_0 += staStep1;
- accu += fMultDiv2( p_flt[1], *sta_0); sta_0 += staStep1;
- accu += fMultDiv2( p_flt[2], *sta_0); sta_0 += staStep1;
- accu += fMultDiv2( p_flt[3], *sta_0); sta_0 += staStep1;
- accu += fMultDiv2( p_flt[4], *sta_0);
- *pData_0-- = FX_DBL2FX_QMF(accu<<1);
+ accu = fMultDiv2(p_flt[0], *sta_0);
+ sta_0 += staStep1;
+ accu += fMultDiv2(p_flt[1], *sta_0);
+ sta_0 += staStep1;
+ accu += fMultDiv2(p_flt[2], *sta_0);
+ sta_0 += staStep1;
+ accu += fMultDiv2(p_flt[3], *sta_0);
+ sta_0 += staStep1;
+ accu += fMultDiv2(p_flt[4], *sta_0);
+ *pData_0-- = (accu << 1);
sta_0 -= staStep2;
+ }
}
#endif /* !defined(FUNCTION_qmfAnaPrototypeFirSlot) */
-
#ifndef FUNCTION_qmfAnaPrototypeFirSlot_NonSymmetric
/*!
\brief Perform Analysis Prototype Filtering on a single slot of input data.
*/
-static
-void qmfAnaPrototypeFirSlot_NonSymmetric(
- FIXP_QMF *analysisBuffer,
- int no_channels, /*!< Number channels of analysis filter */
- const FIXP_PFT *p_filter,
- int p_stride, /*!< Stide of analysis filter */
- FIXP_QAS *RESTRICT pFilterStates
- )
-{
+static void qmfAnaPrototypeFirSlot_NonSymmetric(
+ FIXP_DBL *analysisBuffer,
+ int no_channels, /*!< Number channels of analysis filter */
+ const FIXP_PFT *p_filter, int p_stride, /*!< Stride of analysis filter */
+ FIXP_QAS *RESTRICT pFilterStates) {
const FIXP_PFT *RESTRICT p_flt = p_filter;
- int p, k;
+ int p, k;
- for (k = 0; k < 2*no_channels; k++)
- {
+ for (k = 0; k < 2 * no_channels; k++) {
FIXP_DBL accu = (FIXP_DBL)0;
p_flt += QMF_NO_POLY * (p_stride - 1);
@@ -398,9 +221,9 @@ void qmfAnaPrototypeFirSlot_NonSymmetric(
Perform FIR-Filter
*/
for (p = 0; p < QMF_NO_POLY; p++) {
- accu += fMultDiv2(*p_flt++, pFilterStates[2*no_channels * p]);
+ accu += fMultDiv2(*p_flt++, pFilterStates[2 * no_channels * p]);
}
- analysisBuffer[2*no_channels - 1 - k] = FX_DBL2FX_QMF(accu<<1);
+ analysisBuffer[2 * no_channels - 1 - k] = (accu << 1);
pFilterStates++;
}
}
@@ -413,24 +236,24 @@ void qmfAnaPrototypeFirSlot_NonSymmetric(
* samples in rSubband
*
*/
-static void
-qmfForwardModulationLP_even( HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank */
- FIXP_QMF *timeIn, /*!< Time Signal */
- FIXP_QMF *rSubband ) /*!< Real Output */
+static void qmfForwardModulationLP_even(
+ HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank */
+ FIXP_DBL *timeIn, /*!< Time Signal */
+ FIXP_DBL *rSubband) /*!< Real Output */
{
int i;
int L = anaQmf->no_channels;
- int M = L>>1;
+ int M = L >> 1;
int scale;
- FIXP_QMF accu;
+ FIXP_DBL accu;
- const FIXP_QMF *timeInTmp1 = (FIXP_QMF *) &timeIn[3 * M];
- const FIXP_QMF *timeInTmp2 = timeInTmp1;
- FIXP_QMF *rSubbandTmp = rSubband;
+ const FIXP_DBL *timeInTmp1 = (FIXP_DBL *)&timeIn[3 * M];
+ const FIXP_DBL *timeInTmp2 = timeInTmp1;
+ FIXP_DBL *rSubbandTmp = rSubband;
rSubband[0] = timeIn[3 * M] >> 1;
- for (i = M-1; i != 0; i--) {
+ for (i = M - 1; i != 0; i--) {
accu = ((*--timeInTmp1) >> 1) + ((*++timeInTmp2) >> 1);
*++rSubbandTmp = accu;
}
@@ -439,7 +262,7 @@ qmfForwardModulationLP_even( HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf A
timeInTmp2 = &timeIn[0];
rSubbandTmp = &rSubband[M];
- for (i = L-M; i != 0; i--) {
+ for (i = L - M; i != 0; i--) {
accu = ((*timeInTmp1--) >> 1) - ((*timeInTmp2++) >> 1);
*rSubbandTmp++ = accu;
}
@@ -448,165 +271,246 @@ qmfForwardModulationLP_even( HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf A
}
#if !defined(FUNCTION_qmfForwardModulationLP_odd)
-static void
-qmfForwardModulationLP_odd( HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank */
- const FIXP_QMF *timeIn, /*!< Time Signal */
- FIXP_QMF *rSubband ) /*!< Real Output */
+static void qmfForwardModulationLP_odd(
+ HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank */
+ const FIXP_DBL *timeIn, /*!< Time Signal */
+ FIXP_DBL *rSubband) /*!< Real Output */
{
int i;
int L = anaQmf->no_channels;
- int M = L>>1;
- int shift = (anaQmf->no_channels>>6) + 1;
+ int M = L >> 1;
+ int shift = (anaQmf->no_channels >> 6) + 1;
for (i = 0; i < M; i++) {
- rSubband[M + i] = (timeIn[L - 1 - i]>>1) - (timeIn[i]>>shift);
- rSubband[M - 1 - i] = (timeIn[L + i]>>1) + (timeIn[2 * L - 1 - i]>>shift);
+ rSubband[M + i] = (timeIn[L - 1 - i] >> 1) - (timeIn[i] >> shift);
+ rSubband[M - 1 - i] =
+ (timeIn[L + i] >> 1) + (timeIn[2 * L - 1 - i] >> shift);
}
dct_IV(rSubband, L, &shift);
}
#endif /* !defined(FUNCTION_qmfForwardModulationLP_odd) */
-
-
/*!
*
* \brief Perform complex-valued forward modulation of the time domain
* data of timeIn and stores the real part of the subband
* samples in rSubband, and the imaginary part in iSubband
*
- * Only the lower bands are obtained (upto anaQmf->lsb). For
- * a full bandwidth analysis it is required to set both anaQmf->lsb
- * and anaQmf->usb to the amount of QMF bands.
*
*/
-static void
-qmfForwardModulationHQ( HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank */
- const FIXP_QMF *RESTRICT timeIn, /*!< Time Signal */
- FIXP_QMF *RESTRICT rSubband, /*!< Real Output */
- FIXP_QMF *RESTRICT iSubband /*!< Imaginary Output */
- )
-{
+#if !defined(FUNCTION_qmfForwardModulationHQ)
+static void qmfForwardModulationHQ(
+ HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank */
+ const FIXP_DBL *RESTRICT timeIn, /*!< Time Signal */
+ FIXP_DBL *RESTRICT rSubband, /*!< Real Output */
+ FIXP_DBL *RESTRICT iSubband /*!< Imaginary Output */
+) {
int i;
int L = anaQmf->no_channels;
- int L2 = L<<1;
+ int L2 = L << 1;
int shift = 0;
- for (i = 0; i < L; i+=2) {
- FIXP_QMF x0, x1, y0, y1;
-
- x0 = timeIn[i] >> 1;
- x1 = timeIn[i+1] >> 1;
- y0 = timeIn[L2 - 1 - i] >> 1;
- y1 = timeIn[L2 - 2 - i] >> 1;
-
- rSubband[i] = x0 - y0;
- rSubband[i+1] = x1 - y1;
- iSubband[i] = x0 + y0;
- iSubband[i+1] = x1 + y1;
+ /* Time advance by one sample, which is equivalent to the complex
+ rotation at the end of the analysis. Works only for STD mode. */
+ if ((L == 64) && !(anaQmf->flags & (QMF_FLAG_CLDFB | QMF_FLAG_MPSLDFB))) {
+ FIXP_DBL x, y;
+
+ /*rSubband[0] = u[1] + u[0]*/
+ /*iSubband[0] = u[1] - u[0]*/
+ x = timeIn[1] >> 1;
+ y = timeIn[0];
+ rSubband[0] = x + (y >> 1);
+ iSubband[0] = x - (y >> 1);
+
+ /*rSubband[n] = u[n+1] - u[2M-n], n=1,...,M-1*/
+ /*iSubband[n] = u[n+1] + u[2M-n], n=1,...,M-1*/
+ for (i = 1; i < L; i++) {
+ x = timeIn[i + 1] >> 1; /*u[n+1] */
+ y = timeIn[L2 - i]; /*u[2M-n] */
+ rSubband[i] = x - (y >> 1);
+ iSubband[i] = x + (y >> 1);
+ }
+ } else {
+ for (i = 0; i < L; i += 2) {
+ FIXP_DBL x0, x1, y0, y1;
+
+ x0 = timeIn[i + 0] >> 1;
+ x1 = timeIn[i + 1] >> 1;
+ y0 = timeIn[L2 - 1 - i];
+ y1 = timeIn[L2 - 2 - i];
+
+ rSubband[i + 0] = x0 - (y0 >> 1);
+ rSubband[i + 1] = x1 - (y1 >> 1);
+ iSubband[i + 0] = x0 + (y0 >> 1);
+ iSubband[i + 1] = x1 + (y1 >> 1);
+ }
}
dct_IV(rSubband, L, &shift);
dst_IV(iSubband, L, &shift);
- {
- {
- const FIXP_QTW *RESTRICT sbr_t_cos;
- const FIXP_QTW *RESTRICT sbr_t_sin;
+ /* Do the complex rotation except for the case of 64 bands (in STD mode). */
+ if ((L != 64) || (anaQmf->flags & (QMF_FLAG_CLDFB | QMF_FLAG_MPSLDFB))) {
+ if (anaQmf->flags & QMF_FLAG_MPSLDFB_OPTIMIZE_MODULATION) {
+ FIXP_DBL iBand;
+ for (i = 0; i < fMin(anaQmf->lsb, L); i += 2) {
+ iBand = rSubband[i];
+ rSubband[i] = -iSubband[i];
+ iSubband[i] = iBand;
+
+ iBand = -rSubband[i + 1];
+ rSubband[i + 1] = iSubband[i + 1];
+ iSubband[i + 1] = iBand;
+ }
+ } else {
+ const FIXP_QTW *sbr_t_cos;
+ const FIXP_QTW *sbr_t_sin;
+ const int len = L; /* was len = fMin(anaQmf->lsb, L) but in case of USAC
+ the signal above lsb is actually needed in some
+ cases (HBE?) */
sbr_t_cos = anaQmf->t_cos;
sbr_t_sin = anaQmf->t_sin;
- for (i = 0; i < anaQmf->lsb; i++) {
- cplxMult(&iSubband[i], &rSubband[i], iSubband[i], rSubband[i], sbr_t_cos[i], sbr_t_sin[i]);
+ for (i = 0; i < len; i++) {
+ cplxMult(&iSubband[i], &rSubband[i], iSubband[i], rSubband[i],
+ sbr_t_cos[i], sbr_t_sin[i]);
}
}
}
}
+#endif /* FUNCTION_qmfForwardModulationHQ */
/*
* \brief Perform one QMF slot analysis of the time domain data of timeIn
* with specified stride and stores the real part of the subband
* samples in rSubband, and the imaginary part in iSubband
*
- * Only the lower bands are obtained (upto anaQmf->lsb). For
- * a full bandwidth analysis it is required to set both anaQmf->lsb
- * and anaQmf->usb to the amount of QMF bands.
+ * Note: anaQmf->lsb can be greater than anaQmf->no_channels in case
+ * of implicit resampling (USAC with reduced 3/4 core frame length).
*/
-void
-qmfAnalysisFilteringSlot( HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Synthesis Bank */
- FIXP_QMF *qmfReal, /*!< Low and High band, real */
- FIXP_QMF *qmfImag, /*!< Low and High band, imag */
- const INT_PCM *RESTRICT timeIn, /*!< Pointer to input */
- const int stride, /*!< stride factor of input */
- FIXP_QMF *pWorkBuffer /*!< pointer to temporal working buffer */
- )
-{
- int i;
- int offset = anaQmf->no_channels*(QMF_NO_POLY*2-1);
- /*
- Feed time signal into oldest anaQmf->no_channels states
- */
- {
- FIXP_QAS *RESTRICT FilterStatesAnaTmp = ((FIXP_QAS*)anaQmf->FilterStates)+offset;
-
- /* Feed and scale actual time in slot */
- for(i=anaQmf->no_channels>>1; i!=0; i--) {
- /* Place INT_PCM value left aligned in scaledTimeIn */
-#if (QAS_BITS==SAMPLE_BITS)
- *FilterStatesAnaTmp++ = (FIXP_QAS)*timeIn; timeIn += stride;
- *FilterStatesAnaTmp++ = (FIXP_QAS)*timeIn; timeIn += stride;
-#elif (QAS_BITS>SAMPLE_BITS)
- *FilterStatesAnaTmp++ = (FIXP_QAS)((*timeIn)<<(QAS_BITS-SAMPLE_BITS)); timeIn += stride;
- *FilterStatesAnaTmp++ = (FIXP_QAS)((*timeIn)<<(QAS_BITS-SAMPLE_BITS)); timeIn += stride;
-#else
- *FilterStatesAnaTmp++ = (FIXP_QAS)((*timeIn)>>(SAMPLE_BITS-QAS_BITS)); timeIn += stride;
- *FilterStatesAnaTmp++ = (FIXP_QAS)((*timeIn)>>(SAMPLE_BITS-QAS_BITS)); timeIn += stride;
-#endif
- }
- }
+#if (SAMPLE_BITS != DFRACT_BITS) && (QAS_BITS == DFRACT_BITS)
+void qmfAnalysisFilteringSlot(
+ HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Synthesis Bank */
+ FIXP_DBL *qmfReal, /*!< Low and High band, real */
+ FIXP_DBL *qmfImag, /*!< Low and High band, imag */
+ const LONG *RESTRICT timeIn, /*!< Pointer to input */
+ const int stride, /*!< stride factor of input */
+ FIXP_DBL *pWorkBuffer /*!< pointer to temporal working buffer */
+) {
+ int offset = anaQmf->no_channels * (QMF_NO_POLY * 2 - 1);
+ /*
+ Feed time signal into oldest anaQmf->no_channels states
+ */
+ {
+ FIXP_DBL *FilterStatesAnaTmp = ((FIXP_DBL *)anaQmf->FilterStates) + offset;
- if (anaQmf->flags & QMF_FLAG_NONSYMMETRIC) {
- qmfAnaPrototypeFirSlot_NonSymmetric(
- pWorkBuffer,
- anaQmf->no_channels,
- anaQmf->p_filter,
- anaQmf->p_stride,
- (FIXP_QAS*)anaQmf->FilterStates
- );
- } else {
- qmfAnaPrototypeFirSlot( pWorkBuffer,
- anaQmf->no_channels,
- anaQmf->p_filter,
- anaQmf->p_stride,
- (FIXP_QAS*)anaQmf->FilterStates
- );
+ /* Feed and scale actual time in slot */
+ for (int i = anaQmf->no_channels >> 1; i != 0; i--) {
+ /* Place INT_PCM value left aligned in scaledTimeIn */
+
+ *FilterStatesAnaTmp++ = (FIXP_QAS)*timeIn;
+ timeIn += stride;
+ *FilterStatesAnaTmp++ = (FIXP_QAS)*timeIn;
+ timeIn += stride;
}
+ }
- if (anaQmf->flags & QMF_FLAG_LP) {
- if (anaQmf->flags & QMF_FLAG_CLDFB)
- qmfForwardModulationLP_odd( anaQmf,
- pWorkBuffer,
- qmfReal );
- else
- qmfForwardModulationLP_even( anaQmf,
- pWorkBuffer,
- qmfReal );
+ if (anaQmf->flags & QMF_FLAG_NONSYMMETRIC) {
+ qmfAnaPrototypeFirSlot_NonSymmetric(pWorkBuffer, anaQmf->no_channels,
+ anaQmf->p_filter, anaQmf->p_stride,
+ (FIXP_QAS *)anaQmf->FilterStates);
+ } else {
+ qmfAnaPrototypeFirSlot(pWorkBuffer, anaQmf->no_channels, anaQmf->p_filter,
+ anaQmf->p_stride, (FIXP_QAS *)anaQmf->FilterStates);
+ }
- } else {
- qmfForwardModulationHQ( anaQmf,
- pWorkBuffer,
- qmfReal,
- qmfImag
- );
- }
- /*
- Shift filter states
+ if (anaQmf->flags & QMF_FLAG_LP) {
+ if (anaQmf->flags & QMF_FLAG_CLDFB)
+ qmfForwardModulationLP_odd(anaQmf, pWorkBuffer, qmfReal);
+ else
+ qmfForwardModulationLP_even(anaQmf, pWorkBuffer, qmfReal);
- Should be realized with modulo adressing on a DSP instead of a true buffer shift
- */
- FDKmemmove ((FIXP_QAS*)anaQmf->FilterStates, (FIXP_QAS*)anaQmf->FilterStates+anaQmf->no_channels, offset*sizeof(FIXP_QAS));
+ } else {
+ qmfForwardModulationHQ(anaQmf, pWorkBuffer, qmfReal, qmfImag);
+ }
+ /*
+ Shift filter states
+
+ Should be realized with modulo adressing on a DSP instead of a true buffer
+ shift
+ */
+ FDKmemmove(anaQmf->FilterStates,
+ (FIXP_QAS *)anaQmf->FilterStates + anaQmf->no_channels,
+ offset * sizeof(FIXP_QAS));
}
+#endif
+
+void qmfAnalysisFilteringSlot(
+ HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Synthesis Bank */
+ FIXP_DBL *qmfReal, /*!< Low and High band, real */
+ FIXP_DBL *qmfImag, /*!< Low and High band, imag */
+ const INT_PCM *RESTRICT timeIn, /*!< Pointer to input */
+ const int stride, /*!< stride factor of input */
+ FIXP_DBL *pWorkBuffer /*!< pointer to temporal working buffer */
+) {
+ int offset = anaQmf->no_channels * (QMF_NO_POLY * 2 - 1);
+ /*
+ Feed time signal into oldest anaQmf->no_channels states
+ */
+ {
+ FIXP_QAS *FilterStatesAnaTmp = ((FIXP_QAS *)anaQmf->FilterStates) + offset;
+
+ /* Feed and scale actual time in slot */
+ for (int i = anaQmf->no_channels >> 1; i != 0; i--) {
+ /* Place INT_PCM value left aligned in scaledTimeIn */
+#if (QAS_BITS == SAMPLE_BITS)
+ *FilterStatesAnaTmp++ = (FIXP_QAS)*timeIn;
+ timeIn += stride;
+ *FilterStatesAnaTmp++ = (FIXP_QAS)*timeIn;
+ timeIn += stride;
+#elif (QAS_BITS > SAMPLE_BITS)
+ *FilterStatesAnaTmp++ = ((FIXP_QAS)*timeIn) << (QAS_BITS - SAMPLE_BITS);
+ timeIn += stride;
+ *FilterStatesAnaTmp++ = ((FIXP_QAS)*timeIn) << (QAS_BITS - SAMPLE_BITS);
+ timeIn += stride;
+#else
+ *FilterStatesAnaTmp++ = (FIXP_QAS)((*timeIn) >> (SAMPLE_BITS - QAS_BITS));
+ timeIn += stride;
+ *FilterStatesAnaTmp++ = (FIXP_QAS)((*timeIn) >> (SAMPLE_BITS - QAS_BITS));
+ timeIn += stride;
+#endif
+ }
+ }
+ if (anaQmf->flags & QMF_FLAG_NONSYMMETRIC) {
+ qmfAnaPrototypeFirSlot_NonSymmetric(pWorkBuffer, anaQmf->no_channels,
+ anaQmf->p_filter, anaQmf->p_stride,
+ (FIXP_QAS *)anaQmf->FilterStates);
+ } else {
+ qmfAnaPrototypeFirSlot(pWorkBuffer, anaQmf->no_channels, anaQmf->p_filter,
+ anaQmf->p_stride, (FIXP_QAS *)anaQmf->FilterStates);
+ }
+
+ if (anaQmf->flags & QMF_FLAG_LP) {
+ if (anaQmf->flags & QMF_FLAG_CLDFB)
+ qmfForwardModulationLP_odd(anaQmf, pWorkBuffer, qmfReal);
+ else
+ qmfForwardModulationLP_even(anaQmf, pWorkBuffer, qmfReal);
+
+ } else {
+ qmfForwardModulationHQ(anaQmf, pWorkBuffer, qmfReal, qmfImag);
+ }
+ /*
+ Shift filter states
+
+ Should be realized with modulo adressing on a DSP instead of a true buffer
+ shift
+ */
+ FDKmemmove(anaQmf->FilterStates,
+ (FIXP_QAS *)anaQmf->FilterStates + anaQmf->no_channels,
+ offset * sizeof(FIXP_QAS));
+}
/*!
*
@@ -617,40 +521,67 @@ qmfAnalysisFilteringSlot( HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Syn
* shrinking the coefficient table to half the size. The addressing mode
* takes care of the symmetries.
*
- * Only the lower bands are obtained (upto anaQmf->lsb). For
- * a full bandwidth analysis it is required to set both anaQmf->lsb
- * and anaQmf->usb to the amount of QMF bands.
*
* \sa PolyphaseFiltering
*/
+#if (SAMPLE_BITS != DFRACT_BITS) && (QAS_BITS == DFRACT_BITS)
+void qmfAnalysisFiltering(
+ HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank */
+ FIXP_DBL **qmfReal, /*!< Pointer to real subband slots */
+ FIXP_DBL **qmfImag, /*!< Pointer to imag subband slots */
+ QMF_SCALE_FACTOR *scaleFactor, const LONG *timeIn, /*!< Time signal */
+ const int timeIn_e, const int stride,
+ FIXP_DBL *pWorkBuffer /*!< pointer to temporal working buffer */
+) {
+ int i;
+ int no_channels = anaQmf->no_channels;
-void
-qmfAnalysisFiltering( HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank */
- FIXP_QMF **qmfReal, /*!< Pointer to real subband slots */
- FIXP_QMF **qmfImag, /*!< Pointer to imag subband slots */
- QMF_SCALE_FACTOR *scaleFactor,
- const INT_PCM *timeIn, /*!< Time signal */
- const int stride,
- FIXP_QMF *pWorkBuffer /*!< pointer to temporal working buffer */
- )
-{
+ scaleFactor->lb_scale =
+ -ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK - timeIn_e;
+ scaleFactor->lb_scale -= anaQmf->filterScale;
+
+ for (i = 0; i < anaQmf->no_col; i++) {
+ FIXP_DBL *qmfImagSlot = NULL;
+
+ if (!(anaQmf->flags & QMF_FLAG_LP)) {
+ qmfImagSlot = qmfImag[i];
+ }
+
+ qmfAnalysisFilteringSlot(anaQmf, qmfReal[i], qmfImagSlot, timeIn, stride,
+ pWorkBuffer);
+
+ timeIn += no_channels * stride;
+
+ } /* no_col loop i */
+}
+#endif
+
+void qmfAnalysisFiltering(
+ HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank */
+ FIXP_DBL **qmfReal, /*!< Pointer to real subband slots */
+ FIXP_DBL **qmfImag, /*!< Pointer to imag subband slots */
+ QMF_SCALE_FACTOR *scaleFactor, const INT_PCM *timeIn, /*!< Time signal */
+ const int timeIn_e, const int stride,
+ FIXP_DBL *pWorkBuffer /*!< pointer to temporal working buffer */
+) {
int i;
int no_channels = anaQmf->no_channels;
- scaleFactor->lb_scale = -ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK;
+ scaleFactor->lb_scale =
+ -ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK - timeIn_e;
scaleFactor->lb_scale -= anaQmf->filterScale;
- for (i = 0; i < anaQmf->no_col; i++)
- {
- FIXP_QMF *qmfImagSlot = NULL;
+ for (i = 0; i < anaQmf->no_col; i++) {
+ FIXP_DBL *qmfImagSlot = NULL;
- if (!(anaQmf->flags & QMF_FLAG_LP)) {
- qmfImagSlot = qmfImag[i];
- }
+ if (!(anaQmf->flags & QMF_FLAG_LP)) {
+ qmfImagSlot = qmfImag[i];
+ }
- qmfAnalysisFilteringSlot( anaQmf, qmfReal[i], qmfImagSlot, timeIn , stride, pWorkBuffer );
+ qmfAnalysisFilteringSlot(anaQmf, qmfReal[i], qmfImagSlot, timeIn, stride,
+ pWorkBuffer);
- timeIn += no_channels*stride;
+ timeIn += no_channels * stride;
} /* no_col loop i */
}
@@ -662,91 +593,88 @@ qmfAnalysisFiltering( HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analy
* part) and stores the result in pWorkBuffer.
*
*/
-inline
-static void
-qmfInverseModulationLP_even( HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank */
- const FIXP_QMF *qmfReal, /*!< Pointer to qmf real subband slot (input) */
- const int scaleFactorLowBand, /*!< Scalefactor for Low band */
- const int scaleFactorHighBand, /*!< Scalefactor for High band */
- FIXP_QMF *pTimeOut /*!< Pointer to qmf subband slot (output)*/
- )
-{
+inline static void qmfInverseModulationLP_even(
+ HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank */
+ const FIXP_DBL *qmfReal, /*!< Pointer to qmf real subband slot (input) */
+ const int scaleFactorLowBand, /*!< Scalefactor for Low band */
+ const int scaleFactorHighBand, /*!< Scalefactor for High band */
+ FIXP_DBL *pTimeOut /*!< Pointer to qmf subband slot (output)*/
+) {
int i;
int L = synQmf->no_channels;
- int M = L>>1;
+ int M = L >> 1;
int scale;
- FIXP_QMF tmp;
- FIXP_QMF *RESTRICT tReal = pTimeOut;
- FIXP_QMF *RESTRICT tImag = pTimeOut + L;
+ FIXP_DBL tmp;
+ FIXP_DBL *RESTRICT tReal = pTimeOut;
+ FIXP_DBL *RESTRICT tImag = pTimeOut + L;
/* Move input to output vector with offset */
- scaleValues(&tReal[0], &qmfReal[0], synQmf->lsb, scaleFactorLowBand);
- scaleValues(&tReal[0+synQmf->lsb], &qmfReal[0+synQmf->lsb], synQmf->usb-synQmf->lsb, scaleFactorHighBand);
- FDKmemclear(&tReal[0+synQmf->usb], (L-synQmf->usb)*sizeof(FIXP_QMF));
+ scaleValues(&tReal[0], &qmfReal[0], synQmf->lsb, (int)scaleFactorLowBand);
+ scaleValues(&tReal[0 + synQmf->lsb], &qmfReal[0 + synQmf->lsb],
+ synQmf->usb - synQmf->lsb, (int)scaleFactorHighBand);
+ FDKmemclear(&tReal[0 + synQmf->usb], (L - synQmf->usb) * sizeof(FIXP_DBL));
/* Dct type-2 transform */
dct_II(tReal, tImag, L, &scale);
/* Expand output and replace inplace the output buffers */
tImag[0] = tReal[M];
- tImag[M] = (FIXP_QMF)0;
- tmp = tReal [0];
- tReal [0] = tReal[M];
- tReal [M] = tmp;
+ tImag[M] = (FIXP_DBL)0;
+ tmp = tReal[0];
+ tReal[0] = tReal[M];
+ tReal[M] = tmp;
- for (i = 1; i < M/2; i++) {
+ for (i = 1; i < M / 2; i++) {
/* Imag */
tmp = tReal[L - i];
- tImag[M - i] = tmp;
+ tImag[M - i] = tmp;
tImag[i + M] = -tmp;
tmp = tReal[M + i];
- tImag[i] = tmp;
+ tImag[i] = tmp;
tImag[L - i] = -tmp;
/* Real */
- tReal [M + i] = tReal[i];
- tReal [L - i] = tReal[M - i];
+ tReal[M + i] = tReal[i];
+ tReal[L - i] = tReal[M - i];
tmp = tReal[i];
- tReal[i] = tReal [M - i];
- tReal [M - i] = tmp;
-
+ tReal[i] = tReal[M - i];
+ tReal[M - i] = tmp;
}
/* Remaining odd terms */
- tmp = tReal[M + M/2];
- tImag[M/2] = tmp;
- tImag[M/2 + M] = -tmp;
+ tmp = tReal[M + M / 2];
+ tImag[M / 2] = tmp;
+ tImag[M / 2 + M] = -tmp;
- tReal [M + M/2] = tReal[M/2];
+ tReal[M + M / 2] = tReal[M / 2];
}
-inline
-static void
-qmfInverseModulationLP_odd( HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank */
- const FIXP_QMF *qmfReal, /*!< Pointer to qmf real subband slot (input) */
- const int scaleFactorLowBand, /*!< Scalefactor for Low band */
- const int scaleFactorHighBand, /*!< Scalefactor for High band */
- FIXP_QMF *pTimeOut /*!< Pointer to qmf subband slot (output)*/
- )
-{
+inline static void qmfInverseModulationLP_odd(
+ HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank */
+ const FIXP_DBL *qmfReal, /*!< Pointer to qmf real subband slot (input) */
+ const int scaleFactorLowBand, /*!< Scalefactor for Low band */
+ const int scaleFactorHighBand, /*!< Scalefactor for High band */
+ FIXP_DBL *pTimeOut /*!< Pointer to qmf subband slot (output)*/
+) {
int i;
int L = synQmf->no_channels;
- int M = L>>1;
+ int M = L >> 1;
int shift = 0;
/* Move input to output vector with offset */
- scaleValues(pTimeOut+M, qmfReal, synQmf->lsb, scaleFactorLowBand);
- scaleValues(pTimeOut+M+synQmf->lsb, qmfReal+synQmf->lsb, synQmf->usb-synQmf->lsb, scaleFactorHighBand);
- FDKmemclear(pTimeOut+M+synQmf->usb, (L-synQmf->usb)*sizeof(FIXP_QMF));
+ scaleValues(pTimeOut + M, qmfReal, synQmf->lsb, scaleFactorLowBand);
+ scaleValues(pTimeOut + M + synQmf->lsb, qmfReal + synQmf->lsb,
+ synQmf->usb - synQmf->lsb, scaleFactorHighBand);
+ FDKmemclear(pTimeOut + M + synQmf->usb, (L - synQmf->usb) * sizeof(FIXP_DBL));
- dct_IV(pTimeOut+M, L, &shift);
+ dct_IV(pTimeOut + M, L, &shift);
for (i = 0; i < M; i++) {
- pTimeOut[i] = pTimeOut[L - 1 - i];
+ pTimeOut[i] = pTimeOut[L - 1 - i];
pTimeOut[2 * L - 1 - i] = -pTimeOut[L + i];
}
}
-
+#ifndef FUNCTION_qmfInverseModulationHQ
/*!
*
* \brief Perform complex-valued inverse modulation of the subband
@@ -754,208 +682,84 @@ qmfInverseModulationLP_odd( HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf
* part) and stores the result in pWorkBuffer.
*
*/
-inline
-static void
-qmfInverseModulationHQ( HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank */
- const FIXP_QMF *qmfReal, /*!< Pointer to qmf real subband slot */
- const FIXP_QMF *qmfImag, /*!< Pointer to qmf imag subband slot */
- const int scaleFactorLowBand, /*!< Scalefactor for Low band */
- const int scaleFactorHighBand,/*!< Scalefactor for High band */
- FIXP_QMF *pWorkBuffer /*!< WorkBuffer (output) */
- )
-{
+inline static void qmfInverseModulationHQ(
+ HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank */
+ const FIXP_DBL *qmfReal, /*!< Pointer to qmf real subband slot */
+ const FIXP_DBL *qmfImag, /*!< Pointer to qmf imag subband slot */
+ const int scaleFactorLowBand, /*!< Scalefactor for Low band */
+ const int scaleFactorHighBand, /*!< Scalefactor for High band */
+ FIXP_DBL *pWorkBuffer /*!< WorkBuffer (output) */
+) {
int i;
int L = synQmf->no_channels;
- int M = L>>1;
+ int M = L >> 1;
int shift = 0;
- FIXP_QMF *RESTRICT tReal = pWorkBuffer;
- FIXP_QMF *RESTRICT tImag = pWorkBuffer+L;
+ FIXP_DBL *RESTRICT tReal = pWorkBuffer;
+ FIXP_DBL *RESTRICT tImag = pWorkBuffer + L;
- if (synQmf->flags & QMF_FLAG_CLDFB){
+ if (synQmf->flags & QMF_FLAG_CLDFB) {
for (i = 0; i < synQmf->lsb; i++) {
- cplxMult(&tImag[i], &tReal[i],
- scaleValue(qmfImag[i],scaleFactorLowBand), scaleValue(qmfReal[i],scaleFactorLowBand),
- synQmf->t_cos[i], synQmf->t_sin[i]);
+ cplxMult(&tImag[i], &tReal[i], scaleValue(qmfImag[i], scaleFactorLowBand),
+ scaleValue(qmfReal[i], scaleFactorLowBand), synQmf->t_cos[i],
+ synQmf->t_sin[i]);
}
for (; i < synQmf->usb; i++) {
cplxMult(&tImag[i], &tReal[i],
- scaleValue(qmfImag[i],scaleFactorHighBand), scaleValue(qmfReal[i],scaleFactorHighBand),
- synQmf->t_cos[i], synQmf->t_sin[i]);
+ scaleValue(qmfImag[i], scaleFactorHighBand),
+ scaleValue(qmfReal[i], scaleFactorHighBand), synQmf->t_cos[i],
+ synQmf->t_sin[i]);
}
}
- if ( (synQmf->flags & QMF_FLAG_CLDFB) == 0) {
- scaleValues(&tReal[0], &qmfReal[0], synQmf->lsb, scaleFactorLowBand);
- scaleValues(&tReal[0+synQmf->lsb], &qmfReal[0+synQmf->lsb], synQmf->usb-synQmf->lsb, scaleFactorHighBand);
- scaleValues(&tImag[0], &qmfImag[0], synQmf->lsb, scaleFactorLowBand);
- scaleValues(&tImag[0+synQmf->lsb], &qmfImag[0+synQmf->lsb], synQmf->usb-synQmf->lsb, scaleFactorHighBand);
+ if ((synQmf->flags & QMF_FLAG_CLDFB) == 0) {
+ scaleValues(&tReal[0], &qmfReal[0], synQmf->lsb, (int)scaleFactorLowBand);
+ scaleValues(&tReal[0 + synQmf->lsb], &qmfReal[0 + synQmf->lsb],
+ synQmf->usb - synQmf->lsb, (int)scaleFactorHighBand);
+ scaleValues(&tImag[0], &qmfImag[0], synQmf->lsb, (int)scaleFactorLowBand);
+ scaleValues(&tImag[0 + synQmf->lsb], &qmfImag[0 + synQmf->lsb],
+ synQmf->usb - synQmf->lsb, (int)scaleFactorHighBand);
}
- FDKmemclear(&tReal[synQmf->usb], (synQmf->no_channels-synQmf->usb)*sizeof(FIXP_QMF));
- FDKmemclear(&tImag[synQmf->usb], (synQmf->no_channels-synQmf->usb)*sizeof(FIXP_QMF));
+ FDKmemclear(&tReal[synQmf->usb],
+ (synQmf->no_channels - synQmf->usb) * sizeof(FIXP_DBL));
+ FDKmemclear(&tImag[synQmf->usb],
+ (synQmf->no_channels - synQmf->usb) * sizeof(FIXP_DBL));
dct_IV(tReal, L, &shift);
dst_IV(tImag, L, &shift);
- if (synQmf->flags & QMF_FLAG_CLDFB){
+ if (synQmf->flags & QMF_FLAG_CLDFB) {
for (i = 0; i < M; i++) {
- FIXP_QMF r1, i1, r2, i2;
+ FIXP_DBL r1, i1, r2, i2;
r1 = tReal[i];
i2 = tImag[L - 1 - i];
r2 = tReal[L - i - 1];
i1 = tImag[i];
- tReal[i] = (r1 - i1)>>1;
- tImag[L - 1 - i] = -(r1 + i1)>>1;
- tReal[L - i - 1] = (r2 - i2)>>1;
- tImag[i] = -(r2 + i2)>>1;
+ tReal[i] = (r1 - i1) >> 1;
+ tImag[L - 1 - i] = -(r1 + i1) >> 1;
+ tReal[L - i - 1] = (r2 - i2) >> 1;
+ tImag[i] = -(r2 + i2) >> 1;
}
- } else
- {
- /* The array accesses are negative to compensate the missing minus sign in the low and hi band gain. */
+ } else {
+ /* The array accesses are negative to compensate the missing minus sign in
+ * the low and hi band gain. */
/* 26 cycles on ARM926 */
for (i = 0; i < M; i++) {
- FIXP_QMF r1, i1, r2, i2;
+ FIXP_DBL r1, i1, r2, i2;
r1 = -tReal[i];
i2 = -tImag[L - 1 - i];
r2 = -tReal[L - i - 1];
i1 = -tImag[i];
- tReal[i] = (r1 - i1)>>1;
- tImag[L - 1 - i] = -(r1 + i1)>>1;
- tReal[L - i - 1] = (r2 - i2)>>1;
- tImag[i] = -(r2 + i2)>>1;
+ tReal[i] = (r1 - i1) >> 1;
+ tImag[L - 1 - i] = -(r1 + i1) >> 1;
+ tReal[L - i - 1] = (r2 - i2) >> 1;
+ tImag[i] = -(r2 + i2) >> 1;
}
}
}
-
-void qmfSynthesisFilteringSlot( HANDLE_QMF_FILTER_BANK synQmf,
- const FIXP_QMF *realSlot,
- const FIXP_QMF *imagSlot,
- const int scaleFactorLowBand,
- const int scaleFactorHighBand,
- INT_PCM *timeOut,
- const int stride,
- FIXP_QMF *pWorkBuffer)
-{
- if (!(synQmf->flags & QMF_FLAG_LP))
- qmfInverseModulationHQ ( synQmf,
- realSlot,
- imagSlot,
- scaleFactorLowBand,
- scaleFactorHighBand,
- pWorkBuffer
- );
- else
- {
- if (synQmf->flags & QMF_FLAG_CLDFB) {
- qmfInverseModulationLP_odd ( synQmf,
- realSlot,
- scaleFactorLowBand,
- scaleFactorHighBand,
- pWorkBuffer
- );
- } else {
- qmfInverseModulationLP_even ( synQmf,
- realSlot,
- scaleFactorLowBand,
- scaleFactorHighBand,
- pWorkBuffer
- );
- }
- }
-
- if (synQmf->flags & QMF_FLAG_NONSYMMETRIC) {
- qmfSynPrototypeFirSlot_NonSymmetric (
- synQmf,
- pWorkBuffer,
- pWorkBuffer+synQmf->no_channels,
- timeOut,
- stride
- );
- } else {
- qmfSynPrototypeFirSlot ( synQmf,
- pWorkBuffer,
- pWorkBuffer+synQmf->no_channels,
- timeOut,
- stride
- );
- }
-}
-
-
-/*!
- *
- *
- * \brief Perform complex-valued subband synthesis of the
- * low band and the high band and store the
- * time domain data in timeOut
- *
- * First step: Calculate the proper scaling factor of current
- * spectral data in qmfReal/qmfImag, old spectral data in the overlap
- * range and filter states.
- *
- * Second step: Perform Frequency-to-Time mapping with inverse
- * Modulation slot-wise.
- *
- * Third step: Perform FIR-filter slot-wise. To save space for filter
- * states, the MAC operations are executed directly on the filter states
- * instead of accumulating several products in the accumulator. The
- * buffer shift at the end of the function should be replaced by a
- * modulo operation, which is available on some DSPs.
- *
- * Last step: Copy the upper part of the spectral data to the overlap buffer.
- *
- * The qmf coefficient table is symmetric. The symmetry is exploited by
- * shrinking the coefficient table to half the size. The addressing mode
- * takes care of the symmetries. If the #define #QMFTABLE_FULL is set,
- * coefficient addressing works on the full table size. The code will be
- * slightly faster and slightly more compact.
- *
- * Workbuffer requirement: 2 x sizeof(**QmfBufferReal) * synQmf->no_channels
- */
-void
-qmfSynthesisFiltering( HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank */
- FIXP_QMF **QmfBufferReal, /*!< Low and High band, real */
- FIXP_QMF **QmfBufferImag, /*!< Low and High band, imag */
- const QMF_SCALE_FACTOR *scaleFactor,
- const INT ov_len, /*!< split Slot of overlap and actual slots */
- INT_PCM *timeOut, /*!< Pointer to output */
- const INT stride, /*!< stride factor of output */
- FIXP_QMF *pWorkBuffer /*!< pointer to temporal working buffer */
- )
-{
- int i;
- int L = synQmf->no_channels;
- SCHAR scaleFactorHighBand;
- SCHAR scaleFactorLowBand_ov, scaleFactorLowBand_no_ov;
-
- /* adapt scaling */
- scaleFactorHighBand = -ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK - scaleFactor->hb_scale;
- scaleFactorLowBand_ov = - ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK - scaleFactor->ov_lb_scale;
- scaleFactorLowBand_no_ov = - ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK - scaleFactor->lb_scale;
-
- for (i = 0; i < synQmf->no_col; i++) /* ----- no_col loop ----- */
- {
- const FIXP_DBL *QmfBufferImagSlot = NULL;
-
- SCHAR scaleFactorLowBand = (i<ov_len) ? scaleFactorLowBand_ov : scaleFactorLowBand_no_ov;
-
- if (!(synQmf->flags & QMF_FLAG_LP))
- QmfBufferImagSlot = QmfBufferImag[i];
-
- qmfSynthesisFilteringSlot( synQmf,
- QmfBufferReal[i],
- QmfBufferImagSlot,
- scaleFactorLowBand,
- scaleFactorHighBand,
- timeOut+(i*L*stride),
- stride,
- pWorkBuffer);
- } /* no_col loop i */
-
-}
-
+#endif /* #ifndef FUNCTION_qmfInverseModulationHQ */
/*!
*
@@ -964,24 +768,42 @@ qmfSynthesisFiltering( HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf S
* \return 0 if successful
*
*/
-static int
-qmfInitFilterBank (HANDLE_QMF_FILTER_BANK h_Qmf, /*!< Handle to return */
- void *pFilterStates, /*!< Handle to filter states */
- int noCols, /*!< Number of timeslots per frame */
- int lsb, /*!< Lower end of QMF frequency range */
- int usb, /*!< Upper end of QMF frequency range */
- int no_channels, /*!< Number of channels (bands) */
- UINT flags) /*!< flags */
+static int qmfInitFilterBank(
+ HANDLE_QMF_FILTER_BANK h_Qmf, /*!< Handle to return */
+ void *pFilterStates, /*!< Handle to filter states */
+ int noCols, /*!< Number of timeslots per frame */
+ int lsb, /*!< Lower end of QMF frequency range */
+ int usb, /*!< Upper end of QMF frequency range */
+ int no_channels, /*!< Number of channels (bands) */
+ UINT flags, /*!< flags */
+ int synflag) /*!< 1: synthesis; 0: analysis */
{
- FDKmemclear(h_Qmf,sizeof(QMF_FILTER_BANK));
+ FDKmemclear(h_Qmf, sizeof(QMF_FILTER_BANK));
- if (flags & QMF_FLAG_MPSLDFB)
- {
- return -1;
+ if (flags & QMF_FLAG_MPSLDFB) {
+ flags |= QMF_FLAG_NONSYMMETRIC;
+ flags |= QMF_FLAG_MPSLDFB_OPTIMIZE_MODULATION;
+
+ h_Qmf->t_cos = NULL;
+ h_Qmf->t_sin = NULL;
+ h_Qmf->filterScale = QMF_MPSLDFB_PFT_SCALE;
+ h_Qmf->p_stride = 1;
+
+ switch (no_channels) {
+ case 64:
+ h_Qmf->p_filter = qmf_mpsldfb_640;
+ h_Qmf->FilterSize = 640;
+ break;
+ case 32:
+ h_Qmf->p_filter = qmf_mpsldfb_320;
+ h_Qmf->FilterSize = 320;
+ break;
+ default:
+ return -1;
+ }
}
- if ( !(flags & QMF_FLAG_MPSLDFB) && (flags & QMF_FLAG_CLDFB) )
- {
+ if (!(flags & QMF_FLAG_MPSLDFB) && (flags & QMF_FLAG_CLDFB)) {
flags |= QMF_FLAG_NONSYMMETRIC;
h_Qmf->filterScale = QMF_CLDFB_PFT_SCALE;
@@ -994,63 +816,158 @@ qmfInitFilterBank (HANDLE_QMF_FILTER_BANK h_Qmf, /*!< Handle to return */
h_Qmf->FilterSize = 640;
break;
case 32:
- h_Qmf->t_cos = qmf_phaseshift_cos32_cldfb;
+ h_Qmf->t_cos = (synflag) ? qmf_phaseshift_cos32_cldfb_syn
+ : qmf_phaseshift_cos32_cldfb_ana;
h_Qmf->t_sin = qmf_phaseshift_sin32_cldfb;
h_Qmf->p_filter = qmf_cldfb_320;
h_Qmf->FilterSize = 320;
break;
+ case 16:
+ h_Qmf->t_cos = (synflag) ? qmf_phaseshift_cos16_cldfb_syn
+ : qmf_phaseshift_cos16_cldfb_ana;
+ h_Qmf->t_sin = qmf_phaseshift_sin16_cldfb;
+ h_Qmf->p_filter = qmf_cldfb_160;
+ h_Qmf->FilterSize = 160;
+ break;
+ case 8:
+ h_Qmf->t_cos = (synflag) ? qmf_phaseshift_cos8_cldfb_syn
+ : qmf_phaseshift_cos8_cldfb_ana;
+ h_Qmf->t_sin = qmf_phaseshift_sin8_cldfb;
+ h_Qmf->p_filter = qmf_cldfb_80;
+ h_Qmf->FilterSize = 80;
+ break;
default:
return -1;
}
}
- if ( !(flags & QMF_FLAG_MPSLDFB) && ((flags & QMF_FLAG_CLDFB) == 0) )
- {
+ if (!(flags & QMF_FLAG_MPSLDFB) && ((flags & QMF_FLAG_CLDFB) == 0)) {
switch (no_channels) {
case 64:
- h_Qmf->p_filter = qmf_64;
+ h_Qmf->p_filter = qmf_pfilt640;
h_Qmf->t_cos = qmf_phaseshift_cos64;
h_Qmf->t_sin = qmf_phaseshift_sin64;
h_Qmf->p_stride = 1;
h_Qmf->FilterSize = 640;
h_Qmf->filterScale = 0;
break;
+ case 40:
+ if (synflag) {
+ break;
+ } else {
+ h_Qmf->p_filter = qmf_pfilt400; /* Scaling factor 0.8 */
+ h_Qmf->t_cos = qmf_phaseshift_cos40;
+ h_Qmf->t_sin = qmf_phaseshift_sin40;
+ h_Qmf->filterScale = 1;
+ h_Qmf->p_stride = 1;
+ h_Qmf->FilterSize = no_channels * 10;
+ }
+ break;
case 32:
- h_Qmf->p_filter = qmf_64;
+ h_Qmf->p_filter = qmf_pfilt640;
if (flags & QMF_FLAG_DOWNSAMPLED) {
h_Qmf->t_cos = qmf_phaseshift_cos_downsamp32;
h_Qmf->t_sin = qmf_phaseshift_sin_downsamp32;
- }
- else {
- h_Qmf->t_cos = qmf_phaseshift_cos32;
- h_Qmf->t_sin = qmf_phaseshift_sin32;
+ } else {
+ h_Qmf->t_cos = qmf_phaseshift_cos32;
+ h_Qmf->t_sin = qmf_phaseshift_sin32;
}
h_Qmf->p_stride = 2;
h_Qmf->FilterSize = 640;
h_Qmf->filterScale = 0;
break;
+ case 20:
+ h_Qmf->p_filter = qmf_pfilt200;
+ h_Qmf->p_stride = 1;
+ h_Qmf->FilterSize = 200;
+ h_Qmf->filterScale = 0;
+ break;
+ case 12:
+ h_Qmf->p_filter = qmf_pfilt120;
+ h_Qmf->p_stride = 1;
+ h_Qmf->FilterSize = 120;
+ h_Qmf->filterScale = 0;
+ break;
+ case 8:
+ h_Qmf->p_filter = qmf_pfilt640;
+ h_Qmf->p_stride = 8;
+ h_Qmf->FilterSize = 640;
+ h_Qmf->filterScale = 0;
+ break;
+ case 16:
+ h_Qmf->p_filter = qmf_pfilt640;
+ h_Qmf->t_cos = qmf_phaseshift_cos16;
+ h_Qmf->t_sin = qmf_phaseshift_sin16;
+ h_Qmf->p_stride = 4;
+ h_Qmf->FilterSize = 640;
+ h_Qmf->filterScale = 0;
+ break;
+ case 24:
+ h_Qmf->p_filter = qmf_pfilt240;
+ h_Qmf->t_cos = qmf_phaseshift_cos24;
+ h_Qmf->t_sin = qmf_phaseshift_sin24;
+ h_Qmf->p_stride = 1;
+ h_Qmf->FilterSize = 240;
+ h_Qmf->filterScale = 1;
+ break;
default:
return -1;
}
}
+ h_Qmf->synScalefactor = h_Qmf->filterScale;
+ // DCT|DST dependency
+ switch (no_channels) {
+ case 128:
+ h_Qmf->synScalefactor += ALGORITHMIC_SCALING_IN_SYNTHESIS_FILTERBANK + 1;
+ break;
+ case 40: {
+ h_Qmf->synScalefactor += ALGORITHMIC_SCALING_IN_SYNTHESIS_FILTERBANK - 1;
+ } break;
+ case 64:
+ h_Qmf->synScalefactor += ALGORITHMIC_SCALING_IN_SYNTHESIS_FILTERBANK;
+ break;
+ case 8:
+ h_Qmf->synScalefactor += ALGORITHMIC_SCALING_IN_SYNTHESIS_FILTERBANK - 3;
+ break;
+ case 12:
+ h_Qmf->synScalefactor += ALGORITHMIC_SCALING_IN_SYNTHESIS_FILTERBANK;
+ break;
+ case 20:
+ h_Qmf->synScalefactor += ALGORITHMIC_SCALING_IN_SYNTHESIS_FILTERBANK + 1;
+ break;
+ case 32:
+ h_Qmf->synScalefactor += ALGORITHMIC_SCALING_IN_SYNTHESIS_FILTERBANK - 1;
+ break;
+ case 16:
+ h_Qmf->synScalefactor += ALGORITHMIC_SCALING_IN_SYNTHESIS_FILTERBANK - 2;
+ break;
+ case 24:
+ h_Qmf->synScalefactor += ALGORITHMIC_SCALING_IN_SYNTHESIS_FILTERBANK - 1;
+ break;
+ default:
+ return -1;
+ }
+
h_Qmf->flags = flags;
h_Qmf->no_channels = no_channels;
h_Qmf->no_col = noCols;
- h_Qmf->lsb = lsb;
- h_Qmf->usb = fMin(usb, h_Qmf->no_channels);
+ h_Qmf->lsb = fMin(lsb, h_Qmf->no_channels);
+ h_Qmf->usb = synflag
+ ? fMin(usb, h_Qmf->no_channels)
+ : usb; /* was: h_Qmf->usb = fMin(usb, h_Qmf->no_channels); */
- h_Qmf->FilterStates = (void*)pFilterStates;
+ h_Qmf->FilterStates = (void *)pFilterStates;
- h_Qmf->outScalefactor = ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK + ALGORITHMIC_SCALING_IN_SYNTHESIS_FILTERBANK + h_Qmf->filterScale;
+ h_Qmf->outScalefactor =
+ (ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK + h_Qmf->filterScale) +
+ h_Qmf->synScalefactor;
- if ( (h_Qmf->p_stride == 2)
- || ((flags & QMF_FLAG_CLDFB) && (no_channels == 32)) ) {
- h_Qmf->outScalefactor -= 1;
- }
- h_Qmf->outGain = (FIXP_DBL)0x80000000; /* default init value will be not applied */
+ h_Qmf->outGain_m =
+ (FIXP_DBL)0x80000000; /* default init value will be not applied */
+ h_Qmf->outGain_e = 0;
return (0);
}
@@ -1062,41 +979,49 @@ qmfInitFilterBank (HANDLE_QMF_FILTER_BANK h_Qmf, /*!< Handle to return */
* \return void
*
*/
-static inline void
-qmfAdaptFilterStates (HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Filter Bank */
- int scaleFactorDiff) /*!< Scale factor difference to be applied */
+static inline void qmfAdaptFilterStates(
+ HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Filter Bank */
+ int scaleFactorDiff) /*!< Scale factor difference to be applied */
{
if (synQmf == NULL || synQmf->FilterStates == NULL) {
return;
}
- scaleValues((FIXP_QSS*)synQmf->FilterStates, synQmf->no_channels*(QMF_NO_POLY*2 - 1), scaleFactorDiff);
+ if (scaleFactorDiff > 0) {
+ scaleValuesSaturate((FIXP_QSS *)synQmf->FilterStates,
+ synQmf->no_channels * (QMF_NO_POLY * 2 - 1),
+ scaleFactorDiff);
+ } else {
+ scaleValues((FIXP_QSS *)synQmf->FilterStates,
+ synQmf->no_channels * (QMF_NO_POLY * 2 - 1), scaleFactorDiff);
+ }
}
/*!
*
* \brief Create QMF filter bank instance
*
- * Only the lower bands are obtained (upto anaQmf->lsb). For
- * a full bandwidth analysis it is required to set both anaQmf->lsb
- * and anaQmf->usb to the amount of QMF bands.
*
* \return 0 if succesful
*
*/
-int
-qmfInitAnalysisFilterBank (HANDLE_QMF_FILTER_BANK h_Qmf, /*!< Returns handle */
- FIXP_QAS *pFilterStates, /*!< Handle to filter states */
- int noCols, /*!< Number of timeslots per frame */
- int lsb, /*!< lower end of QMF */
- int usb, /*!< upper end of QMF */
- int no_channels, /*!< Number of channels (bands) */
- int flags) /*!< Low Power flag */
+int qmfInitAnalysisFilterBank(
+ HANDLE_QMF_FILTER_BANK h_Qmf, /*!< Returns handle */
+ FIXP_QAS *pFilterStates, /*!< Handle to filter states */
+ int noCols, /*!< Number of timeslots per frame */
+ int lsb, /*!< lower end of QMF */
+ int usb, /*!< upper end of QMF */
+ int no_channels, /*!< Number of channels (bands) */
+ int flags) /*!< Low Power flag */
{
- int err = qmfInitFilterBank(h_Qmf, pFilterStates, noCols, lsb, usb, no_channels, flags);
- if ( !(flags & QMF_FLAG_KEEP_STATES) && (h_Qmf->FilterStates != NULL) ) {
- FDKmemclear(h_Qmf->FilterStates, (2*QMF_NO_POLY-1)*h_Qmf->no_channels*sizeof(FIXP_QAS));
+ int err = qmfInitFilterBank(h_Qmf, pFilterStates, noCols, lsb, usb,
+ no_channels, flags, 0);
+ if (!(flags & QMF_FLAG_KEEP_STATES) && (h_Qmf->FilterStates != NULL)) {
+ FDKmemclear(h_Qmf->FilterStates,
+ (2 * QMF_NO_POLY - 1) * h_Qmf->no_channels * sizeof(FIXP_QAS));
}
+ FDK_ASSERT(h_Qmf->no_channels >= h_Qmf->lsb);
+
return err;
}
@@ -1104,36 +1029,37 @@ qmfInitAnalysisFilterBank (HANDLE_QMF_FILTER_BANK h_Qmf, /*!< Returns handle *
*
* \brief Create QMF filter bank instance
*
- * Only the lower bands are obtained (upto anaQmf->lsb). For
- * a full bandwidth analysis it is required to set both anaQmf->lsb
- * and anaQmf->usb to the amount of QMF bands.
*
* \return 0 if succesful
*
*/
-int
-qmfInitSynthesisFilterBank (HANDLE_QMF_FILTER_BANK h_Qmf, /*!< Returns handle */
- FIXP_QSS *pFilterStates, /*!< Handle to filter states */
- int noCols, /*!< Number of timeslots per frame */
- int lsb, /*!< lower end of QMF */
- int usb, /*!< upper end of QMF */
- int no_channels, /*!< Number of channels (bands) */
- int flags) /*!< Low Power flag */
+int qmfInitSynthesisFilterBank(
+ HANDLE_QMF_FILTER_BANK h_Qmf, /*!< Returns handle */
+ FIXP_QSS *pFilterStates, /*!< Handle to filter states */
+ int noCols, /*!< Number of timeslots per frame */
+ int lsb, /*!< lower end of QMF */
+ int usb, /*!< upper end of QMF */
+ int no_channels, /*!< Number of channels (bands) */
+ int flags) /*!< Low Power flag */
{
int oldOutScale = h_Qmf->outScalefactor;
- int err = qmfInitFilterBank(h_Qmf, pFilterStates, noCols, lsb, usb, no_channels, flags);
- if ( h_Qmf->FilterStates != NULL ) {
- if ( !(flags & QMF_FLAG_KEEP_STATES) ) {
- FDKmemclear(h_Qmf->FilterStates, (2*QMF_NO_POLY-1)*h_Qmf->no_channels*sizeof(FIXP_QSS));
+ int err = qmfInitFilterBank(h_Qmf, pFilterStates, noCols, lsb, usb,
+ no_channels, flags, 1);
+ if (h_Qmf->FilterStates != NULL) {
+ if (!(flags & QMF_FLAG_KEEP_STATES)) {
+ FDKmemclear(
+ h_Qmf->FilterStates,
+ (2 * QMF_NO_POLY - 1) * h_Qmf->no_channels * sizeof(FIXP_QSS));
} else {
- qmfAdaptFilterStates(h_Qmf, oldOutScale-h_Qmf->outScalefactor);
+ qmfAdaptFilterStates(h_Qmf, oldOutScale - h_Qmf->outScalefactor);
}
}
- return err;
-}
-
+ FDK_ASSERT(h_Qmf->no_channels >= h_Qmf->lsb);
+ FDK_ASSERT(h_Qmf->no_channels >= h_Qmf->usb);
+ return err;
+}
/*!
*
@@ -1142,34 +1068,23 @@ qmfInitSynthesisFilterBank (HANDLE_QMF_FILTER_BANK h_Qmf, /*!< Returns handle
* \return void
*
*/
-void
-qmfChangeOutScalefactor (HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank */
- int outScalefactor /*!< New scaling factor for output data */
- )
-{
- if (synQmf == NULL || synQmf->FilterStates == NULL) {
+void qmfChangeOutScalefactor(
+ HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank */
+ int outScalefactor /*!< New scaling factor for output data */
+) {
+ if (synQmf == NULL) {
return;
}
/* Add internal filterbank scale */
- outScalefactor += ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK + ALGORITHMIC_SCALING_IN_SYNTHESIS_FILTERBANK + synQmf->filterScale;
-
- if ( (synQmf->p_stride == 2)
- || ((synQmf->flags & QMF_FLAG_CLDFB) && (synQmf->no_channels == 32)) ) {
- outScalefactor -= 1;
- }
+ outScalefactor +=
+ (ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK + synQmf->filterScale) +
+ synQmf->synScalefactor;
/* adjust filter states when scale factor has been changed */
- if (synQmf->outScalefactor != outScalefactor)
- {
+ if (synQmf->outScalefactor != outScalefactor) {
int diff;
- if (outScalefactor > (SAMPLE_BITS - 1)) {
- outScalefactor = SAMPLE_BITS - 1;
- } else if (outScalefactor < (1 - SAMPLE_BITS)) {
- outScalefactor = 1 - SAMPLE_BITS;
- }
-
diff = synQmf->outScalefactor - outScalefactor;
qmfAdaptFilterStates(synQmf, diff);
@@ -1181,16 +1096,40 @@ qmfChangeOutScalefactor (HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf S
/*!
*
+ * \brief Get scale factor change which was set by qmfChangeOutScalefactor()
+ *
+ * \return scaleFactor
+ *
+ */
+int qmfGetOutScalefactor(
+ HANDLE_QMF_FILTER_BANK synQmf) /*!< Handle of Qmf Synthesis Bank */
+{
+ int scaleFactor = synQmf->outScalefactor
+ ? (synQmf->outScalefactor -
+ (ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK +
+ synQmf->filterScale + synQmf->synScalefactor))
+ : 0;
+ return scaleFactor;
+}
+
+/*!
+ *
* \brief Change gain for output data
*
* \return void
*
*/
-void
-qmfChangeOutGain (HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank */
- FIXP_DBL outputGain /*!< New gain for output data */
- )
-{
- synQmf->outGain = outputGain;
+void qmfChangeOutGain(
+ HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank */
+ FIXP_DBL outputGain, /*!< New gain for output data (mantissa) */
+ int outputGainScale /*!< New gain for output data (exponent) */
+) {
+ synQmf->outGain_m = outputGain;
+ synQmf->outGain_e = outputGainScale;
}
+/* When QMF_16IN_32OUT is set, synthesis functions for 16 and 32 bit parallel
+ * output is compiled */
+#define INT_PCM_QMFOUT INT_PCM
+#define SAMPLE_BITS_QMFOUT SAMPLE_BITS
+#include "qmf_pcm.h"