From b34e188dc5a26f8a3684ea851767580b82c4a03e Mon Sep 17 00:00:00 2001 From: Arnaud Lefort Date: Wed, 5 Nov 2025 16:26:47 +0100 Subject: [PATCH] Porting to float main of fix for basop issue 2184. --- lib_com/options.h | 2 + lib_enc/ivas_stat_enc.h | 6 ++ lib_enc/ivas_stereo_dmx_evs.c | 168 +++++++++++++++++++++++++++++++--- 3 files changed, 165 insertions(+), 11 deletions(-) diff --git a/lib_com/options.h b/lib_com/options.h index a98f995caa..dd4f314974 100755 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -194,6 +194,8 @@ #define NONBE_1380_OMASA_BUILD_DIFF /* Nokia: Fix for issue #1380: Large differences in OMASA output between Debug and Release builds */ +#define FIX_1430_EVS_STEREO_DMX_CHANNEL_DISAPPEARING /* Orange: Fix for basop issue 2184 - to prevent one channel from becoming inaudible in the mono downmix output */ + /* ##################### End NON-BE switches ########################### */ /* ################## End DEVELOPMENT switches ######################### */ diff --git a/lib_enc/ivas_stat_enc.h b/lib_enc/ivas_stat_enc.h index 2620fb3e97..1dcf4f2536 100644 --- a/lib_enc/ivas_stat_enc.h +++ b/lib_enc/ivas_stat_enc.h @@ -1081,6 +1081,12 @@ typedef struct stereo_dmx_evs_correlation_filter_structure { float isd_rate_s; float iccr_s; +#ifdef FIX_1430_EVS_STEREO_DMX_CHANNEL_DISAPPEARING + float phitd; + float iccres_s; + float lvlin[CPE_CHANNELS]; +#endif + float ipd_ff[STEREO_DMX_EVS_NB_SUBBAND_MAX]; float Pr[STEREO_DMX_EVS_NB_SUBBAND_MAX]; float Pi[STEREO_DMX_EVS_NB_SUBBAND_MAX]; diff --git a/lib_enc/ivas_stereo_dmx_evs.c b/lib_enc/ivas_stereo_dmx_evs.c index bf516cb974..e25ce350a4 100644 --- a/lib_enc/ivas_stereo_dmx_evs.c +++ b/lib_enc/ivas_stereo_dmx_evs.c @@ -78,6 +78,15 @@ #define STEREO_DMX_EVS_ICCR_HYST_L 0.75f #define STEREO_DMX_EVS_ICCR_HYST_H 0.85f +#ifdef FIX_1430_EVS_STEREO_DMX_CHANNEL_DISAPPEARING +#define STEREO_DMX_EVS_ICCRES_FORGETTING 0.92f +#define STEREO_DMX_EVS_LVLU_FORGETTING 0.5f +#define STEREO_DMX_EVS_LVLD_FORGETTING 0.92f +#define STEREO_DMX_EVS_ICLD_THRESH 3.f +#define STEREO_DMX_EVS_ICCRES_THRESH 0.4f +#define STEREO_DMX_EVS_DICLD_THRESH 1.49623566f +#endif + #define STEREO_DMX_EVS_SWTCH_HYS_THRES 1 #define STEREO_DMX_EVS_LR_EGY 15.0f #define STEREO_DMX_EVS_ILDS_EGY 10000.0f @@ -124,10 +133,15 @@ static void calc_poc( STEREO_DMX_EVS_POC_HANDLE hPOC, STEREO_DMX_EVS_PHA_HANDLE static ivas_error estimate_itd( float *corr, STEREO_DMX_EVS_POC_HANDLE hPOC, STEREO_DMX_EVS_PHA_HANDLE hPHA, const float srcL[], const float srcR[], float itd[], const int16_t input_frame ); static void weighted_ave( const float src1[], const float src2[], float dst[], const float gain, const float old_gain, const int16_t input_frame, const float wnd[] ); static void adapt_gain( const float src[], float dst[], const float gain, const float old_gain, const int16_t input_frame, const float wnd[] ); -static void create_M_signal( const float srcL[], const float srcR[], float dmx[], const float w_curr, const int16_t input_frame, const float wnd[], float *w_prev, float *dmx_energy, float *src_energy ); static float find_poc_peak( STEREO_DMX_EVS_POC_HANDLE hPOC, float itd[], const int16_t input_frame, const float ratio ); -static void calc_energy( const float src1[], const float src2[], float energy[], const int16_t input_frame, const float ratio ); static float spectral_flatness( const float sig[], const int16_t sig_length ); +#ifdef FIX_1430_EVS_STEREO_DMX_CHANNEL_DISAPPEARING +static void create_M_signal( const float srcL[], const float srcR[], float dmx[], const float w_curr, const int16_t input_frame, const float wnd[], float *w_prev, float *dmx_energy, float *src_energy, STEREO_DMX_EVS_PHA_HANDLE hPHA ); +static void calc_energy( const float src1[], const float src2[], float energy[], float *lvl, const int16_t input_frame, const float ratio ); +#else +static void create_M_signal( const float srcL[], const float srcR[], float dmx[], const float w_curr, const int16_t input_frame, const float wnd[], float *w_prev, float *dmx_energy, float *src_energy ); +static void calc_energy( const float src1[], const float src2[], float energy[], const int16_t input_frame, const float ratio ); +#endif /*-------------------------------------------------------------------* * estimate_itd_wnd_fft() @@ -485,7 +499,11 @@ static void calc_poc( Ni = 0; eneL = 0; eneR = 0; - +#ifdef FIX_1430_EVS_STEREO_DMX_CHANNEL_DISAPPEARING + step = n0 >> 3; + tmp1 = 0.0f; + tmp2 = 0.0f; +#endif for ( n = 1, i = 1; n < nsbd; n++ ) { tPr = 0.0f; @@ -518,13 +536,20 @@ static void calc_poc( eneL += ( specLr[i] * specLr[i] + specLi[i] * specLi[i] ); eneR += ( specRr[i] * specRr[i] + specRi[i] * specRi[i] ); + +#ifdef FIX_1430_EVS_STEREO_DMX_CHANNEL_DISAPPEARING + if ( i == step - 1 ) + { + tmp1 = eneL; + tmp2 = eneR; + } +#endif } Pn = inv_sqrtf( ( tPr * tPr + tPi * tPi ) + EPSILON ); tPr *= Pn; tPi *= Pn; - Pr[n] = ipd_ff[n] * Pr[n] + ( 1.0f - ipd_ff[n] ) * tPr; Pi[n] = ipd_ff[n] * Pi[n] + ( 1.0f - ipd_ff[n] ) * tPi; Pn = inv_sqrtf( ( Pr[n] * Pr[n] + Pi[n] * Pi[n] ) + EPSILON ); @@ -536,8 +561,12 @@ static void calc_poc( } /* Computes Spectral flatness on one channel */ +#ifdef FIX_1430_EVS_STEREO_DMX_CHANNEL_DISAPPEARING + if ( spectral_flatness( &tEl[1], nsbd - 1 ) < hPHA->pha_ipd_sf_Threshold ) +#else tmp1 = spectral_flatness( &tEl[1], nsbd - 1 ); if ( tmp1 < hPHA->pha_ipd_sf_Threshold ) +#endif { hPHA->pha_ipd_chanswitch_allowed = 0; } @@ -549,6 +578,34 @@ static void calc_poc( ICCr = sqrtf( ( Nr * Nr + Ni * Ni ) / ( eneL * eneR + EPSILON ) ); hPHA->iccr_s = STEREO_DMX_EVS_ICCR_FORGETTING * hPHA->iccr_s + ( 1.0f - STEREO_DMX_EVS_ICCR_FORGETTING ) * ICCr; +#ifdef FIX_1430_EVS_STEREO_DMX_CHANNEL_DISAPPEARING + eneL -= tmp1; + eneR -= tmp2; + + IPDr = cosf( hPHA->phitd * step ); + IPDi = sinf( hPHA->phitd * step ); + tmp1 = cosf( hPHA->phitd ); + tmp2 = sinf( hPHA->phitd ); + + for ( Nr = 0, Ni = 0, i = step; i < ( n0 - 1 ); i++ ) + { + tIPDr = ( specRr[i] * IPDr + specRi[i] * IPDi ); + tIPDi = ( specRr[i] * IPDi - specRi[i] * IPDr ); + Nr += ( specLr[i] * tIPDr - specLi[i] * tIPDi ); + Ni += ( specLi[i] * tIPDr + specLr[i] * tIPDi ); + tIPDr = IPDr; + IPDr = tIPDr * tmp1 - IPDi * tmp2; + IPDi = tIPDr * tmp2 + IPDi * tmp1; + } + + if ( ICCr == 0.f ) + { + ICCr = 1; + } + ICCr = 0.5f * ( ICCr + ( sqrtf( ( Nr * Nr + Ni * Ni ) / ( eneL * eneR + EPSILON ) ) ) ); + hPHA->iccres_s = STEREO_DMX_EVS_ICCRES_FORGETTING * hPHA->iccres_s + ( 1.0f - STEREO_DMX_EVS_ICCRES_FORGETTING ) * ICCr; +#endif + if ( hPHA->curr_pha == STEREO_DMX_EVS_PHA_IPD ) { hPHA->force_poc = FALSE; @@ -1142,7 +1199,16 @@ static float spectral_flatness( * * calculate energy *-------------------------------------------------------------------*/ - +#ifdef FIX_1430_EVS_STEREO_DMX_CHANNEL_DISAPPEARING +static void calc_energy( + const float src1[], /* i : Lch input signal */ + const float src2[], /* i : Rch input signal */ + float energy[], /* o : calculated energy */ + float *lvl, /* o : calculated rms level */ + const int16_t input_frame, /* i : input frame length per channel */ + const float ratio /* i : adapting ratio */ +) +#else static void calc_energy( const float src1[], /* i : Lch input signal */ const float src2[], /* i : Rch input signal */ @@ -1150,8 +1216,13 @@ static void calc_energy( const int16_t input_frame, /* i : input frame length per channel */ const float ratio /* i : adapting ratio */ ) +#endif { +#ifdef FIX_1430_EVS_STEREO_DMX_CHANNEL_DISAPPEARING + float E, wnd, wnd_diff, lvli, lvlff; +#else float E, wnd, wnd_diff; +#endif int16_t i, adaptlen; /* Initialization */ @@ -1179,6 +1250,14 @@ static void calc_energy( *energy = *energy * ratio + ( E / (float) input_frame ) * ( 1.0f - ratio ); +#ifdef FIX_1430_EVS_STEREO_DMX_CHANNEL_DISAPPEARING + if ( lvl != NULL ) + { + lvli = log10f( E + EPSILON ); + lvlff = ( lvli > *lvl ) ? STEREO_DMX_EVS_LVLU_FORGETTING : STEREO_DMX_EVS_LVLD_FORGETTING; + *lvl = lvlff * *lvl + ( 1.0f - lvlff ) * lvli; + } +#endif return; } @@ -1215,8 +1294,6 @@ static void adapt_gain( const float wnd[] /* i : window coef */ ) { - - int16_t i, len, len2; float gain_tmp, gain_sub; @@ -1235,13 +1312,11 @@ static void adapt_gain( dst[i] = src[i] * gain_tmp; } - for ( ; i < input_frame; i++ ) { dst[i] = src[i] * gain; } - return; } @@ -1251,7 +1326,20 @@ static void adapt_gain( * * create downmix signal *-------------------------------------------------------------------*/ - +#ifdef FIX_1430_EVS_STEREO_DMX_CHANNEL_DISAPPEARING +static void create_M_signal( + const float srcL[], /* i : Lch input signal */ + const float srcR[], /* i : Rch input signal */ + float dmx[], /* o : output signal */ + const float w_curr, /* i : adapting weight */ + const int16_t input_frame, /* i : input frame length per channel */ + const float wnd[], /* i : window coef */ + float *w_prev, /* i/o: adapting prev weight */ + float *dmx_energy, /* i/o: downmix signal energy */ + float *src_energy, /* i/o: input signal energy */ + STEREO_DMX_EVS_PHA_HANDLE hPHA /* i/o: correlation filter structure */ +) +#else static void create_M_signal( const float srcL[], /* i : Lch input signal */ const float srcR[], /* i : Rch input signal */ @@ -1263,6 +1351,7 @@ static void create_M_signal( float *dmx_energy, /* i/o: downmix signal energy */ float *src_energy /* i/o: input signal energy */ ) +#endif { float weighted[L_FRAME48k], eps, amp_mod[CPE_CHANNELS], Lbias; @@ -1272,9 +1361,15 @@ static void create_M_signal( weighted_ave( srcL, srcR, dmx, w_curr, w_prev[0], input_frame, wnd ); +#ifdef FIX_1430_EVS_STEREO_DMX_CHANNEL_DISAPPEARING + calc_energy( srcL, srcL, src_energy, hPHA->lvlin, input_frame, STEREO_DMX_EVS_DMX_EGY_FORGETTING ); + calc_energy( srcR, srcR, src_energy + 1, hPHA->lvlin + 1, input_frame, STEREO_DMX_EVS_DMX_EGY_FORGETTING ); + calc_energy( dmx, dmx, dmx_energy, NULL, input_frame, STEREO_DMX_EVS_DMX_EGY_FORGETTING ); +#else calc_energy( srcL, srcL, src_energy, input_frame, STEREO_DMX_EVS_DMX_EGY_FORGETTING ); calc_energy( srcR, srcR, src_energy + 1, input_frame, STEREO_DMX_EVS_DMX_EGY_FORGETTING ); calc_energy( dmx, dmx, dmx_energy, input_frame, STEREO_DMX_EVS_DMX_EGY_FORGETTING ); +#endif if ( src_energy[0] * Lbias > src_energy[1] ) { @@ -1363,7 +1458,12 @@ void stereo_dmx_evs_enc( float *p_data_mem, *p_prev_taps, *p_curr_taps, *p_data, *p_sub_frame; float ftmp, *fad_g, *p_dmx_data, *p_dmx_data_fo; bool is_transient; + +#ifdef FIX_1430_EVS_STEREO_DMX_CHANNEL_DISAPPEARING + STEREO_DMX_EVS_PRC prev_prc, req_prc; +#else STEREO_DMX_EVS_PRC prev_prc; +#endif STEREO_DMX_EVS_PHA_HANDLE hPHA; if ( is_binaural ) @@ -1423,8 +1523,14 @@ void stereo_dmx_evs_enc( dmx_weight = 0.5f; } +#ifdef FIX_1430_EVS_STEREO_DMX_CHANNEL_DISAPPEARING + hPHA->phitd = hStereoDmxEVS->itd * PI2 / input_frame; + create_M_signal( data_f[0], data_f[1], dmx_poc_data, dmx_weight, input_frame, hStereoDmxEVS->s_wnd, + hStereoDmxEVS->dmx_weight, hStereoDmxEVS->pre_dmx_energy, hStereoDmxEVS->aux_dmx_energy, hPHA ); +#else create_M_signal( data_f[0], data_f[1], dmx_poc_data, dmx_weight, input_frame, hStereoDmxEVS->s_wnd, hStereoDmxEVS->dmx_weight, hStereoDmxEVS->pre_dmx_energy, hStereoDmxEVS->aux_dmx_energy ); +#endif /* pha */ @@ -1494,6 +1600,38 @@ void stereo_dmx_evs_enc( prev_prc = hPHA->curr_prc; if ( abs( (int16_t) hStereoDmxEVS->itd ) > hPHA->prc_thres ) +#ifdef FIX_1430_EVS_STEREO_DMX_CHANNEL_DISAPPEARING + { + req_prc = STEREO_DMX_EVS_PRC_POC; + if ( ( fabs( hPHA->lvlin[0] - hPHA->lvlin[1] ) < STEREO_DMX_EVS_ICLD_THRESH ) && ( hPHA->iccres_s < STEREO_DMX_EVS_ICCRES_THRESH ) && ( ( ( dmx_weight + hStereoDmxEVS->dmx_weight[1] ) > STEREO_DMX_EVS_DICLD_THRESH * ( 1 - dmx_weight + hStereoDmxEVS->dmx_weight[2] ) ) || ( ( 1 - dmx_weight + hStereoDmxEVS->dmx_weight[2] ) > STEREO_DMX_EVS_DICLD_THRESH * ( dmx_weight + hStereoDmxEVS->dmx_weight[1] ) ) ) ) + { + req_prc = STEREO_DMX_EVS_PRC_PHA; + } + } + else + { + req_prc = STEREO_DMX_EVS_PRC_PHA; + } + + // Set mode with hysteresis + if ( hPHA->curr_prc != req_prc ) + { + if ( hPHA->prev_prc == req_prc ) + { + hPHA->prc_hys_cnt += 1; + } + else + { + hPHA->prc_hys_cnt = 0; + } + + if ( hPHA->prc_hys_cnt >= STEREO_DMX_EVS_SWTCH_PRC_HYS_THRES ) + { + hPHA->curr_prc = req_prc; + } + } + hPHA->prev_prc = req_prc; +#else { if ( hPHA->curr_prc != STEREO_DMX_EVS_PRC_POC ) { @@ -1533,6 +1671,7 @@ void stereo_dmx_evs_enc( } hPHA->prev_prc = STEREO_DMX_EVS_PRC_PHA; } +#endif if ( is_transient || ( 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->force_poc ) ) { @@ -1677,7 +1816,6 @@ void stereo_dmx_evs_enc( mvr2s( p_dmx_data, data, n_samples ); - return; } @@ -1837,6 +1975,14 @@ ivas_error stereo_dmx_evs_init_encoder( hStereoDmxEVS->hPHA->pha_len = len / 2; hStereoDmxEVS->hPHA->isd_rate_s = 0.0f; hStereoDmxEVS->hPHA->iccr_s = 0.0f; +#ifdef FIX_1430_EVS_STEREO_DMX_CHANNEL_DISAPPEARING + hStereoDmxEVS->hPHA->iccres_s = 0.0f; + hStereoDmxEVS->hPHA->phitd = 0.0f; + for ( n = 0; n < CPE_CHANNELS; n++ ) + { + hStereoDmxEVS->hPHA->lvlin[n] = 0.0f; + } +#endif pha_len = hStereoDmxEVS->hPHA->pha_len; fad_len = hStereoDmxEVS->hPHA->fad_len; -- GitLab