diff --git a/lib_com/options.h b/lib_com/options.h index 86adc4edcf481d1226beacbcaeaa5104e07e4ed3..8f09466764dda13d2e0ac0e3606f4e77e5f964cc 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -97,6 +97,7 @@ #define HARMONIZE_DCT /* VA: removal of duplicated DCT functions */ #define FIX_2489_HARMONIZE_FdCng_encodeSID /* FhG: harmonize FdCng_encodeSID_fx() and FdCng_encodeSID_ivas_fx() */ #define FIX_1527_CMR_BITRATE_IDX /* Fix for incorrect bitrate idx packed in rtp CMR E-byte */ +#define HARMONIZE_2502_GENERATE_COMFORT_NOISE_DEC /* FhG: harmonize generate_comfort_noise_dec_fx() and generate_comfort_noise_dec_ivas_fx() */ /* #################### End BE switches ################################## */ diff --git a/lib_com/prot_fx.h b/lib_com/prot_fx.h index cc9dde7806a12fe0c3daba544e052acfd2f2c8c3..059b73cc2876420eba621d8686fe8438569b1c76 100644 --- a/lib_com/prot_fx.h +++ b/lib_com/prot_fx.h @@ -6667,6 +6667,7 @@ void generate_comfort_noise_dec_fx( const Word16 nchan_out /* i : number of output channels */ ); +#ifndef HARMONIZE_2502_GENERATE_COMFORT_NOISE_DEC void generate_comfort_noise_dec_ivas_fx( Word32 **bufferReal, /* o : matrix to real part of i bands */ Word32 **bufferImag, /* o : matrix to imaginary part of i bands */ @@ -6676,6 +6677,7 @@ void generate_comfort_noise_dec_ivas_fx( Word16 gen_exc, const Word16 nchan_out /* i : number of output channels */ ); +#endif void generate_comfort_noise_dec_hf_fx( diff --git a/lib_dec/acelp_core_dec_fx.c b/lib_dec/acelp_core_dec_fx.c index 0152fa0989378f6ae1ef6b8aff7de62bcbd82643..9cc73595dc20e67ae3a931d512b7fb6a7ff6fcf1 100644 --- a/lib_dec/acelp_core_dec_fx.c +++ b/lib_dec/acelp_core_dec_fx.c @@ -736,7 +736,11 @@ ivas_error acelp_core_dec_fx( } ELSE { +#ifdef HARMONIZE_2502_GENERATE_COMFORT_NOISE_DEC + generate_comfort_noise_dec_fx( NULL, NULL, NULL, st, &( st->Q_exc ), 1, nchan_out ); +#else generate_comfort_noise_dec_ivas_fx( NULL, NULL, NULL, st, &( st->Q_exc ), 1, nchan_out ); +#endif } FdCng_exc( st->hFdCngDec->hFdCngCom, &st->CNG_mode, st->L_frame, st->lsp_old_fx, st->first_CNG, st->lspCNG_fx, Aq_fx, lsp_new_fx, lsf_new_fx, exc_fx, exc2_fx, bwe_exc_fx ); diff --git a/lib_dec/fd_cng_dec_fx.c b/lib_dec/fd_cng_dec_fx.c index 93bedf43a00c89350d011790ead71a93914d2b5e..cb83329764f49eec8e331897914b0a390ac6ad29 100644 --- a/lib_dec/fd_cng_dec_fx.c +++ b/lib_dec/fd_cng_dec_fx.c @@ -1119,7 +1119,11 @@ Word16 ApplyFdCng_fx( } ELSE { +#ifdef HARMONIZE_2502_GENERATE_COMFORT_NOISE_DEC + generate_comfort_noise_dec_fx( cldfbBufferReal, cldfbBufferImag, cldfbBufferScale, st, &( st->Q_exc ), 2, -1 ); +#else generate_comfort_noise_dec_ivas_fx( cldfbBufferReal, cldfbBufferImag, cldfbBufferScale, st, &( st->Q_exc ), 2, -1 ); +#endif } } @@ -2410,6 +2414,7 @@ void noisy_speech_detection_fx( return; } +#ifndef HARMONIZE_2502_GENERATE_COMFORT_NOISE_DEC void generate_comfort_noise_dec_fx( Word32 **bufferReal, /* o : matrix to real part of input bands bufferScale*/ Word32 **bufferImag, /* o : matrix to imaginary part of input bands bufferScale*/ @@ -3457,6 +3462,773 @@ void generate_comfort_noise_dec_ivas_fx( } return; } +#else /*HARMONIZE_2502_GENERATE_COMFORT_NOISE_DEC*/ +void generate_comfort_noise_dec_fx( + Word32 **bufferReal, /* o : Real part of input bands bufferScale*/ + Word32 **bufferImag, /* o : Imaginary part of input bands bufferScale*/ + Word16 *bufferScale, /* o : pointer to scalefactor for real and imaginary part of input bands */ + Decoder_State *st, /* i/o: decoder state structure */ + Word16 *Q_new, + Word16 gen_exc, /*Q0*/ + const Word16 nchan_out /* i : number of output channels Q0*/ +) +{ + Word16 i, j, s; + Word32 *ptr_r, *ptr_i; + HANDLE_FD_CNG_DEC hFdCngDec = st->hFdCngDec; + HANDLE_FD_CNG_COM hFdCngCom = hFdCngDec->hFdCngCom; + Word32 *cngNoiseLevel = hFdCngCom->cngNoiseLevel; + Word16 cngNoiseLevel_exp = hFdCngCom->cngNoiseLevelExp; + move16(); + + Word32 *ptr_level = cngNoiseLevel; + Word16 *seed = &( hFdCngCom->seed ); + Word16 scaleCldfb; + Word32 *fftBuffer = hFdCngCom->fftBuffer; /*hFdCngCom->fftBuffer_exp*/ + Word16 fftBuffer_exp = hFdCngCom->fftBuffer_exp; + Word16 *timeDomainOutput = hFdCngCom->timeDomainBuffer; + Word32 sqrtNoiseLevel; + Word16 preemph_fac; + Word16 old_syn_pe_tmp[16]; + Word16 tcx_transition; + TCX_DEC_HANDLE hTcxDec; + move16(); + + Word16 element_mode = st->element_mode; + move16(); + + + Word16 sn = 0, cnt = 0; + move16(); + move16(); + Word16 sqrtNoiseLevel_exp; + Word16 idx = 0; + move16(); + Word16 temp; + Word16 fftBuffer_exp2 = 0; + move16(); + Word16 fftBuffer_temp_exp[FFTLEN]; + Word16 *seed2 = &hFdCngCom->seed2; + Word16 c1 = 0, c2 = 0; + move16(); + move16(); + Word32 tmp1, tmp2; + + hTcxDec = st->hTcxDec; + + scaleCldfb = mult( hFdCngCom->invScalingFactor, CLDFB_SCALING ); /*CLDFBinvScalingFactor_EXP + 1*/ + + IF( NE_16( element_mode, EVS_MONO ) ) + { + temp = 0; + move16(); + c1 = Sqrt16( hFdCngCom->coherence_fx[0], &temp ); /*Q15 - temp*/ + c1 = shl( c1, temp ); /*Q15*/ + temp = 0; + move16(); + c2 = Sqrt16( sub( MAX_16, hFdCngCom->coherence_fx[0] ), &temp ); /*Q15 - temp*/ + c2 = shl( c2, temp ); /*Q15*/ + + temp = getScaleFactor32( fftBuffer, FFTLEN ); + scale_sig32( fftBuffer, FFTLEN, temp ); /*Q31 - hFdCngCom->fftBuffer_exp + temp*/ + fftBuffer_exp = sub( fftBuffer_exp, temp ); + hFdCngCom->fftBuffer_exp = fftBuffer_exp; + move16(); + set16_fx( fftBuffer_temp_exp, fftBuffer_exp, FFTLEN ); + fftBuffer_exp2 = fftBuffer_exp; + move16(); + fftBuffer_exp = 0; + move16(); + + test(); + if ( EQ_16( st->element_mode, IVAS_CPE_MDCT ) && EQ_16( st->idchan, 1 ) ) + { + seed2 = &( hFdCngCom->seed3 ); + } + } + + /* Generate Gaussian random noise in real and imaginary parts of the FFT bins + Amplitudes are adjusted to the estimated noise level cngNoiseLevel_flt in each bin */ + IF( EQ_16( element_mode, EVS_MONO ) ) + { + /* + scaling Gaussian random noise: format Q3.29 + */ + sn = 0; + move16(); + IF( s_and( cngNoiseLevel_exp, 1 ) != 0 ) + { + sn = add( sn, 1 ); + cngNoiseLevel_exp = add( cngNoiseLevel_exp, sn ); + move16(); + } + + cnt = sub( hFdCngCom->stopFFTbin, hFdCngCom->startBand ); + } + + + IF( hFdCngCom->startBand == 0 ) + { + IF( EQ_16( element_mode, EVS_MONO ) ) + { + /* DC component in FFT */ + s = 0; + move16(); + sqrtNoiseLevel = Sqrt32( L_shr( *ptr_level, sn ), &s ); /*Q31 - s*/ + + fftBuffer[0] = L_shl( Mpy_32_32( rand_gauss( seed ), sqrtNoiseLevel ), s ); /*Q31 - hFdCngCom->fftBuffer_exp*/ + move32(); + + /* Nyquist frequency is discarded */ + fftBuffer[1] = L_deposit_l( 0 ); + + ptr_level = ptr_level + 1; + ptr_r = fftBuffer + 2; /*Q31 - hFdCngCom->fftBuffer_exp*/ + cnt = sub( cnt, 1 ); + sn = add( sn, 1 ); + } + ELSE + { + test(); + test(); + test(); + IF( ( EQ_16( st->element_mode, IVAS_CPE_MDCT && NE_16( nchan_out, 1 ) ) ) || ( EQ_16( st->element_mode, IVAS_SCE ) && st->cng_ism_flag ) ) + { + rand_gauss_fx( &tmp1, seed, Q15 ); + rand_gauss_fx( &tmp2, seed2, Q15 ); + fftBuffer[0] = L_add( Mpy_32_16_1( tmp1, c1 ), Mpy_32_16_1( tmp2, c2 ) ); /*Q0*/ + move32(); + fftBuffer_temp_exp[0] = Q16 + Q15; + move16(); + } + ELSE + { + rand_gauss_fx( &fftBuffer[0], seed, Q15 ); + fftBuffer_temp_exp[0] = Q16; + move16(); + } + sqrtNoiseLevel_exp = cngNoiseLevel_exp; + move16(); + sqrtNoiseLevel = Sqrt32( *ptr_level, &sqrtNoiseLevel_exp ); /*Q31 - sqrtNoiseLevel_exp*/ + fftBuffer[0] = Mpy_32_32( fftBuffer[0], sqrtNoiseLevel ); /*Q31 - (sqrtNoiseLevel_exp + fftBuffer_temp_exp[0])*/ + move32(); + fftBuffer_temp_exp[0] = add( sqrtNoiseLevel_exp, fftBuffer_temp_exp[0] ); + move16(); + ptr_level++; + ptr_r = fftBuffer + 2; /*Q31 - (fftBuffer_temp_exp)*/ + idx = 2; + } + } + ELSE + { + IF( EQ_16( element_mode, EVS_MONO ) ) + { + Word16 startBand2 = shl( hFdCngCom->startBand, 1 ); /*Q0*/ + set32_fx( fftBuffer, 0, startBand2 ); + ptr_r = fftBuffer + startBand2; /*Q31 - hFdCngCom->fftBuffer_exp*/ + sn = add( sn, 1 ); + } + ELSE + { + fftBuffer[0] = 0; + move16(); + set32_fx( fftBuffer + 2, 0, shl( sub( hFdCngCom->startBand, 1 ), 1 ) ); + ptr_r = fftBuffer + shl( hFdCngCom->startBand, 1 ); /*Q31 - fftBuffer_exp*/ + idx = shl( hFdCngCom->startBand, 1 ); /*Q0*/ + } + } + + ptr_i = ptr_r + 1; /*Q31 - fftBuffer_exp*/ + test(); + IF( EQ_16( st->element_mode, IVAS_CPE_MDCT ) && NE_16( nchan_out, 1 ) ) + { + Word16 band_len_accu, b; + + band_len_accu = 0; + move16(); + i = 0; + move16(); + + FOR( b = 0; b < MDCT_ST_DTX_NUM_COHERENCE_BANDS; b++ ) + { + band_len_accu = add( band_len_accu, mdct_stereo_dtx_coherence_bandlengths[b] ); + + /* First band needs to be shortened. The offset from encoder-side estimation is already in, so add it back here */ + IF( EQ_16( b, 0 ) ) + { + band_len_accu = add( band_len_accu, sub( MDCT_ST_DTX_FIRST_BAND_OFFSET, hFdCngCom->startBand ) ); + } + + /* + * for last band, we need to keep going until the end of the fft section - if there is still any + * this way, the coherence value of the last band is used for eveyrthing above as well + */ + IF( EQ_16( b, sub( MDCT_ST_DTX_NUM_COHERENCE_BANDS, 1 ) ) ) + { + band_len_accu = s_max( band_len_accu, sub( hFdCngCom->stopFFTbin, hFdCngCom->startBand ) ); + } + + /* mixing values for coherence is now frequency-dependent */ + temp = 0; + move16(); + c1 = Sqrt16( hFdCngCom->coherence_fx[b], &temp ); /*Q15 - temp*/ + c1 = shl( c1, temp ); /*Q15*/ + temp = 0; + move16(); + c2 = Sqrt16( sub( MAX_16, hFdCngCom->coherence_fx[b] ), &temp ); /*Q15 - temp*/ + c2 = shl( c2, temp ); /*Q15*/ + + FOR( ; i < band_len_accu; i++ ) + { + sqrtNoiseLevel_exp = sub( cngNoiseLevel_exp, 1 ); + sqrtNoiseLevel = Sqrt32( *ptr_level, &sqrtNoiseLevel_exp ); /*Q31 - sqrtNoiseLevel_exp*/ + + /* Real part in FFT bins */ + rand_gauss_fx( &tmp1, seed, Q15 ); + rand_gauss_fx( &tmp2, seed2, Q15 ); + *ptr_r = L_add( Mpy_32_16_1( tmp1, c1 ), Mpy_32_16_1( tmp2, c2 ) ); /*Q15*/ + move32(); + fftBuffer_temp_exp[idx] = Q16; + move16(); + ( *ptr_r ) = Mpy_32_32( ( *ptr_r ), sqrtNoiseLevel ); /*Q15 - sqrtNoiseLevel_exp*/ + move32(); + fftBuffer_temp_exp[idx] = add( fftBuffer_temp_exp[idx], sqrtNoiseLevel_exp ); + move16(); + idx = add( idx, 1 ); + + /* Imaginary part in FFT bins */ + rand_gauss_fx( &tmp1, seed, Q15 ); /*Q15*/ + rand_gauss_fx( &tmp2, seed2, Q15 ); /*Q15*/ + *ptr_i = L_add( Mpy_32_16_1( tmp1, c1 ), Mpy_32_16_1( tmp2, c2 ) ); /*Q15*/ + move32(); + fftBuffer_temp_exp[idx] = Q16; + move16(); + ( *ptr_i ) = Mpy_32_32( ( *ptr_i ), sqrtNoiseLevel ); /*Q15 - sqrtNoiseLevel_exp*/ + move32(); + fftBuffer_temp_exp[idx] = add( fftBuffer_temp_exp[idx], sqrtNoiseLevel_exp ); + move16(); + idx = add( idx, 1 ); + + /* advance all pointers together here */ + ptr_r += 2; + ptr_i += 2; + ptr_level++; + } + } + } + ELSE IF( EQ_16( element_mode, EVS_MONO ) ) + { + FOR( i = 0; i < cnt; i++ ) + { + s = 0; + move16(); + sqrtNoiseLevel = Sqrt32( L_shr( *ptr_level, sn ), &s ); /*Q31 - s*/ + + /* Real part in FFT bins */ + *ptr_r = L_shl( Mpy_32_32( rand_gauss( seed ), sqrtNoiseLevel ), s ); + move32(); + ptr_r += 2; + + /* Imaginary part in FFT bins */ + *ptr_i = L_shl( Mpy_32_32( rand_gauss( seed ), sqrtNoiseLevel ), s ); + move32(); + + ptr_i += 2; + ptr_level = ptr_level + 1; + } + } + ELSE + { + FOR( ; ptr_level < cngNoiseLevel + sub( hFdCngCom->stopFFTbin, hFdCngCom->startBand ); ptr_level++ ) + { + /* Real part in FFT bins */ + test(); + IF( EQ_16( st->element_mode, IVAS_SCE ) && st->cng_ism_flag ) + { + rand_gauss_fx( &tmp1, seed, Q15 ); /*Q15*/ + rand_gauss_fx( &tmp2, seed2, Q15 ); /*Q15*/ + *ptr_r = L_add( Mpy_32_16_1( tmp1, c1 ), Mpy_32_16_1( tmp2, c2 ) ); /*Q15*/ + move32(); + fftBuffer_temp_exp[idx] = Q16; + move16(); + } + ELSE + { + rand_gauss_fx( ptr_r, seed, Q15 ); /*Q15*/ + fftBuffer_temp_exp[idx] = Q16; + move16(); + } + + sqrtNoiseLevel_exp = sub( cngNoiseLevel_exp, 1 ); + sqrtNoiseLevel = Sqrt32( *ptr_level, &sqrtNoiseLevel_exp ); /*Q31 - sqrtNoiseLevel_exp*/ + ( *ptr_r ) = Mpy_32_32( ( *ptr_r ), sqrtNoiseLevel ); /*Q15 - sqrtNoiseLevel_exp*/ + move32(); + fftBuffer_temp_exp[idx] = add( fftBuffer_temp_exp[idx], sqrtNoiseLevel_exp ); + move16(); + idx = add( idx, 1 ); + ptr_r += 2; + + /* Imaginary part in FFT bins */ + test(); + IF( EQ_16( st->element_mode, IVAS_SCE ) && st->cng_ism_flag ) + { + rand_gauss_fx( &tmp1, seed, Q15 ); /*Q15*/ + rand_gauss_fx( &tmp2, seed2, Q15 ); /*Q15*/ + *ptr_i = L_add( Mpy_32_16_1( tmp1, c1 ), Mpy_32_16_1( tmp2, c2 ) ); /*Q15*/ + move32(); + fftBuffer_temp_exp[idx] = Q16; + move16(); + } + ELSE + { + rand_gauss_fx( ptr_i, seed, Q15 ); /*Q15*/ + fftBuffer_temp_exp[idx] = Q16; + move16(); + } + sqrtNoiseLevel_exp = sub( cngNoiseLevel_exp, 1 ); + sqrtNoiseLevel = Sqrt32( *ptr_level, &sqrtNoiseLevel_exp ); /*Q31 - sqrtNoiseLevel_exp*/ + ( *ptr_i ) = Mpy_32_32( ( *ptr_i ), sqrtNoiseLevel ); /*Q15 - sqrtNoiseLevel_exp*/ + move32(); + fftBuffer_temp_exp[idx] = add( fftBuffer_temp_exp[idx], sqrtNoiseLevel_exp ); + move16(); + idx = add( idx, 1 ); + ptr_i += 2; + } + } + + /* Remaining FFT bins are set to zero */ + set32_fx( fftBuffer + shl( hFdCngCom->stopFFTbin, 1 ), 0, sub( hFdCngCom->fftlen, shl( hFdCngCom->stopFFTbin, 1 ) ) ); + fftBuffer_exp = add( shr( cngNoiseLevel_exp, 1 ), CNG_RAND_GAUSS_SHIFT ); + + IF( NE_16( element_mode, EVS_MONO ) ) + { + set16_fx( fftBuffer_temp_exp + shl( hFdCngCom->stopFFTbin, 1 ), 0, sub( hFdCngCom->fftlen, shl( hFdCngCom->stopFFTbin, 1 ) ) ); + + /* Nyquist frequency is discarded */ + fftBuffer[1] = 0; + move32(); + + fftBuffer_exp = MAX_16; + move16(); + FOR( i = 0; i < hFdCngCom->fftlen; i++ ) + { + IF( fftBuffer[i] != 0 ) + { + fftBuffer_exp = s_min( fftBuffer_exp, add( sub( 31, fftBuffer_temp_exp[i] ), norm_l( fftBuffer[i] ) ) ); + } + } + if ( EQ_16( fftBuffer_exp, MAX_16 ) ) + { + fftBuffer_exp = 0; + move16(); + } + fftBuffer_exp = sub( 31, fftBuffer_exp ); + FOR( i = 0; i < hFdCngCom->fftlen; i++ ) + { + fftBuffer[i] = L_shr( fftBuffer[i], sub( fftBuffer_exp, fftBuffer_temp_exp[i] ) ); /*Q31 - fftBuffer_temp_exp[i]*/ + move32(); + } + } + + /* If previous frame is active, reset the overlap-add buffer */ + tcx_transition = 0; + move16(); + IF( EQ_16( hFdCngCom->frame_type_previous, ACTIVE_FRAME ) ) + { + set16_fx( hFdCngCom->olapBufferSynth, 0, hFdCngCom->fftlen ); + test(); + test(); + if ( ( st->last_core_bfi > ACELP_CORE && EQ_16( st->codec_mode, MODE2 ) ) || EQ_16( st->codec_mode, MODE1 ) ) + { + tcx_transition = 1; + move16(); + } + } + + /* Perform STFT synthesis */ + IF( EQ_16( element_mode, EVS_MONO ) ) + { + SynthesisSTFT( fftBuffer, fftBuffer_exp, timeDomainOutput, hFdCngCom->olapBufferSynth, hFdCngCom->olapWinSyn, + tcx_transition, hFdCngCom, gen_exc, Q_new, st->element_mode, nchan_out ); + } + ELSE + { + SynthesisSTFT_ivas_fx( fftBuffer, fftBuffer_exp, timeDomainOutput, hFdCngCom->olapBufferSynth, hFdCngCom->olapWinSyn, + tcx_transition, hFdCngCom, gen_exc, Q_new, st->element_mode, nchan_out ); /* fftBuffer in hfDCngCom->fftBuffer_exp */ + /* fftBuffer now in different Qs [0 to fftlen - 1] = hfDCngCom->fftBuffer_exp and [fftlen to FFTLEN(640)] = fftBuffer_exp2, bringing it in common exponent */ + Word16 shift1 = L_norm_arr( fftBuffer, hFdCngCom->fftlen ); + Word16 shift2 = L_norm_arr( fftBuffer + hFdCngCom->fftlen, sub( FFTLEN, hFdCngCom->fftlen ) ); + Word16 shift = s_max( sub( hFdCngCom->fftBuffer_exp, shift1 ), sub( fftBuffer_exp2, shift2 ) ); + + scale_sig32( fftBuffer, hFdCngCom->fftlen, sub( hFdCngCom->fftBuffer_exp, shift ) ); + scale_sig32( fftBuffer + hFdCngCom->fftlen, sub( FFTLEN, hFdCngCom->fftlen ), sub( fftBuffer_exp2, shift ) ); + hFdCngCom->fftBuffer_exp = shift; + move16(); + } + { + Word32 Lener, att; + Word16 exp; + /* update CNG excitation energy for LP_CNG */ + + /* calculate the residual signal energy */ + /*enr = dotp( hFdCngCom->exc_cng, hFdCngCom->exc_cng, hFdCngCom->frameSize ) / hFdCngCom->frameSize;*/ + Lener = Dot_productSq16HQ( 1, hFdCngCom->exc_cng, st->L_frame, &exp ); /*Q31 - exp*/ + exp = add( sub( shl( sub( 15, *Q_new ), 1 ), 8 ), exp ); /*8 = log2(256)*/ + + /* convert log2 of residual signal energy */ + /*(float)log10( enr + 0.1f ) / (float)log10( 2.0f );*/ + Lener = BASOP_Util_Log2( Lener ); /*Q25*/ + Lener = L_add( Lener, L_shl( L_deposit_l( exp ), WORD32_BITS - 1 - LD_DATA_SCALE ) ); /*Q25*/ + if ( EQ_16( st->L_frame, L_FRAME16k ) ) + { + Lener = L_sub( Lener, 10802114l /*0.3219280949f Q25*/ ); /*log2(320) = 8.3219280949f*/ + } + /* decrease the energy in case of WB input */ + IF( st->bwidth != NB ) + { + IF( EQ_16( st->bwidth, WB ) ) + { + IF( st->CNG_mode >= 0 ) + { + /* Bitrate adapted attenuation */ + att = L_shl( L_deposit_l( ENR_ATT_fx[st->CNG_mode] ), 17 ); /*Q25*/ + } + ELSE + { + /* Use least attenuation for higher bitrates */ + att = L_shl( L_deposit_l( ENR_ATT_fx[4] ), 17 ); /*Q25*/ + } + } + ELSE + { + att = 384 << 17; /*1.5 Q8<<17=Q25*/ + move16(); + } + Lener = L_sub( Lener, att ); + } + /*st->lp_ener = 0.8f * stcod->lp_ener + 0.2f * pow( 2.0f, enr );*/ + Lener = BASOP_util_Pow2( Lener, 6, &exp ); /*Q31 - exp*/ + Lener = Mult_32_16( Lener, 6554 /*0.2f Q15*/ ); /*Q31 - exp*/ + exp = sub( 25, exp ); + Lener = L_shr( Lener, exp ); /*Q6*/ + st->lp_ener_fx = L_add( Mult_32_16( st->lp_ener_fx, 26214 /*0.8f Q15*/ ), Lener ); /*Q6*/ + move32(); + } + + /* Generate Gaussian random noise in real and imaginary parts of the CLDFB bands + Amplitudes are adjusted to the estimated noise level cngNoiseLevel_flt in each band */ + + /* + * Note: for the stereo DTX noise mixing, c1 and c2 at this point are set to the value calculated for the last band + * as all the coherence bands are in the FFT region, we do not need the special handling here + */ + + test(); + IF( bufferReal != NULL && ( LT_16( hFdCngCom->numCoreBands, hFdCngCom->regularStopBand ) ) ) + { + IF( EQ_16( element_mode, EVS_MONO ) ) + { + + Word16 sc = add( shr( add( cngNoiseLevel_exp, CLDFBinvScalingFactor_EXP + 1 - 1 ), 1 ), CNG_RAND_GAUSS_SHIFT ); + sn = sub( sn, 1 ); + assert( ( ( cngNoiseLevel_exp + CLDFBinvScalingFactor_EXP + 1 - 1 ) & 1 ) == 0 ); + + FOR( j = hFdCngCom->numCoreBands; j < hFdCngCom->regularStopBand; j++ ) + { + /* scaleCLDFB: CLDFBinvScalingFactor_EXP + 1 */ + s = 0; + move16(); + sqrtNoiseLevel = Sqrt32( L_shr( Mpy_32_16_1( *ptr_level, scaleCldfb ), sn ), &s ); /*Q31 - s*/ + + FOR( i = 0; i < hFdCngCom->numSlots; i++ ) + { + /* Real part in CLDFB band */ + bufferReal[i][j] = L_shl( Mpy_32_32( rand_gauss( seed ), sqrtNoiseLevel ), s ); /*bufferScale*/ + move32(); + /*fprintf(pFile,"%13.10f\n",WORD322FL_SCALE(bufferReal[i][j],sc));*/ + + /* Imaginary part in CLDFB band */ + bufferImag[i][j] = L_shl( Mpy_32_32( rand_gauss( seed ), sqrtNoiseLevel ), s ); /*bufferScale*/ + move32(); + /*fprintf(pFile,"%13.10f\n",WORD322FL_SCALE(bufferImag[i][j],sc));*/ + } + ptr_level = ptr_level + 1; + } + *bufferScale = sub( sc, 15 ); + move16(); + } + ELSE /*EQ_16( element_mode, EVS_MONO )*/ + { + Word16 bufferReal_exp[CLDFB_NO_COL_MAX]; + Word16 bufferImag_exp[CLDFB_NO_COL_MAX]; + *bufferScale = 0; + move16(); + FOR( j = hFdCngCom->numCoreBands; j < hFdCngCom->regularStopBand; j++ ) + { + sqrtNoiseLevel_exp = add( CLDFBinvScalingFactor_EXP, sub( cngNoiseLevel_exp, 1 ) ); + sqrtNoiseLevel = Sqrt32( Mpy_32_16_1( *ptr_level, scaleCldfb ), &sqrtNoiseLevel_exp ); /*Q31 - sqrtNoiseLevel_exp*/ + + FOR( i = 0; i < hFdCngCom->numSlots; i++ ) + { + /* Real part in CLDFB band */ + test(); + IF( ( EQ_16( st->element_mode, IVAS_CPE_MDCT ) && NE_16( nchan_out, 1 ) ) || ( EQ_16( st->element_mode, IVAS_SCE ) && st->cng_ism_flag ) ) + { + rand_gauss_fx( &tmp1, seed, Q15 ); /*Q15*/ + rand_gauss_fx( &tmp2, seed2, Q15 ); /*Q15*/ + bufferReal[i][j] = L_add( Mpy_32_16_1( tmp1, c1 ), Mpy_32_16_1( tmp2, c2 ) ); /*Q15*/ + move32(); + bufferReal_exp[j] = Q16; + move16(); + } + ELSE + { + rand_gauss_fx( &bufferReal[i][j], seed, Q15 ); /*Q15*/ + move32(); + bufferReal_exp[j] = Q16; + move16(); + } + + bufferReal[i][j] = Mpy_32_32( bufferReal[i][j], sqrtNoiseLevel ); /*Q31 - ( bufferReal_exp[j] + sqrtNoiseLevel_exp )*/ + move32(); + bufferReal_exp[j] = add( bufferReal_exp[j], sqrtNoiseLevel_exp ); + move16(); + + /* Imaginary part in CLDFB band */ + test(); + IF( ( EQ_16( st->element_mode, IVAS_CPE_MDCT ) && NE_16( nchan_out, 1 ) ) || ( EQ_16( st->element_mode, IVAS_SCE ) && st->cng_ism_flag ) ) + { + rand_gauss_fx( &tmp1, seed, Q15 ); /*Q15*/ + rand_gauss_fx( &tmp2, seed2, Q15 ); /*Q15*/ + bufferImag[i][j] = L_add( Mpy_32_16_1( tmp1, c1 ), Mpy_32_16_1( tmp2, c2 ) ); /*Q15*/ + move32(); + bufferImag_exp[j] = Q16; + move16(); + } + ELSE + { + rand_gauss_fx( &bufferImag[i][j], seed, Q15 ); /*Q15*/ + bufferImag_exp[j] = Q16; + move16(); + } + bufferImag[i][j] = Mpy_32_32( bufferImag[i][j], sqrtNoiseLevel ); /*Q31 - ( bufferReal_exp[j] + sqrtNoiseLevel_exp )*/ + bufferImag_exp[j] = add( bufferImag_exp[j], sqrtNoiseLevel_exp ); + move16(); + + move32(); + } + ptr_level++; + } + + FOR( j = hFdCngCom->numCoreBands; j < hFdCngCom->regularStopBand; j++ ) + { + *bufferScale = s_max( *bufferScale, bufferReal_exp[j] ); + move16(); + *bufferScale = s_max( *bufferScale, bufferImag_exp[j] ); + move16(); + } + + FOR( j = hFdCngCom->numCoreBands; j < hFdCngCom->regularStopBand; j++ ) + { + FOR( i = 0; i < hFdCngCom->numSlots; i++ ) + { + bufferImag[i][j] = L_shr( bufferImag[i][j], sub( *bufferScale, bufferImag_exp[j] ) ); /*bufferImag_exp*/ + move32(); + bufferReal[i][j] = L_shr( bufferReal[i][j], sub( *bufferScale, bufferReal_exp[j] ) ); /*bufferReal_exp*/ + move32(); + } + } + } /*EQ_16( element_mode, EVS_MONO )*/ + } + + test(); + IF( EQ_16( hFdCngCom->frame_type_previous, ACTIVE_FRAME ) && EQ_16( st->codec_mode, MODE2 ) ) + { + Word32 old_exc_ener, gain, noise32; + Word16 seed_loc, lpcorder, old_syn, tmp, gain16, N, N2, N4, N8; + Word16 old_exc_ener_exp, gain_exp; + Word16 normFacE, normShiftE, normShiftEM1; + Word16 normFacG, normShiftG, normShiftGM1; + Word16 noiseExp, *old_exc, *old_Aq, *old_syn_pe; + Word16 noise[640], normShiftP2; + Word16 Q_exc, Q_syn; + + + assert( hFdCngCom->frameSize <= 640 ); + + seed_loc = hFdCngCom->seed; /*Q0*/ + move16(); + N = hFdCngCom->frameSize; /*Q0*/ + move16(); + N2 = shr( hFdCngCom->frameSize, 1 ); + + IF( st->last_core_bfi > ACELP_CORE ) + { + Word16 left_overlap_mode; + left_overlap_mode = st->hTcxCfg->tcx_last_overlap_mode; + move16(); + if ( EQ_16( left_overlap_mode, ALDO_WINDOW ) ) + { + left_overlap_mode = FULL_OVERLAP; + move16(); + } + tcx_windowing_synthesis_current_frame( timeDomainOutput, st->hTcxCfg->tcx_mdct_window, st->hTcxCfg->tcx_mdct_window_half, st->hTcxCfg->tcx_mdct_window_minimum, st->hTcxCfg->tcx_mdct_window_length, st->hTcxCfg->tcx_mdct_window_half_length, + st->hTcxCfg->tcx_mdct_window_min_length, 0, left_overlap_mode, NULL, NULL, NULL, NULL, NULL, shr( N, 1 ), shr( sub( abs_s( st->hTcxCfg->tcx_offset ), st->hTcxCfg->tcx_offset ), 1 ), 1, 0, 0 ); + + IF( st->hTcxCfg->last_aldo != 0 ) + { + FOR( i = 0; i < hFdCngCom->frameSize - NS2SA( st->sr_core, N_ZERO_MDCT_NS ); i++ ) + { + timeDomainOutput[i] = add( timeDomainOutput[i], shr_r( st->hHQ_core->old_out_LB_fx[i + NS2SA_FX2( st->sr_core, N_ZERO_MDCT_NS )], st->hHQ_core->Q_old_wtda_LB ) ); /*st->q_old_outLB_fx*/ + move16(); + } + } + ELSE + { + tcx_windowing_synthesis_past_frame( hTcxDec->syn_Overl, st->hTcxCfg->tcx_mdct_window, st->hTcxCfg->tcx_mdct_window_half, st->hTcxCfg->tcx_mdct_window_minimum, + st->hTcxCfg->tcx_mdct_window_length, st->hTcxCfg->tcx_mdct_window_half_length, st->hTcxCfg->tcx_mdct_window_min_length, st->hTcxCfg->tcx_last_overlap_mode ); + + FOR( i = 0; i < st->hTcxCfg->tcx_mdct_window_length; i++ ) + { + timeDomainOutput[i] = add( timeDomainOutput[i], shl( hTcxDec->syn_Overl[i], TCX_IMDCT_HEADROOM ) ); /*st->q_old_outLB_fx*/ + move16(); + } + } + } + ELSE + { + + /* + - the scaling of the LPCs (e.g. old_Aq) is always Q12 (encoder or decoder) + + - the scaling of the deemphasized signals (e.g. old_syn) is always Q0 (encoder or decoder) + + - the scaling of the excitation signals in the encoder (e.g. old_exc) is Q_new + - the scaling of the preemphasized signals in the encoder (e.g. old_syn_pe) is Q_new-1 + + - the scaling of the excitation signals in the decoder (e.g. old_exc) is Q_exc (or stdec->Q_exc) + - the scaling of the preemphasized signals in the decoder (e.g. old_syn_pe) is Q_syn (or stdec->Q_syn) + */ + + lpcorder = M; + move16(); + old_Aq = st->old_Aq_12_8_fx; /*Q12*/ + old_exc = st->old_exc_fx + sub( L_EXC_MEM_DEC, N2 ); /*Q_exc*/ + old_syn_pe = st->mem_syn2_fx; /*Q_syn*/ + old_syn = st->syn[lpcorder]; /*Q_syn*/ + move16(); + preemph_fac = st->preemph_fac; /*Q15*/ + move16(); + Q_exc = st->Q_exc; + move16(); + Q_syn = st->Q_syn; + move16(); + + /* shift to be in the range of values supported by getNormReciprocalWord16() */ + N8 = shr( N2, CNG_NORM_RECIPROCAL_RANGE_SHIFT ); + + assert( N2 == ( N8 << CNG_NORM_RECIPROCAL_RANGE_SHIFT ) ); + + normFacE = getNormReciprocalWord16( N8 ); + normShiftE = BASOP_util_norm_s_bands2shift( N8 ); + normShiftEM1 = sub( normShiftE, 1 ); + normShiftP2 = add( normShiftE, CNG_NORM_RECIPROCAL_RANGE_SHIFT ); + + old_exc_ener = L_shr( L_mult( old_exc[0], old_exc[0] ), normShiftP2 ); /*2*(Q_exc)+1+normShiftP2*/ + FOR( i = 1; i < N2; i++ ) + { + old_exc_ener = L_add( old_exc_ener, L_shr( L_mult( old_exc[i], old_exc[i] ), normShiftP2 ) ); /*2*(Q_exc)+1+normShiftP2*/ + } + old_exc_ener = L_shl( Mpy_32_16_1( old_exc_ener, shl( normFacE, normShiftEM1 ) ), 1 ); /*Q31*/ + + old_exc_ener_exp = 0; + move16(); + old_exc_ener = Sqrt32( old_exc_ener, &old_exc_ener_exp ); /*Q31 - old_exc_ener_exp*/ + old_exc_ener_exp = add( old_exc_ener_exp, ( sub( 15, Q_exc ) ) ); + + /* shift to be in the range of values supported by getNormReciprocalWord16() */ + N4 = shr( N, CNG_NORM_RECIPROCAL_RANGE_SHIFT ); + + assert( N == ( N4 << CNG_NORM_RECIPROCAL_RANGE_SHIFT ) ); + + normFacG = getNormReciprocalWord16( N4 ); + normShiftG = BASOP_util_norm_s_bands2shift( N4 ); + normShiftGM1 = sub( normShiftG, 1 ); + normShiftP2 = add( normShiftG, CNG_NORM_RECIPROCAL_RANGE_SHIFT ); + + gain = L_deposit_l( 0 ); + FOR( i = 0; i < N; i++ ) + { + noise32 = rand_gauss( &seed_loc ); + noise[i] = extract_h( noise32 ); + move16(); + gain = L_add( gain, L_shr( L_mult( noise[i], noise[i] ), normShiftP2 ) ); + } + gain = L_shl( Mpy_32_16_1( gain, shl( normFacG, normShiftGM1 ) ), 1 ); /*Q31 - gain_exp*/ + + gain_exp = 2 * CNG_RAND_GAUSS_SHIFT; + move16(); + gain = ISqrt32( gain, &gain_exp ); /*Q31 - gain_exp*/ + + gain = Mpy_32_32( old_exc_ener, gain ); /*Q31 - old_exc_ener_exp - gain_exp*/ + gain16 = extract_h( gain ); /*Q15 - old_exc_ener_exp - gain_exp*/ + + gain_exp = add( old_exc_ener_exp, gain_exp ); + noiseExp = add( CNG_RAND_GAUSS_SHIFT, gain_exp ); + + s = sub( 15 - NOISE_HEADROOM, noiseExp ); + FOR( i = 0; i < N; i++ ) + { + noise[i] = shr_sat( mult( noise[i], gain16 ), s ); /*Q15 - noiseExp*/ + move16(); + } + + assert( lpcorder <= 16 ); + + s = sub( 15 - NOISE_HEADROOM, ( sub( 15, Q_syn ) ) ); + FOR( i = 0; i < lpcorder; i++ ) + { + old_syn_pe_tmp[i] = shr_sat( old_syn_pe[i], s ); /*Q0*/ + move16(); + } + + E_UTIL_synthesis( + 0, /* i : scaling to apply for a[0] Q0 */ + old_Aq, /* i : LP filter coefficients Q12 */ + noise, /* i : input signal Qx */ + noise, /* o : output signal Qx-s */ + N, /* i : size of filtering Q0 */ + old_syn_pe_tmp, /* i/o: memory associated with this filtering. Q0 */ + 0, /* i : 0=no update, 1=update of memory. Q0 */ + lpcorder /* i : order of LP filter Q0 */ + ); + + tmp = old_syn; + move16(); + + E_UTIL_deemph2( + NOISE_HEADROOM, + noise, /* I/O: signal Qx */ + preemph_fac, /* I: deemphasis factor Qx */ + N, /* I: vector size */ + &tmp /* I/O: memory (signal[-1]) Qx */ + ); + + FOR( i = 0; i < N4; i++ ) + { + tmp = mult( noise[i], hFdCngCom->olapWinSyn[i].v.re ); /*Q15 - noiseExp*/ + timeDomainOutput[i] = add( timeDomainOutput[i], tmp ); + move16(); + tmp = mult( noise[( i + N4 )], hFdCngCom->olapWinSyn[( ( N4 - 1 ) - i )].v.im ); /*Q15 - noiseExp*/ + timeDomainOutput[( i + N4 )] = add( timeDomainOutput[( i + N4 )], tmp ); + move16(); + move16(); + } + } + } + return; +} +#endif /*HARMONIZE_2502_GENERATE_COMFORT_NOISE_DEC*/ void generate_comfort_noise_dec_hf_fx(