diff options
author | Dave Burke <daveburke@google.com> | 2012-04-17 09:51:45 -0700 |
---|---|---|
committer | Dave Burke <daveburke@google.com> | 2012-04-17 23:04:43 -0700 |
commit | 9bf37cc9712506b2483650c82d3c41152337ef7e (patch) | |
tree | 77db44e2bae06e3d144b255628be2b7a55c581d3 /libSBRdec/src/lpp_tran.cpp | |
parent | a37315fe10ee143d6d0b28c19d41a476a23e63ea (diff) | |
download | fdk-aac-9bf37cc9712506b2483650c82d3c41152337ef7e.tar.gz fdk-aac-9bf37cc9712506b2483650c82d3c41152337ef7e.tar.bz2 fdk-aac-9bf37cc9712506b2483650c82d3c41152337ef7e.zip |
Fraunhofer AAC codec.
License boilerplate update to follow.
Change-Id: I2810460c11a58b6d148d84673cc031f3685e79b5
Diffstat (limited to 'libSBRdec/src/lpp_tran.cpp')
-rw-r--r-- | libSBRdec/src/lpp_tran.cpp | 942 |
1 files changed, 942 insertions, 0 deletions
diff --git a/libSBRdec/src/lpp_tran.cpp b/libSBRdec/src/lpp_tran.cpp new file mode 100644 index 0000000..0a7721e --- /dev/null +++ b/libSBRdec/src/lpp_tran.cpp @@ -0,0 +1,942 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Low Power Profile Transposer, $Revision: 36841 $ + 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 +*/ + +#include "lpp_tran.h" + +#include "sbr_ram.h" +#include "sbr_rom.h" + +#include "genericStds.h" +#include "autocorr2nd.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. + */ + +#ifndef FUNCTION_mapInvfMode +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; + } +} +#endif /* #ifndef FUNCTION_mapInvfMode */ + +/*! + * + * \brief Perform inverse filtering level emphasis + * + * Retrieve bandwidth expansion factor and apply smoothing for each filter band + * + */ + +#ifndef FUNCTION_inverseFilteringLevelEmphasis +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)); + } +} +#endif /* #ifndef FUNCTION_inverseFilteringLevelEmphasis */ + +/* 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) + +/*! + * + * \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 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 */ + + 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;*/ + int targetStopBand; + + + 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; + + /* 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. */ + 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); + } + + /* init bwIndex for each patch */ + FDKmemclear(bwIndex, pSettings->noOfPatches*sizeof(INT)); + + /* + 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;*/ + + /* 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))+(6))+LPC_ORDER]; + FIXP_DBL *plowBandReal = lowBandReal; + FIXP_DBL **pqmfBufferReal = qmfBufferReal; + FIXP_DBL lowBandImag[(((1024)/(32))+(6))+LPC_ORDER]; + FIXP_DBL *plowBandImag = lowBandImag; + FIXP_DBL **pqmfBufferImag = qmfBufferImag; + 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++){ + *plowBandReal++ = hLppTrans->lpcFilterStatesReal[i][loBand]; + if (!useLP) + *plowBandImag++ = hLppTrans->lpcFilterStatesImag[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;i++){ + *plowBandReal++ = (*pqmfBufferReal++)[loBand]; + *plowBandImag++ = (*pqmfBufferImag++)[loBand]; + } + } else + { + /* pSettings->overlap is always even */ + FDK_ASSERT((pSettings->overlap & 1) == 0); + + for(i=0;i<((pSettings->overlap+pSettings->nCols)>>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){ + /* 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]++; + + + /* + 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++ ) { + qmfBufferReal[i][hiBand] = lowBandReal[LPC_ORDER+i]>>descale; + qmfBufferImag[i][hiBand] = lowBandImag[LPC_ORDER+i]>>descale; + } + } 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); +#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; + + qmfBufferReal[i][hiBand] = (lowBandReal[LPC_ORDER+i]>>descale) + (accu1<<1); + qmfBufferImag[i][hiBand] = (lowBandImag[LPC_ORDER+i]>>descale) + (accu2<<1); + } +#endif + } else + { + int descale = fixMin(DFRACT_BITS-1, (LPC_SCALE_FACTOR+dynamicScale)); + + FDK_ASSERT(dynamicScale >= 0); + for(i = startSample; i < stopSample; i++ ) { + FIXP_DBL accu1; + + accu1 = (fMultDiv2(a0r,lowBandReal[LPC_ORDER+i-1]) + fMultDiv2(a1r,lowBandReal[LPC_ORDER+i-2]))>>dynamicScale; + + qmfBufferReal[i][hiBand] = (lowBandReal[LPC_ORDER+i]>>descale) + (accu1<<1); + } + } + } /* 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); + +} + +/*! + * + * \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 ( lsb - SHIFT_START_SB < 4 ) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + + /* + * Initialize the patching parameter + */ + desiredBorder = 21; + if (fs < 92017) { + desiredBorder = 23; + } + if (fs < 75132) { + desiredBorder = 32; + } + if (fs < 55426) { + desiredBorder = 43; + } + if (fs < 46009) { + desiredBorder = 46; + } + if (fs < 35777) { + desiredBorder = 64; + } + + 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 */ + } + + /* 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]; + } + + /* + * 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; +} |