summaryrefslogtreecommitdiffstats
path: root/libSBRenc/src/invf_est.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libSBRenc/src/invf_est.cpp')
-rw-r--r--libSBRenc/src/invf_est.cpp472
1 files changed, 472 insertions, 0 deletions
diff --git a/libSBRenc/src/invf_est.cpp b/libSBRenc/src/invf_est.cpp
new file mode 100644
index 0000000..4f4670c
--- /dev/null
+++ b/libSBRenc/src/invf_est.cpp
@@ -0,0 +1,472 @@
+/****************************************************************************
+
+ (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$
+
+*******************************************************************************/
+
+#include "invf_est.h"
+#include "sbr_misc.h"
+
+#include "genericStds.h"
+
+#define MAX_NUM_REGIONS 10
+#define SCALE_FAC_QUO 512.0f
+#define SCALE_FAC_NRG 256.0f
+
+#ifndef min
+#define min(a,b) ( a < b ? a:b)
+#endif
+
+#ifndef max
+#define max(a,b) ( a > b ? a:b)
+#endif
+
+static const FIXP_DBL quantStepsSbr[4] = { 0x00400000, 0x02800000, 0x03800000, 0x04c00000 } ; /* table scaled with SCALE_FAC_QUO */
+static const FIXP_DBL quantStepsOrig[4] = { 0x00000000, 0x00c00000, 0x01c00000, 0x02800000 } ; /* table scaled with SCALE_FAC_QUO */
+static const FIXP_DBL nrgBorders[4] = { 0x0c800000, 0x0f000000, 0x11800000, 0x14000000 } ; /* table scaled with SCALE_FAC_NRG */
+
+static const DETECTOR_PARAMETERS detectorParamsAAC = {
+ quantStepsSbr,
+ quantStepsOrig,
+ nrgBorders,
+ 4, /* Number of borders SBR. */
+ 4, /* Number of borders orig. */
+ 4, /* Number of borders Nrg. */
+ { /* Region space. */
+ {INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF, INVF_OFF}, /* | */
+ {INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF, INVF_OFF}, /* | */
+ {INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF}, /* regionSbr */
+ {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF}, /* | */
+ {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF} /* | */
+ },/*------------------------ regionOrig ---------------------------------*/
+ { /* Region space transient. */
+ {INVF_LOW_LEVEL, INVF_LOW_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF}, /* | */
+ {INVF_LOW_LEVEL, INVF_LOW_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF}, /* | */
+ {INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF}, /* regionSbr */
+ {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF}, /* | */
+ {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF} /* | */
+ },/*------------------------ regionOrig ---------------------------------*/
+ {-4, -3, -2, -1, 0} /* Reduction factor of the inverse filtering for low energies.*/
+};
+
+static const FIXP_DBL hysteresis = 0x00400000 ; /* Delta value for hysteresis. scaled with SCALE_FAC_QUO */
+
+/*
+ * AAC+SBR PARAMETERS for Speech
+ *********************************/
+static const DETECTOR_PARAMETERS detectorParamsAACSpeech = {
+ quantStepsSbr,
+ quantStepsOrig,
+ nrgBorders,
+ 4, /* Number of borders SBR. */
+ 4, /* Number of borders orig. */
+ 4, /* Number of borders Nrg. */
+ { /* Region space. */
+ {INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF}, /* | */
+ {INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF}, /* | */
+ {INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF}, /* regionSbr */
+ {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF}, /* | */
+ {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF} /* | */
+ },/*------------------------ regionOrig ---------------------------------*/
+ { /* Region space transient. */
+ {INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF}, /* | */
+ {INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF}, /* | */
+ {INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF}, /* regionSbr */
+ {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF}, /* | */
+ {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF} /* | */
+ },/*------------------------ regionOrig ---------------------------------*/
+ {-4, -3, -2, -1, 0} /* Reduction factor of the inverse filtering for low energies.*/
+};
+
+/*
+ * Smoothing filters.
+ ************************/
+typedef const FIXP_DBL FIR_FILTER[5];
+
+static const FIR_FILTER fir_0 = { 0x7fffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } ;
+static const FIR_FILTER fir_1 = { 0x2aaaaa80, 0x555554ff, 0x00000000, 0x00000000, 0x00000000 } ;
+static const FIR_FILTER fir_2 = { 0x10000000, 0x30000000, 0x40000000, 0x00000000, 0x00000000 } ;
+static const FIR_FILTER fir_3 = { 0x077f80e8, 0x199999a0, 0x2bb3b240, 0x33333340, 0x00000000 } ;
+static const FIR_FILTER fir_4 = { 0x04130598, 0x0ebdb000, 0x1becfa60, 0x2697a4c0, 0x2aaaaa80 } ;
+
+
+static const FIR_FILTER *const fir_table[5] = {
+ &fir_0,
+ &fir_1,
+ &fir_2,
+ &fir_3,
+ &fir_4
+};
+
+/**************************************************************************/
+/*!
+ \brief Calculates the values used for the detector.
+
+
+ \return none
+
+*/
+/**************************************************************************/
+static void
+calculateDetectorValues(FIXP_DBL **quotaMatrixOrig, /*!< Matrix holding the tonality values of the original. */
+ SCHAR *indexVector, /*!< Index vector to obtain the patched data. */
+ FIXP_DBL *nrgVector, /*!< Energy vector. */
+ DETECTOR_VALUES *detectorValues, /*!< pointer to DETECTOR_VALUES struct. */
+ INT startChannel, /*!< Start channel. */
+ INT stopChannel, /*!< Stop channel. */
+ INT startIndex, /*!< Start index. */
+ INT stopIndex, /*!< Stop index. */
+ INT numberOfStrongest /*!< The number of sorted tonal components to be considered. */
+ )
+{
+ INT i,temp, j;
+
+ const FIXP_DBL* filter = *fir_table[INVF_SMOOTHING_LENGTH];
+ FIXP_DBL origQuotaMeanStrongest, sbrQuotaMeanStrongest;
+ FIXP_DBL origQuota, sbrQuota;
+ FIXP_DBL invIndex, invChannel, invTemp;
+ FIXP_DBL quotaVecOrig[64], quotaVecSbr[64];
+
+ FDKmemclear(quotaVecOrig,64*sizeof(FIXP_DBL));
+ FDKmemclear(quotaVecSbr,64*sizeof(FIXP_DBL));
+
+ invIndex = GetInvInt(stopIndex-startIndex);
+ invChannel = GetInvInt(stopChannel-startChannel);
+
+ /*
+ Calculate the mean value, over the current time segment, for the original, the HFR
+ and the difference, over all channels in the current frequency range.
+ NOTE: the averaging is done on the values quota/(1 - quota + RELAXATION).
+ */
+
+ /* The original, the sbr signal and the total energy */
+ detectorValues->avgNrg = FL2FXCONST_DBL(0.0f);
+ for(j=startIndex; j<stopIndex; j++) {
+ for(i=startChannel; i<stopChannel; i++) {
+ quotaVecOrig[i] += fMult(quotaMatrixOrig[j][i], invIndex);
+
+ if(indexVector[i] != -1)
+ quotaVecSbr[i] += fMult(quotaMatrixOrig[j][indexVector[i]], invIndex);
+ }
+ detectorValues->avgNrg += fMult(nrgVector[j], invIndex);
+ }
+
+ /*
+ Calculate the mean value, over the current frequency range, for the original, the HFR
+ and the difference. Also calculate the same mean values for the three vectors, but only
+ includeing the x strongest copmponents.
+ */
+
+ origQuota = FL2FXCONST_DBL(0.0f);
+ sbrQuota = FL2FXCONST_DBL(0.0f);
+ for(i=startChannel; i<stopChannel; i++) {
+ origQuota += fMultDiv2(quotaVecOrig[i], invChannel);
+ sbrQuota += fMultDiv2(quotaVecSbr[i], invChannel);
+ }
+
+ /*
+ Calculate the mean value for the x strongest components
+ */
+ FDKsbrEnc_Shellsort_fract(quotaVecOrig+startChannel,stopChannel-startChannel);
+ FDKsbrEnc_Shellsort_fract(quotaVecSbr+startChannel,stopChannel-startChannel);
+
+ origQuotaMeanStrongest = FL2FXCONST_DBL(0.0f);
+ sbrQuotaMeanStrongest = FL2FXCONST_DBL(0.0f);
+
+ temp = min(stopChannel - startChannel, numberOfStrongest);
+ invTemp = GetInvInt(temp);
+
+ for(i=0; i<temp; i++) {
+ origQuotaMeanStrongest += fMultDiv2(quotaVecOrig[i + stopChannel - temp], invTemp);
+ sbrQuotaMeanStrongest += fMultDiv2(quotaVecSbr[i + stopChannel - temp], invTemp);
+ }
+
+ /*
+ The value for the strongest component
+ */
+ detectorValues->origQuotaMax = quotaVecOrig[stopChannel - 1];
+ detectorValues->sbrQuotaMax = quotaVecSbr[stopChannel - 1];
+
+ /*
+ Buffer values
+ */
+ FDKmemmove(detectorValues->origQuotaMean, detectorValues->origQuotaMean + 1, INVF_SMOOTHING_LENGTH*sizeof(FIXP_DBL));
+ FDKmemmove(detectorValues->sbrQuotaMean, detectorValues->sbrQuotaMean + 1, INVF_SMOOTHING_LENGTH*sizeof(FIXP_DBL));
+ FDKmemmove(detectorValues->origQuotaMeanStrongest, detectorValues->origQuotaMeanStrongest + 1, INVF_SMOOTHING_LENGTH*sizeof(FIXP_DBL));
+ FDKmemmove(detectorValues->sbrQuotaMeanStrongest, detectorValues->sbrQuotaMeanStrongest + 1, INVF_SMOOTHING_LENGTH*sizeof(FIXP_DBL));
+
+ detectorValues->origQuotaMean[INVF_SMOOTHING_LENGTH] = origQuota<<1;
+ detectorValues->sbrQuotaMean[INVF_SMOOTHING_LENGTH] = sbrQuota<<1;
+ detectorValues->origQuotaMeanStrongest[INVF_SMOOTHING_LENGTH] = origQuotaMeanStrongest<<1;
+ detectorValues->sbrQuotaMeanStrongest[INVF_SMOOTHING_LENGTH] = sbrQuotaMeanStrongest<<1;
+
+ /*
+ Filter values
+ */
+ detectorValues->origQuotaMeanFilt = FL2FXCONST_DBL(0.0f);
+ detectorValues->sbrQuotaMeanFilt = FL2FXCONST_DBL(0.0f);
+ detectorValues->origQuotaMeanStrongestFilt = FL2FXCONST_DBL(0.0f);
+ detectorValues->sbrQuotaMeanStrongestFilt = FL2FXCONST_DBL(0.0f);
+
+ for(i=0;i<INVF_SMOOTHING_LENGTH+1;i++) {
+ detectorValues->origQuotaMeanFilt += fMult(detectorValues->origQuotaMean[i], filter[i]);
+ detectorValues->sbrQuotaMeanFilt += fMult(detectorValues->sbrQuotaMean[i], filter[i]);
+ detectorValues->origQuotaMeanStrongestFilt += fMult(detectorValues->origQuotaMeanStrongest[i], filter[i]);
+ detectorValues->sbrQuotaMeanStrongestFilt += fMult(detectorValues->sbrQuotaMeanStrongest[i], filter[i]);
+ }
+}
+
+/**************************************************************************/
+/*!
+ \brief Returns the region in which the input value belongs.
+
+
+
+ \return region.
+
+*/
+/**************************************************************************/
+static INT
+findRegion(FIXP_DBL currVal, /*!< The current value. */
+ const FIXP_DBL *borders, /*!< The border of the regions. */
+ const INT numBorders /*!< The number of borders. */
+ )
+{
+ INT i;
+
+ if(currVal < borders[0]){
+ return 0;
+ }
+
+ for(i = 1; i < numBorders; i++){
+ if( currVal >= borders[i-1] && currVal < borders[i]){
+ return i;
+ }
+ }
+
+ if(currVal >= borders[numBorders-1]){
+ return numBorders;
+ }
+
+ return 0; /* We never get here, it's just to avoid compiler warnings.*/
+}
+
+/**************************************************************************/
+/*!
+ \brief Makes a clever decision based on the quota vector.
+
+
+ \return decision on which invf mode to use
+
+*/
+/**************************************************************************/
+static INVF_MODE
+decisionAlgorithm(const DETECTOR_PARAMETERS *detectorParams, /*!< Struct with the detector parameters. */
+ DETECTOR_VALUES *detectorValues, /*!< Struct with the detector values. */
+ INT transientFlag, /*!< Flag indicating if there is a transient present.*/
+ INT* prevRegionSbr, /*!< The previous region in which the Sbr value was. */
+ INT* prevRegionOrig /*!< The previous region in which the Orig value was. */
+ )
+{
+ INT invFiltLevel, regionSbr, regionOrig, regionNrg;
+
+ /*
+ Current thresholds.
+ */
+ const FIXP_DBL *quantStepsSbr = detectorParams->quantStepsSbr;
+ const FIXP_DBL *quantStepsOrig = detectorParams->quantStepsOrig;
+ const FIXP_DBL *nrgBorders = detectorParams->nrgBorders;
+ const INT numRegionsSbr = detectorParams->numRegionsSbr;
+ const INT numRegionsOrig = detectorParams->numRegionsOrig;
+ const INT numRegionsNrg = detectorParams->numRegionsNrg;
+
+ FIXP_DBL quantStepsSbrTmp[MAX_NUM_REGIONS];
+ FIXP_DBL quantStepsOrigTmp[MAX_NUM_REGIONS];
+
+ /*
+ Current detector values.
+ */
+ FIXP_DBL origQuotaMeanFilt;
+ FIXP_DBL sbrQuotaMeanFilt;
+ FIXP_DBL nrg;
+
+ /* 0.375 = 3.0 / 8.0; 0.31143075889 = log2(RELAXATION)/64.0; 0.625 = log(16)/64.0; 0.6875 = 44/64.0 */
+ origQuotaMeanFilt = (fMultDiv2(FL2FXCONST_DBL(2.f*0.375f), (FIXP_DBL)(CalcLdData(max(detectorValues->origQuotaMeanFilt,(FIXP_DBL)1)) + FL2FXCONST_DBL(0.31143075889f)))) << 0; /* scaled by 1/2^9 */
+ sbrQuotaMeanFilt = (fMultDiv2(FL2FXCONST_DBL(2.f*0.375f), (FIXP_DBL)(CalcLdData(max(detectorValues->sbrQuotaMeanFilt,(FIXP_DBL)1)) + FL2FXCONST_DBL(0.31143075889f)))) << 0; /* scaled by 1/2^9 */
+ /* If energy is zero then we will get different results for different word lengths. */
+ nrg = (fMultDiv2(FL2FXCONST_DBL(2.f*0.375f), (FIXP_DBL)(CalcLdData(detectorValues->avgNrg+(FIXP_DBL)1) + FL2FXCONST_DBL(0.0625f) + FL2FXCONST_DBL(0.6875f)))) << 0; /* scaled by 1/2^8; 2^44 -> qmf energy scale */
+
+ FDKmemcpy(quantStepsSbrTmp,quantStepsSbr,numRegionsSbr*sizeof(FIXP_DBL));
+ FDKmemcpy(quantStepsOrigTmp,quantStepsOrig,numRegionsOrig*sizeof(FIXP_DBL));
+
+ if(*prevRegionSbr < numRegionsSbr)
+ quantStepsSbrTmp[*prevRegionSbr] = quantStepsSbr[*prevRegionSbr] + hysteresis;
+ if(*prevRegionSbr > 0)
+ quantStepsSbrTmp[*prevRegionSbr - 1] = quantStepsSbr[*prevRegionSbr - 1] - hysteresis;
+
+ if(*prevRegionOrig < numRegionsOrig)
+ quantStepsOrigTmp[*prevRegionOrig] = quantStepsOrig[*prevRegionOrig] + hysteresis;
+ if(*prevRegionOrig > 0)
+ quantStepsOrigTmp[*prevRegionOrig - 1] = quantStepsOrig[*prevRegionOrig - 1] - hysteresis;
+
+ regionSbr = findRegion(sbrQuotaMeanFilt, quantStepsSbrTmp, numRegionsSbr);
+ regionOrig = findRegion(origQuotaMeanFilt, quantStepsOrigTmp, numRegionsOrig);
+ regionNrg = findRegion(nrg,nrgBorders,numRegionsNrg);
+
+ *prevRegionSbr = regionSbr;
+ *prevRegionOrig = regionOrig;
+
+ /* Use different settings if a transient is present*/
+ invFiltLevel = (transientFlag == 1) ? detectorParams->regionSpaceTransient[regionSbr][regionOrig]
+ : detectorParams->regionSpace[regionSbr][regionOrig];
+
+ /* Compensate for low energy.*/
+ invFiltLevel = max(invFiltLevel + detectorParams->EnergyCompFactor[regionNrg],0);
+
+ return (INVF_MODE) (invFiltLevel);
+}
+
+/**************************************************************************/
+/*!
+ \brief Estiamtion of the inverse filtering level required
+ in the decoder.
+
+ A second order LPC is calculated for every filterbank channel, using
+ the covariance method. THe ratio between the energy of the predicted
+ signal and the energy of the non-predictable signal is calcualted.
+
+ \return none.
+
+*/
+/**************************************************************************/
+void
+FDKsbrEnc_qmfInverseFilteringDetector(HANDLE_SBR_INV_FILT_EST hInvFilt, /*!< Handle to the SBR_INV_FILT_EST struct. */
+ FIXP_DBL **quotaMatrix, /*!< The matrix holding the tonality values of the original. */
+ FIXP_DBL *nrgVector, /*!< The energy vector. */
+ SCHAR *indexVector, /*!< Index vector to obtain the patched data. */
+ INT startIndex, /*!< Start index. */
+ INT stopIndex, /*!< Stop index. */
+ INT transientFlag, /*!< Flag indicating if a transient is present or not.*/
+ INVF_MODE* infVec /*!< Vector holding the inverse filtering levels. */
+ )
+{
+ INT band;
+
+ /*
+ * Do the inverse filtering level estimation.
+ *****************************************************/
+ for(band = 0 ; band < hInvFilt->noDetectorBands; band++){
+ INT startChannel = hInvFilt->freqBandTableInvFilt[band];
+ INT stopChannel = hInvFilt->freqBandTableInvFilt[band+1];
+
+
+ calculateDetectorValues( quotaMatrix,
+ indexVector,
+ nrgVector,
+ &hInvFilt->detectorValues[band],
+ startChannel,
+ stopChannel,
+ startIndex,
+ stopIndex,
+ hInvFilt->numberOfStrongest);
+
+ infVec[band]= decisionAlgorithm( hInvFilt->detectorParams,
+ &hInvFilt->detectorValues[band],
+ transientFlag,
+ &hInvFilt->prevRegionSbr[band],
+ &hInvFilt->prevRegionOrig[band]);
+ }
+
+}
+
+
+/**************************************************************************/
+/*!
+ \brief Initialize an instance of the inverse filtering level estimator.
+
+
+ \return errorCode, noError if successful.
+
+*/
+/**************************************************************************/
+INT
+FDKsbrEnc_initInvFiltDetector (HANDLE_SBR_INV_FILT_EST hInvFilt, /*!< Pointer to a handle to the SBR_INV_FILT_EST struct. */
+ INT* freqBandTableDetector, /*!< Frequency band table for the inverse filtering. */
+ INT numDetectorBands, /*!< Number of inverse filtering bands. */
+ UINT useSpeechConfig /*!< Flag: adapt tuning parameters according to speech*/
+ )
+{
+ INT i;
+
+ FDKmemclear( hInvFilt,sizeof(SBR_INV_FILT_EST));
+
+ hInvFilt->detectorParams = (useSpeechConfig) ? &detectorParamsAACSpeech
+ : &detectorParamsAAC ;
+
+ hInvFilt->noDetectorBandsMax = numDetectorBands;
+
+ /*
+ Memory initialisation
+ */
+ for(i=0;i<hInvFilt->noDetectorBandsMax;i++){
+ FDKmemclear(&hInvFilt->detectorValues[i], sizeof(DETECTOR_VALUES));
+ hInvFilt->prevInvfMode[i] = INVF_OFF;
+ hInvFilt->prevRegionOrig[i] = 0;
+ hInvFilt->prevRegionSbr[i] = 0;
+ }
+
+ /*
+ Reset the inverse fltering detector.
+ */
+ FDKsbrEnc_resetInvFiltDetector(hInvFilt,
+ freqBandTableDetector,
+ hInvFilt->noDetectorBandsMax);
+
+ return (0);
+}
+
+
+/**************************************************************************/
+/*!
+ \brief resets sbr inverse filtering structure.
+
+
+
+ \return errorCode, noError if successful.
+
+*/
+/**************************************************************************/
+INT
+FDKsbrEnc_resetInvFiltDetector(HANDLE_SBR_INV_FILT_EST hInvFilt, /*!< Handle to the SBR_INV_FILT_EST struct. */
+ INT* freqBandTableDetector, /*!< Frequency band table for the inverse filtering. */
+ INT numDetectorBands) /*!< Number of inverse filtering bands. */
+{
+
+ hInvFilt->numberOfStrongest = 1;
+ FDKmemcpy(hInvFilt->freqBandTableInvFilt,freqBandTableDetector,(numDetectorBands+1)*sizeof(INT));
+ hInvFilt->noDetectorBands = numDetectorBands;
+
+ return (0);
+}
+
+