diff --git a/lib_com/ivas_prot_fx.h b/lib_com/ivas_prot_fx.h index 90d485b06f759540f471bc3cd55e70a577eb9792..dc9dbada520c7a9fc4329decaff4dc6cf88db51c 100644 --- a/lib_com/ivas_prot_fx.h +++ b/lib_com/ivas_prot_fx.h @@ -582,6 +582,16 @@ ivas_error ivas_cpe_dec_fx( const Word16 nb_bits_metadata, /* i : number of metadata bits */ Word16 *q_output /* i/o : Q of output synthesis signal */ ); + +void ivas_post_proc_fx( + SCE_DEC_HANDLE hSCE, /* i/o: SCE decoder structure */ + CPE_DEC_HANDLE hCPE, /* i/o: CPE decoder structure */ + const Word16 n, /* i : channel number */ + Word32 synth[], /* i/o: output synthesis signal */ + Word32 *output[CPE_CHANNELS], /* i/o: output synthesis signal */ + const Word16 output_frame, /* i : output frame length */ + const Word16 sba_dirac_stereo_flag /* i : signal stereo output for SBA DirAC */ +); #endif //ivas_lfe_dec_fx.c diff --git a/lib_com/lpc_tools_fx.c b/lib_com/lpc_tools_fx.c index 188407cb27b996f60554b2201347e639dc50847e..5afe87253b565e7ad7166f5cb1b029edd906d3e0 100644 --- a/lib_com/lpc_tools_fx.c +++ b/lib_com/lpc_tools_fx.c @@ -474,6 +474,227 @@ Word16 E_LPC_lev_dur_stab(const Word16 Rh[], const Word16 Rl[], Word16 A[], return(flag); } + +Word16 E_LPC_lev_dur_fx(const Word16 Rh[], const Word16 Rl[], Word32 A[], + Word32 epsP[], const Word16 order + , Word32 *mem +) +{ + return(E_LPC_lev_dur_stab_fx(Rh, Rl, A, epsP, order, mem, 32750)); /* 0.99945 in Q15 */ +} + +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 +) +{ + 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) */ + } + 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(norm_l(t1), 3); + A[0] = L_shl(2048, k + 16); + move16(); + FOR(i = 1; i <= order; i++) + { + t0 = L_Comp(Ah[i], Al[i]); +#ifdef BASOP_NOGLOB + A[i] = L_shl_o(t0, k, &Overflow); +#else + A[i] = L_shl(t0, k)); +#endif + } + + BASOP_SATURATE_WARNING_ON_EVS + IF(mem != NULL) + { + /* Enforce stable LPC filter - parcorr[0] and parcorr[1] are not LPC coeffiecients */ + IF(flag) + { + Copy32(mem, A, order + 1); + } + ELSE /* If stable LPC filter, store into memories */ + { + Copy32(A, mem, order + 1); + } + } + + + return(flag); +} + + /* * E_LPC_a_add_tilt * diff --git a/lib_com/prot_fx2.h b/lib_com/prot_fx2.h index 12abc90f8aa217c1d4cad4b8defd5ef46b631402..168e7451f1d65f1e5a82cb8938e74a0c52f789c2 100644 --- a/lib_com/prot_fx2.h +++ b/lib_com/prot_fx2.h @@ -961,6 +961,16 @@ Word16 E_LPC_lev_dur(const Word16 Rh[], const Word16 Rl[], Word16 A[], 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_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 +); + void E_LPC_a_add_tilt(const Word16 *a, Word16 *ap, Word16 gamma, Word16 m); void E_LPC_int_lpc_tcx(const Word16 lsp_old[], /* i : LSPs from past frame (1Q14) */ const Word16 lsp_new[], /* i : LSPs from present frame (1Q14) */ @@ -2095,6 +2105,10 @@ void Syn_filt_s( void E_UTIL_synthesis(const Word16 shift, const Word16 a[], const Word16 x[], Word16 y[], const Word16 lg, Word16 mem[], const Word16 update, const Word16 m); +void E_UTIL_synthesis_fx(const Word16 shift, const Word32 a[], const Word32 x[], Word32 y[], + const Word16 lg, Word32 mem[], const Word16 update, const Word16 m +); + void synth_mem_updt2( const Word16 L_frame, /* i : frame length */ const Word16 last_L_frame, /* i : frame length */ @@ -4875,6 +4889,16 @@ void tcx_ltp_post( Word16* tcx_buf ); +void tcx_ltp_post32( + Decoder_State* st, + TCX_LTP_DEC_HANDLE hTcxLtpDec, + Word16 core, + Word16 output_frame, + Word16 delay, + Word32* sig, + Word32* tcx_buf +); + //gs_inact_switching_fx.c void Inac_swtch_ematch_fx( Word16 exc2[], /* i/o: CELP/GSC excitation buffer Q_exc*/ diff --git a/lib_com/syn_filt_fx.c b/lib_com/syn_filt_fx.c index a8aa91a021baa0cbfe96d6fff188da68fb7e86b5..e3c127bdbb91205865d79437a7796acce91cd094 100644 --- a/lib_com/syn_filt_fx.c +++ b/lib_com/syn_filt_fx.c @@ -60,6 +60,50 @@ static Word32 syn_kern_24(Word32 L_tmp, const Word16 a[], const Word16 y[]) return syn_kern_8(L_tmp, a+16, y-16); } + +static Word32 syn_kern_2_fx(Word32 L_tmp, const Word32 a[], const Word32 y[]) +{ + L_tmp = Msub_32_32_r(L_tmp, y[-1], a[1]); + return Msub_32_32_r(L_tmp, y[-2], a[2]); +} + +static Word32 syn_kern_4_fx(Word32 L_tmp, const Word32 a[], const Word32 y[]) +{ + L_tmp = syn_kern_2_fx(L_tmp, a, y); + return syn_kern_2_fx(L_tmp, a + 2, y - 2); +} + +static Word32 syn_kern_6_fx(Word32 L_tmp, const Word32 a[], const Word32 y[]) +{ + L_tmp = syn_kern_4_fx(L_tmp, a, y); + return syn_kern_2_fx(L_tmp, a + 4, y - 4); +} + +static Word32 syn_kern_8_fx(Word32 L_tmp, const Word32 a[], const Word32 y[]) +{ + L_tmp = syn_kern_4_fx(L_tmp, a, y); + return syn_kern_4_fx(L_tmp, a + 4, y - 4); +} + +static Word32 syn_kern_10_fx(Word32 L_tmp, const Word32 a[], const Word32 y[]) +{ + L_tmp = syn_kern_8_fx(L_tmp, a, y); + return syn_kern_2_fx(L_tmp, a + 8, y - 8); +} + +Word32 syn_kern_16_fx(Word32 L_tmp, const Word32 a[], const Word32 y[]) +{ + L_tmp = syn_kern_8_fx(L_tmp, a, y); + return syn_kern_8_fx(L_tmp, a + 8, y - 8); +} + +static Word32 syn_kern_24_fx(Word32 L_tmp, const Word32 a[], const Word32 y[]) +{ + L_tmp = syn_kern_16_fx(L_tmp, a, y); + return syn_kern_8_fx(L_tmp, a + 16, y - 16); +} + + /*------------------------------------------------------------------* * Syn_filt_s_lc: * @@ -259,6 +303,94 @@ void E_UTIL_synthesis(const Word16 shift, const Word16 a[], const Word16 x[], Wo } +void E_UTIL_synthesis_fx(const Word16 shift, const Word32 a[], const Word32 x[], Word32 y[], + const Word16 lg, Word32 mem[], const Word16 update, const Word16 m +) +{ + Word16 i, j; + Word32 a0; + Word32 L_tmp; + Word16 q; + Word32(*syn_kern)(Word32 L_tmp, const Word32 a[], const Word32 y[]) = NULL; + Flag Overflow = 0; + + if (EQ_16(m, 6)) + { + syn_kern = syn_kern_6_fx; + } + if (EQ_16(m, 10)) + { + syn_kern = syn_kern_10_fx; + } + if (EQ_16(m, 16)) + { + syn_kern = syn_kern_16_fx; + } + if (EQ_16(m, 24)) + { + syn_kern = syn_kern_24_fx; + } + assert(syn_kern != NULL); + q = add(norm_l(a[0]), 1); + + + + /*-----------------------------------------------------------------------* + * Set Memory Pointer at End for Backward Access + *-----------------------------------------------------------------------*/ + mem += m; /*move32();*/ + + a0 = L_shr_o(a[0], shift, &Overflow); /* input / 2^shift */ + + /*-----------------------------------------------------------------------* + * Do the filtering + *-----------------------------------------------------------------------*/ + /* Filtering Only from Input + Memory */ + L_tmp = syn_kern(Mpy_32_32(a0, *x++), a, mem); + L_tmp = L_shl_o(L_tmp, q, &Overflow); + *y++ = L_tmp; + + /* Filtering from Input + Mix of Memory & Output Signal Past */ + FOR(i = 1; i < m; i++) + { + L_tmp = Mpy_32_32(a0, *x++); + /* Process Output Signal Past */ + FOR(j = 1; j <= i; j++) + { + L_tmp = Msub_32_32_r(L_tmp, a[j], y[-j]); + } + /* Process Memory */ + FOR(; j <= m; j++) + { + L_tmp = Msub_32_32_r(L_tmp, a[j], mem[i - j]); + } + L_tmp = L_shl_o(L_tmp, q, &Overflow); + *y++ = L_tmp; + } + + /* Filtering from Input + Output Signal Past */ + FOR(; i < lg; i++) + { + L_tmp = syn_kern(Mpy_32_32(a0, *x++), a, y); + L_tmp = L_shl_o(L_tmp, q, &Overflow); + *y++ = L_tmp; + } + + /*-----------------------------------------------------------------------* + * Update memory if required + *-----------------------------------------------------------------------*/ + IF(update != 0) + { + FOR(i = 0; i < m; i++) + { + *--mem = *--y; + move32(); + } + } + + return; +} + /*-------------------------------------------------------------------* * synth_mem_updt2() diff --git a/lib_com/tcx_ltp_fx.c b/lib_com/tcx_ltp_fx.c index 6a77d13278e2e9c90388d736eb70bfebf44aa7f7..a734dca55868e9b1103d3df1ec9b8ae155e85141 100644 --- a/lib_com/tcx_ltp_fx.c +++ b/lib_com/tcx_ltp_fx.c @@ -14,6 +14,8 @@ *-------------------------------------------------------------------*/ #define ALPHA 27853/*0.85f Q15*/ +#define MAX_TCX_LTP_FILTER_LEN 8 +#define MAX_TRANSITION_LEN 240 /* L_FRAME_48K / 4 */ void tcx_ltp_get_lpc( Word16 *x, @@ -107,6 +109,98 @@ void tcx_ltp_get_lpc( } +void tcx_ltp_get_lpc_fx( + Word32 *x, + const Word16 L, + Word32 *A, + const Word16 order ) +{ + Word16 i, j, s, s2, tmp; + Word32 r, L_tmp; + + Word16 tmpbuf[L_FRAME_MAX], *p = x; + Word16 r_l[TCXLTP_LTP_ORDER + 1], r_h[TCXLTP_LTP_ORDER + 1]; + + + assert( L <= L_FRAME_MAX ); + + /* calc r[0], determine shift */ + s = 0; + move16(); + r = L_deposit_l( 0 ); + FOR( j = 0; j < L; j++ ) + { + L_tmp = L_sub( r, 0x40000000 ); + if ( L_tmp > 0 ) + s = sub( s, 1 ); + if ( L_tmp > 0 ) + r = L_shr( r, 2 ); + + tmp = shl( x[j], s ); + r = L_mac0( r, tmp, tmp ); + } + r = L_max( r, L_shl( 100, shl( s, 1 ) ) ); + r = Mpy_32_16_1( r, 16386 /*1.0001f Q14*/ ); + s2 = norm_l( r ); + r = L_shl( r, s2 ); + s2 = sub( s2, 1 ); + r_l[0] = L_Extract_lc( r, &r_h[0] ); + move16(); + move16(); + + IF( s < 0 ) + { + /* shift buffer by s, recompute r[0] to reduce risk of instable LPC */ + r = L_deposit_l( 0 ); + tmp = lshl( (Word16) 0x8000, s ); /* factor corresponding to right shift by -s */ + + { + Word64 r64 = 0; + move64(); + FOR( j = 0; j < L; j++ ) + { + tmpbuf[j] = mult_r( x[j], tmp ); + move16(); + r64 = W_mac0_16_16( r64, tmpbuf[j], tmpbuf[j] ); + } + r = W_sat_l( r64 ); + } + r = L_max( r, L_shl( 100, shl( s, 1 ) ) ); + r = Mpy_32_16_1( r, 16386 /*1.0001f Q14*/ ); + s2 = norm_l( r ); + r = L_shl( r, s2 ); + s2 = sub( s2, 1 ); + r_l[0] = L_Extract_lc( r, &r_h[0] ); + move16(); + move16(); + + p = tmpbuf; + } + + /* calc r[1...] */ + FOR( i = 1; i <= order; i++ ) + { + r = L_deposit_l( 0 ); + + tmp = sub( L, i ); + { + Word64 r64 = 0; + move64(); + FOR( j = 0; j < tmp; j++ ) + { + r64 = W_mac0_16_16( r64, p[j], p[j + i] ); + } + r = W_sat_l( r64 ); + } + r = L_shl( r, s2 ); + r_l[i] = L_Extract_lc( r, &r_h[i] ); + move16(); + move16(); + } + + E_LPC_lev_dur_fx( r_h, r_l, A, NULL, order, NULL ); +} + static void tcx_ltp_get_zir( Word16 *zir, const Word16 length, @@ -203,6 +297,94 @@ static void tcx_ltp_get_zir( } } +static void tcx_ltp_get_zir_fx( + Word32 *zir, + const Word16 length, + Word32 *synth_ltp, + Word32 *synth, + Word32 *A, + const Word16 lpcorder, + const Word16 gain, + const Word16 pitch_int, + const Word16 pitch_fr, + const Word16 pitres, + const Word16 filtIdx ) +{ + Word32 buf[TCXLTP_LTP_ORDER]; + Word16 alpha, step; + Word32 *x0, *x1; + Word32 *y0, *y1; + Word32 s, s2; + const Word16 *w0, *w1, *v0, *v1; + Word32 i; + Word16 j, k, L; + + x0 = &synth_ltp[-pitch_int]; + x1 = x0 - 1; + y0 = synth; + y1 = y0 - 1; + + assert( filtIdx >= 0 ); + + w0 = &tcxLtpFilters[filtIdx].filt[pitch_fr]; + w1 = &tcxLtpFilters[filtIdx].filt[sub( pitres, pitch_fr )]; + v0 = &tcxLtpFilters[filtIdx].filt[0]; + v1 = &tcxLtpFilters[filtIdx].filt[pitres]; + L = tcxLtpFilters[filtIdx].length; + move16(); + + FOR( j = 0; j < lpcorder; j++ ) + { + s = L_deposit_l( 0 ); + s2 = L_deposit_l( 0 ); + k = 0; + move16(); + FOR( i = 0; i < L; i++ ) + { + s = Madd_32_16_r( Madd_32_16_r( s, x0[i], w0[k] ), x1[-i], w1[k] ); + s2 = Madd_32_16_r( Madd_32_16_r( s2, y0[i], v0[k] ), y1[-i], v1[k] ); + k = add( k, pitres ); + } + + /* s2 *= ALPHA; + buf[j] = ( synth[j] - gain * s2 ) - ( synth_ltp[j] - gain * s ); */ + i = L_sub_sat( s, Mpy_32_16_1( s2, ALPHA ) ); + buf[j] = L_add_sat( L_sub_sat( synth[j], synth_ltp[j] ), Mpy_32_16_1( i, gain ) ); + + move16(); + + x0++; + x1++; + y0++; + y1++; + } + + set32_fx( zir, 0, length ); + + E_UTIL_synthesis_fx( 0, A, zir, zir, length, buf, 0, lpcorder ); + + alpha = 0x7FFF; + move16(); + /* step = 1.f/(float)(length/2); */ + step = shl( 4, norm_s( length ) ); + if ( s_and( length, sub( length, 1 ) ) != 0 ) + { + step = mult_r( step, 26214 /*64.f/80.f Q15*/ ); + } + if ( EQ_16( length, 240 ) ) + { + step = 273 /*1.f/120.f Q15*/; + move16(); + } + + FOR( j = shr( length, 1 ); j < length; j++ ) + { + zir[j] = Mpy_32_16_r( zir[j], alpha ); + move32(); + alpha = sub( alpha, step ); + } +} + void predict_signal( const Word16 excI[], /* i : input excitation buffer */ Word16 excO[], /* o : output excitation buffer */ @@ -367,16 +549,646 @@ static void tcx_ltp_synth_filter( #endif BASOP_SATURATE_WARNING_ON_EVS; - x0++; - x1++; - y0++; - y1++; + x0++; + x1++; + y0++; + y1++; + } + } + ELSE + { + Copy( synth, synth_ltp, length ); + } +} + +static void tcx_ltp_synth_filter32( + Word32 *synth_ltp, + Word32 *synth, + Word16 length, + Word16 pitch_int, + Word16 pitch_fr, + Word16 gain, + Word16 pitch_res, + Word32 *zir, /* can be NULL */ + Word16 fade, /* 0=normal, +1=fade-in, -1=fade-out */ + Word16 filtIdx ) +{ + Word32 *x0, *x1; + Word32 *y0, *y1; + Word32 s, s2; + const Word16 *v0, *v1; + const Word16 *w0, *w1; + Word16 alpha, step = 0; /* initialize just to avoid compiler warning */ + Word16 i, j, k, L; + Word32 L_tmp, L_tmp2; + + IF( gain > 0 ) + { + x0 = &synth_ltp[-pitch_int]; + x1 = x0 - 1; + y0 = synth; + y1 = y0 - 1; + + assert( filtIdx >= 0 ); + + w0 = &tcxLtpFilters[filtIdx].filt[pitch_fr]; + w1 = &tcxLtpFilters[filtIdx].filt[sub( pitch_res, pitch_fr )]; + v0 = &tcxLtpFilters[filtIdx].filt[0]; + v1 = &tcxLtpFilters[filtIdx].filt[pitch_res]; + + L = tcxLtpFilters[filtIdx].length; + move16(); + + alpha = 0; + move16(); + IF( fade != 0 ) + { + if ( fade < 0 ) + { + alpha = 0x7FFF; + move16(); + } + + /* step = 1.f/(float)(length); */ + step = shl( 2, norm_s( length ) ); + if ( s_and( length, sub( length, 1 ) ) != 0 ) + { + step = mult_r( step, 26214 /*64.f/80.f Q15*/ ); + } + if ( EQ_16( length, 240 ) ) + { + step = 137 /*1.f/240.f Q15*/; + move16(); + } + + if ( fade < 0 ) + step = negate( step ); + } + + FOR( j = 0; j < length; j++ ) + { + s = L_deposit_l( 0 ); + s2 = L_deposit_l( 0 ); + k = 0; + move16(); + FOR( i = 0; i < L; i++ ) + { +#ifdef BASOP_NOGLOB + s = Madd_32_16_r( Madd_32_16_r( s, x0[i], w0[k] ), x1[-i], w1[k] ); + s2 = Madd_32_16_r( Madd_32_16_r( s2, y0[i], v0[k] ), y1[-i], v1[k] ); +#else + s = L_mac( L_mac( s, w0[k], x0[i] ), w1[k], x1[-i] ); + s2 = L_mac( L_mac( s2, v0[k], y0[i] ), v1[k], y1[-i] ); +#endif + k = add( k, pitch_res ); + } + + /* s2 *= ALPHA; + normal: synth_ltp[j] = synth[j] - gain * s2 + gain * s; + zir: synth_ltp[j] = synth[j] - gain * s2 + gain * s - zir[j]; + fade-in/out: synth_ltp[j] = synth[j] - alpha * gain * s2 + alpha * gain * s; */ +#ifdef BASOP_NOGLOB + L_tmp = L_sub_sat( s, Mpy_32_16_r( s2, ALPHA ) ); +#else + i = sub( round_fx( s ), mult_r( round_fx( s2 ), ALPHA ) ); +#endif + L_tmp2 = Mpy_32_16_r( L_tmp, gain ); + IF( fade != 0 ) + L_tmp2 = Mpy_32_16_r( L_tmp2, alpha ); +#ifdef BASOP_NOGLOB + L_tmp2 = L_add_sat( synth[j], L_tmp2 ); + IF( zir != NULL ) + { + L_tmp2 = L_sub_sat( L_tmp2, zir[j] ); + } +#else + L_tmp2 = add( synth[j], L_tmp2 ); + if ( zir != NULL ) + L_tmp2 = sub( L_tmp2, zir[j] ); +#endif + + synth_ltp[j] = L_tmp2; + move16(); + + BASOP_SATURATE_WARNING_OFF_EVS; +#ifdef BASOP_NOGLOB + if ( fade != 0 ) + { + alpha = add_sat( alpha, step ); + } +#else + if ( fade != 0 ) + alpha = add( alpha, step ); +#endif + BASOP_SATURATE_WARNING_ON_EVS; + + x0++; + x1++; + y0++; + y1++; + } + } + ELSE + { + Copy32( synth, synth_ltp, length ); + } +} + +static void tcx_ltp_synth_filter_10( + Word16 *out, + Word16 *in, + const Word16 length, + const Word16 pitch_int, + const Word16 pitch_fr, + const Word16 gain, + const Word16 pitch_res, + const Word16 filtIdx ) +{ + Word16 *x0, *x1; + Word16 *y0, *y1; + Word32 s, s2; + const Word16 *v0, *v1; + const Word16 *w0, *w1; + Word16 i, j, k, L; + Word16 curr_gain, gain_step; + + x0 = &out[-pitch_int]; + x1 = x0 - 1; + y0 = in; + y1 = y0 - 1; + + assert( GE_16( filtIdx, 0 ) ); + + w0 = &tcxLtpFilters[filtIdx].filt[pitch_fr]; + w1 = &tcxLtpFilters[filtIdx].filt[pitch_res - pitch_fr]; + v0 = &tcxLtpFilters[filtIdx].filt[0]; + v1 = &tcxLtpFilters[filtIdx].filt[pitch_res]; + L = tcxLtpFilters[filtIdx].length; + + curr_gain = gain; + gain_step = negate( gain ) / length; + + for ( j = 0; j < length; j++ ) + { + s = 0; + s2 = 0; + + for ( i = 0, k = 0; i < L; i++, k += pitch_res ) + { + // s += w0[k] * x0[i] + w1[k] * x1[-i]; + // s2 += v0[k] * y0[i] + v1[k] * y1[-i]; + s = L_mac_sat( L_mac_sat( s, w0[k], x0[i] ), w1[k], x1[-i] ); + s2 = L_mac_sat( L_mac_sat( s2, v0[k], y0[i] ), v1[k], y1[-i] ); + } + + // out[j] = in[j] - curr_gain * s2 * ALPHA + curr_gain * s; + out[j] = add_sat( in[j], mult_r_sat( curr_gain, sub_sat( round_fx_sat( s ), mult_r_sat( round_fx_sat( s2 ), ALPHA ) ) ) ); + + x0++; + x1++; + y0++; + y1++; + + curr_gain = add( curr_gain, gain_step ); + } + + return; +} + +static void tcx_ltp_synth_filter_10_fx( + Word32 *out, + Word32 *in, + const Word16 length, + const Word16 pitch_int, + const Word16 pitch_fr, + const Word16 gain, + const Word16 pitch_res, + const Word16 filtIdx) +{ + Word32 *x0, *x1; + Word32 *y0, *y1; + Word32 s, s2; + const Word16 *v0, *v1; + const Word16 *w0, *w1; + Word16 i, j, k, L; + Word16 curr_gain, gain_step; + + x0 = &out[-pitch_int]; + x1 = x0 - 1; + y0 = in; + y1 = y0 - 1; + + assert(GE_16(filtIdx, 0)); + + w0 = &tcxLtpFilters[filtIdx].filt[pitch_fr]; + w1 = &tcxLtpFilters[filtIdx].filt[pitch_res - pitch_fr]; + v0 = &tcxLtpFilters[filtIdx].filt[0]; + v1 = &tcxLtpFilters[filtIdx].filt[pitch_res]; + L = tcxLtpFilters[filtIdx].length; + + curr_gain = gain; + gain_step = negate(gain) / length; + + for (j = 0; j < length; j++) + { + s = 0; + s2 = 0; + + for (i = 0, k = 0; i < L; i++, k += pitch_res) + { + // s += w0[k] * x0[i] + w1[k] * x1[-i]; + // s2 += v0[k] * y0[i] + v1[k] * y1[-i]; + s = Madd_32_16_r(Madd_32_16_r(s, x0[i], w0[k]), x1[-i], w1[k]); + s2 = Madd_32_16_r(Madd_32_16_r(s2, y0[i], v0[k]), y1[-i], v1[k]); + } + + // out[j] = in[j] - curr_gain * s2 * ALPHA + curr_gain * s; + out[j] = L_add_sat(in[j], Mpy_32_16_1(L_sub_sat(s, Mpy_32_16_1(s2, ALPHA)), curr_gain)); + + x0++; + x1++; + y0++; + y1++; + + curr_gain = add(curr_gain, gain_step); + } + + return; +} + +static void tcx_ltp_synth_filter_01( + Word16 *out, + Word16 *in, + const Word16 length, + const Word16 pitch_int, + const Word16 pitch_fr, + const Word16 gain, + const Word16 pitch_res, + const Word16 filtIdx ) +{ + Word16 *x0, *x1; + Word16 *y0, *y1; + Word32 s, s2; + const Word16 *v0, *v1; + const Word16 *w0, *w1; + Word16 i, j, k, L; + Word16 curr_gain, gain_step; + + x0 = &out[negate( pitch_int )]; + x1 = x0 - 1; + y0 = in; + y1 = y0 - 1; + + assert( GE_16( filtIdx, 0 ) ); + + w0 = &tcxLtpFilters[filtIdx].filt[pitch_fr]; + w1 = &tcxLtpFilters[filtIdx].filt[pitch_res - pitch_fr]; + v0 = &tcxLtpFilters[filtIdx].filt[0]; + v1 = &tcxLtpFilters[filtIdx].filt[pitch_res]; + L = tcxLtpFilters[filtIdx].length; + + curr_gain = 0; + gain_step = gain / length; + + for ( j = 0; j < length; j++ ) + { + s = 0; + s2 = 0; + + for ( i = 0, k = 0; i < L; i++, k = add( k, pitch_res ) ) + { + // s += w0[k] * x0[i] + w1[k] * x1[-i]; + // s2 += v0[k] * y0[i] + v1[k] * y1[-i]; + s = L_mac_sat( L_mac_sat( s, w0[k], x0[i] ), w1[k], x1[-i] ); + s2 = L_mac_sat( L_mac_sat( s2, v0[k], y0[i] ), v1[k], y1[-i] ); + } + + // out[j] = in[j] - curr_gain * s2 * ALPHA + curr_gain * s; + out[j] = add_sat( in[j], mult_r_sat( curr_gain, sub_sat( round_fx_sat( s ), mult_r_sat( round_fx_sat( s2 ), ALPHA ) ) ) ); + + + x0++; + x1++; + y0++; + y1++; + + curr_gain = add( curr_gain, gain_step ); + } + + return; +} + +static void tcx_ltp_synth_filter_01_fx( + Word32 *out, + Word32 *in, + const Word16 length, + const Word16 pitch_int, + const Word16 pitch_fr, + const Word16 gain, + const Word16 pitch_res, + const Word16 filtIdx) +{ + Word32 *x0, *x1; + Word32 *y0, *y1; + Word32 s, s2; + const Word16 *v0, *v1; + const Word16 *w0, *w1; + Word16 i, j, k, L; + Word16 curr_gain, gain_step; + + x0 = &out[negate(pitch_int)]; + x1 = x0 - 1; + y0 = in; + y1 = y0 - 1; + + assert(GE_16(filtIdx, 0)); + + w0 = &tcxLtpFilters[filtIdx].filt[pitch_fr]; + w1 = &tcxLtpFilters[filtIdx].filt[pitch_res - pitch_fr]; + v0 = &tcxLtpFilters[filtIdx].filt[0]; + v1 = &tcxLtpFilters[filtIdx].filt[pitch_res]; + L = tcxLtpFilters[filtIdx].length; + + curr_gain = 0; + gain_step = gain / length; + + for (j = 0; j < length; j++) + { + s = 0; + s2 = 0; + + for (i = 0, k = 0; i < L; i++, k = add(k, pitch_res)) + { + // s += w0[k] * x0[i] + w1[k] * x1[-i]; + // s2 += v0[k] * y0[i] + v1[k] * y1[-i]; + s = Madd_32_16_r(Madd_32_16_r(s, x0[i], w0[k]), x1[-i], w1[k]); + s2 = Madd_32_16_r(Madd_32_16_r(s2, y0[i], v0[k]), y1[-i], v1[k]); + } + + // out[j] = in[j] - curr_gain * s2 * ALPHA + curr_gain * s; + out[j] = L_add_sat(in[j], Mpy_32_16_r(L_sub_sat(s, Mpy_32_16_1(s2, ALPHA)), curr_gain)); + + + x0++; + x1++; + y0++; + y1++; + + curr_gain = add(curr_gain, gain_step); + } + + return; +} + +/*------------------------------------------------------------------- + *tcx_ltp_synth_filter_11_unequal_pitch_flt() + * + * blend between two filters by means of OAO + * filter the input signal at the initial subinterval with + * the first filter unit according to parameters associated to + * the preceding update interval with scaling from non-zero gain towards 0 + * followed by the second filter unit according to parameters associated to + * the current update interval with scaling from 0 towards non-zero gain + ---------------------------------------------------------------------*/ + +static void tcx_ltp_synth_filter_11_unequal_pitch( + Word16 *out, + Word16 *in, + const Word16 length, + const Word16 cur_pitch_int, + const Word16 cur_pitch_fr, + const Word16 cur_gain, + const Word16 pitch_res, + const Word16 filtIdx, + const Word16 prev_pitch_int, + const Word16 prev_pitch_fr, + const Word16 prev_gain, + const Word16 prev_pitch_res, + const Word16 prev_filtIdx ) +{ + Word16 *x0, *x1; + Word16 *y0, *y1; + Word16 *l0, *l1; + Word16 *m0, *m1; + Word32 s, s2, s3, s4; + const Word16 *v0, *v1; + const Word16 *w0, *w1; + const Word16 *p0, *p1; + const Word16 *q0, *q1; + Word16 i, j, k, L; + Word16 prev_L; + Word16 temp_buf[MAX_TRANSITION_LEN + 2 * MAX_TCX_LTP_FILTER_LEN]; + Word16 *temp_ptr; + Word16 gain, gain_step; + + x0 = &out[negate( prev_pitch_int )]; + x1 = x0 - 1; + y0 = in; + y1 = y0 - 1; + + assert( GE_16( filtIdx, 0 ) && GE_16( prev_filtIdx, 0 ) ); + + w0 = &tcxLtpFilters[prev_filtIdx].filt[prev_pitch_fr]; + w1 = &tcxLtpFilters[prev_filtIdx].filt[prev_pitch_res - prev_pitch_fr]; + v0 = &tcxLtpFilters[prev_filtIdx].filt[0]; + v1 = &tcxLtpFilters[prev_filtIdx].filt[prev_pitch_res]; + + prev_L = tcxLtpFilters[prev_filtIdx].length; + + p0 = &tcxLtpFilters[filtIdx].filt[cur_pitch_fr]; + p1 = &tcxLtpFilters[filtIdx].filt[pitch_res - cur_pitch_fr]; + q0 = &tcxLtpFilters[filtIdx].filt[0]; + q1 = &tcxLtpFilters[filtIdx].filt[pitch_res]; + + L = tcxLtpFilters[filtIdx].length; + + /* 1. decreasing gain filter. The first filter unit with the parameters associated to the previous interval and scaling towards 0 */ + gain = prev_gain; + gain_step = negate( prev_gain ) / length; + + for ( j = 0; j < length; j++ ) + { + s = 0; + s2 = 0; + + for ( i = 0, k = 0; i < prev_L; i++, k += prev_pitch_res ) + { + // s += w0[k] * x0[i] + w1[k] * x1[-i]; + // s2 += v0[k] * y0[i] + v1[k] * y1[-i]; + s = L_mac_sat( L_mac_sat( s, w0[k], x0[i] ), w1[k], x1[-i] ); + s2 = L_mac_sat( L_mac_sat( s2, v0[k], y0[i] ), v1[k], y1[-i] ); + } + + // out[j] = in[j] - gain * s2 * ALPHA + gain * s; + out[j] = add_sat( in[j], mult_r_sat( gain, sub_sat( round_fx_sat( s ), mult_r_sat( round_fx_sat( s2 ), ALPHA ) ) ) ); + + x0++; + x1++; + y0++; + y1++; + + gain = add( gain, gain_step ); + } + + Copy( out - L, temp_buf, length + L ); + Copy( in + length, temp_buf + length + L, L ); + temp_ptr = &temp_buf[0] + L; + + m0 = temp_ptr; + m1 = temp_ptr - 1; + l0 = &out[negate( cur_pitch_int )]; + l1 = l0 - 1; + + /* 2. increasing gain filter. The second filter unit with the parameters associated to the current interval and scaling from 0 towards current gain */ + gain = 0; + gain_step = cur_gain / length; + + for ( j = 0; j < length; j++ ) + { + s3 = 0; + s4 = 0; + + for ( i = 0, k = 0; i < L; i++, k += pitch_res ) + { + // s3 += p0[k] * l0[i] + p1[k] * l1[-i]; + // s4 += q0[k] * m0[i] + q1[k] * m1[-i]; + s3 = L_mac_sat( L_mac_sat( s3, p0[k], l0[i] ), p1[k], l1[-i] ); + s4 = L_mac_sat( L_mac_sat( s4, q0[k], m0[i] ), q1[k], m1[-i] ); + } + + // out[j] = *(temp_ptr + j) - gain * s4 * ALPHA + gain * s3; + out[j] = add_sat( *( temp_ptr + j ), mult_r_sat( gain, sub_sat( round_fx_sat( s3 ), mult_r_sat( round_fx_sat( s4 ), ALPHA ) ) ) ); + + + l0++; + l1++; + m0++; + m1++; + + gain = add( gain, gain_step ); + } + + return; +} + +static void tcx_ltp_synth_filter_11_unequal_pitch_fx( + Word32 *out, + Word32 *in, + const Word16 length, + const Word16 cur_pitch_int, + const Word16 cur_pitch_fr, + const Word16 cur_gain, + const Word16 pitch_res, + const Word16 filtIdx, + const Word16 prev_pitch_int, + const Word16 prev_pitch_fr, + const Word16 prev_gain, + const Word16 prev_pitch_res, + const Word16 prev_filtIdx ) +{ + Word32 *x0, *x1; + Word32 *y0, *y1; + Word32 *l0, *l1; + Word32 *m0, *m1; + Word32 s, s2, s3, s4; + const Word16 *v0, *v1; + const Word16 *w0, *w1; + const Word16 *p0, *p1; + const Word16 *q0, *q1; + Word16 i, j, k, L; + Word16 prev_L; + Word32 temp_buf[MAX_TRANSITION_LEN + 2 * MAX_TCX_LTP_FILTER_LEN]; + Word32 *temp_ptr; + Word16 gain, gain_step; + + x0 = &out[negate( prev_pitch_int )]; + x1 = x0 - 1; + y0 = in; + y1 = y0 - 1; + + assert( GE_16( filtIdx, 0 ) && GE_16( prev_filtIdx, 0 ) ); + + w0 = &tcxLtpFilters[prev_filtIdx].filt[prev_pitch_fr]; + w1 = &tcxLtpFilters[prev_filtIdx].filt[prev_pitch_res - prev_pitch_fr]; + v0 = &tcxLtpFilters[prev_filtIdx].filt[0]; + v1 = &tcxLtpFilters[prev_filtIdx].filt[prev_pitch_res]; + + prev_L = tcxLtpFilters[prev_filtIdx].length; + + p0 = &tcxLtpFilters[filtIdx].filt[cur_pitch_fr]; + p1 = &tcxLtpFilters[filtIdx].filt[pitch_res - cur_pitch_fr]; + q0 = &tcxLtpFilters[filtIdx].filt[0]; + q1 = &tcxLtpFilters[filtIdx].filt[pitch_res]; + + L = tcxLtpFilters[filtIdx].length; + + /* 1. decreasing gain filter. The first filter unit with the parameters associated to the previous interval and scaling towards 0 */ + gain = prev_gain; + gain_step = negate( prev_gain ) / length; + + for ( j = 0; j < length; j++ ) + { + s = 0; + s2 = 0; + + for ( i = 0, k = 0; i < prev_L; i++, k += prev_pitch_res ) + { + // s += w0[k] * x0[i] + w1[k] * x1[-i]; + // s2 += v0[k] * y0[i] + v1[k] * y1[-i]; + s = Madd_32_16_r( Madd_32_16_r( s, x0[i], w0[k] ), x1[-i], w1[k] ); + s2 = Madd_32_16_r( Madd_32_16_r( s2, y0[i], v0[k] ), y1[-i], v1[k] ); } + + // out[j] = in[j] - gain * s2 * ALPHA + gain * s; + out[j] = L_add_sat( in[j], Mpy_32_16_r( L_sub_sat( s, Mpy_32_16_1( s2, ALPHA ) ), gain ) ); + + x0++; + x1++; + y0++; + y1++; + + gain = add( gain, gain_step ); } - ELSE + + Copy32( out - L, temp_buf, length + L ); + Copy32( in + length, temp_buf + length + L, L ); + temp_ptr = &temp_buf[0] + L; + + m0 = temp_ptr; + m1 = temp_ptr - 1; + l0 = &out[negate( cur_pitch_int )]; + l1 = l0 - 1; + + /* 2. increasing gain filter. The second filter unit with the parameters associated to the current interval and scaling from 0 towards current gain */ + gain = 0; + gain_step = cur_gain / length; + + for ( j = 0; j < length; j++ ) { - Copy( synth, synth_ltp, length ); + s3 = 0; + s4 = 0; + + for ( i = 0, k = 0; i < L; i++, k += pitch_res ) + { + // s3 += p0[k] * l0[i] + p1[k] * l1[-i]; + // s4 += q0[k] * m0[i] + q1[k] * m1[-i]; + s3 = Madd_32_16_r( Madd_32_16_r( s3, l0[i], p0[k] ), l1[-i], p1[k] ); + s4 = Madd_32_16_r( Madd_32_16_r( s4, m0[i], q0[k] ), m1[-i], q1[k] ); + } + + // out[j] = *(temp_ptr + j) - gain * s4 * ALPHA + gain * s3; + out[j] = L_add_sat( *( temp_ptr + j ), Mpy_32_16_r( L_sub_sat( s3, Mpy_32_16_1( s4, ALPHA ) ), gain ) ); + + + l0++; + l1++; + m0++; + m1++; + + gain = add( gain, gain_step ); } + + return; } Word16 tcx_ltp_decode_params( @@ -723,27 +1535,27 @@ void tcx_ltp_post( test(); test(); test(); -#ifdef IVAS_CODE_TCX_LTP +//#ifdef IVAS_CODE_TCX_LTP if (st->element_mode != EVS_MONO) { - if (gain == 0.f && hTcxLtpDec->tcxltp_gain_post_prev == 0.f) + if (gain == 0 && hTcxLtpDec->tcxltp_gain_post_prev == 0) { /* The filtering is deactivated, just copy input to the output */ - mvr2r(sig_in + delay, sig_out + delay, L_transition); + Copy(sig_in + delay, sig_out + delay, L_transition); } - else if (gain == 0.f && hTcxLtpDec->tcxltp_gain_post_prev != 0.f) + else if (gain == 0 && hTcxLtpDec->tcxltp_gain_post_prev != 0) { /* Filtering with the first filter unit */ tcx_ltp_synth_filter_10(sig_out + delay, sig_in + delay, L_transition, hTcxLtpDec->tcxltp_pitch_int_post_prev, hTcxLtpDec->tcxltp_pitch_fr_post_prev, hTcxLtpDec->tcxltp_gain_post_prev, st->pit_res_max_past, hTcxLtpDec->tcxltp_filt_idx_prev); } - else if (gain != 0.f && hTcxLtpDec->tcxltp_gain_post_prev == 0.f) + else if (gain != 0 && hTcxLtpDec->tcxltp_gain_post_prev == 0) { /* Filtering with the second filter unit */ tcx_ltp_synth_filter_01(sig_out + delay, sig_in + delay, L_transition, pitch_int, pitch_fr, gain, st->pit_res_max, filtIdx); } else if (gain == hTcxLtpDec->tcxltp_gain_post_prev && pitch_int == hTcxLtpDec->tcxltp_pitch_int_post_prev && pitch_fr == hTcxLtpDec->tcxltp_pitch_fr_post_prev && st->pit_res_max == st->pit_res_max_past && filtIdx == hTcxLtpDec->tcxltp_filt_idx_prev) { - tcx_ltp_synth_filter(sig_out + delay, sig_in + delay, L_transition, pitch_int, pitch_fr, gain, st->pit_res_max, filtIdx); + tcx_ltp_synth_filter( sig_out + delay, sig_in + delay, L_transition, pitch_int, pitch_fr, gain, st->pit_res_max, NULL, 0, filtIdx ); } else { @@ -753,7 +1565,7 @@ void tcx_ltp_post( } } ELSE -#endif +//#endif { IF(gain == 0 && hTcxLtpDec->tcxltp_gain_post_prev == 0) { @@ -808,3 +1620,352 @@ void tcx_ltp_post( Copy( sig_out, hTcxLtpDec->tcxltp_mem_out, output_frame ); } + + +void tcx_ltp_post32( + Decoder_State *st, + TCX_LTP_DEC_HANDLE hTcxLtpDec, + Word16 core, + Word16 output_frame, + Word16 delay, + Word32 *sig, + Word32 *tcx_buf ) +{ + Word16 tmp, L_transition, lpcorder, filtIdx; + Word16 gain, gain2; + Word32 tmp32; + Word32 zir[L_FRAME_PLUS / 4], A[TCXLTP_LTP_ORDER + 1]; + Word32 buf_in[TCXLTP_MAX_DELAY + L_FRAME48k + TCXLTP_MAX_DELAY], buf_out[2 * L_FRAME48k]; + Word32 *sig_in, *sig_out; + Word16 pitch_int, pitch_fr; + Word16 tcx_buf_len, bfi, L_frame_core, SideInfoOnly; + Word32 total_brate; + + total_brate = st->total_brate; + move32(); + IF( EQ_16( st->element_mode, IVAS_CPE_MDCT ) ) + { + total_brate = st->bits_frame_nominal * FRAMES_PER_SEC; + move32(); + } + + filtIdx = 0; /* just to avoid comilation warnings */ + tcx_buf_len = NS2SA_fx2( st->output_Fs, TCXLTP_DELAY_NS ); + SideInfoOnly = 0; + + if ( GE_32( total_brate, HQ_96k ) ) + { + SideInfoOnly = 1; + move16(); + } + + L_frame_core = st->L_frame; + move16(); + + if ( EQ_16( st->element_mode, IVAS_CPE_MDCT ) ) + { + L_frame_core = L_FRAME; + move16(); + } + + IF( EQ_16( core, ACELP_CORE ) ) + { + bfi = 0; + pitch_int = 0; + pitch_fr = 0; + gain = 0; + L_frame_core = st->L_frame_past; + move16(); + move16(); + move16(); + move16(); + } + ELSE + { + bfi = st->bfi; + pitch_int = hTcxLtpDec->tcxltp_pitch_int; + pitch_fr = hTcxLtpDec->tcxltp_pitch_fr; + gain = hTcxLtpDec->tcxltp_gain; + move16(); + move16(); + move16(); + move16(); + } + /******** Init ********/ + + + /* Parameters */ + L_transition = shr( output_frame, 2 ); + lpcorder = TCXLTP_LTP_ORDER; + move16(); + + /* Input buffer */ + sig_in = buf_in + tcx_buf_len; + Copy32( hTcxLtpDec->tcxltp_mem_in_32, buf_in, tcx_buf_len ); + Copy32( sig, buf_in + tcx_buf_len, output_frame ); + IF( core > ACELP_CORE ) + { + Copy32( tcx_buf, sig_in + output_frame, tcx_buf_len ); + } + Copy32( sig + output_frame - tcx_buf_len, hTcxLtpDec->tcxltp_mem_in_32, tcx_buf_len ); + + /* Output buffer */ + sig_out = buf_out + output_frame; + Copy32( hTcxLtpDec->tcxltp_mem_out_32, buf_out, output_frame ); + + /* TCX-LTP parameters: integer pitch, fractional pitch, gain */ + test(); + test(); + IF( !( SideInfoOnly != 0 || hTcxLtpDec->tcxltp != 0 ) || EQ_16( core, ACELP_CORE ) ) + { + /* No LTP */ + pitch_int = 0; + move16(); + pitch_fr = 0; + move16(); + gain = 0; + move16(); + } + ELSE IF( bfi == 0 ) + { + /* LTP and good frame */ + IF( NE_16( output_frame, L_frame_core ) ) + { + tmp = div_s( output_frame, shl( L_frame_core, 2 ) ); /* Q13 */ + tmp32 = L_mult0( add( imult1616( pitch_int, st->pit_res_max ), pitch_fr ), tmp ); /* Q13 */ + tmp = round_fx( L_shl( tmp32, 3 ) ); /* Q0 */ + pitch_int = idiv1616U( tmp, st->pit_res_max ); + pitch_fr = sub( tmp, imult1616( pitch_int, st->pit_res_max ) ); + } + IF( EQ_16( st->element_mode, EVS_MONO ) ) /* hard tunings for EVS_MONO, HQ_48k is TCX only */ + { + test(); + test(); + IF( EQ_32( total_brate, 48000 ) && EQ_16( L_frame_core, L_FRAME16k ) ) + { + gain = mult_r( gain, 10486 /*0.32f Q15*/ ); + } + ELSE IF( EQ_32( total_brate, 48000 ) && EQ_16( L_frame_core, 512 ) ) + { + gain = mult_r( gain, 13107 /*0.40f Q15*/ ); + } + ELSE + { + gain = mult_r( gain, 20972 /*0.64f Q15*/ ); + } + } + ELSE IF( GT_16( st->element_mode, IVAS_SCE ) && GE_32( total_brate, IVAS_96k ) ) + { + gain = mult_r( gain, 13107 /*0.40f Q15*/ ); + } + ELSE + { + gain = mult_r( gain, 20972 /*0.64f Q15*/ ); + } + } + ELSE + { + /* PLC: [TCX: Fade-out] + * PLC: LTP and bad frame (concealment) */ + IF( st->pit_res_max == st->pit_res_max_past ) /* ensure consistent core SR to previous frame; otherwise, set gain to 0 */ + { + pitch_int = hTcxLtpDec->tcxltp_pitch_int_post_prev; + move16(); + pitch_fr = hTcxLtpDec->tcxltp_pitch_fr_post_prev; + move16(); + gain = shl( mult_r( hTcxLtpDec->tcxltp_gain_post_prev, st->hTcxDec->damping ), 1 ); + } + ELSE + { + gain = 0; + move16(); + } + } + + + IF( SideInfoOnly != 0 ) + { + gain = 0; + move16(); + if ( bfi != 0 ) + { + hTcxLtpDec->tcxltp_gain_post_prev = 0; + move16(); + } + } + gain2 = gain; + move16(); + + IF( EQ_16( L_frame_core, L_FRAME ) ) + { + SWITCH( output_frame ) + { + case L_FRAME8k: + filtIdx = 0; + move16(); + BREAK; + case L_FRAME16k: + filtIdx = 1; + move16(); + BREAK; + case L_FRAME32k: + filtIdx = 2; + move16(); + BREAK; + case L_FRAME48k: + filtIdx = 3; + move16(); + BREAK; + default: + assert( 0 ); + } + } + ELSE IF( EQ_16( L_frame_core, L_FRAME16k ) ) + { + SWITCH( output_frame ) + { + case L_FRAME8k: + filtIdx = 4; + move16(); + BREAK; + case L_FRAME16k: + filtIdx = 5; + move16(); + BREAK; + case L_FRAME32k: + filtIdx = 6; + move16(); + BREAK; + case L_FRAME48k: + filtIdx = 7; + move16(); + BREAK; + default: + assert( 0 ); + } + } + ELSE IF( EQ_16( L_frame_core, 512 ) ) + { + SWITCH( output_frame ) + { + case L_FRAME8k: + filtIdx = 8; + move16(); + BREAK; + case L_FRAME16k: + filtIdx = 9; + move16(); + BREAK; + case L_FRAME32k: + filtIdx = 10; + move16(); + BREAK; + case L_FRAME48k: + filtIdx = 11; + move16(); + BREAK; + default: + assert( 0 ); + } + } + ELSE + { + filtIdx = -1; + move16(); + } + + + /******** Previous-frame part ********/ + + tcx_ltp_synth_filter32( sig_out, sig_in, delay, hTcxLtpDec->tcxltp_pitch_int_post_prev, hTcxLtpDec->tcxltp_pitch_fr_post_prev, hTcxLtpDec->tcxltp_gain_post_prev, + st->pit_res_max_past, NULL, 0, hTcxLtpDec->tcxltp_filt_idx_prev ); + + /******** Transition part ********/ + + test(); + test(); + test(); + //#ifdef IVAS_CODE_TCX_LTP + if ( st->element_mode != EVS_MONO ) + { + if ( gain == 0 && hTcxLtpDec->tcxltp_gain_post_prev == 0 ) + { + /* The filtering is deactivated, just copy input to the output */ + Copy32( sig_in + delay, sig_out + delay, L_transition ); + } + else if ( gain == 0 && hTcxLtpDec->tcxltp_gain_post_prev != 0 ) + { + /* Filtering with the first filter unit */ + tcx_ltp_synth_filter_10_fx( sig_out + delay, sig_in + delay, L_transition, hTcxLtpDec->tcxltp_pitch_int_post_prev, hTcxLtpDec->tcxltp_pitch_fr_post_prev, hTcxLtpDec->tcxltp_gain_post_prev, st->pit_res_max_past, hTcxLtpDec->tcxltp_filt_idx_prev ); + } + else if ( gain != 0 && hTcxLtpDec->tcxltp_gain_post_prev == 0 ) + { + /* Filtering with the second filter unit */ + tcx_ltp_synth_filter_01_fx( sig_out + delay, sig_in + delay, L_transition, pitch_int, pitch_fr, gain, st->pit_res_max, filtIdx ); + } + else if ( gain == hTcxLtpDec->tcxltp_gain_post_prev && pitch_int == hTcxLtpDec->tcxltp_pitch_int_post_prev && pitch_fr == hTcxLtpDec->tcxltp_pitch_fr_post_prev && st->pit_res_max == st->pit_res_max_past && filtIdx == hTcxLtpDec->tcxltp_filt_idx_prev ) + { + tcx_ltp_synth_filter32( sig_out + delay, sig_in + delay, L_transition, pitch_int, pitch_fr, gain, st->pit_res_max, NULL, 0, filtIdx ); + } + else + { + /* Filtering with the first filter unit, followed by the filtering with the second filter unit */ + tcx_ltp_synth_filter_11_unequal_pitch_fx( sig_out + delay, sig_in + delay, L_transition, pitch_int, pitch_fr, gain, st->pit_res_max, filtIdx, + hTcxLtpDec->tcxltp_pitch_int_post_prev, hTcxLtpDec->tcxltp_pitch_fr_post_prev, hTcxLtpDec->tcxltp_gain_post_prev, st->pit_res_max_past, hTcxLtpDec->tcxltp_filt_idx_prev ); + } + } + ELSE + //#endif + { + IF( gain == 0 && hTcxLtpDec->tcxltp_gain_post_prev == 0 ) + { + Copy32( sig_in + delay, sig_out + delay, L_transition ); + } + ELSE IF( hTcxLtpDec->tcxltp_gain_post_prev == 0 ) + { + tcx_ltp_synth_filter32( sig_out + delay, sig_in + delay, L_transition, pitch_int, + pitch_fr, gain, st->pit_res_max, NULL, 1, filtIdx ); + } + ELSE IF( gain == 0 ) + { + tcx_ltp_synth_filter32( sig_out + delay, sig_in + delay, L_transition, hTcxLtpDec->tcxltp_pitch_int_post_prev, hTcxLtpDec->tcxltp_pitch_fr_post_prev, + hTcxLtpDec->tcxltp_gain_post_prev, st->pit_res_max_past, NULL, -1, hTcxLtpDec->tcxltp_filt_idx_prev ); + } + ELSE IF( EQ_16( gain, hTcxLtpDec->tcxltp_gain_post_prev ) && EQ_16( pitch_int, hTcxLtpDec->tcxltp_pitch_int_post_prev ) && EQ_16( pitch_fr, hTcxLtpDec->tcxltp_pitch_fr_post_prev ) ) + { + tcx_ltp_synth_filter32( sig_out + delay, sig_in + delay, L_transition, pitch_int, pitch_fr, gain, st->pit_res_max, NULL, 0, filtIdx ); + } + ELSE + { + tcx_ltp_get_lpc_fx( sig_out + delay - output_frame, output_frame, A, lpcorder ); + + tcx_ltp_get_zir_fx( zir, L_transition, sig_out + delay - lpcorder, sig_in + delay - lpcorder, A, lpcorder, gain, pitch_int, pitch_fr, st->pit_res_max, filtIdx ); + + tcx_ltp_synth_filter32( sig_out + delay, sig_in + delay, L_transition, pitch_int, pitch_fr, gain, st->pit_res_max, zir, 0, filtIdx ); + } + } + + /******** Current-frame part - subsequent subinterval, filtered with the third filter unit ********/ + + tcx_ltp_synth_filter32( sig_out + ( delay + L_transition ), sig_in + ( delay + L_transition ), output_frame - ( delay + L_transition ), pitch_int, pitch_fr, gain, st->pit_res_max, NULL, 0, filtIdx ); + + + /******** Output ********/ + + + /* copy to output */ + + Copy32( sig_out, sig, output_frame ); + + /* Update */ + hTcxLtpDec->tcxltp_pitch_int_post_prev = pitch_int; + move16(); + hTcxLtpDec->tcxltp_pitch_fr_post_prev = pitch_fr; + move16(); + hTcxLtpDec->tcxltp_gain_post_prev = gain2; + move16(); + hTcxLtpDec->tcxltp_filt_idx_prev = filtIdx; + move16(); + st->pit_res_max_past = st->pit_res_max; + Copy32( sig_out, hTcxLtpDec->tcxltp_mem_out_32, output_frame ); +} diff --git a/lib_dec/core_dec_init.c b/lib_dec/core_dec_init.c index 1d7f47e752af2ff2206e28640f20fc973b945ddb..3ccd51c13bcedf3453c36043e655b0f0a21accd7 100644 --- a/lib_dec/core_dec_init.c +++ b/lib_dec/core_dec_init.c @@ -931,9 +931,16 @@ void tcxltp_dec_init( { set_f( hTcxLtpDec->tcxltp_mem_in_float, 0.0f, TCXLTP_MAX_DELAY ); set_f( hTcxLtpDec->tcxltp_mem_out_float, 0.0f, L_FRAME48k ); +#ifdef IVAS_FLOAT_FIXED + set32_fx(hTcxLtpDec->tcxltp_mem_in_32, 0, TCXLTP_MAX_DELAY); + set32_fx(hTcxLtpDec->tcxltp_mem_out_32, 0, L_FRAME48k); +#endif // IVAS_FLOAT_FIXED hTcxLtpDec->tcxltp_pitch_int_post_prev = 0; hTcxLtpDec->tcxltp_pitch_fr_post_prev = 0; hTcxLtpDec->tcxltp_gain_post_prev_float = 0.f; +#ifdef IVAS_FLOAT_FIXED + hTcxLtpDec->tcxltp_gain_post_prev = 0; +#endif // IVAS_FLOAT_FIXED hTcxLtpDec->tcxltp_filt_idx_prev = -1; } } diff --git a/lib_dec/ivas_post_proc.c b/lib_dec/ivas_post_proc.c index f78373d2f8581ea506a4c2186d0a624c87fb419e..c43a054274006a5fb2038ca457c3b20abf43aaac 100644 --- a/lib_dec/ivas_post_proc.c +++ b/lib_dec/ivas_post_proc.c @@ -149,6 +149,106 @@ void ivas_post_proc( return; } +#ifdef IVAS_FLOAT_FIXED +void ivas_post_proc_fx( + SCE_DEC_HANDLE hSCE, /* i/o: SCE decoder structure */ + CPE_DEC_HANDLE hCPE, /* i/o: CPE decoder structure */ + const Word16 n, /* i : channel number */ + Word32 synth[], /* i/o: output synthesis signal */ + Word32 *output[CPE_CHANNELS], /* i/o: output synthesis signal */ + const Word16 output_frame, /* i : output frame length */ + const Word16 sba_dirac_stereo_flag /* i : signal stereo output for SBA DirAC */ +) +{ + Word16 k; + Word16 delay_comp; + Word32 output_Fs; + Decoder_State **sts; + TCX_LTP_DEC_HANDLE hTcxLtpDec; + + IF( hSCE != NULL ) + { + sts = hSCE->hCoreCoder; + } + ELSE + { + sts = hCPE->hCoreCoder; + } + + output_Fs = sts[0]->output_Fs; + + IF( ( NE_16( sts[n]->element_mode, IVAS_CPE_DFT ) && !( sba_dirac_stereo_flag && NE_16( sts[n]->element_mode, IVAS_CPE_MDCT ) ) ) || ( EQ_16( sts[n]->element_mode, IVAS_CPE_DFT ) && EQ_16( hCPE->nchan_out, 1 ) && EQ_16( hCPE->hStereoDft->hConfig->res_cod_mode, STEREO_DFT_RES_COD_OFF ) ) ) + { + IF( sts[n]->hTcxLtpDec != NULL ) + { + hTcxLtpDec = sts[n]->hTcxLtpDec; + + IF( NE_16( sts[n]->core, TCX_20_CORE ) && NE_16( sts[n]->core, TCX_10_CORE ) ) + { + /* TCX-LTP Postfilter: used in Mode 1 to update memories and to avoid discontinuities when the past frame was TCX */ + tcx_ltp_post32( sts[n], hTcxLtpDec, ACELP_CORE, output_frame, 0, synth, NULL ); + } + ELSE + { + /* set delay */ + delay_comp = NS2SA_fx2( output_Fs, DELAY_CLDFB_NS ); + + IF( !( EQ_16( sts[n]->element_mode, IVAS_CPE_DFT ) && EQ_16( hCPE->nchan_out, 1 ) && EQ_16( hCPE->hStereoDft->hConfig->res_cod_mode, STEREO_DFT_RES_COD_OFF ) ) && NE_16( sts[n]->element_mode, IVAS_CPE_MDCT ) ) + { + // mvr2r( sts[n]->prev_synth_buffer32_fx, sts[n]->hTcxDec->FBTCXdelayBuf_32, 0 ); + Copy32( sts[n]->delay_buf_out32_fx, sts[n]->hTcxDec->FBTCXdelayBuf_32 + 0, delay_comp ); + } + ELSE IF( sba_dirac_stereo_flag && EQ_16( sts[n]->element_mode, IVAS_CPE_MDCT ) ) + { + Word16 numZeros = (Word16) ( NS2SA_fx2( output_Fs, N_ZERO_MDCT_NS ) ); + Copy32( sts[n]->hHQ_core->oldOut_fx + numZeros, sts[n]->hTcxDec->FBTCXdelayBuf_32, delay_comp ); + } + + tcx_ltp_post32( sts[n], hTcxLtpDec, sts[n]->core, output_frame, NS2SA_fx2( output_Fs, ACELP_LOOK_NS ) + delay_comp, synth, sts[n]->hTcxDec->FBTCXdelayBuf_32 ); + } + } + } + ELSE /* IVAS_CPE_DFT */ + { + Word16 pit_res_max_past_tmp; + + pit_res_max_past_tmp = sts[0]->pit_res_max_past; + FOR( k = 0; k < hCPE->nchan_out; k++ ) + { + IF( EQ_16( k, 0 ) ) + { + hTcxLtpDec = sts[0]->hTcxLtpDec; + } + ELSE + { + hTcxLtpDec = hCPE->hStereoDft->hTcxLtpDec; + /* copy LTP side-info of downmix channel also to right channel struct */ + hTcxLtpDec->tcxltp = sts[0]->hTcxLtpDec->tcxltp; + hTcxLtpDec->tcxltp_gain = sts[0]->hTcxLtpDec->tcxltp_gain; + hTcxLtpDec->tcxltp_pitch_int = sts[0]->hTcxLtpDec->tcxltp_pitch_int; + hTcxLtpDec->tcxltp_pitch_fr = sts[0]->hTcxLtpDec->tcxltp_pitch_fr; + /* revert update of pit_res_max_past to have correct value also in right channel */ + sts[0]->pit_res_max_past = pit_res_max_past_tmp; + } + + /*TCX-LTP*/ + IF( NE_16( sts[0]->core, TCX_20_CORE ) && NE_16( sts[0]->core, TCX_10_CORE ) ) + { + /* update memories and to avoid discontinuities when the past frame was TCX */ + tcx_ltp_post32( sts[0], hTcxLtpDec, ACELP_CORE, output_frame, 0, output[k], NULL ); + } + ELSE + { + /*Use channel 0 side info.*/ + tcx_ltp_post32( sts[0], hTcxLtpDec, TCX_20_CORE, output_frame, NS2SA( output_Fs, STEREO_DFT32MS_OVL_NS ), output[k], hCPE->output_mem_fx[k] ); + } + } + } + + return; +} +#endif // IVAS_FLOAT_FIXED + /*------------------------------------------------------------------------- * stereo_dft_dec_core_switching() diff --git a/lib_dec/ivas_stereo_switching_dec.c b/lib_dec/ivas_stereo_switching_dec.c index 250e65daaa29119be55df0c5539fd0c25264cb3c..615a9cb2ea84466b49f721dd1a514bc1edf3fb7c 100644 --- a/lib_dec/ivas_stereo_switching_dec.c +++ b/lib_dec/ivas_stereo_switching_dec.c @@ -36,6 +36,7 @@ #include "rom_com.h" #include "prot.h" #include "ivas_prot.h" +#include "ivas_prot_fx.h" #include "ivas_rom_com.h" #include "assert.h" #include "wmc_auto.h" @@ -1118,7 +1119,86 @@ void synchro_synthesis( if ( hCPE->element_mode != IVAS_CPE_MDCT ) { +#ifdef IVAS_FLOAT_FIXED + Word32 *output_fx[2]; + Word32 op[2][L_FRAME48k]; + output_fx[0] = op[0]; + output_fx[1] = op[1]; + + for ( int p = 0; p < L_FRAME48k; p++ ) + { + output_fx[0][p] = (Word32) ( output[0][p] * ONE_IN_Q14 ); + output_fx[1][p] = (Word32) ( output[1][p] * ONE_IN_Q14 ); + + if ( p < NS2SA( output_Fs, STEREO_DFT32MS_OVL_NS ) ) + { + hCPE->output_mem_fx[0][p] = (Word32) ( hCPE->output_mem[0][p] * ONE_IN_Q14 ); + hCPE->output_mem_fx[1][p] = (Word32) ( hCPE->output_mem[1][p] * ONE_IN_Q14 ); + } + + hCPE->hCoreCoder[0]->hTcxLtpDec->tcxltp_mem_out_32[p] = (Word32) ( hCPE->hCoreCoder[0]->hTcxLtpDec->tcxltp_mem_out_float[p] * ONE_IN_Q14 ); + if ( p < TCXLTP_MAX_DELAY ) + { + hCPE->hCoreCoder[0]->hTcxLtpDec->tcxltp_mem_in_32[p] = (Word32) ( hCPE->hCoreCoder[0]->hTcxLtpDec->tcxltp_mem_in_float[p] * ONE_IN_Q14 ); + } + } + if ( !( ( hCPE->hCoreCoder[0]->element_mode != IVAS_CPE_DFT && !( sba_dirac_stereo_flag && hCPE->hCoreCoder[0]->element_mode != IVAS_CPE_MDCT ) ) || ( hCPE->hCoreCoder[0]->element_mode == IVAS_CPE_DFT && hCPE->nchan_out == 1 && hCPE->hStereoDft->hConfig->res_cod_mode == STEREO_DFT_RES_COD_OFF ) ) ) + { + for ( int p = 0; p < L_FRAME48k; p++ ) + { + hCPE->hStereoDft->hTcxLtpDec->tcxltp_mem_out_32[p] = (Word32) ( hCPE->hStereoDft->hTcxLtpDec->tcxltp_mem_out_float[p] * ONE_IN_Q14 ); + if ( p < TCXLTP_MAX_DELAY ) + { + hCPE->hStereoDft->hTcxLtpDec->tcxltp_mem_in_32[p] = (Word32) ( hCPE->hStereoDft->hTcxLtpDec->tcxltp_mem_in_float[p] * ONE_IN_Q14 ); + } + } + hCPE->hStereoDft->hTcxLtpDec->tcxltp_gain_post_prev = (Word16) ( hCPE->hStereoDft->hTcxLtpDec->tcxltp_gain_post_prev_float * ONE_IN_Q15 ); + hCPE->hStereoDft->hTcxLtpDec->tcxltp_gain = (Word16) ( hCPE->hStereoDft->hTcxLtpDec->tcxltp_gain_float * ONE_IN_Q15 ); + } + hCPE->hCoreCoder[0]->hTcxLtpDec->tcxltp_gain_post_prev = (Word16) ( hCPE->hCoreCoder[0]->hTcxLtpDec->tcxltp_gain_post_prev_float * ONE_IN_Q15 ); + hCPE->hCoreCoder[0]->hTcxLtpDec->tcxltp_gain = (Word16) ( hCPE->hCoreCoder[0]->hTcxLtpDec->tcxltp_gain_float * ONE_IN_Q15 ); + for ( int p = 0; p < 111; p++ ) + { + hCPE->hCoreCoder[0]->hTcxDec->FBTCXdelayBuf_32[p] = (Word32) ( hCPE->hCoreCoder[0]->hTcxDec->FBTCXdelayBuf_float[p] * ONE_IN_Q14 ); + } + + ivas_post_proc_fx( NULL, hCPE, 0, output_fx[0], output_fx, output_frame, sba_dirac_stereo_flag ); + + for ( int p = 0; p < L_FRAME48k; p++ ) + { + output[0][p] = (float) output_fx[0][p] / ONE_IN_Q14; + output[1][p] = (float) output_fx[1][p] / ONE_IN_Q14; + + if ( p < NS2SA( output_Fs, STEREO_DFT32MS_OVL_NS ) ) + { + hCPE->output_mem[0][p] = (float) hCPE->output_mem_fx[0][p] / ONE_IN_Q14; + hCPE->output_mem[1][p] = (float) hCPE->output_mem_fx[1][p] / ONE_IN_Q14; + } + + hCPE->hCoreCoder[0]->hTcxLtpDec->tcxltp_mem_out_float[p] = (float) hCPE->hCoreCoder[0]->hTcxLtpDec->tcxltp_mem_out_32[p] / ONE_IN_Q14; + if ( p < TCXLTP_MAX_DELAY ) + { + hCPE->hCoreCoder[0]->hTcxLtpDec->tcxltp_mem_in_float[p] = (float) hCPE->hCoreCoder[0]->hTcxLtpDec->tcxltp_mem_in_32[p] / ONE_IN_Q14; + } + } + hCPE->hCoreCoder[0]->hTcxLtpDec->tcxltp_gain_post_prev_float = (float) hCPE->hCoreCoder[0]->hTcxLtpDec->tcxltp_gain_post_prev / ONE_IN_Q15; + hCPE->hCoreCoder[0]->hTcxLtpDec->tcxltp_gain_float = (float) hCPE->hCoreCoder[0]->hTcxLtpDec->tcxltp_gain / ONE_IN_Q15; + if ( !( ( hCPE->hCoreCoder[0]->element_mode != IVAS_CPE_DFT && !( sba_dirac_stereo_flag && hCPE->hCoreCoder[0]->element_mode != IVAS_CPE_MDCT ) ) || ( hCPE->hCoreCoder[0]->element_mode == IVAS_CPE_DFT && hCPE->nchan_out == 1 && hCPE->hStereoDft->hConfig->res_cod_mode == STEREO_DFT_RES_COD_OFF ) ) ) + { + for ( int p = 0; p < L_FRAME48k; p++ ) + { + hCPE->hStereoDft->hTcxLtpDec->tcxltp_mem_out_float[p] = (float) hCPE->hStereoDft->hTcxLtpDec->tcxltp_mem_out_32[p] / ONE_IN_Q14; + if ( p < TCXLTP_MAX_DELAY ) + { + hCPE->hStereoDft->hTcxLtpDec->tcxltp_mem_out_float[p] = (float) hCPE->hStereoDft->hTcxLtpDec->tcxltp_mem_out_32[p] / ONE_IN_Q14; + } + } + hCPE->hStereoDft->hTcxLtpDec->tcxltp_gain_post_prev_float = (float) hCPE->hStereoDft->hTcxLtpDec->tcxltp_gain_post_prev / ONE_IN_Q15; + hCPE->hStereoDft->hTcxLtpDec->tcxltp_gain_float = (float) hCPE->hStereoDft->hTcxLtpDec->tcxltp_gain / ONE_IN_Q15; + } +#else ivas_post_proc( NULL, hCPE, 0, output[0], output, output_frame, sba_dirac_stereo_flag ); +#endif // IVAS_FLOAT_FIXED } /* zero padding in order to synchronize the upmixed DFT stereo synthesis with the TD/MDCT stereo synthesis */ @@ -1315,7 +1395,47 @@ void synchro_synthesis( { mvr2r( sts[n]->prev_synth_buffer + delay_comp_DFT, hCPE->hCoreCoder[n]->hTcxDec->FBTCXdelayBuf_float, delay_diff ); delay_signal_float( output[n], output_frame, hCPE->hCoreCoder[n]->hTcxDec->FBTCXdelayBuf_float, delay_diff ); +#ifdef IVAS_FLOAT_FIXED + Word32 *output_fx[2]; + Word32 op[2][L_FRAME48k]; + output_fx[0] = op[0]; + output_fx[1] = op[1]; + for ( int p = 0; p < L_FRAME48k; p++ ) + { + output_fx[0][p] = (Word32) ( output[0][p] * ONE_IN_Q14 ); + output_fx[1][p] = (Word32) ( output[1][p] * ONE_IN_Q14 ); + + hCPE->hCoreCoder[n]->hTcxLtpDec->tcxltp_mem_out_32[p] = (Word32) ( hCPE->hCoreCoder[n]->hTcxLtpDec->tcxltp_mem_out_float[p] * ONE_IN_Q14 ); + if ( p < TCXLTP_MAX_DELAY ) + { + hCPE->hCoreCoder[n]->hTcxLtpDec->tcxltp_mem_in_32[p] = (Word32) ( hCPE->hCoreCoder[n]->hTcxLtpDec->tcxltp_mem_in_float[p] * ONE_IN_Q14 ); + } + } + hCPE->hCoreCoder[n]->hTcxLtpDec->tcxltp_gain_post_prev = (Word16) ( hCPE->hCoreCoder[n]->hTcxLtpDec->tcxltp_gain_post_prev_float * ONE_IN_Q15 ); + hCPE->hCoreCoder[n]->hTcxLtpDec->tcxltp_gain = (Word16) ( hCPE->hCoreCoder[n]->hTcxLtpDec->tcxltp_gain_float * ONE_IN_Q15 ); + for ( int p = 0; p < 111; p++ ) + { + hCPE->hCoreCoder[n]->hTcxDec->FBTCXdelayBuf_32[p] = (Word32) ( hCPE->hCoreCoder[n]->hTcxDec->FBTCXdelayBuf_float[p] * ONE_IN_Q14 ); + } + + ivas_post_proc_fx( NULL, hCPE, n, output_fx[n], output_fx, output_frame, 0 ); + + for ( int p = 0; p < L_FRAME48k; p++ ) + { + output[0][p] = (float) output_fx[0][p] / ONE_IN_Q14; + output[1][p] = (float) output_fx[1][p] / ONE_IN_Q14; + + hCPE->hCoreCoder[n]->hTcxLtpDec->tcxltp_mem_out_float[p] = (float) hCPE->hCoreCoder[n]->hTcxLtpDec->tcxltp_mem_out_32[p] / ONE_IN_Q14; + if ( p < TCXLTP_MAX_DELAY ) + { + hCPE->hCoreCoder[n]->hTcxLtpDec->tcxltp_mem_in_float[p] = (float) hCPE->hCoreCoder[n]->hTcxLtpDec->tcxltp_mem_in_32[p] / ONE_IN_Q14; + } + } + hCPE->hCoreCoder[n]->hTcxLtpDec->tcxltp_gain_post_prev_float = (float) hCPE->hCoreCoder[n]->hTcxLtpDec->tcxltp_gain_post_prev / ONE_IN_Q15; + hCPE->hCoreCoder[n]->hTcxLtpDec->tcxltp_gain_float = (float) hCPE->hCoreCoder[n]->hTcxLtpDec->tcxltp_gain / ONE_IN_Q15; +#else ivas_post_proc( NULL, hCPE, n, output[n], output, output_frame, 0 ); +#endif // IVAS_FLOAT_FIXED delay_signal_float( output[n], output_frame, sts[n]->prev_synth_buffer, delay_comp_DFT ); mvr2r( hCPE->hCoreCoder[n]->hTcxDec->FBTCXdelayBuf_float, sts[n]->prev_synth_buffer + delay_comp_DFT, delay_diff ); } diff --git a/lib_dec/stat_dec.h b/lib_dec/stat_dec.h index 663b5f2ee26f39a0238f150b478352d65c3cba3c..5a9f0b7dfab78cf6149fc950902eba57ff52d61d 100644 --- a/lib_dec/stat_dec.h +++ b/lib_dec/stat_dec.h @@ -524,12 +524,14 @@ typedef struct tcx_ltp_dec_structure float tcxltp_mem_in_float[TCXLTP_MAX_DELAY]; Word16 tcxltp_mem_in[TCXLTP_MAX_DELAY]; + Word32 tcxltp_mem_in_32[TCXLTP_MAX_DELAY]; #ifdef IVAS_FLOAT_FIXED Word16 exp_tcxltp_mem_in; #endif float tcxltp_mem_out_float[L_FRAME48k]; Word16 tcxltp_mem_out[L_FRAME48k]; + Word32 tcxltp_mem_out_32[L_FRAME48k]; #ifdef IVAS_FLOAT_FIXED Word16 exp_tcxltp_mem_out; #endif @@ -608,6 +610,7 @@ typedef struct tcx_dec_structure float FBTCXdelayBuf_float[111]; /* 2.3125ms at 48kHz -> 111 samples */ Word16 FBTCXdelayBuf[111]; /* 2.3125ms at 48kHz -> 111 samples */ + Word32 FBTCXdelayBuf_32[111]; /* 2.3125ms at 48kHz -> 111 samples */ /*TCX resisual Q*/ @@ -2172,6 +2175,7 @@ typedef struct Decoder_State float delay_buf_out[HQ_DELTA_MAX * HQ_DELAY_COMP]; Word16 delay_buf_out_fx[HQ_DELTA_MAX * HQ_DELAY_COMP]; /*Q0*/ + Word32 delay_buf_out32_fx[HQ_DELTA_MAX * HQ_DELAY_COMP]; /*Q0*/ #ifdef IVAS_FLOAT_FIXED Word16 exp_delay_buf_out; #endif