diff --git a/lib_com/fd_cng_com_fx.c b/lib_com/fd_cng_com_fx.c index 0120c48dcbb4cf6d7c3187b9ac7dd778381c91bb..c51c122ed067dba36fd37862df5b277fa1aaf475 100644 --- a/lib_com/fd_cng_com_fx.c +++ b/lib_com/fd_cng_com_fx.c @@ -68,6 +68,10 @@ void initFdCngCom(HANDLE_FD_CNG_COM hFdCngCom, Word16 scale) /* Initialize the overlap-add */ set16_fx( hFdCngCom->timeDomainBuffer, 0, L_FRAME16k ); hFdCngCom->olapBufferAna = NULL; +#ifdef IVAS_FLOAT_FIXED + set16_fx( hFdCngCom->olapBufferAna_fx, 0, FFTLEN ); +#endif // IVAS_FLOAT_FIXED + move16(); set16_fx( hFdCngCom->olapBufferSynth, 0, FFTLEN ); hFdCngCom->olapBufferSynth2 = NULL; @@ -76,9 +80,11 @@ void initFdCngCom(HANDLE_FD_CNG_COM hFdCngCom, Word16 scale) /* Initialize the comfort noise generation */ set32_fx( hFdCngCom->fftBuffer, 0, FFTLEN ); set32_fx( hFdCngCom->cngNoiseLevel, 0, FFTCLDFBLEN ); + set16_fx( &hFdCngCom->cngNoiseLevelExp, 0, 1); /* Initialize quantizer */ set32_fx( hFdCngCom->sidNoiseEst, 0, NPART ); + set16_fx( &hFdCngCom->sidNoiseEstExp, 0, 1 ); set16_fx( hFdCngCom->A_cng, 0, M+1 ); hFdCngCom->A_cng[0] = 4096/*1.f Q12*/; /* 3Q12 */ move16(); @@ -145,7 +151,7 @@ void initFdCngCom(HANDLE_FD_CNG_COM hFdCngCom, Word16 scale) move16(); hFdCngCom->msAlphaCor[1] = 644245120l/*0.3f Q31*/; move16(); - + set16_fx(hFdCngCom->psize, 0, NPART); /* Initialize exponents */ hFdCngCom->exp_cldfb_periodog = 0; move16(); @@ -1042,6 +1048,620 @@ void minimum_statistics ( } +#ifdef IVAS_FLOAT_FIXED +void minimum_statistics_fx( + Word16 len, /* i : Total number of partitions (CLDFB or FFT) */ + Word16 lenFFT, /* i : Number of FFT partitions */ + Word16 *psize, /* i : Partition sizes, fractional */ + Word16 *msPeriodog, /* i : Periodogram (energies) */ + Word16 *msNoiseFloor, /* i/o: Noise floors (energies) */ + Word16 *msNoiseEst, /* i/o: Noise estimates (energies) */ + Word32 *msAlpha, /* i/o: Forgetting factors */ + Word16 *msPsd, /* i/o: Power Spectral Density (smoothed periodogram => energies) */ + Word16 *msPsdFirstMoment, /* i/o: PSD statistics of 1st order (energy means) */ + Word32 *msPsdSecondMoment, /* i/o: PSD statistics of 2nd order (energy variances) */ + Word32 *msMinBuf, /* i/o: Buffer of minima (energies) */ + Word32 *msBminWin, /* o : Bias correction factors */ + Word32 *msBminSubWin, /* o : Bias correction factors */ + Word32 *msCurrentMin, /* i/o: Local minima (energies) */ + Word32 *msCurrentMinOut, /* i/o: Local minima (energies) */ + Word32 *msCurrentMinSubWindow, /* i/o: Local minima (energies) */ + Word16 *msLocalMinFlag, /* i : Binary flag */ + Word16 *msNewMinFlag, /* i : Binary flag */ + Word16 *msPeriodogBuf, /* i/o: Buffer of periodograms (energies) */ + Word16 *msPeriodogBufPtr, /* i/o: Counter */ + HANDLE_FD_CNG_COM hFdCngCom, /* i/o: FD_CNG structure containing all buffers and variables */ + const Word16 enc_dec, /* i : encoder/decoder indicator */ + const Word16 element_mode /* i : IVAS element mode type */ +) +{ + Word16 i, j, k, s, s1, s2, s3; + Word16 len2; + Word16 current_len; + Word16 start, stop, cnt; + Word16 totsize; + Word16 inv_totsize; + + Word32 tmp, tmp0, tmp1; + Word32 scalar, scalar2, scalar3; + Word32 snr; + Word32 msAlphaHatMin2; + Word32 BminCorr; + Word32 QeqInvAv; + Word32 *ptr; + Word32 *msPsdSum; + Word32 *msPeriodogSum; + + Word16 tmp16, tmp16_1; + Word16 beta; + Word16 slope; + Word16 QeqInv; + Word16 scalar16; + Word16 scalar216; + Word16 scalar316; + Word16 msM_win; + Word16 msM_subwin; + Word16 msAlphaCorAlpha; + Word16 msAlphaCorAlpha2; + Word16 msPeriodogSum16; + Word16 msNoiseFloor16; +#ifdef BASOP_NOGLOB_DECLARE_LOCAL + Flag Overflow = 0; +#endif + + + len2 = i_mult( MSNUMSUBFR, len ); + + msM_win = hFdCngCom->msM_win; + move16(); + msM_subwin = hFdCngCom->msM_subwin; + move16(); + + msAlphaCorAlpha = MSALPHACORALPHA; + move16(); + msAlphaCorAlpha2 = MSALPHACORALPHA2; + move16(); + + msPsdSum = hFdCngCom->msPsdSum; + msPeriodogSum = hFdCngCom->msPeriodogSum; + + /* No minimum statistics at initialization */ + IF( LT_16( hFdCngCom->msFrCnt_init_counter, hFdCngCom->msFrCnt_init_thresh ) ) + { + Copy( msPeriodog, msPsd, len ); /* 6Q9 */ + Copy( msPeriodog, msNoiseFloor, len ); /* 6Q9 */ + Copy( msPeriodog, msNoiseEst, len ); /* 6Q9 */ + Copy( msPeriodog, msPsdFirstMoment, len ); /* 6Q9 */ + + set32_fx( msPsdSecondMoment, 0l /*0.0 Q31*/, len ); + msPeriodogSum[0] = dotp_s_fx( msPeriodog, psize, lenFFT, CNG_HS ); + move32(); + msPsdSum[0] = msPeriodogSum[0]; /* 16Q15 */ + move32(); + + IF( LT_16( lenFFT, len ) ) + { + msPeriodogSum[1] = dotp_s_fx( msPeriodog + lenFFT, psize + lenFFT, sub( len, lenFFT ), CNG_HS ); + move32(); + msPsdSum[1] = msPeriodogSum[1]; /* 16Q15 */ + move32(); + } + + /* Increment frame counter at initialization */ + /* Some frames are sometimes zero at initialization => ignore them */ + IF( LT_16( msPeriodog[0], hFdCngCom->init_old ) ) + { + set32_fx( msCurrentMinOut, 2147483647l /*1.0 Q31*/, len ); /* 16Q15 */ + set32_fx( msCurrentMin, 2147483647l /*1.0 Q31*/, len ); /* 16Q15 */ + set32_fx( msMinBuf, 2147483647l /*1.0 Q31*/, len2 ); /* 16Q15 */ + set32_fx( msCurrentMinSubWindow, 2147483647l /*1.0 Q31*/, len ); /* 16Q15 */ + + hFdCngCom->msFrCnt_init_counter = add( hFdCngCom->msFrCnt_init_counter, 1 ); + move16(); + } + hFdCngCom->init_old = msPeriodog[0]; /* 6Q9 */ + move16(); + } + ELSE + { + /* Consider the FFT and CLDFB bands separately + - first iteration for FFT bins, + - second one for CLDFB bands in SWB mode */ + cnt = 0; + move16(); + start = 0; + move16(); + stop = lenFFT; + move16(); + totsize = sub( hFdCngCom->stopFFTbin, hFdCngCom->startBand ); + WHILE( GT_16( stop, start ) ) + { + current_len = sub( stop, start ); + + /* Compute smoothed correction factor for PSD smoothing */ + + /* msPeriodogSum[cnt] with format 16Q15 */ + msPeriodogSum[cnt] = dotp_s_fx( msPeriodog + start, psize + start, current_len, CNG_HS ); + move32(); + + IF( msPeriodogSum[cnt] == 0 ) + { + hFdCngCom->msAlphaCor[cnt] = Mpy_32_16_1( hFdCngCom->msAlphaCor[cnt], msAlphaCorAlpha ); + move32(); + } + ELSE + { + /* calculate scalar with normalized msPeriodogSum[cnt], exponent -2*s1 */ + s1 = norm_l( msPeriodogSum[cnt] ); + msPeriodogSum16 = round_fx( L_shl( msPeriodogSum[cnt], s1 ) ); + scalar = L_mult( msPeriodogSum16, msPeriodogSum16 ); + + /* calculate difference, both elements in 16Q15 format, use absolute value + to avoid -1.0 x -1.0 multiplications later */ + scalar2 = L_abs( L_sub( msPsdSum[cnt], msPeriodogSum[cnt] ) ); + + s2 = WORD32_BITS - 1; + move16(); + if ( scalar2 != 0 ) + { + /* use absolute value to avoid -1.0 x -1.0 multiplications */ + s2 = norm_l( scalar2 ); + } +#ifdef BASOP_NOGLOB + scalar216 = round_fx_o( L_shl_o( scalar2, s2, &Overflow ), &Overflow ); +#else + scalar216 = round_fx( L_shl( scalar2, s2 ) ); +#endif + scalar2 = L_mult( scalar216, scalar216 ); + + /* find common exponent */ + tmp16_1 = sub( s1, s2 ); + tmp16 = s_min( shl( abs_s( tmp16_1 ), 1 ), WORD32_BITS - 1 ); + if ( tmp16_1 < 0 ) + { + scalar2 = L_shr( scalar2, tmp16 ); + } + if ( tmp16_1 > 0 ) + { + scalar = L_shr( scalar, tmp16 ); + } + + + /* add scalar and scalar2, avoid overflows */ + scalar = L_shr( scalar, 1 ); + scalar2 = L_shr( scalar2, 1 ); + scalar3 = L_add( scalar, scalar2 ); + + /* calculate division */ + scalar16 = BASOP_Util_Divide3232_uu_1616_Scale( scalar, scalar3, &s3 ); + s3 = s_max( s3, -( WORD16_BITS - 1 ) ); + scalar16 = shl( scalar16, s3 ); + scalar16 = s_max( scalar16, MSALPHACORMAX ); + + hFdCngCom->msAlphaCor[cnt] = L_add( Mpy_32_16_1( hFdCngCom->msAlphaCor[cnt], msAlphaCorAlpha ), + L_mult( scalar16, msAlphaCorAlpha2 ) ); + move32(); + } + + /* Compute SNR */ + + /* msPeriodogSum[cnt] with format 16Q15 */ + snr = dotp_s_fx( msNoiseFloor + start, psize + start, current_len, CNG_HS ); + + IF( GT_32( L_shr( Mpy_32_16_1( msPsdSum[cnt], 18431 /*0.56246299817 Q15*/ ), 13 ), snr ) ) + { + tmp0 = BASOP_Util_Log2( msPsdSum[cnt] ); + tmp1 = BASOP_Util_Log2( snr ); + tmp1 = L_sub( tmp0, tmp1 ); + tmp1 = Mpy_32_16_1( tmp1, MSSNREXP ); + msAlphaHatMin2 = BASOP_Util_InvLog2( tmp1 ); + } + ELSE + { + msAlphaHatMin2 = MSALPHAHATMIN; + move32(); + } + scalar = Mpy_32_16_1( hFdCngCom->msAlphaCor[cnt], MSALPHAMAX ); + + FOR( j = start; j < stop; j++ ) + { + /* Compute optimal smoothing parameter for PSD estimation */ test(); + test(); + IF( ( scalar == 0 ) || ( msNoiseFloor[j] == 0 ) ) + { + msAlpha[j] = msAlphaHatMin2; + move32(); + } + ELSE + { + /* calculate scalar2 with normalized msNoiseFloor[j], exponent -2*s1 */ + s1 = WORD16_BITS - 1; + move16(); + if ( msNoiseFloor[j] != 0 ) + { + s1 = norm_s( msNoiseFloor[j] ); + } + msNoiseFloor16 = shl( msNoiseFloor[j], s1 ); + scalar2 = L_mult( msNoiseFloor16, msNoiseFloor16 ); + + /* calculate difference, both elements in 6Q9 format, use absolute value + to avoid -1.0 x -1.0 multiplications later */ + scalar316 = abs_s( sub( msPsd[j], msNoiseFloor[j] ) ); + + s2 = WORD16_BITS - 1; + move16(); + if ( scalar316 != 0 ) + { + /* use absolute value to avoid -1.0 x -1.0 multiplications */ + s2 = norm_s( scalar316 ); + } + scalar316 = shl( scalar316, s2 ); + scalar3 = L_mult( scalar316, scalar316 ); + + /* find common exponent */ + tmp16_1 = sub( s1, s2 ); + tmp16 = s_min( shl( abs_s( tmp16_1 ), 1 ), WORD32_BITS - 1 ); + if ( tmp16_1 < 0 ) + { + scalar3 = L_shr( scalar3, tmp16 ); + } + if ( tmp16_1 > 0 ) + { + scalar2 = L_shr( scalar2, tmp16 ); + } + + /* add scalar2 and scalar3, avoid overflows */ + scalar2 = L_shr( scalar2, 1 ); + scalar3 = L_shr( scalar3, 1 ); + scalar3 = L_add( scalar2, scalar3 ); + + /* calculate division */ + tmp16 = BASOP_Util_Divide3232_uu_1616_Scale( scalar2, scalar3, &s3 ); + scalar2 = Mpy_32_16_1( scalar, tmp16 ); + s3 = s_max( s3, -( WORD32_BITS - 1 ) ); + scalar2 = L_shl( scalar2, s3 ); + msAlpha[j] = L_max( scalar2, msAlphaHatMin2 ); + move32(); + } + + /* Compute the PSD (smoothed periodogram) in each band */ + msPsd[j] = round_fx( L_add( Mpy_32_16_1( msAlpha[j], msPsd[j] ), + Mpy_32_16_1( L_sub( 2147483647l /*1.0 Q31*/, msAlpha[j] ), msPeriodog[j] ) ) ); + } + msPsdSum[cnt] = dotp_s_fx( msPsd + start, psize + start, current_len, CNG_HS ); + move32(); + + QeqInvAv = 0l /*0.0 Q31*/; + move32(); + + /* scalar: 7Q24 format */ + tmp = 1191182336l /*(float)(MSNUMSUBFR*MSSUBFRLEN)-1.0 Q24*/; + move32(); + scalar = L_sub( tmp, L_mult( round_fx( tmp ), msM_win ) ); + + /* scalar2: 4Q27 format */ + tmp = 1476395008l /*(float)MSSUBFRLEN-1.0 Q27*/; + move32(); + scalar2 = L_sub( tmp, L_mult( round_fx( tmp ), msM_subwin ) ); + + FOR( j = start; j < stop; j++ ) + { + /* Compute variance of PSD */ + tmp = L_min( msAlpha[j], MSBETAMAX_SQRT ); + + s1 = WORD32_BITS - 1; + move16(); + if ( tmp != 0 ) + { + s1 = norm_l( tmp ); + } + s2 = shl( s1, 1 ); + + s2 = s_min( s2, WORD32_BITS - 1 ); + + /* beta: scaled by s2 */ +#ifdef BASOP_NOGLOB + tmp16 = round_fx_o( L_shl_o( tmp, s1, &Overflow ), &Overflow ); +#else + tmp16 = round_fx( L_shl( tmp, s1 ) ); +#endif + beta = mult_r( tmp16, tmp16 ); + + /* scalar3: scaled by s3 */ + scalar3 = L_sub( L_deposit_l( msPsd[j] ), L_deposit_l( msPsdFirstMoment[j] ) ); + s3 = norm_l( scalar3 ); + scalar3 = L_shl( scalar3, s3 ); + + /* msPsdFirstMoment: 6Q9 */ + tmp = L_msu( L_mult( beta, msPsdFirstMoment[j] ), beta, msPsd[j] ); + msPsdFirstMoment[j] = add( round_fx( L_shr( tmp, s2 ) ), msPsd[j] ); + move16(); + + /* msPsdSecondMoment: 12Q19 */ + tmp0 = L_shr( Mpy_32_16_r( msPsdSecondMoment[j], beta ), s2 ); + tmp1 = Mpy_32_32( scalar3, scalar3 ); + tmp1 = L_shr( L_sub( tmp1, L_shr( Mpy_32_16_r( tmp1, beta ), s2 ) ), sub( shl( s3, 1 ), 32 ) ); + msPsdSecondMoment[j] = L_add( tmp0, tmp1 ); + move32(); + + /* Compute inverse of amount of degrees of freedom */ + QeqInv = MSQEQINVMAX; + move16(); + + IF( msNoiseFloor[j] != 0 /*0.0 Q15*/ ) + { + tmp = L_mult( msNoiseFloor[j], msNoiseFloor[j] ); + tmp16 = BASOP_Util_Divide3232_uu_1616_Scale( msPsdSecondMoment[j], tmp, &s ); + /* consider factor of 2 */ + s = s_min( s_max( sub( s, 1 ), -( WORD16_BITS - 1 ) ), ( WORD16_BITS - 1 ) ); + if ( s < 0 ) + { + QeqInv = shl( tmp16, s ); + } + QeqInv = s_min( QeqInv, MSQEQINVMAX ); + } + QeqInvAv = L_add( QeqInvAv, L_mult( QeqInv, psize[j] ) ); + + /* Compute bias correction Bmin */ + tmp0 = Mpy_32_16_1( scalar, QeqInv ); + tmp1 = L_sub( 1073741824l /*0.5 Q31*/, L_mult( msM_win, QeqInv ) ); + tmp16 = BASOP_Util_Divide3232_uu_1616_Scale( tmp0, tmp1, &s ); + msBminWin[j] = L_add( 134217728l /*1.0 Q27*/, L_shl( L_deposit_h( tmp16 ), add( s, 7 - 4 ) ) ); + move32(); + + tmp0 = Mpy_32_16_1( scalar2, QeqInv ); + tmp1 = L_sub( 1073741824l /*0.5 Q31*/, L_mult( msM_subwin, QeqInv ) ); + tmp16 = BASOP_Util_Divide3232_uu_1616_Scale( tmp0, tmp1, &s ); + msBminSubWin[j] = L_add( 134217728l /*1.0 Q27*/, L_shl( L_deposit_h( tmp16 ), s ) ); + move32(); + } + + inv_totsize = BASOP_Util_Divide3232_uu_1616_Scale( 1, totsize, &s ); + QeqInvAv = Mpy_32_16_1( QeqInvAv, inv_totsize ); + QeqInvAv = L_shl( QeqInvAv, s ); + hFdCngCom->msQeqInvAv[cnt] = QeqInvAv; + move32(); + + /* New minimum? */ + + /* exponent QeqInvAv: CNG_S, exponent MSAV: (4>>1) */ + s = CNG_S + 2 * MSAV_EXP; + move16(); + BminCorr = Mpy_32_16_1( Sqrt32( QeqInvAv, &s ), MSAV ); + BminCorr = L_shl( BminCorr, sub( s, 1 ) ); + + /* exponent BminCorr: 1 */ + BminCorr = L_add( BminCorr, 1073741824l /*0.5 Q31*/ ); + + FOR( j = start; j < stop; j++ ) + { + /* exponent scalar: CNG_S+1 */ + scalar = Mpy_32_16_1( BminCorr, msPsd[j] ); + + /* exponent scalar2: CNG_S+1+4 */ + scalar2 = Mpy_32_32( scalar, msBminWin[j] ); + + msNewMinFlag[j] = 0; + move16(); + IF( LT_32( scalar2, msCurrentMin[j] ) /*0.0 Q31*/ ) + { + msNewMinFlag[j] = 1; + move16(); + /* exponent msCurrentMin[j]: CNG_S+1+4 */ + msCurrentMin[j] = scalar2; + move32(); + /* exponent msCurrentMinSubWindow[j]: CNG_S */ + BASOP_SATURATE_WARNING_OFF_EVS; +#ifdef BASOP_NOGLOB + msCurrentMinSubWindow[j] = L_shl_o( Mpy_32_32( scalar, msBminSubWin[j] ), 5, &Overflow ); +#else /* BASOP_NOGLOB */ + msCurrentMinSubWindow[j] = L_shl( Mpy_32_32( scalar, msBminSubWin[j] ), 5 ); +#endif /* BASOP_NOGLOB */ + move32(); + BASOP_SATURATE_WARNING_ON_EVS; + } + } + + /* This is used later to identify local minima */ + IF( GE_16( hFdCngCom->msFrCnt, MSSUBFRLEN ) ) + { + FOR( i = 0; i < 3; i++ ) + { + IF( LT_32( hFdCngCom->msQeqInvAv[cnt], L_shr( L_deposit_h( msQeqInvAv_thresh[i] ), CNG_S ) ) /*0.0 Q31*/ ) + { + BREAK; + } + } + /* format 1Q30 */ + hFdCngCom->msSlope[cnt] = msNoiseSlopeMax[i]; + move32(); + } + + /* Consider the FFT and CLDFB bands separately */ + start = stop; + move16(); + stop = len; + move16(); + totsize = sub( hFdCngCom->stopBand, hFdCngCom->stopFFTbin ); + cnt = add( cnt, 1 ); + } /*while (stop > start)*/ + + /* Update minimum between sub windows */ + test(); + IF( GT_16( hFdCngCom->msFrCnt, 1 ) && LT_16( hFdCngCom->msFrCnt, MSSUBFRLEN ) ) + { + FOR( j = 0; j < len; j++ ) + { + if ( msNewMinFlag[j] > 0 ) + { + msLocalMinFlag[j] = 1; + move16(); + } + if ( LT_32( msCurrentMinSubWindow[j], msCurrentMinOut[j] ) /*0.0 Q31*/ ) + { + /* msCurrentMinOut[j] scaled with CNG_S */ + msCurrentMinOut[j] = msCurrentMinSubWindow[j]; + move32(); + } + } + /* Get the current noise floor */ + Copy_Scale_sig_32_16( msCurrentMinOut, msNoiseFloor, len, -16 ); + } + ELSE /* sub window complete */ + { + IF( GE_16( hFdCngCom->msFrCnt, MSSUBFRLEN ) ) + { + /* Collect buffers */ + Copy32( msCurrentMinSubWindow, msMinBuf + len * hFdCngCom->msMinBufferPtr, len ); + + /* Compute minimum among all buffers */ + Copy32( msMinBuf, msCurrentMinOut, len ); + ptr = msMinBuf + len; + FOR( i = 1; i < MSNUMSUBFR; i++ ) + { + FOR( j = 0; j < len; j++ ) + { + if ( LT_32( *ptr, msCurrentMinOut[j] ) /*0.0 Q31*/ ) + { + msCurrentMinOut[j] = *ptr; + move32(); + } + ptr++; + } + } + + /* Take over local minima */ + slope = hFdCngCom->msSlope[0]; + move16(); + FOR( j = 0; j < len; j++ ) + { + if ( EQ_16( j, lenFFT ) ) + { + slope = hFdCngCom->msSlope[1]; + move16(); + } + test(); + test(); + test(); + IF( ( msLocalMinFlag[j] != 0 ) && ( msNewMinFlag[j] == 0 ) && ( LT_32( L_shr( msCurrentMinSubWindow[j], 1 ), Mpy_32_16_1( msCurrentMinOut[j], slope ) ) /*0.0 Q31*/ ) && ( GT_32( msCurrentMinSubWindow[j], msCurrentMinOut[j] ) /*0.0 Q31*/ ) ) + { + msCurrentMinOut[j] = msCurrentMinSubWindow[j]; + move32(); + i = j; + move16(); + FOR( k = 0; k < MSNUMSUBFR; k++ ) + { + msMinBuf[i] = msCurrentMinOut[j]; + move32(); + i = add( i, len ); + } + } + } + + /* Reset */ + set16_fx( msLocalMinFlag, 0, len ); + set32_fx( msCurrentMin, 2147483647l /*1.0 Q31*/, len ); + + /* Get the current noise floor */ + Copy_Scale_sig_32_16( msCurrentMinOut, msNoiseFloor, len, -16 ); + } + } + + + /* Detect sudden offsets based on the FFT bins (core bandwidth) */ + IF( GT_32( Mpy_32_16_1( msPsdSum[0], 655 /*0.02 Q15*/ ), msPeriodogSum[0] ) /*0.0 Q31*/ ) + { + IF( hFdCngCom->offsetflag > 0 ) + { + Copy( msPeriodog, msPsd, len ); + FOR( j = 0; j < len; j++ ) + { + msCurrentMinOut[j] = L_deposit_h( msPeriodog[j] ); + } + set32_fx( hFdCngCom->msAlphaCor, 2147483647l /*1.0 Q31*/, cnt ); + set32_fx( msAlpha, 0l /*0.0 Q31*/, len ); + Copy( msPeriodog, msPsdFirstMoment, len ); + set32_fx( msPsdSecondMoment, 0l /*0.0 Q31*/, len ); + + msPsdSum[0] = dotp_s_fx( msPeriodog, psize, lenFFT, CNG_HS ); + move32(); + IF( LT_16( lenFFT, len ) ) + { + msPsdSum[1] = dotp_s_fx( msPeriodog + lenFFT, psize + lenFFT, sub( len, lenFFT ), CNG_HS ); + move32(); + } + } + hFdCngCom->offsetflag = 1; + move16(); + } + ELSE + { + hFdCngCom->offsetflag = 0; + move16(); + } + + + /* Increment frame counter */ + IF( EQ_16( hFdCngCom->msFrCnt, MSSUBFRLEN ) ) + { + hFdCngCom->msFrCnt = 1; + move16(); + hFdCngCom->msMinBufferPtr = add( hFdCngCom->msMinBufferPtr, 1 ); + move16(); + if ( EQ_16( hFdCngCom->msMinBufferPtr, MSNUMSUBFR ) ) + { + hFdCngCom->msMinBufferPtr = 0; + move16(); + } + } + ELSE + { + hFdCngCom->msFrCnt = add( hFdCngCom->msFrCnt, 1 ); + } + + /* Smooth noise estimate during CNG phases */ + FOR( j = 0; j < len; j++ ) + { + msNoiseEst[j] = round_fx( L_mac( L_mult( 31130 /*0.95 Q15*/, msNoiseEst[j] ), 1638 /*0.05 Q15*/, msNoiseFloor[j] ) ); + } + } + if ( enc_dec == DEC && element_mode == IVAS_CPE_TD ) + { + // v_multc(msNoiseEst, 1.4125f, msNoiseEst, NPART_SHAPING); + v_multc_att( msNoiseEst, 23142, msNoiseEst, NPART_SHAPING ); + } + /* Collect buffers */ + Copy( msPeriodog, msPeriodogBuf + len * ( *msPeriodogBufPtr ), len ); + + *msPeriodogBufPtr = add( *msPeriodogBufPtr, 1 ); + move16(); + if ( EQ_16( *msPeriodogBufPtr, MSBUFLEN ) ) + { + ( *msPeriodogBufPtr ) = 0; + move16(); + } + + /* Upper limit the noise floors with the averaged input energy */ + FOR( j = 0; j < len; j++ ) + { + scalar = L_mult( msPeriodogBuf[j], 6554 /*1.0/MSBUFLEN Q15*/ ); + + FOR( i = j + len; i < MSBUFLEN * len; i += len ) + { + scalar = L_mac( scalar, msPeriodogBuf[i], 6554 /*1.0/MSBUFLEN Q15*/ ); + } + scalar16 = round_fx( scalar ); + if ( GT_16( msNoiseEst[j], scalar16 ) /*0.0 Q15*/ ) + { + msNoiseEst[j] = scalar16; + move16(); + } + + assert( msNoiseEst[j] >= 0 /*0.0 Q15*/ ); + } +} +#endif // IVAS_FLOAT_FIXED + /*------------------------------------------------------------------- * apply_scale() * @@ -1421,6 +2041,62 @@ void AnalysisSTFT ( } +#ifdef IVAS_FLOAT_FIXED +/*------------------------------------------------------------------- + * AnalysisSTFT_fx() + * + * STFT analysis filterbank + *-------------------------------------------------------------------*/ +void AnalysisSTFT_fx( + const Word16 *timeDomainInput, + Word16 Q, + Word32 *fftBuffer, /* o : FFT bins */ + Word16 *fftBuffer_exp, /* i : exponent of FFT bins */ + HANDLE_FD_CNG_COM hFdCngCom /* i/o: FD_CNG structure containing all buffers and variables */ +) +{ + Word16 i, len; + const Word32 *olapWin; + Word16 *olapBuffer; + + assert( ( hFdCngCom->fftlen >> 1 ) == hFdCngCom->frameSize ); + + /* pointer inititialization */ + assert( hFdCngCom->olapBufferAna != NULL ); + olapBuffer = hFdCngCom->olapBufferAna_fx; + olapWin = hFdCngCom->olapWinAna_fx; + + /* olapWin factor is scaled with one bit */ + *fftBuffer_exp = 1; + move16(); + len = sub( hFdCngCom->fftlen, hFdCngCom->frameSize ); + assert( len <= 320 ); /* see size of olapBuffer */ + + /* Window the signal */ + Copy( olapBuffer + hFdCngCom->frameSize, olapBuffer, len ); + + FOR( i = 0; i < hFdCngCom->frameSize; i++ ) + { + olapBuffer[i + len] = shr( timeDomainInput[i], Q ); + move16(); + } + + /* Window the signal */ + v_L_mult_3216( olapWin, olapBuffer, fftBuffer, hFdCngCom->fftlen ); + + FOR( i = 0; i < hFdCngCom->fftlen; i++ ) + { + fftBuffer[i] = L_shr( fftBuffer[i], 11 ); + } + *fftBuffer_exp = WORD16_BITS + 11; + + /* Perform FFT */ + RFFTN_fx( fftBuffer, hFdCngCom->fftSineTab_fx, hFdCngCom->fftlen, -1 ); + + + return; +} +#endif // IVAS_FLOAT_FIXED /*------------------------------------------------------------------- * SynthesisSTFT() diff --git a/lib_com/prot_fx1.h b/lib_com/prot_fx1.h index f1fa2fe2ecb01a8dac1fc5d35ea3c7ffa43c3915..c9008c968fe31b11d8f6dbf2e149c01009b82cbd 100644 --- a/lib_com/prot_fx1.h +++ b/lib_com/prot_fx1.h @@ -397,6 +397,24 @@ void v_multc_att32( Word32 y[], /* o : Output vector that contains att*x */ const Word16 N /* i : Vector length */ ); +void v_multc_att3232( + const Word32 x[], /* i : Input vector Qx */ + const Word32 att, /* i : Constant Q32, <= MAX_32 */ + Word32 y[], /* o : Output vector that contains att*x */ + const Word16 N /* i : Vector length */ +); +void v_L_mult_1616( + const Word16 x1[], /* i : Input vector 1 */ + const Word16 x2[], /* i : Input vector 2 */ + Word32 y[], /* o : Output vector that contains vector 1 .* vector 2 */ + const Word16 N /* i : Vector length */ +); +void v_L_mult_3216( + const Word32 x1[], /* i : Input vector 1 */ + const Word16 x2[], /* i : Input vector 2 */ + Word32 y[], /* o : Output vector that contains vector 1 .* vector 2 */ + const Word16 N /* i : Vector length */ +); void add_vec_fx( const Word16 x1[], /* i : Input vector 1 */ const Word16 Qx1, /* i : SCaling of input 1 */ @@ -513,6 +531,15 @@ void delay_signal32( const Word16 delay /* i : delay in samples */ ); +Word16 lin_interp_fx( + const Word16 x, /* i : the value to be mapped */ + const Word16 x1, /* i : source range interval: low end */ + const Word16 y1, /* i : source range interval: high end */ + const Word16 x2, /* i : target range interval: low */ + const Word16 y2, /* i : target range interval: high */ + const Word16 flag_sat /* i : flag to indicate whether to apply saturation */ +); + Word16 ceil_log_2( UWord64 val ); #ifdef IVAS_FLOAT_FIXED diff --git a/lib_com/prot_fx2.h b/lib_com/prot_fx2.h index d046453a1e595bce6ce984c5c581bd186348cf2a..638feecc695fb70a0f8aa642b98e78e704539dba 100644 --- a/lib_com/prot_fx2.h +++ b/lib_com/prot_fx2.h @@ -4601,6 +4601,35 @@ void minimum_statistics(Word16 len, /* i : Total number of Word16 *msPeriodogBufPtr, /* i/o: Counter */ HANDLE_FD_CNG_COM st /* i/o: FD_CNG structure containing buffers and variables */ ); + +#ifdef IVAS_FLOAT_FIXED +void minimum_statistics_fx( + Word16 len, /* i : Total number of partitions (CLDFB or FFT) */ + Word16 lenFFT, /* i : Number of FFT partitions */ + Word16 *psize, /* i : Partition sizes, fractional */ + Word16 *msPeriodog, /* i : Periodogram (energies) */ + Word16 *msNoiseFloor, /* i/o: Noise floors (energies) */ + Word16 *msNoiseEst, /* i/o: Noise estimates (energies) */ + Word32 *msAlpha, /* i/o: Forgetting factors */ + Word16 *msPsd, /* i/o: Power Spectral Density (smoothed periodogram => energies) */ + Word16 *msPsdFirstMoment, /* i/o: PSD statistics of 1st order (energy means) */ + Word32 *msPsdSecondMoment, /* i/o: PSD statistics of 2nd order (energy variances) */ + Word32 *msMinBuf, /* i/o: Buffer of minima (energies) */ + Word32 *msBminWin, /* o : Bias correction factors */ + Word32 *msBminSubWin, /* o : Bias correction factors */ + Word32 *msCurrentMin, /* i/o: Local minima (energies) */ + Word32 *msCurrentMinOut, /* i/o: Local minima (energies) */ + Word32 *msCurrentMinSubWindow, /* i/o: Local minima (energies) */ + Word16 *msLocalMinFlag, /* i : Binary flag */ + Word16 *msNewMinFlag, /* i : Binary flag */ + Word16 *msPeriodogBuf, /* i/o: Buffer of periodograms (energies) */ + Word16 *msPeriodogBufPtr, /* i/o: Counter */ + HANDLE_FD_CNG_COM hFdCngCom, /* i/o: FD_CNG structure containing all buffers and variables */ + const Word16 enc_dec, /* i : encoder/decoder indicator */ + const Word16 element_mode /* i : IVAS element mode type */ +); +#endif // IVAS_FLOAT_FIXED + /* Apply bitrate-dependant scale */ void apply_scale( Word32* scale, /* o : scalefactor */ @@ -4642,6 +4671,14 @@ void AnalysisSTFT( HANDLE_FD_CNG_COM hFdCngCom /* i/o: FD_CNG structure containing all buffers and variables */ ); +void AnalysisSTFT_fx( + const Word16 *timeDomainInput, + Word16 Q, + Word32 *fftBuffer, /* o : FFT bins */ + Word16 *fftBuffer_exp, /* i : exponent of FFT bins */ + HANDLE_FD_CNG_COM hFdCngCom /* i/o: FD_CNG structure containing all buffers and variables */ +); + /* STFT synthesis filterbank */ void SynthesisSTFT( Word32* fftBuffer, /* i : pointer to FFT bins */ @@ -6528,6 +6565,18 @@ void init_tcx_cfg_fx( Word16 is_music ); + Word16 ApplyFdCng_fx( + Word16 *timeDomainInput, /* i : pointer to time domain input */ + Word16 Q, + Word32 *powerSpectrum, + Word32 **cldfbBufferReal, /* i/o: real part of the CLDFB buffer */ + Word32 **cldfbBufferImag, /* i/o: imaginary part of the CLDFB buffer */ + Word16 *cldfbBufferScale, /* o : pointer to the scalefactor for real and imaginary part of the CLDFB buffer */ + Decoder_State *st, + const Word16 concealWholeFrame, /* i : binary flag indicating frame loss */ + Word16 is_music +); + /* Perform noise estimation */ void perform_noise_estimation_dec( const Word16* timeDomainInput, /* i: pointer to time domain i */ @@ -6546,6 +6595,19 @@ void init_tcx_cfg_fx( #endif ); + void perform_noise_estimation_dec_fx( + const Word16 *timeDomainInput, /* i: pointer to time domain input */ + const Word16 Q, + Word32 *power_spectrum, + HANDLE_FD_CNG_DEC hFdCngDec, /* i/o: FD_CNG structure containing all buffers and variables */ + const Word16 element_mode, /* i : element mode */ + const Word16 bwidth, /* i : audio bandwidth */ + const Word16 L_frame, /* i : frame length at internal Fs */ + const Word16 last_L_frame, /* i : frame length of the last frame at internal Fs */ + const Word32 last_core_brate, /* i : previous frame core bitrate */ + const Word16 VAD /* i : VAD flag in the decoder */ + ); + /* Decode the CLDFB-CNG bitstream */ void FdCng_decodeSID(HANDLE_FD_CNG_COM st, /* i/o: FD_CNG structure containing all buffers and variables */ Decoder_State *corest); /* i/o: decoder state structure */ diff --git a/lib_com/rom_com.c b/lib_com/rom_com.c index f8386649e2f114bf99a0ea512f9acfa575e50c4d..1a1ffa0bb1aa217fadef425843db0ddf19988051 100644 --- a/lib_com/rom_com.c +++ b/lib_com/rom_com.c @@ -13101,6 +13101,158 @@ const float olapWinAna640[640] = 0.0659250169992446900000000f, 0.0589897930622100830000000f, 0.0520531460642814640000000f, 0.0451152473688125610000000f, 0.0381762608885765080000000f, 0.0312363542616367340000000f, 0.0242956969887018200000000f, 0.0173544511198997500000000f, 0.0104127889499068260000000f, 0.0034708750899881124000000f }; +#ifdef IVAS_FLOAT_FIXED +const Word32 olapWinAna512_fx[512] = { /* Q30 */ + 4658693, 13975905, 23292590, 32608396, 41922980, 51235980, 60547056, 69855848, + 79162008, 88465192, 97765048, 107061216, 116353360, 125641120, 134924144, 144202096, + 153474624, 162741360, 172001968, 181256112, 190503440, 199743568, 208976192, 218200960, + 227417488, 236625472, 245824528, 255014368, 264194560, 273364832, 282524800, 291674144, + 300812512, 309939520, 319054880, 328158240, 337249248, 346327520, 355392768, 364444672, + 373482816, 382506912, 391516576, 400511584, 409491456, 418455904, 427404576, 436337216, + 445253408, 454152800, 463035104, 471900032, 480747136, 489576160, 498386752, 507178592, + 515951328, 524704608, 533438144, 542151616, 550844672, 559516992, 568168256, 576798144, + 585406272, 593992320, 602556096, 611097152, 619615168, 628109888, 636580992, 645028096, + 653450880, 661849088, 670222400, 678570432, 686892992, 695189632, 703460096, 711704128, + 719921344, 728111424, 736274112, 744409088, 752515968, 760594560, 768644608, 776665664, + 784657408, 792619584, 800552064, 808454272, 816326144, 824167232, 831977280, 839756032, + 847503104, 855218368, 862901376, 870551936, 878169728, 885754432, 893305728, 900823488, + 908307264, 915756864, 923171904, 930552256, 937897664, 945207680, 952482048, 959720640, + 966923136, 974089152, 981218496, 988310912, 995366080, 1002383808, 1009363840, 1016305856, + 1023209536, 1030074688, 1036901120, 1043688512, 1050436672, 1057145152, 1063813888, 1070442688, + 1077031040, 1083578880, 1090085888, 1096551936, 1102976640, 1109359872, 1115701248, 1122000640, + 1128257792, 1134472576, 1140644480, 1146773504, 1152859392, 1158901888, 1164900608, 1170855680, + 1176766592, 1182633088, 1188455168, 1194232448, 1199964800, 1205651968, 1211293824, 1216889984, + 1222440320, 1227944704, 1233402752, 1238814464, 1244179456, 1249497600, 1254768768, 1259992704, + 1265169152, 1270297984, 1275378944, 1280411904, 1285396736, 1290333056, 1295220992, 1300060032, + 1304850048, 1309591040, 1314282624, 1318924928, 1323517440, 1328060032, 1332552832, 1336995328, + 1341387520, 1345729152, 1350020224, 1354260352, 1358449536, 1362587648, 1366674432, 1370709632, + 1374693376, 1378625408, 1382505344, 1386333312, 1390109184, 1393832576, 1397503616, 1401121920, + 1404687488, 1408200320, 1411659904, 1415066496, 1418419840, 1421719680, 1424966016, 1428158720, + 1431297664, 1434382720, 1437413760, 1440390656, 1443313408, 1446181632, 1448995584, 1451755008, + 1454459648, 1457109632, 1459704704, 1462244864, 1464729856, 1467159808, 1469534464, 1471853824, + 1474117760, 1476326272, 1478479104, 1480576256, 1482617728, 1484603264, 1486533120, 1488406912, + 1490224640, 1491986176, 1493691648, 1495340800, 1496933760, 1498470400, 1499950464, 1501374080, + 1502741248, 1504051840, 1505305856, 1506503168, 1507643648, 1508727424, 1509754368, 1510724480, + 1511637888, 1512494208, 1513293568, 1514035968, 1514721408, 1515349760, 1515921152, 1516435456, + 1516892672, 1517292672, 1517635584, 1517921408, 1518150144, 1518321664, 1518435968, 1518493184, + 1518493184, 1518435968, 1518321664, 1518150144, 1517921408, 1517635584, 1517292672, 1516892672, + 1516435456, 1515921152, 1515349760, 1514721408, 1514035968, 1513293568, 1512494208, 1511637888, + 1510724480, 1509754368, 1508727424, 1507643648, 1506503040, 1505305728, 1504051840, 1502741248, + 1501374080, 1499950464, 1498470272, 1496933760, 1495340800, 1493691648, 1491986176, 1490224640, + 1488406784, 1486533120, 1484603264, 1482617728, 1480576256, 1478479104, 1476326272, 1474117760, + 1471853824, 1469534464, 1467159808, 1464729856, 1462244864, 1459704704, 1457109504, 1454459648, + 1451754880, 1448995584, 1446181632, 1443313408, 1440390656, 1437413760, 1434382720, 1431297664, + 1428158720, 1424966016, 1421719680, 1418419712, 1415066496, 1411659904, 1408200192, 1404687488, + 1401121920, 1397503488, 1393832576, 1390109056, 1386333312, 1382505344, 1378625280, 1374693376, + 1370709632, 1366674432, 1362587648, 1358449536, 1354260352, 1350020096, 1345729024, 1341387392, + 1336995200, 1332552704, 1328060032, 1323517440, 1318924800, 1314282624, 1309590912, 1304850048, + 1300059904, 1295220864, 1290333056, 1285396736, 1280411904, 1275378944, 1270297856, 1265169024, + 1259992576, 1254768640, 1249497600, 1244179456, 1238814336, 1233402752, 1227944576, 1222440192, + 1216889984, 1211293696, 1205651840, 1199964672, 1194232320, 1188455040, 1182632960, 1176766464, + 1170855552, 1164900608, 1158901760, 1152859264, 1146773504, 1140644352, 1134472448, 1128257664, + 1122000640, 1115701120, 1109359744, 1102976512, 1096551808, 1090085760, 1083578752, 1077030912, + 1070442560, 1063813824, 1057145088, 1050436608, 1043688448, 1036901056, 1030074624, 1023209472, + 1016305728, 1009363776, 1002383744, 995365952, 988310848, 981218432, 974089024, 966922944, + 959720576, 952481920, 945207488, 937897472, 930552192, 923171840, 915756736, 908307072, + 900823296, 893305664, 885754240, 878169600, 870551808, 862901248, 855218240, 847503040, + 839755968, 831977216, 824167104, 816326016, 808454208, 800551936, 792619520, 784657280, + 776665472, 768644480, 760594496, 752515904, 744408960, 736273984, 728111296, 719921216, + 711704000, 703460032, 695189504, 686892864, 678570368, 670222272, 661848960, 653450752, + 645027968, 636580864, 628109760, 619615104, 611097024, 602555968, 593992256, 585406144, + 576798016, 568168128, 559516864, 550844544, 542151488, 533438016, 524704480, 515951200, + 507178432, 498386592, 489576032, 480747008, 471899904, 463035040, 454152672, 445253280, + 436337056, 427404480, 418455744, 409491328, 400511456, 391516512, 382506816, 373482688, + 364444544, 355392672, 346327392, 337249088, 328158112, 319054752, 309939392, 300812384, + 291674016, 282524672, 273364704, 264194448, 255014224, 245824400, 236625328, 227417360, + 218200832, 208976064, 199743440, 190503312, 181255984, 172001856, 162741232, 153474480, + 144201968, 134924016, 125640984, 116353224, 107061080, 97764912, 88465064, 79161880, + 69855712, 60546920, 51235848, 41922844, 32608264, 23292456, 13975772, 4658560 +}; + +const Word32 olapWinAna640_fx[640] = { /* Q30 */ + 3726956, 11180779, 18634332, 26087438, 33539914, 40991584, 48442264, 55891776, + 63339940, 70786584, 78231520, 85674560, 93115552, 100554288, 107990608, 115424328, + 122855256, 130283240, 137708080, 145129584, 152547616, 159961952, 167372448, 174778896, + 182181152, 189579008, 196972288, 204360832, 211744464, 219122960, 226496192, 233863984, + 241226128, 248582448, 255932784, 263276976, 270614784, 277946112, 285270720, 292588448, + 299899136, 307202592, 314498688, 321787136, 329067872, 336340672, 343605344, 350861792, + 358109728, 365349088, 372579616, 379801184, 387013568, 394216640, 401410208, 408594112, + 415768160, 422932192, 430086016, 437229536, 444362464, 451484736, 458596064, 465696416, + 472785504, 479863168, 486929344, 493983712, 501026240, 508056672, 515074880, 522080640, + 529073824, 536054304, 543021824, 549976256, 556917440, 563845248, 570759424, 577659840, + 584546368, 591418816, 598276992, 605120768, 611949952, 618764352, 625563904, 632348352, + 639117568, 645871424, 652609664, 659332224, 666038848, 672729472, 679403776, 686061824, + 692703360, 699328128, 705936064, 712526976, 719100736, 725657216, 732196160, 738717440, + 745220992, 751706496, 758173952, 764623104, 771053888, 777466048, 783859456, 790234048, + 796589568, 802925888, 809242816, 815540288, 821818048, 828076096, 834314176, 840532096, + 846729856, 852907136, 859063872, 865199872, 871315072, 877409344, 883482368, 889534144, + 895564480, 901573248, 907560320, 913525504, 919468672, 925389632, 931288320, 937164672, + 943018240, 948849280, 954657344, 960442432, 966204416, 971943104, 977658304, 983350016, + 989017984, 994662144, 1000282368, 1005878464, 1011450368, 1016997760, 1022520768, 1028019136, + 1033492736, 1038941376, 1044364992, 1049763520, 1055136768, 1060484416, 1065806656, 1071103168, + 1076373888, 1081618688, 1086837376, 1092029952, 1097196160, 1102335872, 1107449088, 1112535680, + 1117595392, 1122628224, 1127633920, 1132612480, 1137563776, 1142487680, 1147383936, 1152252672, + 1157093632, 1161906688, 1166691712, 1171448576, 1176177280, 1180877696, 1185549568, 1190193024, + 1194807680, 1199393536, 1203950464, 1208478464, 1212977408, 1217447040, 1221887232, 1226298112, + 1230679424, 1235031040, 1239352960, 1243644928, 1247907072, 1252139008, 1256340864, 1260512384, + 1264653440, 1268764288, 1272844288, 1276893824, 1280912512, 1284900352, 1288857216, 1292782976, + 1296677760, 1300541056, 1304373120, 1308173824, 1311942912, 1315680512, 1319386240, 1323060224, + 1326702336, 1330312576, 1333890688, 1337436672, 1340950400, 1344431872, 1347880960, 1351297536, + 1354681472, 1358032896, 1361351424, 1364637312, 1367890304, 1371110272, 1374297216, 1377451008, + 1380571776, 1383659136, 1386713216, 1389733760, 1392720896, 1395674496, 1398594432, 1401480704, + 1404333312, 1407151872, 1409936640, 1412687360, 1415404160, 1418086784, 1420735232, 1423349376, + 1425929344, 1428475008, 1430986112, 1433462784, 1435904896, 1438312448, 1440685312, 1443023360, + 1445326848, 1447595392, 1449828992, 1452027776, 1454191616, 1456320256, 1458413824, 1460472448, + 1462495616, 1464483712, 1466436480, 1468353920, 1470235904, 1472082688, 1473893760, 1475669376, + 1477409536, 1479113984, 1480782720, 1482416000, 1484013440, 1485575040, 1487100928, 1488591104, + 1490045184, 1491463424, 1492845824, 1494192256, 1495502592, 1496776960, 1498015232, 1499217280, + 1500383360, 1501513344, 1502606976, 1503664512, 1504685824, 1505670912, 1506619520, 1507532032, + 1508408192, 1509247872, 1510051200, 1510818304, 1511548928, 1512243072, 1512900864, 1513522176, + 1514107008, 1514655360, 1515167104, 1515642496, 1516081408, 1516483584, 1516849280, 1517178496, + 1517471232, 1517727232, 1517946752, 1518129664, 1518276096, 1518385792, 1518459008, 1518495488, + 1518495488, 1518459008, 1518385792, 1518276096, 1518129664, 1517946752, 1517727232, 1517471104, + 1517178496, 1516849280, 1516483584, 1516081280, 1515642496, 1515167104, 1514655360, 1514107008, + 1513522176, 1512900864, 1512243072, 1511548928, 1510818304, 1510051200, 1509247872, 1508408192, + 1507532032, 1506619520, 1505670912, 1504685696, 1503664512, 1502606976, 1501513344, 1500383360, + 1499217280, 1498015232, 1496776960, 1495502592, 1494192128, 1492845824, 1491463424, 1490045184, + 1488590976, 1487100928, 1485575040, 1484013312, 1482416000, 1480782720, 1479113984, 1477409536, + 1475669376, 1473893760, 1472082560, 1470235904, 1468353920, 1466436480, 1464483712, 1462495616, + 1460472320, 1458413824, 1456320256, 1454191488, 1452027776, 1449828992, 1447595392, 1445326848, + 1443023360, 1440685312, 1438312448, 1435904768, 1433462656, 1430986112, 1428474880, 1425929344, + 1423349376, 1420735104, 1418086784, 1415404160, 1412687360, 1409936640, 1407151872, 1404333184, + 1401480704, 1398594432, 1395674496, 1392720896, 1389733760, 1386713088, 1383659008, 1380571648, + 1377451008, 1374297216, 1371110272, 1367890304, 1364637312, 1361351424, 1358032768, 1354681472, + 1351297408, 1347880832, 1344431744, 1340950272, 1337436672, 1333890688, 1330312576, 1326702336, + 1323060224, 1319386240, 1315680384, 1311942912, 1308173696, 1304373120, 1300541056, 1296677632, + 1292782848, 1288857088, 1284900224, 1280912512, 1276893696, 1272844288, 1268764160, 1264653440, + 1260512256, 1256340736, 1252138880, 1247906944, 1243644800, 1239352832, 1235030912, 1230679296, + 1226297984, 1221887104, 1217446912, 1212977280, 1208478336, 1203950464, 1199393408, 1194807552, + 1190192896, 1185549440, 1180877696, 1176177280, 1171448576, 1166691584, 1161906560, 1157093504, + 1152252544, 1147383808, 1142487552, 1137563648, 1132612352, 1127633792, 1122628096, 1117595264, + 1112535552, 1107448960, 1102335872, 1097196032, 1092029824, 1086837248, 1081618560, 1076373888, + 1071103104, 1065806592, 1060484352, 1055136576, 1049763456, 1044364928, 1038941312, 1033492608, + 1028019072, 1022520704, 1016997696, 1011450240, 1005878400, 1000282304, 994662080, 989017920, + 983349888, 977658240, 971942976, 966204288, 960442368, 954657280, 948849152, 943018176, + 937164480, 931288192, 925389504, 919468544, 913525312, 907560192, 901573184, 895564416, + 889534016, 883482304, 877409152, 871314944, 865199808, 859063744, 852907008, 846729728, + 840532032, 834314112, 828075968, 821817984, 815540096, 809242752, 802925696, 796589376, + 790233856, 783859392, 777465984, 771053824, 764622976, 758173824, 751706432, 745220864, + 738717312, 732196032, 725657088, 719100608, 712526848, 705935936, 699328000, 692703232, + 686061760, 679403712, 672729280, 666038720, 659332096, 652609536, 645871296, 639117440, + 632348224, 625563776, 618764224, 611949824, 605120640, 598276864, 591418688, 584546240, + 577659712, 570759296, 563845120, 556917312, 549976128, 543021696, 536054144, 529073696, + 522080512, 515074752, 508056512, 501026112, 493983648, 486929216, 479863072, 472785376, + 465696288, 458596000, 451484608, 444362336, 437229408, 430085952, 422932064, 415768032, + 408593952, 401410080, 394216512, 387013440, 379801024, 372579456, 365348960, 358109632, + 350861664, 343605248, 336340544, 329067744, 321787008, 314498528, 307202464, 299899008, + 292588320, 285270592, 277945984, 270614656, 263276832, 255932656, 248582320, 241225984, + 233863840, 226496064, 219122832, 211744320, 204360704, 196972144, 189578864, 182181008, + 174778768, 167372304, 159961824, 152547472, 145129456, 137707936, 130283104, 122855136, + 115424192, 107990472, 100554160, 93115416, 85674432, 78231384, 70786448, 63339808, + 55891640, 48442128, 40991448, 33539780, 26087306, 18634200, 11180647, 3726823 +}; +#endif // IVAS_FLOAT_FIXED + /* Synthesis windows for overlap-add */ /* for (j=0; jfftlen; j++) hs->olapWinSyn[j] = (float)sin(EVS_PI*((float)j+0.5f)/(float)(hs->fftlen); */ const float olapWinSyn256[256] = diff --git a/lib_com/rom_com.h b/lib_com/rom_com.h index 4fd5757d763b91dec435b5d60fe17854266ab72e..0ee8513132c7c92b9fee23cfe3166ab25177daaa 100644 --- a/lib_com/rom_com.h +++ b/lib_com/rom_com.h @@ -1694,6 +1694,10 @@ extern const Word16 fftSineTab640_fx[321]; extern const float olapWinAna512[512]; extern const float olapWinAna640[640]; +#ifdef IVAS_FLOAT_FIXED +extern const Word32 olapWinAna512_fx[512]; // Q30 +extern const Word32 olapWinAna640_fx[640]; // Q30 +#endif // IVAS_FLOAT_FIXED extern const float olapWinSyn256[256]; extern const Word16 olapWinSyn256_fx[256]; diff --git a/lib_com/stat_com.h b/lib_com/stat_com.h index 492ee128aae423170ad44b1c3b533ca20d651f4b..df13cd8dcc9cfce2c8781548d540d22ce89daf5a 100644 --- a/lib_com/stat_com.h +++ b/lib_com/stat_com.h @@ -409,6 +409,7 @@ typedef struct const float *olapWinAna_flt; const float *olapWinSyn_flt; #ifdef IVAS_FLOAT_FIXED + const Word32 *olapWinAna_fx; const Word16 *olapWinSyn_fx; #endif const float *fftSineTab_flt; @@ -416,7 +417,9 @@ typedef struct const Word16 *fftSineTab_fx; #endif Word32 fftBuffer[FFTLEN]; + Word16 fftBuffer_exp; Word16 *olapBufferAna; /* points to FD_CNG_DEC->olapBufferAna[320] in case of decoder */ + Word16 olapBufferAna_fx[FFTLEN]; /* points to FD_CNG_DEC->olapBufferAna[320] in case of decoder */ Word16 olapBufferSynth[FFTLEN]; Word16 *olapBufferSynth2; /* points to FD_CNG_DEC->olapBufferSynth2[FFTLEN] in case of decoder */ const PWord16 * olapWinAna; @@ -494,6 +497,7 @@ typedef struct Word16 sidNoiseEstExp; float sidNoiseEstLp_flt[NPART]; + Word32 sidNoiseEstLp[NPART]; int16_t frame_type_previous; diff --git a/lib_com/tools_fx.c b/lib_com/tools_fx.c index dd3ab398033b41196d635c66b6b5d2a40be1ecd6..f44798f14ad87c9f8be53d5968af2536665be561 100644 --- a/lib_com/tools_fx.c +++ b/lib_com/tools_fx.c @@ -48,6 +48,7 @@ #include "prot_fx1.h" #include "prot_fx2.h" #include "basop_util.h" +#include "basop32.h" #include "wmc_auto.h" #define INV_BANDS10 3277 /* 1/10 in Q15 */ @@ -2527,6 +2528,77 @@ void v_multc_att32( } } } + +/*-------------------------------------------------------------------* + * v_multc_att3232() + * + * Attenuation of a vector, attenuation factor in Q31 + *-------------------------------------------------------------------*/ + +void v_multc_att3232( + const Word32 x[], /* i : Input vector Qx */ + const Word32 att, /* i : Constant Q32, <= MAX_32 */ + Word32 y[], /* o : Output vector that contains att*x */ + const Word16 N /* i : Vector length */ +) +{ + Word16 i; + IF( LE_32( att, MAX_32 ) ) + { + FOR( i = 0; i < N; i++ ) + { + y[i] = Mpy_32_32_r( x[i], att ); + move32(); + } + } +} + +/*-------------------------------------------------------------------* + * v_L_mult_1616() + * + * Multiplication of two vectors, Output in Word32 + *-------------------------------------------------------------------*/ + +void v_L_mult_1616( + const Word16 x1[], /* i : Input vector 1 */ + const Word16 x2[], /* i : Input vector 2 */ + Word32 y[], /* o : Output vector that contains vector 1 .* vector 2 */ + const Word16 N /* i : Vector length */ +) +{ + Word16 i; + + for ( i = 0; i < N; i++ ) + { + y[i] = L_mult( x1[i], x2[i] ); + } + + return; +} + +/*-------------------------------------------------------------------* + * v_L_mult_3216() + * + * Multiplication of two vectors, Output in Word32 + *-------------------------------------------------------------------*/ + +void v_L_mult_3216( + const Word32 x1[], /* i : Input vector 1 */ + const Word16 x2[], /* i : Input vector 2 */ + Word32 y[], /* o : Output vector that contains vector 1 .* vector 2 */ + const Word16 N /* i : Vector length */ +) +{ + Word16 i; + + for ( i = 0; i < N; i++ ) + { + y[i] = Mpy_32_16_1( x1[i], x2[i] ); + } + + return; +} + /*-------------------------------------------------------------------* * add_vec() * @@ -3525,6 +3597,43 @@ void delay_signal32( return; } + +/*---------------------------------------------------------------------* + * lin_interp_fx() + * + * Linearly maps x from source range to the target range + *---------------------------------------------------------------------*/ + +/*! r: mapped output value */ +Word16 lin_interp_fx( + const Word16 x, /* i : Q15 the value to be mapped */ + const Word16 x1, /* i : Q15 source range interval: low end */ + const Word16 y1, /* i : Q15 source range interval: high end */ + const Word16 x2, /* i : Q15 target range interval: low */ + const Word16 y2, /* i : Q15 target range interval: high */ + const Word16 flag_sat /* i : flag to indicate whether to apply saturation */ +) +{ + IF( EQ_16( sub( x2, x1 ), 0 ) ) + { + return y1; + } + ELSE IF( flag_sat ) + { + IF( GE_16( x, s_max( x1, x2 ) ) ) + { + return GT_16( x1, x2 ) ? y1 : y2; + } + ELSE IF( LE_16( x, s_min( x1, x2 ) ) ) + { + return LT_16( x1, x2 ) ? y1 : y2; + } + } + + return add_sat( y1, mult( sub( x, x1 ), div_s( sub( y2, y1 ), sub( x2, x1 ) ) ) ); +} + + /*--------------------------------------------------------------------- * sign() * @@ -3543,4 +3652,4 @@ Word32 sign_l( { return MAX_32; } -} \ No newline at end of file +} diff --git a/lib_dec/core_dec_init.c b/lib_dec/core_dec_init.c index ab46aa571c844e1129bd8c43b072b7113032dfc6..609c0fa8ed27a3b1a96574c3d721591fb5b8c742 100644 --- a/lib_dec/core_dec_init.c +++ b/lib_dec/core_dec_init.c @@ -701,6 +701,10 @@ void open_decoder_LPD_flt( if (is_init || MCT_flag || !(st->element_mode == IVAS_CPE_MDCT && st->element_mode == last_element_mode)) { +#ifdef IVAS_FLOAT_FIXED + st->hTcxDec->CngLevelBackgroundTrace_bfi_fx = PLC_MIN_CNG_LEV; + st->hTcxDec->CngLevelBackgroundTrace_bfi_exp = 16; +#endif // IVAS_FLOAT_FIXED st->hTcxDec->CngLevelBackgroundTrace_bfi = PLC_MIN_CNG_LEV_FLT; st->hTcxDec->NoiseLevelIndex_bfi = PLC_MIN_STAT_BUFF_SIZE - 1; st->hTcxDec->CurrLevelIndex_bfi = 0; diff --git a/lib_dec/core_switching_dec.c b/lib_dec/core_switching_dec.c index f957a1fe8ebdf295b138995d3ae3bd4c25bee0a9..ee95b2ff876372535c2cc8c968c66556f7b94f57 100644 --- a/lib_dec/core_switching_dec.c +++ b/lib_dec/core_switching_dec.c @@ -297,6 +297,9 @@ ivas_error core_switching_pre_dec( /* Last frame was Stereo CNG and the synthesis memory is outdated -- reset */ set_f( st->hTcxDec->old_syn_Overl_float, 0.0f, L_FRAME32k / 2 ); set_f( st->hFdCngDec->hFdCngCom->olapBufferAna_flt, 0.0f, FFTLEN ); +#ifdef IVAS_FLOAT_FIXED + set16_fx( st->hFdCngDec->hFdCngCom->olapBufferAna_fx, 0, FFTLEN ); +#endif // IVAS_FLOAT_FIXED } set_f( st->agc_mem2, 0, 2 ); @@ -504,10 +507,12 @@ ivas_error core_switching_pre_dec( if ( st->core != AMR_WB_CORE ) { configureFdCngDec_flt( st->hFdCngDec, st->bwidth, st->rf_flag == 1 && st->total_brate == ACELP_13k20 ? ACELP_9k60 : st->total_brate, st->L_frame, st->last_L_frame, st->element_mode ); + configureFdCngDec( st->hFdCngDec, st->bwidth, st->rf_flag == 1 && st->total_brate == ACELP_13k20 ? ACELP_9k60 : st->total_brate, st->L_frame, st->last_L_frame, st->element_mode ); } else { configureFdCngDec_flt( st->hFdCngDec, WB, ACELP_8k00, st->L_frame, st->last_L_frame, st->element_mode ); + configureFdCngDec( st->hFdCngDec, WB, ACELP_8k00, st->L_frame, st->last_L_frame, st->element_mode ); if ( st->VAD ) { @@ -519,6 +524,9 @@ ivas_error core_switching_pre_dec( if ( st->element_mode == IVAS_CPE_DFT || st->element_mode == IVAS_CPE_TD ) { lerp_flt( st->hFdCngDec->hFdCngCom->olapBufferAna_flt + st->last_L_frame, st->hFdCngDec->hFdCngCom->olapBufferAna_flt + st->L_frame, st->L_frame, st->last_L_frame ); +#ifdef IVAS_FLOAT_FIXED + lerp( st->hFdCngDec->hFdCngCom->olapBufferAna_fx + st->last_L_frame, st->hFdCngDec->hFdCngCom->olapBufferAna_fx + st->L_frame, st->L_frame, st->last_L_frame ); +#endif // IVAS_FLOAT_FIXED } lerp_flt( st->hFdCngDec->hFdCngCom->olapBufferSynth2_flt, st->hFdCngDec->hFdCngCom->olapBufferSynth2_flt, st->L_frame * 2, st->last_L_frame * 2 ); diff --git a/lib_dec/fd_cng_dec.c b/lib_dec/fd_cng_dec.c index fe0e21b3555778d967c6c75351c6fee2e4046f38..775f333e50d765968e668aa9e6238c6d6a5a9899 100644 --- a/lib_dec/fd_cng_dec.c +++ b/lib_dec/fd_cng_dec.c @@ -72,9 +72,9 @@ /*------------------------------------------------------------------- * Local fucntions declarations *-------------------------------------------------------------------*/ - +#ifndef IVAS_FLOAT_FIXED static void perform_noise_estimation_dec_flt( const float *timeDomainInput, float *power_spectrum, HANDLE_FD_CNG_DEC hFdCngDec, const int16_t element_mode, const int16_t bwidth, const int16_t L_frame, const int16_t last_L_frame, const int32_t last_core_brate, const int16_t VAD ); - +#endif // IVAS_FLOAT_FIXED /*------------------------------------------------------------------- * createFdCngDec_flt() @@ -304,6 +304,10 @@ void configureFdCngDec_flt( hsCom->startBand = 2; hsCom->stopBand = hsCom->FdCngSetup.sidPartitions[hsCom->FdCngSetup.numPartitions - 1] + 1; initPartitions_flt( hsCom->FdCngSetup.sidPartitions, hsCom->FdCngSetup.numPartitions, hsCom->startBand, hsCom->stopBand, hsCom->part, &hsCom->npart, hsCom->midband, hsCom->psize_flt, hsCom->psize_inv_flt, 0 ); +#ifdef IVAS_FLOAT_FIXED + initPartitions(hsCom->FdCngSetup.sidPartitions, hsCom->FdCngSetup.numPartitions, hsCom->startBand, hsCom->stopBand, hsCom->part, &hsCom->npart, hsCom->midband, hsCom->psize, hsCom->psize_norm, &hsCom->psize_norm_exp, hsCom->psize_inv, 0); +#endif // IVAS_FLOAT_FIXED + if ( hsCom->stopFFTbin == 160 ) { hsCom->nFFTpart = 17; @@ -329,6 +333,9 @@ void configureFdCngDec_flt( stopBandFR = hsCom->stopFFTbin; } initPartitions_flt( hsCom->FdCngSetup.shapingPartitions, hsCom->FdCngSetup.numShapingPartitions, hsCom->startBand, hsCom->stopFFTbin, hFdCngDec->part_shaping, &hFdCngDec->npart_shaping, hFdCngDec->midband_shaping, hFdCngDec->psize_shaping_float, hFdCngDec->psize_inv_shaping_float, stopBandFR ); +#ifdef IVAS_FLOAT_FIXED + initPartitions( hsCom->FdCngSetup.shapingPartitions, hsCom->FdCngSetup.numShapingPartitions, hsCom->startBand, hsCom->stopFFTbin, hFdCngDec->part_shaping, &hFdCngDec->npart_shaping, hFdCngDec->midband_shaping, hFdCngDec->psize_shaping, hFdCngDec->psize_shaping_norm, &hFdCngDec->psize_shaping_norm_exp, hFdCngDec->psize_inv_shaping, stopBandFR ); +#endif // IVAS_FLOAT_FIXED hFdCngDec->nFFTpart_shaping = hFdCngDec->npart_shaping; @@ -339,6 +346,7 @@ void configureFdCngDec_flt( hsCom->olapWinAna_flt = olapWinAna512; hsCom->olapWinSyn_flt = olapWinSyn256; #ifdef IVAS_FLOAT_FIXED + hsCom->olapWinAna_fx = olapWinAna512_fx; hsCom->fftSineTab_fx = NULL; hsCom->olapWinSyn_fx = olapWinSyn256_fx; #endif @@ -348,6 +356,7 @@ void configureFdCngDec_flt( hsCom->olapWinAna_flt = olapWinAna640; hsCom->olapWinSyn_flt = olapWinSyn320; #ifdef IVAS_FLOAT_FIXED + hsCom->olapWinAna_fx = olapWinAna640_fx; hsCom->fftSineTab_fx = fftSineTab640_fx; hsCom->olapWinSyn_fx = olapWinSyn320_fx; #endif @@ -449,7 +458,145 @@ void ApplyFdCng_flt( ( !st->BER_detect ) ) { /* Perform noise estimation at the decoder */ +#ifdef IVAS_FLOAT_FIXED + Word16 timeDomainInput_fx[L_FRAME16k], q_tdi = 0; + Word32 powerSpectrum_fx[L_FRAME16k]; + if ( timeDomainInput != NULL ) + { + float max1 = 0.f; + for ( int p = 0; p < L_frame; p++ ) + { + if ( (float) fabs( (float) timeDomainInput[p] ) > max1 ) + max1 = (float) fabs( (float) timeDomainInput[p] ); + } + q_tdi = norm_s( (Word16) max1 ); + for ( int p = 0; p < L_frame; p++ ) + { + timeDomainInput_fx[p] = (Word16) ( timeDomainInput[p] * ( 1u << q_tdi ) ); + } + } + for ( int p = 0; p < L_frame; p++ ) + { + hFdCngDec->hFdCngCom->periodog[p] = (Word32) ( hFdCngDec->hFdCngCom->periodog_flt[p] * ( 1u << ( 31 - hFdCngDec->hFdCngCom->periodog_exp ) ) ); + } + if ( powerSpectrum != NULL ) + { + for ( int p = 0; p < L_FRAME16k; p++ ) + { + if ( powerSpectrum[p] <= (float) MAX_32 ) + { + powerSpectrum_fx[p] = (Word32) ( powerSpectrum[p] /** ( 1u << 0 )*/ ); + } + else + { + powerSpectrum_fx[p] = MAX_32; + } + } + } + for ( int p = 0; p < hFdCngDec->hFdCngCom->fftlen; p++ ) + { + hFdCngDec->hFdCngCom->fftBuffer[p] = (Word32) ( hFdCngDec->hFdCngCom->fftBuffer_flt[p] * ( 1u << ( 31 - hFdCngDec->hFdCngCom->fftBuffer_exp ) ) ); + } + hFdCngDec->msNoiseEst_exp = 31 - Q4; + for ( int p = 0; p < NPART_SHAPING; p++ ) + { + hFdCngDec->msNoiseEst[p] = (Word32) ( hFdCngDec->msNoiseEst_float[p] * ( 1u << ( 31 - hFdCngDec->msNoiseEst_exp ) ) ); + hFdCngDec->msPeriodog_ST_fx[p] = (Word32) ( hFdCngDec->msPeriodog_ST[p] * ( 1u << ( 31 - hFdCngDec->msPeriodog_ST_exp ) ) ); + } + for ( int p = 0; p < MSBUFLEN * NPART_SHAPING; p++ ) + { + if ( ( st->hFdCngDec->msMinBuf_float[p] * ( 1u << Q15 ) ) >= (float) MAX_32 ) + { + st->hFdCngDec->msMinBuf[p] = MAX_32; + } + else + { + st->hFdCngDec->msMinBuf[p] = (Word32) ( st->hFdCngDec->msMinBuf_float[p] * ( 1u << ( 31 - 6 ) ) ); + } + } + + perform_noise_estimation_dec_fx( timeDomainInput_fx, q_tdi, powerSpectrum_fx, hFdCngDec, st->element_mode, st->bwidth, L_frame, last_L_frame, st->last_core_brate, st->VAD ); + + IF( EQ_16( st->element_mode, IVAS_CPE_TD ) || EQ_16( st->element_mode, IVAS_CPE_DFT ) ) + { + for ( int p = 0; p < hFdCngDec->hFdCngCom->stopFFTbin - hFdCngDec->hFdCngCom->startBand; p++ ) + { + hFdCngDec->hFdCngCom->periodog_flt[p] = ( (float) hFdCngDec->hFdCngCom->periodog[p] / (float) ( 1u << ( 31 - hFdCngDec->hFdCngCom->periodog_exp ) ) ); + hFdCngDec->bandNoiseShape_float[p] = ( (float) hFdCngDec->bandNoiseShape[p] / ( 1u << ( 31 - hFdCngDec->msNoiseEst_exp ) ) ); + } + + for ( int p = 0; p < L_FRAME16k - hFdCngDec->hFdCngCom->startBand; p++ ) + { + hFdCngDec->smoothed_psd[hFdCngDec->hFdCngCom->startBand + p] = ( (float) hFdCngDec->smoothed_psd_fx[hFdCngDec->hFdCngCom->startBand + p] / ( 1u << ( 31 - hFdCngDec->msNoiseEst_exp ) ) ); + } + for ( int p = 0; p < hFdCngDec->npart_shaping; p++ ) + { + hFdCngDec->msPsd_float[p] = ( (float) hFdCngDec->msPsd_fx[p] / ( 1u << ( 31 - hFdCngDec->msNoiseEst_exp ) ) ); + } + } + for ( int p = 0; p < hFdCngDec->hFdCngCom->fftlen; p++ ) + { + hFdCngDec->hFdCngCom->fftBuffer_flt[p] = ( (float) hFdCngDec->hFdCngCom->fftBuffer[p] / ( 1u << ( 31 - hFdCngDec->hFdCngCom->fftBuffer_exp ) ) ); + } + for ( int p = 0; p < hFdCngDec->npart_shaping; p++ ) + { + hFdCngDec->msNoiseEst_float[p] = ( (float) hFdCngDec->msNoiseEst[p] / ( 1u << ( 31 - hFdCngDec->msNoiseEst_exp ) ) ); + } + IF( !( EQ_16( st->element_mode, IVAS_CPE_TD ) || EQ_16( st->element_mode, IVAS_CPE_DFT ) ) ) + { + for ( int p = 0; p < MSBUFLEN * NPART_SHAPING; p++ ) + { + if ( ( st->hFdCngDec->msMinBuf[p] == MAX_32 ) ) + { + st->hFdCngDec->msMinBuf_float[p] = FLT_MAX; + } + else + { + st->hFdCngDec->msMinBuf_float[p] = (float) st->hFdCngDec->msMinBuf[p] / ( 1u << ( 31 - 6 ) ); // CNG_S = 6 + } + } + for ( int p = 0; p < hFdCngDec->npart_shaping; p++ ) + { + hFdCngDec->msPsd_float[p] = ( (float) hFdCngDec->msPsd[p] / ( 1u << Q9 ) ); + hFdCngDec->msPeriodog_float[p] = ( (float) hFdCngDec->msPeriodog[p] / ( 1u << ( 31 - hFdCngDec->msPeriodog_exp ) ) ); + hFdCngDec->msPeriodogBuf_float[p] = ( (float) hFdCngDec->msPeriodogBuf[p] / ( 1u << Q9 ) ); + hFdCngDec->msPeriodog_ST[p] = ( (float) hFdCngDec->msPeriodog_ST_fx[p] / ( 1u << ( 31 - hFdCngDec->msPeriodog_ST_exp ) ) ); + hFdCngDec->msPsdFirstMoment_float[p] = ( (float) hFdCngDec->msPsdFirstMoment[p] / ( 1u << Q9 ) ); + hFdCngDec->msPsdSecondMoment_float[p] = ( (float) hFdCngDec->msPsdSecondMoment[p] / ( 1u << Q19 ) ); + hFdCngDec->msNoiseFloor_float[p] = ( (float) hFdCngDec->msNoiseFloor[p] / ( 1u << Q9 ) ); + hFdCngDec->msAlpha_float[p] = ( (float) hFdCngDec->msAlpha[p] / ( 1u << Q31 ) ); + hFdCngDec->msBminWin_float[p] = ( (float) hFdCngDec->msBminWin[p] / ( 1u << Q27 ) ); + hFdCngDec->msBminSubWin_float[p] = ( (float) hFdCngDec->msBminSubWin[p] / ( 1u << Q27 ) ); + if (st->hFdCngDec->msCurrentMin[p] == MAX_32) + { + st->hFdCngDec->msCurrentMin_float[p] = FLT_MAX; + } + else + { + st->hFdCngDec->msCurrentMin_float[p] = ((float)st->hFdCngDec->msCurrentMin[p] / (1u << (31 - (6 + 1 + 4)))); // exp : CNG_S + 1 + 4 + } + if (st->hFdCngDec->msCurrentMinOut[p] == MAX_32) + { + st->hFdCngDec->msCurrentMinOut_float[p] = FLT_MAX; + } + else + { + st->hFdCngDec->msCurrentMinOut_float[p] = ((float)st->hFdCngDec->msCurrentMinOut[p] / (1u << (31 - 6))); + } + if (st->hFdCngDec->msCurrentMinSubWindow[p] == MAX_32) + { + st->hFdCngDec->msCurrentMinSubWindow_float[p] = FLT_MAX; + } + else + { + st->hFdCngDec->msCurrentMinSubWindow_float[p] = ((float)st->hFdCngDec->msCurrentMinSubWindow[p] / (1u << (31 - 6))); + } + } + } +#else perform_noise_estimation_dec_flt( timeDomainInput, powerSpectrum, hFdCngDec, st->element_mode, st->bwidth, L_frame, last_L_frame, st->last_core_brate, st->VAD ); +#endif // IVAS_FLOAT_FIXED + if ( st->element_mode != IVAS_CPE_TD && st->element_mode != IVAS_CPE_DFT ) { @@ -496,7 +643,58 @@ void ApplyFdCng_flt( if ( hFdCngCom->active_frame_counter > 0 ) { /* Perform noise estimation in active frames in the decoder for downward updates */ +#ifdef IVAS_FLOAT_FIXED + Word16 timeDomainInput_fx[L_FRAME16k], q_tdi; + Word32 *powerSpectrum_fx = NULL; + float max1 = 0.f; + for ( int p = 0; p < L_frame; p++ ) + { + if ( (float) fabs( (double) timeDomainInput[p] ) > max1 ) + max1 = (float) fabs( (double) timeDomainInput[p] ); + } + q_tdi = norm_s( (Word16) max1 ); + for ( int p = 0; p < L_frame; p++ ) + { + timeDomainInput_fx[p] = (Word16) ( timeDomainInput[p] * ( 1u << q_tdi ) ); + hFdCngDec->hFdCngCom->periodog[p] = (Word32) ( hFdCngDec->hFdCngCom->periodog_flt[p] * ( 1u << ( 31 - hFdCngDec->hFdCngCom->periodog_exp ) ) ); + } + for ( int p = 0; p < hFdCngDec->hFdCngCom->fftlen; p++ ) + { + hFdCngDec->hFdCngCom->fftBuffer[p] = (Word32) ( hFdCngDec->hFdCngCom->fftBuffer_flt[p] * ( 1u << ( 31 - hFdCngDec->hFdCngCom->fftBuffer_exp ) ) ); + } + hFdCngDec->msNoiseEst_exp = 31 - Q4; + for ( int p = 0; p < NPART_SHAPING; p++ ) + { + hFdCngDec->msNoiseEst[p] = (Word32) ( hFdCngDec->msNoiseEst_float[p] * (1u << (31 - hFdCngDec->msNoiseEst_exp))); + hFdCngDec->msPeriodog_ST_fx[p] = (Word32) ( hFdCngDec->msPeriodog_ST[p] * ( 1u << ( 31 - hFdCngDec->msPeriodog_ST_exp ) ) ); + } + + perform_noise_estimation_dec_fx( timeDomainInput_fx, q_tdi, powerSpectrum_fx, hFdCngDec, st->element_mode, st->bwidth, L_frame, last_L_frame, st->last_core_brate, st->VAD ); + + for ( int p = 0; p < hFdCngDec->hFdCngCom->stopFFTbin - hFdCngDec->hFdCngCom->startBand; p++ ) + { + hFdCngDec->hFdCngCom->periodog_flt[p] = ( (float) hFdCngDec->hFdCngCom->periodog[p] / (float) ( 1u << ( 31 - hFdCngDec->hFdCngCom->periodog_exp ) ) ); + hFdCngDec->bandNoiseShape_float[p] = ( (float) hFdCngDec->bandNoiseShape[p] / (1u << (31 - hFdCngDec->msNoiseEst_exp))); + } + + for ( int p = 0; p < L_FRAME16k - hFdCngDec->hFdCngCom->startBand; p++ ) + { + hFdCngDec->smoothed_psd[hFdCngDec->hFdCngCom->startBand + p] = ( (float) hFdCngDec->smoothed_psd_fx[hFdCngDec->hFdCngCom->startBand + p] / (1u << (31 - hFdCngDec->msNoiseEst_exp))); + } + for ( int p = 0; p < hFdCngDec->hFdCngCom->fftlen; p++ ) + { + hFdCngDec->hFdCngCom->fftBuffer_flt[p] = ( (float) hFdCngDec->hFdCngCom->fftBuffer[p] / ( 1u << ( 31 - hFdCngDec->hFdCngCom->fftBuffer_exp ) ) ); + } + for ( int p = 0; p < hFdCngDec->npart_shaping; p++ ) + { + hFdCngDec->msNoiseEst_float[p] = ( (float) hFdCngDec->msNoiseEst[p] / (1u << (31 - hFdCngDec->msNoiseEst_exp))); + hFdCngDec->msPsd_float[p] = ( (float) hFdCngDec->msPsd_fx[p] / (1u << (31 - hFdCngDec->msNoiseEst_exp))); + hFdCngDec->msPeriodog_float[p] = ( (float) hFdCngDec->msPeriodog[p] / ( 1u << ( 31 - hFdCngDec->hFdCngCom->periodog_exp ) ) ); + hFdCngDec->msPeriodog_ST[p] = ( (float) hFdCngDec->msPeriodog_ST_fx[p] / ( 1u << ( 31 - hFdCngDec->msPeriodog_ST_exp ) ) ); + } +#else perform_noise_estimation_dec_flt( timeDomainInput, powerSpectrum, hFdCngDec, st->element_mode, st->bwidth, L_frame, last_L_frame, st->last_core_brate, st->VAD ); +#endif // IVAS_FLOAT_FIXED } } @@ -558,7 +756,71 @@ void ApplyFdCng_flt( if ( st != NULL && st->cng_type == LP_CNG ) { /* Perform noise estimation on inactive phase at the decoder */ +#ifdef IVAS_FLOAT_FIXED + Word16 timeDomainInput_fx[L_FRAME16k], q_tdi = 0; + Word32 powerSpectrum_fx[L_FRAME16k]; + if ( timeDomainInput != NULL ) + { + float max1 = 0.f; + for ( int p = 0; p < L_frame; p++ ) + { + if ( (float) fabs( (double) timeDomainInput[p] ) > max1 ) + max1 = (float) fabs( (double) timeDomainInput[p] ); + } + q_tdi = norm_s( (Word16) max1 ); + for ( int p = 0; p < L_frame; p++ ) + { + timeDomainInput_fx[p] = (Word16) ( timeDomainInput[p] * ( 1u << q_tdi ) ); + } + } + for ( int p = 0; p < L_frame; p++ ) + { + hFdCngDec->hFdCngCom->periodog[p] = (Word32) ( hFdCngDec->hFdCngCom->periodog_flt[p] * ( 1u << ( 31 - hFdCngDec->hFdCngCom->periodog_exp ) ) ); + } + if ( powerSpectrum != NULL ) + { + for ( int p = 0; p < L_FRAME16k; p++ ) + { + powerSpectrum_fx[p] = (Word32) ( powerSpectrum[p] * ( 1u << Q2 ) ); + } + } + for ( int p = 0; p < hFdCngDec->hFdCngCom->fftlen; p++ ) + { + hFdCngDec->hFdCngCom->fftBuffer[p] = (Word32) ( hFdCngDec->hFdCngCom->fftBuffer_flt[p] * ( 1u << ( 31 - hFdCngDec->hFdCngCom->fftBuffer_exp ) ) ); + } + hFdCngDec->msNoiseEst_exp = 31 - Q4; + for ( int p = 0; p < NPART_SHAPING; p++ ) + { + hFdCngDec->msNoiseEst[p] = (Word32) ( hFdCngDec->msNoiseEst_float[p] * ( 1u << ( 31 - hFdCngDec->msNoiseEst_exp ) ) ); + hFdCngDec->msPeriodog_ST_fx[p] = (Word32) ( hFdCngDec->msPeriodog_ST[p] * ( 1u << ( 31 - hFdCngDec->msPeriodog_ST_exp ) ) ); + } + + perform_noise_estimation_dec_fx( timeDomainInput_fx, q_tdi, powerSpectrum_fx, hFdCngDec, st->element_mode, st->bwidth, L_frame, last_L_frame, st->last_core_brate, st->VAD ); + + for ( int p = 0; p < hFdCngDec->hFdCngCom->stopFFTbin - hFdCngDec->hFdCngCom->startBand; p++ ) + { + hFdCngDec->hFdCngCom->periodog_flt[p] = ( (float) hFdCngDec->hFdCngCom->periodog[p] / (float) ( 1u << ( 31 - hFdCngDec->hFdCngCom->periodog_exp ) ) ); + hFdCngDec->bandNoiseShape_float[p] = ( (float) hFdCngDec->bandNoiseShape[p] / ( 1u << ( 31 - hFdCngDec->msNoiseEst_exp ) ) ); + } + + for ( int p = 0; p < L_FRAME16k - hFdCngDec->hFdCngCom->startBand; p++ ) + { + hFdCngDec->smoothed_psd[hFdCngDec->hFdCngCom->startBand + p] = ( (float) hFdCngDec->smoothed_psd_fx[hFdCngDec->hFdCngCom->startBand + p] / ( 1u << ( 31 - hFdCngDec->msNoiseEst_exp ) ) ); + } + for ( int p = 0; p < hFdCngDec->hFdCngCom->fftlen; p++ ) + { + hFdCngDec->hFdCngCom->fftBuffer_flt[p] = ( (float) hFdCngDec->hFdCngCom->fftBuffer[p] / ( 1u << ( 31 - hFdCngDec->hFdCngCom->fftBuffer_exp ) ) ); + } + for ( int p = 0; p < hFdCngDec->npart_shaping; p++ ) + { + hFdCngDec->msNoiseEst_float[p] = ( (float) hFdCngDec->msNoiseEst[p] / ( 1u << ( 31 - hFdCngDec->msNoiseEst_exp ) ) ); + hFdCngDec->msPsd_float[p] = ( (float) hFdCngDec->msPsd_fx[p] / ( 1u << ( 31 - hFdCngDec->msNoiseEst_exp ) ) ); + hFdCngDec->msPeriodog_float[p] = ( (float) hFdCngDec->msPeriodog[p] / ( 1u << ( 31 - hFdCngDec->hFdCngCom->periodog_exp ) ) ); + hFdCngDec->msPeriodog_ST[p] = ( (float) hFdCngDec->msPeriodog_ST_fx[p] / ( 1u << ( 31 - hFdCngDec->msPeriodog_ST_exp ) ) ); + } +#else perform_noise_estimation_dec_flt( timeDomainInput, powerSpectrum, hFdCngDec, st->element_mode, st->bwidth, L_frame, last_L_frame, st->last_core_brate, st->VAD ); +#endif // IVAS_FLOAT_FIXED if ( st->element_mode != IVAS_CPE_TD && st->element_mode != IVAS_CPE_DFT ) { @@ -657,7 +919,7 @@ void ApplyFdCng_flt( return; } - +#ifndef IVAS_FLOAT_FIXED /*------------------------------------------------------------------- * perform_noise_estimation_dec_flt() * @@ -1002,7 +1264,7 @@ static void perform_noise_estimation_dec_flt( return; } - +#endif // IVAS_FLOAT_FIXED /*------------------------------------------------------------------- * FdCng_decodeSID_flt() diff --git a/lib_dec/fd_cng_dec_fx.c b/lib_dec/fd_cng_dec_fx.c index 84d73d6643c17c67bf6114b98ec2f748d22b4d22..32be6e22cdfb2bde3b91c8cf653b42d004aafba8 100644 --- a/lib_dec/fd_cng_dec_fx.c +++ b/lib_dec/fd_cng_dec_fx.c @@ -11,10 +11,16 @@ #include "stat_dec.h" #include "prot_fx1.h" #include "prot_fx2.h" +#include "ivas_prot_fx.h" #include "basop_util.h" #include "rom_basop_util.h" +#define CNA_ACT_DN_LARGE_PARTITION 50 /* index of the first larger partition */ +#define ST_PERIODOG_FACT_Q15 29491 /* 0.9 in Q15, short-term filter factor for periodogram */ +#define CNA_ACT_DN_FACT_Q15 22938 /* 0.7 in Q15, downward updating factor for CNA during active frames */ +#define FIRST_CNA_NOISE_UPD_FRAMES 5 /* minimum number of CN initialization frames */ + /******************************** * External tables * ********************************/ @@ -129,6 +135,10 @@ void initFdCngDec( set16_fx( hFdCngDec->psize_shaping, 0, NPART_SHAPING ); move16(); hFdCngDec->nFFTpart_shaping = 0; + set32_fx(hFdCngDec->msPeriodog_ST_fx, 0, NPART_SHAPING); + hFdCngDec->msPeriodog_ST_exp = 0; + hFdCngDec->hFdCngCom->fftBuffer_exp = 0; + hFdCngDec->hFdCngCom->periodog_exp = 0; #ifdef IVAS_CODE_CNG set_f(hFdCngDec->hFdCngCom->sidNoiseEstLp, 0.0f, NPART); @@ -1037,263 +1047,1500 @@ Word16 ApplyFdCng ( return 0; } - -/* - perform_noise_estimation_dec - - Parameters: - - timeDomainInput, i: pointer to time domain input - bitrate, i: bitrate - st i/o: FD_CNG structure containing all buffers and variables - - Function: - perform noise estimation - - Returns: - void -*/ -void perform_noise_estimation_dec ( - const Word16 *timeDomainInput, /* i: pointer to time domain input */ - const Word16 Q, -#ifdef IVAS_CODE_CNG_FIX185_PLC_FADEOUT - float* power_spectrum, -#endif - HANDLE_FD_CNG_DEC hFdCngDec /* i/o: FD_CNG structure containing all buffers and variables */ -#ifdef IVAS_CODE_CNG - ,const int16_t element_mode, /* i : element mode */ - const int16_t bwidth, /* i : audio bandwidth */ - const int16_t L_frame, /* i : frame length at internal Fs */ - const int16_t last_L_frame, /* i : frame length of the last frame at internal Fs */ - const int32_t last_core_brate, /* i : previous frame core bitrate */ - const int16_t VAD /* i : VAD flag in the decoder */ -#endif - ) +#ifdef IVAS_FLOAT_FIXED +Word16 ApplyFdCng_fx( + Word16 *timeDomainInput, /* i : pointer to time domain input */ + Word16 Q, + Word32 *powerSpectrum, + Word32 **cldfbBufferReal, /* i/o: real part of the CLDFB buffer */ + Word32 **cldfbBufferImag, /* i/o: imaginary part of the CLDFB buffer */ + Word16 *cldfbBufferScale, /* o : pointer to the scalefactor for real and imaginary part of the CLDFB buffer */ + Decoder_State *st, + const Word16 concealWholeFrame, /* i : binary flag indicating frame loss */ + Word16 is_music ) { - Word16 i, tmp_r, tmp_i, fac, fftBuffer_exp; - Word16 s, len, npart, nFFTpart; - Word16 startBand, stopFFTbin; - - Word16 *part, *psize_inv, *psize_norm; - Word32 tmp, *fftBuffer, *periodog, *ptr_per, *ptr_r, *ptr_i; -#ifdef IVAS_CODE_CNG - PMT("lots of code related to IVAS needs to be done ") + Word16 j, k, nBins; + Word16 s, s1, s2, num, denom; + Word32 *cngNoiseLevel; + Word16 *cngNoiseLevel_exp; + Word32 L_tmp; + Word16 L_tmp_exp; + Word16 facTab[NPART]; + Word16 facTabExp[NPART]; + Word16 tmp_loop; + Word32 L_c; + Word16 lsp_cng[M]; + HANDLE_FD_CNG_DEC hFdCngDec; + HANDLE_FD_CNG_COM hFdCngCom; +#ifdef BASOP_NOGLOB_DECLARE_LOCAL + Flag Overflow = 0; + Flag Carry = 0; #endif + Word16 L_frame, last_L_frame; + Word16 factor; + Word32 *sidNoiseEst; - /* pointer initialization */ - periodog = hFdCngDec->hFdCngCom->periodog; - fftBuffer = hFdCngDec->hFdCngCom->fftBuffer; - - part = hFdCngDec->part_shaping; - psize_inv = hFdCngDec->psize_inv_shaping; - psize_norm = hFdCngDec->psize_shaping_norm; - - /* variable initialization */ - startBand = hFdCngDec->hFdCngCom->startBand; - move16(); - stopFFTbin = hFdCngDec->hFdCngCom->stopFFTbin; - move16(); + hFdCngDec = st->hFdCngDec; + hFdCngCom = hFdCngDec->hFdCngCom; + sidNoiseEst = hFdCngCom->sidNoiseEst; - npart = hFdCngDec->npart_shaping; - move16(); - nFFTpart = hFdCngDec->nFFTpart_shaping; - move16(); + /* limit L_frame and core fs values for MDCT-Stereo modes which can have higher core sampling than 16kHz, but use a downsampled buffer */ + L_frame = s_min( st->L_frame, L_FRAME16k ); + last_L_frame = s_min( st->last_L_frame, L_FRAME16k ); - /* Perform STFT analysis */ -#ifdef IVAS_CODE_CNG_FIX185_PLC_FADEOUT - IF (!(EQ_16(element_mode, IVAS_CPE_MDCT) && power_spectrum != NULL)) + IF( EQ_16( hFdCngCom->frame_type_previous, ACTIVE_FRAME ) ) { - /* Perform STFT analysis */ - AnalysisSTFT(timeDomainInput, Q, fftBuffer, &fftBuffer_exp, hFdCngDec->hFdCngCom); + hFdCngCom->inactive_frame_counter = 0; + move16(); } -#else - /* Perform STFT analysis */ - AnalysisSTFT (timeDomainInput, Q, fftBuffer, &fftBuffer_exp, hFdCngDec->hFdCngCom); -#endif - fftBuffer_exp = add(fftBuffer_exp,WORD16_BITS-1); -#ifdef IVAS_CODE_CNG - if (element_mode == IVAS_CPE_TD || element_mode == IVAS_CPE_DFT) + IF( EQ_16( st->element_mode, IVAS_CPE_TD ) ) { - /* Calculate periodogram (squared magnitude in each FFT bin) */ - if (startBand == 0) - { - (*ptr_per) = fftBuffer[0] * fftBuffer[0]; - ptr_per++; - ptr_r = fftBuffer + 2; - } - else - { - ptr_r = fftBuffer + 2 * startBand; - } + hFdCngDec->flag_dtx_mode = hFdCngDec->flag_dtx_mode || st->first_CNG; + test(); + move16(); + } + cngNoiseLevel = hFdCngCom->cngNoiseLevel; + cngNoiseLevel_exp = &hFdCngCom->cngNoiseLevelExp; + move16(); + move16(); + nBins = sub( hFdCngCom->stopFFTbin, hFdCngCom->startBand ); - ptr_i = ptr_r + 1; + SWITCH( st->m_frame_type ) + { + case ACTIVE_FRAME: - for (; ptr_per < periodog + stopFFTbin - startBand; ptr_per++) - { - (*ptr_per) = (*ptr_r) * (*ptr_r) + (*ptr_i) * (*ptr_i); - ptr_r += 2; - ptr_i += 2; - } + /************************** + * ACTIVE_FRAME at DECODER * + **************************/ - /* Rescale to get energy/sample: it should be 2*(1/N)*(2/N), parseval relation with 1/N,*2 for nrg computed till Nyquist only, 2/N as windowed samples correspond to half a frame*/ - v_multc(periodog, 4.f / (float)(hFdCngDec->hFdCngCom->fftlen * hFdCngDec->hFdCngCom->fftlen), periodog, stopFFTbin - startBand); + hFdCngCom->inactive_frame_counter = 0; + move16(); + hFdCngCom->sid_frame_counter = 0; + move16(); - /* Combine bins of power spectrum into partitions */ - i = 0; - for (p = 0; p < npart; p++) - { + /* set noise estimation inactive during concealment, as no update with noise generated by concealment should be performed. */ + /* set noise estimation inactive during concealment, no update with noise generated by concealment should be performed. */ - /* calculate mean over all bins in power partition */ - temp = 0; - for (; i <= part[p]; i++) + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + IF( EQ_16( concealWholeFrame, 0 ) && + ( timeDomainInput == NULL || + ( *timeDomainInput( MINVAL_WORD16 ) && + *( timeDomainInput + hFdCngCom->frameSize - 1 ) < MAXVAL_WORD16 && + *( timeDomainInput + hFdCngCom->frameSize - 1 ) > ( MINVAL_WORD16 ) ) ) && + ( ( ( ( NE_16( st->element_mode, IVAS_CPE_TD ) && NE_16( st->element_mode, IVAS_CPE_DFT ) && hFdCngDec->flag_dtx_mode ) || !st->VAD || ( LT_16( st->ini_frame, 100 ) && st->is_ism_format ) ) && + !( EQ_16( st->cng_type, LP_CNG ) && hFdCngDec->flag_dtx_mode ) && ( EQ_16( is_music, 0 ) ) ) || + EQ_16( st->element_mode, IVAS_CPE_TD ) ) && + ( !st->BER_detect ) ) { - temp += periodog[i]; - } - msPeriodog[p] = temp * psize_inv[p]; - } + /* Perform noise estimation at the decoder */ + perform_noise_estimation_dec_fx( timeDomainInput, Q, powerSpectrum, hFdCngDec, st->element_mode, st->bwidth, L_frame, last_L_frame, st->last_core_brate, st->VAD ); - /* compensate for the loss of variance - don't do when first noise update is not completed yet due to risk of msPeriodog[p] < 0 */ - if (hFdCngDec->first_cna_noise_updated) - { - i = 0; - for (p = 0; p < npart; p++) - { - /* calculate variance over all bins in power partition */ - temp = 0; - for (; i <= part[p]; i++) + /* Update the shaping parameters */ + test(); + IF( NE_16( st->element_mode, IVAS_CPE_TD ) && NE_16( st->element_mode, IVAS_CPE_DFT ) ) { - delta = periodog[i] - msPeriodog[p]; - temp += delta * delta; + scalebands( hFdCngDec->msNoiseEst, hFdCngDec->part_shaping, hFdCngDec->nFFTpart_shaping, hFdCngDec->midband_shaping, hFdCngDec->nFFTpart_shaping, nBins, hFdCngDec->bandNoiseShape, 1 ); } - temp *= psize_inv[p]; + hFdCngDec->bandNoiseShape_exp = hFdCngDec->msNoiseEst_exp; + move16(); - /* compensate for the loss of variance */ - msPeriodog[p] = (float)(msPeriodog[p] + sqrt(temp) * rand_gauss(&ftemp, &hFdCngDec->cna_seed)); - if (msPeriodog[p] < 1e-5f) + /* Update CNG levels */ + test(); + IF( hFdCngDec->flag_dtx_mode != 0 && st->cng_type == FD_CNG ) { - msPeriodog[p] = 1e-5f; - } - } - } - - /* calculate total energy (short-term and long-term) */ - enr_tot = sum_f(msPeriodog, npart) + EPSILON; - enr_tot0 = sum_f(msNoiseEst, npart) + EPSILON; - - /* update short-term periodogram on larger partitions */ - for (p = CNA_ACT_DN_LARGE_PARTITION; p < npart; p++) - { - if (L_frame != last_L_frame || last_core_brate <= SID_2k40) - { - /* core Fs has changed or last frame was SID/NO_DATA -> re-initialize short-term periodogram */ - hFdCngDec->msPeriodog_ST[p] = msPeriodog[p]; - } - else - { - hFdCngDec->msPeriodog_ST[p] = (float)(ST_PERIODOG_FACT * hFdCngDec->msPeriodog_ST[p] + (1 - ST_PERIODOG_FACT) * msPeriodog[p]); - } - } - - /* core Fs has changed -> partitions have changed -> re-calculate long-term periodogram */ - /* part L_FRAME16k L_FRAME */ - /* ... */ - /* [55] 146 146 */ - /* [56] 174 160 */ - /* [57] 210 174 */ - /* [58] 254 190 */ - /* [59] 306 210 */ - /* [60] 317 230 */ - /* [61] 253 */ + /* This needs to be done only once per inactive phase */ + bandcombinepow( + hFdCngDec->bandNoiseShape, + hFdCngDec->bandNoiseShape_exp, + nBins, + hFdCngCom->part, + hFdCngCom->nFFTpart, + hFdCngCom->psize_inv, + hFdCngDec->partNoiseShape, + &hFdCngDec->partNoiseShape_exp ); + + + j = 0; + move16(); + // s2 = -( WORD32_BITS - 1 ); + s2 = negate( sub( WORD32_BITS, 1 ) ); + move16(); + FOR( k = 0; k < hFdCngCom->nFFTpart; k++ ) + { + assert( hFdCngDec->partNoiseShape[k] >= 0 ); + assert( hFdCngCom->sidNoiseEst[k] >= 0 ); - if (last_L_frame == L_FRAME16k && L_frame == L_FRAME) - { - msNoiseEst[61] = msNoiseEst[58]; - msNoiseEst[60] = min(msNoiseEst[58], msNoiseEst[57]); - msNoiseEst[59] = msNoiseEst[57]; - msNoiseEst[58] = msNoiseEst[56]; - msNoiseEst[57] = msNoiseEst[56]; - msNoiseEst[56] = min(msNoiseEst[56], msNoiseEst[55]); - } - else if (last_L_frame == L_FRAME && L_frame == L_FRAME16k) - { - msNoiseEst[56] = min(msNoiseEst[56], msNoiseEst[57]); - msNoiseEst[57] = min(msNoiseEst[58], msNoiseEst[59]); - msNoiseEst[58] = min(msNoiseEst[60], msNoiseEst[61]); - msNoiseEst[59] = 0.0f; - msNoiseEst[60] = 0.0f; - msNoiseEst[61] = 0.0f; + /* add DELTA as it is done in FLC version, in order to avoid num > denom */ + facTab[k] = 0; + move16(); + IF( hFdCngDec->partNoiseShape[k] != 0 ) + { + s1 = norm_l( hFdCngCom->sidNoiseEst[k] ); + L_tmp = L_shl( hFdCngCom->sidNoiseEst[k], s1 ); + L_tmp_exp = sub( hFdCngCom->sidNoiseEstExp, s1 ); + L_tmp = BASOP_Util_Add_Mant32Exp( L_tmp, L_tmp_exp, DELTA_MANTISSA_W32, DELTA_EXPONENT, &L_tmp_exp ); + L_tmp = L_shr( L_tmp, 1 ); + s = add( L_tmp_exp, 1 ); + num = extract_h( L_tmp ); + + s1 = norm_l( hFdCngDec->partNoiseShape[k] ); + L_tmp = L_shl( hFdCngDec->partNoiseShape[k], s1 ); + L_tmp_exp = sub( hFdCngDec->partNoiseShape_exp, s1 ); + L_tmp = BASOP_Util_Add_Mant32Exp( L_tmp, L_tmp_exp, DELTA_MANTISSA_W32, DELTA_EXPONENT, &L_tmp_exp ); + s = sub( s, L_tmp_exp ); + denom = extract_h( L_tmp ); + + facTab[k] = div_s( num, denom ); + move16(); + facTabExp[k] = s; + move16(); + } + /* Set unique exponent, if mantissa is equal to zero */ + IF( EQ_16( facTab[k], 0 ) ) + { + facTabExp[k] = negate( sub( WORD32_BITS, 1 ) ); + move16(); + } + s2 = s_max( s2, facTabExp[k] ); + } - hFdCngDec->ms_cnt_bw_up = FIRST_CNA_NOISE_UPD_FRAMES; - } + FOR( k = 0; k < hFdCngCom->nFFTpart; k++ ) + { + s = sub( facTabExp[k], s2 ); + s = s_max( s_min( s, sub( WORD32_BITS, 1 ) ), negate( sub( WORD32_BITS, 1 ) ) ); + FOR( ; j <= hFdCngCom->part[k]; j++ ) + { + cngNoiseLevel[j] = L_shl( Mpy_32_16_1( hFdCngDec->bandNoiseShape[j], facTab[k] ), s ); + move32(); + } + } - /* Smooth with IIR filter */ - if (!hFdCngDec->first_cna_noise_updated) - { - if (!VAD) - { - /* background noise update with moving average */ - alpha = 1.0f / (hFdCngDec->first_cna_noise_update_cnt + 1); - for (p = 0; p < npart; p++) - { - msNoiseEst[p] = (1 - alpha) * msNoiseEst[p] + alpha * msPeriodog[p]; - } + /* adapt scaling for rest of the buffer */ + IF( NE_16( s2, -( WORD32_BITS - 1 ) ) ) + { + s = sub( *cngNoiseLevel_exp, add( hFdCngDec->bandNoiseShape_exp, s2 ) ); + FOR( ; k < hFdCngCom->npart; k++ ) + { + FOR( ; j <= hFdCngCom->part[k]; j++ ) + { + cngNoiseLevel[j] = L_shl( cngNoiseLevel[j], s ); + move32(); + } + } - /* check, if we reached the required number of first CNA noise update frames */ - if (hFdCngDec->first_cna_noise_update_cnt < FIRST_CNA_NOISE_UPD_FRAMES - 1) - { - hFdCngDec->first_cna_noise_update_cnt++; + *cngNoiseLevel_exp = add( hFdCngDec->bandNoiseShape_exp, s2 ); + move16(); + } } - else + ELSE { - hFdCngDec->first_cna_noise_updated = 1; - if (hFdCngDec->hFdCngCom->msFrCnt_init_counter == 0) + /* This sets the new CNG levels until a SID update overwrites it */ + test(); + test(); + test(); + IF( !( EQ_16( st->element_mode, IVAS_CPE_TD ) ) || ( EQ_16( st->element_mode, IVAS_CPE_TD ) && !hFdCngDec->flag_dtx_mode && !st->VAD ) ) { - hFdCngDec->hFdCngCom->msFrCnt_init_counter = 1; + Copy32( hFdCngDec->bandNoiseShape, cngNoiseLevel, nBins ); + *cngNoiseLevel_exp = hFdCngDec->bandNoiseShape_exp; + move16(); } } - } - else - { + + IF( ( EQ_16( st->element_mode, IVAS_CPE_MDCT ) && timeDomainInput == NULL ) ) + { + // st->hTcxDec->CngLevelBackgroundTrace_bfi = sqrtf(sum_f(cngNoiseLevel, hFdCngCom->stopFFTbin - hFdCngCom->startBand) / NORM_MDCT_FACTOR); + + tmp_loop = sub( hFdCngCom->stopFFTbin, hFdCngCom->startBand ); + L_tmp = L_deposit_h( 0 ); + L_c = L_deposit_h( 0 ); + FOR( j = 0; j < tmp_loop; j++ ) + { + + Carry = 0; +#ifdef BASOP_NOGLOB + L_tmp = L_add_co( L_tmp, *( cngNoiseLevel + j ), &Carry, &Overflow ); +#else + L_tmp = L_add_c( L_tmp, *( cngNoiseLevel + j ) ); +#endif + Overflow = 0; + + IF( *( cngNoiseLevel + j ) < 0 ) + { + L_c = L_msuNs( L_c, 0, 0 ); + } + IF( *( cngNoiseLevel + j ) >= 0 ) + { +#ifdef BASOP_NOGLOB + L_c = L_macNs_co( L_c, 0, 0, &Carry, &Overflow ); +#else + L_c = L_macNs( L_c, 0, 0 ); +#endif + } + } + L_tmp = norm_llQ31( L_c, L_tmp, &L_tmp_exp ); + L_tmp_exp = sub( add( L_tmp_exp, *cngNoiseLevel_exp ), 1 ); + + // L_tmp = Mpy_32_16_1(L_tmp, hFdCngCom->fftlen); /*Q16*/ + + L_tmp = Mpy_32_16_1( L_tmp, shr( T_DIV_L_Frame[L_shl( L_mac( -28000, NORM_MDCT_FACTOR, 95 ), 1 - 15 )], 1 ) ); /*Q16,exp -7*/ + L_tmp_exp = add( L_tmp_exp, -7 ); /*->Q16, L_tmp_exp */ + L_tmp_exp = add( L_tmp_exp, 31 - 16 ); /*->Q31, L_tmp_exp*/ + +#ifdef BASOP_NOGLOB + st->hTcxDec->CngLevelBackgroundTrace_bfi_fx = ( Sqrt32( L_tmp, &L_tmp_exp ) ); +#else + st->hTcxDec->CngLevelBackgroundTrace_bfi_fx = ( Sqrt32( L_tmp, &L_tmp_exp ) ); +#endif + st->hTcxDec->CngLevelBackgroundTrace_bfi_exp = L_tmp_exp; + move16(); + } + ELSE + { + // st->hTcxDec->CngLevelBackgroundTrace_bfi = (float)sqrt((sum_f(cngNoiseLevel, hFdCngCom->stopFFTbin - hFdCngCom->startBand) / 2 * hFdCngCom->fftlen) / L_frame); + + tmp_loop = sub( hFdCngCom->stopFFTbin, hFdCngCom->startBand ); + L_tmp = L_deposit_h( 0 ); + L_c = L_deposit_h( 0 ); + FOR( j = 0; j < tmp_loop; j++ ) + { + + Carry = 0; +#ifdef BASOP_NOGLOB + L_tmp = L_add_co( L_tmp, *( cngNoiseLevel + j ), &Carry, &Overflow ); +#else + L_tmp = L_add_c( L_tmp, *( cngNoiseLevel + j ) ); +#endif + Overflow = 0; + + IF( *( cngNoiseLevel + j ) < 0 ) + { + L_c = L_msuNs( L_c, 0, 0 ); + } + IF( *( cngNoiseLevel + j ) >= 0 ) + { +#ifdef BASOP_NOGLOB + L_c = L_macNs_co( L_c, 0, 0, &Carry, &Overflow ); +#else + L_c = L_macNs( L_c, 0, 0 ); +#endif + } + } + L_tmp = norm_llQ31( L_c, L_tmp, &L_tmp_exp ); + L_tmp_exp = sub( add( L_tmp_exp, *cngNoiseLevel_exp ), 1 ); + + L_tmp = Mpy_32_16_1( L_tmp, hFdCngCom->fftlen ); /*Q16*/ + + L_tmp = Mpy_32_16_1( L_tmp, T_DIV_L_Frame[L_shl( L_mac( -28000, st->L_frame, 95 ), 1 - 15 )] ); /*Q16,exp -7*/ + L_tmp_exp = add( L_tmp_exp, -7 ); /*->Q16, L_tmp_exp */ + L_tmp_exp = add( L_tmp_exp, 31 - 16 ); /*->Q31, L_tmp_exp*/ + +#ifdef BASOP_NOGLOB + st->hTcxDec->CngLevelBackgroundTrace_bfi_fx = ( Sqrt32( L_tmp, &L_tmp_exp ) ); +#else + st->hTcxDec->CngLevelBackgroundTrace_bfi_fx = ( Sqrt32( L_tmp, &L_tmp_exp ) ); +#endif + st->hTcxDec->CngLevelBackgroundTrace_bfi_exp = L_tmp_exp; + move16(); + } + + /*st->cngTDLevel = (float)sqrt( (sumFLOAT(cngNoiseLevel, hFdCngCom->stopFFTbin - hFdCngCom->startBand) / 2 * hFdCngCom->fftlen) / st->Mode2_L_frame);*/ + tmp_loop = sub( hFdCngCom->stopFFTbin, hFdCngCom->startBand ); + L_tmp = L_deposit_h( 0 ); + L_c = L_deposit_h( 0 ); + FOR( j = 0; j < tmp_loop; j++ ) + { + + Carry = 0; +#ifdef BASOP_NOGLOB + L_tmp = L_add_co( L_tmp, *( cngNoiseLevel + j ), &Carry, &Overflow ); +#else + L_tmp = L_add_c( L_tmp, *( cngNoiseLevel + j ) ); +#endif + Overflow = 0; + + IF( *( cngNoiseLevel + j ) < 0 ) + { + L_c = L_msuNs( L_c, 0, 0 ); + } + IF( *( cngNoiseLevel + j ) >= 0 ) + { +#ifdef BASOP_NOGLOB + L_c = L_macNs_co( L_c, 0, 0, &Carry, &Overflow ); +#else + L_c = L_macNs( L_c, 0, 0 ); +#endif + } + } + L_tmp = norm_llQ31( L_c, L_tmp, &L_tmp_exp ); + L_tmp_exp = sub( add( L_tmp_exp, *cngNoiseLevel_exp ), 1 ); + + L_tmp = Mpy_32_16_1( L_tmp, hFdCngCom->fftlen ); /*Q16*/ + + L_tmp = Mpy_32_16_1( L_tmp, T_DIV_L_Frame[L_shl( L_mac( -28000, st->L_frame, 95 ), 1 - 15 )] ); /*Q16,exp -7*/ + L_tmp_exp = add( L_tmp_exp, -7 ); /*->Q16, L_tmp_exp */ + L_tmp_exp = add( L_tmp_exp, 31 - 16 ); /*->Q31, L_tmp_exp*/ + +#ifdef BASOP_NOGLOB + st->cngTDLevel = round_fx_sat( Sqrt32( L_tmp, &L_tmp_exp ) ); +#else + st->cngTDLevel = round_fx( Sqrt32( L_tmp, &L_tmp_exp ) ); +#endif + st->cngTDLevel_e = L_tmp_exp; + move16(); + } + ELSE IF( EQ_16( st->element_mode, IVAS_CPE_TD ) || EQ_16( st->element_mode, IVAS_CPE_DFT ) ) + { + IF( hFdCngCom->active_frame_counter > 0 ) + { + /* Perform noise estimation in active frames in the decoder for downward updates */ + perform_noise_estimation_dec_fx( timeDomainInput, Q, powerSpectrum, hFdCngDec, st->element_mode, st->bwidth, L_frame, last_L_frame, st->last_core_brate, st->VAD ); + } + } + test(); + test(); + L_tmp = 0; + FOR( j = hFdCngCom->startBand; j < hFdCngCom->stopFFTbin; j++ ) + { + L_tmp = L_add( L_tmp, L_shr( cngNoiseLevel[j], 16 ) ); + } + L_tmp_exp = add( *cngNoiseLevel_exp, 16 ); +#ifdef BASOP_NOGLOB + IF( EQ_16( concealWholeFrame, 1 ) && EQ_16( st->nbLostCmpt, 1 ) && ( L_shl_o( L_tmp, L_tmp_exp, &Overflow ) > 21474836 /*0.01f Q31*/ ) ) +#else + IF( EQ_16( concealWholeFrame, 1 ) && EQ_16( st->nbLostCmpt, 1 ) && ( L_shl( L_tmp, L_tmp_exp ) > 21474836 /*0.01f Q31*/ ) ) +#endif + { + /* update isf cng estimate for concealment. Do that during concealment, in order to avoid addition clean channel complexity*/ + IF( EQ_16( st->element_mode, IVAS_CPE_MDCT ) && NE_16( st->core, ACELP_CORE ) ) + { + TonalMdctConceal_whiten_noise_shape_ivas_fx( st, L_frame, ON_FIRST_LOST_FRAME ); + } + ELSE IF( NE_16( st->element_mode, IVAS_CPE_MDCT ) ) + { + lpc_from_spectrum( hFdCngCom, hFdCngCom->startBand, hFdCngCom->stopFFTbin, 0 ); + E_LPC_a_lsp_conversion( hFdCngCom->A_cng, lsp_cng, st->lspold_cng, M ); + Copy( lsp_cng, st->lspold_cng, M ); + + lsp2lsf_fx( lsp_cng, st->lsf_cng, M, st->sr_core ); + } + + st->plcBackgroundNoiseUpdated = 1; + move16(); + } + BREAK; + + case SID_FRAME: + + hFdCngDec->flag_dtx_mode = 1; + move16(); + /* no break */ + + case ZERO_FRAME: + + test(); + IF( st != NULL && EQ_16( st->cng_type, LP_CNG ) ) + { + /* Perform noise estimation on inactive phase at the decoder */ + perform_noise_estimation_dec_fx( timeDomainInput, Q, powerSpectrum, hFdCngDec, st->element_mode, st->bwidth, L_frame, last_L_frame, st->last_core_brate, st->VAD ); + + /* Update the shaping parameters */ + + IF( NE_16( st->element_mode, IVAS_CPE_TD ) && NE_16( st->element_mode, IVAS_CPE_DFT ) ) + { + scalebands( hFdCngDec->msNoiseEst, hFdCngDec->part_shaping, hFdCngDec->nFFTpart_shaping, hFdCngDec->midband_shaping, hFdCngDec->nFFTpart_shaping, hFdCngCom->stopFFTbin - hFdCngCom->startBand, hFdCngDec->bandNoiseShape, 1 ); + } + hFdCngDec->bandNoiseShape_exp = hFdCngDec->msNoiseEst_exp; + move16(); + /* This sets the new CNG levels until a SID update overwrites it */ + Copy32( hFdCngDec->bandNoiseShape, cngNoiseLevel, hFdCngCom->stopFFTbin - hFdCngCom->startBand ); /* This sets the new CNG levels until a SID update overwrites it */ + *cngNoiseLevel_exp = hFdCngDec->bandNoiseShape_exp; + move16(); + + /*st->cngTDLevel = (float)sqrt( (sumFLOAT(cngNoiseLevel, hFdCngCom->stopFFTbin - hFdCngCom->startBand) / 2 * hFdCngCom->fftlen) / st->Mode2_L_frame);*/ + tmp_loop = sub( hFdCngCom->stopFFTbin, hFdCngCom->startBand ); + L_tmp = L_deposit_h( 0 ); + L_c = L_deposit_h( 0 ); + FOR( j = 0; j < tmp_loop; j++ ) + { + + Carry = 0; +#ifdef BASOP_NOGLOB /* Critical Carry/Overflow */ + L_tmp = L_add_co( L_tmp, *( cngNoiseLevel + j ), &Carry, &Overflow ); + Overflow = 0; + + IF( *( cngNoiseLevel + j ) < 0 ) + { + L_c = L_msuNs_co( L_c, 0, 0, &Carry, &Overflow ); + } + IF( *( cngNoiseLevel + j ) >= 0 ) + { + L_c = L_macNs_co( L_c, 0, 0, &Carry, &Overflow ); + } +#else + L_tmp = L_add_c( L_tmp, *( cngNoiseLevel + j ) ); + Overflow = 0; + + IF( *( cngNoiseLevel + j ) < 0 ) + { + L_c = L_msuNs( L_c, 0, 0 ); + } + IF( *( cngNoiseLevel + j ) >= 0 ) + { + L_c = L_macNs( L_c, 0, 0 ); + } +#endif + } + L_tmp = norm_llQ31( L_c, L_tmp, &L_tmp_exp ); + L_tmp_exp = sub( add( L_tmp_exp, *cngNoiseLevel_exp ), 1 ); + + L_tmp = Mpy_32_16_1( L_tmp, hFdCngCom->fftlen ); /*Q16*/ + + L_tmp = Mpy_32_16_1( L_tmp, T_DIV_L_Frame[L_shl( L_mac( -28000, st->L_frame, 95 ), 1 - 15 )] ); /*Q16,exp -7*/ + L_tmp_exp = add( L_tmp_exp, -7 ); /*->Q16, L_tmp_exp */ + L_tmp_exp = add( L_tmp_exp, 31 - 16 ); /*->Q31, L_tmp_exp*/ + +#ifdef BASOP_NOGLOB /* Critical Carry/Overflow */ + st->cngTDLevel = round_fx_o( Sqrt32( L_tmp, &L_tmp_exp ), &Overflow ); +#else + st->cngTDLevel = round_fx( Sqrt32( L_tmp, &L_tmp_exp ) ); +#endif + st->cngTDLevel_e = L_tmp_exp; + move16(); + BREAK; + } + hFdCngCom->inactive_frame_counter = add( hFdCngCom->inactive_frame_counter, 1 ); + move16(); + + /************************************* + * SID_FRAME or ZERO_FRAME at DECODER * + *************************************/ + + /* Detect first non-active frame */ + IF( EQ_16( hFdCngCom->inactive_frame_counter, 1 ) ) + { + /* Compute the fine spectral structure of the comfort noise shape using the decoder-side noise estimates */ + bandcombinepow( + hFdCngDec->bandNoiseShape, + hFdCngDec->bandNoiseShape_exp, + nBins, + hFdCngCom->part, + hFdCngCom->nFFTpart, + hFdCngCom->psize_inv, + hFdCngDec->partNoiseShape, + &hFdCngDec->partNoiseShape_exp ); + IF( EQ_16( st->element_mode, IVAS_CPE_DFT ) ) + { + Copy32( hFdCngDec->hFdCngCom->sidNoiseEst, hFdCngDec->hFdCngCom->sidNoiseEstLp, NPART ); + } + } + + IF( EQ_16( st->m_frame_type, SID_FRAME ) ) + { + IF( LT_32( hFdCngCom->msFrCnt_init_counter, L_deposit_l( hFdCngCom->msFrCnt_init_thresh ) ) ) + { + /* At initialization, interpolate the bin/band-wise levels from the partition levels */ + scalebands( hFdCngCom->sidNoiseEst, hFdCngCom->part, hFdCngCom->npart, hFdCngCom->midband, + hFdCngCom->nFFTpart, sub( hFdCngCom->stopBand, hFdCngCom->startBand ), cngNoiseLevel, 1 ); + *cngNoiseLevel_exp = hFdCngCom->sidNoiseEstExp; + move16(); + } + ELSE + { + IF( EQ_16( st->element_mode, IVAS_CPE_DFT ) ) + { + sidNoiseEst = hFdCngCom->sidNoiseEstLp; + move16(); + } + /* Interpolate the CLDFB band levels from the SID (partition) levels */ + IF( GT_16( hFdCngCom->regularStopBand, hFdCngCom->numCoreBands ) ) + { + scalebands( hFdCngCom->sidNoiseEst, hFdCngCom->part, hFdCngCom->npart, hFdCngCom->midband, + hFdCngCom->nFFTpart, sub( hFdCngCom->stopBand, hFdCngCom->startBand ), cngNoiseLevel, 0 ); + + *cngNoiseLevel_exp = hFdCngCom->sidNoiseEstExp; + move16(); + } + + s2 = negate( sub( WORD32_BITS, 1 ) ); + move16(); + /* Shape the SID noise levels in each FFT bin */ + j = 0; + move16(); + FOR( k = 0; k < hFdCngCom->nFFTpart; k++ ) + { + assert( hFdCngDec->partNoiseShape[k] >= 0 ); + + /* add DELTA as it is done in FLC version, in order to avoid num > denom */ + facTab[k] = 0; + move16(); + IF( hFdCngDec->partNoiseShape[k] != 0 ) + { + s1 = norm_l( hFdCngCom->sidNoiseEst[k] ); + L_tmp = L_shl( hFdCngCom->sidNoiseEst[k], s1 ); + L_tmp_exp = sub( hFdCngCom->sidNoiseEstExp, s1 ); + L_tmp = BASOP_Util_Add_Mant32Exp( hFdCngCom->sidNoiseEst[k], hFdCngCom->sidNoiseEstExp, DELTA_MANTISSA_W32, DELTA_EXPONENT, &L_tmp_exp ); + L_tmp = L_shr( L_tmp, 1 ); + s = add( L_tmp_exp, 1 ); + num = extract_h( L_tmp ); + + s1 = norm_l( hFdCngDec->partNoiseShape[k] ); + L_tmp = L_shl( hFdCngDec->partNoiseShape[k], s1 ); + L_tmp_exp = sub( hFdCngDec->partNoiseShape_exp, s1 ); + L_tmp = BASOP_Util_Add_Mant32Exp( L_tmp, L_tmp_exp, DELTA_MANTISSA_W32, DELTA_EXPONENT, &L_tmp_exp ); + s = sub( s, L_tmp_exp ); + denom = extract_h( L_tmp ); + + facTab[k] = div_s( num, denom ); + move16(); + facTabExp[k] = s; + move16(); + } + /* Set unique exponent, IF mantissa is equal to zero */ + IF( EQ_16( facTab[k], 0 ) ) + { + facTabExp[k] = negate( sub( WORD32_BITS, 1 ) ); + move16(); + } + s2 = s_max( s2, facTabExp[k] ); + } + + FOR( k = 0; k < hFdCngCom->nFFTpart; k++ ) + { + s = sub( facTabExp[k], s2 ); + s = s_max( s_min( s, sub( WORD32_BITS, 1 ) ), negate( sub( WORD32_BITS, 1 ) ) ); + FOR( ; j <= hFdCngCom->part[k]; j++ ) + { + cngNoiseLevel[j] = L_shl( Mpy_32_16_1( hFdCngDec->bandNoiseShape[j], facTab[k] ), s ); + move32(); + } + } + /* adapt scaling for rest of the buffer */ + s = sub( *cngNoiseLevel_exp, add( hFdCngDec->bandNoiseShape_exp, s2 ) ); + FOR( ; k < hFdCngCom->npart; k++ ) + { + FOR( ; j <= hFdCngCom->part[k]; j++ ) + { + cngNoiseLevel[j] = L_shl( cngNoiseLevel[j], s ); + move32(); + } + } + *cngNoiseLevel_exp = add( hFdCngDec->bandNoiseShape_exp, s2 ); + move16(); + } + } + ELSE IF( EQ_16( st->element_mode, IVAS_CPE_DFT ) ) + { + IF( !( hFdCngCom->msFrCnt_init_counter < hFdCngCom->msFrCnt_init_thresh ) ) + { + Word16 scale; + sidNoiseEst = hFdCngCom->sidNoiseEstLp; + j = 0; + FOR( k = 0; k < hFdCngCom->nFFTpart; k++ ) + { + factor = BASOP_Util_Divide3232_Scale( ( sidNoiseEst[k] + 1 ), ( hFdCngDec->partNoiseShape[k] + 1 ), &scale ); + FOR( ; j <= hFdCngCom->part[k]; j++ ) + { + cngNoiseLevel[j] = Mpy_32_16_1( hFdCngDec->bandNoiseShape[j], factor ); + } + } + } + } + IF( EQ_16( st->codec_mode, MODE2 ) ) + { + /* Generate comfort noise during SID or zero frames */ + generate_comfort_noise_dec( cldfbBufferReal, cldfbBufferImag, cldfbBufferScale, st, &( st->Q_exc ), 2, -1 ); + } + + BREAK; + + default: + return -1; + } + + + return 0; +} +#endif // IVAS_FLOAT_FIXED + +/* + perform_noise_estimation_dec + + Parameters: + + timeDomainInput, i: pointer to time domain input + bitrate, i: bitrate + st i/o: FD_CNG structure containing all buffers and variables + + Function: + perform noise estimation + + Returns: + void +*/ +void perform_noise_estimation_dec ( + const Word16 *timeDomainInput, /* i: pointer to time domain input */ + const Word16 Q, +#ifdef IVAS_CODE_CNG_FIX185_PLC_FADEOUT + float* power_spectrum, +#endif + HANDLE_FD_CNG_DEC hFdCngDec /* i/o: FD_CNG structure containing all buffers and variables */ +#ifdef IVAS_CODE_CNG + ,const int16_t element_mode, /* i : element mode */ + const int16_t bwidth, /* i : audio bandwidth */ + const int16_t L_frame, /* i : frame length at internal Fs */ + const int16_t last_L_frame, /* i : frame length of the last frame at internal Fs */ + const int32_t last_core_brate, /* i : previous frame core bitrate */ + const int16_t VAD /* i : VAD flag in the decoder */ +#endif + ) +{ + Word16 i, tmp_r, tmp_i, fac, fftBuffer_exp; + Word16 s, len, npart, nFFTpart; + Word16 startBand, stopFFTbin; + + Word16 *part, *psize_inv, *psize_norm; + Word32 tmp, *fftBuffer, *periodog, *ptr_per, *ptr_r, *ptr_i; +#ifdef IVAS_CODE_CNG + PMT("lots of code related to IVAS needs to be done ") +#endif + + + /* pointer initialization */ + periodog = hFdCngDec->hFdCngCom->periodog; + fftBuffer = hFdCngDec->hFdCngCom->fftBuffer; + + part = hFdCngDec->part_shaping; + psize_inv = hFdCngDec->psize_inv_shaping; + psize_norm = hFdCngDec->psize_shaping_norm; + + /* variable initialization */ + startBand = hFdCngDec->hFdCngCom->startBand; + move16(); + stopFFTbin = hFdCngDec->hFdCngCom->stopFFTbin; + move16(); + + npart = hFdCngDec->npart_shaping; + move16(); + nFFTpart = hFdCngDec->nFFTpart_shaping; + move16(); + + /* Perform STFT analysis */ +#ifdef IVAS_CODE_CNG_FIX185_PLC_FADEOUT + IF (!(EQ_16(element_mode, IVAS_CPE_MDCT) && power_spectrum != NULL)) + { + /* Perform STFT analysis */ + AnalysisSTFT(timeDomainInput, Q, fftBuffer, &fftBuffer_exp, hFdCngDec->hFdCngCom); + } +#else + /* Perform STFT analysis */ + AnalysisSTFT (timeDomainInput, Q, fftBuffer, &fftBuffer_exp, hFdCngDec->hFdCngCom); +#endif + fftBuffer_exp = add(fftBuffer_exp,WORD16_BITS-1); +#ifdef IVAS_CODE_CNG + if (element_mode == IVAS_CPE_TD || element_mode == IVAS_CPE_DFT) + { + /* Calculate periodogram (squared magnitude in each FFT bin) */ + if (startBand == 0) + { + (*ptr_per) = fftBuffer[0] * fftBuffer[0]; + ptr_per++; + ptr_r = fftBuffer + 2; + } + else + { + ptr_r = fftBuffer + 2 * startBand; + } + + ptr_i = ptr_r + 1; + + for (; ptr_per < periodog + stopFFTbin - startBand; ptr_per++) + { + (*ptr_per) = (*ptr_r) * (*ptr_r) + (*ptr_i) * (*ptr_i); + ptr_r += 2; + ptr_i += 2; + } + + /* Rescale to get energy/sample: it should be 2*(1/N)*(2/N), parseval relation with 1/N,*2 for nrg computed till Nyquist only, 2/N as windowed samples correspond to half a frame*/ + v_multc(periodog, 4.f / (float)(hFdCngDec->hFdCngCom->fftlen * hFdCngDec->hFdCngCom->fftlen), periodog, stopFFTbin - startBand); + + /* Combine bins of power spectrum into partitions */ + i = 0; + for (p = 0; p < npart; p++) + { + + /* calculate mean over all bins in power partition */ + temp = 0; + for (; i <= part[p]; i++) + { + temp += periodog[i]; + } + msPeriodog[p] = temp * psize_inv[p]; + } + + /* compensate for the loss of variance - don't do when first noise update is not completed yet due to risk of msPeriodog[p] < 0 */ + if (hFdCngDec->first_cna_noise_updated) + { + i = 0; + for (p = 0; p < npart; p++) + { + /* calculate variance over all bins in power partition */ + temp = 0; + for (; i <= part[p]; i++) + { + delta = periodog[i] - msPeriodog[p]; + temp += delta * delta; + } + temp *= psize_inv[p]; + + /* compensate for the loss of variance */ + msPeriodog[p] = (float)(msPeriodog[p] + sqrt(temp) * rand_gauss(&ftemp, &hFdCngDec->cna_seed)); + + if (msPeriodog[p] < 1e-5f) + { + msPeriodog[p] = 1e-5f; + } + } + } + + /* calculate total energy (short-term and long-term) */ + enr_tot = sum_f(msPeriodog, npart) + EPSILON; + enr_tot0 = sum_f(msNoiseEst, npart) + EPSILON; + + /* update short-term periodogram on larger partitions */ + for (p = CNA_ACT_DN_LARGE_PARTITION; p < npart; p++) + { + if (L_frame != last_L_frame || last_core_brate <= SID_2k40) + { + /* core Fs has changed or last frame was SID/NO_DATA -> re-initialize short-term periodogram */ + hFdCngDec->msPeriodog_ST[p] = msPeriodog[p]; + } + else + { + hFdCngDec->msPeriodog_ST[p] = (float)(ST_PERIODOG_FACT * hFdCngDec->msPeriodog_ST[p] + (1 - ST_PERIODOG_FACT) * msPeriodog[p]); + } + } + + /* core Fs has changed -> partitions have changed -> re-calculate long-term periodogram */ + /* part L_FRAME16k L_FRAME */ + /* ... */ + /* [55] 146 146 */ + /* [56] 174 160 */ + /* [57] 210 174 */ + /* [58] 254 190 */ + /* [59] 306 210 */ + /* [60] 317 230 */ + /* [61] 253 */ + + if (last_L_frame == L_FRAME16k && L_frame == L_FRAME) + { + msNoiseEst[61] = msNoiseEst[58]; + msNoiseEst[60] = min(msNoiseEst[58], msNoiseEst[57]); + msNoiseEst[59] = msNoiseEst[57]; + msNoiseEst[58] = msNoiseEst[56]; + msNoiseEst[57] = msNoiseEst[56]; + msNoiseEst[56] = min(msNoiseEst[56], msNoiseEst[55]); + } + else if (last_L_frame == L_FRAME && L_frame == L_FRAME16k) + { + msNoiseEst[56] = min(msNoiseEst[56], msNoiseEst[57]); + msNoiseEst[57] = min(msNoiseEst[58], msNoiseEst[59]); + msNoiseEst[58] = min(msNoiseEst[60], msNoiseEst[61]); + msNoiseEst[59] = 0.0f; + msNoiseEst[60] = 0.0f; + msNoiseEst[61] = 0.0f; + + hFdCngDec->ms_cnt_bw_up = FIRST_CNA_NOISE_UPD_FRAMES; + } + + /* Smooth with IIR filter */ + if (!hFdCngDec->first_cna_noise_updated) + { + if (!VAD) + { + /* background noise update with moving average */ + alpha = 1.0f / (hFdCngDec->first_cna_noise_update_cnt + 1); + for (p = 0; p < npart; p++) + { + msNoiseEst[p] = (1 - alpha) * msNoiseEst[p] + alpha * msPeriodog[p]; + } + + /* check, if we reached the required number of first CNA noise update frames */ + if (hFdCngDec->first_cna_noise_update_cnt < FIRST_CNA_NOISE_UPD_FRAMES - 1) + { + hFdCngDec->first_cna_noise_update_cnt++; + } + else + { + hFdCngDec->first_cna_noise_updated = 1; + if (hFdCngDec->hFdCngCom->msFrCnt_init_counter == 0) + { + hFdCngDec->hFdCngCom->msFrCnt_init_counter = 1; + } + } + } + else + { + hFdCngDec->first_cna_noise_update_cnt = 0; + } + } + else + { + hFdCngDec->hFdCngCom->msFrCnt_init_counter = 1; + if (VAD) + { + /* no updates during active frames except for significant energy drops */ + enr_ratio = enr_tot / enr_tot0; + if (enr_ratio < 0.5f) + { + /* total energy significantly decreases during active frames -> downward update */ + wght = lin_interp(enr_ratio, 0.0f, 0.8f, 0.5f, 0.95f, 1); + for (p = 0; p < npart; p++) + { + if (msPeriodog[p] < msNoiseEst[p]) + { + msNoiseEst[p] = wght * msNoiseEst[p] + (1 - wght) * msPeriodog[p]; + } + } + } + else + { + /* energy significantly decreases in one of the larger partitions during active frames -> downward update */ + for (p = CNA_ACT_DN_LARGE_PARTITION; p < npart; p++) + { + if (hFdCngDec->msPeriodog_ST[p] < msNoiseEst[p]) + { + msNoiseEst[p] = (float)(CNA_ACT_DN_FACT * msNoiseEst[p] + (1 - CNA_ACT_DN_FACT) * hFdCngDec->msPeriodog_ST[p]); + } + } + } + } + else + { + + if (bwidth >= WB && hFdCngDec->ms_last_inactive_bwidth == NB) + { + /* bandwidth increased -> set counter for fast initilization */ + hFdCngDec->ms_cnt_bw_up = FIRST_CNA_NOISE_UPD_FRAMES; + } + hFdCngDec->ms_last_inactive_bwidth = bwidth; + /* update background noise during inactive frames */ + ptr_per = msNoiseEst; + for (p = 0; p < npart; p++) + { + enr = msPeriodog[p]; + alpha = 0.95f; + /* bandwidth increased -> do fast re-initilization */ + if (hFdCngDec->ms_cnt_bw_up > 0 && p > 55) + { + alpha = 1.0f / (hFdCngDec->ms_cnt_bw_up + 1); + } + else if (enr < *ptr_per && part[p] == 1) + { + /* faster downward update for single-bin partitions */ + alpha = 0.8f; + } + else if (enr > 2.0f * (*ptr_per)) + { + /* prevent abrupt upward updates */ + enr = 2.0f * (*ptr_per); + } + + /* IIR smoothing */ + *ptr_per *= alpha; + *ptr_per += (1 - alpha) * enr; + ptr_per++; + } + + if (hFdCngDec->ms_cnt_bw_up > 0) + { + hFdCngDec->ms_cnt_bw_up--; + } + } + } + + mvr2r(msNoiseEst, hFdCngDec->msPsd, npart); + + /* Expand partitions into bins of power spectrum */ + scalebands(msNoiseEst, part, nFFTpart, hFdCngDec->midband_shaping, nFFTpart, stopFFTbin - startBand, hFdCngDec->bandNoiseShape, 1); + + mvr2r(hFdCngDec->bandNoiseShape, &hFdCngDec->smoothed_psd[startBand], stopFFTbin - startBand); + set_zero(&hFdCngDec->smoothed_psd[stopFFTbin], L_FRAME16k - stopFFTbin); + } + else +#endif + { +#ifdef IVAS_CODE_CNG_FIX185_PLC_FADEOUT + if (element_mode == IVAS_CPE_MDCT && power_spectrum != NULL) + { + /* use power spectrum calculated in the MDCT-domain instead of calculating new power spectrum */ + periodog = power_spectrum; + } + else + { + /* Compute the squared magnitude in each FFT bin */ + if (startBand == 0) + { + (*ptr_per) = fftBuffer[0] * fftBuffer[0]; /* DC component */ + ptr_per++; + ptr_r = fftBuffer + 2; + } + else + { + ptr_r = fftBuffer + 2 * startBand; + } + + ptr_i = ptr_r + 1; + + for (; ptr_per < periodog + stopFFTbin - startBand; ptr_per++) + { + (*ptr_per) = (*ptr_r) * (*ptr_r) + (*ptr_i) * (*ptr_i); + ptr_r += 2; + ptr_i += 2; + } + /* Nyquist frequency is discarded */ + + /* Rescale to get energy/sample: it should be 2*(1/N)*(2/N), parseval relation with 1/N,*2 for nrg computed till Nyquist only, 2/N as windowed samples correspond to half a frame*/ + v_multc(periodog, 4.f / (float)(hFdCngDec->hFdCngCom->fftlen * hFdCngDec->hFdCngCom->fftlen), periodog, stopFFTbin - startBand); + } +#else + assert(startBand != 0); + + len = sub(stopFFTbin, startBand); + + s = getScaleFactor32 (&fftBuffer[2*startBand], 2*len); + s = sub(s,1); + + ptr_per = periodog; + IF ( startBand == 0 ) + { + /* DC component */ + tmp_r = extract_h(L_shl(fftBuffer[0],s)); + + tmp = L_mult(tmp_r, tmp_r); + *ptr_per = tmp; + + ptr_per++; + ptr_r = fftBuffer + 2; + len = sub(len, 1); + } + ELSE + { + ptr_r = fftBuffer + shl(startBand, 1); + } + + ptr_i = ptr_r+1; + FOR (i=0; i < len; i++) + { + tmp_r = extract_h(L_shl(*ptr_r,s)); + tmp_i = extract_h(L_shl(*ptr_i,s)); + + tmp = L_mac(L_mult(tmp_r, tmp_r),tmp_i, tmp_i); + *ptr_per = tmp; + + ptr_r += 2; + ptr_i += 2; + ptr_per++; + } + + hFdCngDec->hFdCngCom->periodog_exp = shl(sub(fftBuffer_exp, s), 1); + + /* Rescale */ + assert((hFdCngDec->hFdCngCom->fftlen == 640) || (hFdCngDec->hFdCngCom->fftlen == 512) || (hFdCngDec->hFdCngCom->fftlen == 320)); + + fac = 20972/*0.64 Q15*/; + move16(); + if (EQ_16(hFdCngDec->hFdCngCom->fftlen, 512)) + { + fac = 16384/*0.5 Q15*/; + move16(); + } + + if (EQ_16(hFdCngDec->hFdCngCom->fftlen, 640)) + { + s = 18; + move16(); + } + if (EQ_16(hFdCngDec->hFdCngCom->fftlen, 512)) + { + s = 17; + move16(); + } + if (EQ_16(hFdCngDec->hFdCngCom->fftlen, 320)) + { + s = 16; + move16(); + } + + len = sub(stopFFTbin, startBand); + FOR (i=0; i < len; i++) + { + hFdCngDec->hFdCngCom->periodog[i] = Mpy_32_16_1(hFdCngDec->hFdCngCom->periodog[i], fac); + } + hFdCngDec->hFdCngCom->periodog_exp = add(hFdCngDec->hFdCngCom->periodog_exp, sub(2, s)); +#endif + + /* Adjust to the desired frequency resolution by averaging over spectral partitions for SID transmission */ + bandcombinepow(periodog, hFdCngDec->hFdCngCom->periodog_exp, sub(stopFFTbin, startBand), part, npart, psize_inv, hFdCngDec->msPeriodog, &hFdCngDec->msPeriodog_exp); + + + hFdCngDec->msPeriodog_exp_fft = hFdCngDec->msPeriodog_exp; + move16(); + hFdCngDec->msPeriodog_exp_cldfb = hFdCngDec->msPeriodog_exp; + move16(); + + + /* Compress MS inputs */ + compress_range(hFdCngDec->msPeriodog, hFdCngDec->msPeriodog_exp, hFdCngDec->msLogPeriodog, npart); + + /* Call the minimum statistics routine for noise estimation */ + minimum_statistics ( + npart, + nFFTpart, + psize_norm, + hFdCngDec->msLogPeriodog, + hFdCngDec->msNoiseFloor, + hFdCngDec->msLogNoiseEst, + hFdCngDec->msAlpha, + hFdCngDec->msPsd, + hFdCngDec->msPsdFirstMoment, + hFdCngDec->msPsdSecondMoment, + hFdCngDec->msMinBuf, + hFdCngDec->msBminWin, + hFdCngDec->msBminSubWin, + hFdCngDec->msCurrentMin, + hFdCngDec->msCurrentMinOut, + hFdCngDec->msCurrentMinSubWindow, + hFdCngDec->msLocalMinFlag, + hFdCngDec->msNewMinFlag, + hFdCngDec->msPeriodogBuf, + &(hFdCngDec->msPeriodogBufPtr), + hFdCngDec->hFdCngCom +#ifdef IVAS_CODE_CNG + , DEC, element_mode +#endif + ); + + /* Expand MS outputs */ + expand_range(hFdCngDec->msLogNoiseEst, hFdCngDec->msNoiseEst, &hFdCngDec->msNoiseEst_exp, npart); +} +} + +#ifdef IVAS_FLOAT_FIXED +void perform_noise_estimation_dec_fx( + const Word16 *timeDomainInput, /* i: pointer to time domain input */ + const Word16 Q, + Word32 *power_spectrum, + HANDLE_FD_CNG_DEC hFdCngDec, /* i/o: FD_CNG structure containing all buffers and variables */ + const Word16 element_mode, /* i : element mode */ + const Word16 bwidth, /* i : audio bandwidth */ + const Word16 L_frame, /* i : frame length at internal Fs */ + const Word16 last_L_frame, /* i : frame length of the last frame at internal Fs */ + const Word32 last_core_brate, /* i : previous frame core bitrate */ + const Word16 VAD /* i : VAD flag in the decoder */ +) +{ + Word16 i, p, fftBuffer_exp = 0; + Word16 npart, nFFTpart; + Word16 startBand, stopFFTbin; + + Word16 *part, *psize_inv, *psize_norm; + Word32 *fftBuffer, *periodog, *ptr_per, *ptr_r, *ptr_i; + Word32 temp, ftemp, delta, L_tmp; + Word16 e_temp, wght; + Word32 enr, enr_tot, enr_tot0; + Word16 enr_ratio, alpha; + Word32 *msPeriodog; + Word32 *msNoiseEst; + Word32 *reIter; + Word32 rescale_fac = 0; + Word64 W_tmp; + Word16 tmp_s, tmp_q, min_q = 31; + Word16 exp_flag = 0; +#ifdef IVAS_CODE_CNG + PMT( "lots of code related to IVAS needs to be done " ) +#endif + + + /* pointer initialization */ + periodog = hFdCngDec->hFdCngCom->periodog; + fftBuffer = hFdCngDec->hFdCngCom->fftBuffer; + ptr_per = periodog; + msPeriodog = hFdCngDec->msPeriodog; + msNoiseEst = hFdCngDec->msNoiseEst; + + part = hFdCngDec->part_shaping; + psize_inv = hFdCngDec->psize_inv_shaping; + psize_norm = hFdCngDec->psize_shaping_norm; + + /* variable initialization */ + startBand = hFdCngDec->hFdCngCom->startBand; + move16(); + stopFFTbin = hFdCngDec->hFdCngCom->stopFFTbin; + move16(); + + npart = hFdCngDec->npart_shaping; + move16(); + nFFTpart = hFdCngDec->nFFTpart_shaping; + move16(); + + /* Perform STFT analysis */ + IF( !( EQ_16( element_mode, IVAS_CPE_MDCT ) && power_spectrum != NULL ) ) + { + /* Perform STFT analysis */ + AnalysisSTFT_fx( timeDomainInput, Q, fftBuffer, &fftBuffer_exp, hFdCngDec->hFdCngCom ); + } + + IF( EQ_16( element_mode, IVAS_CPE_TD ) || EQ_16( element_mode, IVAS_CPE_DFT ) ) + { + SWITCH( hFdCngDec->hFdCngCom->fftlen ) + { + case 640: + rescale_fac = 20972; // 4/(640 * 640) in Q31 + BREAK; + case 512: + rescale_fac = 32768; // 4/(512 * 512) in Q31 + BREAK; + case 320: + rescale_fac = 83886; // 4/(320 * 320) in Q31 + BREAK; + default: + assert( 0 ); + } + /* Calculate periodogram (squared magnitude in each FFT bin) */ + IF( EQ_16( startBand, 0 ) ) + { + W_tmp = W_mult0_32_32( fftBuffer[0], fftBuffer[0] ); + min_q = 2; + ( *ptr_per ) = W_extract_l( W_shr( W_tmp, sub( i_mult( sub( 31, fftBuffer_exp ), 2 ), min_q ) ) ); + ptr_per++; + ptr_r = fftBuffer + 2; + } + ELSE + { + ptr_r = fftBuffer + i_mult( 2, startBand ); + } + + ptr_i = ptr_r + 1; + + FOR( ; ptr_per < periodog + stopFFTbin - startBand; ptr_per++ ) + { + W_tmp = W_add( W_mult0_32_32( ( *ptr_r ), ( *ptr_r ) ), W_mult0_32_32( ( *ptr_i ), ( *ptr_i ) ) ); + + tmp_s = W_norm( W_tmp ); + tmp_q = sub( add( i_mult( sub( 31, fftBuffer_exp ), 2 ), tmp_s ), 32 ); + IF( LT_16( tmp_q, 0 ) ) + { + W_tmp = W_shr( W_tmp, negate( tmp_q ) ); + } + IF( LT_16( tmp_q, min_q ) ) + { + reIter = ptr_per; + Word16 diff = ( LE_16( tmp_q, 0 ) ) ? min_q : sub( min_q, tmp_q ); + + WHILE( reIter > periodog ) + { + reIter--; + *reIter = L_shr( *reIter, diff ); + } + IF( GE_16( tmp_q, 0 ) ) + { + min_q = tmp_q; + } + ELSE IF( LT_16( tmp_q, 0 ) ) + { + min_q = 0; + } + } + ( *ptr_per ) = W_extract_l( W_shr( W_tmp, ( 31 - fftBuffer_exp ) * 2 - min_q ) ); // Qmin_q + + /* Rescale to get energy/sample: it should be 2*(1/N)*(2/N), parseval relation with 1/N,*2 for nrg computed till Nyquist only, 2/N as windowed samples correspond to half a frame*/ + ( *ptr_per ) = Mpy_32_32_r( ( *ptr_per ), rescale_fac ); // Q = min_q + IF( LT_16( tmp_q, 0 ) ) + { + ( *ptr_per ) = L_shl( ( *ptr_per ), negate( tmp_q ) ); + } + + ptr_r += 2; + ptr_i += 2; + } + + hFdCngDec->hFdCngCom->periodog_exp = sub( 31, min_q ); + hFdCngDec->hFdCngCom->fftBuffer_exp = fftBuffer_exp; + + tmp_s = getScaleFactor32( periodog, stopFFTbin - startBand ); + IF( GT_16( tmp_s, 7 ) ) + { + tmp_s = sub( tmp_s, 7 ); + hFdCngDec->hFdCngCom->periodog_exp = sub( hFdCngDec->hFdCngCom->periodog_exp, tmp_s ); + FOR( p = 0; p < stopFFTbin - startBand; p++ ) + { + periodog[p] = L_shl( periodog[p], tmp_s ); + } + } + + /* Combine bins of power spectrum into partitions */ + i = 0; + FOR( p = 0; p < npart; p++ ) + { + + /* calculate mean over all bins in power partition */ + temp = 0; + FOR( ; i <= part[p]; i++ ) + { + temp = L_add( temp, periodog[i] ); + } + msPeriodog[p] = Mpy_32_16_1( temp, psize_inv[p] ); // Qtemp = Qperiodog + } + + hFdCngDec->msPeriodog_exp = hFdCngDec->hFdCngCom->periodog_exp; + + /* compensate for the loss of variance - don't do when first noise update is not completed yet due to risk of msPeriodog[p] < 0 */ + IF( hFdCngDec->first_cna_noise_updated ) + { + i = 0; + FOR( p = 0; p < npart; p++ ) + { + /* calculate variance over all bins in power partition */ + temp = 0; + W_tmp = 0; + FOR( ; i <= part[p]; i++ ) + { + delta = L_sub( periodog[i], msPeriodog[p] ); + W_tmp = W_add( W_tmp, W_mult0_32_32( delta, delta ) ); + } + tmp_s = W_norm( W_tmp ); + temp = W_extract_h( W_shl( W_tmp, tmp_s ) ); // Q = 63 - 2*(31-exp) - tmp_s + + temp = Mpy_32_16_1( temp, psize_inv[p] ); // Qtemp + + /* compensate for the loss of variance */ + e_temp = sub( 63, add( i_mult( sub( 31, hFdCngDec->hFdCngCom->periodog_exp ), 2 ), tmp_s ) ); + temp = Sqrt32( temp, &e_temp ); + IF( LT_16( e_temp, 0 ) ) + { + temp = L_shr( temp, abs_s( e_temp ) ); + } + + ftemp = rand_gauss( &hFdCngDec->cna_seed ); + + L_tmp = Mpy_32_32( temp, ftemp ); + // L_tmp = L_shr( L_tmp, ( 31 - e_temp ) + 29 - 31 - ( 31 - hFdCngDec->hFdCngCom->periodog_exp ) ); + L_tmp = L_shr( L_tmp, sub( sub( hFdCngDec->hFdCngCom->periodog_exp, e_temp ), 2 ) ); + + msPeriodog[p] = L_add( msPeriodog[p], L_tmp ); + + IF( LT_32( msPeriodog[p], 0 ) ) + { + msPeriodog[p] = 0; + } + } + } + + /* calculate total energy (short-term and long-term) */ + tmp_s = getScaleFactor32( msPeriodog, npart ); + IF( LT_16( tmp_s, 5 ) ) + { + FOR( p = 0; p < npart; p++ ) + { + msPeriodog[p] = L_shr( msPeriodog[p], sub( 5, tmp_s ) ); + } + hFdCngDec->msPeriodog_exp = add( hFdCngDec->msPeriodog_exp, sub( 5, tmp_s ) ); + } + enr_tot = 1; + enr_tot0 = 1; + IF( GE_16( hFdCngDec->msNoiseEst_exp, hFdCngDec->msPeriodog_exp ) ) + { + enr_tot = L_add_sat( L_shr( sum32_fx( msPeriodog, npart ), sub( hFdCngDec->msNoiseEst_exp, hFdCngDec->msPeriodog_exp ) ), 1 ); + enr_tot0 = L_add_sat( sum32_fx( msNoiseEst, npart ), 1 ); + } + ELSE IF( LT_16( hFdCngDec->msNoiseEst_exp, hFdCngDec->msPeriodog_exp ) ) + { + enr_tot = L_add_sat( sum32_fx( msPeriodog, npart ), 1 ); + enr_tot0 = L_add_sat( L_shr( sum32_fx( msNoiseEst, npart ), sub( hFdCngDec->msPeriodog_exp, hFdCngDec->msNoiseEst_exp ) ), 1 ); + } + + IF( !( NE_16( L_frame, last_L_frame ) || LE_32( last_core_brate, SID_2k40 ) ) ) + { + IF( GT_16( hFdCngDec->hFdCngCom->periodog_exp, hFdCngDec->msPeriodog_ST_exp ) ) + { + exp_flag = 1; + } + ELSE + { + exp_flag = 0; + } + } + + /* update short-term periodogram on larger partitions */ + FOR( p = CNA_ACT_DN_LARGE_PARTITION; p < npart; p++ ) + { + IF( NE_16( L_frame, last_L_frame ) || LE_32( last_core_brate, SID_2k40 ) ) + { + /* core Fs has changed or last frame was SID/NO_DATA -> re-initialize short-term periodogram */ + hFdCngDec->msPeriodog_ST_fx[p] = msPeriodog[p]; + hFdCngDec->msPeriodog_ST_exp = hFdCngDec->hFdCngCom->periodog_exp; + } + ELSE + { + temp = msPeriodog[p]; + IF( exp_flag ) + { + hFdCngDec->msPeriodog_ST_fx[p] = L_shr( hFdCngDec->msPeriodog_ST_fx[p], sub( hFdCngDec->hFdCngCom->periodog_exp, hFdCngDec->msPeriodog_ST_exp ) ); + } + ELSE + { + temp = L_shr( temp, sub( hFdCngDec->msPeriodog_ST_exp, hFdCngDec->hFdCngCom->periodog_exp ) ); + } + + hFdCngDec->msPeriodog_ST_fx[p] = L_add( Mpy_32_16_1( hFdCngDec->msPeriodog_ST_fx[p], ST_PERIODOG_FACT_Q15 ), Mpy_32_16_1( temp, sub( MAX_16, ST_PERIODOG_FACT_Q15 ) ) ); + } + } + IF( !( NE_16( L_frame, last_L_frame ) || LE_32( last_core_brate, SID_2k40 ) ) ) + { + IF( exp_flag ) + { + hFdCngDec->msPeriodog_ST_exp = hFdCngDec->hFdCngCom->periodog_exp; + } + } + + /* core Fs has changed -> partitions have changed -> re-calculate long-term periodogram */ + /* part L_FRAME16k L_FRAME */ + /* ... */ + /* [55] 146 146 */ + /* [56] 174 160 */ + /* [57] 210 174 */ + /* [58] 254 190 */ + /* [59] 306 210 */ + /* [60] 317 230 */ + /* [61] 253 */ + + IF( EQ_16( last_L_frame, L_FRAME16k ) && EQ_16( L_frame, L_FRAME ) ) + { + msNoiseEst[61] = msNoiseEst[58]; + msNoiseEst[60] = L_min( msNoiseEst[58], msNoiseEst[57] ); + msNoiseEst[59] = msNoiseEst[57]; + msNoiseEst[58] = msNoiseEst[56]; + msNoiseEst[57] = msNoiseEst[56]; + msNoiseEst[56] = L_min( msNoiseEst[56], msNoiseEst[55] ); + } + ELSE IF( EQ_16( last_L_frame, L_FRAME ) && EQ_16( L_frame, L_FRAME16k ) ) + { + msNoiseEst[56] = L_min( msNoiseEst[56], msNoiseEst[57] ); + msNoiseEst[57] = L_min( msNoiseEst[58], msNoiseEst[59] ); + msNoiseEst[58] = L_min( msNoiseEst[60], msNoiseEst[61] ); + msNoiseEst[59] = 0; + msNoiseEst[60] = 0; + msNoiseEst[61] = 0; + + hFdCngDec->ms_cnt_bw_up = FIRST_CNA_NOISE_UPD_FRAMES; + } + + /* Smooth with IIR filter */ + IF( !hFdCngDec->first_cna_noise_updated ) + { + IF( !VAD ) + { + Word16 e = 15; + /* background noise update with moving average */ + IF( NE_16( hFdCngDec->first_cna_noise_update_cnt, 0 ) ) + { + alpha = Inv16( hFdCngDec->first_cna_noise_update_cnt + 1, &e ); + IF( LT_16( e, 0 ) ) + { + alpha = shr( alpha, negate( e ) ); // Q15 + } + FOR( p = 0; p < npart; p++ ) + { + temp = msPeriodog[p]; + temp = L_shr( temp, sub( hFdCngDec->msNoiseEst_exp, hFdCngDec->msPeriodog_exp ) ); + msNoiseEst[p] = L_add( Mpy_32_16_1( msNoiseEst[p], sub( shl_sat( 1, sub( 15, e ) ), alpha ) ), Mpy_32_16_1( temp, alpha ) ); + } + } + ELSE + { + FOR( p = 0; p < npart; p++ ) + { + msNoiseEst[p] = L_shr( msPeriodog[p], sub( hFdCngDec->msNoiseEst_exp, hFdCngDec->msPeriodog_exp ) ); + } + } + + /* check, if we reached the required number of first CNA noise update frames */ + IF( hFdCngDec->first_cna_noise_update_cnt < FIRST_CNA_NOISE_UPD_FRAMES - 1 ) + { + hFdCngDec->first_cna_noise_update_cnt++; + } + ELSE + { + hFdCngDec->first_cna_noise_updated = 1; + IF( EQ_16( hFdCngDec->hFdCngCom->msFrCnt_init_counter, 0 ) ) + { + hFdCngDec->hFdCngCom->msFrCnt_init_counter = 1; + } + } + } + ELSE + { hFdCngDec->first_cna_noise_update_cnt = 0; } } - else + ELSE { hFdCngDec->hFdCngCom->msFrCnt_init_counter = 1; - if (VAD) + IF( VAD ) { + Word16 scale; /* no updates during active frames except for significant energy drops */ - enr_ratio = enr_tot / enr_tot0; - if (enr_ratio < 0.5f) + enr_ratio = BASOP_Util_Divide3232_Scale( enr_tot, enr_tot0, &scale ); + IF( GE_16( scale, 0 ) ) + { + enr_ratio = shr( enr_ratio, scale ); + } + ELSE + { + enr_ratio = shr( enr_ratio, sub( 15, scale ) ); + } + IF( LT_16( enr_ratio, ONE_IN_Q14 ) ) { /* total energy significantly decreases during active frames -> downward update */ - wght = lin_interp(enr_ratio, 0.0f, 0.8f, 0.5f, 0.95f, 1); - for (p = 0; p < npart; p++) + wght = lin_interp_fx( enr_ratio, 0, 26214 /*0.8f in Q15*/, 16384 /*0.5f in Q15*/, 31130 /*0.95f in Q15*/, 32767 /*1 in Q15*/ ); + + FOR( p = 0; p < npart; p++ ) { - if (msPeriodog[p] < msNoiseEst[p]) + L_tmp = L_shr( msPeriodog[p], sub( sub( 31, hFdCngDec->hFdCngCom->periodog_exp ), 4 ) ); + IF( LT_32( L_tmp, msNoiseEst[p] ) ) { - msNoiseEst[p] = wght * msNoiseEst[p] + (1 - wght) * msPeriodog[p]; + msNoiseEst[p] = L_add( Mpy_32_16_1( msNoiseEst[p], wght ), Mpy_32_16_1( L_tmp, (Word16) L_sub( ONE_IN_Q15, wght ) ) ); } } } - else + ELSE { /* energy significantly decreases in one of the larger partitions during active frames -> downward update */ - for (p = CNA_ACT_DN_LARGE_PARTITION; p < npart; p++) + FOR( p = CNA_ACT_DN_LARGE_PARTITION; p < npart; p++ ) { - if (hFdCngDec->msPeriodog_ST[p] < msNoiseEst[p]) + L_tmp = L_shr( hFdCngDec->msPeriodog_ST_fx[p], sub( sub( 31, hFdCngDec->msPeriodog_ST_exp ), 4 ) ); + IF( LT_32( hFdCngDec->msPeriodog_ST_fx[p], msNoiseEst[p] ) ) { - msNoiseEst[p] = (float)(CNA_ACT_DN_FACT * msNoiseEst[p] + (1 - CNA_ACT_DN_FACT) * hFdCngDec->msPeriodog_ST[p]); + msNoiseEst[p] = L_add( Mpy_32_16_1( msNoiseEst[p], CNA_ACT_DN_FACT_Q15 ), Mpy_32_16_1( L_tmp, (Word16) L_sub( ONE_IN_Q15, CNA_ACT_DN_FACT_Q15 ) ) ); } } } } - else + ELSE { - if (bwidth >= WB && hFdCngDec->ms_last_inactive_bwidth == NB) + IF( GE_16( bwidth, WB ) && EQ_16( hFdCngDec->ms_last_inactive_bwidth, NB ) ) { /* bandwidth increased -> set counter for fast initilization */ hFdCngDec->ms_cnt_bw_up = FIRST_CNA_NOISE_UPD_FRAMES; @@ -1301,178 +2548,169 @@ void perform_noise_estimation_dec ( hFdCngDec->ms_last_inactive_bwidth = bwidth; /* update background noise during inactive frames */ ptr_per = msNoiseEst; - for (p = 0; p < npart; p++) + FOR( p = 0; p < npart; p++ ) { + Word16 i_e = 15; enr = msPeriodog[p]; - alpha = 0.95f; + temp = L_shr( enr, sub( hFdCngDec->msNoiseEst_exp, hFdCngDec->msPeriodog_exp ) ); + alpha = 31130; // 0.95f in Q15 /* bandwidth increased -> do fast re-initilization */ - if (hFdCngDec->ms_cnt_bw_up > 0 && p > 55) + IF( GT_16( hFdCngDec->ms_cnt_bw_up, 0 ) && GT_16( p, 55 ) ) { - alpha = 1.0f / (hFdCngDec->ms_cnt_bw_up + 1); + alpha = Inv16( add( hFdCngDec->ms_cnt_bw_up, 1 ), &i_e ); + IF( LT_16( i_e, 0 ) ) + { + alpha = shr( alpha, negate( i_e ) ); // Q15 + } } - else if (enr < *ptr_per && part[p] == 1) + ELSE IF( LT_32( temp, *ptr_per ) && EQ_16( part[p], 1 ) ) { /* faster downward update for single-bin partitions */ - alpha = 0.8f; + alpha = 26214; // 0.8f in Q15 } - else if (enr > 2.0f * (*ptr_per)) + ELSE IF( GT_32( temp, L_shl( ( *ptr_per ), 1 ) ) ) { /* prevent abrupt upward updates */ - enr = 2.0f * (*ptr_per); + temp = L_shl( ( *ptr_per ), 1 ); } /* IIR smoothing */ - *ptr_per *= alpha; - *ptr_per += (1 - alpha) * enr; + *ptr_per = Mpy_32_16_1( ( *ptr_per ), alpha ); + *ptr_per = L_add( ( *ptr_per ), Mpy_32_16_1( temp, sub( MAX_16, alpha ) ) ); ptr_per++; } - if (hFdCngDec->ms_cnt_bw_up > 0) + IF( GT_16( hFdCngDec->ms_cnt_bw_up, 0 ) ) { hFdCngDec->ms_cnt_bw_up--; } } } - mvr2r(msNoiseEst, hFdCngDec->msPsd, npart); + Copy32( msNoiseEst, hFdCngDec->msPsd_fx, npart ); + hFdCngDec->msPsd_exp_fft = hFdCngDec->msNoiseEst_exp; /* Expand partitions into bins of power spectrum */ - scalebands(msNoiseEst, part, nFFTpart, hFdCngDec->midband_shaping, nFFTpart, stopFFTbin - startBand, hFdCngDec->bandNoiseShape, 1); - - mvr2r(hFdCngDec->bandNoiseShape, &hFdCngDec->smoothed_psd[startBand], stopFFTbin - startBand); - set_zero(&hFdCngDec->smoothed_psd[stopFFTbin], L_FRAME16k - stopFFTbin); + scalebands( msNoiseEst, part, nFFTpart, hFdCngDec->midband_shaping, nFFTpart, sub( stopFFTbin, startBand ), hFdCngDec->bandNoiseShape, 1 ); + hFdCngDec->bandNoiseShape_exp = hFdCngDec->msNoiseEst_exp; + Copy32( hFdCngDec->bandNoiseShape, &hFdCngDec->smoothed_psd_fx[startBand], sub( stopFFTbin, startBand ) ); + set32_fx( &hFdCngDec->smoothed_psd_fx[stopFFTbin], 0, sub( L_FRAME16k, stopFFTbin ) ); } - else -#endif + ELSE { -#ifdef IVAS_CODE_CNG_FIX185_PLC_FADEOUT - if (element_mode == IVAS_CPE_MDCT && power_spectrum != NULL) + IF( EQ_16( element_mode, IVAS_CPE_MDCT ) && power_spectrum != NULL ) { /* use power spectrum calculated in the MDCT-domain instead of calculating new power spectrum */ periodog = power_spectrum; + hFdCngDec->hFdCngCom->periodog_exp = 31; } - else + ELSE { /* Compute the squared magnitude in each FFT bin */ - if (startBand == 0) + IF( EQ_16( startBand, 0 ) ) { - (*ptr_per) = fftBuffer[0] * fftBuffer[0]; /* DC component */ + W_tmp = W_mult0_32_32( fftBuffer[0], fftBuffer[0] ); /* DC component */ + min_q = 2; + ( *ptr_per ) = W_extract_l( W_shr( W_tmp, sub( i_mult( sub( 31, fftBuffer_exp ), 2 ), min_q ) ) ); ptr_per++; ptr_r = fftBuffer + 2; } - else + ELSE { - ptr_r = fftBuffer + 2 * startBand; + ptr_r = fftBuffer + i_mult( 2, startBand ); } ptr_i = ptr_r + 1; - for (; ptr_per < periodog + stopFFTbin - startBand; ptr_per++) + SWITCH( hFdCngDec->hFdCngCom->fftlen ) { - (*ptr_per) = (*ptr_r) * (*ptr_r) + (*ptr_i) * (*ptr_i); - ptr_r += 2; - ptr_i += 2; + case 640: + rescale_fac = 20972; // 4/(640 * 640) in Q31 + BREAK; + case 512: + rescale_fac = 32768; // 4/(512 * 512) in Q31 + BREAK; + case 320: + rescale_fac = 83886; // 4/(320 * 320) in Q31 + BREAK; + default: + assert( 0 ); } - /* Nyquist frequency is discarded */ - - /* Rescale to get energy/sample: it should be 2*(1/N)*(2/N), parseval relation with 1/N,*2 for nrg computed till Nyquist only, 2/N as windowed samples correspond to half a frame*/ - v_multc(periodog, 4.f / (float)(hFdCngDec->hFdCngCom->fftlen * hFdCngDec->hFdCngCom->fftlen), periodog, stopFFTbin - startBand); - } -#else - assert(startBand != 0); - - len = sub(stopFFTbin, startBand); - - s = getScaleFactor32 (&fftBuffer[2*startBand], 2*len); - s = sub(s,1); - - ptr_per = periodog; - IF ( startBand == 0 ) - { - /* DC component */ - tmp_r = extract_h(L_shl(fftBuffer[0],s)); - - tmp = L_mult(tmp_r, tmp_r); - *ptr_per = tmp; - - ptr_per++; - ptr_r = fftBuffer + 2; - len = sub(len, 1); - } - ELSE - { - ptr_r = fftBuffer + shl(startBand, 1); - } - - ptr_i = ptr_r+1; - FOR (i=0; i < len; i++) - { - tmp_r = extract_h(L_shl(*ptr_r,s)); - tmp_i = extract_h(L_shl(*ptr_i,s)); - - tmp = L_mac(L_mult(tmp_r, tmp_r),tmp_i, tmp_i); - *ptr_per = tmp; - ptr_r += 2; - ptr_i += 2; - ptr_per++; - } + FOR( ; ptr_per < periodog + stopFFTbin - startBand; ptr_per++ ) + { + W_tmp = W_add( W_mult0_32_32( ( *ptr_r ), ( *ptr_r ) ), W_mult0_32_32( ( *ptr_i ), ( *ptr_i ) ) ); - hFdCngDec->hFdCngCom->periodog_exp = shl(sub(fftBuffer_exp, s), 1); + tmp_s = W_norm( W_tmp ); + tmp_q = sub( add( i_mult( sub( 31, fftBuffer_exp ), 2 ), tmp_s ), 32 ); + IF( LT_16( tmp_q, 0 ) ) + { + W_tmp = W_shr( W_tmp, negate( tmp_q ) ); + } + IF( LT_16( tmp_q, min_q ) ) + { + reIter = ptr_per; + Word16 diff = ( tmp_q <= 0 ) ? min_q : sub( min_q, tmp_q ); + WHILE( reIter > periodog ) + { + reIter--; + *reIter = L_shr( *reIter, diff ); + } + IF( GE_16( tmp_q, 0 ) ) + { + min_q = tmp_q; + } + ELSE IF( LT_16( tmp_q, 0 ) ) + { + min_q = 0; + } + } + ( *ptr_per ) = W_extract_l( W_shr( W_tmp, sub( i_mult( sub( 31, fftBuffer_exp ), 2 ), min_q ) ) ); // Q = min_q - /* Rescale */ - assert((hFdCngDec->hFdCngCom->fftlen == 640) || (hFdCngDec->hFdCngCom->fftlen == 512) || (hFdCngDec->hFdCngCom->fftlen == 320)); + /* Rescale to get energy/sample: it should be 2*(1/N)*(2/N), parseval relation with 1/N,*2 for nrg computed till Nyquist only, 2/N as windowed samples correspond to half a frame*/ + ( *ptr_per ) = Mpy_32_32_r( ( *ptr_per ), rescale_fac ); // Q = min_q + IF( LT_16( tmp_q, 0 ) ) + { + ( *ptr_per ) = L_shl( ( *ptr_per ), negate( tmp_q ) ); + } - fac = 20972/*0.64 Q15*/; - move16(); - if (EQ_16(hFdCngDec->hFdCngCom->fftlen, 512)) - { - fac = 16384/*0.5 Q15*/; - move16(); - } + ptr_r += 2; + ptr_i += 2; + } - if (EQ_16(hFdCngDec->hFdCngCom->fftlen, 640)) - { - s = 18; - move16(); - } - if (EQ_16(hFdCngDec->hFdCngCom->fftlen, 512)) - { - s = 17; - move16(); - } - if (EQ_16(hFdCngDec->hFdCngCom->fftlen, 320)) - { - s = 16; - move16(); - } + hFdCngDec->hFdCngCom->periodog_exp = sub( 31, min_q ); + hFdCngDec->hFdCngCom->fftBuffer_exp = fftBuffer_exp; - len = sub(stopFFTbin, startBand); - FOR (i=0; i < len; i++) - { - hFdCngDec->hFdCngCom->periodog[i] = Mpy_32_16_1(hFdCngDec->hFdCngCom->periodog[i], fac); - } - hFdCngDec->hFdCngCom->periodog_exp = add(hFdCngDec->hFdCngCom->periodog_exp, sub(2, s)); -#endif + tmp_s = getScaleFactor32( periodog, L_frame ); + IF( GT_16( tmp_s, 3 ) ) + { + tmp_s = sub( tmp_s, 3 ); + hFdCngDec->hFdCngCom->periodog_exp = sub( hFdCngDec->hFdCngCom->periodog_exp, tmp_s ); + FOR( p = 0; p < stopFFTbin - startBand; p++ ) + { + periodog[p] = L_shl( periodog[p], tmp_s ); + } + } + } - /* Adjust to the desired frequency resolution by averaging over spectral partitions for SID transmission */ - bandcombinepow(periodog, hFdCngDec->hFdCngCom->periodog_exp, sub(stopFFTbin, startBand), part, npart, psize_inv, hFdCngDec->msPeriodog, &hFdCngDec->msPeriodog_exp); + /* Adjust to the desired frequency resolution by averaging over spectral partitions for SID transmission */ + bandcombinepow( periodog, hFdCngDec->hFdCngCom->periodog_exp, sub( stopFFTbin, startBand ), part, npart, psize_inv, hFdCngDec->msPeriodog, &hFdCngDec->msPeriodog_exp ); hFdCngDec->msPeriodog_exp_fft = hFdCngDec->msPeriodog_exp; - move16(); + move16(); hFdCngDec->msPeriodog_exp_cldfb = hFdCngDec->msPeriodog_exp; - move16(); + move16(); - /* Compress MS inputs */ - compress_range(hFdCngDec->msPeriodog, hFdCngDec->msPeriodog_exp, hFdCngDec->msLogPeriodog, npart); + /* Compress MS inputs */ + compress_range( hFdCngDec->msPeriodog, hFdCngDec->msPeriodog_exp, hFdCngDec->msLogPeriodog, npart ); - /* Call the minimum statistics routine for noise estimation */ - minimum_statistics ( - npart, - nFFTpart, - psize_norm, + /* Call the minimum statistics routine for noise estimation */ + minimum_statistics_fx( + npart, + nFFTpart, + psize_norm, hFdCngDec->msLogPeriodog, hFdCngDec->msNoiseFloor, hFdCngDec->msLogNoiseEst, @@ -1489,17 +2727,21 @@ void perform_noise_estimation_dec ( hFdCngDec->msLocalMinFlag, hFdCngDec->msNewMinFlag, hFdCngDec->msPeriodogBuf, - &(hFdCngDec->msPeriodogBufPtr), - hFdCngDec->hFdCngCom -#ifdef IVAS_CODE_CNG - , DEC, element_mode -#endif - ); + &( hFdCngDec->msPeriodogBufPtr ), + hFdCngDec->hFdCngCom, + DEC, element_mode ); - /* Expand MS outputs */ - expand_range(hFdCngDec->msLogNoiseEst, hFdCngDec->msNoiseEst, &hFdCngDec->msNoiseEst_exp, npart); -} + FOR( i = 0; i < hFdCngDec->npart_shaping; i++ ) + { + hFdCngDec->msPsd_fx[i] = (Word32) hFdCngDec->msPsd[i]; + } + hFdCngDec->msPsd_exp_fft = 6 + WORD16_BITS; + + /* Expand MS outputs */ + expand_range( hFdCngDec->msLogNoiseEst, hFdCngDec->msNoiseEst, &hFdCngDec->msNoiseEst_exp, npart ); + } } +#endif // IVAS_FLOAT_FIXED diff --git a/lib_dec/init_dec.c b/lib_dec/init_dec.c index 140929e2ca1ec5adac7984cba43a95801fe7720b..1affc9b9e25361402eb86665487d32c7731972c6 100644 --- a/lib_dec/init_dec.c +++ b/lib_dec/init_dec.c @@ -40,6 +40,8 @@ #include "ivas_cnst.h" #include "rom_com.h" #include "prot.h" +#include "prot_fx1.h" +#include "prot_fx2.h" #include "wmc_auto.h" /*----------------------------------------------------------------------* @@ -710,12 +712,20 @@ ivas_error init_decoder( /* Init FD-CNG */ initFdCngDec_flt( st ); +#ifdef IVAS_FLOAT_FIXED + st->cldfbSyn->scale = (Word16) ( st->cldfbSyn->scale_flt * ( 1u << norm_s( (Word16) st->cldfbSyn->scale_flt ) ) ); + initFdCngDec( st, st->cldfbSyn->scale ); +#endif // IVAS_FLOAT_FIXED } else { st->hFdCngDec = NULL; } +#ifdef IVAS_FLOAT_FIXED + st->cngTDLevel = 0; + st->cngTDLevel_e = 0; +#endif // IVAS_FLOAT_FIXED st->cngTDLevel_float = 0.f; st->lp_noise_float = -20.0f; st->force_lpd_reset = 0; diff --git a/lib_dec/ivas_stereo_mdct_stereo_dec.c b/lib_dec/ivas_stereo_mdct_stereo_dec.c index 4e8d5b0aaa60c794922c16367a6801670a9208b4..c4e2bf8a2ee5a611048d2abf0af9d8853c674863 100644 --- a/lib_dec/ivas_stereo_mdct_stereo_dec.c +++ b/lib_dec/ivas_stereo_mdct_stereo_dec.c @@ -868,6 +868,10 @@ ivas_error initMdctStereoDtxData( /* Init FD-CNG */ initFdCngDec_flt( st ); +#ifdef IVAS_FLOAT_FIXED + st->cldfbSyn->scale = (Word16) ( st->cldfbSyn->scale_flt * ( 1u << norm_s( (Word16) st->cldfbSyn->scale_flt ) ) ); + initFdCngDec( st, st->cldfbSyn->scale ); +#endif IVAS_FLOAT_FIXED } IF ( EQ_16( st->first_CNG, 0 ) ) diff --git a/lib_dec/ivas_stereo_switching_dec.c b/lib_dec/ivas_stereo_switching_dec.c index e66192a6afc722ecb1ec75e949e9cf7c9c5f1b22..60f15c5086950077b5a450124bf10e5cbbb48bb7 100644 --- a/lib_dec/ivas_stereo_switching_dec.c +++ b/lib_dec/ivas_stereo_switching_dec.c @@ -620,6 +620,10 @@ ivas_error stereo_memory_dec( return error; } initFdCngDec_flt( st ); +#ifdef IVAS_FLOAT_FIXED + st->cldfbSyn->scale = (Word16) ( st->cldfbSyn->scale_flt * ( 1u << norm_s( (Word16) st->cldfbSyn->scale_flt ) ) ); + initFdCngDec( st, st->cldfbSyn->scale ); +#endif // IVAS_FLOAT_FIXED configureFdCngDec_flt( st->hFdCngDec, st->bwidth, st->total_brate, st->L_frame, st->last_L_frame, st->element_mode ); } @@ -724,6 +728,10 @@ ivas_error stereo_memory_dec( /* Init FD-CNG */ initFdCngDec_flt( st ); +#ifdef IVAS_FLOAT_FIXED + st->cldfbSyn->scale = (Word16)(st->cldfbSyn->scale_flt * (1u << norm_s((Word16)st->cldfbSyn->scale_flt))); + initFdCngDec( st, st->cldfbSyn->scale); +#endif // IVAS_FLOAT_FIXED if ( hCPE->last_element_mode == IVAS_CPE_DFT ) { @@ -1031,6 +1039,10 @@ ivas_error stereo_memory_dec( return error; } initFdCngDec_flt( hCPE->hCoreCoder[i] ); +#ifdef IVAS_FLOAT_FIXED + hCPE->hCoreCoder[i]->cldfbSyn->scale = (Word16) ( hCPE->hCoreCoder[i]->cldfbSyn->scale_flt * ( 1u << norm_s( (Word16) hCPE->hCoreCoder[i]->cldfbSyn->scale_flt ) ) ); + initFdCngDec( hCPE->hCoreCoder[i], hCPE->hCoreCoder[i]->cldfbSyn->scale ); +#endif // IVAS_FLOAT_FIXED } } } diff --git a/lib_dec/ivas_tcx_core_dec.c b/lib_dec/ivas_tcx_core_dec.c index 309e28fc7ba9c4abf844c81871c205376664a653..03746f1896a0f3afa57d2355ad4d23399106bda5 100644 --- a/lib_dec/ivas_tcx_core_dec.c +++ b/lib_dec/ivas_tcx_core_dec.c @@ -844,6 +844,180 @@ void stereo_tcx_core_dec( if ( st->element_mode != IVAS_CPE_TD ) { +#ifdef IVAS_FLOAT_FIXED + Word16 signal_out_fx[L_FRAME48k], signal_outFB_fx[L_FRAME48k], q_buf = 1; + + if ( ivas_format == ISM_FORMAT ) + { + for ( int p = 0; p < L_FRAME48k; p++ ) + { + signal_outFB_fx[p] = (Word16) ( signal_outFB[p] * ( 1u << q_buf ) ); + } + } + else + { + for ( int p = 0; p < L_FRAME48k; p++ ) + { + signal_out_fx[p] = (Word16) ( signal_out[p] * ( 1u << q_buf ) ); + } + } + for ( int p = 0; p < st->L_frame; p++ ) + { + st->hFdCngDec->hFdCngCom->periodog[p] = (Word32) ( st->hFdCngDec->hFdCngCom->periodog_flt[p] * ( 1u << ( 31 - st->hFdCngDec->hFdCngCom->periodog_exp ) ) ); + } + for ( int p = 0; p < st->hFdCngDec->hFdCngCom->fftlen; p++ ) + { + st->hFdCngDec->hFdCngCom->fftBuffer[p] = (Word32) ( st->hFdCngDec->hFdCngCom->fftBuffer_flt[p] * ( 1u << ( 31 - st->hFdCngDec->hFdCngCom->fftBuffer_exp ) ) ); + } + st->hFdCngDec->msNoiseEst_exp = 31 - Q4; + for ( int p = 0; p < st->hFdCngDec->npart_shaping; p++ ) + { + st->hFdCngDec->msNoiseEst[p] = (Word32) ( st->hFdCngDec->msNoiseEst_float[p] * ( 1u << ( 31 - st->hFdCngDec->msNoiseEst_exp ) ) ); + st->hFdCngDec->msPeriodog[p] = (Word32) ( st->hFdCngDec->msPeriodog_float[p] * ( 1u << ( 31 - st->hFdCngDec->msPeriodog_exp ) ) ); + st->hFdCngDec->msPeriodog_ST_fx[p] = (Word32) ( st->hFdCngDec->msPeriodog_ST[p] * ( 1u << ( 31 - st->hFdCngDec->msPeriodog_ST_exp ) ) ); + } + for ( int p = 0; p < MSBUFLEN * NPART_SHAPING; p++ ) + { + if ( ( st->hFdCngDec->msMinBuf_float[p] * ( 1u << Q15 ) ) >= (float) MAX_32 ) + { + st->hFdCngDec->msMinBuf[p] = MAX_32; + } + else + { + st->hFdCngDec->msMinBuf[p] = (Word32) ( st->hFdCngDec->msMinBuf_float[p] * ( 1u << ( 31 - 6 ) ) ); + } + } + + st->hFdCngDec->hFdCngCom->cngNoiseLevelExp = 24; // Q7 + for ( int p = 0; p < FFTCLDFBLEN; p++ ) + { + st->hFdCngDec->hFdCngCom->cngNoiseLevel[p] = (Word32) ( st->hFdCngDec->hFdCngCom->cngNoiseLevel_flt[p] * ( 1u << ( 31 - st->hFdCngDec->hFdCngCom->cngNoiseLevelExp ) ) ); + } + st->hFdCngDec->hFdCngCom->sidNoiseEstExp = 31 - Q4; + st->hFdCngDec->partNoiseShape_exp = 31 - Q4; + for ( int p = 0; p < 24; p++ ) + { + st->hFdCngDec->hFdCngCom->sidNoiseEst[p] = (Word32) ( st->hFdCngDec->hFdCngCom->sidNoiseEst_flt[p] * ( 1u << ( 31 - st->hFdCngDec->hFdCngCom->sidNoiseEstExp ) ) ); + st->hFdCngDec->partNoiseShape[p] = (Word32) ( st->hFdCngDec->partNoiseShape_float[p] * ( 1u << ( 31 - st->hFdCngDec->partNoiseShape_exp ) ) ); + } +/*=================================*/ + IF( EQ_32( ivas_format, ISM_FORMAT ) ) + { + Word16 buffer[L_FRAME16k]; + lerp( signal_outFB_fx, buffer, st->L_frame, hTcxDec->L_frameTCX ); + ApplyFdCng_fx( buffer, q_buf /* Q of buffer */, NULL, NULL, NULL, NULL, st, st->bfi, 0 ); + } + ELSE + { + ApplyFdCng_fx( signal_out_fx, q_buf, NULL, NULL, NULL, NULL, st, st->bfi, 0 ); + } +/*=================================*/ + if ( ( ( st->m_frame_type == ACTIVE_FRAME ) && ( ( st->bfi == 0 && + ( signal_out == NULL || + ( *signal_out( -FLT_MAX ) && + *( signal_out + st->hFdCngDec->hFdCngCom->frameSize - 1 ) < FLT_MAX && + *( signal_out + st->hFdCngDec->hFdCngCom->frameSize - 1 ) > ( -FLT_MAX ) ) ) && + ( ( ( ( st->element_mode != IVAS_CPE_TD && st->element_mode != IVAS_CPE_DFT && st->hFdCngDec->flag_dtx_mode ) || !st->VAD || ( st->ini_frame < 100 && st->is_ism_format ) ) && + !( st->cng_type == LP_CNG && st->hFdCngDec->flag_dtx_mode ) ) || + ( st->element_mode == IVAS_CPE_TD ) ) && + ( !st->BER_detect ) ) || + ( ( st->element_mode == IVAS_CPE_TD || st->element_mode == IVAS_CPE_DFT ) && ( st->hFdCngDec->hFdCngCom->active_frame_counter > 0 ) ) || ( ( st->bfi == 1 ) && ( st->nbLostCmpt == 1 ) ) ) ) || + ( st->m_frame_type == ZERO_FRAME ) ) + { + st->hTcxDec->CngLevelBackgroundTrace_bfi = fix_to_float( st->hTcxDec->CngLevelBackgroundTrace_bfi_fx, ( 31 - st->hTcxDec->CngLevelBackgroundTrace_bfi_exp ) ); + st->cngTDLevel_float = fix16_to_float( st->cngTDLevel, ( 15 - st->cngTDLevel_e ) ); + for ( int p = 0; p < st->hFdCngDec->hFdCngCom->fftlen; p++ ) + { + st->hFdCngDec->hFdCngCom->fftBuffer_flt[p] = ( (float) st->hFdCngDec->hFdCngCom->fftBuffer[p] / ( 1u << ( 31 - st->hFdCngDec->hFdCngCom->fftBuffer_exp ) ) ); + } + for ( int p = 0; p < ( st->hFdCngDec->hFdCngCom->stopFFTbin - st->hFdCngDec->hFdCngCom->startBand ); p++ ) + { + st->hFdCngDec->hFdCngCom->cngNoiseLevel_flt[p] = ( (float) st->hFdCngDec->hFdCngCom->cngNoiseLevel[p] / ( 1u << ( 31 - st->hFdCngDec->hFdCngCom->cngNoiseLevelExp ) ) ); + } + for ( int p = 0; p < ( st->hFdCngDec->hFdCngCom->stopFFTbin - st->hFdCngDec->hFdCngCom->startBand ); p++ ) + { + st->hFdCngDec->bandNoiseShape_float[p] = ( (float) st->hFdCngDec->bandNoiseShape[p] / ( 1u << ( 31 - st->hFdCngDec->bandNoiseShape_exp ) ) ); + } + for ( int p = 0; p < st->hFdCngDec->hFdCngCom->stopFFTbin - st->hFdCngDec->hFdCngCom->startBand; p++ ) + { + st->hFdCngDec->hFdCngCom->periodog_flt[p] = ( (float) st->hFdCngDec->hFdCngCom->periodog[p] / (float) ( 1u << ( 31 - st->hFdCngDec->hFdCngCom->periodog_exp ) ) ); + } + for ( int p = 0; p < st->hFdCngDec->npart_shaping; p++ ) + { + st->hFdCngDec->msPsd_float[p] = ( (float) st->hFdCngDec->msPsd_fx[p] / ( 1u << ( 31 - st->hFdCngDec->msPsd_exp_fft ) ) ); + st->hFdCngDec->msNoiseEst_float[p] = (float) st->hFdCngDec->msNoiseEst[p] / ( 1u << ( 31 - st->hFdCngDec->msNoiseEst_exp ) ); + st->hFdCngDec->msPeriodog_float[p] = ( (float) st->hFdCngDec->msPeriodog[p] / ( 1u << ( 31 - st->hFdCngDec->msPeriodog_exp ) ) ); + st->hFdCngDec->msPeriodog_ST[p] = ( (float) st->hFdCngDec->msPeriodog_ST_fx[p] / ( 1u << ( 31 - st->hFdCngDec->msPeriodog_ST_exp ) ) ); + } + if ( st->element_mode == IVAS_CPE_TD || st->element_mode == IVAS_CPE_DFT ) + { + for ( int p = 0; p < L_FRAME16k - st->hFdCngDec->hFdCngCom->startBand; p++ ) + { + st->hFdCngDec->smoothed_psd[st->hFdCngDec->hFdCngCom->startBand + p] = ( (float) st->hFdCngDec->smoothed_psd_fx[st->hFdCngDec->hFdCngCom->startBand + p] / ( 1u << ( 31 - st->hFdCngDec->msNoiseEst_exp ) ) ); + } + } + IF( !( EQ_16( st->element_mode, IVAS_CPE_TD ) || EQ_16( st->element_mode, IVAS_CPE_DFT ) ) ) + { + for ( int p = 0; p < MSNUMSUBFR * NPART_SHAPING; p++ ) + { + if ( ( st->hFdCngDec->msMinBuf[p] == MAX_32 ) ) + { + st->hFdCngDec->msMinBuf_float[p] = FLT_MAX; + } + else + { + st->hFdCngDec->msMinBuf_float[p] = (float) st->hFdCngDec->msMinBuf[p] / ( 1u << ( 31 - 6 ) ); // CNG_S = 6 + } + } + for ( int p = 0; p < st->hFdCngDec->npart_shaping; p++ ) + { + st->hFdCngDec->msPeriodogBuf_float[p] = ( (float) st->hFdCngDec->msPeriodogBuf[p] / ( 1u << Q9 ) ); + st->hFdCngDec->msPsdFirstMoment_float[p] = ( (float) st->hFdCngDec->msPsdFirstMoment[p] / ( 1u << Q9 ) ); + st->hFdCngDec->msPsdSecondMoment_float[p] = ( (float) st->hFdCngDec->msPsdSecondMoment[p] / ( 1u << Q19 ) ); + st->hFdCngDec->msNoiseFloor_float[p] = ( (float) st->hFdCngDec->msNoiseFloor[p] / ( 1u << Q9 ) ); + st->hFdCngDec->msAlpha_float[p] = ( (float) st->hFdCngDec->msAlpha[p] / ( 1u << Q31 ) ); + st->hFdCngDec->msBminWin_float[p] = ( (float) st->hFdCngDec->msBminWin[p] / ( 1u << Q27 ) ); + st->hFdCngDec->msBminSubWin_float[p] = ( (float) st->hFdCngDec->msBminSubWin[p] / ( 1u << Q27 ) ); + if ( st->hFdCngDec->msCurrentMin[p] == MAX_32 ) + { + st->hFdCngDec->msCurrentMin_float[p] = FLT_MAX; + } + else + { + st->hFdCngDec->msCurrentMin_float[p] = ( (float) st->hFdCngDec->msCurrentMin[p] / ( 1u << ( 31 - ( 6 + 1 + 4 ) ) ) ); // exp : CNG_S + 1 + 4 + } + if ( st->hFdCngDec->msCurrentMinOut[p] == MAX_32 ) + { + st->hFdCngDec->msCurrentMinOut_float[p] = FLT_MAX; + } + else + { + st->hFdCngDec->msCurrentMinOut_float[p] = ( (float) st->hFdCngDec->msCurrentMinOut[p] / ( 1u << ( 31 - 6 ) ) ); + } + if ( st->hFdCngDec->msCurrentMinSubWindow[p] == MAX_32 ) + { + st->hFdCngDec->msCurrentMinSubWindow_float[p] = FLT_MAX; + } + else + { + st->hFdCngDec->msCurrentMinSubWindow_float[p] = ( (float) st->hFdCngDec->msCurrentMinSubWindow[p] / ( 1u << ( 31 - 6 ) ) ); + } + } + } + if ( sum_f( st->hFdCngDec->hFdCngCom->cngNoiseLevel_flt + st->hFdCngDec->hFdCngCom->startBand, st->hFdCngDec->hFdCngCom->stopFFTbin - st->hFdCngDec->hFdCngCom->startBand ) > 0.01f ) + { + if ( st->element_mode != IVAS_CPE_MDCT || st->core == ACELP_CORE ) + { + int A_cng_q = 15 - norm_s( st->hFdCngDec->hFdCngCom->A_cng[0] ); + for ( int p = 0; p < M; p++ ) + { + st->hFdCngDec->hFdCngCom->A_cng_flt[p] = ( (float) st->hFdCngDec->hFdCngCom->A_cng[p] / ( 1u << A_cng_q ) ); + st->lspold_cng_float[p] = ( (float) st->lspold_cng[p] / ( 1u << Q15 ) ); + } + } + } + } +#else if ( ivas_format == ISM_FORMAT ) { float buffer[L_FRAME16k]; @@ -854,6 +1028,7 @@ void stereo_tcx_core_dec( { ApplyFdCng_flt( signal_out, NULL, NULL, NULL, st, st->bfi, 0 ); } +#endif // IVAS_FLOAT_FIXED } /* Generate additional comfort noise to mask potential coding artefacts */ @@ -895,7 +1070,156 @@ void stereo_tcx_core_dec( if ( st->element_mode == IVAS_CPE_TD && st->idchan == 0 ) { +#ifdef IVAS_FLOAT_FIXED + Word16 signal_out_fx[L_FRAME48k], q_buf = 1; + + for ( int p = 0; p < L_FRAME48k; p++ ) + { + signal_out_fx[p] = (Word16) ( signal_out[p] * ( 1u << q_buf ) ); + } + for ( int p = 0; p < st->L_frame; p++ ) + { + st->hFdCngDec->hFdCngCom->periodog[p] = (Word32) ( st->hFdCngDec->hFdCngCom->periodog_flt[p] * ( 1u << ( 31 - st->hFdCngDec->hFdCngCom->periodog_exp ) ) ); + } + for ( int p = 0; p < st->hFdCngDec->hFdCngCom->fftlen; p++ ) + { + st->hFdCngDec->hFdCngCom->fftBuffer[p] = (Word32) ( st->hFdCngDec->hFdCngCom->fftBuffer_flt[p] * ( 1u << ( 31 - st->hFdCngDec->hFdCngCom->fftBuffer_exp ) ) ); + } + st->hFdCngDec->msNoiseEst_exp = 31 - Q4; + for ( int p = 0; p < st->hFdCngDec->npart_shaping; p++ ) + { + st->hFdCngDec->msNoiseEst[p] = (Word32) ( st->hFdCngDec->msNoiseEst_float[p] * ( 1u << ( 31 - st->hFdCngDec->msNoiseEst_exp ) ) ); + st->hFdCngDec->msPeriodog[p] = (Word32) ( st->hFdCngDec->msPeriodog_float[p] * ( 1u << ( 31 - st->hFdCngDec->msPeriodog_exp ) ) ); + st->hFdCngDec->msPeriodog_ST_fx[p] = (Word32) ( st->hFdCngDec->msPeriodog_ST[p] * ( 1u << ( 31 - st->hFdCngDec->msPeriodog_ST_exp ) ) ); + } + for ( int p = 0; p < MSBUFLEN * NPART_SHAPING; p++ ) + { + if ( ( st->hFdCngDec->msMinBuf_float[p] * ( 1u << Q15 ) ) >= (float) MAX_32 ) + { + st->hFdCngDec->msMinBuf[p] = MAX_32; + } + else + { + st->hFdCngDec->msMinBuf[p] = (Word32) ( st->hFdCngDec->msMinBuf_float[p] * ( 1u << ( 31 - 6 ) ) ); + } + } + + st->hFdCngDec->hFdCngCom->cngNoiseLevelExp = 24; // Q7 + for ( int p = 0; p < FFTCLDFBLEN; p++ ) + { + st->hFdCngDec->hFdCngCom->cngNoiseLevel[p] = (Word32) ( st->hFdCngDec->hFdCngCom->cngNoiseLevel_flt[p] * ( 1u << ( 31 - st->hFdCngDec->hFdCngCom->cngNoiseLevelExp ) ) ); + } + st->hFdCngDec->hFdCngCom->sidNoiseEstExp = 31 - Q4; + st->hFdCngDec->partNoiseShape_exp = 31 - Q4; + for ( int p = 0; p < 24; p++ ) + { + st->hFdCngDec->hFdCngCom->sidNoiseEst[p] = (Word32) ( st->hFdCngDec->hFdCngCom->sidNoiseEst_flt[p] * ( 1u << ( 31 - st->hFdCngDec->hFdCngCom->sidNoiseEstExp ) ) ); + st->hFdCngDec->partNoiseShape[p] = (Word32) ( st->hFdCngDec->partNoiseShape_float[p] * ( 1u << ( 31 - st->hFdCngDec->partNoiseShape_exp ) ) ); + } + + ApplyFdCng_fx( signal_out_fx, q_buf, NULL, NULL, NULL, NULL, st, st->bfi, 0 ); + + if ( ( ( st->m_frame_type == ACTIVE_FRAME ) && ( ( st->bfi == 0 && + ( signal_out == NULL || + ( *signal_out( -FLT_MAX ) && + *( signal_out + st->hFdCngDec->hFdCngCom->frameSize - 1 ) < FLT_MAX && + *( signal_out + st->hFdCngDec->hFdCngCom->frameSize - 1 ) > ( -FLT_MAX ) ) ) && + ( ( ( ( st->element_mode != IVAS_CPE_TD && st->element_mode != IVAS_CPE_DFT && st->hFdCngDec->flag_dtx_mode ) || !st->VAD || ( st->ini_frame < 100 && st->is_ism_format ) ) && + !( st->cng_type == LP_CNG && st->hFdCngDec->flag_dtx_mode ) ) || + ( st->element_mode == IVAS_CPE_TD ) ) && + ( !st->BER_detect ) ) || + ( ( st->element_mode == IVAS_CPE_TD || st->element_mode == IVAS_CPE_DFT ) && ( st->hFdCngDec->hFdCngCom->active_frame_counter > 0 ) ) || ( ( st->bfi == 1 ) && ( st->nbLostCmpt == 1 ) ) ) ) || + ( st->m_frame_type == ZERO_FRAME ) ) + { + st->hTcxDec->CngLevelBackgroundTrace_bfi = fix_to_float( st->hTcxDec->CngLevelBackgroundTrace_bfi_fx, ( 31 - st->hTcxDec->CngLevelBackgroundTrace_bfi_exp ) ); + st->cngTDLevel_float = fix16_to_float( st->cngTDLevel, ( 15 - st->cngTDLevel_e ) ); + for ( int p = 0; p < st->hFdCngDec->hFdCngCom->fftlen; p++ ) + { + st->hFdCngDec->hFdCngCom->fftBuffer_flt[p] = ( (float) st->hFdCngDec->hFdCngCom->fftBuffer[p] / ( 1u << ( 31 - st->hFdCngDec->hFdCngCom->fftBuffer_exp ) ) ); + } + for ( int p = 0; p < ( st->hFdCngDec->hFdCngCom->stopFFTbin - st->hFdCngDec->hFdCngCom->startBand ); p++ ) + { + st->hFdCngDec->hFdCngCom->cngNoiseLevel_flt[p] = ( (float) st->hFdCngDec->hFdCngCom->cngNoiseLevel[p] / ( 1u << ( 31 - st->hFdCngDec->hFdCngCom->cngNoiseLevelExp ) ) ); + } + for ( int p = 0; p < ( st->hFdCngDec->hFdCngCom->stopFFTbin - st->hFdCngDec->hFdCngCom->startBand ); p++ ) + { + st->hFdCngDec->bandNoiseShape_float[p] = ( (float) st->hFdCngDec->bandNoiseShape[p] / ( 1u << ( 31 - st->hFdCngDec->bandNoiseShape_exp ) ) ); + } + for ( int p = 0; p < st->hFdCngDec->hFdCngCom->stopFFTbin - st->hFdCngDec->hFdCngCom->startBand; p++ ) + { + st->hFdCngDec->hFdCngCom->periodog_flt[p] = ( (float) st->hFdCngDec->hFdCngCom->periodog[p] / (float) ( 1u << ( 31 - st->hFdCngDec->hFdCngCom->periodog_exp ) ) ); + } + for ( int p = 0; p < st->hFdCngDec->npart_shaping; p++ ) + { + st->hFdCngDec->msPsd_float[p] = ( (float) st->hFdCngDec->msPsd_fx[p] / ( 1u << ( 31 - st->hFdCngDec->msPsd_exp_fft ) ) ); + st->hFdCngDec->msNoiseEst_float[p] = (float) st->hFdCngDec->msNoiseEst[p] / ( 1u << ( 31 - st->hFdCngDec->msNoiseEst_exp ) ); + st->hFdCngDec->msPeriodog_float[p] = ( (float) st->hFdCngDec->msPeriodog[p] / ( 1u << ( 31 - st->hFdCngDec->msPeriodog_exp ) ) ); + st->hFdCngDec->msPeriodog_ST[p] = ( (float) st->hFdCngDec->msPeriodog_ST_fx[p] / ( 1u << ( 31 - st->hFdCngDec->msPeriodog_ST_exp ) ) ); + } + if ( st->element_mode == IVAS_CPE_TD || st->element_mode == IVAS_CPE_DFT ) + { + for ( int p = 0; p < L_FRAME16k - st->hFdCngDec->hFdCngCom->startBand; p++ ) + { + st->hFdCngDec->smoothed_psd[st->hFdCngDec->hFdCngCom->startBand + p] = ( (float) st->hFdCngDec->smoothed_psd_fx[st->hFdCngDec->hFdCngCom->startBand + p] / ( 1u << ( 31 - st->hFdCngDec->msNoiseEst_exp ) ) ); + } + } + IF( !( EQ_16( st->element_mode, IVAS_CPE_TD ) || EQ_16( st->element_mode, IVAS_CPE_DFT ) ) ) + { + for ( int p = 0; p < MSBUFLEN * NPART_SHAPING; p++ ) + { + if ( ( st->hFdCngDec->msMinBuf[p] == MAX_32 ) ) + { + st->hFdCngDec->msMinBuf_float[p] = FLT_MAX; + } + else + { + st->hFdCngDec->msMinBuf_float[p] = (float) st->hFdCngDec->msMinBuf[p] / ( 1u << ( 31 - 6 ) ); // CNG_S = 6 + } + } + for ( int p = 0; p < st->hFdCngDec->npart_shaping; p++ ) + { + st->hFdCngDec->msPeriodogBuf_float[p] = ( (float) st->hFdCngDec->msPeriodogBuf[p] / ( 1u << Q9 ) ); + st->hFdCngDec->msPsdFirstMoment_float[p] = ( (float) st->hFdCngDec->msPsdFirstMoment[p] / ( 1u << Q9 ) ); + st->hFdCngDec->msPsdSecondMoment_float[p] = ( (float) st->hFdCngDec->msPsdSecondMoment[p] / ( 1u << Q19 ) ); + st->hFdCngDec->msNoiseFloor_float[p] = ( (float) st->hFdCngDec->msNoiseFloor[p] / ( 1u << Q9 ) ); + st->hFdCngDec->msAlpha_float[p] = ( (float) st->hFdCngDec->msAlpha[p] / ( 1u << Q31 ) ); + st->hFdCngDec->msBminWin_float[p] = ( (float) st->hFdCngDec->msBminWin[p] / ( 1u << Q27 ) ); + st->hFdCngDec->msBminSubWin_float[p] = ( (float) st->hFdCngDec->msBminSubWin[p] / ( 1u << Q27 ) ); + if ( st->hFdCngDec->msCurrentMin[p] == MAX_32 ) + { + st->hFdCngDec->msCurrentMin_float[p] = FLT_MAX; + } + else + { + st->hFdCngDec->msCurrentMin_float[p] = ( (float) st->hFdCngDec->msCurrentMin[p] / ( 1u << ( 31 - ( 6 + 1 + 4 ) ) ) ); // exp : CNG_S + 1 + 4 + } + if ( st->hFdCngDec->msCurrentMinOut[p] == MAX_32 ) + { + st->hFdCngDec->msCurrentMinOut_float[p] = FLT_MAX; + } + else + { + st->hFdCngDec->msCurrentMinOut_float[p] = ( (float) st->hFdCngDec->msCurrentMinOut[p] / ( 1u << ( 31 - 6 ) ) ); + } + if ( st->hFdCngDec->msCurrentMinSubWindow[p] == MAX_32 ) + { + st->hFdCngDec->msCurrentMinSubWindow_float[p] = FLT_MAX; + } + else + { + st->hFdCngDec->msCurrentMinSubWindow_float[p] = ( (float) st->hFdCngDec->msCurrentMinSubWindow[p] / ( 1u << ( 31 - 6 ) ) ); + } + } + } + for ( int p = 0; p < M; p++ ) + { + st->hFdCngDec->hFdCngCom->A_cng_flt[p] = ( (float) st->hFdCngDec->hFdCngCom->A_cng[p] / ( 1u << Q14 ) ); + st->lspold_cng_float[p] = ( (float) st->lspold_cng[p] / ( 1u << Q15 ) ); + } + } +#else ApplyFdCng_flt( signal_out, NULL, NULL, NULL, st, st->bfi, 0 ); +#endif // IVAS_FLOAT_FIXED } } diff --git a/lib_dec/stat_dec.h b/lib_dec/stat_dec.h index 849050de56348807855661dd81c244b5929254d9..40db77d895be16d0e53f152c642ec7dc535017a1 100644 --- a/lib_dec/stat_dec.h +++ b/lib_dec/stat_dec.h @@ -100,6 +100,7 @@ typedef struct float msPsd_float[NPART_SHAPING]; /* Power Spectral Density estimate (i.e., smoothed periodogram) */ Word16 msPsd[NPART_SHAPING]; /* Power Spectral Density estimate (i.e., smoothed periodogram) */ + Word32 msPsd_fx[NPART_SHAPING]; /* Power Spectral Density estimate (i.e., smoothed periodogram) */ Word16 msPsd_exp_fft; @@ -168,6 +169,8 @@ typedef struct float smoothed_psd[L_FRAME16k]; /* stereo CNA - periodogram smoothed with IIR filter */ float msPeriodog_ST[NPART_SHAPING]; /* stereo CNA - short-term periodogram */ + Word32 msPeriodog_ST_fx[NPART_SHAPING]; /* stereo CNA - short-term periodogram */ + Word16 msPeriodog_ST_exp; /* exponent of stereo CNA - short-term periodogram */ int16_t ms_last_inactive_bwidth; /* stereo CNA - bandwidth from the last inactive frame */ int16_t ms_cnt_bw_up; /* stereo CNA - downward counter of frames since the last NB->WB switch */ float cna_LR_LT; /* stereo CNA - long-term L/R correlation factor calculated on stereo upmix */ @@ -199,7 +202,7 @@ typedef struct int16_t msPeriodogBufPtr; #ifdef IVAS_FLOAT_FIXED - Word32 smoothed_psd_fx[L_FRAME16k]; + Word32 smoothed_psd_fx[L_FRAME16k]; /* stereo CNA - periodogram smoothed with IIR filter */ Word16 cna_g_state_fx[STEREO_DFT_BAND_MAX]; /* stereo CNA - side gains from the last inactive frame */ Word16 cna_cm_fx[STEREO_DFT_BAND_MAX]; /* stereo CNA - coherence from the last inactive frame */ Word16 cna_act_fact_fx; /* stereo CNA - long-term signal activity factor (0-1) */