aboutsummaryrefslogtreecommitdiffstats
path: root/libAACenc/src/aacenc_pns.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libAACenc/src/aacenc_pns.cpp')
-rw-r--r--libAACenc/src/aacenc_pns.cpp532
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;
+ }
+ }
+ }
+}