From 9bf37cc9712506b2483650c82d3c41152337ef7e Mon Sep 17 00:00:00 2001 From: Dave Burke Date: Tue, 17 Apr 2012 09:51:45 -0700 Subject: Fraunhofer AAC codec. License boilerplate update to follow. Change-Id: I2810460c11a58b6d148d84673cc031f3685e79b5 --- libAACenc/src/aacenc_tns.cpp | 1286 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1286 insertions(+) create mode 100644 libAACenc/src/aacenc_tns.cpp (limited to 'libAACenc/src/aacenc_tns.cpp') diff --git a/libAACenc/src/aacenc_tns.cpp b/libAACenc/src/aacenc_tns.cpp new file mode 100644 index 0000000..f795e24 --- /dev/null +++ b/libAACenc/src/aacenc_tns.cpp @@ -0,0 +1,1286 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + 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$ + Initial author: Alex Groeschel + contents/description: Temporal noise shaping + +******************************************************************************/ + +#include "aacenc_tns.h" +#include "psy_const.h" +#include "psy_configuration.h" +#include "tns_func.h" +#include "aacEnc_rom.h" +#include "aacenc_tns.h" + +enum { + HIFILT = 0, /* index of higher filter */ + LOFILT = 1 /* index of lower filter */ +}; + + +#define FILTER_DIRECTION 0 + +static const FIXP_DBL acfWindowLong[12+3+1] = { + 0x7fffffff,0x7fb80000,0x7ee00000,0x7d780000,0x7b800000,0x78f80000,0x75e00000,0x72380000, + 0x6e000000,0x69380000,0x63e00000,0x5df80000,0x57800000,0x50780000,0x48e00000,0x40b80000 +}; + +static const FIXP_DBL acfWindowShort[4+3+1] = { + 0x7fffffff,0x7e000000,0x78000000,0x6e000000,0x60000000,0x4e000000,0x38000000,0x1e000000 +}; + + +typedef struct { + INT filterEnabled[MAX_NUM_OF_FILTERS]; + INT threshOn[MAX_NUM_OF_FILTERS]; /* min. prediction gain for using tns TABUL*/ + INT filterStartFreq[MAX_NUM_OF_FILTERS]; /* lowest freq for lpc TABUL*/ + INT tnsLimitOrder[MAX_NUM_OF_FILTERS]; /* Limit for TNS order TABUL*/ + INT tnsFilterDirection[MAX_NUM_OF_FILTERS]; /* Filtering direction, 0=up, 1=down TABUL */ + INT acfSplit[MAX_NUM_OF_FILTERS]; + FIXP_DBL tnsTimeResolution[MAX_NUM_OF_FILTERS]; /* TNS max. time resolution TABUL. Should be fract but MSVC won't compile then */ + INT seperateFiltersAllowed; + +} TNS_PARAMETER_TABULATED; + + +typedef struct{ + INT bitRateFrom[2]; /* noneSbr=0, useSbr=1 */ + INT bitRateTo[2]; /* noneSbr=0, useSbr=1 */ + TNS_PARAMETER_TABULATED paramTab[2]; /* mono=0, stereo=1 */ + +} TNS_INFO_TAB; + +#define TNS_TIMERES_SCALE (1) +#define FL2_TIMERES_FIX(a) ( FL2FXCONST_DBL(a/(float)(1<= tnsInfoTab[i].bitRateFrom[sbrLd?1:0]) && + bitRate <= tnsInfoTab[i].bitRateTo[sbrLd?1:0]) + { + tnsConfigTab = &tnsInfoTab[i].paramTab[(channels==1)?0:1]; + } + } + + return tnsConfigTab; +} + + +static INT getTnsMaxBands( + const INT sampleRate, + const INT granuleLength, + const INT isShortBlock + ) +{ + int i; + INT numBands = -1; + const TNS_MAX_TAB_ENTRY *pMaxBandsTab = NULL; + int maxBandsTabSize = 0; + + switch (granuleLength) { + case 960: + case 1024: + pMaxBandsTab = tnsMaxBandsTab1024; + maxBandsTabSize = sizeof(tnsMaxBandsTab1024)/sizeof(TNS_MAX_TAB_ENTRY); + break; + case 480: + pMaxBandsTab = tnsMaxBandsTab480; + maxBandsTabSize = sizeof(tnsMaxBandsTab480)/sizeof(TNS_MAX_TAB_ENTRY); + break; + case 512: + pMaxBandsTab = tnsMaxBandsTab512; + maxBandsTabSize = sizeof(tnsMaxBandsTab512)/sizeof(TNS_MAX_TAB_ENTRY); + break; + default: + numBands = -1; + } + + if (pMaxBandsTab!=NULL) { + for (i=0; i= pMaxBandsTab[i].samplingRate) { + break; + } + } + } + + return numBands; +} + +/***************************************************************************/ +/*! + \brief FDKaacEnc_FreqToBandWithRounding + + Returns index of nearest band border + + \param frequency + \param sampling frequency + \param total number of bands + \param pointer to table of band borders + + \return band border +****************************************************************************/ + +INT FDKaacEnc_FreqToBandWithRounding( + const INT freq, + const INT fs, + const INT numOfBands, + const INT *bandStartOffset + ) +{ + INT lineNumber, band; + + /* assert(freq >= 0); */ + lineNumber = (freq*bandStartOffset[numOfBands]*4/fs+1)/2; + + /* freq > fs/2 */ + if (lineNumber >= bandStartOffset[numOfBands]) + return numOfBands; + + /* find band the line number lies in */ + for (band=0; bandlineNumber) break; + } + + /* round to nearest band border */ + if (lineNumber - bandStartOffset[band] > + bandStartOffset[band+1] - lineNumber ) + { + band++; + } + + return(band); +} + + +/***************************************************************************** + + functionname: FDKaacEnc_InitTnsConfiguration + description: fill TNS_CONFIG structure with sensible content + returns: + input: bitrate, samplerate, number of channels, + blocktype (long or short), + TNS Config struct (modified), + psy config struct, + tns active flag + output: + +*****************************************************************************/ +AAC_ENCODER_ERROR FDKaacEnc_InitTnsConfiguration(INT bitRate, + INT sampleRate, + INT channels, + INT blockType, + INT granuleLength, + INT ldSbrPresent, + TNS_CONFIG *tC, + PSY_CONFIGURATION *pC, + INT active, + INT useTnsPeak) +{ + int i; + //float acfTimeRes = (blockType == SHORT_WINDOW) ? 0.125f : 0.046875f; + + if (channels <= 0) + return (AAC_ENCODER_ERROR)1; + + /* initialize TNS filter flag, order, and coefficient resolution (in bits per coeff) */ + tC->tnsActive = (active) ? TRUE : FALSE; + tC->maxOrder = (blockType == SHORT_WINDOW) ? 5 : 12; /* maximum: 7, 20 */ + if (bitRate < 16000) + tC->maxOrder -= 2; + tC->coefRes = (blockType == SHORT_WINDOW) ? 3 : 4; + + /* LPC stop line: highest MDCT line to be coded, but do not go beyond TNS_MAX_BANDS! */ + tC->lpcStopBand = getTnsMaxBands(sampleRate, granuleLength, (blockType == SHORT_WINDOW) ? 1 : 0); + + if (tC->lpcStopBand < 0) { + return (AAC_ENCODER_ERROR)1; + } + + tC->lpcStopBand = FDKmin(tC->lpcStopBand, pC->sfbActive); + tC->lpcStopLine = pC->sfbOffset[tC->lpcStopBand]; + + switch (granuleLength) { + case 960: + case 1024: + /* TNS start line: skip lower MDCT lines to prevent artifacts due to filter mismatch */ + tC->lpcStartBand[LOFILT] = (blockType == SHORT_WINDOW) ? 0 : ((sampleRate < 18783) ? 4 : 8); + tC->lpcStartLine[LOFILT] = pC->sfbOffset[tC->lpcStartBand[LOFILT]]; + + i = tC->lpcStopBand; + while (pC->sfbOffset[i] > (tC->lpcStartLine[LOFILT] + (tC->lpcStopLine - tC->lpcStartLine[LOFILT]) / 4)) i--; + tC->lpcStartBand[HIFILT] = i; + tC->lpcStartLine[HIFILT] = pC->sfbOffset[i]; + + tC->confTab.threshOn[HIFILT] = 1437; + tC->confTab.threshOn[LOFILT] = 1500; + + tC->confTab.tnsLimitOrder[HIFILT] = tC->maxOrder; + tC->confTab.tnsLimitOrder[LOFILT] = tC->maxOrder - 7; + + tC->confTab.tnsFilterDirection[HIFILT] = FILTER_DIRECTION; + tC->confTab.tnsFilterDirection[LOFILT] = FILTER_DIRECTION; + + tC->confTab.acfSplit[HIFILT] = -1; /* signal Merged4to2QuartersAutoCorrelation in FDKaacEnc_MergedAutoCorrelation*/ + tC->confTab.acfSplit[LOFILT] = -1; /* signal Merged4to2QuartersAutoCorrelation in FDKaacEnc_MergedAutoCorrelation */ + + tC->confTab.filterEnabled[HIFILT] = 1; + tC->confTab.filterEnabled[LOFILT] = 1; + tC->confTab.seperateFiltersAllowed = 1; + + /* compute autocorrelation window based on maximum filter order for given block type */ + /* for (i = 0; i <= tC->maxOrder + 3; i++) { + float acfWinTemp = acfTimeRes * i; + acfWindow[i] = FL2FXCONST_DBL(1.0f - acfWinTemp * acfWinTemp); + } + */ + if (blockType == SHORT_WINDOW) { + FDKmemcpy(tC->acfWindow[HIFILT], acfWindowShort, FDKmin(sizeof(acfWindowShort), sizeof(tC->acfWindow[HIFILT]))); + FDKmemcpy(tC->acfWindow[LOFILT], acfWindowShort, FDKmin(sizeof(acfWindowShort), sizeof(tC->acfWindow[HIFILT]))); + } + else { + FDKmemcpy(tC->acfWindow[HIFILT], acfWindowLong, FDKmin(sizeof(acfWindowLong), sizeof(tC->acfWindow[HIFILT]))); + FDKmemcpy(tC->acfWindow[LOFILT], acfWindowLong, FDKmin(sizeof(acfWindowLong), sizeof(tC->acfWindow[HIFILT]))); + } + break; + case 480: + case 512: + { + const TNS_PARAMETER_TABULATED* pCfg = FDKaacEnc_GetTnsParam(bitRate, channels, ldSbrPresent); + + if ( pCfg != NULL ) { + tC->lpcStartBand[HIFILT] = FDKaacEnc_FreqToBandWithRounding(pCfg->filterStartFreq[HIFILT], sampleRate, pC->sfbCnt, pC->sfbOffset); + tC->lpcStartLine[HIFILT] = pC->sfbOffset[tC->lpcStartBand[HIFILT]]; + tC->lpcStartBand[LOFILT] = FDKaacEnc_FreqToBandWithRounding(pCfg->filterStartFreq[LOFILT], sampleRate, pC->sfbCnt, pC->sfbOffset); + tC->lpcStartLine[LOFILT] = pC->sfbOffset[tC->lpcStartBand[LOFILT]]; + + tC->confTab.threshOn[HIFILT] = pCfg->threshOn[HIFILT]; + tC->confTab.threshOn[LOFILT] = pCfg->threshOn[LOFILT]; + + tC->confTab.tnsLimitOrder[HIFILT] = pCfg->tnsLimitOrder[HIFILT]; + tC->confTab.tnsLimitOrder[LOFILT] = pCfg->tnsLimitOrder[LOFILT]; + + tC->confTab.tnsFilterDirection[HIFILT] = pCfg->tnsFilterDirection[HIFILT]; + tC->confTab.tnsFilterDirection[LOFILT] = pCfg->tnsFilterDirection[LOFILT]; + + tC->confTab.acfSplit[HIFILT] = pCfg->acfSplit[HIFILT]; + tC->confTab.acfSplit[LOFILT] = pCfg->acfSplit[LOFILT]; + + tC->confTab.filterEnabled[HIFILT] = pCfg->filterEnabled[HIFILT]; + tC->confTab.filterEnabled[LOFILT] = pCfg->filterEnabled[LOFILT]; + tC->confTab.seperateFiltersAllowed = pCfg->seperateFiltersAllowed; + + FDKaacEnc_CalcGaussWindow(tC->acfWindow[HIFILT], tC->maxOrder+1, sampleRate, granuleLength, pCfg->tnsTimeResolution[HIFILT], TNS_TIMERES_SCALE); + FDKaacEnc_CalcGaussWindow(tC->acfWindow[LOFILT], tC->maxOrder+1, sampleRate, granuleLength, pCfg->tnsTimeResolution[LOFILT], TNS_TIMERES_SCALE); + } + else { + tC->tnsActive = FALSE; /* no configuration available, disable tns tool */ + } + } + break; + default: + tC->tnsActive = FALSE; /* no configuration available, disable tns tool */ + } + + return AAC_ENC_OK; + +} + +/***************************************************************************/ +/*! + \brief FDKaacEnc_ScaleUpSpectrum + + Scales up spectrum lines in a given frequency section + + \param scaled spectrum + \param original spectrum + \param frequency line to start scaling + \param frequency line to enc scaling + + \return scale factor + +****************************************************************************/ +static inline INT FDKaacEnc_ScaleUpSpectrum( + FIXP_DBL *dest, + const FIXP_DBL *src, + const INT startLine, + const INT stopLine + ) +{ + INT i, scale; + + FIXP_DBL maxVal = FL2FXCONST_DBL(0.f); + + /* Get highest value in given spectrum */ + for (i=startLine; i>scale); + } + } + else { + for (i=startLine; i<(stopLine-lag); i++) { + result += (fMult(spectrum[i], spectrum[i+lag])>>scale); + } + } + + return result; +} + +/***************************************************************************/ +/*! + \brief FDKaacEnc_AutoCorrNormFac + + Autocorrelation function for 1st and 2nd half of the spectrum + + \param pointer to spectrum + \param pointer to autocorrelation window + \param filter start line + +****************************************************************************/ +static inline FIXP_DBL FDKaacEnc_AutoCorrNormFac( + const FIXP_DBL value, + const INT scale, + INT *sc + ) +{ + #define HLM_MIN_NRG 0.0000000037252902984619140625f /* 2^-28 */ + #define MAX_INV_NRGFAC (1.f/HLM_MIN_NRG) + + FIXP_DBL retValue; + FIXP_DBL A, B; + + if (scale>=0) { + A = value; + B = FL2FXCONST_DBL(HLM_MIN_NRG)>>fixMin(DFRACT_BITS-1,scale); + } + else { + A = value>>fixMin(DFRACT_BITS-1,(-scale)); + B = FL2FXCONST_DBL(HLM_MIN_NRG); + } + + if (A > B) { + int shift = 0; + FIXP_DBL tmp = invSqrtNorm2(value,&shift); + + retValue = fMult(tmp,tmp); + *sc += (2*shift); + } + else { + /* MAX_INV_NRGFAC*FDKpow(2,-28) = 1/2^-28 * 2^-28 = 1.0 */ + retValue = /*FL2FXCONST_DBL(MAX_INV_NRGFAC*FDKpow(2,-28))*/ (FIXP_DBL)MAXVAL_DBL; + *sc += scale+28; + } + + return retValue; +} + +static void FDKaacEnc_MergedAutoCorrelation( + const FIXP_DBL *spectrum, + const FIXP_DBL acfWindow[MAX_NUM_OF_FILTERS][TNS_MAX_ORDER+3+1], + const INT lpcStartLine[MAX_NUM_OF_FILTERS], + const INT lpcStopLine, + const INT maxOrder, + const INT acfSplit[MAX_NUM_OF_FILTERS], + FIXP_DBL *_rxx1, + FIXP_DBL *_rxx2 + ) +{ + int i, idx0, idx1, idx2, idx3, idx4, lag; + FIXP_DBL rxx1_0, rxx2_0, rxx3_0, rxx4_0; + + /* buffer for temporal spectrum */ + C_ALLOC_SCRATCH_START(pSpectrum, FIXP_DBL, (1024)); + + /* pre-initialization output */ + FDKmemclear(&_rxx1[0], sizeof(FIXP_DBL)*(maxOrder+1)); + FDKmemclear(&_rxx2[0], sizeof(FIXP_DBL)*(maxOrder+1)); + + /* MDCT line indices separating the 1st, 2nd, 3rd, and 4th analysis quarters */ + if ( (acfSplit[LOFILT]==-1) || (acfSplit[HIFILT]==-1) ) { + /* autocorrelation function for 1st, 2nd, 3rd, and 4th quarter of the spectrum */ + idx0 = lpcStartLine[LOFILT]; + i = lpcStopLine - lpcStartLine[LOFILT]; + idx1 = idx0 + i / 4; + idx2 = idx0 + i / 2; + idx3 = idx0 + i * 3 / 4; + idx4 = lpcStopLine; + } + else { + FDK_ASSERT(acfSplit[LOFILT]==1); + FDK_ASSERT(acfSplit[HIFILT]==3); + i = (lpcStopLine - lpcStartLine[HIFILT]) / 3; + idx0 = lpcStartLine[LOFILT]; + idx1 = lpcStartLine[HIFILT]; + idx2 = idx1 + i; + idx3 = idx2 + i; + idx4 = lpcStopLine; + } + + /* copy spectrum to temporal buffer and scale up as much as possible */ + INT sc1 = FDKaacEnc_ScaleUpSpectrum(pSpectrum, spectrum, idx0, idx1); + INT sc2 = FDKaacEnc_ScaleUpSpectrum(pSpectrum, spectrum, idx1, idx2); + INT sc3 = FDKaacEnc_ScaleUpSpectrum(pSpectrum, spectrum, idx2, idx3); + INT sc4 = FDKaacEnc_ScaleUpSpectrum(pSpectrum, spectrum, idx3, idx4); + + /* get scaling values for summation */ + INT nsc1, nsc2, nsc3, nsc4; + for (nsc1=1; (1<dataRaw.Short.subBlockInfo[subBlockNumber] + : &tnsData->dataRaw.Long.subBlockInfo; + + tnsData->filtersMerged = FALSE; + tsbi->tnsActive = FALSE; + tsbi->predictionGain = 1000; + tnsInfo->numOfFilters[subBlockNumber] = 0; + tnsInfo->coefRes[subBlockNumber] = tC->coefRes; + for (i = 0; i < tC->maxOrder; i++) { + tnsInfo->coef[subBlockNumber][HIFILT][i] = tnsInfo->coef[subBlockNumber][LOFILT][i] = 0; + } + + tnsInfo->length[subBlockNumber][HIFILT] = tnsInfo->length[subBlockNumber][LOFILT] = 0; + tnsInfo->order [subBlockNumber][HIFILT] = tnsInfo->order [subBlockNumber][LOFILT] = 0; + + if ( (tC->tnsActive) && (tC->maxOrder>0) ) + { + int sumSqrCoef; + + FDKaacEnc_MergedAutoCorrelation( + spectrum, + tC->acfWindow, + tC->lpcStartLine, + tC->lpcStopLine, + tC->maxOrder, + tC->confTab.acfSplit, + rxx1, + rxx2); + + /* compute higher TNS filter in lattice (ParCor) form with LeRoux-Gueguen algorithm */ + tsbi->predictionGain = FDKaacEnc_AutoToParcor(rxx2, parcor_tmp, tC->confTab.tnsLimitOrder[HIFILT]); + + /* non-linear quantization of TNS lattice coefficients with given resolution */ + FDKaacEnc_Parcor2Index( + parcor_tmp, + tnsInfo->coef[subBlockNumber][HIFILT], + tC->confTab.tnsLimitOrder[HIFILT], + tC->coefRes); + + /* reduce filter order by truncating trailing zeros, compute sum(abs(coefs)) */ + for (i = tC->confTab.tnsLimitOrder[HIFILT] - 1; i >= 0; i--) { + if (tnsInfo->coef[subBlockNumber][HIFILT][i] != 0) { + break; + } + } + + tnsInfo->order[subBlockNumber][HIFILT] = i + 1; + + sumSqrCoef = 0; + for (; i >= 0; i--) { + sumSqrCoef += tnsInfo->coef[subBlockNumber][HIFILT][i] * tnsInfo->coef[subBlockNumber][HIFILT][i]; + } + + tnsInfo->direction[subBlockNumber][HIFILT] = tC->confTab.tnsFilterDirection[HIFILT]; + tnsInfo->length[subBlockNumber][HIFILT] = sfbCnt - tC->lpcStartBand[HIFILT]; + + /* disable TNS if predictionGain is less than 3dB or sumSqrCoef is too small */ + if ((tsbi->predictionGain > tC->confTab.threshOn[HIFILT]) || (sumSqrCoef > (tC->confTab.tnsLimitOrder[HIFILT]/2 + 2))) + { + tsbi->tnsActive = TRUE; + tnsInfo->numOfFilters[subBlockNumber]++; + + /* compute second filter for lower quarter; only allowed for long windows! */ + if ( (blockType != SHORT_WINDOW) && + (tC->confTab.filterEnabled[LOFILT]) && (tC->confTab.seperateFiltersAllowed) ) + { + /* compute second filter for lower frequencies */ + + /* compute TNS filter in lattice (ParCor) form with LeRoux-Gueguen algorithm */ + INT predGain = FDKaacEnc_AutoToParcor(rxx1, parcor_tmp, tC->confTab.tnsLimitOrder[LOFILT]); + + /* non-linear quantization of TNS lattice coefficients with given resolution */ + FDKaacEnc_Parcor2Index( + parcor_tmp, + tnsInfo->coef[subBlockNumber][LOFILT], + tC->confTab.tnsLimitOrder[LOFILT], + tC->coefRes); + + /* reduce filter order by truncating trailing zeros, compute sum(abs(coefs)) */ + for (i = tC->confTab.tnsLimitOrder[LOFILT] - 1; i >= 0; i--) { + if (tnsInfo->coef[subBlockNumber][LOFILT][i] != 0) { + break; + } + } + tnsInfo->order[subBlockNumber][LOFILT] = i + 1; + + sumSqrCoef = 0; + for (; i >= 0; i--) { + sumSqrCoef += tnsInfo->coef[subBlockNumber][LOFILT][i] * tnsInfo->coef[subBlockNumber][LOFILT][i]; + } + + tnsInfo->direction[subBlockNumber][LOFILT] = tC->confTab.tnsFilterDirection[LOFILT]; + tnsInfo->length[subBlockNumber][LOFILT] = tC->lpcStartBand[HIFILT] - tC->lpcStartBand[LOFILT]; + + /* filter lower quarter if gain is high enough, but not if it's too high */ + if ( ( (predGain > tC->confTab.threshOn[LOFILT]) && (predGain < (16000 * tC->confTab.tnsLimitOrder[LOFILT])) ) + || ( (sumSqrCoef > 9) && (sumSqrCoef < 22 * tC->confTab.tnsLimitOrder[LOFILT]) ) ) + { + /* compare lower to upper filter; if they are very similar, merge them */ + sumSqrCoef = 0; + for (i = 0; i < tC->confTab.tnsLimitOrder[LOFILT]; i++) { + sumSqrCoef += FDKabs(tnsInfo->coef[subBlockNumber][HIFILT][i] - tnsInfo->coef[subBlockNumber][LOFILT][i]); + } + if ( (sumSqrCoef < 2) && + (tnsInfo->direction[subBlockNumber][LOFILT] == tnsInfo->direction[subBlockNumber][HIFILT]) ) + { + tnsData->filtersMerged = TRUE; + tnsInfo->length[subBlockNumber][HIFILT] = sfbCnt - tC->lpcStartBand[LOFILT]; + for (; i < tnsInfo->order[subBlockNumber][HIFILT]; i++) { + if (FDKabs(tnsInfo->coef[subBlockNumber][HIFILT][i]) > 1) { + break; + } + } + for (i--; i >= 0; i--) { + if (tnsInfo->coef[subBlockNumber][HIFILT][i] != 0) { + break; + } + } + if (i < tnsInfo->order[subBlockNumber][HIFILT]) { + tnsInfo->order[subBlockNumber][HIFILT] = i + 1; + } + } + else { + tnsInfo->numOfFilters[subBlockNumber]++; + } + } /* filter lower part */ + } /* second filter allowed */ + } /* if predictionGain > 1437 ... */ + } /* maxOrder > 0 && tnsActive */ + + return 0; + +} + + +/***************************************************************************/ +/*! + \brief FDKaacLdEnc_TnsSync + + synchronize TNS parameters when TNS gain difference small (relative) + + \param pointer to TNS data structure (destination) + \param pointer to TNS data structure (source) + \param pointer to TNS config structure + \param number of sub-block + \param block type + + \return void +****************************************************************************/ +void FDKaacEnc_TnsSync( + TNS_DATA *tnsDataDest, + const TNS_DATA *tnsDataSrc, + TNS_INFO *tnsInfoDest, + TNS_INFO *tnsInfoSrc, + const INT blockTypeDest, + const INT blockTypeSrc, + const TNS_CONFIG *tC + ) +{ + int i, w, absDiff, nWindows; + TNS_SUBBLOCK_INFO *sbInfoDest; + const TNS_SUBBLOCK_INFO *sbInfoSrc; + + /* if one channel contains short blocks and the other not, do not synchronize */ + if ( (blockTypeSrc == SHORT_WINDOW && blockTypeDest != SHORT_WINDOW) || + (blockTypeDest == SHORT_WINDOW && blockTypeSrc != SHORT_WINDOW) ) + { + return; + } + + if (blockTypeDest != SHORT_WINDOW) { + sbInfoDest = &tnsDataDest->dataRaw.Long.subBlockInfo; + sbInfoSrc = &tnsDataSrc->dataRaw.Long.subBlockInfo; + nWindows = 1; + } else { + sbInfoDest = &tnsDataDest->dataRaw.Short.subBlockInfo[0]; + sbInfoSrc = &tnsDataSrc->dataRaw.Short.subBlockInfo[0]; + nWindows = 8; + } + + for (w=0; wtnsActive || pSbInfoSrcW->tnsActive) { + for (i = 0; i < tC->maxOrder; i++) { + absDiff = FDKabs(tnsInfoDest->coef[w][HIFILT][i] - tnsInfoSrc->coef[w][HIFILT][i]); + absDiffSum += absDiff; + /* if coefficients diverge too much between channels, do not synchronize */ + if ((absDiff > 1) || (absDiffSum > 2)) { + doSync = 0; + break; + } + } + + if (doSync) { + /* if no significant difference was detected, synchronize coefficient sets */ + if (pSbInfoSrcW->tnsActive) { + /* no dest filter, or more dest than source filters: use one dest filter */ + if ((!pSbInfoDestW->tnsActive) || + ((pSbInfoDestW->tnsActive) && (tnsInfoDest->numOfFilters[w] > tnsInfoSrc->numOfFilters[w]))) + { + pSbInfoDestW->tnsActive = tnsInfoDest->numOfFilters[w] = 1; + } + tnsDataDest->filtersMerged = tnsDataSrc->filtersMerged; + tnsInfoDest->order [w][HIFILT] = tnsInfoSrc->order [w][HIFILT]; + tnsInfoDest->length [w][HIFILT] = tnsInfoSrc->length [w][HIFILT]; + tnsInfoDest->direction [w][HIFILT] = tnsInfoSrc->direction [w][HIFILT]; + tnsInfoDest->coefCompress[w][HIFILT] = tnsInfoSrc->coefCompress[w][HIFILT]; + + for (i = 0; i < tC->maxOrder; i++) { + tnsInfoDest->coef[w][HIFILT][i] = tnsInfoSrc->coef[w][HIFILT][i]; + } + } + else + pSbInfoDestW->tnsActive = tnsInfoDest->numOfFilters[w] = 0; + } + } + + } +} + +/***************************************************************************/ +/*! + \brief FDKaacEnc_TnsEncode + + perform TNS encoding + + \param pointer to TNS info structure + \param pointer to TNS data structure + \param number of sfbs + \param pointer to TNS config structure + \param low-pass line + \param pointer to spectrum + \param number of sub-block + \param block type + + \return ERROR STATUS +****************************************************************************/ +INT FDKaacEnc_TnsEncode( + TNS_INFO* tnsInfo, + TNS_DATA* tnsData, + const INT numOfSfb, + const TNS_CONFIG *tC, + const INT lowPassLine, + FIXP_DBL* spectrum, + const INT subBlockNumber, + const INT blockType + ) +{ + INT i, startLine, stopLine; + + if ( ( (blockType == SHORT_WINDOW) && (!tnsData->dataRaw.Short.subBlockInfo[subBlockNumber].tnsActive) ) + || ( (blockType != SHORT_WINDOW) && (!tnsData->dataRaw.Long.subBlockInfo.tnsActive) ) ) + { + return 1; + } + + startLine = (tnsData->filtersMerged) ? tC->lpcStartLine[LOFILT] : tC->lpcStartLine[HIFILT]; + stopLine = tC->lpcStopLine; + + for (i=0; inumOfFilters[subBlockNumber]; i++) { + + INT lpcGainFactor; + FIXP_DBL LpcCoeff[TNS_MAX_ORDER]; + FIXP_DBL workBuffer[TNS_MAX_ORDER]; + FIXP_DBL parcor_tmp[TNS_MAX_ORDER]; + + FDKaacEnc_Index2Parcor( + tnsInfo->coef[subBlockNumber][i], + parcor_tmp, + tnsInfo->order[subBlockNumber][i], + tC->coefRes); + + lpcGainFactor = FDKaacEnc_ParcorToLpc( + parcor_tmp, + LpcCoeff, + tnsInfo->order[subBlockNumber][i], + workBuffer); + + FDKaacEnc_AnalysisFilter( + &spectrum[startLine], + stopLine - startLine, + LpcCoeff, + tnsInfo->order[subBlockNumber][i], + lpcGainFactor); + + /* update for second filter */ + startLine = tC->lpcStartLine[LOFILT]; + stopLine = tC->lpcStartLine[HIFILT]; + } + + return(0); + +} + +static void FDKaacEnc_CalcGaussWindow( + FIXP_DBL *win, + const int winSize, + const INT samplingRate, + const INT transformResolution, + const FIXP_DBL timeResolution, + const INT timeResolution_e + ) +{ + #define PI_SCALE (2) + #define PI_FIX FL2FXCONST_DBL(3.1416f/(float)(1<> (DFRACT_BITS-1)); + tmp = (FIXP_DBL)((LONG)workBuffer[0]^sign); + + if(input[0]=0; j--) { + FIXP_DBL accu1 = fMult(tmp, input[j]); + FIXP_DBL accu2 = fMult(tmp, workBuffer[j]); + workBuffer[j] += accu1; + input[j] += accu2; + } + + workBuffer++; + } + + tmp = fMult((FIXP_DBL)((LONG)TNS_PREDGAIN_SCALE<<21), fDivNorm(autoCorr_0, input[0], &scale)); + predictionGain = (LONG)scaleValue(tmp,scale-21); + + return (predictionGain); +} + + +static INT FDKaacEnc_Search3(FIXP_DBL parcor) +{ + INT i, index=0; + + for(i=0;i<8;i++){ + if(parcor > FDKaacEnc_tnsCoeff3Borders[i]) + index=i; + } + return(index-4); +} + +static INT FDKaacEnc_Search4(FIXP_DBL parcor) +{ + INT i, index=0; + + for(i=0;i<16;i++){ + if(parcor > FDKaacEnc_tnsCoeff4Borders[i]) + index=i; + } + return(index-8); +} + + +/***************************************************************************** + + functionname: FDKaacEnc_Parcor2Index + +*****************************************************************************/ +static void FDKaacEnc_Parcor2Index( + const FIXP_DBL *parcor, + INT *RESTRICT index, + const INT order, + const INT bitsPerCoeff + ) +{ + INT i; + for(i=0; i, + ptr. to work buffer (required size: order) + output: LPC coefficients + +*****************************************************************************/ +static INT FDKaacEnc_ParcorToLpc( + const FIXP_DBL *reflCoeff, + FIXP_DBL *RESTRICT LpcCoeff, + const INT numOfCoeff, + FIXP_DBL *RESTRICT workBuffer + ) +{ + INT i, j; + INT shiftval, par2LpcShiftVal = 6; /* 6 should be enough, bec. max(numOfCoeff) = 20 */ + FIXP_DBL maxVal = FL2FXCONST_DBL(0.0f); + + LpcCoeff[0] = reflCoeff[0] >> par2LpcShiftVal; + for(i=1; i> par2LpcShiftVal; + } + + /* normalize LpcCoeff and calc shiftfactor */ + for(i=0; i=par2LpcShiftVal) ? par2LpcShiftVal : shiftval; + + for(i=0; i0) { + + INT idx = 0; + + /* keep filter coefficients twice and save memory copy operation in + modulo state buffer */ +#if defined(ARCH_PREFER_MULT_32x16) + FIXP_SGL coeff[2*TNS_MAX_ORDER]; + const FIXP_SGL *pCoeff; + for(i=0;i=0); + signal[j] = (tmp<