From b341fc82c93683d408e20e04145dab9caf42d9cd Mon Sep 17 00:00:00 2001 From: Manuel Jander Date: Tue, 5 May 2026 18:31:57 +0200 Subject: [PATCH 1/5] Improve FD CNG precision for test case in issue #2575. --- lib_com/options.h | 1 + lib_dec/ivas_stereo_cng_dec_fx.c | 43 ++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/lib_com/options.h b/lib_com/options.h index 5390fd919..d5a92b694 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -132,6 +132,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 NONBE_FIX_2575 /* Fhg: Fix issue 2575, precision loss in FD CNG */ /* ##################### End NON-BE switches ########################### */ diff --git a/lib_dec/ivas_stereo_cng_dec_fx.c b/lib_dec/ivas_stereo_cng_dec_fx.c index bf09e2336..d09cdc1b5 100644 --- a/lib_dec/ivas_stereo_cng_dec_fx.c +++ b/lib_dec/ivas_stereo_cng_dec_fx.c @@ -794,6 +794,27 @@ static void stereo_dft_generate_comfort_noise_fx( IF( ( chan == 0 ) && LE_32( st->core_brate, SID_2k40 ) ) { /* update smoothed periodogram used by stereo CNA in SID and NO_DATA frames from cngNoiseLevel_flt */ +#ifdef NONBE_FIX_2575 + + /* Normalize smoothed_psd_fx and cngNoiseLevel to avoid its exponents running away. */ + q_shift_1 = L_norm_arr( st->hFdCngDec->smoothed_psd_fx, L_FRAME16k ); + q_shift_2 = L_norm_arr( hFdCngCom->cngNoiseLevel, FFTCLDFBLEN ); + + scale_sig32( st->hFdCngDec->smoothed_psd_fx, L_FRAME16k, q_shift_1 ); /* Q31 - st->hFdCngDec->smoothed_psd_exp */ + st->hFdCngDec->smoothed_psd_exp = sub( st->hFdCngDec->smoothed_psd_exp, q_shift_1 ); + move16(); + scale_sig32( hFdCngCom->cngNoiseLevel, FFTCLDFBLEN, q_shift_2 ); /* Q31 - hFdCngCom->cngNoiseLevelExp */ + hFdCngCom->cngNoiseLevelExp = sub( hFdCngCom->cngNoiseLevelExp, q_shift_2 ); + move16(); + + /* Determine appropiate exponent for the resulting smoothed_psd_fx */ + min_q = sub( s_min( sub( Q31, st->hFdCngDec->smoothed_psd_exp ), sub( Q31, hFdCngCom->cngNoiseLevelExp ) ), 1 /* Guard bit */ ); + q_shift_1 = sub( sub( Q31, hFdCngCom->cngNoiseLevelExp ), min_q ); + q_shift_2 = sub( sub( Q31, st->hFdCngDec->smoothed_psd_exp ), min_q ); + + st->hFdCngDec->smoothed_psd_exp = sub( Q31, min_q ); + move16(); +#else q_shift_1 = L_norm_arr( st->hFdCngDec->smoothed_psd_fx, L_FRAME16k ); q_shift_2 = L_norm_arr( hFdCngCom->cngNoiseLevel, FFTCLDFBLEN ); @@ -805,10 +826,19 @@ static void stereo_dft_generate_comfort_noise_fx( scale_sig32( hFdCngCom->cngNoiseLevel, FFTCLDFBLEN, sub( min_q, sub( Q31, hFdCngCom->cngNoiseLevelExp ) ) ); /* Q31 - hFdCngCom->cngNoiseLevelExp */ hFdCngCom->cngNoiseLevelExp = st->hFdCngDec->smoothed_psd_exp; move16(); +#endif FOR( i = hFdCngCom->startBand; i < hFdCngCom->stopFFTbin; i++ ) { +#ifdef NONBE_FIX_2575 + Word32 ftmp2; + ftmp2 = L_shr( st->hFdCngDec->smoothed_psd_fx[i], q_shift_2 ); // min_q +#endif +#ifdef NONBE_FIX_2575 + ftmp = L_shr( hFdCngCom->cngNoiseLevel[i - hFdCngCom->startBand], q_shift_1 ); // min_q +#else ftmp = hFdCngCom->cngNoiseLevel[i - hFdCngCom->startBand]; +#endif move32(); IF( !st->hFdCngDec->first_cna_noise_updated ) { @@ -820,11 +850,20 @@ static void stereo_dft_generate_comfort_noise_fx( { alpha = (Word16) ( 0x799A ); move16(); + test(); +#ifdef NONBE_FIX_2575 + IF( ( st->hFdCngDec->smoothed_psd_fx[i] > 0 ) && EQ_16( BASOP_Util_Cmp_Mant32Exp( Mpy_32_16_1( hFdCngCom->cngNoiseLevel[i - hFdCngCom->startBand], (Word16) 0x3333 ), hFdCngCom->cngNoiseLevelExp, st->hFdCngDec->smoothed_psd_fx[i], st->hFdCngDec->smoothed_psd_exp ), 1 ) ) +#else IF( ( st->hFdCngDec->smoothed_psd_fx[i] > 0 ) && GT_32( Mpy_32_16_1( ftmp, (Word16) 0x3333 ), st->hFdCngDec->smoothed_psd_fx[i] ) ) +#endif { /* prevent abrupt upward update steps */ +#ifdef NONBE_FIX_2575 + ftmp = L_add( L_shl( ftmp2, 1 ), L_shr( ftmp2, 1 ) ); /* st->hFdCngDec->smoothed_psd_exp */ +#else ftmp = L_add( L_shl( st->hFdCngDec->smoothed_psd_fx[i], 1 ), L_shr( st->hFdCngDec->smoothed_psd_fx[i], 1 ) ); /* st->hFdCngDec->smoothed_psd_exp */ +#endif move16(); } ELSE IF( LT_32( ftmp, st->hFdCngDec->smoothed_psd_fx[i] ) ) @@ -836,7 +875,11 @@ static void stereo_dft_generate_comfort_noise_fx( } /* smoothing */ +#ifdef NONBE_FIX_2575 + st->hFdCngDec->smoothed_psd_fx[i] = L_add( Mpy_32_16_1( ftmp2, alpha ), Mpy_32_16_1( ftmp, sub( MAX_16, alpha ) ) ); /* st->hFdCngDec->smoothed_psd_exp */ +#else st->hFdCngDec->smoothed_psd_fx[i] = L_add( Mpy_32_16_1( st->hFdCngDec->smoothed_psd_fx[i], alpha ), Mpy_32_16_1( ftmp, sub( MAX_16, alpha ) ) ); /* st->hFdCngDec->smoothed_psd_exp */ +#endif move32(); } -- GitLab From 3ddc2ac454135351a00dc747c9dced4cdced0028 Mon Sep 17 00:00:00 2001 From: Manuel Jander Date: Wed, 6 May 2026 14:48:59 +0200 Subject: [PATCH 2/5] Improve accuracy of smoothed_psd_fx[]. Fix issues if difference between smoothed_psd_exp and cngNoiseLevelExp is 24 or larger. --- lib_dec/ivas_stereo_cng_dec_fx.c | 61 ++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/lib_dec/ivas_stereo_cng_dec_fx.c b/lib_dec/ivas_stereo_cng_dec_fx.c index d09cdc1b5..24150ade1 100644 --- a/lib_dec/ivas_stereo_cng_dec_fx.c +++ b/lib_dec/ivas_stereo_cng_dec_fx.c @@ -118,7 +118,11 @@ static void stereo_dft_generate_comfort_noise_fx( Word16 trigo_step; Word32 tmp32_1, tmp32_2; Word16 q_div, q_sqrt1, q_sqrt2, q_sqrt, sqrt_res; +#ifdef NONBE_FIX_2575 + Word16 q_shift; +#else Word16 q_shift, q_shift_1, q_shift_2, min_q; +#endif Word16 tmp16, tmp_p, tmp_s; hFdCngCom = st->hFdCngDec->hFdCngCom; @@ -795,25 +799,9 @@ static void stereo_dft_generate_comfort_noise_fx( { /* update smoothed periodogram used by stereo CNA in SID and NO_DATA frames from cngNoiseLevel_flt */ #ifdef NONBE_FIX_2575 - - /* Normalize smoothed_psd_fx and cngNoiseLevel to avoid its exponents running away. */ - q_shift_1 = L_norm_arr( st->hFdCngDec->smoothed_psd_fx, L_FRAME16k ); - q_shift_2 = L_norm_arr( hFdCngCom->cngNoiseLevel, FFTCLDFBLEN ); - - scale_sig32( st->hFdCngDec->smoothed_psd_fx, L_FRAME16k, q_shift_1 ); /* Q31 - st->hFdCngDec->smoothed_psd_exp */ - st->hFdCngDec->smoothed_psd_exp = sub( st->hFdCngDec->smoothed_psd_exp, q_shift_1 ); + Word16 smoothed_psd_exp[L_FRAME16k], smoothed_psd_exp_max = MIN_16; move16(); - scale_sig32( hFdCngCom->cngNoiseLevel, FFTCLDFBLEN, q_shift_2 ); /* Q31 - hFdCngCom->cngNoiseLevelExp */ - hFdCngCom->cngNoiseLevelExp = sub( hFdCngCom->cngNoiseLevelExp, q_shift_2 ); - move16(); - - /* Determine appropiate exponent for the resulting smoothed_psd_fx */ - min_q = sub( s_min( sub( Q31, st->hFdCngDec->smoothed_psd_exp ), sub( Q31, hFdCngCom->cngNoiseLevelExp ) ), 1 /* Guard bit */ ); - q_shift_1 = sub( sub( Q31, hFdCngCom->cngNoiseLevelExp ), min_q ); - q_shift_2 = sub( sub( Q31, st->hFdCngDec->smoothed_psd_exp ), min_q ); - st->hFdCngDec->smoothed_psd_exp = sub( Q31, min_q ); - move16(); #else q_shift_1 = L_norm_arr( st->hFdCngDec->smoothed_psd_fx, L_FRAME16k ); q_shift_2 = L_norm_arr( hFdCngCom->cngNoiseLevel, FFTCLDFBLEN ); @@ -831,15 +819,16 @@ static void stereo_dft_generate_comfort_noise_fx( FOR( i = hFdCngCom->startBand; i < hFdCngCom->stopFFTbin; i++ ) { #ifdef NONBE_FIX_2575 - Word32 ftmp2; - ftmp2 = L_shr( st->hFdCngDec->smoothed_psd_fx[i], q_shift_2 ); // min_q -#endif -#ifdef NONBE_FIX_2575 - ftmp = L_shr( hFdCngCom->cngNoiseLevel[i - hFdCngCom->startBand], q_shift_1 ); // min_q + Word16 ftmp_exp; + + ftmp = hFdCngCom->cngNoiseLevel[i - hFdCngCom->startBand]; + move32(); + ftmp_exp = hFdCngCom->cngNoiseLevelExp; + move16(); #else ftmp = hFdCngCom->cngNoiseLevel[i - hFdCngCom->startBand]; -#endif move32(); +#endif IF( !st->hFdCngDec->first_cna_noise_updated ) { /* very first update */ @@ -853,20 +842,27 @@ static void stereo_dft_generate_comfort_noise_fx( test(); #ifdef NONBE_FIX_2575 - IF( ( st->hFdCngDec->smoothed_psd_fx[i] > 0 ) && EQ_16( BASOP_Util_Cmp_Mant32Exp( Mpy_32_16_1( hFdCngCom->cngNoiseLevel[i - hFdCngCom->startBand], (Word16) 0x3333 ), hFdCngCom->cngNoiseLevelExp, st->hFdCngDec->smoothed_psd_fx[i], st->hFdCngDec->smoothed_psd_exp ), 1 ) ) + IF( ( st->hFdCngDec->smoothed_psd_fx[i] > 0 ) && EQ_16( BASOP_Util_Cmp_Mant32Exp( Mpy_32_16_1( ftmp, (Word16) 0x3333 ), ftmp_exp, st->hFdCngDec->smoothed_psd_fx[i], st->hFdCngDec->smoothed_psd_exp ), 1 ) ) #else IF( ( st->hFdCngDec->smoothed_psd_fx[i] > 0 ) && GT_32( Mpy_32_16_1( ftmp, (Word16) 0x3333 ), st->hFdCngDec->smoothed_psd_fx[i] ) ) #endif { /* prevent abrupt upward update steps */ #ifdef NONBE_FIX_2575 - ftmp = L_add( L_shl( ftmp2, 1 ), L_shr( ftmp2, 1 ) ); /* st->hFdCngDec->smoothed_psd_exp */ + ftmp = L_add( L_shr( st->hFdCngDec->smoothed_psd_fx[i], 2 - 1 ), L_shr( st->hFdCngDec->smoothed_psd_fx[i], 2 + 1 ) ); /* ftmp_exp */ + move16(); + ftmp_exp = add( st->hFdCngDec->smoothed_psd_exp, 2 ); + move16(); #else ftmp = L_add( L_shl( st->hFdCngDec->smoothed_psd_fx[i], 1 ), L_shr( st->hFdCngDec->smoothed_psd_fx[i], 1 ) ); /* st->hFdCngDec->smoothed_psd_exp */ -#endif move16(); +#endif } +#ifdef NONBE_FIX_2575 + ELSE IF( EQ_16( BASOP_Util_Cmp_Mant32Exp( ftmp, ftmp_exp, st->hFdCngDec->smoothed_psd_fx[i], st->hFdCngDec->smoothed_psd_exp ), 1 ) ) +#else ELSE IF( LT_32( ftmp, st->hFdCngDec->smoothed_psd_fx[i] ) ) +#endif { /* faster downward updates */ alpha = (Word16) ( 0x599A ); @@ -876,13 +872,24 @@ static void stereo_dft_generate_comfort_noise_fx( /* smoothing */ #ifdef NONBE_FIX_2575 - st->hFdCngDec->smoothed_psd_fx[i] = L_add( Mpy_32_16_1( ftmp2, alpha ), Mpy_32_16_1( ftmp, sub( MAX_16, alpha ) ) ); /* st->hFdCngDec->smoothed_psd_exp */ + st->hFdCngDec->smoothed_psd_fx[i] = BASOP_Util_Add_Mant32Exp( Mpy_32_16_1( st->hFdCngDec->smoothed_psd_fx[i], alpha ), st->hFdCngDec->smoothed_psd_exp, Mpy_32_16_1( ftmp, sub( MAX_16, alpha ) ), ftmp_exp, &smoothed_psd_exp[i] ); /* smoothed_psd_exp[i] */ + smoothed_psd_exp_max = s_max( smoothed_psd_exp_max, smoothed_psd_exp[i] ); #else st->hFdCngDec->smoothed_psd_fx[i] = L_add( Mpy_32_16_1( st->hFdCngDec->smoothed_psd_fx[i], alpha ), Mpy_32_16_1( ftmp, sub( MAX_16, alpha ) ) ); /* st->hFdCngDec->smoothed_psd_exp */ #endif move32(); } +#ifdef NONBE_FIX_2575 + /* Find common exponent for smoothed_psd_fx[] */ + FOR( i = hFdCngCom->startBand; i < hFdCngCom->stopFFTbin; i++ ) + { + st->hFdCngDec->smoothed_psd_fx[i] = L_shr( st->hFdCngDec->smoothed_psd_fx[i], sub( smoothed_psd_exp_max, smoothed_psd_exp[i] ) ); + } + st->hFdCngDec->smoothed_psd_exp = smoothed_psd_exp_max; + move16(); +#endif + /* update msNoiseEst in SID and NO_DATA frames */ bandcombinepow( &st->hFdCngDec->smoothed_psd_fx[hFdCngCom->startBand], st->hFdCngDec->smoothed_psd_exp, sub( hFdCngCom->stopFFTbin, hFdCngCom->startBand ), st->hFdCngDec->part_shaping, st->hFdCngDec->nFFTpart_shaping, st->hFdCngDec->psize_inv_shaping, st->hFdCngDec->msNoiseEst, &st->hFdCngDec->msNoiseEst_exp ); -- GitLab From 3448f78d9951bad5e5452ddcac39d643df75adcf Mon Sep 17 00:00:00 2001 From: Manuel Jander Date: Wed, 6 May 2026 15:07:16 +0200 Subject: [PATCH 3/5] Fix wrong compare value (was greater than instead of less than). --- lib_dec/ivas_stereo_cng_dec_fx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_dec/ivas_stereo_cng_dec_fx.c b/lib_dec/ivas_stereo_cng_dec_fx.c index 24150ade1..8abc4700c 100644 --- a/lib_dec/ivas_stereo_cng_dec_fx.c +++ b/lib_dec/ivas_stereo_cng_dec_fx.c @@ -859,7 +859,7 @@ static void stereo_dft_generate_comfort_noise_fx( #endif } #ifdef NONBE_FIX_2575 - ELSE IF( EQ_16( BASOP_Util_Cmp_Mant32Exp( ftmp, ftmp_exp, st->hFdCngDec->smoothed_psd_fx[i], st->hFdCngDec->smoothed_psd_exp ), 1 ) ) + ELSE IF( EQ_16( BASOP_Util_Cmp_Mant32Exp( ftmp, ftmp_exp, st->hFdCngDec->smoothed_psd_fx[i], st->hFdCngDec->smoothed_psd_exp ), -1 ) ) #else ELSE IF( LT_32( ftmp, st->hFdCngDec->smoothed_psd_fx[i] ) ) #endif -- GitLab From b04d03c2299980e2dac4fe57ee24ee02c21ed9ab Mon Sep 17 00:00:00 2001 From: Manuel Jander Date: Wed, 6 May 2026 22:16:49 +0200 Subject: [PATCH 4/5] Remove rescale to Q4 of sidNoiseEstLp and sidNoiseEst. Remove duplicated call to ApplyFdCng_fx() (issue #2578). --- lib_dec/acelp_core_dec_fx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib_dec/acelp_core_dec_fx.c b/lib_dec/acelp_core_dec_fx.c index 4ca6b2e8c..c43fc0bbe 100644 --- a/lib_dec/acelp_core_dec_fx.c +++ b/lib_dec/acelp_core_dec_fx.c @@ -688,6 +688,7 @@ ivas_error acelp_core_dec_fx( ApplyFdCng_fx( psyn_fx, st->Q_syn, NULL, 0, realBuffer_fx, imagBuffer_fx, NULL, st, 0, ( st->coder_type == AUDIO && !st->GSC_noisy_speech ) ); +#ifndef NONBE_FIX_2575 Word16 new_sidNoiseEstExp = 31 - Q4; move16(); Scale_sig32( st->hFdCngDec->hFdCngCom->sidNoiseEstLp, NPART, sub( st->hFdCngDec->hFdCngCom->sidNoiseEstExp, new_sidNoiseEstExp ) ); // Q(31-sidNoiseEstExp) @@ -700,9 +701,10 @@ ivas_error acelp_core_dec_fx( st->hFdCngDec->hFdCngCom->cngNoiseLevelExp = new_cngNoiseLevelExp; move16(); - test(); ApplyFdCng_fx( psyn_fx, st->Q_syn, NULL, 0, realBuffer_fx, imagBuffer_fx, NULL, st, 0, ( EQ_16( st->coder_type, AUDIO ) && !st->GSC_noisy_speech ) ); - +#else + test(); +#endif IF( st->hFdCngDec->hFdCngCom->cngNoiseLevelExp < 0 ) { Scale_sig32( st->hFdCngDec->hFdCngCom->cngNoiseLevel, FFTCLDFBLEN, st->hFdCngDec->hFdCngCom->cngNoiseLevelExp ); // Q(31-cngNoiseLevelExp) -- GitLab From 69eb54668b0ee7424b6210d0c6113c727606ae76 Mon Sep 17 00:00:00 2001 From: Manuel Jander Date: Wed, 6 May 2026 22:47:04 +0200 Subject: [PATCH 5/5] Correct instrumentation. --- lib_dec/acelp_core_dec_fx.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib_dec/acelp_core_dec_fx.c b/lib_dec/acelp_core_dec_fx.c index c43fc0bbe..d371353f0 100644 --- a/lib_dec/acelp_core_dec_fx.c +++ b/lib_dec/acelp_core_dec_fx.c @@ -686,9 +686,9 @@ ivas_error acelp_core_dec_fx( move32(); } +#ifndef NONBE_FIX_2575 ApplyFdCng_fx( psyn_fx, st->Q_syn, NULL, 0, realBuffer_fx, imagBuffer_fx, NULL, st, 0, ( st->coder_type == AUDIO && !st->GSC_noisy_speech ) ); -#ifndef NONBE_FIX_2575 Word16 new_sidNoiseEstExp = 31 - Q4; move16(); Scale_sig32( st->hFdCngDec->hFdCngCom->sidNoiseEstLp, NPART, sub( st->hFdCngDec->hFdCngCom->sidNoiseEstExp, new_sidNoiseEstExp ) ); // Q(31-sidNoiseEstExp) @@ -700,11 +700,10 @@ ivas_error acelp_core_dec_fx( Scale_sig32( st->hFdCngDec->hFdCngCom->cngNoiseLevel, FFTCLDFBLEN, sub( st->hFdCngDec->hFdCngCom->cngNoiseLevelExp, new_cngNoiseLevelExp ) ); // Q(31-cngNoiseLevelExp) st->hFdCngDec->hFdCngCom->cngNoiseLevelExp = new_cngNoiseLevelExp; move16(); - - ApplyFdCng_fx( psyn_fx, st->Q_syn, NULL, 0, realBuffer_fx, imagBuffer_fx, NULL, st, 0, ( EQ_16( st->coder_type, AUDIO ) && !st->GSC_noisy_speech ) ); -#else - test(); #endif + test(); + ApplyFdCng_fx( psyn_fx, st->Q_syn, NULL, 0, realBuffer_fx, imagBuffer_fx, NULL, st, 0, ( EQ_16( st->coder_type, AUDIO ) && !st->GSC_noisy_speech ) ); + IF( st->hFdCngDec->hFdCngCom->cngNoiseLevelExp < 0 ) { Scale_sig32( st->hFdCngDec->hFdCngCom->cngNoiseLevel, FFTCLDFBLEN, st->hFdCngDec->hFdCngCom->cngNoiseLevelExp ); // Q(31-cngNoiseLevelExp) -- GitLab