From b081a0d8247c3e1e2c8799b73e36d3e75ad15f43 Mon Sep 17 00:00:00 2001 From: Sandesh Venkatesh Date: Mon, 28 Oct 2024 10:45:54 +0530 Subject: [PATCH] Fix for 3GPP issue 949 --- lib_com/lpc_tools_fx.c | 214 ++++++++++++++++++++++++++++++++++++++++ lib_com/preemph_fx.c | 55 +++++++++++ lib_com/prot_fx.h | 4 + lib_dec/er_dec_tcx_fx.c | 7 +- 4 files changed, 277 insertions(+), 3 deletions(-) diff --git a/lib_com/lpc_tools_fx.c b/lib_com/lpc_tools_fx.c index 26a9549d6..bfb5d8ed1 100644 --- a/lib_com/lpc_tools_fx.c +++ b/lib_com/lpc_tools_fx.c @@ -579,6 +579,220 @@ Word16 E_LPC_lev_dur_stab( const Word16 Rh[], const Word16 Rl[], Word16 A[], Wor return ( flag ); } +Word16 E_LPC_lev_dur_ivas_fx( const Word16 Rh[], const Word16 Rl[], Word16 A[], Word32 epsP[], const Word16 order, Word16 *mem ) +{ + return ( E_LPC_lev_dur_stab_ivas_fx( Rh, Rl, A, epsP, order, mem, 32750 ) ); /* 0.99945 in Q15 */ +} + +Word16 E_LPC_lev_dur_stab_ivas_fx( const Word16 Rh[], const Word16 Rl[], Word16 A[], Word32 epsP[], const Word16 order, Word16 *mem, Word16 k_max ) +{ + Word16 i, j, k; + Word16 hi, lo; + Word16 Kh, Kl; /* reflection coefficient; hi and lo */ + Word16 alp_h, alp_l, alp_exp; /* Prediction gain; hi lo and exponent */ + Word32 t0, t1, t2; /* temporary variables */ + Word16 flag; + Word16 Ah[TCXLTP_LTP_ORDER + 1], Al[TCXLTP_LTP_ORDER + 1]; /* LPC coef. in double prec. */ +#ifdef BASOP_NOGLOB_DECLARE_LOCAL + Flag Overflow = 0; +#endif + + + BASOP_SATURATE_WARNING_OFF_EVS + if ( epsP != NULL ) + { + epsP[0] = L_Comp( Rh[0], Rl[0] ); + move32(); + } + + flag = 0; + move16(); + + /* K = A[1] = -R[1] / R[0] */ + t1 = L_Comp( Rh[1], Rl[1] ); /* R[1] in Q31 */ + t2 = L_abs( t1 ); /* abs R[1] */ + t0 = L_deposit_l( 0 ); + IF( Rh[0] != 0 ) + { + t0 = Div_32_opt( t2, Rh[0], Rl[0] ); /* R[1]/R[0] in Q31 */ + /* Cause a difference in MODE1 due to different implementation of div32*/ + } + if ( t1 > 0 ) + { + t0 = L_negate( t0 ); /* -R[1]/R[0] */ + } + Kl = L_Extract_lc( t0, &Kh ); /* K in DPF */ + t0 = L_shr( t0, 4 ); /* A[1] in Q27 */ + L_Extract( t0, &Ah[1], &Al[1] ); /* A[1] in DPF */ + + /* Alpha = R[0] * (1-K**2) */ + t0 = Sqr_32( Kh, Kl ); /* K*K in Q31 */ + t0 = L_abs( t0 ); /* Some case <0 !! */ + t0 = L_sub( (Word32) 0x7fffffffL, t0 ); /* 1 - K*K in Q31 */ + lo = L_Extract_lc( t0, &hi ); /* DPF format */ + t0 = Mpy_32( Rh[0], Rl[0], hi, lo ); /* Alpha in Q31 */ + if ( epsP != NULL ) + { + epsP[1] = t0; + move32(); + } + + /* Normalize Alpha */ + alp_exp = norm_l( t0 ); + t0 = L_shl( t0, alp_exp ); + alp_l = L_Extract_lc( t0, &alp_h ); + /* DPF format */ + + /*--------------------------------------* + * ITERATIONS I=2 to m + *--------------------------------------*/ + + FOR( i = 2; i <= order; i++ ) + { + /* t0 = SUM(R[j]*A[i-j], j=1, i-1) + R[i] */ + t0 = L_deposit_l( 0 ); + FOR( j = 1; j < i; j++ ) + { + t0 = Mac_32( t0, Rh[j], Rl[j], Ah[i - j], Al[i - j] ); + } + +#ifdef BASOP_NOGLOB + t0 = L_shl_o( t0, 4, &Overflow ); /* result in Q27 -> convert to Q31 */ +#else /* BASOP_NOGLOB */ + t0 = L_shl( t0, 4 ); /* result in Q27 -> convert to Q31 */ +#endif /* BASOP_NOGLOB */ + /* No overflow possible */ + + /* Compose and add R[i] in Q3 */ +#ifdef BASOP_NOGLOB + t0 = L_mac_o( t0, Rl[i], 1, &Overflow ); + t0 = L_msu_o( t0, Rh[i], -32768, &Overflow ); +#else /* BASOP_NOGLOB */ + t0 = L_mac( t0, Rl[i], 1 ); + t0 = L_msu( t0, Rh[i], -32768 ); +#endif /* BASOP_NOGLOB */ + + /* K = -t0 / Alpha */ + t1 = L_abs( t0 ); + t2 = L_deposit_l( 0 ); + IF( alp_h != 0 ) + { + t2 = Div_32_opt( t1, alp_h, alp_l ); /* abs(t0)/Alpha */ + /* Cause a difference in MODE1 due to different implementation of div32*/ + } + + if ( t0 > 0 ) + { + t2 = L_negate( t2 ); /* K =-t0/Alpha */ + } +#ifdef BASOP_NOGLOB + t2 = L_shl_o( t2, alp_exp, &Overflow ); /* denormalize; compare to Alpha */ +#else /* BASOP_NOGLOB */ + t2 = L_shl( t2, alp_exp ); /* denormalize; compare to Alpha */ +#endif /* BASOP_NOGLOB */ + test(); + if ( ( mem != NULL ) && ( ( GT_16( abs_s( extract_h( t2 ) ), k_max ) ) ) ) + { + flag = 1; + move16(); /* Test for unstable filter. If unstable keep old A(z) */ + } + test(); + if ( ( mem != NULL ) && ( ( LT_32( L_abs( t2 ), 5 ) ) ) ) + { + flag = 1; + move16(); /*R matrix not reliable (R saturated for many coeff), keep old A(z) */ + } + Kl = L_Extract_lc( t2, &Kh ); /* K in DPF */ + + /*------------------------------------------* + * Compute new LPC coeff. -> An[i] + * An[j]= A[j] + K*A[i-j] , j=1 to i-1 + * An[i]= K + *------------------------------------------*/ + + k = mult_r( i, 16384 ); + FOR( j = 1; j < k; j++ ) + { + /* Do two Iterations Together to Allow Direct Update of Ah & Al */ + t0 = Mac_32( L_Comp( Ah[j], Al[j] ), Kh, Kl, Ah[i - j], Al[i - j] ); + t1 = Mac_32( L_Comp( Ah[i - j], Al[i - j] ), Kh, Kl, Ah[j], Al[j] ); + L_Extract( t0, &Ah[j], &Al[j] ); + L_Extract( t1, &Ah[i - j], &Al[i - j] ); + } + IF( s_and( i, 1 ) == 0 ) + { + t0 = Mac_32( L_Comp( Ah[j], Al[j] ), Kh, Kl, Ah[i - j], Al[i - j] ); + L_Extract( t0, &Ah[j], &Al[j] ); + } + t2 = L_shr( t2, 4 ); /* t2 = K in Q31 ->convert to Q27 */ + L_Extract( t2, &Ah[i], &Al[i] ); /* An[i] in Q27 */ + + /* Alpha = Alpha * (1-K**2) */ +#ifdef BASOP_NOGLOB + t1 = L_mult_o( Kh, Kh, &Overflow ); /* K*K in Q31 */ +#else /* BASOP_NOGLOB */ + t1 = L_mult( Kh, Kh ); /* K*K in Q31 */ +#endif /* BASOP_NOGLOB */ + t0 = L_mac( t1, mult( Kh, Kl ), 2 ); + t0 = L_abs( t0 ); /* Some case <0 !! */ + t0 = L_sub( (Word32) 0x7fffffffL, t0 ); /* 1 - K*K in Q31 */ + lo = L_Extract_lc( t0, &hi ); /* DPF format */ + t0 = Mpy_32( alp_h, alp_l, hi, lo ); /* Alpha in Q31 */ + + + /* store denormalized alpha in epsP */ + t1 = L_shr( t0, alp_exp ); + if ( epsP != NULL ) + { + epsP[i] = t1; + move32(); + } + + /* Normalize Alpha */ + j = norm_l( t0 ); + t0 = L_shl( t0, j ); + alp_l = L_Extract_lc( t0, &alp_h ); /* DPF format */ + alp_exp = add( alp_exp, j ); /* Add normalization to alp_exp */ + } + + /* Adaptive scaling */ + t1 = L_deposit_l( 0 ); + FOR( i = 1; i <= order; i++ ) + { + t0 = L_Comp( Ah[i], Al[i] ); + t1 = L_max( t1, L_abs( t0 ) ); + } + k = s_min( sub( norm_l( t1 ), 1 ), 3 ); + A[0] = shl( 2048, k ); + move16(); + FOR( i = 1; i <= order; i++ ) + { + t0 = L_Comp( Ah[i], Al[i] ); +#ifdef BASOP_NOGLOB + A[i] = round_fx_o( L_shl_o( t0, k, &Overflow ), &Overflow ); +#else + A[i] = round_fx( L_shl( t0, k ) ); +#endif + move16(); + } + + BASOP_SATURATE_WARNING_ON_EVS + IF( mem != NULL ) + { + /* Enforce stable LPC filter - parcorr[0] and parcorr[1] are not LPC coeffiecients */ + IF( flag ) + { + Copy( mem, A, add( order, 1 ) ); + } + ELSE /* If stable LPC filter, store into memories */ + { + Copy( A, mem, add( order, 1 ) ); + } + } + + + return ( flag ); +} Word16 E_LPC_lev_dur_fx( const Word16 Rh[], const Word16 Rl[], Word32 A[], Word32 epsP[], const Word16 order, Word32 *mem ) { diff --git a/lib_com/preemph_fx.c b/lib_com/preemph_fx.c index 63de35dca..13a0b5e42 100644 --- a/lib_com/preemph_fx.c +++ b/lib_com/preemph_fx.c @@ -158,3 +158,58 @@ Word16 E_UTIL_f_preemph3( Word16 *signal, const Word16 mu, const Word16 lg, Word return Q_new; } + +Word16 E_UTIL_f_preemph3_ivas_fx( Word16 *signal, const Word16 mu, const Word16 lg, Word16 *mem, Word16 bits ) +{ + Word16 i, QVal, mus, tmp_fixed, Q_new; + Word32 L_tmp, L_maxloc; + + + QVal = shl( 1, sub( 15, bits ) ); + mus = shr( mu, bits ); + + L_tmp = L_mult( signal[0], QVal ); + L_tmp = L_msu( L_tmp, *mem, mus ); + L_maxloc = L_abs( L_tmp ); + + FOR( i = 1; i < lg; i++ ) + { + L_tmp = L_mult( signal[i], QVal ); + L_tmp = L_msu( L_tmp, signal[i - 1], mus ); + L_tmp = L_abs( L_tmp ); + L_maxloc = L_max( L_tmp, L_maxloc ); + } + + tmp_fixed = extract_h( L_maxloc ); + + Q_new = Q_MAX; + move16(); + IF( tmp_fixed != 0 ) + { + Q_new = sub( norm_s( tmp_fixed ), bits ); + Q_new = s_max( Q_new, 0 ); + Q_new = sub( s_min( Q_new, Q_MAX ), 1 ); + } + + tmp_fixed = signal[lg - 1]; + move16(); + + FOR( i = sub( lg, 1 ); i > 0; i-- ) + { + L_tmp = L_mult( signal[i], QVal ); + L_tmp = L_msu( L_tmp, signal[i - 1], mus ); + L_tmp = L_shl( L_tmp, Q_new ); + signal[i] = round_fx( L_tmp ); + move16(); + } + + L_tmp = L_mult( signal[0], QVal ); + L_tmp = L_msu( L_tmp, *mem, mus ); + L_tmp = L_shl( L_tmp, Q_new ); + signal[0] = round_fx( L_tmp ); + move16(); + *mem = tmp_fixed; + move16(); + + return Q_new; +} diff --git a/lib_com/prot_fx.h b/lib_com/prot_fx.h index 70d2f94b0..a148ab903 100644 --- a/lib_com/prot_fx.h +++ b/lib_com/prot_fx.h @@ -1114,6 +1114,9 @@ void autocorr_fx_32( Word16 E_LPC_lev_dur( const Word16 Rh[], const Word16 Rl[], Word16 A[], Word32 epsP[], const Word16 order, Word16 *parcorr ); Word16 E_LPC_lev_dur_stab( const Word16 Rh[], const Word16 Rl[], Word16 A[], Word32 epsP[], const Word16 order, Word16 *parcorr, Word16 k_max ); +Word16 E_LPC_lev_dur_ivas_fx( const Word16 Rh[], const Word16 Rl[], Word16 A[], Word32 epsP[], const Word16 order, Word16 *parcorr ); +Word16 E_LPC_lev_dur_stab_ivas_fx( const Word16 Rh[], const Word16 Rl[], Word16 A[], Word32 epsP[], const Word16 order, Word16 *parcorr, Word16 k_max ); + Word16 E_LPC_lev_dur_fx( const Word16 Rh[], const Word16 Rl[], Word32 A[], Word32 epsP[], const Word16 order, Word32 *mem ); Word16 E_LPC_lev_dur_stab_fx( const Word16 Rh[], const Word16 Rl[], Word32 A[], Word32 epsP[], const Word16 order, Word32 *mem, Word16 k_max ); @@ -2609,6 +2612,7 @@ void preemph_copy_fx( void E_UTIL_f_preemph2( Word16 shift, Word16 *signal, const Word16 mu, const Word16 lg, Word16 *mem ); Word16 E_UTIL_f_preemph3( Word16 *signal, const Word16 mu, const Word16 lg, Word16 *mem, Word16 bits ); +Word16 E_UTIL_f_preemph3_ivas_fx( Word16 *signal, const Word16 mu, const Word16 lg, Word16 *mem, Word16 bits ); // swb_bwe_com_fx.c Word16 WB_BWE_gain_pred_fx( Word16 *WB_fenv, /* o : WB frequency envelopes */ diff --git a/lib_dec/er_dec_tcx_fx.c b/lib_dec/er_dec_tcx_fx.c index 1a1dbce92..bbe1276f1 100644 --- a/lib_dec/er_dec_tcx_fx.c +++ b/lib_dec/er_dec_tcx_fx.c @@ -1263,7 +1263,7 @@ void con_tcx_ivas_fx( /* apply pre-emphasis to the signal */ mem = synth[( -( ( ( L_frame / 2 ) + hTcxDec->pit_max_TCX ) + M + M ) - 1 )]; /*Q0*/ move16(); - Q_exc = E_UTIL_f_preemph3( &( synth[-add( add( shr( L_frame, 1 ), hTcxDec->pit_max_TCX ), 2 * M )] ), st->preemph_fac, add( add( shr( L_frame, 1 ), hTcxDec->pit_max_TCX ), shl( M, 1 ) ), &mem, 1 ); + Q_exc = E_UTIL_f_preemph3_ivas_fx( &( synth[-add( add( shr( L_frame, 1 ), hTcxDec->pit_max_TCX ), 2 * M )] ), st->preemph_fac, add( add( shr( L_frame, 1 ), hTcxDec->pit_max_TCX ), shl( M, 1 ) ), &mem, 1 ); st->Mode2_lp_gainc = L_deposit_l( 0 ); st->Mode2_lp_gainp = get_gain2( synth - shl( L_subfr, 1 ), synth - add( shl( L_subfr, 1 ), Tc ), shl( L_subfr, 1 ) ); @@ -1286,7 +1286,7 @@ void con_tcx_ivas_fx( lag_wind( r_h, r_l, M, st->output_Fs, LAGW_STRONG ); /* Levinson Durbin */ - E_LPC_lev_dur( r_h, r_l, A_local, NULL, M, NULL ); + E_LPC_lev_dur_ivas_fx( r_h, r_l, A_local, NULL, M, NULL ); /* copy for multiple frame loss */ Copy( A_local, st->old_Aq_12_8_fx, M + 1 ); /*Q14*/ @@ -1308,7 +1308,7 @@ void con_tcx_ivas_fx( /* apply pre-emphasis to the signal */ mem = synth[( -L_frame - 1 )]; /*Q0*/ move16(); - Q_exc = E_UTIL_f_preemph3( &( synth[-L_frame] ), st->preemph_fac, L_frame, &mem, 1 ); + Q_exc = E_UTIL_f_preemph3_ivas_fx( &( synth[-L_frame] ), st->preemph_fac, L_frame, &mem, 1 ); Copy( st->old_Aq_12_8_fx, A_local, M + 1 ); /*Q14*/ offset = shr( L_frame, 1 ); @@ -2029,6 +2029,7 @@ void con_tcx_ivas_fx( } } #endif + E_UTIL_synthesis( sub( Q_exc, Q_syn ), A_local, -- GitLab