diff options
author | Matthias P. Braendli <matthias.braendli@mpb.li> | 2019-11-11 11:38:02 +0100 |
---|---|---|
committer | Matthias P. Braendli <matthias.braendli@mpb.li> | 2019-11-11 11:38:02 +0100 |
commit | 0e5af65c467b2423a0b857ae3ad98c91acc1e190 (patch) | |
tree | d07f69550d8886271e44fe79c4dcfb299cafbd38 /fdk-aac/libSBRdec/src/lpp_tran.cpp | |
parent | efe406d9724f959c8bc2a31802559ca6d41fd897 (diff) | |
download | ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.tar.gz ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.tar.bz2 ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.zip |
Include patched FDK-AAC in the repository
The initial idea was to get the DAB+ patch into upstream, but since
that follows the android source releases, there is no place for a custom
DAB+ patch there.
So instead of having to maintain a patched fdk-aac that has to have the
same .so version as the distribution package on which it is installed,
we prefer having a separate fdk-aac-dab library to avoid collision.
At that point, there's no reason to keep fdk-aac in a separate
repository, as odr-audioenc is the only tool that needs DAB+ encoding
support. Including it here simplifies installation, and makes it
consistent with toolame-dab, also shipped in this repository.
DAB+ decoding support (needed by ODR-SourceCompanion, dablin, etisnoop,
welle.io and others) can be done using upstream FDK-AAC.
Diffstat (limited to 'fdk-aac/libSBRdec/src/lpp_tran.cpp')
-rw-r--r-- | fdk-aac/libSBRdec/src/lpp_tran.cpp | 1471 |
1 files changed, 1471 insertions, 0 deletions
diff --git a/fdk-aac/libSBRdec/src/lpp_tran.cpp b/fdk-aac/libSBRdec/src/lpp_tran.cpp new file mode 100644 index 0000000..2ef07eb --- /dev/null +++ b/fdk-aac/libSBRdec/src/lpp_tran.cpp @@ -0,0 +1,1471 @@ +/* ----------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© 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. + +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 +----------------------------------------------------------------------------- */ + +/**************************** SBR decoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +/*! + \file + \brief Low Power Profile Transposer + This module provides the transposer. The main entry point is lppTransposer(). + The function generates high frequency content by copying data from the low + band (provided by core codec) into the high band. This process is also + referred to as "patching". The function also implements spectral whitening by + means of inverse filtering based on LPC coefficients. + + Together with the QMF filterbank the transposer can be tested using a supplied + test program. See main_audio.cpp for details. This module does use fractional + arithmetic and the accuracy of the computations has an impact on the overall + sound quality. The module also needs to take into account the different + scaling of spectral data. + + \sa lppTransposer(), main_audio.cpp, sbr_scale.h, \ref documentationOverview +*/ + +#ifdef __ANDROID__ +#include "log/log.h" +#endif + +#include "lpp_tran.h" + +#include "sbr_ram.h" +#include "sbr_rom.h" + +#include "genericStds.h" +#include "autocorr2nd.h" + +#include "HFgen_preFlat.h" + +#if defined(__arm__) +#include "arm/lpp_tran_arm.cpp" +#endif + +#define LPC_SCALE_FACTOR 2 + +/*! + * + * \brief Get bandwidth expansion factor from filtering level + * + * Returns a filter parameter (bandwidth expansion factor) depending on + * the desired filtering level signalled in the bitstream. + * When switching the filtering level from LOW to OFF, an additional + * level is being inserted to achieve a smooth transition. + */ + +static FIXP_DBL mapInvfMode(INVF_MODE mode, INVF_MODE prevMode, + WHITENING_FACTORS whFactors) { + switch (mode) { + case INVF_LOW_LEVEL: + if (prevMode == INVF_OFF) + return whFactors.transitionLevel; + else + return whFactors.lowLevel; + + case INVF_MID_LEVEL: + return whFactors.midLevel; + + case INVF_HIGH_LEVEL: + return whFactors.highLevel; + + default: + if (prevMode == INVF_LOW_LEVEL) + return whFactors.transitionLevel; + else + return whFactors.off; + } +} + +/*! + * + * \brief Perform inverse filtering level emphasis + * + * Retrieve bandwidth expansion factor and apply smoothing for each filter band + * + */ + +static void inverseFilteringLevelEmphasis( + HANDLE_SBR_LPP_TRANS hLppTrans, /*!< Handle of lpp transposer */ + UCHAR nInvfBands, /*!< Number of bands for inverse filtering */ + INVF_MODE *sbr_invf_mode, /*!< Current inverse filtering modes */ + INVF_MODE *sbr_invf_mode_prev, /*!< Previous inverse filtering modes */ + FIXP_DBL *bwVector /*!< Resulting filtering levels */ +) { + for (int i = 0; i < nInvfBands; i++) { + FIXP_DBL accu; + FIXP_DBL bwTmp = mapInvfMode(sbr_invf_mode[i], sbr_invf_mode_prev[i], + hLppTrans->pSettings->whFactors); + + if (bwTmp < hLppTrans->bwVectorOld[i]) { + accu = fMultDiv2(FL2FXCONST_DBL(0.75f), bwTmp) + + fMultDiv2(FL2FXCONST_DBL(0.25f), hLppTrans->bwVectorOld[i]); + } else { + accu = fMultDiv2(FL2FXCONST_DBL(0.90625f), bwTmp) + + fMultDiv2(FL2FXCONST_DBL(0.09375f), hLppTrans->bwVectorOld[i]); + } + + if (accu<FL2FXCONST_DBL(0.015625f)>> 1) { + bwVector[i] = FL2FXCONST_DBL(0.0f); + } else { + bwVector[i] = fixMin(accu << 1, FL2FXCONST_DBL(0.99609375f)); + } + } +} + +/* Resulting autocorrelation determinant exponent */ +#define ACDET_EXP \ + (2 * (DFRACT_BITS + sbrScaleFactor->lb_scale + 10 - ac.det_scale)) +#define AC_EXP (-sbrScaleFactor->lb_scale + LPC_SCALE_FACTOR) +#define ALPHA_EXP (-sbrScaleFactor->lb_scale + LPC_SCALE_FACTOR + 1) +/* Resulting transposed QMF values exponent 16 bit normalized samplebits + * assumed. */ +#define QMFOUT_EXP ((SAMPLE_BITS - 15) - sbrScaleFactor->lb_scale) + +static inline void calc_qmfBufferReal(FIXP_DBL **qmfBufferReal, + const FIXP_DBL *const lowBandReal, + const int startSample, + const int stopSample, const UCHAR hiBand, + const int dynamicScale, const int descale, + const FIXP_SGL a0r, const FIXP_SGL a1r) { + FIXP_DBL accu1, accu2; + int i; + + for (i = 0; i < stopSample - startSample; i++) { + accu1 = fMultDiv2(a1r, lowBandReal[i]); + accu1 = (fMultDiv2(a0r, lowBandReal[i + 1]) + accu1); + accu1 = accu1 >> dynamicScale; + + accu1 <<= 1; + accu2 = (lowBandReal[i + 2] >> descale); + qmfBufferReal[i + startSample][hiBand] = accu1 + accu2; + } +} + +/*! + * + * \brief Perform transposition by patching of subband samples. + * This function serves as the main entry point into the module. The function + * determines the areas for the patching process (these are the source range as + * well as the target range) and implements spectral whitening by means of + * inverse filtering. The function autoCorrelation2nd() is an auxiliary function + * for calculating the LPC coefficients for the filtering. The actual + * calculation of the LPC coefficients and the implementation of the filtering + * are done as part of lppTransposer(). + * + * Note that the filtering is done on all available QMF subsamples, whereas the + * patching is only done on those QMF subsamples that will be used in the next + * QMF synthesis. The filtering is also implemented before the patching includes + * further dependencies on parameters from the SBR data. + * + */ + +void lppTransposer( + HANDLE_SBR_LPP_TRANS hLppTrans, /*!< Handle of lpp transposer */ + QMF_SCALE_FACTOR *sbrScaleFactor, /*!< Scaling factors */ + FIXP_DBL **qmfBufferReal, /*!< Pointer to pointer to real part of subband + samples (source) */ + + FIXP_DBL *degreeAlias, /*!< Vector for results of aliasing estimation */ + FIXP_DBL **qmfBufferImag, /*!< Pointer to pointer to imaginary part of + subband samples (source) */ + const int useLP, const int fPreWhitening, const int v_k_master0, + const int timeStep, /*!< Time step of envelope */ + const int firstSlotOffs, /*!< Start position in time */ + const int lastSlotOffs, /*!< Number of overlap-slots into next frame */ + const int nInvfBands, /*!< Number of bands for inverse filtering */ + INVF_MODE *sbr_invf_mode, /*!< Current inverse filtering modes */ + INVF_MODE *sbr_invf_mode_prev /*!< Previous inverse filtering modes */ +) { + INT bwIndex[MAX_NUM_PATCHES]; + FIXP_DBL bwVector[MAX_NUM_PATCHES]; /*!< pole moving factors */ + FIXP_DBL preWhiteningGains[(64) / 2]; + int preWhiteningGains_exp[(64) / 2]; + + int i; + int loBand, start, stop; + TRANSPOSER_SETTINGS *pSettings = hLppTrans->pSettings; + PATCH_PARAM *patchParam = pSettings->patchParam; + int patch; + + FIXP_SGL alphar[LPC_ORDER], a0r, a1r; + FIXP_SGL alphai[LPC_ORDER], a0i = 0, a1i = 0; + FIXP_SGL bw = FL2FXCONST_SGL(0.0f); + + int autoCorrLength; + + FIXP_DBL k1, k1_below = 0, k1_below2 = 0; + + ACORR_COEFS ac; + int startSample; + int stopSample; + int stopSampleClear; + + int comLowBandScale; + int ovLowBandShift; + int lowBandShift; + /* int ovHighBandShift;*/ + + alphai[0] = FL2FXCONST_SGL(0.0f); + alphai[1] = FL2FXCONST_SGL(0.0f); + + startSample = firstSlotOffs * timeStep; + stopSample = pSettings->nCols + lastSlotOffs * timeStep; + FDK_ASSERT((lastSlotOffs * timeStep) <= pSettings->overlap); + + inverseFilteringLevelEmphasis(hLppTrans, nInvfBands, sbr_invf_mode, + sbr_invf_mode_prev, bwVector); + + stopSampleClear = stopSample; + + autoCorrLength = pSettings->nCols + pSettings->overlap; + + if (pSettings->noOfPatches > 0) { + /* Set upper subbands to zero: + This is required in case that the patches do not cover the complete + highband (because the last patch would be too short). Possible + optimization: Clearing bands up to usb would be sufficient here. */ + int targetStopBand = + patchParam[pSettings->noOfPatches - 1].targetStartBand + + patchParam[pSettings->noOfPatches - 1].numBandsInPatch; + + int memSize = ((64) - targetStopBand) * sizeof(FIXP_DBL); + + if (!useLP) { + for (i = startSample; i < stopSampleClear; i++) { + FDKmemclear(&qmfBufferReal[i][targetStopBand], memSize); + FDKmemclear(&qmfBufferImag[i][targetStopBand], memSize); + } + } else { + for (i = startSample; i < stopSampleClear; i++) { + FDKmemclear(&qmfBufferReal[i][targetStopBand], memSize); + } + } + } +#ifdef __ANDROID__ + else { + // Safetynet logging + android_errorWriteLog(0x534e4554, "112160868"); + } +#endif + + /* init bwIndex for each patch */ + FDKmemclear(bwIndex, sizeof(bwIndex)); + + /* + Calc common low band scale factor + */ + comLowBandScale = + fixMin(sbrScaleFactor->ov_lb_scale, sbrScaleFactor->lb_scale); + + ovLowBandShift = sbrScaleFactor->ov_lb_scale - comLowBandScale; + lowBandShift = sbrScaleFactor->lb_scale - comLowBandScale; + /* ovHighBandShift = firstSlotOffs == 0 ? ovLowBandShift:0;*/ + + if (fPreWhitening) { + sbrDecoder_calculateGainVec( + qmfBufferReal, qmfBufferImag, + DFRACT_BITS - 1 - 16 - + sbrScaleFactor->ov_lb_scale, /* convert scale to exponent */ + DFRACT_BITS - 1 - 16 - + sbrScaleFactor->lb_scale, /* convert scale to exponent */ + pSettings->overlap, preWhiteningGains, preWhiteningGains_exp, + v_k_master0, startSample, stopSample); + } + + /* outer loop over bands to do analysis only once for each band */ + + if (!useLP) { + start = pSettings->lbStartPatching; + stop = pSettings->lbStopPatching; + } else { + start = fixMax(1, pSettings->lbStartPatching - 2); + stop = patchParam[0].targetStartBand; + } + + for (loBand = start; loBand < stop; loBand++) { + FIXP_DBL lowBandReal[(((1024) / (32) * (4) / 2) + (3 * (4))) + LPC_ORDER]; + FIXP_DBL *plowBandReal = lowBandReal; + FIXP_DBL **pqmfBufferReal = + qmfBufferReal + firstSlotOffs * timeStep /* + pSettings->overlap */; + FIXP_DBL lowBandImag[(((1024) / (32) * (4) / 2) + (3 * (4))) + LPC_ORDER]; + FIXP_DBL *plowBandImag = lowBandImag; + FIXP_DBL **pqmfBufferImag = + qmfBufferImag + firstSlotOffs * timeStep /* + pSettings->overlap */; + int resetLPCCoeffs = 0; + int dynamicScale = DFRACT_BITS - 1 - LPC_SCALE_FACTOR; + int acDetScale = 0; /* scaling of autocorrelation determinant */ + + for (i = 0; + i < LPC_ORDER + firstSlotOffs * timeStep /*+pSettings->overlap*/; + i++) { + *plowBandReal++ = hLppTrans->lpcFilterStatesRealLegSBR[i][loBand]; + if (!useLP) + *plowBandImag++ = hLppTrans->lpcFilterStatesImagLegSBR[i][loBand]; + } + + /* + Take old slope length qmf slot source values out of (overlap)qmf buffer + */ + if (!useLP) { + for (i = 0; + i < pSettings->nCols + pSettings->overlap - firstSlotOffs * timeStep; + i++) { + *plowBandReal++ = (*pqmfBufferReal++)[loBand]; + *plowBandImag++ = (*pqmfBufferImag++)[loBand]; + } + } else { + /* pSettings->overlap is always even */ + FDK_ASSERT((pSettings->overlap & 1) == 0); + for (i = 0; i < ((pSettings->nCols + pSettings->overlap - + firstSlotOffs * timeStep) >> + 1); + i++) { + *plowBandReal++ = (*pqmfBufferReal++)[loBand]; + *plowBandReal++ = (*pqmfBufferReal++)[loBand]; + } + if (pSettings->nCols & 1) { + *plowBandReal++ = (*pqmfBufferReal++)[loBand]; + } + } + + /* + Determine dynamic scaling value. + */ + dynamicScale = + fixMin(dynamicScale, + getScalefactor(lowBandReal, LPC_ORDER + pSettings->overlap) + + ovLowBandShift); + dynamicScale = + fixMin(dynamicScale, + getScalefactor(&lowBandReal[LPC_ORDER + pSettings->overlap], + pSettings->nCols) + + lowBandShift); + if (!useLP) { + dynamicScale = + fixMin(dynamicScale, + getScalefactor(lowBandImag, LPC_ORDER + pSettings->overlap) + + ovLowBandShift); + dynamicScale = + fixMin(dynamicScale, + getScalefactor(&lowBandImag[LPC_ORDER + pSettings->overlap], + pSettings->nCols) + + lowBandShift); + } + dynamicScale = fixMax( + 0, dynamicScale - 1); /* one additional bit headroom to prevent -1.0 */ + + /* + Scale temporal QMF buffer. + */ + scaleValues(&lowBandReal[0], LPC_ORDER + pSettings->overlap, + dynamicScale - ovLowBandShift); + scaleValues(&lowBandReal[LPC_ORDER + pSettings->overlap], pSettings->nCols, + dynamicScale - lowBandShift); + + if (!useLP) { + scaleValues(&lowBandImag[0], LPC_ORDER + pSettings->overlap, + dynamicScale - ovLowBandShift); + scaleValues(&lowBandImag[LPC_ORDER + pSettings->overlap], + pSettings->nCols, dynamicScale - lowBandShift); + } + + if (!useLP) { + acDetScale += autoCorr2nd_cplx(&ac, lowBandReal + LPC_ORDER, + lowBandImag + LPC_ORDER, autoCorrLength); + } else { + acDetScale += + autoCorr2nd_real(&ac, lowBandReal + LPC_ORDER, autoCorrLength); + } + + /* Examine dynamic of determinant in autocorrelation. */ + acDetScale += 2 * (comLowBandScale + dynamicScale); + acDetScale *= 2; /* two times reflection coefficent scaling */ + acDetScale += ac.det_scale; /* ac scaling of determinant */ + + /* In case of determinant < 10^-38, resetLPCCoeffs=1 has to be enforced. */ + if (acDetScale > 126) { + resetLPCCoeffs = 1; + } + + alphar[1] = FL2FXCONST_SGL(0.0f); + if (!useLP) alphai[1] = FL2FXCONST_SGL(0.0f); + + if (ac.det != FL2FXCONST_DBL(0.0f)) { + FIXP_DBL tmp, absTmp, absDet; + + absDet = fixp_abs(ac.det); + + if (!useLP) { + tmp = (fMultDiv2(ac.r01r, ac.r12r) >> (LPC_SCALE_FACTOR - 1)) - + ((fMultDiv2(ac.r01i, ac.r12i) + fMultDiv2(ac.r02r, ac.r11r)) >> + (LPC_SCALE_FACTOR - 1)); + } else { + tmp = (fMultDiv2(ac.r01r, ac.r12r) >> (LPC_SCALE_FACTOR - 1)) - + (fMultDiv2(ac.r02r, ac.r11r) >> (LPC_SCALE_FACTOR - 1)); + } + absTmp = fixp_abs(tmp); + + /* + Quick check: is first filter coeff >= 1(4) + */ + { + INT scale; + FIXP_DBL result = fDivNorm(absTmp, absDet, &scale); + scale = scale + ac.det_scale; + + if ((scale > 0) && (result >= (FIXP_DBL)MAXVAL_DBL >> scale)) { + resetLPCCoeffs = 1; + } else { + alphar[1] = FX_DBL2FX_SGL(scaleValue(result, scale)); + if ((tmp < FL2FX_DBL(0.0f)) ^ (ac.det < FL2FX_DBL(0.0f))) { + alphar[1] = -alphar[1]; + } + } + } + + if (!useLP) { + tmp = (fMultDiv2(ac.r01i, ac.r12r) >> (LPC_SCALE_FACTOR - 1)) + + ((fMultDiv2(ac.r01r, ac.r12i) - + (FIXP_DBL)fMultDiv2(ac.r02i, ac.r11r)) >> + (LPC_SCALE_FACTOR - 1)); + + absTmp = fixp_abs(tmp); + + /* + Quick check: is second filter coeff >= 1(4) + */ + { + INT scale; + FIXP_DBL result = fDivNorm(absTmp, absDet, &scale); + scale = scale + ac.det_scale; + + if ((scale > 0) && + (result >= /*FL2FXCONST_DBL(1.f)*/ (FIXP_DBL)MAXVAL_DBL >> + scale)) { + resetLPCCoeffs = 1; + } else { + alphai[1] = FX_DBL2FX_SGL(scaleValue(result, scale)); + if ((tmp < FL2FX_DBL(0.0f)) ^ (ac.det < FL2FX_DBL(0.0f))) { + alphai[1] = -alphai[1]; + } + } + } + } + } + + alphar[0] = FL2FXCONST_SGL(0.0f); + if (!useLP) alphai[0] = FL2FXCONST_SGL(0.0f); + + if (ac.r11r != FL2FXCONST_DBL(0.0f)) { + /* ac.r11r is always >=0 */ + FIXP_DBL tmp, absTmp; + + if (!useLP) { + tmp = (ac.r01r >> (LPC_SCALE_FACTOR + 1)) + + (fMultDiv2(alphar[1], ac.r12r) + fMultDiv2(alphai[1], ac.r12i)); + } else { + if (ac.r01r >= FL2FXCONST_DBL(0.0f)) + tmp = (ac.r01r >> (LPC_SCALE_FACTOR + 1)) + + fMultDiv2(alphar[1], ac.r12r); + else + tmp = -((-ac.r01r) >> (LPC_SCALE_FACTOR + 1)) + + fMultDiv2(alphar[1], ac.r12r); + } + + absTmp = fixp_abs(tmp); + + /* + Quick check: is first filter coeff >= 1(4) + */ + + if (absTmp >= (ac.r11r >> 1)) { + resetLPCCoeffs = 1; + } else { + INT scale; + FIXP_DBL result = fDivNorm(absTmp, fixp_abs(ac.r11r), &scale); + alphar[0] = FX_DBL2FX_SGL(scaleValue(result, scale + 1)); + + if ((tmp > FL2FX_DBL(0.0f)) ^ (ac.r11r < FL2FX_DBL(0.0f))) + alphar[0] = -alphar[0]; + } + + if (!useLP) { + tmp = (ac.r01i >> (LPC_SCALE_FACTOR + 1)) + + (fMultDiv2(alphai[1], ac.r12r) - fMultDiv2(alphar[1], ac.r12i)); + + absTmp = fixp_abs(tmp); + + /* + Quick check: is second filter coeff >= 1(4) + */ + if (absTmp >= (ac.r11r >> 1)) { + resetLPCCoeffs = 1; + } else { + INT scale; + FIXP_DBL result = fDivNorm(absTmp, fixp_abs(ac.r11r), &scale); + alphai[0] = FX_DBL2FX_SGL(scaleValue(result, scale + 1)); + if ((tmp > FL2FX_DBL(0.0f)) ^ (ac.r11r < FL2FX_DBL(0.0f))) + alphai[0] = -alphai[0]; + } + } + } + + if (!useLP) { + /* Now check the quadratic criteria */ + if ((fMultDiv2(alphar[0], alphar[0]) + fMultDiv2(alphai[0], alphai[0])) >= + FL2FXCONST_DBL(0.5f)) + resetLPCCoeffs = 1; + if ((fMultDiv2(alphar[1], alphar[1]) + fMultDiv2(alphai[1], alphai[1])) >= + FL2FXCONST_DBL(0.5f)) + resetLPCCoeffs = 1; + } + + if (resetLPCCoeffs) { + alphar[0] = FL2FXCONST_SGL(0.0f); + alphar[1] = FL2FXCONST_SGL(0.0f); + if (!useLP) { + alphai[0] = FL2FXCONST_SGL(0.0f); + alphai[1] = FL2FXCONST_SGL(0.0f); + } + } + + if (useLP) { + /* Aliasing detection */ + if (ac.r11r == FL2FXCONST_DBL(0.0f)) { + k1 = FL2FXCONST_DBL(0.0f); + } else { + if (fixp_abs(ac.r01r) >= fixp_abs(ac.r11r)) { + if (fMultDiv2(ac.r01r, ac.r11r) < FL2FX_DBL(0.0f)) { + k1 = (FIXP_DBL)MAXVAL_DBL /*FL2FXCONST_SGL(1.0f)*/; + } else { + /* Since this value is squared later, it must not ever become -1.0f. + */ + k1 = (FIXP_DBL)(MINVAL_DBL + 1) /*FL2FXCONST_SGL(-1.0f)*/; + } + } else { + INT scale; + FIXP_DBL result = + fDivNorm(fixp_abs(ac.r01r), fixp_abs(ac.r11r), &scale); + k1 = scaleValue(result, scale); + + if (!((ac.r01r < FL2FX_DBL(0.0f)) ^ (ac.r11r < FL2FX_DBL(0.0f)))) { + k1 = -k1; + } + } + } + if ((loBand > 1) && (loBand < v_k_master0)) { + /* Check if the gain should be locked */ + FIXP_DBL deg = + /*FL2FXCONST_DBL(1.0f)*/ (FIXP_DBL)MAXVAL_DBL - fPow2(k1_below); + degreeAlias[loBand] = FL2FXCONST_DBL(0.0f); + if (((loBand & 1) == 0) && (k1 < FL2FXCONST_DBL(0.0f))) { + if (k1_below < FL2FXCONST_DBL(0.0f)) { /* 2-Ch Aliasing Detection */ + degreeAlias[loBand] = (FIXP_DBL)MAXVAL_DBL /*FL2FXCONST_DBL(1.0f)*/; + if (k1_below2 > + FL2FXCONST_DBL(0.0f)) { /* 3-Ch Aliasing Detection */ + degreeAlias[loBand - 1] = deg; + } + } else if (k1_below2 > + FL2FXCONST_DBL(0.0f)) { /* 3-Ch Aliasing Detection */ + degreeAlias[loBand] = deg; + } + } + if (((loBand & 1) == 1) && (k1 > FL2FXCONST_DBL(0.0f))) { + if (k1_below > FL2FXCONST_DBL(0.0f)) { /* 2-CH Aliasing Detection */ + degreeAlias[loBand] = (FIXP_DBL)MAXVAL_DBL /*FL2FXCONST_DBL(1.0f)*/; + if (k1_below2 < + FL2FXCONST_DBL(0.0f)) { /* 3-CH Aliasing Detection */ + degreeAlias[loBand - 1] = deg; + } + } else if (k1_below2 < + FL2FXCONST_DBL(0.0f)) { /* 3-CH Aliasing Detection */ + degreeAlias[loBand] = deg; + } + } + } + /* remember k1 values of the 2 QMF channels below the current channel */ + k1_below2 = k1_below; + k1_below = k1; + } + + patch = 0; + + while (patch < pSettings->noOfPatches) { /* inner loop over every patch */ + + int hiBand = loBand + patchParam[patch].targetBandOffs; + + if (loBand < patchParam[patch].sourceStartBand || + loBand >= patchParam[patch].sourceStopBand + //|| hiBand >= hLppTrans->pSettings->noChannels + ) { + /* Lowband not in current patch - proceed */ + patch++; + continue; + } + + FDK_ASSERT(hiBand < (64)); + + /* bwIndex[patch] is already initialized with value from previous band + * inside this patch */ + while (hiBand >= pSettings->bwBorders[bwIndex[patch]] && + bwIndex[patch] < MAX_NUM_PATCHES - 1) { + bwIndex[patch]++; + } + + /* + Filter Step 2: add the left slope with the current filter to the buffer + pure source values are already in there + */ + bw = FX_DBL2FX_SGL(bwVector[bwIndex[patch]]); + + a0r = FX_DBL2FX_SGL( + fMult(bw, alphar[0])); /* Apply current bandwidth expansion factor */ + + if (!useLP) a0i = FX_DBL2FX_SGL(fMult(bw, alphai[0])); + bw = FX_DBL2FX_SGL(fPow2(bw)); + a1r = FX_DBL2FX_SGL(fMult(bw, alphar[1])); + if (!useLP) a1i = FX_DBL2FX_SGL(fMult(bw, alphai[1])); + + /* + Filter Step 3: insert the middle part which won't be windowed + */ + if (bw <= FL2FXCONST_SGL(0.0f)) { + if (!useLP) { + int descale = + fixMin(DFRACT_BITS - 1, (LPC_SCALE_FACTOR + dynamicScale)); + for (i = startSample; i < stopSample; i++) { + FIXP_DBL accu1, accu2; + accu1 = lowBandReal[LPC_ORDER + i] >> descale; + accu2 = lowBandImag[LPC_ORDER + i] >> descale; + if (fPreWhitening) { + accu1 = scaleValueSaturate( + fMultDiv2(accu1, preWhiteningGains[loBand]), + preWhiteningGains_exp[loBand] + 1); + accu2 = scaleValueSaturate( + fMultDiv2(accu2, preWhiteningGains[loBand]), + preWhiteningGains_exp[loBand] + 1); + } + qmfBufferReal[i][hiBand] = accu1; + qmfBufferImag[i][hiBand] = accu2; + } + } else { + int descale = + fixMin(DFRACT_BITS - 1, (LPC_SCALE_FACTOR + dynamicScale)); + for (i = startSample; i < stopSample; i++) { + qmfBufferReal[i][hiBand] = lowBandReal[LPC_ORDER + i] >> descale; + } + } + } else { /* bw <= 0 */ + + if (!useLP) { + int descale = + fixMin(DFRACT_BITS - 1, (LPC_SCALE_FACTOR + dynamicScale)); +#ifdef FUNCTION_LPPTRANSPOSER_func1 + lppTransposer_func1( + lowBandReal + LPC_ORDER + startSample, + lowBandImag + LPC_ORDER + startSample, + qmfBufferReal + startSample, qmfBufferImag + startSample, + stopSample - startSample, (int)hiBand, dynamicScale, descale, a0r, + a0i, a1r, a1i, fPreWhitening, preWhiteningGains[loBand], + preWhiteningGains_exp[loBand] + 1); +#else + for (i = startSample; i < stopSample; i++) { + FIXP_DBL accu1, accu2; + + accu1 = (fMultDiv2(a0r, lowBandReal[LPC_ORDER + i - 1]) - + fMultDiv2(a0i, lowBandImag[LPC_ORDER + i - 1]) + + fMultDiv2(a1r, lowBandReal[LPC_ORDER + i - 2]) - + fMultDiv2(a1i, lowBandImag[LPC_ORDER + i - 2])) >> + dynamicScale; + accu2 = (fMultDiv2(a0i, lowBandReal[LPC_ORDER + i - 1]) + + fMultDiv2(a0r, lowBandImag[LPC_ORDER + i - 1]) + + fMultDiv2(a1i, lowBandReal[LPC_ORDER + i - 2]) + + fMultDiv2(a1r, lowBandImag[LPC_ORDER + i - 2])) >> + dynamicScale; + + accu1 = (lowBandReal[LPC_ORDER + i] >> descale) + (accu1 << 1); + accu2 = (lowBandImag[LPC_ORDER + i] >> descale) + (accu2 << 1); + if (fPreWhitening) { + accu1 = scaleValueSaturate( + fMultDiv2(accu1, preWhiteningGains[loBand]), + preWhiteningGains_exp[loBand] + 1); + accu2 = scaleValueSaturate( + fMultDiv2(accu2, preWhiteningGains[loBand]), + preWhiteningGains_exp[loBand] + 1); + } + qmfBufferReal[i][hiBand] = accu1; + qmfBufferImag[i][hiBand] = accu2; + } +#endif + } else { + FDK_ASSERT(dynamicScale >= 0); + calc_qmfBufferReal( + qmfBufferReal, &(lowBandReal[LPC_ORDER + startSample - 2]), + startSample, stopSample, hiBand, dynamicScale, + fMin(DFRACT_BITS - 1, (LPC_SCALE_FACTOR + dynamicScale)), a0r, + a1r); + } + } /* bw <= 0 */ + + patch++; + + } /* inner loop over patches */ + + /* + * store the unmodified filter coefficients if there is + * an overlapping envelope + *****************************************************************/ + + } /* outer loop over bands (loBand) */ + + if (useLP) { + for (loBand = pSettings->lbStartPatching; + loBand < pSettings->lbStopPatching; loBand++) { + patch = 0; + while (patch < pSettings->noOfPatches) { + UCHAR hiBand = loBand + patchParam[patch].targetBandOffs; + + if (loBand < patchParam[patch].sourceStartBand || + loBand >= patchParam[patch].sourceStopBand || + hiBand >= (64) /* Highband out of range (biterror) */ + ) { + /* Lowband not in current patch or highband out of range (might be + * caused by biterrors)- proceed */ + patch++; + continue; + } + + if (hiBand != patchParam[patch].targetStartBand) + degreeAlias[hiBand] = degreeAlias[loBand]; + + patch++; + } + } /* end for loop */ + } + + for (i = 0; i < nInvfBands; i++) { + hLppTrans->bwVectorOld[i] = bwVector[i]; + } + + /* + set high band scale factor + */ + sbrScaleFactor->hb_scale = comLowBandScale - (LPC_SCALE_FACTOR); +} + +void lppTransposerHBE( + HANDLE_SBR_LPP_TRANS hLppTrans, /*!< Handle of lpp transposer */ + HANDLE_HBE_TRANSPOSER hQmfTransposer, + QMF_SCALE_FACTOR *sbrScaleFactor, /*!< Scaling factors */ + FIXP_DBL **qmfBufferReal, /*!< Pointer to pointer to real part of subband + samples (source) */ + FIXP_DBL **qmfBufferImag, /*!< Pointer to pointer to imaginary part of + subband samples (source) */ + const int timeStep, /*!< Time step of envelope */ + const int firstSlotOffs, /*!< Start position in time */ + const int lastSlotOffs, /*!< Number of overlap-slots into next frame */ + const int nInvfBands, /*!< Number of bands for inverse filtering */ + INVF_MODE *sbr_invf_mode, /*!< Current inverse filtering modes */ + INVF_MODE *sbr_invf_mode_prev /*!< Previous inverse filtering modes */ +) { + INT bwIndex; + FIXP_DBL bwVector[MAX_NUM_PATCHES_HBE]; /*!< pole moving factors */ + + int i; + int loBand, start, stop; + TRANSPOSER_SETTINGS *pSettings = hLppTrans->pSettings; + PATCH_PARAM *patchParam = pSettings->patchParam; + + FIXP_SGL alphar[LPC_ORDER], a0r, a1r; + FIXP_SGL alphai[LPC_ORDER], a0i = 0, a1i = 0; + FIXP_SGL bw = FL2FXCONST_SGL(0.0f); + + int autoCorrLength; + + ACORR_COEFS ac; + int startSample; + int stopSample; + int stopSampleClear; + + int comBandScale; + int ovLowBandShift; + int lowBandShift; + /* int ovHighBandShift;*/ + + alphai[0] = FL2FXCONST_SGL(0.0f); + alphai[1] = FL2FXCONST_SGL(0.0f); + + startSample = firstSlotOffs * timeStep; + stopSample = pSettings->nCols + lastSlotOffs * timeStep; + + inverseFilteringLevelEmphasis(hLppTrans, nInvfBands, sbr_invf_mode, + sbr_invf_mode_prev, bwVector); + + stopSampleClear = stopSample; + + autoCorrLength = pSettings->nCols + pSettings->overlap; + + if (pSettings->noOfPatches > 0) { + /* Set upper subbands to zero: + This is required in case that the patches do not cover the complete + highband (because the last patch would be too short). Possible + optimization: Clearing bands up to usb would be sufficient here. */ + int targetStopBand = + patchParam[pSettings->noOfPatches - 1].targetStartBand + + patchParam[pSettings->noOfPatches - 1].numBandsInPatch; + + int memSize = ((64) - targetStopBand) * sizeof(FIXP_DBL); + + for (i = startSample; i < stopSampleClear; i++) { + FDKmemclear(&qmfBufferReal[i][targetStopBand], memSize); + FDKmemclear(&qmfBufferImag[i][targetStopBand], memSize); + } + } +#ifdef __ANDROID__ + else { + // Safetynet logging + android_errorWriteLog(0x534e4554, "112160868"); + } +#endif + + /* + Calc common low band scale factor + */ + comBandScale = sbrScaleFactor->hb_scale; + + ovLowBandShift = sbrScaleFactor->hb_scale - comBandScale; + lowBandShift = sbrScaleFactor->hb_scale - comBandScale; + /* ovHighBandShift = firstSlotOffs == 0 ? ovLowBandShift:0;*/ + + /* outer loop over bands to do analysis only once for each band */ + + start = hQmfTransposer->startBand; + stop = hQmfTransposer->stopBand; + + for (loBand = start; loBand < stop; loBand++) { + bwIndex = 0; + + FIXP_DBL lowBandReal[(((1024) / (32) * (4) / 2) + (3 * (4))) + LPC_ORDER]; + FIXP_DBL lowBandImag[(((1024) / (32) * (4) / 2) + (3 * (4))) + LPC_ORDER]; + + int resetLPCCoeffs = 0; + int dynamicScale = DFRACT_BITS - 1 - LPC_SCALE_FACTOR; + int acDetScale = 0; /* scaling of autocorrelation determinant */ + + for (i = 0; i < LPC_ORDER; i++) { + lowBandReal[i] = hLppTrans->lpcFilterStatesRealHBE[i][loBand]; + lowBandImag[i] = hLppTrans->lpcFilterStatesImagHBE[i][loBand]; + } + + for (; i < LPC_ORDER + firstSlotOffs * timeStep; i++) { + lowBandReal[i] = hLppTrans->lpcFilterStatesRealHBE[i][loBand]; + lowBandImag[i] = hLppTrans->lpcFilterStatesImagHBE[i][loBand]; + } + + /* + Take old slope length qmf slot source values out of (overlap)qmf buffer + */ + for (i = firstSlotOffs * timeStep; + i < pSettings->nCols + pSettings->overlap; i++) { + lowBandReal[i + LPC_ORDER] = qmfBufferReal[i][loBand]; + lowBandImag[i + LPC_ORDER] = qmfBufferImag[i][loBand]; + } + + /* store unmodified values to buffer */ + for (i = 0; i < LPC_ORDER + pSettings->overlap; i++) { + hLppTrans->lpcFilterStatesRealHBE[i][loBand] = + qmfBufferReal[pSettings->nCols - LPC_ORDER + i][loBand]; + hLppTrans->lpcFilterStatesImagHBE[i][loBand] = + qmfBufferImag[pSettings->nCols - LPC_ORDER + i][loBand]; + } + + /* + Determine dynamic scaling value. + */ + dynamicScale = + fixMin(dynamicScale, + getScalefactor(lowBandReal, LPC_ORDER + pSettings->overlap) + + ovLowBandShift); + dynamicScale = + fixMin(dynamicScale, + getScalefactor(&lowBandReal[LPC_ORDER + pSettings->overlap], + pSettings->nCols) + + lowBandShift); + dynamicScale = + fixMin(dynamicScale, + getScalefactor(lowBandImag, LPC_ORDER + pSettings->overlap) + + ovLowBandShift); + dynamicScale = + fixMin(dynamicScale, + getScalefactor(&lowBandImag[LPC_ORDER + pSettings->overlap], + pSettings->nCols) + + lowBandShift); + + dynamicScale = fixMax( + 0, dynamicScale - 1); /* one additional bit headroom to prevent -1.0 */ + + /* + Scale temporal QMF buffer. + */ + scaleValues(&lowBandReal[0], LPC_ORDER + pSettings->overlap, + dynamicScale - ovLowBandShift); + scaleValues(&lowBandReal[LPC_ORDER + pSettings->overlap], pSettings->nCols, + dynamicScale - lowBandShift); + scaleValues(&lowBandImag[0], LPC_ORDER + pSettings->overlap, + dynamicScale - ovLowBandShift); + scaleValues(&lowBandImag[LPC_ORDER + pSettings->overlap], pSettings->nCols, + dynamicScale - lowBandShift); + + acDetScale += autoCorr2nd_cplx(&ac, lowBandReal + LPC_ORDER, + lowBandImag + LPC_ORDER, autoCorrLength); + + /* Examine dynamic of determinant in autocorrelation. */ + acDetScale += 2 * (comBandScale + dynamicScale); + acDetScale *= 2; /* two times reflection coefficent scaling */ + acDetScale += ac.det_scale; /* ac scaling of determinant */ + + /* In case of determinant < 10^-38, resetLPCCoeffs=1 has to be enforced. */ + if (acDetScale > 126) { + resetLPCCoeffs = 1; + } + + alphar[1] = FL2FXCONST_SGL(0.0f); + alphai[1] = FL2FXCONST_SGL(0.0f); + + if (ac.det != FL2FXCONST_DBL(0.0f)) { + FIXP_DBL tmp, absTmp, absDet; + + absDet = fixp_abs(ac.det); + + tmp = (fMultDiv2(ac.r01r, ac.r12r) >> (LPC_SCALE_FACTOR - 1)) - + ((fMultDiv2(ac.r01i, ac.r12i) + fMultDiv2(ac.r02r, ac.r11r)) >> + (LPC_SCALE_FACTOR - 1)); + absTmp = fixp_abs(tmp); + + /* + Quick check: is first filter coeff >= 1(4) + */ + { + INT scale; + FIXP_DBL result = fDivNorm(absTmp, absDet, &scale); + scale = scale + ac.det_scale; + + if ((scale > 0) && (result >= (FIXP_DBL)MAXVAL_DBL >> scale)) { + resetLPCCoeffs = 1; + } else { + alphar[1] = FX_DBL2FX_SGL(scaleValue(result, scale)); + if ((tmp < FL2FX_DBL(0.0f)) ^ (ac.det < FL2FX_DBL(0.0f))) { + alphar[1] = -alphar[1]; + } + } + } + + tmp = (fMultDiv2(ac.r01i, ac.r12r) >> (LPC_SCALE_FACTOR - 1)) + + ((fMultDiv2(ac.r01r, ac.r12i) - + (FIXP_DBL)fMultDiv2(ac.r02i, ac.r11r)) >> + (LPC_SCALE_FACTOR - 1)); + + absTmp = fixp_abs(tmp); + + /* + Quick check: is second filter coeff >= 1(4) + */ + { + INT scale; + FIXP_DBL result = fDivNorm(absTmp, absDet, &scale); + scale = scale + ac.det_scale; + + if ((scale > 0) && + (result >= /*FL2FXCONST_DBL(1.f)*/ (FIXP_DBL)MAXVAL_DBL >> scale)) { + resetLPCCoeffs = 1; + } else { + alphai[1] = FX_DBL2FX_SGL(scaleValue(result, scale)); + if ((tmp < FL2FX_DBL(0.0f)) ^ (ac.det < FL2FX_DBL(0.0f))) { + alphai[1] = -alphai[1]; + } + } + } + } + + alphar[0] = FL2FXCONST_SGL(0.0f); + alphai[0] = FL2FXCONST_SGL(0.0f); + + if (ac.r11r != FL2FXCONST_DBL(0.0f)) { + /* ac.r11r is always >=0 */ + FIXP_DBL tmp, absTmp; + + tmp = (ac.r01r >> (LPC_SCALE_FACTOR + 1)) + + (fMultDiv2(alphar[1], ac.r12r) + fMultDiv2(alphai[1], ac.r12i)); + + absTmp = fixp_abs(tmp); + + /* + Quick check: is first filter coeff >= 1(4) + */ + + if (absTmp >= (ac.r11r >> 1)) { + resetLPCCoeffs = 1; + } else { + INT scale; + FIXP_DBL result = fDivNorm(absTmp, fixp_abs(ac.r11r), &scale); + alphar[0] = FX_DBL2FX_SGL(scaleValue(result, scale + 1)); + + if ((tmp > FL2FX_DBL(0.0f)) ^ (ac.r11r < FL2FX_DBL(0.0f))) + alphar[0] = -alphar[0]; + } + + tmp = (ac.r01i >> (LPC_SCALE_FACTOR + 1)) + + (fMultDiv2(alphai[1], ac.r12r) - fMultDiv2(alphar[1], ac.r12i)); + + absTmp = fixp_abs(tmp); + + /* + Quick check: is second filter coeff >= 1(4) + */ + if (absTmp >= (ac.r11r >> 1)) { + resetLPCCoeffs = 1; + } else { + INT scale; + FIXP_DBL result = fDivNorm(absTmp, fixp_abs(ac.r11r), &scale); + alphai[0] = FX_DBL2FX_SGL(scaleValue(result, scale + 1)); + if ((tmp > FL2FX_DBL(0.0f)) ^ (ac.r11r < FL2FX_DBL(0.0f))) { + alphai[0] = -alphai[0]; + } + } + } + + /* Now check the quadratic criteria */ + if ((fMultDiv2(alphar[0], alphar[0]) + fMultDiv2(alphai[0], alphai[0])) >= + FL2FXCONST_DBL(0.5f)) { + resetLPCCoeffs = 1; + } + if ((fMultDiv2(alphar[1], alphar[1]) + fMultDiv2(alphai[1], alphai[1])) >= + FL2FXCONST_DBL(0.5f)) { + resetLPCCoeffs = 1; + } + + if (resetLPCCoeffs) { + alphar[0] = FL2FXCONST_SGL(0.0f); + alphar[1] = FL2FXCONST_SGL(0.0f); + alphai[0] = FL2FXCONST_SGL(0.0f); + alphai[1] = FL2FXCONST_SGL(0.0f); + } + + while (bwIndex < MAX_NUM_PATCHES - 1 && + loBand >= pSettings->bwBorders[bwIndex]) { + bwIndex++; + } + + /* + Filter Step 2: add the left slope with the current filter to the buffer + pure source values are already in there + */ + bw = FX_DBL2FX_SGL(bwVector[bwIndex]); + + a0r = FX_DBL2FX_SGL( + fMult(bw, alphar[0])); /* Apply current bandwidth expansion factor */ + a0i = FX_DBL2FX_SGL(fMult(bw, alphai[0])); + bw = FX_DBL2FX_SGL(fPow2(bw)); + a1r = FX_DBL2FX_SGL(fMult(bw, alphar[1])); + a1i = FX_DBL2FX_SGL(fMult(bw, alphai[1])); + + /* + Filter Step 3: insert the middle part which won't be windowed + */ + if (bw <= FL2FXCONST_SGL(0.0f)) { + int descale = fixMin(DFRACT_BITS - 1, (LPC_SCALE_FACTOR + dynamicScale)); + for (i = startSample; i < stopSample; i++) { + qmfBufferReal[i][loBand] = lowBandReal[LPC_ORDER + i] >> descale; + qmfBufferImag[i][loBand] = lowBandImag[LPC_ORDER + i] >> descale; + } + } else { /* bw <= 0 */ + + int descale = fixMin(DFRACT_BITS - 1, (LPC_SCALE_FACTOR + dynamicScale)); + + for (i = startSample; i < stopSample; i++) { + FIXP_DBL accu1, accu2; + + accu1 = (fMultDiv2(a0r, lowBandReal[LPC_ORDER + i - 1]) - + fMultDiv2(a0i, lowBandImag[LPC_ORDER + i - 1]) + + fMultDiv2(a1r, lowBandReal[LPC_ORDER + i - 2]) - + fMultDiv2(a1i, lowBandImag[LPC_ORDER + i - 2])) >> + dynamicScale; + accu2 = (fMultDiv2(a0i, lowBandReal[LPC_ORDER + i - 1]) + + fMultDiv2(a0r, lowBandImag[LPC_ORDER + i - 1]) + + fMultDiv2(a1i, lowBandReal[LPC_ORDER + i - 2]) + + fMultDiv2(a1r, lowBandImag[LPC_ORDER + i - 2])) >> + dynamicScale; + + qmfBufferReal[i][loBand] = + (lowBandReal[LPC_ORDER + i] >> descale) + (accu1 << 1); + qmfBufferImag[i][loBand] = + (lowBandImag[LPC_ORDER + i] >> descale) + (accu2 << 1); + } + } /* bw <= 0 */ + + /* + * store the unmodified filter coefficients if there is + * an overlapping envelope + *****************************************************************/ + + } /* outer loop over bands (loBand) */ + + for (i = 0; i < nInvfBands; i++) { + hLppTrans->bwVectorOld[i] = bwVector[i]; + } + + /* + set high band scale factor + */ + sbrScaleFactor->hb_scale = comBandScale - (LPC_SCALE_FACTOR); +} + +/*! + * + * \brief Initialize one low power transposer instance + * + * + */ +SBR_ERROR +createLppTransposer( + HANDLE_SBR_LPP_TRANS hs, /*!< Handle of low power transposer */ + TRANSPOSER_SETTINGS *pSettings, /*!< Pointer to settings */ + const int highBandStartSb, /*!< ? */ + UCHAR *v_k_master, /*!< Master table */ + const int numMaster, /*!< Valid entries in master table */ + const int usb, /*!< Highband area stop subband */ + const int timeSlots, /*!< Number of time slots */ + const int nCols, /*!< Number of colums (codec qmf bank) */ + UCHAR *noiseBandTable, /*!< Mapping of SBR noise bands to QMF bands */ + const int noNoiseBands, /*!< Number of noise bands */ + UINT fs, /*!< Sample Frequency */ + const int chan, /*!< Channel number */ + const int overlap) { + /* FB inverse filtering settings */ + hs->pSettings = pSettings; + + pSettings->nCols = nCols; + pSettings->overlap = overlap; + + switch (timeSlots) { + case 15: + case 16: + break; + + default: + return SBRDEC_UNSUPPORTED_CONFIG; /* Unimplemented */ + } + + if (chan == 0) { + /* Init common data only once */ + hs->pSettings->nCols = nCols; + + return resetLppTransposer(hs, highBandStartSb, v_k_master, numMaster, + noiseBandTable, noNoiseBands, usb, fs); + } + return SBRDEC_OK; +} + +static int findClosestEntry(UCHAR goalSb, UCHAR *v_k_master, UCHAR numMaster, + UCHAR direction) { + int index; + + if (goalSb <= v_k_master[0]) return v_k_master[0]; + + if (goalSb >= v_k_master[numMaster]) return v_k_master[numMaster]; + + if (direction) { + index = 0; + while (v_k_master[index] < goalSb) { + index++; + } + } else { + index = numMaster; + while (v_k_master[index] > goalSb) { + index--; + } + } + + return v_k_master[index]; +} + +/*! + * + * \brief Reset memory for one lpp transposer instance + * + * \return SBRDEC_OK on success, SBRDEC_UNSUPPORTED_CONFIG on error + */ +SBR_ERROR +resetLppTransposer( + HANDLE_SBR_LPP_TRANS hLppTrans, /*!< Handle of lpp transposer */ + UCHAR highBandStartSb, /*!< High band area: start subband */ + UCHAR *v_k_master, /*!< Master table */ + UCHAR numMaster, /*!< Valid entries in master table */ + UCHAR *noiseBandTable, /*!< Mapping of SBR noise bands to QMF bands */ + UCHAR noNoiseBands, /*!< Number of noise bands */ + UCHAR usb, /*!< High band area: stop subband */ + UINT fs /*!< SBR output sampling frequency */ +) { + TRANSPOSER_SETTINGS *pSettings = hLppTrans->pSettings; + PATCH_PARAM *patchParam = pSettings->patchParam; + + int i, patch; + int targetStopBand; + int sourceStartBand; + int patchDistance; + int numBandsInPatch; + + int lsb = v_k_master[0]; /* Start subband expressed in "non-critical" sampling + terms*/ + int xoverOffset = highBandStartSb - + lsb; /* Calculate distance in QMF bands between k0 and kx */ + int startFreqHz; + + int desiredBorder; + + usb = fixMin(usb, v_k_master[numMaster]); /* Avoid endless loops (compare with + float code). */ + + /* + * Plausibility check + */ + + if (pSettings->nCols == 64) { + if (lsb < 4) { + /* 4:1 SBR Requirement k0 >= 4 missed! */ + return SBRDEC_UNSUPPORTED_CONFIG; + } + } else if (lsb - SHIFT_START_SB < 4) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + /* + * Initialize the patching parameter + */ + /* ISO/IEC 14496-3 (Figure 4.48): goalSb = round( 2.048e6 / fs ) */ + desiredBorder = (((2048000 * 2) / fs) + 1) >> 1; + + desiredBorder = findClosestEntry(desiredBorder, v_k_master, numMaster, + 1); /* Adapt region to master-table */ + + /* First patch */ + sourceStartBand = SHIFT_START_SB + xoverOffset; + targetStopBand = lsb + xoverOffset; /* upperBand */ + + /* Even (odd) numbered channel must be patched to even (odd) numbered channel + */ + patch = 0; + while (targetStopBand < usb) { + /* Too many patches? + Allow MAX_NUM_PATCHES+1 patches here. + we need to check later again, since patch might be the highest patch + AND contain less than 3 bands => actual number of patches will be reduced + by 1. + */ + if (patch > MAX_NUM_PATCHES) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + patchParam[patch].guardStartBand = targetStopBand; + patchParam[patch].targetStartBand = targetStopBand; + + numBandsInPatch = + desiredBorder - targetStopBand; /* Get the desired range of the patch */ + + if (numBandsInPatch >= lsb - sourceStartBand) { + /* Desired number bands are not available -> patch whole source range */ + patchDistance = + targetStopBand - sourceStartBand; /* Get the targetOffset */ + patchDistance = + patchDistance & ~1; /* Rounding off odd numbers and make all even */ + numBandsInPatch = + lsb - (targetStopBand - + patchDistance); /* Update number of bands to be patched */ + numBandsInPatch = findClosestEntry(targetStopBand + numBandsInPatch, + v_k_master, numMaster, 0) - + targetStopBand; /* Adapt region to master-table */ + } + + if (pSettings->nCols == 64) { + if (numBandsInPatch == 0 && sourceStartBand == SHIFT_START_SB) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + } + + /* Desired number bands are available -> get the minimal even patching + * distance */ + patchDistance = + numBandsInPatch + targetStopBand - lsb; /* Get minimal distance */ + patchDistance = (patchDistance + 1) & + ~1; /* Rounding up odd numbers and make all even */ + + if (numBandsInPatch > 0) { + patchParam[patch].sourceStartBand = targetStopBand - patchDistance; + patchParam[patch].targetBandOffs = patchDistance; + patchParam[patch].numBandsInPatch = numBandsInPatch; + patchParam[patch].sourceStopBand = + patchParam[patch].sourceStartBand + numBandsInPatch; + + targetStopBand += patchParam[patch].numBandsInPatch; + patch++; + } + + /* All patches but first */ + sourceStartBand = SHIFT_START_SB; + + /* Check if we are close to desiredBorder */ + if (desiredBorder - targetStopBand < 3) /* MPEG doc */ + { + desiredBorder = usb; + } + } + + patch--; + + /* If highest patch contains less than three subband: skip it */ + if ((patch > 0) && (patchParam[patch].numBandsInPatch < 3)) { + patch--; + targetStopBand = + patchParam[patch].targetStartBand + patchParam[patch].numBandsInPatch; + } + + /* now check if we don't have one too many */ + if (patch >= MAX_NUM_PATCHES) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + pSettings->noOfPatches = patch + 1; + + /* Check lowest and highest source subband */ + pSettings->lbStartPatching = targetStopBand; + pSettings->lbStopPatching = 0; + for (patch = 0; patch < pSettings->noOfPatches; patch++) { + pSettings->lbStartPatching = + fixMin(pSettings->lbStartPatching, patchParam[patch].sourceStartBand); + pSettings->lbStopPatching = + fixMax(pSettings->lbStopPatching, patchParam[patch].sourceStopBand); + } + + for (i = 0; i < noNoiseBands; i++) { + pSettings->bwBorders[i] = noiseBandTable[i + 1]; + } + for (; i < MAX_NUM_NOISE_VALUES; i++) { + pSettings->bwBorders[i] = 255; + } + + /* + * Choose whitening factors + */ + + startFreqHz = + ((lsb + xoverOffset) * fs) >> 7; /* Shift does a division by 2*(64) */ + + for (i = 1; i < NUM_WHFACTOR_TABLE_ENTRIES; i++) { + if (startFreqHz < FDK_sbrDecoder_sbr_whFactorsIndex[i]) break; + } + i--; + + pSettings->whFactors.off = FDK_sbrDecoder_sbr_whFactorsTable[i][0]; + pSettings->whFactors.transitionLevel = + FDK_sbrDecoder_sbr_whFactorsTable[i][1]; + pSettings->whFactors.lowLevel = FDK_sbrDecoder_sbr_whFactorsTable[i][2]; + pSettings->whFactors.midLevel = FDK_sbrDecoder_sbr_whFactorsTable[i][3]; + pSettings->whFactors.highLevel = FDK_sbrDecoder_sbr_whFactorsTable[i][4]; + + return SBRDEC_OK; +} |