From 8d6f1d53aee5350306d6ac60902d61ee8afd7ed8 Mon Sep 17 00:00:00 2001 From: Arnaud Lefort Date: Wed, 5 Nov 2025 09:41:09 +0100 Subject: [PATCH] Fix for issue 2184. --- lib_com/options.h | 2 + lib_enc/ivas_stat_enc.h | 12 +- lib_enc/ivas_stereo_dmx_evs_fx.c | 310 +++++++++++++++++++++++++++++-- 3 files changed, 301 insertions(+), 23 deletions(-) diff --git a/lib_com/options.h b/lib_com/options.h index c1a258bcf..0799870f6 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -93,6 +93,8 @@ #define FIX_2176_ASSERT_DEC_MAP_PARAMS_DIRAC2STEREO /* FhG: Reduce hStereoDft->q_smooth_buf_fx by one to prevent overflow in the subframe_band_nrg[][] calculation */ #define FIX_2015_PREMPH_SAT_ALT /* VA: saturation can happen during preemphasis filtering due to a too aggressive scaling factor, allows preemphis to get 1 more bit headroom */ + +#define FIX_2184_EVS_STEREO_DMX_CHANNEL_DISAPPEARING /* Orange: Fix for issue 2184 - to prevent one channel from becoming inaudible in the mono downmix output */ /* ################### End FIXES switches ########################### */ /* #################### Start BASOP porting switches ############################ */ diff --git a/lib_enc/ivas_stat_enc.h b/lib_enc/ivas_stat_enc.h index e3f40478e..6cad0ac68 100644 --- a/lib_enc/ivas_stat_enc.h +++ b/lib_enc/ivas_stat_enc.h @@ -1184,8 +1184,14 @@ typedef struct stereo_dmx_evs_phase_only_correlation_structure typedef struct stereo_dmx_evs_correlation_filter_structure { - Word32 isd_rate_s_fx; // Q31 - Word32 iccr_s_fx; // Q31 + Word32 isd_rate_s_fx; // Q31 + Word32 iccr_s_fx; // Q31 +#ifdef FIX_2184_EVS_STEREO_DMX_CHANNEL_DISAPPEARING + Word32 phitd_fx; // Q15 + Word32 iccres_s_fx; // Q31 + Word32 lvlin_fx[CPE_CHANNELS]; + Word16 lvlin_fx_e[CPE_CHANNELS]; +#endif Word32 ipd_ff_fx[STEREO_DMX_EVS_NB_SUBBAND_MAX]; // Q31 Word32 Pr_fx[STEREO_DMX_EVS_NB_SUBBAND_MAX]; // Q31 Word32 Pi_fx[STEREO_DMX_EVS_NB_SUBBAND_MAX]; // Q31 @@ -1194,7 +1200,6 @@ typedef struct stereo_dmx_evs_correlation_filter_structure Word16 pha_len; Word16 fad_len; - Word16 win_fx[STEREO_DMX_EVS_PHA_LEN_MAX]; // Q14 Word32 fad_g_fx[STEREO_DMX_EVS_FAD_LEN_MAX]; // Q31 Word32 *p_prev_taps_fx[CPE_CHANNELS], prev_taps_fx[CPE_CHANNELS][STEREO_DMX_EVS_PHA_LEN_MAX]; // Q31 @@ -1223,7 +1228,6 @@ typedef struct stereo_dmx_evs_correlation_filter_structure Word32 fad_g_prc_fx[L_FRAME48k]; // Q31 Word16 fad_len_prc; - Word32 trns_aux_energy_fx[CPE_CHANNELS]; Word16 trns_aux_energy_fx_e[CPE_CHANNELS]; Word32 crst_fctr_fx; // Q0 diff --git a/lib_enc/ivas_stereo_dmx_evs_fx.c b/lib_enc/ivas_stereo_dmx_evs_fx.c index 852be98fe..73f7e246c 100644 --- a/lib_enc/ivas_stereo_dmx_evs_fx.c +++ b/lib_enc/ivas_stereo_dmx_evs_fx.c @@ -77,6 +77,16 @@ #define STEREO_DMX_EVS_ICCR_HYST_L_Q31 1610612736 #define STEREO_DMX_EVS_ICCR_HYST_H_Q31 1825361101 +#ifdef FIX_2184_EVS_STEREO_DMX_CHANNEL_DISAPPEARING +#define STEREO_DMX_EVS_ICCRES_FORGETTING_Q31 1975684956 +#define STEREO_DMX_EVS_LVLU_FORGETTING_Q31 1073741824 +#define STEREO_DMX_EVS_LVLD_FORGETTING_Q31 1975684956 +#define STEREO_DMX_EVS_ICLD_THRESH_FX 1610612736 +#define STEREO_DMX_EVS_ICLD_THRESH_FX_E 2 +#define STEREO_DMX_EVS_ICCRES_THRESH_Q31 858993459 +#define STEREO_DMX_EVS_DICLD_THRESH_Q30 1606570807 +#endif + #define STEREO_DMX_EVS_SWTCH_HYS_THRES 1 #define STEREO_DMX_EVS_LR_EGY_Q27 2013265920 #define STEREO_DMX_EVS_ILDS_EGY_Q17 1310720000 @@ -194,6 +204,31 @@ static void weighted_ave_fx( const Word16 input_frame, /* i : input frame length per channel */ const Word32 wnd_fx[] /* i : window coef Q31 */ ); +#ifdef FIX_2184_EVS_STEREO_DMX_CHANNEL_DISAPPEARING +static void calc_energy_fx( + const Word32 src1_fx[], /* i : Lch input signal */ + const Word32 src2_fx[], /* i : Rch input signal */ + Word32 energy_fx[], /* o : calculated energy */ + Word16 *energy_fx_e, /* o : calculated energy */ + Word32 *lvl_fx, /* i/o: signal level lvl_fx_e */ + Word16 *lvl_fx_e, /* i/o: signal level */ + const Word16 input_frame, /* i : input frame length per channel */ + const Word32 ratio_float_fx ); +static void create_M_signal_fx( + const Word32 srcL_fx[], /* i : Lch input signal Q16 */ + const Word32 srcR_fx[], /* i : Rch input signal Q16 */ + Word32 dmx_fx[], /* o : output signal Q31 */ + const Word32 w_curr_fx, /* i : adapting weight Q31 */ + const Word16 input_frame, /* i : input frame length per channel */ + const Word32 wnd_fx[], /* i : window coef Q31 */ + Word32 *w_prev_fx, /* i/o: adapting prev weight Q31 */ + Word32 *dmx_energy_fx, /* i/o: downmix signal energy dmx_energy_fx_e */ + Word16 *dmx_energy_fx_e, /* i/o: downmix signal energy */ + Word32 *src_energy_fx, /* i/o: input signal energy src_energy_fx_e */ + Word16 *src_energy_fx_e, /* i/o: input signal energy */ + STEREO_DMX_EVS_PHA_HANDLE hPHA /* i/o: correlation filter structure */ +); +#else static void calc_energy_fx( const Word32 src1_fx[], /* i : Lch input signal */ const Word32 src2_fx[], /* i : Rch input signal */ @@ -201,20 +236,20 @@ static void calc_energy_fx( Word16 *energy_fx_e, /* o : calculated energy */ const Word16 input_frame, /* i : input frame length per channel */ const Word32 ratio_float_fx ); - static void create_M_signal_fx( const Word32 srcL_fx[], /* i : Lch input signal Q16 */ const Word32 srcR_fx[], /* i : Rch input signal Q16 */ Word32 dmx_fx[], /* o : output signal Q31 */ const Word32 w_curr_fx, /* i : adapting weight Q31 */ - const Word16 input_frame, /* i : input frame length per channel */ + const Word16 input_frame, /* i : input frame length per channel */ const Word32 wnd_fx[], /* i : window coef Q31 */ - Word32 *w_prev_fx, /* i/o: adapting prev weight Q31*/ + Word32 *w_prev_fx, /* i/o: adapting prev weight Q31 */ Word32 *dmx_energy_fx, /* i/o: downmix signal energy dmx_energy_fx_e */ - Word16 *dmx_energy_fx_e, /* i/o: downmix signal energy */ + Word16 *dmx_energy_fx_e, /* i/o: downmix signal energy */ Word32 *src_energy_fx, /* i/o: input signal energy src_energy_fx_e */ Word16 *src_energy_fx_e /* i/o: input signal energy */ ); +#endif static Word32 find_poc_peak_fx( STEREO_DMX_EVS_POC_HANDLE hPOC, /* i/o: phase only correlation structure */ Word16 itd_fx[], /* o : estimated itd */ @@ -728,6 +763,13 @@ static void calc_poc_fx( move32(); eneR_e = 0; move16(); +#ifdef FIX_2184_EVS_STEREO_DMX_CHANNEL_DISAPPEARING + step = sub( n0 >> 3, 1 ); + tmp1 = 0; + tmp2 = 0; + n1 = 0; + n2 = 0; +#endif FOR( ( n = 1, i = 1 ); n < nsbd; n++ ) { @@ -824,6 +866,16 @@ static void calc_poc_fx( W_tmp = W_shl( W_tmp, L_tmp_e ); } eneR = BASOP_Util_Add_Mant32Exp( eneR, eneR_e, W_round64_L( W_tmp ), sub( 1, L_tmp_e ), &eneR_e ); + +#ifdef FIX_2184_EVS_STEREO_DMX_CHANNEL_DISAPPEARING + IF( EQ_16( i, step ) ) + { + tmp1 = eneL; + n1 = eneL_e; + tmp2 = eneR; + n2 = eneR_e; + } +#endif } // Pn = (float) inv_sqrt( ( tPr * tPr + tPi * tPi ) + EPSILON ); @@ -854,8 +906,12 @@ static void calc_poc_fx( } /* Computes Spectral flatness on one channel */ +#ifdef FIX_2184_EVS_STEREO_DMX_CHANNEL_DISAPPEARING + IF( LT_32( spectral_flatness_fx( &tEl[1], &tEl_e[1], sub( nsbd, 1 ) ), STEREO_DMX_EVS_IPD_SF_THRES_Q31 ) ) +#else tmp1 = spectral_flatness_fx( &tEl[1], &tEl_e[1], nsbd - 1 ); IF( LT_32( tmp1, STEREO_DMX_EVS_IPD_SF_THRES_Q31 ) ) +#endif { hPHA->pha_ipd_chanswitch_allowed = 0; move16(); @@ -879,6 +935,82 @@ static void calc_poc_fx( hPHA->iccr_s_fx = L_add( Mpy_32_32_r( STEREO_DMX_EVS_ICCR_FORGETTING_Q31, hPHA->iccr_s_fx ), Mpy_32_32_r( MAX_32 - STEREO_DMX_EVS_ICCR_FORGETTING_Q31, ICCr ) ); // Q31 move32(); +#ifdef FIX_2184_EVS_STEREO_DMX_CHANNEL_DISAPPEARING + step = add( step, 1 ); + + eneL = BASOP_Util_Add_Mant32Exp( eneL, eneL_e, -tmp1, n1, &eneL_e ); + eneR = BASOP_Util_Add_Mant32Exp( eneR, eneR_e, -tmp2, n2, &eneR_e ); + + mult_angle = extract_l( imult3216( hPHA->phitd_fx, step ) ); // Remainder in Q15 + tmp1 = L_shr( imult3216( EVS_2PI_FX, mult_angle ), Q15 ); // Q13 + IF( GT_32( tmp1, EVS_PI_FX ) ) + { + tmp1 = L_sub( tmp1, EVS_2PI_FX ); + } + ELSE IF( LT_32( tmp1, -EVS_PI_FX ) ) + { + tmp1 = L_add( tmp1, EVS_2PI_FX ); + } + mult_angle = extract_l( tmp1 ); + IPDr = L_deposit_h( getCosWord16( mult_angle ) ); + IPDr = L_shl_sat( IPDr, 1 ); + IPDi = L_deposit_h( getSinWord16( mult_angle ) ); + + mult_angle = extract_l( hPHA->phitd_fx ); // Remainder in Q15 + tmp1 = L_shr( imult3216( EVS_2PI_FX, mult_angle ), Q15 ); // Q13 + IF( GT_32( tmp1, EVS_PI_FX ) ) + { + tmp1 = L_sub( tmp1, EVS_2PI_FX ); + } + ELSE IF( LT_32( tmp1, -EVS_PI_FX ) ) + { + tmp1 = L_add( tmp1, EVS_2PI_FX ); + } + mult_angle = extract_l( tmp1 ); + L_tmp1 = L_deposit_h( getCosWord16( mult_angle ) ); + L_tmp1 = L_shl_sat( L_tmp1, 1 ); + L_tmp2 = L_deposit_h( getSinWord16( mult_angle ) ); + + Nr = 0; + move32(); + Nr_e = 0; + move16(); + Ni = 0; + move32(); + Ni_e = 0; + + n1 = sub( n0, 1 ); + FOR( i = step; i < n1; i++ ) + { + tIPDr = L_add( Mpy_32_32_r( specRr[i], IPDr ), Mpy_32_32_r( specRi[i], IPDi ) ); + tIPDi = L_sub( Mpy_32_32_r( specRr[i], IPDi ), Mpy_32_32_r( specRi[i], IPDr ) ); + + Nr = BASOP_Util_Add_Mant32Exp( Nr, Nr_e, L_sub( Mpy_32_32_r( specLr[i], tIPDr ), Mpy_32_32_r( specLi[i], tIPDi ) ), 0, &Nr_e ); + Ni = BASOP_Util_Add_Mant32Exp( Ni, Ni_e, L_add( Mpy_32_32_r( specLi[i], tIPDr ), Mpy_32_32_r( specLr[i], tIPDi ) ), 0, &Ni_e ); + + tIPDr = IPDr; + move32(); + IPDr = L_sub_sat( Mpy_32_32_r( tIPDr, L_tmp1 ), Mpy_32_32_r( IPDi, L_tmp2 ) ); + IPDi = L_add_sat( Mpy_32_32_r( tIPDr, L_tmp2 ), Mpy_32_32_r( IPDi, L_tmp1 ) ); + } + + if ( EQ_32( ICCr, 0 ) ) + { + ICCr = ONE_IN_Q31; + move32(); + } + + L_tmp1 = BASOP_Util_Add_Mant32Exp( Mpy_32_32_r( Nr, Nr ), shl( Nr_e, 1 ), Mpy_32_32_r( Ni, Ni ), shl( Ni_e, 1 ), &L_tmp1_e ); + L_tmp2 = BASOP_Util_Add_Mant32Exp( Mpy_32_32_r( eneL, eneR ), add( eneL_e, eneR_e ), EPSILON_FX_M, EPSILON_FX_E, &L_tmp2_e ); + + L_tmp2 = BASOP_Util_Add_Mant32Exp( Mpy_32_32_r( eneL, eneR ), add( eneL_e, eneR_e ), EPSILON_FX_M, EPSILON_FX_E, &L_tmp2_e ); + L_tmp = BASOP_Util_Divide3232_Scale_newton( L_tmp1, L_tmp2, &L_tmp_e ); + L_tmp_e = add( L_tmp_e, sub( L_tmp1_e, L_tmp2_e ) ); + L_tmp = Sqrt32( L_tmp, &L_tmp_e ); + L_tmp = L_shl_sat( L_tmp, L_tmp_e ); // Q31 + + hPHA->iccres_s_fx = L_add( Mpy_32_32_r( STEREO_DMX_EVS_ICCRES_FORGETTING_Q31, hPHA->iccres_s_fx ), Mpy_32_32_r( L_sub( MAX_32, STEREO_DMX_EVS_ICCRES_FORGETTING_Q31 ), L_add_sat( ICCr >> 1, L_tmp >> 1 ) ) ); // Q31 +#endif IF( EQ_32( hPHA->curr_pha, STEREO_DMX_EVS_PHA_IPD ) ) { @@ -1437,7 +1569,11 @@ static Word32 find_poc_peak_fx( move16(); move16(); move16(); +#ifdef FIX_2184_EVS_STEREO_DMX_CHANNEL_DISAPPEARING + IF( Q_fx[n] == 0 ) +#else if ( Q_fx[n] == 0 ) +#endif { Q_e[n] = 0; move16(); @@ -1823,17 +1959,33 @@ static void renorm_poc_fx( * * calculate energy *-------------------------------------------------------------------*/ -static void calc_energy_fx( - const Word32 src1_fx[], /* i : Lch input signal Q16*/ - const Word32 src2_fx[], /* i : Rch input signal Q16 */ - Word32 energy_fx[], /* o : calculated energy energy_fx_e*/ - Word16 *energy_fx_e, /* o : calculated energy */ - const Word16 input_frame, /* i : input frame length per channel */ - const Word32 ratio_float_fx // Q31 -) +#ifdef FIX_2184_EVS_STEREO_DMX_CHANNEL_DISAPPEARING +void calc_energy_fx( + const Word32 src1_fx[], /* i : Lch input signal */ + const Word32 src2_fx[], /* i : Rch input signal */ + Word32 energy_fx[], /* o : calculated energy */ + Word16 *energy_fx_e, /* o : calculated energy */ + Word32 *lvl_fx, /* i/o: signal level lvl_fx_e */ + Word16 *lvl_fx_e, /* i/o: signal level */ + const Word16 input_frame, /* i : input frame length per channel */ + const Word32 ratio_float_fx ) +#else +void calc_energy_fx( + const Word32 src1_fx[], /* i : Lch input signal */ + const Word32 src2_fx[], /* i : Rch input signal */ + Word32 energy_fx[], /* o : calculated energy */ + Word16 *energy_fx_e, /* o : calculated energy */ + const Word16 input_frame, /* i : input frame length per channel */ + const Word32 ratio_float_fx ) +#endif { +#ifdef FIX_2184_EVS_STEREO_DMX_CHANNEL_DISAPPEARING + Word32 E_32_fx, wnd_fx, wnd_diff_fx, lvli_fx, lvlff_fx; + Word16 i, adaptlen, lvli_fx_e; +#else Word32 E_32_fx, wnd_fx, wnd_diff_fx; Word16 i, adaptlen; +#endif Word64 E_fx; /* Initialization */ @@ -1898,6 +2050,24 @@ static void calc_energy_fx( *energy_fx = BASOP_Util_Add_Mant32Exp( Mpy_32_32( *energy_fx, ratio_float_fx ), *energy_fx_e, Mpy_32_32( temp32, L_sub( MAX_32, ratio_float_fx ) ), sub( 31, q_temp32 ), energy_fx_e ); move32(); +#ifdef FIX_2184_EVS_STEREO_DMX_CHANNEL_DISAPPEARING + IF( ( lvl_fx != NULL ) && ( lvl_fx_e != NULL ) ) + { + E_32_fx = BASOP_Util_Add_Mant32Exp( E_32_fx, sub( 31, q_E ), EPSILON_FX_M, EPSILON_FX_E, &temp_e ); + lvli_fx = BASOP_Util_Log10( E_32_fx, temp_e ); + lvli_fx_e = 6; // +6 : compensate result of log in Q25 + IF( EQ_16( BASOP_Util_Cmp_Mant32Exp( lvli_fx, lvli_fx_e, *lvl_fx, *lvl_fx_e ), 1 ) ) + { + lvlff_fx = STEREO_DMX_EVS_LVLU_FORGETTING_Q31; + } + ELSE + { + lvlff_fx = STEREO_DMX_EVS_LVLD_FORGETTING_Q31; + } + *lvl_fx = BASOP_Util_Add_Mant32Exp( Mpy_32_32( *lvl_fx, lvlff_fx ), *lvl_fx_e, Mpy_32_32( lvli_fx, L_sub( MAX_32, lvlff_fx ) ), lvli_fx_e, lvl_fx_e ); // Q(31 - *lvli_fx_e) + } +#endif + return; } @@ -1987,19 +2157,36 @@ static void adapt_gain_fx( * * create downmix signal *-------------------------------------------------------------------*/ -static void create_M_signal_fx( +#ifdef FIX_2184_EVS_STEREO_DMX_CHANNEL_DISAPPEARING +void create_M_signal_fx( + const Word32 srcL_fx[], /* i : Lch input signal Q16 */ + const Word32 srcR_fx[], /* i : Rch input signal Q16 */ + Word32 dmx_fx[], /* o : output signal Q31 */ + const Word32 w_curr_fx, /* i : adapting weight Q31 */ + const Word16 input_frame, /* i : input frame length per channel */ + const Word32 wnd_fx[], /* i : window coef Q31 */ + Word32 *w_prev_fx, /* i/o: adapting prev weight Q31 */ + Word32 *dmx_energy_fx, /* i/o: downmix signal energy dmx_energy_fx_e */ + Word16 *dmx_energy_fx_e, /* i/o: downmix signal energy */ + Word32 *src_energy_fx, /* i/o: input signal energy src_energy_fx_e */ + Word16 *src_energy_fx_e, /* i/o: input signal energy */ + STEREO_DMX_EVS_PHA_HANDLE hPHA /* i/o: correlation filter structure */ +) +#else +void create_M_signal_fx( const Word32 srcL_fx[], /* i : Lch input signal Q16 */ const Word32 srcR_fx[], /* i : Rch input signal Q16 */ Word32 dmx_fx[], /* o : output signal Q31 */ const Word32 w_curr_fx, /* i : adapting weight Q31 */ - const Word16 input_frame, /* i : input frame length per channel */ + const Word16 input_frame, /* i : input frame length per channel */ const Word32 wnd_fx[], /* i : window coef Q31 */ - Word32 *w_prev_fx, /* i/o: adapting prev weight Q31*/ + Word32 *w_prev_fx, /* i/o: adapting prev weight Q31 */ Word32 *dmx_energy_fx, /* i/o: downmix signal energy dmx_energy_fx_e */ - Word16 *dmx_energy_fx_e, /* i/o: downmix signal energy */ + Word16 *dmx_energy_fx_e, /* i/o: downmix signal energy */ Word32 *src_energy_fx, /* i/o: input signal energy src_energy_fx_e */ Word16 *src_energy_fx_e /* i/o: input signal energy */ ) +#endif { Word32 amp_mod_fx[CPE_CHANNELS]; Word32 weighted_fx[L_FRAME48k], Lbias_fx; @@ -2022,9 +2209,15 @@ static void create_M_signal_fx( move32(); } weighted_ave_fx( srcL_fx, srcR_fx, dmx_fx, w_curr_fx, w_prev_fx[0], input_frame, wnd_fx ); +#ifdef FIX_2184_EVS_STEREO_DMX_CHANNEL_DISAPPEARING + calc_energy_fx( srcL_fx, srcL_fx, src_energy_fx, src_energy_fx_e, hPHA->lvlin_fx, hPHA->lvlin_fx_e, input_frame, STEREO_DMX_EVS_DMX_EGY_FORGETTING_FX ); + calc_energy_fx( srcR_fx, srcR_fx, src_energy_fx + 1, src_energy_fx_e + 1, hPHA->lvlin_fx + 1, hPHA->lvlin_fx_e + 1, input_frame, STEREO_DMX_EVS_DMX_EGY_FORGETTING_FX ); + calc_energy_fx( dmx_fx, dmx_fx, dmx_energy_fx, dmx_energy_fx_e, NULL, NULL, input_frame, STEREO_DMX_EVS_DMX_EGY_FORGETTING_FX ); +#else calc_energy_fx( srcL_fx, srcL_fx, src_energy_fx, src_energy_fx_e, input_frame, STEREO_DMX_EVS_DMX_EGY_FORGETTING_FX ); calc_energy_fx( srcR_fx, srcR_fx, src_energy_fx + 1, src_energy_fx_e + 1, input_frame, STEREO_DMX_EVS_DMX_EGY_FORGETTING_FX ); calc_energy_fx( dmx_fx, dmx_fx, dmx_energy_fx, dmx_energy_fx_e, input_frame, STEREO_DMX_EVS_DMX_EGY_FORGETTING_FX ); +#endif temp32_1 = Mpy_32_32( src_energy_fx[0], Lbias_fx ); // 31 - src_energy_fx_e + Q28-31 temp_e_1 = add( src_energy_fx_e[0], 3 ); @@ -2147,7 +2340,16 @@ void stereo_dmx_evs_enc_fx( Word32 dmx_poc_data[L_FRAME48k] /*Q11*/, dmx_pha_data[L_FRAME48k] /*Q11*/, *p_dmx_data, fx_tmp, *p_dmx_data_fo; Word16 n_fad_r, n_fad_g, m_fad_g, n_fad_cnt; +#ifdef FIX_2184_EVS_STEREO_DMX_CHANNEL_DISAPPEARING + STEREO_DMX_EVS_PRC prev_prc, req_prc; + Word32 L_tmp1, L_tmp2, L_dmx_weight, icld_fx; + Word16 L_tmp1_e, L_tmp2_e, icld_fx_e; +#else STEREO_DMX_EVS_PRC prev_prc; + Word32 L_tmp1, L_tmp2; + Word16 L_tmp1_e, L_tmp2_e; +#endif + STEREO_DMX_EVS_PHA_HANDLE hPHA; Word16 input_subframe, is_transient, dmx_gain_sgc; @@ -2156,9 +2358,6 @@ void stereo_dmx_evs_enc_fx( Word16 input_frame; - Word32 L_tmp1, L_tmp2; - Word16 L_tmp1_e, L_tmp2_e; - Word64 W_tmp; Word16 W_tmp_q; @@ -2231,7 +2430,9 @@ void stereo_dmx_evs_enc_fx( move16(); FOR( k = 0; k < CPE_CHANNELS; k++ ) { +#ifndef FIX_2184_EVS_STEREO_DMX_CHANNEL_DISAPPEARING fx_tmp = 0; +#endif move32(); FOR( m = 0; m < STEREO_DMX_EVS_NB_SBFRM; m++ ) { @@ -2273,7 +2474,11 @@ void stereo_dmx_evs_enc_fx( L_tmp2 = BASOP_Util_Divide3232_Scale_newton( subframe_energy[m], L_tmp1, &L_tmp2_e ); L_tmp2_e = add( L_tmp2_e, sub( subframe_energy_e[m], L_tmp1_e ) ); // if ( subframe_energy[m] / ( subframe_energy[m - 1] + EPSILON ) > STEREO_DMX_EVS_TRNS_DTC_INST ) +#ifdef FIX_2184_EVS_STEREO_DMX_CHANNEL_DISAPPEARING + IF( BASOP_Util_Cmp_Mant32Exp( L_tmp2, L_tmp2_e, STEREO_DMX_EVS_TRNS_DTC_INST_Q0, 31 ) > 0 ) +#else if ( BASOP_Util_Cmp_Mant32Exp( L_tmp2, L_tmp2_e, STEREO_DMX_EVS_TRNS_DTC_INST_Q0, 31 ) > 0 ) +#endif { is_transient = 1; move16(); @@ -2303,8 +2508,16 @@ void stereo_dmx_evs_enc_fx( move16(); } +#ifdef FIX_2184_EVS_STEREO_DMX_CHANNEL_DISAPPEARING + L_dmx_weight = L_deposit_h( dmx_weight ); + L_tmp1 = L_deposit_l( BASOP_Util_Divide1616_Scale( hStereoDmxEVS->itd_fx, input_frame, &L_tmp1_e ) ); + hPHA->phitd_fx = L_shl( L_tmp1, L_tmp1_e ); // Q15 + create_M_signal_fx( data_fx[0], data_fx[1], dmx_poc_data, L_dmx_weight, input_frame, hStereoDmxEVS->s_wnd_fx, + hStereoDmxEVS->dmx_weight_fx, hStereoDmxEVS->pre_dmx_energy_fx, hStereoDmxEVS->pre_dmx_energy_fx_e, hStereoDmxEVS->aux_dmx_energy_fx, hStereoDmxEVS->aux_dmx_energy_fx_e, hPHA ); +#else create_M_signal_fx( data_fx[0], data_fx[1], dmx_poc_data, L_deposit_h( dmx_weight ), input_frame, hStereoDmxEVS->s_wnd_fx, hStereoDmxEVS->dmx_weight_fx, hStereoDmxEVS->pre_dmx_energy_fx, hStereoDmxEVS->pre_dmx_energy_fx_e, hStereoDmxEVS->aux_dmx_energy_fx, hStereoDmxEVS->aux_dmx_energy_fx_e ); +#endif // Downscaling signals to avoid accumulation overflows scale_sig32( data_fx[0], input_frame, -5 ); // Q31->Q26 @@ -2396,6 +2609,50 @@ void stereo_dmx_evs_enc_fx( move32(); // if ( abs( (int16_t) hStereoDmxEVS->itd ) > hPHA->prc_thres ) IF( GT_16( abs_s( hStereoDmxEVS->itd_fx ), hPHA->prc_thres ) ) +#ifdef FIX_2184_EVS_STEREO_DMX_CHANNEL_DISAPPEARING + { + req_prc = STEREO_DMX_EVS_PRC_POC; + move32(); + + icld_fx = L_abs( BASOP_Util_Add_Mant32Exp( hPHA->lvlin_fx[0], hPHA->lvlin_fx_e[0], L_negate( hPHA->lvlin_fx[1] ), hPHA->lvlin_fx_e[1], &( icld_fx_e ) ) ); + L_tmp1 = L_add( L_shr_r( L_dmx_weight, 1 ), L_shr_r( hStereoDmxEVS->dmx_weight_fx[1], 1 ) ); // Q30 + L_tmp2 = L_add( L_sub( ONE_IN_Q30, L_shr_r( L_dmx_weight, 1 ) ), L_shr_r( hStereoDmxEVS->dmx_weight_fx[2], 1 ) ); // Q30 + + IF( ( BASOP_Util_Cmp_Mant32Exp( L_abs( icld_fx ), icld_fx_e, STEREO_DMX_EVS_ICLD_THRESH_FX, STEREO_DMX_EVS_ICLD_THRESH_FX_E ) < 0 ) && LT_32( hPHA->iccres_s_fx, STEREO_DMX_EVS_ICCRES_THRESH_Q31 ) && ( GT_32( L_shr_r( L_tmp1, 1 ), Mpy_32_32( STEREO_DMX_EVS_DICLD_THRESH_Q30, L_tmp2 ) ) || GT_32( L_shr_r( L_tmp2, 1 ), Mpy_32_32( STEREO_DMX_EVS_DICLD_THRESH_Q30, L_tmp1 ) ) ) ) + { + req_prc = STEREO_DMX_EVS_PRC_PHA; + move32(); + } + } + ELSE + { + req_prc = STEREO_DMX_EVS_PRC_PHA; + move32(); + } + + // Set mode with hysteresis + IF( NE_32( hPHA->curr_prc, req_prc ) ) + { + IF( EQ_32( hPHA->prev_prc, req_prc ) ) + { + hPHA->prc_hys_cnt = add( hPHA->prc_hys_cnt, 1 ); + move16(); + } + ELSE + { + hPHA->prc_hys_cnt = 0; + move16(); + } + + IF( GE_16( hPHA->prc_hys_cnt, STEREO_DMX_EVS_SWTCH_PRC_HYS_THRES ) ) + { + hPHA->curr_prc = req_prc; + move32(); + } + } + hPHA->prev_prc = req_prc; + move32(); +#else { IF( NE_32( hPHA->curr_prc, STEREO_DMX_EVS_PRC_POC ) ) { @@ -2409,6 +2666,7 @@ void stereo_dmx_evs_enc_fx( hPHA->prc_hys_cnt = 0; move16(); } + IF( GE_16( hPHA->prc_hys_cnt, STEREO_DMX_EVS_SWTCH_PRC_HYS_THRES ) ) { hPHA->curr_prc = STEREO_DMX_EVS_PRC_POC; @@ -2442,6 +2700,7 @@ void stereo_dmx_evs_enc_fx( hPHA->prev_prc = STEREO_DMX_EVS_PRC_PHA; move32(); } +#endif // if ( ( is_transient == 1 ) || ( hStereoDmxEVS->aux_dmx_energy[0] > STEREO_DMX_EVS_ILDS_EGY * hStereoDmxEVS->aux_dmx_energy[1] ) || ( hStereoDmxEVS->aux_dmx_energy[1] > STEREO_DMX_EVS_ILDS_EGY * hStereoDmxEVS->aux_dmx_energy[0] ) || ( ( hPHA->p_curr_taps[0] == NULL ) && ( hPHA->p_curr_taps[1] == NULL ) ) ) test(); @@ -2892,6 +3151,19 @@ ivas_error stereo_dmx_evs_init_encoder_fx( hStereoDmxEVS->hPHA->iccr_s_fx = 0; move32(); +#ifdef FIX_2184_EVS_STEREO_DMX_CHANNEL_DISAPPEARING + hStereoDmxEVS->hPHA->phitd_fx = 0; + hStereoDmxEVS->hPHA->iccres_s_fx = 0; + move32(); + FOR( n = 0; n < CPE_CHANNELS; n++ ) + { + hStereoDmxEVS->hPHA->lvlin_fx[n] = 0; + move32(); + hStereoDmxEVS->hPHA->lvlin_fx_e[n] = 0; + move16(); + } +#endif + pha_len = hStereoDmxEVS->hPHA->pha_len; move16(); fad_len = hStereoDmxEVS->hPHA->fad_len; -- GitLab