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 /libAACenc/src/aacenc_pns.cpp | |
parent | a37315fe10ee143d6d0b28c19d41a476a23e63ea (diff) | |
download | ODR-AudioEnc-9bf37cc9712506b2483650c82d3c41152337ef7e.tar.gz ODR-AudioEnc-9bf37cc9712506b2483650c82d3c41152337ef7e.tar.bz2 ODR-AudioEnc-9bf37cc9712506b2483650c82d3c41152337ef7e.zip |
Fraunhofer AAC codec.
License boilerplate update to follow.
Change-Id: I2810460c11a58b6d148d84673cc031f3685e79b5
Diffstat (limited to 'libAACenc/src/aacenc_pns.cpp')
-rw-r--r-- | libAACenc/src/aacenc_pns.cpp | 532 |
1 files changed, 532 insertions, 0 deletions
diff --git a/libAACenc/src/aacenc_pns.cpp b/libAACenc/src/aacenc_pns.cpp new file mode 100644 index 0000000..8437132 --- /dev/null +++ b/libAACenc/src/aacenc_pns.cpp @@ -0,0 +1,532 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (2001) + 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: M. Lohwasser + contents/description: pns.c + +******************************************************************************/ + +#define PNS_CONFORMANCE_TEST 0 + +#include "aacenc_pns.h" +#include "psy_data.h" +#include "pnsparam.h" +#include "noisedet.h" +#include "bit_cnt.h" +#include "interface.h" + + +/* minCorrelationEnergy = (1.0e-10f)^2 ~ 2^-67 = 2^-47 * 2^-20 */ +static const FIXP_DBL minCorrelationEnergy = FL2FXCONST_DBL(0.0); /* FL2FXCONST_DBL((float)FDKpow(2.0,-47)); */ +/* noiseCorrelationThresh = 0.6^2 */ +static const FIXP_DBL noiseCorrelationThresh = FL2FXCONST_DBL(0.36); + +static void FDKaacEnc_FDKaacEnc_noiseDetection( PNS_CONFIG *pnsConf, + PNS_DATA *pnsData, + const INT sfbActive, + const INT *sfbOffset, + INT tnsOrder, + INT tnsPredictionGain, + INT tnsActive, + FIXP_DBL *mdctSpectrum, + INT *sfbMaxScaleSpec, + FIXP_SGL *sfbtonality ); + +static void FDKaacEnc_CalcNoiseNrgs( const INT sfbActive, + INT *pnsFlag, + FIXP_DBL *sfbEnergyLdData, + INT *noiseNrg ); + +/***************************************************************************** + + functionname: initPnsConfiguration + description: fill pnsConf with pns parameters + returns: error status + input: PNS Config struct (modified) + bitrate, samplerate, usePns, + number of sfb's, pointer to sfb offset + output: error code + +*****************************************************************************/ + +AAC_ENCODER_ERROR FDKaacEnc_InitPnsConfiguration(PNS_CONFIG *pnsConf, + INT bitRate, + INT sampleRate, + INT usePns, + INT sfbCnt, + const INT *sfbOffset, + const INT numChan, + const INT isLC) +{ + AAC_ENCODER_ERROR ErrorStatus; + + /* init noise detection */ + ErrorStatus = FDKaacEnc_GetPnsParam(&pnsConf->np, + bitRate, + sampleRate, + sfbCnt, + sfbOffset, + &usePns, + numChan, + isLC); + if (ErrorStatus != AAC_ENC_OK) + return ErrorStatus; + + pnsConf->minCorrelationEnergy = minCorrelationEnergy; + pnsConf->noiseCorrelationThresh = noiseCorrelationThresh; + + pnsConf->usePns = usePns; + + return AAC_ENC_OK; +} + + + +/***************************************************************************** + + functionname: FDKaacEnc_PnsDetect + description: do decision, if PNS shall used or not + returns: + input: pns config structure + pns data structure (modified), + lastWindowSequence (long or short blocks) + sfbActive + pointer to Sfb Energy, Threshold, Offset + pointer to mdct Spectrum + length of each group + pointer to tonality calculated in chaosmeasure + tns order and prediction gain + calculated noiseNrg at active PNS + output: pnsFlag in pns data structure + +*****************************************************************************/ +void FDKaacEnc_PnsDetect(PNS_CONFIG *pnsConf, + PNS_DATA *pnsData, + const INT lastWindowSequence, + const INT sfbActive, + const INT maxSfbPerGroup, + FIXP_DBL *sfbThresholdLdData, + const INT *sfbOffset, + FIXP_DBL *mdctSpectrum, + INT *sfbMaxScaleSpec, + FIXP_SGL *sfbtonality, + INT tnsOrder, + INT tnsPredictionGain, + INT tnsActive, + FIXP_DBL *sfbEnergyLdData, + INT *noiseNrg ) + +{ + int sfb; + int startNoiseSfb; + + if (pnsConf->np.detectionAlgorithmFlags & IS_LOW_COMLEXITY) { + if ( (!pnsConf->usePns) || /* pns enabled? */ + (lastWindowSequence == SHORT_WINDOW) ) /* currently only long blocks */ + { + FDKmemclear(pnsData->pnsFlag, MAX_GROUPED_SFB*sizeof(INT)); /* clear all pnsFlags */ + for (sfb=0; sfb<MAX_GROUPED_SFB; sfb++) { + noiseNrg[sfb] = NO_NOISE_PNS; /* clear nrg's of previous frame */ + } + return; + } + } + else { + if(!pnsConf->usePns) + return; + + /* PNS only for long Windows */ + if (pnsConf->np.detectionAlgorithmFlags & JUST_LONG_WINDOW) { + if(lastWindowSequence != LONG_WINDOW) { + for (sfb = 0; sfb < sfbActive; sfb++) { + pnsData->pnsFlag[sfb] = 0; /* clear all pnsFlags */ + } + return; + } + } + } + /* + call noise detection + */ + FDKaacEnc_FDKaacEnc_noiseDetection( pnsConf, + pnsData, + sfbActive, + sfbOffset, + tnsOrder, + tnsPredictionGain, + tnsActive, + mdctSpectrum, + sfbMaxScaleSpec, + sfbtonality ); + + /* set startNoiseSfb (long) */ + startNoiseSfb = pnsConf->np.startSfb; + + /* Set noise substitution status */ + for(sfb = 0; sfb < sfbActive; sfb++) { + + /* No PNS below startNoiseSfb */ + if(sfb < startNoiseSfb){ + pnsData->pnsFlag[sfb] = 0; + continue; + } + + /* + do noise substitution if + fuzzy measure is high enough + sfb freq > minimum sfb freq + signal in coder band is not masked + */ + + if((pnsData->noiseFuzzyMeasure[sfb] > FL2FXCONST_SGL(0.5)) && + ( (sfbThresholdLdData[sfb] + FL2FXCONST_DBL(0.5849625f/64.0f)) /* thr * 1.5 = thrLd +ld(1.5)/64 */ + < sfbEnergyLdData[sfb] ) ) + { + /* + mark in psyout flag array that we will code + this band with PNS + */ + pnsData->pnsFlag[sfb] = 1; /* PNS_ON */ + } + else{ + pnsData->pnsFlag[sfb] = 0; /* PNS_OFF */ + } + + /* no PNS if LTP is active */ + } + + /* avoid PNS holes */ + if((pnsData->noiseFuzzyMeasure[0]>FL2FXCONST_SGL(0.5f)) && (pnsData->pnsFlag[1])) { + pnsData->pnsFlag[0] = 1; + } + + for(sfb=1; sfb<maxSfbPerGroup-1; sfb++) { + if((pnsData->noiseFuzzyMeasure[sfb]>pnsConf->np.gapFillThr) && + (pnsData->pnsFlag[sfb-1]) && (pnsData->pnsFlag[sfb+1])) { + pnsData->pnsFlag[sfb] = 1; + } + } + + if(maxSfbPerGroup>0) { + /* avoid PNS hole */ + if((pnsData->noiseFuzzyMeasure[maxSfbPerGroup-1]>pnsConf->np.gapFillThr) && (pnsData->pnsFlag[maxSfbPerGroup-2])) { + pnsData->pnsFlag[maxSfbPerGroup-1] = 1; + } + /* avoid single PNS band */ + if(pnsData->pnsFlag[maxSfbPerGroup-2]==0) { + pnsData->pnsFlag[maxSfbPerGroup-1] = 0; + } + } + + /* avoid single PNS bands */ + if(pnsData->pnsFlag[1]==0) { + pnsData->pnsFlag[0] = 0; + } + + for(sfb=1; sfb<maxSfbPerGroup-1; sfb++) { + if((pnsData->pnsFlag[sfb-1]==0)&&(pnsData->pnsFlag[sfb+1]==0)) { + pnsData->pnsFlag[sfb] = 0; + } + } + + + /* + calculate noiseNrg's + */ + FDKaacEnc_CalcNoiseNrgs( sfbActive, + pnsData->pnsFlag, + sfbEnergyLdData, + noiseNrg ); +} + + +/***************************************************************************** + + functionname:FDKaacEnc_FDKaacEnc_noiseDetection + description: wrapper for noisedet.c + returns: + input: pns config structure + pns data structure (modified), + sfbActive + tns order and prediction gain + pointer to mdct Spectrumand Sfb Energy + pointer to Sfb tonality + output: noiseFuzzyMeasure in structure pnsData + flags tonal / nontonal + +*****************************************************************************/ +static void FDKaacEnc_FDKaacEnc_noiseDetection( PNS_CONFIG *pnsConf, + PNS_DATA *pnsData, + const INT sfbActive, + const INT *sfbOffset, + int tnsOrder, + INT tnsPredictionGain, + INT tnsActive, + FIXP_DBL *mdctSpectrum, + INT *sfbMaxScaleSpec, + FIXP_SGL *sfbtonality ) +{ + INT condition = TRUE; + if ( !(pnsConf->np.detectionAlgorithmFlags & IS_LOW_COMLEXITY) ) { + condition = (tnsOrder > 3); + } + /* + no PNS if heavy TNS activity + clear pnsData->noiseFuzzyMeasure + */ + if((pnsConf->np.detectionAlgorithmFlags & USE_TNS_GAIN_THR) && + (tnsPredictionGain >= pnsConf->np.tnsGainThreshold) && condition && + !((pnsConf->np.detectionAlgorithmFlags & USE_TNS_PNS) && (tnsPredictionGain >= pnsConf->np.tnsPNSGainThreshold) && (tnsActive)) ) + { + /* clear all noiseFuzzyMeasure */ + FDKmemclear(pnsData->noiseFuzzyMeasure, sfbActive*sizeof(FIXP_SGL)); + } + else + { + /* + call noise detection, output in pnsData->noiseFuzzyMeasure, + use real mdct spectral data + */ + FDKaacEnc_noiseDetect( mdctSpectrum, + sfbMaxScaleSpec, + sfbActive, + sfbOffset, + pnsData->noiseFuzzyMeasure, + &pnsConf->np, + sfbtonality); + } +} + + +/***************************************************************************** + + functionname:FDKaacEnc_CalcNoiseNrgs + description: Calculate the NoiseNrg's + returns: + input: sfbActive + if pnsFlag calculate NoiseNrg + pointer to sfbEnergy and groupLen + pointer to noiseNrg (modified) + output: noiseNrg's in pnsFlaged sfb's + +*****************************************************************************/ + +static void FDKaacEnc_CalcNoiseNrgs( const INT sfbActive, + INT *RESTRICT pnsFlag, + FIXP_DBL *RESTRICT sfbEnergyLdData, + INT *RESTRICT noiseNrg ) +{ + int sfb; + INT tmp = (-LOG_NORM_PCM)<<2; + + for(sfb = 0; sfb < sfbActive; sfb++) { + if(pnsFlag[sfb]) { + INT nrg = (-sfbEnergyLdData[sfb]+FL2FXCONST_DBL(0.5f/64.0f))>>(DFRACT_BITS-1-7); + noiseNrg[sfb] = tmp - nrg; + } + } +} + + +/***************************************************************************** + + functionname:FDKaacEnc_CodePnsChannel + description: Execute pns decission + returns: + input: sfbActive + pns config structure + use PNS if pnsFlag + pointer to Sfb Energy, noiseNrg, Threshold + output: set sfbThreshold high to code pe with 0, + noiseNrg marks flag for pns coding + +*****************************************************************************/ + +void FDKaacEnc_CodePnsChannel(const INT sfbActive, + PNS_CONFIG *pnsConf, + INT *RESTRICT pnsFlag, + FIXP_DBL *RESTRICT sfbEnergyLdData, + INT *RESTRICT noiseNrg, + FIXP_DBL *RESTRICT sfbThresholdLdData) +{ + INT sfb; + INT lastiNoiseEnergy = 0; + INT firstPNSband = 1; /* TRUE for first PNS-coded band */ + + /* no PNS */ + if(!pnsConf->usePns) { + for(sfb = 0; sfb < sfbActive; sfb++) { + /* no PNS coding */ + noiseNrg[sfb] = NO_NOISE_PNS; + } + return; + } + + /* code PNS */ + for(sfb = 0; sfb < sfbActive; sfb++) { + if(pnsFlag[sfb]) { + /* high sfbThreshold causes pe = 0 */ + if(noiseNrg[sfb] != NO_NOISE_PNS) + sfbThresholdLdData[sfb] = sfbEnergyLdData[sfb] + FL2FXCONST_DBL(1.0f/LD_DATA_SCALING); + + /* set noiseNrg in valid region */ + if(!firstPNSband) { + INT deltaiNoiseEnergy = noiseNrg[sfb] - lastiNoiseEnergy; + + if(deltaiNoiseEnergy > CODE_BOOK_PNS_LAV) + noiseNrg[sfb] -= deltaiNoiseEnergy - CODE_BOOK_PNS_LAV; + else if(deltaiNoiseEnergy < -CODE_BOOK_PNS_LAV) + noiseNrg[sfb] -= deltaiNoiseEnergy + CODE_BOOK_PNS_LAV; + } + else { + firstPNSband = 0; + } + lastiNoiseEnergy = noiseNrg[sfb]; + } + else { + /* no PNS coding */ + noiseNrg[sfb] = NO_NOISE_PNS; + } + } +} + + +/***************************************************************************** + + functionname:FDKaacEnc_PreProcessPnsChannelPair + description: Calculate the correlation of noise in a channel pair + + returns: + input: sfbActive + pointer to sfb energies left, right and mid channel + pns config structure + pns data structure left and right (modified) + + output: noiseEnergyCorrelation in pns data structure + +*****************************************************************************/ + +void FDKaacEnc_PreProcessPnsChannelPair(const INT sfbActive, + FIXP_DBL *RESTRICT sfbEnergyLeft, + FIXP_DBL *RESTRICT sfbEnergyRight, + FIXP_DBL *RESTRICT sfbEnergyLeftLD, + FIXP_DBL *RESTRICT sfbEnergyRightLD, + FIXP_DBL *RESTRICT sfbEnergyMid, + PNS_CONFIG *RESTRICT pnsConf, + PNS_DATA *pnsDataLeft, + PNS_DATA *pnsDataRight) +{ + INT sfb; + FIXP_DBL ccf; + + if(!pnsConf->usePns) + return; + + FIXP_DBL *RESTRICT pNoiseEnergyCorrelationL = pnsDataLeft->noiseEnergyCorrelation; + FIXP_DBL *RESTRICT pNoiseEnergyCorrelationR = pnsDataRight->noiseEnergyCorrelation; + + for(sfb=0;sfb< sfbActive;sfb++) { + FIXP_DBL quot = (sfbEnergyLeftLD[sfb]>>1) + (sfbEnergyRightLD[sfb]>>1); + + if(quot < FL2FXCONST_DBL(-32.0f/(float)LD_DATA_SCALING)) + ccf = FL2FXCONST_DBL(0.0f); + else { + FIXP_DBL accu = sfbEnergyMid[sfb]- (((sfbEnergyLeft[sfb]>>1)+(sfbEnergyRight[sfb]>>1))>>1); + INT sign = (accu < FL2FXCONST_DBL(0.0f)) ? 1 : 0 ; + accu = fixp_abs(accu); + + ccf = CalcLdData(accu) + FL2FXCONST_DBL((float)1.0f/(float)LD_DATA_SCALING) - quot; /* ld(accu*2) = ld(accu) + 1 */ + ccf = (ccf>=FL2FXCONST_DBL(0.0)) ? ((FIXP_DBL)MAXVAL_DBL) : (sign) ? -CalcInvLdData(ccf) : CalcInvLdData(ccf); + } + + pNoiseEnergyCorrelationL[sfb] = ccf; + pNoiseEnergyCorrelationR[sfb] = ccf; + } +} + + + +/***************************************************************************** + + functionname:FDKaacEnc_PostProcessPnsChannelPair + description: if PNS used at left and right channel, + use msMask to flag correlation + returns: + input: sfbActive + pns config structure + pns data structure left and right (modified) + pointer to msMask, flags correlation by pns coding (modified) + Digest of MS coding + output: pnsFlag in pns data structure, + msFlag in msMask (flags correlation) + +*****************************************************************************/ + +void FDKaacEnc_PostProcessPnsChannelPair(const INT sfbActive, + PNS_CONFIG *pnsConf, + PNS_DATA *pnsDataLeft, + PNS_DATA *pnsDataRight, + INT *RESTRICT msMask, + INT *msDigest ) +{ + INT sfb; + + if(!pnsConf->usePns) + return; + + for(sfb=0;sfb<sfbActive;sfb++) { + /* + MS post processing + */ + if( msMask[sfb] ) { + if( (pnsDataLeft->pnsFlag[sfb]) && + (pnsDataRight->pnsFlag[sfb]) ) { + /* AAC only: Standard */ + /* do this to avoid ms flags in layers that should not have it */ + if(pnsDataLeft->noiseEnergyCorrelation[sfb] <= pnsConf->noiseCorrelationThresh){ + msMask[sfb] = 0; + *msDigest = MS_SOME; + } + } + else { + /* + No PNS coding + */ + pnsDataLeft->pnsFlag[sfb] = 0; + pnsDataRight->pnsFlag[sfb] = 0; + } + } + + /* + Use MS flag to signal noise correlation if + pns is active in both channels + */ + if( (pnsDataLeft->pnsFlag[sfb]) && (pnsDataRight->pnsFlag[sfb]) ) { + if(pnsDataLeft->noiseEnergyCorrelation[sfb] > pnsConf->noiseCorrelationThresh) { + msMask[sfb] = 1; + *msDigest = MS_SOME; + } + } + } +} |