diff --git a/lib_com/options.h b/lib_com/options.h index 598299d16be2487400788cbb8f308feabd723e21..4d98455de566de273e49ce21f66b98f7879a7408 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -88,6 +88,7 @@ #define FIX_2480_HARM_TONALMDCT /* FhG: basop issue 2480: Harmonize TonalMDCTConceal_Detect_fx() and TonalMDCTConceal_Detect_ivas_fx() */ #define FIX_2479_HARM_PITCH_GAIN /* FhG: basop issue 2479: Harmonize tcx_ltp_pitch_search_*(), tcx_ltp_find_gain_*fx() */ #define HARMONIZE_2481_EXTEND_SHRINK /* FhG: basop issue 2481: Harmonize extend_frm_*fx() and shrink_frm_*fx() */ +#define FIX_2489_HARMONIZE_FdCng_encodeSID /* FhG: harmonize FdCng_encodeSID_fx() and FdCng_encodeSID_ivas_fx() */ /* #################### End BE switches ################################## */ diff --git a/lib_enc/acelp_core_enc_fx.c b/lib_enc/acelp_core_enc_fx.c index 27e6e2528428947499a9a59af1198db60f058d65..621b0d80dda2eb58521601d51e74c21e22c055e5 100644 --- a/lib_enc/acelp_core_enc_fx.c +++ b/lib_enc/acelp_core_enc_fx.c @@ -358,7 +358,11 @@ ivas_error acelp_core_enc_fx( test(); IF( EQ_32( st->core_brate, SID_2k40 ) && NE_16( st->element_mode, IVAS_CPE_MDCT ) ) { +#ifdef FIX_2489_HARMONIZE_FdCng_encodeSID + FdCng_encodeSID_fx( st ); +#else FdCng_encodeSID_fx( st->hFdCngEnc, st, st->preemph_fac ); +#endif st->hDtxEnc->last_CNG_L_frame = st->L_frame; move16(); } @@ -393,7 +397,11 @@ ivas_error acelp_core_enc_fx( test(); IF( EQ_32( st->core_brate, SID_2k40 ) && NE_16( st->element_mode, IVAS_CPE_MDCT ) ) { +#ifdef FIX_2489_HARMONIZE_FdCng_encodeSID + FdCng_encodeSID_fx( st ); +#else FdCng_encodeSID_ivas_fx( st ); +#endif st->hDtxEnc->last_CNG_L_frame = st->L_frame; move16(); } diff --git a/lib_enc/enc_acelp_tcx_main_fx.c b/lib_enc/enc_acelp_tcx_main_fx.c index 855ef896ec5c4854ba6a1a4a5319679084610d76..1aff6eb3de6785be55cfc0c5dbde49961c1ecdae 100644 --- a/lib_enc/enc_acelp_tcx_main_fx.c +++ b/lib_enc/enc_acelp_tcx_main_fx.c @@ -88,7 +88,11 @@ void enc_acelp_tcx_main_fx( /* Run SID Coder */ IF( st->core_brate == SID_2k40 ) { +#ifdef FIX_2489_HARMONIZE_FdCng_encodeSID + FdCng_encodeSID_fx( st ); +#else FdCng_encodeSID_fx( st->hFdCngEnc, st, st->preemph_fac ); +#endif } /* Generate Comfort Noise */ diff --git a/lib_enc/fd_cng_enc_fx.c b/lib_enc/fd_cng_enc_fx.c index 378e0f9c643563e5d7d1466023ecaa3ef0530954..a5f1802321334a4892ed3d326deacebbb3fe4808 100644 --- a/lib_enc/fd_cng_enc_fx.c +++ b/lib_enc/fd_cng_enc_fx.c @@ -923,7 +923,7 @@ static void msvq_encoder( return; } - +#ifndef FIX_2489_HARMONIZE_FdCng_encodeSID /* FdCng_encodeSID_fx @@ -943,6 +943,7 @@ static void msvq_encoder( Returns: void */ + void FdCng_encodeSID_fx( HANDLE_FD_CNG_ENC stenc, /* i/o: pointer to FD_CNG structure containing all buffers and variables */ Encoder_State *corest, @@ -1145,6 +1146,7 @@ void FdCng_encodeSID_fx( return; } +#endif /*FIX_2489_HARMONIZE_FdCng_encodeSID*/ void generate_comfort_noise_enc_fx( @@ -1938,6 +1940,370 @@ void perform_noise_estimation_enc_ivas_fx( * * Generate a bitstream out of the partition levels *-------------------------------------------------------------------*/ +#ifdef FIX_2489_HARMONIZE_FdCng_encodeSID +#define FIX_2489_HARMONIZE_FdCng_encodeSID_IVASHP /* FhG: activate FdCng_encodeSID higher precision in IVAS case - development */ +void FdCng_encodeSID_fx( + Encoder_State *corest /* i/o: encoder state structure */ +) +{ + Word16 i, index, N; + Word16 E_Exp; + Word16 indices[32]; + Word32 temp, gain_fx, e_fx; + Word32 v_fx[32]; + Word32 *E_fx; + Word16 element_mode = corest->element_mode; + move16(); + Word16 preemph_fac = corest->preemph_fac; // Q15 + move16(); + + BSTR_ENC_HANDLE hBstr = corest->hBstr; + HANDLE_FD_CNG_ENC hFdCngEnc = corest->hFdCngEnc; + HANDLE_FD_CNG_COM hFdCngCom = hFdCngEnc->hFdCngCom; + + + /* Init */ + + E_fx = hFdCngEnc->msNoiseEst_fx; + N = hFdCngEnc->npartDec; + move16(); + E_Exp = hFdCngEnc->msNoiseEst_fx_exp; + move16(); + + /* Convert to LOG */ + e_fx = L_deposit_l( 0 ); + +#ifdef FIX_2489_HARMONIZE_FdCng_encodeSID_IVASHP + IF( element_mode == 0 ) +#endif + { + Word16 normShiftN = BASOP_util_norm_s_bands2shift( N ); + Word16 normFacN = getNormReciprocalWord16( N ); + Word32 E_ExpLd64 = L_shl( E_Exp, WORD32_BITS - 1 - LD_DATA_SCALE ); + /* e: Q14.23 format, v_fx: Q9.23 format */ + temp = Mpy_32_32_r( L_shl( 1, sub( 31, E_Exp ) ), 214748 ); /* 1e-4f, Q31-E_Exp */ + FOR( i = 0; i < N; i++ ) + { + /* assert( E_fx[i] != 0 ); */ + /* constant: 0.75257498916 = 10.0 * log10(2.0)/log10(10.0) * 0.25 */ + v_fx[i] = Mpy_32_16_1( L_add( BASOP_Util_Log2( L_add( E_fx[i], L_max( 1, temp ) ) ), E_ExpLd64 ), 24660 /*0.75257498916 Q15*/ ); + move32(); + e_fx = L_add( e_fx, L_shr( v_fx[i], normShiftN ) ); + } + e_fx = L_shl( Mpy_32_16_1( e_fx, shl( normFacN, sub( normShiftN, 1 ) ) ), 1 ); + } +#ifdef FIX_2489_HARMONIZE_FdCng_encodeSID_IVASHP + ELSE + { + set_zero_fx( v_fx, FDCNG_VQ_MAX_LEN ); + FOR( i = 0; i < N; i++ ) + { + IF( E_fx[i] == 0 ) + { + /* 10 * log(1e-4) = 10 * (-4) = -40 */ + v_fx[i] = -41943040; // -40.0 in Q20 + move32(); + } + ELSE + { + v_fx[i] = Mpy_32_32( 671088640 /*10 in Q26*/, BASOP_Util_Log10( E_fx[i], E_Exp ) ); // Q20 = 26+25-31 + move32(); + } + e_fx = L_add( e_fx, L_shr( v_fx[i], 1 ) ); // Q19, add one bit headroom + } + } +#endif + + /* Normalize MSVQ input */ + + gain_fx = 0; + move32(); +#ifdef FIX_2489_HARMONIZE_FdCng_encodeSID_IVASHP + IF( element_mode == 0 ) +#endif + { + Word16 normFacGain = getNormReciprocalWord16( N_GAIN_MAX - N_GAIN_MIN ); + Word16 normShiftGain = BASOP_util_norm_s_bands2shift( N_GAIN_MAX - N_GAIN_MIN ); + /* gain: Q9.23 format */ + FOR( i = N_GAIN_MIN; i < N_GAIN_MAX; i++ ) + { + gain_fx = L_add( gain_fx, L_shr( v_fx[i], normShiftGain ) ); + } + gain_fx = L_shl( Mpy_32_16_1( gain_fx, shl( normFacGain, sub( normShiftGain, 1 ) ) ), 1 ); + } +#ifdef FIX_2489_HARMONIZE_FdCng_encodeSID_IVASHP + ELSE + { + FOR( i = N_GAIN_MIN; i < N_GAIN_MAX; i++ ) + { + gain_fx = L_add( gain_fx, v_fx[i] ); // Q20 + } + + /*gain /= (float) ( N_GAIN_MAX - N_GAIN_MIN );*/ + gain_fx = Mpy_32_32( gain_fx, 165191050 /* 1/13 in Q31*/ ); // Q20 + + FOR( i = 0; i < N; i++ ) + { + v_fx[i] = L_sub( v_fx[i], gain_fx ); // Q20 + move32(); + } + } +#endif + + /*MSVQ*/ + IF( element_mode == 0 ) + { + Word16 v16[32]; + FOR( i = 0; i < N; i++ ) + { + v16[i] = extract_h( L_sub( v_fx[i], gain_fx ) ); + } + + /* MSVQ encoder */ + msvq_encoder( cdk_37bits, v16, levels_37bits, FD_CNG_maxC_37bits, FD_CNG_stages_37bits, N, FD_CNG_maxN_37bits, indices ); + + /* MSVQ decoder */ + msvq_decoder( cdk_37bits, FD_CNG_stages_37bits, N, FD_CNG_maxN_37bits, indices, v16 ); + + FOR( i = 0; i < N; i++ ) + { + v_fx[i] = L_deposit_h( v16[i] ); + } + } + ELSE + { + /* MSVQ encoder */ + Word16 w_fx[32]; + set_val_Word16( w_fx, ONE_IN_Q8, N ); + Word32 dct_target_fx[FDCNG_VQ_DCT_MAXTRUNC]; + Word32 tot_sig_ext_fx[FDCNG_VQ_MAX_LEN]; + + + /* DCT domain compressed/truncated indices used for first stage */ + /* quantization with stage1 stored in DCT24 domain, stages 2 through 6 directly dearched + in FDCNG band domain + */ + Word32 tmpRAM_fx[FDCNG_VQ_MAX_LEN][FDCNG_VQ_DCT_MAXTRUNC]; + Word32 *invTrfMatrix_fx = (Word32 *) tmpRAM_fx; /* dynamically filled */ + + IF( EQ_16( N, FDCNG_VQ_MAX_LEN_WB ) ) + { + /* truncated DCT21 analysis */ + create_IDCT_N_Matrix_fx( invTrfMatrix_fx, N, FDCNG_VQ_DCT_MAXTRUNC, sizeof( tmpRAM_fx ) / ( sizeof( Word32 ) ) ); // Q31 + + dctT2_N_apply_matrix_fx( v_fx /*Q20*/, dct_target_fx, FDCNG_VQ_DCT_MAXTRUNC, N, invTrfMatrix_fx, FDCNG_VQ_DCT_MAXTRUNC, DCT_T2_21_XX ); // Q20 + + /* truncated IDCT21 extension to 24 bands */ + extend_dctN_input_fx( v_fx, dct_target_fx, N, tot_sig_ext_fx, FDCNG_VQ_MAX_LEN, invTrfMatrix_fx, FDCNG_VQ_DCT_MAXTRUNC, IDCT_T2_XX_21 ); // Q20 + + Copy32( tot_sig_ext_fx, v_fx, FDCNG_VQ_MAX_LEN ); /* write extended result as input to VQ stage #1 */ // Q20 + } + + create_IDCT_N_Matrix_fx( invTrfMatrix_fx, FDCNG_VQ_MAX_LEN, FDCNG_VQ_DCT_MAXTRUNC, sizeof( tmpRAM_fx ) / ( sizeof( Word32 ) ) ); // Q31 + + msvq_enc_ivas_fx( ivas_cdk_37bits_fx, Q7, NULL, NULL, v_fx, 11 /*Q20*/, levels_37bits, FD_CNG_maxC_37bits, FD_CNG_stages_37bits, w_fx, N, FD_CNG_maxN_37bits, 1, invTrfMatrix_fx, indices ); + + msvq_dec_fx( ivas_cdk_37bits_fx, NULL, NULL, FD_CNG_stages_37bits, N, FD_CNG_maxN_37bits, indices, 1, invTrfMatrix_fx, v_fx, NULL, 7 ); + } + + /* Compute gain */ +#ifdef FIX_2489_HARMONIZE_FdCng_encodeSID_IVASHP + IF( element_mode == 0 ) +#endif + { + Word16 normShiftN = BASOP_util_norm_s_bands2shift( N ); + Word16 normFacN = getNormReciprocalWord16( N ); + /*Q9.23 format */ + gain_fx = 0; + FOR( i = 0; i < N; i++ ) + { + gain_fx = L_add( gain_fx, L_shr( v_fx[i], normShiftN ) ); + } + gain_fx = L_sub( e_fx, L_shl( Mpy_32_16_1( gain_fx, shl( normFacN, sub( normShiftN, 1 ) ) ), 1 ) ); + } +#ifdef FIX_2489_HARMONIZE_FdCng_encodeSID_IVASHP + ELSE + { + Word16 v_e = sub( 31, sub( 20, find_guarded_bits_fx( N ) ) ); + gain_fx = 0; + move32(); + FOR( i = 0; i < N; i++ ) + { + gain_fx = L_add( gain_fx, v_fx[i] ); // Q = 31 - v_e + } + e_fx = L_shl( e_fx, sub( 12, v_e ) ); // Q = 31 - v_e + gain_fx = Mpy_32_16_1( L_sub( e_fx, gain_fx ), div_s( 1, N ) ); // Q = 31 - v_e + gain_fx = L_shl( gain_fx, sub( v_e, 8 ) ); // Q23 + } +#endif + + /* Apply bitrate-dependant scale */ + apply_scale( &gain_fx, hFdCngCom->CngBandwidth, hFdCngCom->CngBitrate, + ( element_mode == 0 ) ? ( scaleTableMono ) : ( scaleTableStereo ), + ( element_mode == 0 ) ? ( SIZE_SCALE_TABLE_MONO ) : ( SIZE_SCALE_TABLE_STEREO ) ); + + + /* Quantize gain */ +#ifdef FIX_2489_HARMONIZE_FdCng_encodeSID_IVASHP + IF( element_mode == 0 ) +#endif + { + /*Q14.23 format */ + gain_fx = L_add( gain_fx, L_shr( gain_fx, 1 ) ); + gain_fx = L_add( gain_fx, 507510784l /*60.5 Q23*/ ); + index = extract_l( L_shr( gain_fx, WORD32_BITS - 1 - 8 ) ); + } +#ifdef FIX_2489_HARMONIZE_FdCng_encodeSID_IVASHP + ELSE + { + temp = Madd_32_32( L_shl( GAIN_Q_OFFSET_IVAS_FX_Q0, 22 ), gain_fx, 1610612736 /*1.5 in Q30*/ ); // Q22 + index = extract_l( L_shr( L_add( temp, ONE_IN_Q21 ), 22 ) ); // Q0 + } +#endif + + if ( index < 0 ) + { + index = 0; + move16(); + } + + if ( GT_16( index, 127 ) ) + { + index = 127; + move16(); + } + + /* Apply gain and undo log */ +#ifdef FIX_2489_HARMONIZE_FdCng_encodeSID_IVASHP + IF( element_mode == 0 ) +#endif + { + Word32 E_ExpLd64; + /* gain Q14.23 format */ + gain_fx = L_shl( L_deposit_l( index ), WORD32_BITS - 1 - 8 ); + gain_fx = L_sub( gain_fx, 503316480l /*60.0 Q23*/ ); + gain_fx = Mpy_32_16_1( gain_fx, 21845 /*2.0f/3.0f Q15*/ ); + Word16 sidNoiseEst_Exp = 0; + + /* sidNoiseEst: format Q6.26, 0.66438561897 = log10(10)/log10(2.0) / 10.0 * 2.0 */ + + /* calculate worst case for scaling */ + { + Word32 maxVal = 0x80000000 /*-1.0 Q31*/; + move32(); + FOR( i = 0; i < N; i++ ) + { + maxVal = L_max( maxVal, v_fx[i] ); + } + + maxVal = L_add( maxVal, gain_fx ); + maxVal = L_shl( Mpy_32_16_1( maxVal, 21771 /*0.66438561897 Q15*/ ), 1 ); + move16(); + WHILE( maxVal >= 0 ) + { + maxVal = L_sub( maxVal, 33554432l /*0.015625 Q31*/ ); + sidNoiseEst_Exp = add( sidNoiseEst_Exp, 1 ); + } + hFdCngCom->sidNoiseEstExp = sidNoiseEst_Exp; + move16(); + E_ExpLd64 = L_shl( sidNoiseEst_Exp, WORD32_BITS - 1 - LD_DATA_SCALE ); + } + + FOR( i = 0; i < N; i++ ) + { + temp = L_add( v_fx[i], gain_fx ); + temp = L_shl( Mpy_32_16_1( temp, 21771 /*0.66438561897 Q15*/ ), 1 ); + temp = L_sub( temp, E_ExpLd64 ); + assert( temp < 0 ); + hFdCngCom->sidNoiseEst[i] = BASOP_Util_InvLog2( temp ); + move32(); + } + } +#ifdef FIX_2489_HARMONIZE_FdCng_encodeSID_IVASHP + ELSE + { + Word16 v_e = sub( 31, sub( 20, find_guarded_bits_fx( N ) ) ); + gain_fx = L_shl( L_mult0( sub( index, GAIN_Q_OFFSET_IVAS_FX_Q0 ), 21845 /*1.5 in Q15*/ ), sub( 16, v_e ) ); // Q = 31-v_e + + Word16 exp[32]; + FOR( i = 0; i < N; i++ ) + { + temp = Mpy_32_32( L_add( v_fx[i], gain_fx ), 214748365 /* 0.1 in Q31*/ ); // Q = 31-v_e + hFdCngCom->sidNoiseEst[i] = BASOP_Util_fPow( 10, 31, temp, v_e, &exp[i] ); + move32(); + } + + maximum_s( exp, N, &hFdCngCom->sidNoiseEstExp ); + + FOR( i = 0; i < N; i++ ) + { + hFdCngCom->sidNoiseEst[i] = L_shr( hFdCngCom->sidNoiseEst[i], sub( hFdCngCom->sidNoiseEstExp, exp[i] ) ); // exp = hFdCngCom->sidNoiseEstExp + move32(); + } + } +#endif + + /* NB last band energy compensation */ + IF( EQ_16( hFdCngCom->CngBandwidth, NB ) ) + { + hFdCngCom->sidNoiseEst[N - 1] = Mpy_32_16_1( hFdCngCom->sidNoiseEst[N - 1], NB_LAST_BAND_SCALE ); // exp(hFdCngCom->sidNoiseEstExp) + move32(); + } + + test(); + IF( EQ_16( hFdCngCom->CngBandwidth, SWB ) && LE_32( hFdCngCom->CngBitrate, ACELP_13k20 ) ) + { + hFdCngCom->sidNoiseEst[N - 1] = Mpy_32_16_1( hFdCngCom->sidNoiseEst[N - 1], SWB_13k2_LAST_BAND_SCALE ); // exp(hFdCngCom->sidNoiseEstExp) + move32(); + } + + + /* Write bitstream */ + IF( EQ_16( corest->codec_mode, MODE2 ) ) + { + FOR( i = 0; i < FD_CNG_stages_37bits; i++ ) + { + push_next_indice( hBstr, indices[i], bits_37bits[i] ); + } + push_next_indice( hBstr, index, 7 ); + } + ELSE + { + Word16 is_frame_len_16k = 0; + move16(); + Word16 IDX = IND_ACELP_16KHZ; + move16(); + push_indice( hBstr, IND_SID_TYPE, 1, 1 ); + if ( element_mode > 0 ) + { + IDX = IND_BWIDTH; + move16(); + } + push_indice( hBstr, IDX, corest->bwidth, 2 ); + if ( EQ_16( corest->L_frame, L_FRAME16k ) ) + { + is_frame_len_16k = 1; + move16(); + } + push_indice( hBstr, IND_ACELP_16KHZ, is_frame_len_16k, 1 ); + FOR( i = 0; i < FD_CNG_stages_37bits; i++ ) + { + push_indice( hBstr, IND_LSF, indices[i], bits_37bits[i] ); + } + + push_indice( hBstr, IND_ENERGY, index, 7 ); + } + + /* Interpolate the bin/band-wise levels from the partition levels */ + scalebands( hFdCngCom->sidNoiseEst, hFdCngEnc->partDec, hFdCngEnc->npartDec, hFdCngEnc->midbandDec, hFdCngEnc->nFFTpartDec, sub( hFdCngEnc->stopBandDec, hFdCngEnc->startBandDec ), hFdCngCom->cngNoiseLevel, 1 ); + hFdCngCom->cngNoiseLevelExp = hFdCngCom->sidNoiseEstExp; + move16(); + + lpc_from_spectrum( hFdCngCom, hFdCngEnc->startBandDec, hFdCngEnc->stopFFTbinDec, preemph_fac ); + + return; +} +#else /*FIX_2489_HARMONIZE_FdCng_encodeSID*/ void FdCng_encodeSID_ivas_fx( Encoder_State *st /* i/o: encoder state structure */ ) @@ -2165,6 +2531,7 @@ void FdCng_encodeSID_ivas_fx( return; } +#endif /*FIX_2489_HARMONIZE_FdCng_encodeSID*/ /*-------------------------------------------------------------------* diff --git a/lib_enc/prot_fx_enc.h b/lib_enc/prot_fx_enc.h index ffcfbff2081ebcb5af61dcc7aa0c5ce0f66524df..f273715125d24326c571ede425da029ce634fbc5 100644 --- a/lib_enc/prot_fx_enc.h +++ b/lib_enc/prot_fx_enc.h @@ -1473,11 +1473,16 @@ void CNG_enc_fx( Word16 *sid_bw ); /* Generate a bitstream out of the partition levels */ +#ifdef FIX_2489_HARMONIZE_FdCng_encodeSID +void FdCng_encodeSID_fx( + Encoder_State *corest ); +#else void FdCng_encodeSID_fx( HANDLE_FD_CNG_ENC st, /* i/o: FD_CNG structure containing all buffers and variables */ Encoder_State *corest, Word16 preemph_fac /* i : preemphase factor */ ); +#endif /* Generate the comfort noise based on the target noise level */ void generate_comfort_noise_enc_fx( @@ -1631,9 +1636,11 @@ Word16 AdjustFirstSID_fx( Encoder_State *stcod /* i : pointer to Coder_State_Plus structure */ ); +#ifndef FIX_2489_HARMONIZE_FdCng_encodeSID void FdCng_encodeSID_ivas_fx( Encoder_State *st /* i/o: encoder state structure */ ); +#endif void resetFdCngEnc_fx( Encoder_State *st );