From a11173eb120ea539ac8b0099a346cbc658dea201 Mon Sep 17 00:00:00 2001 From: Tapani Pihlajakuja Date: Fri, 8 May 2026 16:05:16 +0300 Subject: [PATCH 1/2] Fix BASOP issue 2442: Improve MASA2 to MONO and Ambi rendering by fixing bugs, adding accuracy, and limiting low signal power diffuse synthesis gains. --- lib_com/options.h | 1 + lib_rend/ivas_dirac_output_synthesis_dec_fx.c | 99 +++++++++++++++++++ lib_rend/ivas_dirac_rend_fx.c | 17 ++++ lib_rend/lib_rend_fx.c | 44 +++++++++ 4 files changed, 161 insertions(+) diff --git a/lib_com/options.h b/lib_com/options.h index c357e4d4d..fa031addc 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -133,6 +133,7 @@ #define FIX_FLOAT_1578_OMASA_REND_SPIKES /* Nokia: Float issue 1578: Fix spikes and collapsed perception in OMASA/MASA rendering to FOA/HOA */ #define FIX_1521_SBA_LOUDNESS_STEREO /* FhG: issue 1521: Fix loudness for SBA to stereo rendering */ #define FIX_1559 /* Eri/FhG: fix for Issue 1559 in FD CNG with bitrate/bw switching */ +#define FIX_BASOP_2442_MASA2TC_TO_MONO_AND_AMBI /* Nokia: BASOP issue 2442: Aligns float with identical diffuse gain limitation to minimize diff */ /* ##################### End NON-BE switches ########################### */ diff --git a/lib_rend/ivas_dirac_output_synthesis_dec_fx.c b/lib_rend/ivas_dirac_output_synthesis_dec_fx.c index 0a6afb017..a0602f77d 100644 --- a/lib_rend/ivas_dirac_output_synthesis_dec_fx.c +++ b/lib_rend/ivas_dirac_output_synthesis_dec_fx.c @@ -56,6 +56,11 @@ #define POINT_3679_Q31 790059234 /*.3679 q31*/ #define POINT_1175_Q31 252329329 /*.1175 q31*/ +#ifdef FIX_BASOP_2442_MASA2TC_TO_MONO_AND_AMBI +#define DIRAC_SMALL_DIFF_POW_LIM 65536 +#define DIRAC_SMALL_DIFF_POW_MAX_GAIN 2 +#endif + /*------------------------------------------------------------------------- * Local function prototypes *------------------------------------------------------------------------*/ @@ -2001,12 +2006,32 @@ void ivas_dirac_dec_output_synthesis_process_subframe_psd_ls_fx( masa_stereo_type_detect->target_power_y_smooth_fx = L_shl( masa_stereo_type_detect->target_power_y_smooth_fx, sub( q_com, masa_stereo_type_detect->q_target_power_y_smooth ) ); move32(); +#ifdef FIX_BASOP_2442_MASA2TC_TO_MONO_AND_AMBI + + W_temp = W_add( W_mult0_32_32( a, target_power_y ), W_mult0_32_32( b, masa_stereo_type_detect->target_power_y_smooth_fx ) ); // Q31 + q_com + IF( W_temp ) + { + exp = W_norm( W_temp ); + masa_stereo_type_detect->target_power_y_smooth_fx = W_extract_h( W_shl( W_temp, exp ) ); // Q31 + q_com + exp - 32 + move32(); + masa_stereo_type_detect->q_target_power_y_smooth = sub( add( q_com, exp ), 1 ); + move16(); + } + ELSE + { + masa_stereo_type_detect->target_power_y_smooth_fx = 0; // Q31 + move32(); + masa_stereo_type_detect->q_target_power_y_smooth = Q31; + move16(); + } +#else masa_stereo_type_detect->target_power_y_smooth_fx = L_add( Mpy_32_32( a, target_power_y ), Mpy_32_32( b, masa_stereo_type_detect->target_power_y_smooth_fx ) ); //(Q31, q_com) -> q_com move32(); masa_stereo_type_detect->q_target_power_y_smooth = q_com; move16(); +#endif IF( NE_16( masa_stereo_type_detect->q_subtract_power_y, masa_stereo_type_detect->q_subtract_power_y_smooth ) ) { @@ -2046,7 +2071,11 @@ void ivas_dirac_dec_output_synthesis_process_subframe_psd_ls_fx( { subtract_target_ratio = L_sub( BASOP_Util_Log2( masa_stereo_type_detect->subtract_power_y_smooth_fx ), BASOP_Util_Log2( masa_stereo_type_detect->target_power_y_smooth_fx ) ); // Q25 +#ifdef FIX_BASOP_2442_MASA2TC_TO_MONO_AND_AMBI + exp = sub( masa_stereo_type_detect->q_subtract_power_y_smooth, masa_stereo_type_detect->q_target_power_y_smooth ); +#else exp = sub( masa_stereo_type_detect->q_subtract_power_y_smooth, q_com ); +#endif L_tmp = Mpy_32_32( L_sub( subtract_target_ratio, L_shl( exp, 25 ) ), LOG10_2_Q31 ); // Q25 } ELSE @@ -2272,6 +2301,24 @@ void ivas_dirac_dec_output_synthesis_process_subframe_psd_ls_fx( Word32 cmp = W_shl_sat_l( DIRAC_GAIN_LIMIT_Q26, sub( h_dirac_output_synthesis_state->gains_dir_prev_q, 26 ) ); Word32 cmp2 = W_extract_h( W_shl( W_mult_32_32( DIRAC_GAIN_LIMIT_Q26, L_shl( 1, h_dirac_output_synthesis_state->gains_diff_prev_q ) ), Q5 ) ); +#ifdef FIX_BASOP_2442_MASA2TC_TO_MONO_AND_AMBI + Word32 diff_gain_limit = L_shl( DIRAC_SMALL_DIFF_POW_MAX_GAIN, h_dirac_output_synthesis_state->gains_diff_prev_q ); + Word32 power_diff_small_lim; + IF( GT_16( h_dirac_output_synthesis_state->proto_power_diff_smooth_q, norm_l( DIRAC_SMALL_DIFF_POW_LIM ) ) ) + { + power_diff_small_lim = MAX_32; /* All bands have low very low signal energy */ + } + ELSE IF( LT_16( h_dirac_output_synthesis_state->proto_power_diff_smooth_q, -31 ) ) + { + power_diff_small_lim = 0; /* All bands have high enough signal energy */ + } + ELSE + { + power_diff_small_lim = L_shl( DIRAC_SMALL_DIFF_POW_LIM, h_dirac_output_synthesis_state->proto_power_diff_smooth_q ); + } + +#endif + FOR( k = 0; k < nchan_out_woLFE; k++ ) { Word32 power_smooth_temp; @@ -2333,6 +2380,14 @@ void ivas_dirac_dec_output_synthesis_process_subframe_psd_ls_fx( Mpy_32_32( g2, ( *( p_cy_auto_diff_smooth_prev ) ) ) ); // (Q31, q_cy_auto_diff_smooth_prev) -> q_cy_auto_diff_smooth_prev move32(); +#ifdef FIX_BASOP_2442_MASA2TC_TO_MONO_AND_AMBI + IF ( LT_32(*( p_power_diff_smooth_prev ), power_diff_small_lim) ) + { + cmp2 = diff_gain_limit; + move32(); + } +#endif + exp = 0; move16(); L_tmp = BASOP_Util_Divide3232_Scale_newton( *( p_cy_auto_diff_smooth_prev++ ), ( *( p_power_diff_smooth_prev++ ) ), &exp ); // (Q31 - exp) + (q_a - q_b) @@ -2370,8 +2425,16 @@ void ivas_dirac_dec_output_synthesis_process_subframe_psd_ls_fx( *( p_cy_auto_dir_smooth_prev++ ) = L_shr_r( L_tmp, q_tmp ); // q_cy_auto_dir_smooth_prev_local move32(); +#ifdef FIX_BASOP_2442_MASA2TC_TO_MONO_AND_AMBI + + W_temp = W_mac_32_32( W_mult_32_32( g1, ( *( p_cy_cross_dir_smooth ) ) ), g2, ( *( p_cy_cross_dir_smooth_prev ) ) ); + q_tmp = W_norm( W_temp ); + L_tmp = W_extract_h( W_shl( W_temp, q_tmp ) ); + *( p_cy_cross_dir_smooth_prev ) = L_shr_r( L_tmp, q_tmp ); // q_cy_cross_dir_smooth_prev +#else *( p_cy_cross_dir_smooth_prev ) = Madd_32_32( Mpy_32_32( g1, ( *( p_cy_cross_dir_smooth ) ) ), g2, ( *( p_cy_cross_dir_smooth_prev ) ) ); // (Q31, q_cy_cross_dir_smooth_prev) -> q_cy_cross_dir_smooth_prev +#endif move32(); test(); if ( *( p_cy_cross_dir_smooth_prev ) == 0 && ( *( p_cy_cross_dir_smooth ) != 0 ) ) @@ -2826,8 +2889,13 @@ void ivas_dirac_dec_compute_directional_responses_fx( Word16 max_exp = MIN16B; move16(); +#ifdef FIX_BASOP_2442_MASA2TC_TO_MONO_AND_AMBI + maximum_fx( exp_arr, num_channels_dir, &max_exp ); + FOR( l = 0; l < num_channels_dir; l++ ) +#else maximum_fx( exp_arr, MAX_OUTPUT_CHANNELS, &max_exp ); FOR( l = 0; l < MAX_OUTPUT_CHANNELS; l++ ) +#endif { direct_response_hoa_fx[l] = L_shr( direct_response_hoa_fx[l], sub( max_exp, exp_arr[l] ) ); /*Q(31-exp_arr[l])->Q(31-max_exp)*/ move32(); @@ -2965,8 +3033,13 @@ void ivas_dirac_dec_compute_directional_responses_fx( } Word16 max_exp = MIN_16; move16(); +#ifdef FIX_BASOP_2442_MASA2TC_TO_MONO_AND_AMBI + maximum_fx( exp_arr, num_channels_dir, &max_exp ); + FOR( l = 0; l < num_channels_dir; l++ ) +#else maximum_fx( exp_arr, MAX_OUTPUT_CHANNELS, &max_exp ); FOR( l = 0; l < MAX_OUTPUT_CHANNELS; l++ ) +#endif { direct_response_hoa_fx[l] = L_shr( direct_response_hoa_fx[l], sub( max_exp, exp_arr[l] ) ); /*q(31-exp_arr[l])->q(31-max_exp)*/ move32(); @@ -2978,7 +3051,11 @@ void ivas_dirac_dec_compute_directional_responses_fx( Q_direct_response_hoa = sub( Q31, exp_direct_response_hoa ); +#ifdef FIX_BASOP_2442_MASA2TC_TO_MONO_AND_AMBI + Scale_sig32( direct_response_hoa_fx, num_channels_dir, sub( Q29, Q_direct_response_hoa ) ); /*Q_direct_response_hoa->q29*/ +#else Scale_sig32( direct_response_hoa_fx, MAX_OUTPUT_CHANNELS, sub( Q29, Q_direct_response_hoa ) ); /*Q_direct_response_hoa->q29*/ +#endif direct_response_q = Q29; move16(); @@ -3080,9 +3157,14 @@ void ivas_dirac_dec_compute_directional_responses_fx( move16(); } +#ifdef FIX_BASOP_2442_MASA2TC_TO_MONO_AND_AMBI + maximum_fx( exp_table, num_channels_dir, &exp_max ); + FOR( i = 0; i < num_channels_dir; i++ ) +#else maximum_fx( exp_table, MAX_OUTPUT_CHANNELS, &exp_max ); FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ ) +#endif { direct_response_ls_fx[i] = L_shr( direct_response_ls_fx[i], sub( exp_max, exp_table[i] ) ); /*(q(31-exp_table[i])->q(31-exp_max))*/ move32(); @@ -3249,8 +3331,13 @@ void ivas_dirac_dec_compute_directional_responses_fx( max_exp = MIN16B; /*Q0*/ move16(); +#ifdef FIX_BASOP_2442_MASA2TC_TO_MONO_AND_AMBI + maximum_fx( exp_arr, num_channels_dir, &max_exp ); + FOR( l = 0; l < num_channels_dir; l++ ) +#else maximum_fx( exp_arr, MAX_OUTPUT_CHANNELS, &max_exp ); FOR( l = 0; l < MAX_OUTPUT_CHANNELS; l++ ) +#endif { direct_response_ls_fx[l] = L_shr( direct_response_ls_fx[l], sub( max_exp, exp_arr[l] ) ); /*Q(31-exp_arr[l])->Q(31-max_exp)*/ move32(); @@ -3264,7 +3351,11 @@ void ivas_dirac_dec_compute_directional_responses_fx( normalizePanningGains_fx( direct_response_ls_fx, &Q_direct_response_ls, num_channels_dir ); exp_direct_response_ls = sub( 31, Q_direct_response_ls ); +#ifdef FIX_BASOP_2442_MASA2TC_TO_MONO_AND_AMBI + Scale_sig32( direct_response_ls_fx, num_channels_dir, sub( Q29, Q_direct_response_ls ) ); /*Q_direct_response_ls->Q29*/ +#else Scale_sig32( direct_response_ls_fx, MAX_OUTPUT_CHANNELS, sub( Q29, Q_direct_response_ls ) ); /*Q_direct_response_ls->Q29*/ +#endif direct_response_q = Q29; move16(); @@ -3991,11 +4082,19 @@ static void spreadCoherencePanningHoa_fx( } Word16 max_val = MIN_16; move16(); +#ifdef FIX_BASOP_2442_MASA2TC_TO_MONO_AND_AMBI + FOR( i = 0; i < num_channels_dir; i++ ) +#else FOR( i = 0; i < 16; i++ ) +#endif { max_val = s_max( max_val, exp_arr[i] ); } +#ifdef FIX_BASOP_2442_MASA2TC_TO_MONO_AND_AMBI + FOR( i = 0; i < num_channels_dir; i++ ) +#else FOR( i = 0; i < 16; i++ ) +#endif { direct_response_fx[i] = L_shr( direct_response_fx[i], sub( max_val, exp_arr[i] ) ); // Q(31-exp_arr[i])->q(31-max_val) move32(); diff --git a/lib_rend/ivas_dirac_rend_fx.c b/lib_rend/ivas_dirac_rend_fx.c index d56272108..e888d0992 100644 --- a/lib_rend/ivas_dirac_rend_fx.c +++ b/lib_rend/ivas_dirac_rend_fx.c @@ -2690,6 +2690,22 @@ void protoSignalComputation2_fx( } } +#ifdef FIX_BASOP_2442_MASA2TC_TO_MONO_AND_AMBI + stereo_type_detect->left_bb_power_fx = BASOP_Util_Add_Mant32Exp( Mpy_32_32( a_fx, left_bb_power_fx ), sub( 31, q_Left_Right_power ), Mpy_32_32( b_fx, stereo_type_detect->left_bb_power_fx ), sub( 31, stereo_type_detect->q_left_bb_power ), &stereo_type_detect->q_left_bb_power ); + move32(); + stereo_type_detect->q_left_bb_power = sub( 31, stereo_type_detect->q_left_bb_power ); + move16(); + + stereo_type_detect->right_bb_power_fx = BASOP_Util_Add_Mant32Exp( Mpy_32_32( a_fx, right_bb_power_fx ), sub( 31, q_Left_Right_power ), Mpy_32_32( b_fx, stereo_type_detect->right_bb_power_fx ), sub( 31, stereo_type_detect->q_right_bb_power ), &stereo_type_detect->q_right_bb_power ); + move32(); + stereo_type_detect->q_right_bb_power = sub( 31, stereo_type_detect->q_right_bb_power ); + move16(); + + stereo_type_detect->total_bb_power_fx = BASOP_Util_Add_Mant32Exp( Mpy_32_32( a_fx, total_bb_power_fx ), sub( 31, q_Left_Right_power ), Mpy_32_32( b_fx, stereo_type_detect->total_bb_power_fx ), sub( 31, stereo_type_detect->q_total_bb_power ), &stereo_type_detect->q_total_bb_power ); + move32(); + stereo_type_detect->q_total_bb_power = sub( 31, stereo_type_detect->q_total_bb_power ); + move16(); +#else temp = Mpy_32_32( a_fx, left_bb_power_fx ); // q_Left_Right_power IF( LT_16( q_Left_Right_power, stereo_type_detect->q_left_bb_power ) ) { @@ -2731,6 +2747,7 @@ void protoSignalComputation2_fx( stereo_type_detect->total_bb_power_fx = Madd_32_32( L_shr( temp, sub( q_Left_Right_power, stereo_type_detect->q_total_bb_power ) ), b_fx, stereo_type_detect->total_bb_power_fx ); // stereo_type_detect->q_total_bb_power move32(); } +#endif IF( LT_16( stereo_type_detect->q_left_bb_power, stereo_type_detect->q_right_bb_power ) ) { diff --git a/lib_rend/lib_rend_fx.c b/lib_rend/lib_rend_fx.c index 1dd55712d..8bcccbddb 100644 --- a/lib_rend/lib_rend_fx.c +++ b/lib_rend/lib_rend_fx.c @@ -9031,9 +9031,31 @@ static void copyMasaMetadataToDiracRenderer_fx( { FOR( bin = MASA_band_grouping_24[band]; bin < MASA_band_grouping_24[band + 1] && bin < maxBin; bin++ ) { +#ifdef FIX_BASOP_2442_MASA2TC_TO_MONO_AND_AMBI + IF( meta->directional_meta[0].azimuth_fx[sf][band] < 0 ) + { + hSpatParamRendCom->azimuth[meta_write_index][bin] = negate( extract_l( L_shr( L_negate( meta->directional_meta[0].azimuth_fx[sf][band] ), Q22 ) ) ); /* Q22 - Q22 = Q0 */ + } + ELSE + { + hSpatParamRendCom->azimuth[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[0].azimuth_fx[sf][band], Q22 ) ); + } +#else hSpatParamRendCom->azimuth[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[0].azimuth_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */ +#endif move16(); +#ifdef FIX_BASOP_2442_MASA2TC_TO_MONO_AND_AMBI + IF( meta->directional_meta[0].elevation_fx[sf][band] < 0 ) + { + hSpatParamRendCom->elevation[meta_write_index][bin] = negate( extract_l( L_shr( L_negate( meta->directional_meta[0].elevation_fx[sf][band] ), Q22 ) ) ); /* Q22 - Q22 = Q0 */ + } + ELSE + { + hSpatParamRendCom->elevation[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[0].elevation_fx[sf][band], Q22 ) ); + } +#else hSpatParamRendCom->elevation[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[0].elevation_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */ +#endif move16(); hSpatParamRendCom->energy_ratio1_fx[meta_write_index][bin] = meta->directional_meta[0].energy_ratio_fx[sf][band]; move32(); @@ -9046,9 +9068,31 @@ static void copyMasaMetadataToDiracRenderer_fx( IF( EQ_16( hSpatParamRendCom->numSimultaneousDirections, 2 ) ) { +#ifdef FIX_BASOP_2442_MASA2TC_TO_MONO_AND_AMBI + IF( meta->directional_meta[1].azimuth_fx[sf][band] < 0 ) + { + hSpatParamRendCom->azimuth2[meta_write_index][bin] = negate( extract_l( L_shr( L_negate( meta->directional_meta[1].azimuth_fx[sf][band] ), Q22 ) ) ); /* Q22 - Q22 = Q0 */ + } + ELSE + { + hSpatParamRendCom->azimuth2[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[1].azimuth_fx[sf][band], Q22 ) ); + } +#else hSpatParamRendCom->azimuth2[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[1].azimuth_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */ +#endif move16(); +#ifdef FIX_BASOP_2442_MASA2TC_TO_MONO_AND_AMBI + IF( meta->directional_meta[1].elevation_fx[sf][band] < 0 ) + { + hSpatParamRendCom->elevation2[meta_write_index][bin] = negate( extract_l( L_shr( L_negate( meta->directional_meta[1].elevation_fx[sf][band] ), Q22 ) ) ); /* Q22 - Q22 = Q0 */ + } + ELSE + { + hSpatParamRendCom->elevation2[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[1].elevation_fx[sf][band], Q22 ) ); + } +#else hSpatParamRendCom->elevation2[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[1].elevation_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */ +#endif move16(); hSpatParamRendCom->energy_ratio2_fx[meta_write_index][bin] = meta->directional_meta[1].energy_ratio_fx[sf][band]; move32(); -- GitLab From 438e11d8ee532cc379fccb8f32eeb951d31500be Mon Sep 17 00:00:00 2001 From: Tapani Pihlajakuja Date: Fri, 8 May 2026 16:12:24 +0300 Subject: [PATCH 2/2] Clang format --- lib_rend/ivas_dirac_output_synthesis_dec_fx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib_rend/ivas_dirac_output_synthesis_dec_fx.c b/lib_rend/ivas_dirac_output_synthesis_dec_fx.c index a0602f77d..c576398d4 100644 --- a/lib_rend/ivas_dirac_output_synthesis_dec_fx.c +++ b/lib_rend/ivas_dirac_output_synthesis_dec_fx.c @@ -57,8 +57,8 @@ #define POINT_1175_Q31 252329329 /*.1175 q31*/ #ifdef FIX_BASOP_2442_MASA2TC_TO_MONO_AND_AMBI -#define DIRAC_SMALL_DIFF_POW_LIM 65536 -#define DIRAC_SMALL_DIFF_POW_MAX_GAIN 2 +#define DIRAC_SMALL_DIFF_POW_LIM 65536 +#define DIRAC_SMALL_DIFF_POW_MAX_GAIN 2 #endif /*------------------------------------------------------------------------- @@ -2381,7 +2381,7 @@ void ivas_dirac_dec_output_synthesis_process_subframe_psd_ls_fx( move32(); #ifdef FIX_BASOP_2442_MASA2TC_TO_MONO_AND_AMBI - IF ( LT_32(*( p_power_diff_smooth_prev ), power_diff_small_lim) ) + IF( LT_32( *( p_power_diff_smooth_prev ), power_diff_small_lim ) ) { cmp2 = diff_gain_limit; move32(); -- GitLab