| |
| /* ----------------------------------------------------------------------------------------------------------- |
| Software License for The Fraunhofer FDK AAC Codec Library for Android |
| |
| © Copyright 1995 - 2012 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. |
| |
| 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: |
| |
| 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 |
| 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. |
| |
| 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." |
| |
| 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. |
| |
| 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. |
| |
| 5. CONTACT INFORMATION |
| |
| Fraunhofer Institute for Integrated Circuits IIS |
| Attention: Audio and Multimedia Departments - FDK AAC LL |
| Am Wolfsmantel 33 |
| 91058 Erlangen, Germany |
| |
| www.iis.fraunhofer.de/amm |
| amm-info@iis.fraunhofer.de |
| ----------------------------------------------------------------------------------------------------------- */ |
| |
| /******************************** Fraunhofer IIS *************************** |
| |
| 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.) |
| |
| 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. |
| |
| \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. |
| |
| */ |
| |
| #include "qmf.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 */ |
| |
| #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); |
| 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); |
| 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 |
| ) |
| { |
| const FIXP_PFT *RESTRICT p_flt = p_filter; |
| int p, k; |
| |
| for (k = 0; k < 2*no_channels; k++) |
| { |
| FIXP_DBL accu = (FIXP_DBL)0; |
| |
| p_flt += QMF_NO_POLY * (p_stride - 1); |
| |
| /* |
| Perform FIR-Filter |
| */ |
| for (p = 0; p < QMF_NO_POLY; p++) { |
| accu += fMultDiv2(*p_flt++, pFilterStates[2*no_channels * p]); |
| } |
| analysisBuffer[2*no_channels - 1 - k] = FX_DBL2FX_QMF(accu<<1); |
| pFilterStates++; |
| } |
| } |
| #endif /* FUNCTION_qmfAnaPrototypeFirSlot_NonSymmetric */ |
| |
| /*! |
| * |
| * \brief Perform real-valued forward modulation of the time domain |
| * data of timeIn and stores the real part of the subband |
| * 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 */ |
| { |
| int i; |
| int L = anaQmf->no_channels; |
| int M = L>>1; |
| int scale; |
| FIXP_QMF accu; |
| |
| const FIXP_QMF *timeInTmp1 = (FIXP_QMF *) &timeIn[3 * M]; |
| const FIXP_QMF *timeInTmp2 = timeInTmp1; |
| FIXP_QMF *rSubbandTmp = rSubband; |
| |
| rSubband[0] = timeIn[3 * M] >> 1; |
| |
| for (i = M-1; i != 0; i--) { |
| accu = ((*--timeInTmp1) >> 1) + ((*++timeInTmp2) >> 1); |
| *++rSubbandTmp = accu; |
| } |
| |
| timeInTmp1 = &timeIn[2 * M]; |
| timeInTmp2 = &timeIn[0]; |
| rSubbandTmp = &rSubband[M]; |
| |
| for (i = L-M; i != 0; i--) { |
| accu = ((*timeInTmp1--) >> 1) - ((*timeInTmp2++) >> 1); |
| *rSubbandTmp++ = accu; |
| } |
| |
| dct_III(rSubband, timeIn, L, &scale); |
| } |
| |
| #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 */ |
| { |
| int i; |
| int L = anaQmf->no_channels; |
| 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); |
| } |
| |
| 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 */ |
| ) |
| { |
| int i; |
| int L = anaQmf->no_channels; |
| 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; |
| } |
| |
| dct_IV(rSubband, L, &shift); |
| dst_IV(iSubband, L, &shift); |
| |
| { |
| { |
| const FIXP_QTW *RESTRICT sbr_t_cos; |
| const FIXP_QTW *RESTRICT sbr_t_sin; |
| 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]); |
| } |
| } |
| } |
| } |
| |
| /* |
| * \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. |
| */ |
| 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 (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 ((FIXP_QAS*)anaQmf->FilterStates, (FIXP_QAS*)anaQmf->FilterStates+anaQmf->no_channels, offset*sizeof(FIXP_QAS)); |
| } |
| |
| |
| /*! |
| * |
| * \brief Perform complex-valued subband filtering of the time domain |
| * data of timeIn and stores the real part of the subband |
| * samples in rAnalysis, and the imaginary part in iAnalysis |
| * The qmf coefficient table is symmetric. The symmetry is expoited by |
| * 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 |
| */ |
| |
| 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 */ |
| ) |
| { |
| int i; |
| int no_channels = anaQmf->no_channels; |
| |
| scaleFactor->lb_scale = -ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK; |
| scaleFactor->lb_scale -= anaQmf->filterScale; |
| |
| for (i = 0; i < anaQmf->no_col; i++) |
| { |
| FIXP_QMF *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 */ |
| } |
| |
| /*! |
| * |
| * \brief Perform low power inverse modulation of the subband |
| * samples stored in rSubband (real part) and iSubband (imaginary |
| * 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)*/ |
| ) |
| { |
| int i; |
| int L = synQmf->no_channels; |
| int M = L>>1; |
| int scale; |
| FIXP_QMF tmp; |
| FIXP_QMF *RESTRICT tReal = pTimeOut; |
| FIXP_QMF *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)); |
| |
| /* 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; |
| |
| for (i = 1; i < M/2; i++) { |
| /* Imag */ |
| tmp = tReal[L - i]; |
| tImag[M - i] = tmp; |
| tImag[i + M] = -tmp; |
| |
| tmp = tReal[M + i]; |
| tImag[i] = tmp; |
| tImag[L - i] = -tmp; |
| |
| /* Real */ |
| tReal [M + i] = tReal[i]; |
| tReal [L - i] = tReal[M - i]; |
| tmp = tReal[i]; |
| 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; |
| |
| 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)*/ |
| ) |
| { |
| int i; |
| int L = synQmf->no_channels; |
| 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)); |
| |
| dct_IV(pTimeOut+M, L, &shift); |
| for (i = 0; i < M; i++) { |
| pTimeOut[i] = pTimeOut[L - 1 - i]; |
| pTimeOut[2 * L - 1 - i] = -pTimeOut[L + i]; |
| } |
| } |
| |
| |
| /*! |
| * |
| * \brief Perform complex-valued inverse modulation of the subband |
| * samples stored in rSubband (real part) and iSubband (imaginary |
| * 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) */ |
| ) |
| { |
| int i; |
| int L = synQmf->no_channels; |
| int M = L>>1; |
| int shift = 0; |
| FIXP_QMF *RESTRICT tReal = pWorkBuffer; |
| FIXP_QMF *RESTRICT tImag = pWorkBuffer+L; |
| |
| 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]); |
| } |
| 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]); |
| } |
| } |
| |
| 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); |
| } |
| |
| FDKmemclear(&tReal[synQmf->usb], (synQmf->no_channels-synQmf->usb)*sizeof(FIXP_QMF)); |
| FDKmemclear(&tImag[synQmf->usb], (synQmf->no_channels-synQmf->usb)*sizeof(FIXP_QMF)); |
| |
| dct_IV(tReal, L, &shift); |
| dst_IV(tImag, L, &shift); |
| |
| if (synQmf->flags & QMF_FLAG_CLDFB){ |
| for (i = 0; i < M; i++) { |
| FIXP_QMF 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; |
| } |
| } 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; |
| 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; |
| } |
| } |
| } |
| |
| 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 */ |
| |
| } |
| |
| |
| /*! |
| * |
| * \brief Create QMF filter bank instance |
| * |
| * \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 */ |
| { |
| FDKmemclear(h_Qmf,sizeof(QMF_FILTER_BANK)); |
| |
| if (flags & QMF_FLAG_MPSLDFB) |
| { |
| return -1; |
| } |
| |
| if ( !(flags & QMF_FLAG_MPSLDFB) && (flags & QMF_FLAG_CLDFB) ) |
| { |
| flags |= QMF_FLAG_NONSYMMETRIC; |
| h_Qmf->filterScale = QMF_CLDFB_PFT_SCALE; |
| |
| h_Qmf->p_stride = 1; |
| switch (no_channels) { |
| case 64: |
| h_Qmf->t_cos = qmf_phaseshift_cos64_cldfb; |
| h_Qmf->t_sin = qmf_phaseshift_sin64_cldfb; |
| h_Qmf->p_filter = qmf_cldfb_640; |
| h_Qmf->FilterSize = 640; |
| break; |
| case 32: |
| h_Qmf->t_cos = qmf_phaseshift_cos32_cldfb; |
| h_Qmf->t_sin = qmf_phaseshift_sin32_cldfb; |
| h_Qmf->p_filter = qmf_cldfb_320; |
| h_Qmf->FilterSize = 320; |
| break; |
| default: |
| return -1; |
| } |
| } |
| |
| if ( !(flags & QMF_FLAG_MPSLDFB) && ((flags & QMF_FLAG_CLDFB) == 0) ) |
| { |
| switch (no_channels) { |
| case 64: |
| h_Qmf->p_filter = qmf_64; |
| 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 32: |
| h_Qmf->p_filter = qmf_64; |
| 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; |
| 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->FilterStates = (void*)pFilterStates; |
| |
| h_Qmf->outScalefactor = ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK + ALGORITHMIC_SCALING_IN_SYNTHESIS_FILTERBANK + h_Qmf->filterScale; |
| |
| 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 */ |
| |
| return (0); |
| } |
| |
| /*! |
| * |
| * \brief Adjust synthesis qmf filter states |
| * |
| * \return void |
| * |
| */ |
| 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); |
| } |
| |
| /*! |
| * |
| * \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 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)); |
| } |
| |
| return err; |
| } |
| |
| /*! |
| * |
| * \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 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)); |
| } else { |
| qmfAdaptFilterStates(h_Qmf, oldOutScale-h_Qmf->outScalefactor); |
| } |
| } |
| return err; |
| } |
| |
| |
| |
| |
| /*! |
| * |
| * \brief Change scale factor for output data and adjust qmf filter states |
| * |
| * \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) { |
| 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; |
| } |
| |
| /* adjust filter states when scale factor has been changed */ |
| 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); |
| |
| /* save new scale factor */ |
| synQmf->outScalefactor = outScalefactor; |
| } |
| } |
| |
| /*! |
| * |
| * \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; |
| } |
| |