From 29beaeb5a329060be51ec90b6909e8b262cca100 Mon Sep 17 00:00:00 2001 From: Sandesh Venkatesh Date: Tue, 23 Jan 2024 17:04:42 +0530 Subject: [PATCH] Converted few functions in dec_tcx [x] Few functions in dec_tcx converted to fixed point. [x] Changes made in dependent functions to call the converted functions. --- lib_com/cnst.h | 5 +- lib_com/ivas_cnst.h | 1 + lib_com/ivas_prot_fx.h | 29 + lib_com/ivas_rom_com_fx.c | 5 + lib_com/ivas_rom_com_fx.h | 1 + lib_com/prot_fx2.h | 63 +- lib_com/tcx_utils_fx.c | 192 ++++++ lib_com/tools_fx.c | 92 +++ lib_dec/core_dec_init_fx.c | 2 +- lib_dec/dec_tcx_fx.c | 484 +++++++++++++-- lib_dec/igf_dec_fx.c | 33 + lib_dec/ivas_mct_dec.c | 6 + lib_dec/ivas_mdct_core_dec.c | 49 ++ lib_dec/ivas_stereo_mdct_core_dec.c | 18 + lib_dec/stat_dec.h | 12 +- lib_dec/tonalMDCTconcealment_fx.c | 928 +++++++++++++++++++++++++++- 16 files changed, 1866 insertions(+), 54 deletions(-) diff --git a/lib_com/cnst.h b/lib_com/cnst.h index cdc395d7a..4e1d2e47a 100644 --- a/lib_com/cnst.h +++ b/lib_com/cnst.h @@ -1086,8 +1086,9 @@ enum #define NBITS_NOISE_FILL_LEVEL 3 /* Number of bits used for coding noise filling level for each range */ #define NF_GAIN_BITS ( NBITS_TCX_GAIN + NOISE_FILL_RANGES * NBITS_NOISE_FILL_LEVEL ) #define MIN_NOISE_FILLING_HOLE 8 -#define HOLE_SIZE_FROM_LTP_FLT( gain ) ( 4 + ( int16_t )( 2.0f * gain * ( 4.0f / 0.625f ) ) ) -#define HOLE_SIZE_FROM_LTP(gain) (add(4, extract_h(L_shr(L_mult0(gain, 0x6666), 10)))) /* 0x6666 -> 2.0*(4.0/0.625) (4Q11) */ +#define HOLE_SIZE_FROM_LTP_FLT( gain ) ( 4 + ( int16_t )( 2.0f * gain * ( 4.0f / 0.625f ) ) ) +#define HOLE_SIZE_FROM_LTP( gain ) (add(4, extract_h(L_shr(L_mult0(gain, 0x6666), 10)))) /* gain (Q15), 0x6666 = 2.0*(4.0/0.625) (4Q11) */ +#define HOLE_SIZE_FROM_LTP32( gain ) (add(4, extract_h(L_shr(Mpy_32_32(gain, 0x66666667), 11)))) /* gain (Q31), 0x66666667 = 2.0*(4.0/0.625) (4Q27) */ #define FDNS_NPTS 64 #define AVG_TCX20_LSF_BITS 40 diff --git a/lib_com/ivas_cnst.h b/lib_com/ivas_cnst.h index f71a41183..aa3057070 100644 --- a/lib_com/ivas_cnst.h +++ b/lib_com/ivas_cnst.h @@ -848,6 +848,7 @@ enum fea_names #define SNS_MEANS_BITS_4_FRAC 14 #define MDCT_ST_PLC_FADEOUT_MIN_NOISE_NRG 0.001f +#define MDCT_ST_PLC_FADEOUT_MIN_NOISE_NRG_Q31 2147483 #define MDCT_ST_PLC_FADEOUT_MAX_CONC_FRAME 2 * FRAMES_PER_SEC #define MDCT_ST_PLC_FADEOUT_TO_ZERO_LEN 20 #define MDCT_ST_PLC_FADEOUT_DELAY_4_LSP_FADE 3 diff --git a/lib_com/ivas_prot_fx.h b/lib_com/ivas_prot_fx.h index 179700c3e..081f2ceb6 100644 --- a/lib_com/ivas_prot_fx.h +++ b/lib_com/ivas_prot_fx.h @@ -262,6 +262,29 @@ void decoder_tcx_invQ_fx( const Word16 frame_cnt /* i : frame counter in the super frame */ ); +void decoder_tcx_noisefilling_fx( + Decoder_State *st, /* i/o: coder memory state */ + const Word32 concealment_noise[L_FRAME48k], + const Word16 concealment_noise_exp, + const Word16 A[], /* i : coefficients NxAz[M+1] */ + const Word16 L_frameTCX_glob, + const Word16 L_spec, + const Word16 L_frame, + const Word16 L_frameTCX, + Word32 x[], + Word16 *x_e, + Word16 *gainlpc2, + Word16 *gainlpc2_e, + int16_t *temp_concealment_method, + const Word16 gain_tcx, + const Word16 gain_tcx_e, + const Word16 *prm_sqQ, + Word16 nf_seed, + const Word16 bfi, /* i : Bad frame indicator */ + const Word16 MCT_flag, + const Word16 frame_cnt /* i : frame counter in the super frame*/ +); + void init_tcx_info_fx( Decoder_State *st, /* i/o: coder memory state */ const Word16 L_frame_glob, /* i : global frame length */ @@ -280,6 +303,12 @@ void IGFDecReplicateTCX10State_fx( IGF_DEC_INSTANCE_HANDLE hIGFDec /* i/o: instance handle of IGF Decoder */ ); +Word16 get_igf_startline( + Decoder_State *st, /* i : decoder state */ + const Word16 L_frame, /* i : length of the frame */ + const Word16 L_frameTCX /* i : full band frame length */ +); + void stereo_dft_dec_analyze_fx( CPE_DEC_HANDLE hCPE, /* i/o: CPE decoder structure */ const Word32 *input_fx, /* i : input signal */ diff --git a/lib_com/ivas_rom_com_fx.c b/lib_com/ivas_rom_com_fx.c index 8bbe1709a..c194b6285 100644 --- a/lib_com/ivas_rom_com_fx.c +++ b/lib_com/ivas_rom_com_fx.c @@ -195,6 +195,11 @@ const Word16 ivas_cos_twiddle_80_fx[ IVAS_80_PT_LEN >> 1 ] = { SHC( 0x26f4 ), SHC( 0x2223 ), SHC( 0x1d45 ), SHC( 0x185a ), SHC( 0x1367 ), SHC( 0x0e6b ), SHC( 0x096a ), SHC( 0x0465 ), }; +const Word16 nf_tw_smoothing_coeffs_fx[N_LTP_GAIN_MEMS] = +{ + 13107, 6553, 6553, 6553 +}; + const Word16 dft_trigo_12k8_fx[STEREO_DFT_N_12k8_ENC / 4 + 1] = { 0, 402, 804, 1206, 1607, 2009, 2410, 2811, 3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997, 6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126, 9512, 9896, 10278, 10659, diff --git a/lib_com/ivas_rom_com_fx.h b/lib_com/ivas_rom_com_fx.h index 3d0fdff06..e23fe5c34 100644 --- a/lib_com/ivas_rom_com_fx.h +++ b/lib_com/ivas_rom_com_fx.h @@ -48,6 +48,7 @@ extern const Word16 ivas_sin_twiddle_160_fx[ IVAS_160_PT_LEN >> 1 ]; extern const Word16 ivas_cos_twiddle_160_fx[ IVAS_160_PT_LEN >> 1 ]; extern const Word16 ivas_sin_twiddle_80_fx[ IVAS_80_PT_LEN >> 1 ]; extern const Word16 ivas_cos_twiddle_80_fx[ IVAS_80_PT_LEN >> 1 ]; +extern const Word16 nf_tw_smoothing_coeffs_fx[N_LTP_GAIN_MEMS]; extern const Word16 dft_trigo_12k8_fx[STEREO_DFT_N_12k8_ENC / 4 + 1]; extern const Word16 dft_trigo_32k_fx[STEREO_DFT_N_32k_ENC / 4 + 1]; extern const Word16 dft_trigo_48k_fx[STEREO_DFT_N_MAX_ENC / 4 + 1]; diff --git a/lib_com/prot_fx2.h b/lib_com/prot_fx2.h index 20c7537a4..82d5afa61 100644 --- a/lib_com/prot_fx2.h +++ b/lib_com/prot_fx2.h @@ -70,6 +70,7 @@ float fix_to_float( Word32 number, Word32 Q ); Word16 float_to_fix16( float number, Word16 Q ); // Word16 to Float float fix16_to_float( Word16 number, Word16 Q ); + void floatToFixed_arrL(const float * f, Word32* i, Word16 Q, Word16 l); void floatToFixed_arr(const float * f, Word16* i, Word16 Q, Word16 l); void fixedToFloat_arrL(const Word32 *i, float * f, Word16 Q, Word16 l); @@ -82,7 +83,24 @@ Word16 Q_factor_arrL(float* x, Word16 l); Word32 floatToFixed(const float f, Word16 Q); float fixedToFloat(const Word32 i, Word16 Q); - Word32 Mult_32_16( +// Float to 32-bit Mantissa and Exponent using frexp +void f2me(float n, Word32 *mantissa, Word16 *expo); +// 32-bit Mantissa and Exponent to Float using ldexp +float me2f(Word32 m, Word16 expo); +// Float to 32-bit Mantissa Array and Exponent +void f2me_buf(const float *x, Word32 *m, Word16 *e, const Word32 n); +// 32-bit Mantissa Array and Exponent to Float +void me2f_buf(const Word32 *m, const Word16 e, float *out, const Word32 n); +// Float to 16-bit Mantissa and Exponent using frexp +void f2me_16(float n, Word16 *mantissa, Word16 *expo); +// 16-bit Mantissa and Exponent to Float using ldexp +float me2f_16(Word16 m, Word16 expo); +// Float to 16-bit Mantissa Array and Exponent +void f2me_buf_16(const float *x, Word16 *m, Word16 *e, const Word32 n); +// 16-bit Mantissa Array and Exponent to Float +void me2f_buf_16(const Word16 *m, const Word16 e, float *out, const Word32 n); + +Word32 Mult_32_16( Word32 a, Word16 b); @@ -3608,6 +3626,20 @@ void tcx_noise_filling( const Word16 element_mode /* i : IVAS element mode */ ); +void tcx_noise_filling_with_shift( + Word32* Q, + Word16* Q_e, + Word16 seed, + const Word16 iFirstLine, + const Word16 lowpassLine, + const Word16 nTransWidth, + const Word16 L_frame, + const Word16 tiltCompFactor, + Word16 fac_ns, + Word16* infoTCXNoise, + const Word16 element_mode /* i : IVAS element mode */ +); + void InitTnsConfigs( const Word16 bwidth, const Word16 L_frame, @@ -5273,6 +5305,17 @@ void TonalMDCTConceal_SaveFreqSignal( #endif ); +void TonalMDCTConceal_SaveFreqSignal_ivas_fx( + TonalMDCTConcealPtr hTonalMDCTConc, + const Word32 *mdctSpectrum, + const Word16 mdctSpectrum_exp, + const Word16 nNewSamples, + const Word16 nNewSamplesCore, + const Word16 *scaleFactors, + const Word16 *scaleFactors_exp, + const Word16 gain_tcx_exp, + const Word16 infoIGFStartLine); + /* The call to TonalMDCTConceal_UpdateState() should be called after TonalMDCTConceal_Apply. */ TONALMDCTCONCEAL_ERROR TonalMDCTConceal_UpdateState(TonalMDCTConcealPtr self, Word16 nNewSamples, @@ -5316,6 +5359,24 @@ void TonalMDCTConceal_Apply( #endif ); +/* Conceals the lost frame using the FD signal previously stored using + * TonalMDCTConceal_SaveFreqSignal. Stores the concealed noise part of + * the signal in mdctSpectrum, the rest of the spectrum is unchanged. */ +void TonalMDCTConceal_InsertNoise_ivas_fx( + const TonalMDCTConcealPtr hTonalMDCTConc, /*IN */ + Word32 *mdctSpectrum, + Word16 *mdctSpectrum_exp, + const Word16 tonalConcealmentActive, + Word16 *pSeed, /*IN/OUT*/ + const Word16 tiltCompFactor, + const Word16 crossfadeGain, + const Word32 concealment_noise[L_FRAME48k], + const Word16 concealment_noise_e, + const Word32 cngLevelBackgroundTrace_bfi, + const Word16 cngLevelBackgroundTrace_e, + const Word16 crossOverFreq ); + + /* Conceals the lost frame using the FD signal previously stored using * TonalMDCTConceal_SaveFreqSignal. Stores the concealed noise part of * the signal in mdctSpectrum, the rest of the spectrum is unchanged. */ diff --git a/lib_com/tcx_utils_fx.c b/lib_com/tcx_utils_fx.c index 0ff6259ee..a0e8bd216 100644 --- a/lib_com/tcx_utils_fx.c +++ b/lib_com/tcx_utils_fx.c @@ -1704,6 +1704,198 @@ void tcx_noise_filling( } +void tcx_noise_filling_with_shift( + Word32 *Q, + Word16 *Q_e, + Word16 seed, + const Word16 iFirstLine, + const Word16 lowpassLine, + const Word16 nTransWidth, + const Word16 L_frame, + const Word16 tiltCompFactor, + Word16 fac_ns, + Word16 *infoTCXNoise, + const Word16 element_mode /* i : IVAS element mode */ +) +{ + Word16 i, m, segmentOffset; + Word16 win; /* window coefficient */ + Word16 tilt_factor; + Word32 nrg; + Word16 tmp1, tmp2, s; + Word32 tmp32; + Word16 new_Q_e[N_MAX]; + + set16_fx( new_Q_e, *Q_e, N_MAX ); + + /* get inverse frame length */ + tmp1 = getInvFrameLen( L_frame ); + + /* tilt_factor = (float)pow(max_val(0.375f, tiltCompFactor), 1.0f/(float)L_frame); */ + tmp32 = BASOP_Util_Log2( L_deposit_h( s_max( 0x3000, tiltCompFactor ) ) ); /* 6Q25 */ + tmp32 = L_shr( Mpy_32_16_1( tmp32, tmp1 ), 6 ); + BASOP_SATURATE_WARNING_OFF_EVS; + tilt_factor = round_fx( BASOP_Util_InvLog2( tmp32 ) ); + BASOP_SATURATE_WARNING_ON_EVS; + + /* find last nonzero line below iFirstLine, use it as start offset */ + i = iFirstLine; + move16(); + tmp1 = shr( iFirstLine, 1 ); + IF( EQ_16( element_mode, IVAS_CPE_MDCT ) ) /* ... but only in mono or parametric stereo since it may cause binaural unmasking in discrete stereo */ + { + segmentOffset = i; + move16(); + } + ELSE + { + FOR( ; i > tmp1; i-- ) + { + IF( Q[i] != 0 ) + { + BREAK; + } + } + /* fac_ns *= (float)pow(tilt_factor, (float)i); */ + FOR( m = 0; m < i; m++ ) + { + fac_ns = mult_r( fac_ns, tilt_factor ); + } + i = add( i, 1 ); + segmentOffset = i; + } + nrg = L_deposit_l( 1 ); + win = 0; + move16(); + move16(); + + FOR( ; i < lowpassLine; i++ ) + { + fac_ns = mult_r( fac_ns, tilt_factor ); + + IF( Q[i] != 0 ) + { + IF( win > 0 ) + { + /* RMS-normalize current noise-filled segment */ + tmp1 = BASOP_Util_Divide3216_Scale( nrg, sub( i, segmentOffset ), &s ); /* mean */ + // Q-factor of nrg is -8. exp = 31-(-8) = 39 + s = add( s, 39 - 15 ); /* scaling */ + tmp1 = ISqrt16( tmp1, &s ); /* 1/RMS */ + tmp1 = mult_r( tmp1, inv_int[nTransWidth] ); /* compensate win */ + + tmp2 = sub( i, win ); + IF( LT_16( segmentOffset, tmp2 ) ) + { + FOR( m = segmentOffset; m < tmp2; m++ ) + { + Word16 nrm = 31; + + Q[m] = Mpy_32_16_1( Q[m], tmp1 ); + IF( Q[m] ) + { + nrm = norm_l( Q[m] ); + } + Q[m] = L_shl( Q[m], nrm ); + new_Q_e[m] = sub( add( new_Q_e[m], s ), nrm ); + move32(); + } + } + + tmp2 = mult( tmp1, inv_int[nTransWidth] ); + tmp1 = extract_l( L_mult0( tmp2, win ) ); + FOR( m = sub( i, win ); m < i; m++ ) + { + Word16 nrm = 31; + + Q[m] = Mpy_32_16_1( Q[m], tmp1 ); + IF( Q[m] ) + { + nrm = norm_l( Q[m] ); + } + Q[m] = L_shl( Q[m], nrm ); + new_Q_e[m] = sub( add( new_Q_e[m], s ), nrm ); + move32(); + win = sub( win, 1 ); + tmp1 = sub( tmp1, tmp2 ); + } + + nrg = L_deposit_l( 1 ); /* start new segment: reset noise segment energy */ + } + segmentOffset = add( i, 1 ); + } + ELSE /* line is zero, so fill line and update window and energy */ + { + IF( LT_16( win, nTransWidth ) ) + { + win = add( win, 1 ); + } + + Word16 nrm = 31; + + seed = own_random2_fx( seed ); + Q[i] = L_mult0( mult( seed, fac_ns ), win ); + IF( Q[i] ) + { + nrm = norm_l( Q[i] ); + } + Q[i] = L_shl( Q[i], nrm ); + new_Q_e[i] = 31 - nrm; + move32(); + + tmp1 = shr( seed, 4 ); + nrg = L_mac0( nrg, tmp1, tmp1 ); /* sum up energy of current noise segment */ + + IF( infoTCXNoise ) /* set noiseflags for IGF */ + { + infoTCXNoise[i] = 1; + move16(); + } + } + } + + IF( win > 0 ) + { + /* RMS-normalize uppermost noise-filled segment */ + tmp1 = BASOP_Util_Divide3216_Scale( nrg, sub( lowpassLine, segmentOffset ), &s ); /* mean */ + // Q-factor of nrg is -8. exp = 31-(-8) = 39 + s = add( s, 39 - 15 ); /* compensate energy scaling */ + tmp1 = ISqrt16( tmp1, &s ); /* 1/RMS */ + tmp1 = mult_r( tmp1, inv_int[nTransWidth] ); /* compensate win */ + + FOR( m = segmentOffset; m < lowpassLine; m++ ) + { + Word16 nrm = 31; + + /* + at this point: + - flt Q[m] = (Q[m] * 2^(new_Q_e[m] - 31)) / (nTransWidth*nTransWidth) + - flt tmp1 = (tmp1 * 2^(s - 15)) * (nTransWidth*nTransWidth) + */ + Q[m] = Mpy_32_16_1( Q[m], tmp1 ); + IF( Q[m] ) + { + nrm = norm_l( Q[m] ); + } + Q[m] = L_shl( Q[m], nrm ); + new_Q_e[m] = add( new_Q_e[m], s - nrm ); + move32(); + } + } + + Word16 max_e = 0; + FOR( i = 0; i < lowpassLine; i++ ) + { + max_e = s_max( max_e, new_Q_e[i] ); + } + + FOR( i = 0; i < lowpassLine; i++ ) + { + Q[i] = L_shr( Q[i], sub( max_e, new_Q_e[i] ) ); + } + + *Q_e = max_e; +} /*--------------------------------------------------------------- diff --git a/lib_com/tools_fx.c b/lib_com/tools_fx.c index d900420a4..0c02046c5 100644 --- a/lib_com/tools_fx.c +++ b/lib_com/tools_fx.c @@ -89,6 +89,98 @@ float fix16_to_float( Word16 number, Word16 Q ) return ret; } +// Float to 32-bit Mantissa and Exponent +void f2me( float n, Word32 *mantissa, Word16 *expo ) +{ + Word32 e; + float mf = (float) frexp( n, &e ); + *expo = (Word16) e; + *mantissa = float_to_fix( mf, Q31 ); +} + +// 32-bit Mantissa and Exponent to Float +float me2f( Word32 m, Word16 expo ) +{ + float mf = fix_to_float( m, Q31 ); + return (float) ldexp( mf, expo ); +} + +// Float buffer to 32-bit mantissa buffer and common exponent. +void f2me_buf( const float *x, Word32 *m, Word16 *e, const Word32 n ) +{ + Word16 max_e = -32, tmp_e; + Word32 i; + + for ( i = 0; i < n; i++ ) + { + f2me( x[i], &m[i], &tmp_e ); + max_e = ( max_e > tmp_e ) ? max_e : tmp_e; + } + + for ( i = 0; i < n; i++ ) + { + f2me( x[i], &m[i], &tmp_e ); + m[i] = L_shr( m[i], max_e - tmp_e ); + } + + *e = max_e; +} + +// 32-bit Mantissa buffer and exponent into float buffer. +void me2f_buf( const Word32 *m, const Word16 e, float *out, const Word32 n ) +{ + for ( int i = 0; i < n; i++ ) + { + out[i] = me2f( m[i], e ); + } +} + +// Float to 16-bit Mantissa and Exponent +void f2me_16( float n, Word16 *mantissa, Word16 *expo ) +{ + Word32 e; + float mf = (float) frexp( n, &e ); + *expo = (Word16) e; + *mantissa = float_to_fix16( mf, 15 ); +} + +// 16-bit Mantissa and Exponent to Float +float me2f_16( Word16 m, Word16 expo ) +{ + float mf = fix16_to_float( m, 15 ); + return (float) ldexp( mf, expo ); +} + +// Float buffer to 16-bit mantissa buffer and common exponent. +void f2me_buf_16( const float *x, Word16 *m, Word16 *e, const Word32 n ) +{ + Word16 max_e = -16, tmp_e; + Word32 i; + + for ( i = 0; i < n; i++ ) + { + f2me_16( x[i], &m[i], &tmp_e ); + max_e = ( max_e > tmp_e ) ? max_e : tmp_e; + } + + for ( i = 0; i < n; i++ ) + { + f2me_16( x[i], &m[i], &tmp_e ); + m[i] = shr( m[i], max_e - tmp_e ); + } + + *e = max_e; +} + +// 16-bit Mantissa buffer and exponent into float buffer. +void me2f_buf_16( const Word16 *m, const Word16 e, float *out, const Word32 n ) +{ + for ( int i = 0; i < n; i++ ) + { + out[i] = me2f_16( m[i], e ); + } +} + int16_t norm_ul(uint32_t UL_var1) { int16_t var_out; diff --git a/lib_dec/core_dec_init_fx.c b/lib_dec/core_dec_init_fx.c index b1b8005ba..6eebcafd6 100644 --- a/lib_dec/core_dec_init_fx.c +++ b/lib_dec/core_dec_init_fx.c @@ -957,7 +957,7 @@ void open_decoder_LPD( st->tonalMDCTconceal.lastBlockData.nSamples = 0; move16(); - TonalMDCTConceal_Init(&st->tonalMDCTconceal, hTcxDec->L_frameTCX, st->L_frame, FDNS_NPTS, st->hTcxCfg); + TonalMDCTConceal_Init_ivas_fx( &st->tonalMDCTconceal, hTcxDec->L_frameTCX, st->L_frame, FDNS_NPTS, st->hTcxCfg ); } st->last_tns_active = 0; st->second_last_tns_active = 0; diff --git a/lib_dec/dec_tcx_fx.c b/lib_dec/dec_tcx_fx.c index f99e83568..2b06e10f3 100644 --- a/lib_dec/dec_tcx_fx.c +++ b/lib_dec/dec_tcx_fx.c @@ -14,6 +14,8 @@ #include "math.h" #include "ivas_prot.h" #include "ivas_prot_fx.h" +#include "ivas_rom_com.h" +#include "ivas_rom_com_fx.h" extern const Word16 T_DIV_L_Frame[];/*0Q15 * 2^-7 */ @@ -2555,16 +2557,16 @@ void decoder_tcx_fx( Word16 A_fx[M + 1], A_q; double max_val = 0; - for ( int j = 0; j < M + 1; j++ ) + FOR ( Word16 j = 0; j < M + 1; j++ ) { max_val = max( max_val, fabs( A[j] ) ); } - if ( fabs( max_val ) < 1.0 ) + IF ( fabs( max_val ) < 1.0 ) A_q = Q15; - else + ELSE A_q = norm_s( (Word16) max_val ); - for ( int j = 0; j < M + 1; j++ ) + FOR ( Word16 j = 0; j < M + 1; j++ ) { A_fx[j] = float_to_fix16( A[j], A_q ); } @@ -2580,58 +2582,33 @@ void decoder_tcx_fx( st->hTcxLtpDec->tcxltp_gain = float_to_fix16( st->hTcxLtpDec->tcxltp_gain_float, Q15 ); st->inv_gamma = FL2WORD16_SCALE( 1 / st->gamma_float, 1 ); st->hTcxCfg->preemph_fac = FL2WORD16( st->hTcxCfg->preemph_fac_flt ); - - if ( (Word16) st->last_gain_syn_deemph_float == 0 ) - st->last_gain_syn_deemph_e = 0; - else - st->last_gain_syn_deemph_e = 15 - norm_s( (Word16) st->last_gain_syn_deemph_float ); - - if ( (Word16) st->last_concealed_gain_syn_deemph_float == 0 ) - st->last_concealed_gain_syn_deemph_e = 0; - else - st->last_concealed_gain_syn_deemph_e = 15 - norm_s( (Word16) st->last_concealed_gain_syn_deemph_float ); - - if ( (Word16) st->hTcxDec->old_gaintcx_bfi_float == 0 ) - st->hTcxDec->old_gaintcx_bfi_e = 0; - else - st->hTcxDec->old_gaintcx_bfi_e = 15 - norm_s( (Word16) st->hTcxDec->old_gaintcx_bfi_float ); - - st->last_gain_syn_deemph = float_to_fix16( st->last_gain_syn_deemph_float, 15 - st->last_gain_syn_deemph_e ); - st->last_concealed_gain_syn_deemph = float_to_fix16( st->last_concealed_gain_syn_deemph_float, 15 - st->last_concealed_gain_syn_deemph_e ); - st->hTcxDec->old_gaintcx_bfi = float_to_fix16( st->hTcxDec->old_gaintcx_bfi_float, 15 - st->hTcxDec->old_gaintcx_bfi_e ); + f2me_16( st->last_gain_syn_deemph_float, &st->last_gain_syn_deemph, &st->last_gain_syn_deemph_e ); + f2me_16( st->last_concealed_gain_syn_deemph_float, &st->last_concealed_gain_syn_deemph, &st->last_concealed_gain_syn_deemph_e ); + f2me_16( st->hTcxDec->old_gaintcx_bfi_float, &st->hTcxDec->old_gaintcx_bfi, &st->hTcxDec->old_gaintcx_bfi_e ); /* end temp init*/ decoder_tcx_invQ_fx( st, prm, A_fx, Aind, L_spec, L_frame, L_frameTCX, x_fx, &x_e, gainlpc2_fx, gainlpc2_e, &xn_buf_fx[0], &fUseTns, &tnsData, &gain_tcx_fx, &gain_tcx_e, &prm_sqQ, &nf_seed, bfi, frame_cnt ); /* TODO: remove float dependency */ - st->hTcxDec->stepCompensate_float = - (float) ( st->hTcxDec->stepCompensate * pow( 2, st->hTcxDec->stepCompensate_e - 15 ) ); - st->hTcxDec->gainHelper_float = - (float) ( st->hTcxDec->gainHelper * pow( 2, st->hTcxDec->gainHelper_e - 15 ) ); - st->last_concealed_gain_syn_deemph_float = - (float) ( st->last_concealed_gain_syn_deemph * pow( 2, st->last_concealed_gain_syn_deemph_e - 15 ) ); - st->last_gain_syn_deemph_float = - (float) ( st->last_gain_syn_deemph * pow( 2, st->last_gain_syn_deemph_e - 15 ) ); - st->hTcxDec->old_gaintcx_bfi_float = - (float) ( st->hTcxDec->old_gaintcx_bfi * pow( 2, st->hTcxDec->old_gaintcx_bfi_e - 15 ) ); - st->hTcxDec->cummulative_damping_tcx_float = - fix16_to_float( st->hTcxDec->cummulative_damping_tcx, Q15 ); - st->hTcxDec->damping_float = - fix16_to_float( st->hTcxDec->damping, Q14 ); + st->hTcxDec->stepCompensate_float = me2f_16( st->hTcxDec->stepCompensate, st->hTcxDec->stepCompensate_e ); + st->hTcxDec->gainHelper_float = me2f_16( st->hTcxDec->gainHelper, st->hTcxDec->gainHelper_e ); + st->last_concealed_gain_syn_deemph_float = me2f_16( st->last_concealed_gain_syn_deemph, st->last_concealed_gain_syn_deemph_e ); + st->last_gain_syn_deemph_float = me2f_16( st->last_gain_syn_deemph, st->last_gain_syn_deemph_e ); + st->hTcxDec->old_gaintcx_bfi_float = me2f_16( st->hTcxDec->old_gaintcx_bfi, st->hTcxDec->old_gaintcx_bfi_e ); + + st->hTcxDec->cummulative_damping_tcx_float = fix16_to_float( st->hTcxDec->cummulative_damping_tcx, Q15 ); + st->hTcxDec->damping_float = fix16_to_float( st->hTcxDec->damping, Q14 ); st->lp_gainp = fix_to_float( st->Mode2_lp_gainp, Q16 ); - for ( int j = 0; j < L_frameTCX; j++ ) + me2f_buf( x_fx, x_e, x, L_frameTCX ); + gain_tcx = me2f_16( gain_tcx_fx, gain_tcx_e ); + FOR ( Word16 j = 0; j < FDNS_NPTS; j++ ) { - x[j] = (float) ( x_fx[j] * pow( 2, x_e - 31 ) ); + gainlpc2[j] = me2f_16( gainlpc2_fx[j], gainlpc2_e[j] ); } - gain_tcx = (float) ( gain_tcx_fx * pow( 2, gain_tcx_e - 15 ) ); - for ( int j = 0; j < FDNS_NPTS; j++ ) + FOR ( Word16 j = 0; j < max( max( L_frame, L_spec ), L_frameTCX ); j++ ) { - gainlpc2[j] = (float) ( gainlpc2_fx[j] * pow( 2, gainlpc2_e[j] - 15 ) ); - } - for ( int i = 0; i < max( max( L_frame, L_spec ), L_frameTCX ); i++ ) - { - xn_buf[i] = fix16_to_float( xn_buf_fx[i], Q14 ); + xn_buf[j] = fix16_to_float( xn_buf_fx[j], Q14 ); } #if 0 @@ -2664,7 +2641,28 @@ void decoder_tcx_fx( #endif #endif +#ifdef IVAS_FLOAT_FIXED + f2me_buf( x, x_fx, &x_e, N_MAX ); + FOR( Word16 j = 0; j < FDNS_NPTS; j++ ) + { + f2me_16( gainlpc2[j], &gainlpc2_fx[j], &gainlpc2_e[j] ); + } + f2me_16( gain_tcx, &gain_tcx_fx, &gain_tcx_e ); + st->hTcxLtpDec->tcxltp_gain = float_to_fix16( st->hTcxLtpDec->tcxltp_gain_float, Q15 ); + st->hTcxDec->cummulative_damping_tcx = float_to_fix16( st->hTcxDec->cummulative_damping_tcx_float, Q15 ); + FOR( Word16 l = 0; l < N_LTP_GAIN_MEMS; l++ ) + { + st->hTcxDec->ltpGainMemory_fx[l] = float_to_fix16( st->hTcxDec->ltpGainMemory[l], Q15 ); + } + decoder_tcx_noisefilling_fx( st, NULL, 0, A_fx, L_frameTCX_glob, L_spec, L_frame, L_frameTCX, x_fx, &x_e, gainlpc2_fx, gainlpc2_e, &tmp_concealment_method, gain_tcx_fx, gain_tcx_e, prm_sqQ, nf_seed, bfi, 0, frame_cnt ); + FOR( Word16 l = 0; l < N_LTP_GAIN_MEMS; l++ ) + { + st->hTcxDec->ltpGainMemory[l] = fix16_to_float( st->hTcxDec->ltpGainMemory_fx[l], Q15 ); + } + me2f_buf( x_fx, x_e, x, N_MAX ); +#else decoder_tcx_noisefilling( st, NULL, A, L_frameTCX_glob, L_spec, L_frame, L_frameTCX, &x[0], &gainlpc2[0], &tmp_concealment_method, gain_tcx, prm_sqQ, nf_seed, bfi, 0, frame_cnt ); +#endif decoder_tcx_noiseshaping_igf( st, L_spec, L_frame, L_frameTCX, left_rect, &x[0], &gainlpc2[0], &tmp_concealment_method, bfi ); @@ -3212,3 +3210,397 @@ void decoder_tcx_invQ_fx( return; } + +/*-------------------------------------------------------------------* + * decoder_tcx_noisefilling_fx() + * + * TCX: core noise filling, IGF updates + *-------------------------------------------------------------------*/ + +void decoder_tcx_noisefilling_fx( + Decoder_State *st, /* i/o: coder memory state */ + const Word32 concealment_noise[L_FRAME48k], + const Word16 concealment_noise_exp, + const Word16 A[], /* i : coefficients NxAz[M+1] */ + const Word16 L_frameTCX_glob, + const Word16 L_spec, + const Word16 L_frame, + const Word16 L_frameTCX, + Word32 x[], + Word16 *x_e, + Word16 *gainlpc2, + Word16 *gainlpc2_e, + Word16 *temp_concealment_method, + const Word16 gain_tcx, + const Word16 gain_tcx_e, + const Word16 *prm_sqQ, + Word16 nf_seed, + const Word16 bfi, /* i : Bad frame indicator */ + const Word16 MCT_flag, + const Word16 frame_cnt /* i : frame counter in the super frame*/ +) +{ + Word16 i; + Word16 firstLine; + Word16 fac_ns; + Word16 noiseFillingSize; + Word16 noiseTransWidth = MIN_NOISE_FILLING_HOLE; + Word16 tmp, tmp1, tmp2; + Word16 sum_word16; + Word16 infoIGFStartLine; + Word16 f, noiseTiltFactor; + Word32 smooth_gain; + TCX_LTP_DEC_HANDLE hTcxLtpDec = st->hTcxLtpDec; + TCX_DEC_HANDLE hTcxDec = st->hTcxDec; + TCX_CONFIG_HANDLE hTcxCfg = st->hTcxCfg; + Word32 total_brate = ( st->element_mode == IVAS_CPE_MDCT ? st->element_brate : st->total_brate ); + Word32 tmp32; + Word16 *pInfoTCXNoise; +#ifdef BASOP_NOGLOB_DECLARE_LOCAL + Flag Overflow = 0; + Flag Carry = 0; +#endif + + /*-----------------------------------------------------------------* + * Initializations + *-----------------------------------------------------------------*/ + + /* Init lengths */ + infoIGFStartLine = get_igf_startline( st, L_frame, L_frameTCX ); + + noiseFillingSize = L_spec; + move16(); + IF( st->igf != 0 ) + { + noiseFillingSize = st->hIGFDec->infoIGFStartLine; + move16(); + } + + IF( bfi == 0 ) + { + fac_ns = extract_l( L_shr( L_mult0( hTcxDec->noise_filling_index[frame_cnt], 0x6000 /* 0.75f in Q15 */ ), NBITS_NOISE_FILL_LEVEL ) ); + } + ELSE + { + fac_ns = 0; + move16(); + } + + /*-----------------------------------------------------------* + * Noise filling. * + *-----------------------------------------------------------*/ + + IF( bfi == 0 && ( fac_ns > 0 ) ) + { + firstLine = tcxGetNoiseFillingTilt( A, M, L_frame, ( total_brate >= ACELP_13k20 && !st->rf_flag ), &noiseTiltFactor ); + + IF( st->tcxonly != 0 ) + { + tmp1 = 0; + move16(); + test(); + test(); + IF( ( hTcxCfg->ctx_hm != 0 ) && ( st->last_core != ACELP_CORE ) && ( st->last_ctx_hm_enabled != 0 ) ) + { + tmp1 = 10240 /*0.3125f Q15*/; + move16(); + } + IF( st->element_mode == IVAS_CPE_MDCT ) + { + IF( frame_cnt == 0 ) + { + Copy( hTcxDec->ltpGainMemory_fx, &hTcxDec->ltpGainMemory_fx[1], N_LTP_GAIN_MEMS - 1 ); + hTcxDec->ltpGainMemory_fx[0] = hTcxLtpDec->tcxltp_gain; /* Q15 */ + } + smooth_gain = Dot_product( hTcxDec->ltpGainMemory_fx, nf_tw_smoothing_coeffs_fx, N_LTP_GAIN_MEMS ); /* Q31 */ + noiseTransWidth = HOLE_SIZE_FROM_LTP32( L_max( smooth_gain, L_deposit_h( tmp1 ) ) ); /* using 32-bit for increased precision. */ + } + ELSE + { + noiseTransWidth = HOLE_SIZE_FROM_LTP( s_max( hTcxLtpDec->tcxltp_gain, tmp1 ) ); + } + + IF( EQ_16( L_frame, shr( st->L_frame, 1 ) ) ) + { + noiseTransWidth = 3; /* minimum transition fading for noise filling in TCX-10 */ + move16(); + } + } + + IF( hTcxDec->tcx_lpc_shaped_ari == 0 ) /* old arithmetic coder */ + { + /* noise filling seed */ + tmp32 = L_deposit_l( 0 ); + FOR( i = 0; i < L_spec; i++ ) + { +#ifdef BASOP_NOGLOB + tmp32 = L_macNs_co( tmp32, abs_s( prm_sqQ[i] ), i, &Carry, &Overflow ); +#else + tmp32 = L_macNs( tmp32, abs_s( prm_sqQ[i] ), i ); +#endif + } + nf_seed = extract_l( tmp32 ); + } + + pInfoTCXNoise = NULL; + Word16 tmp_infoTCXNoiseBuf[IGF_START_MX]; + if ( st->igf ) + { + for ( int j = 0; j < IGF_START_MX; j++ ) + { + tmp_infoTCXNoiseBuf[j] = (Word16) st->hIGFDec->infoTCXNoise[j]; + } + pInfoTCXNoise = tmp_infoTCXNoiseBuf; + move16(); + } + tcx_noise_filling_with_shift( x, x_e, nf_seed, firstLine, noiseFillingSize, noiseTransWidth, L_frame, noiseTiltFactor, fac_ns, pInfoTCXNoise, st->element_mode ); + if ( pInfoTCXNoise ) + { + for ( int j = 0; j < IGF_START_MX; j++ ) + { + st->hIGFDec->infoTCXNoise[j] = (UWord8) tmp_infoTCXNoiseBuf[j]; + } + } + + st->seed_tcx_plc = nf_seed; + move16(); + } + + IF( st->enablePlcWaveadjust ) + { + IF( bfi ) + { + IF( EQ_16( st->nbLostCmpt, 1 ) ) + { + st->hPlcInfo->concealment_method = TCX_NONTONAL; + move16(); + + /* tonal/non-tonal decision */ + test(); + test(); + IF( EQ_16( st->hPlcInfo->Transient[0], 1 ) && EQ_16( st->hPlcInfo->Transient[1], 1 ) && EQ_16( st->hPlcInfo->Transient[2], 1 ) ) + { + sum_word16 = 0; + move16(); + + FOR( i = 9; i >= 0; i-- ) + { + sum_word16 = add( sum_word16, st->hPlcInfo->TCX_Tonality[i] ); + } + + IF( GE_16( sum_word16, 6 ) ) + { + st->hPlcInfo->concealment_method = TCX_TONAL; + move16(); + } + } + + IF( st->tonal_mdct_plc_active ) + { + st->hPlcInfo->concealment_method = TCX_TONAL; + move16(); + } + } + + IF( GT_16( L_frameTCX, hTcxDec->L_frameTCX ) ) + { + st->hPlcInfo->concealment_method = TCX_TONAL; + move16(); + } + + *temp_concealment_method = st->hPlcInfo->concealment_method; + move16(); + + IF( EQ_16( st->core, TCX_10_CORE ) ) + { + *temp_concealment_method = TCX_TONAL; + move16(); + } + } + + /* get the starting location of the subframe in the frame */ + IF( EQ_16( st->core, TCX_10_CORE ) ) + { + st->hPlcInfo->subframe = extract_l( L_mult0( frame_cnt, L_frameTCX_glob ) ); + } + } + + /* PLC: [TCX: Tonal Concealment] */ + /* PLC: [TCX: Fade-out] + * PLC: Fade out to white noise */ + IF( st->hTonalMDCTConc != NULL ) + { + IF( bfi == 0 && NE_16( st->element_mode, IVAS_CPE_MDCT ) ) + { + TonalMDCTConceal_SaveFreqSignal_ivas_fx( st->hTonalMDCTConc, x, *x_e, L_frameTCX, L_frame, gainlpc2, gainlpc2_e, gain_tcx_e, infoIGFStartLine ); + st->hTonalMDCTConc->last_block_nrg_flt = me2f( st->hTonalMDCTConc->last_block_nrg, st->hTonalMDCTConc->last_block_nrg_exp ); + } + ELSE IF( bfi ) + { + IF( !st->enablePlcWaveadjust || EQ_16( *temp_concealment_method, TCX_TONAL ) ) + { + /* set f to 1 to not fade out */ + /* set f to 0 to immediately switch to white noise */ + IF( st->tcxonly && ( NE_16( st->element_mode, IVAS_CPE_MDCT ) || MCT_flag ) ) + { + f = MAX16B; + } + ELSE + { + f = hTcxDec->cummulative_damping_tcx; + } + + test(); + test(); + IF( ( frame_cnt == 0 ) && ( EQ_16( L_frameTCX, shr( hTcxDec->L_frameTCX, 1 ) ) ) && ( st->tcxonly ) && ( !st->tonal_mdct_plc_active ) && ( EQ_16( st->nbLostCmpt, 1 ) ) && ( hTcxCfg->tcx_last_overlap_mode != FULL_OVERLAP ) && ( hTcxCfg->tcx_curr_overlap_mode != FULL_OVERLAP ) ) + { + Word16 exp1, exp2; + Word32 E_2ndlast, E_last; + + Word16 tmp_len; + IF( GT_16( st->element_mode, EVS_MONO ) ) + { + tmp_len = L_frame; + move16(); + } + ELSE + { + tmp_len = infoIGFStartLine; + move16(); + } + + E_2ndlast = CalculateAbsEnergy( 1, &( st->hTonalMDCTConc->lastBlockData.spectralData[0] ), tmp_len, &exp2 ); + E_last = CalculateAbsEnergy( 1, &( st->hTonalMDCTConc->lastBlockData.spectralData[1] ), tmp_len, &exp1 ); + + BASOP_Util_Divide_MantExp( extract_h( E_2ndlast ), exp2, extract_h( E_last ), exp1, &tmp1, &tmp2 ); + + tmp1 = shr( tmp1, 2 ); /*Q13*/ +#ifdef BASOP_NOGLOB + tmp1 = shl_sat( tmp1, tmp2 ); +#else + tmp1 = shl( tmp1, tmp2 ); +#endif + test(); + test(); + /* replace higher energy TCX5 frame by lower one to avoid energy fluctuation */ + IF( GT_16( st->element_mode, EVS_MONO ) ) + { + tmp_len = L_frame; + move16(); + } + ELSE + { + tmp_len = infoIGFStartLine; + move16(); + } + IF( GT_16( tmp1, ONE_IN_Q14 ) ) /* 2 in Q13 = 1 in Q14 */ + { + FOR( i = 0; i < tmp_len; i += 2 ) + { + move16(); + st->hTonalMDCTConc->lastBlockData.spectralData[i] = st->hTonalMDCTConc->lastBlockData.spectralData[i + 1]; + st->hTonalMDCTConc->lastBlockData.spectralData_float[i] = st->hTonalMDCTConc->lastBlockData.spectralData_float[i + 1]; + } + } + ELSE IF( LT_16( tmp1, ONE_IN_Q12 ) ) /*0.5 in Q13 = 1 in Q12*/ + { + FOR( i = 0; i < tmp_len; i += 2 ) + { + move16(); + st->hTonalMDCTConc->lastBlockData.spectralData[i + 1] = st->hTonalMDCTConc->lastBlockData.spectralData[i]; + st->hTonalMDCTConc->lastBlockData.spectralData_float[i + 1] = st->hTonalMDCTConc->lastBlockData.spectralData_float[i]; + } + } + } + + noiseTiltFactor = MAX16B; + move16(); + + tmp = 0; + move16(); + test(); + IF( GE_32( total_brate, ACELP_13k20 ) && st->rf_flag == 0 ) + { + tmp = 1; + move16(); + } + + tcxGetNoiseFillingTilt( A, M, L_frame, tmp, &noiseTiltFactor ); + + f2me( hTcxDec->CngLevelBackgroundTrace_bfi, &hTcxDec->CngLevelBackgroundTrace_bfi_fx, &hTcxDec->CngLevelBackgroundTrace_bfi_exp ); + f2me( st->hTonalMDCTConc->curr_noise_nrg_flt, &st->hTonalMDCTConc->curr_noise_nrg, &st->hTonalMDCTConc->curr_noise_nrg_exp ); + + IF( EQ_16( st->element_mode, IVAS_CPE_MDCT ) && MCT_flag == 0 ) + { + TonalMDCTConceal_InsertNoise_ivas_fx( st->hTonalMDCTConc, x, x_e, st->tonal_mdct_plc_active, &st->seed_tcx_plc, noiseTiltFactor, f, concealment_noise, concealment_noise_exp, hTcxDec->CngLevelBackgroundTrace_bfi_fx, hTcxDec->CngLevelBackgroundTrace_bfi_exp, infoIGFStartLine ); + } + ELSE + { + TonalMDCTConceal_InsertNoise_ivas_fx( st->hTonalMDCTConc, x, x_e, st->tonal_mdct_plc_active, &st->seed_tcx_plc, noiseTiltFactor, f, NULL, 0, hTcxDec->CngLevelBackgroundTrace_bfi_fx, hTcxDec->CngLevelBackgroundTrace_bfi_exp, infoIGFStartLine ); + } + + st->hTonalMDCTConc->faded_signal_nrg_flt = me2f( st->hTonalMDCTConc->faded_signal_nrg, st->hTonalMDCTConc->faded_signal_nrg_exp ); + st->hTonalMDCTConc->curr_noise_nrg_flt = me2f( st->hTonalMDCTConc->curr_noise_nrg, st->hTonalMDCTConc->curr_noise_nrg_exp ); + } + } + } + + /*------------------------- SPLIT 2 noise filling ------------------------*/ + IF( !bfi ) + { + IF( EQ_16( st->element_mode, IVAS_CPE_MDCT ) ) + { + FOR( i = 0; i < L_spec; i++ ) + { + x[i] = Mpy_32_16_1( x[i], gain_tcx ); + move16(); + } + *x_e = add( *x_e, gain_tcx_e ); + } + } + + IF( LT_16( L_spec, L_frame ) ) + { + set32_fx( x + L_spec, 0, sub( L_frame, L_spec ) ); + } + ELSE IF( GT_16( L_spec, L_frameTCX ) ) + { + set32_fx( x + L_frameTCX, 0, sub( L_spec, L_frameTCX ) ); + } + + IF( bfi && ( !st->enablePlcWaveadjust || EQ_16( *temp_concealment_method, TCX_TONAL ) ) && st->igf && ( frame_cnt == 0 ) && ( EQ_16( L_frameTCX, shr( hTcxDec->L_frameTCX, 1 ) ) ) && ( st->tcxonly ) && ( !st->tonal_mdct_plc_active ) && ( EQ_16( st->nbLostCmpt, 1 ) ) && ( hTcxCfg->tcx_last_overlap_mode != FULL_OVERLAP ) && ( hTcxCfg->tcx_curr_overlap_mode != FULL_OVERLAP ) ) + { + IGFDecCopyLPCFlatSpectrum_fx( st->hIGFDec, x, *x_e, IGF_GRID_LB_SHORT ); + /* also replace flat spectrum for the second TCX10 sub frame */ + IGFDecUpdateInfo_fx( st->hIGFDec, 1, IGF_GRID_LB_SHORT ); + IGFDecCopyLPCFlatSpectrum_fx( st->hIGFDec, x, *x_e, IGF_GRID_LB_SHORT ); + IGFDecUpdateInfo_fx( st->hIGFDec, 0, IGF_GRID_LB_SHORT ); + Copy( st->hIGFDec->igfData.igf_curr_subframe[0][0], st->hIGFDec->igfData.igf_curr_subframe[1][0], IGF_MAX_SFB ); + } + ELSE IF( bfi && st->igf && ( frame_cnt == 0 ) && ( EQ_16( L_frameTCX, shr( hTcxDec->L_frameTCX, 1 ) ) ) ) + { + /* copy second to first subframe */ + IGFDecReplicateTCX10State_fx( st->hIGFDec ); + } + + IF( NE_16( st->element_mode, EVS_MONO ) ) + { + IF( bfi ) + { + nf_seed = st->seed_tcx_plc; + move16(); + } + ELSE IF( nf_seed == 0 ) + { + nf_seed = *st->hIGFDec->igfData.igfInfo.nfSeed; + move16(); + } + } + + IF( st->igf ) + { + *st->hIGFDec->igfData.igfInfo.nfSeed = extract_l( L_add( L_mult0( nf_seed, 31821 ), 13849 ) ); + } + + return; +} diff --git a/lib_dec/igf_dec_fx.c b/lib_dec/igf_dec_fx.c index 268d35eca..5839ae1b0 100644 --- a/lib_dec/igf_dec_fx.c +++ b/lib_dec/igf_dec_fx.c @@ -10,6 +10,7 @@ #include "stl.h" #include "prot.h" #include "ivas_prot.h" +#include "ivas_prot_fx.h" #include "prot_fx1.h" #include "prot_fx2.h" #include "cnst.h" @@ -1918,3 +1919,35 @@ void init_igf_dec( return; } + +Word16 get_igf_startline( + Decoder_State *st, /* i : decoder state */ + const Word16 L_frame, /* i : length of the frame */ + const Word16 L_frameTCX /* i : full band frame length */ +) +{ + Word16 igf_startline; + + IF( st->igf == 0 ) + { + IF( st->narrowBand == 0 ) + { + /* minimum needed for output with sampling rates lower then the + nominal sampling rate */ + igf_startline = s_min( L_frameTCX, L_frame ); + move16(); + } + ELSE + { + igf_startline = L_frameTCX; + move16(); + } + } + ELSE + { + igf_startline = s_min( st->hIGFDec->infoIGFStartLine, L_frameTCX ); + move16(); + } + + return igf_startline; +} diff --git a/lib_dec/ivas_mct_dec.c b/lib_dec/ivas_mct_dec.c index 5cbf4f943..006f76b88 100644 --- a/lib_dec/ivas_mct_dec.c +++ b/lib_dec/ivas_mct_dec.c @@ -82,6 +82,12 @@ ivas_error ivas_mct_dec( int32_t ivas_total_brate; ivas_error error; +#ifdef IVAS_FLOAT_FIXED + /* TODO: Temporary fix to avoid garbage values while calculating its q-factor + when not initialised. */ + set_zero((float *)Aq, MCT_MAX_BLOCKS*CPE_CHANNELS*(NB_SUBFR16k + 1) * (M + 1)); +#endif + push_wmops( "ivas_mct_dec" ); error = IVAS_ERR_OK; diff --git a/lib_dec/ivas_mdct_core_dec.c b/lib_dec/ivas_mdct_core_dec.c index 1fc6bef60..0cd91bf8c 100644 --- a/lib_dec/ivas_mdct_core_dec.c +++ b/lib_dec/ivas_mdct_core_dec.c @@ -45,6 +45,7 @@ #include "ivas_stat_com.h" #include #ifdef IVAS_FLOAT_FIXED +#include "prot_fx2.h" #include "ivas_prot_fx.h" #include "prot_fx1.h" #include "prot_fx2.h" @@ -513,12 +514,20 @@ void ivas_mdct_core_invQ( float concealment_noise[CPE_CHANNELS][L_FRAME48k]; TONALMDCTCONC_NOISE_GEN_MODE noise_gen_mode_bfi; +#ifdef IVAS_FLOAT_FIXED + Word16 xn_buf_fx[L_MDCT_OVLP_MAX + L_FRAME_PLUS + L_MDCT_OVLP_MAX]; + Word16 gain_tcx_fx = 0, gain_tcx_e = 0; +#endif + push_wmops( "mdct_core_invQ" ); sts = hCPE->hCoreCoder; bfi = sts[0]->bfi; noise_gen_mode_bfi = NOISE_GEN_MODE_UNDEF; set_f( xn_buf, 0, L_MDCT_OVLP_MAX + L_FRAME_PLUS + L_MDCT_OVLP_MAX ); +#ifdef IVAS_FLOAT_FIXED + set16_fx( xn_buf_fx, 0, L_MDCT_OVLP_MAX + L_FRAME_PLUS + L_MDCT_OVLP_MAX ); +#endif set_s( total_nbbits, 0, CPE_CHANNELS ); set_s( bitsRead, 0, CPE_CHANNELS ); tmp_concealment_method = 0; @@ -843,7 +852,35 @@ void ivas_mdct_core_invQ( TonalMdctConceal_create_concealment_noise_ivas( concealment_noise[ch], hCPE, L_frameTCX[ch], L_frame[ch], ch, k, st->core, st->hTcxDec->cummulative_damping_tcx_float, noise_gen_mode_bfi ); } +#ifdef IVAS_FLOAT_FIXED + Word32 x_fx[N_MAX]; + Word16 Aq_fx[M + 1], Aq_e, x_e; + set32_fx( x_fx, 0, N_MAX ); + f2me_buf( x[ch][k], x_fx, &x_e, L_frameTCX[ch] ); + f2me_buf_16( Aq[ch], Aq_fx, &Aq_e, M + 1 ); + f2me_16( gain_tcx, &gain_tcx_fx, &gain_tcx_e ); + st->hTcxLtpDec->tcxltp_gain = float_to_fix16( st->hTcxLtpDec->tcxltp_gain_float, Q15 ); + st->hTcxDec->cummulative_damping_tcx = float_to_fix16( st->hTcxDec->cummulative_damping_tcx_float, Q15 ); + Word32 concealment_noise_fx[L_FRAME48k]; + Word16 concealment_noise_e = 0, concealment_noise_len; + concealment_noise_len = get_igf_startline( st, L_frame[ch], L_frameTCX[ch] ); + IF( bfi && MCT_flag == 0 )/* to check if concealment_noise was initialised */ + { + f2me_buf( concealment_noise[ch], concealment_noise_fx, &concealment_noise_e, concealment_noise_len ); + } + FOR( Word16 l = 0; l < N_LTP_GAIN_MEMS; l++ ) + { + st->hTcxDec->ltpGainMemory_fx[l] = float_to_fix16( st->hTcxDec->ltpGainMemory[l], Q15 ); + } + decoder_tcx_noisefilling_fx( st, concealment_noise_fx, concealment_noise_e, Aq_fx, L_frameTCX_global[ch], L_spec[ch], L_frame[ch], L_frameTCX[ch], x_fx, &x_e, NULL, NULL, &tmp_concealment_method, gain_tcx_fx, gain_tcx_e, prm_sqQ, nf_seed, bfi, MCT_flag, k ); + FOR( Word16 l = 0; l < N_LTP_GAIN_MEMS; l++ ) + { + st->hTcxDec->ltpGainMemory[l] = fix16_to_float( st->hTcxDec->ltpGainMemory_fx[l], Q15 ); + } + me2f_buf( x_fx, x_e, x[ch][k], L_frameTCX[ch] ); +#else decoder_tcx_noisefilling( st, concealment_noise[ch], Aq[ch], L_frameTCX_global[ch], L_spec[ch], L_frame[ch], L_frameTCX[ch], x[ch][k], NULL, &tmp_concealment_method, gain_tcx, prm_sqQ, nf_seed, bfi, MCT_flag, k ); +#endif decoder_tcx_noiseshaping_igf( st, L_spec[ch], L_frame[ch], L_frameTCX[ch], left_rect[ch], x[ch][k], NULL, &tmp_concealment_method, bfi ); } @@ -1123,7 +1160,19 @@ void ivas_mdct_core_tns_ns( if ( MCT_flag && st->hTonalMDCTConc != NULL && ( ( k + 1 ) == nSubframes[ch] ) ) { +#ifdef IVAS_FLOAT_FIXED + Word32 x_fx[N_MAX]; + Word16 x_e, scf_fx[FDNS_NPTS], scf_e[FDNS_NPTS]; + f2me_buf( x[ch][k], x_fx, &x_e, L_frameTCX[ch] ); + for ( int j = 0; j < st->hTonalMDCTConc->nScaleFactors; j++ ) + { + f2me_16( sns_int_scf[j], &scf_fx[j], &scf_e[j] ); + } + TonalMDCTConceal_SaveFreqSignal_ivas_fx( st->hTonalMDCTConc, x_fx, x_e, L_frameTCX[ch], L_frame[ch], &scf_fx[0], scf_e, 0, get_igf_startline( st, L_frame[ch], L_frameTCX[ch] ) ); + st->hTonalMDCTConc->last_block_nrg_flt = me2f( st->hTonalMDCTConc->last_block_nrg, st->hTonalMDCTConc->last_block_nrg_exp ); +#else TonalMDCTConceal_SaveFreqSignal_ivas( st->hTonalMDCTConc, x[ch][k], L_frameTCX[ch], L_frame[ch], &sns_int_scf[0], get_igf_startline_flt( st, L_frame[ch], L_frameTCX[ch] ) ); +#endif } } else diff --git a/lib_dec/ivas_stereo_mdct_core_dec.c b/lib_dec/ivas_stereo_mdct_core_dec.c index 1c0a2b69f..cdb3572f6 100644 --- a/lib_dec/ivas_stereo_mdct_core_dec.c +++ b/lib_dec/ivas_stereo_mdct_core_dec.c @@ -41,6 +41,7 @@ #include "ivas_stat_dec.h" #include "wmc_auto.h" #ifdef IVAS_FLOAT_FIXED +#include "prot_fx2.h" #include "ivas_prot_fx.h" #endif // IVAS_FLOAT_FIXED @@ -153,6 +154,11 @@ void stereo_mdct_core_dec( int16_t param_lpc[CPE_CHANNELS][NPRM_LPC_NEW]; float Aq[CPE_CHANNELS][( NB_SUBFR16k + 1 ) * ( M + 1 )]; +#ifdef IVAS_FLOAT_FIXED + /* NOTE: temporary fix to avoid garbage values while calculating its + q-factor when not initialised. */ + set_zero( (float *) Aq, CPE_CHANNELS * ( NB_SUBFR16k + 1 ) * ( M + 1 ) ); +#endif float *x[CPE_CHANNELS][NB_DIV]; /*needed to allocate N_MAX to prevent stereo switching crash */ @@ -337,7 +343,19 @@ void stereo_mdct_core_dec( if ( st->hTonalMDCTConc != NULL && ( ( k + 1 ) == nSubframes[ch] ) ) { +#ifdef IVAS_FLOAT_FIXED + Word32 x_fx[N_MAX]; + Word16 x_e, scf_fx[FDNS_NPTS], scf_e[FDNS_NPTS]; + f2me_buf( x[ch][k], x_fx, &x_e, L_frameTCX[ch] ); + for ( int j = 0; j < st->hTonalMDCTConc->nScaleFactors; j++ ) + { + f2me_16( sns_int_scf[j], &scf_fx[j], &scf_e[j] ); + } + TonalMDCTConceal_SaveFreqSignal_ivas_fx( st->hTonalMDCTConc, x_fx, x_e, L_frameTCX[ch], L_frame[ch], &scf_fx[0], scf_e, 0, get_igf_startline( st, L_frame[ch], L_frameTCX[ch] ) ); + st->hTonalMDCTConc->last_block_nrg_flt = me2f( st->hTonalMDCTConc->last_block_nrg, st->hTonalMDCTConc->last_block_nrg_exp ); +#else TonalMDCTConceal_SaveFreqSignal_ivas( st->hTonalMDCTConc, x[ch][k], L_frameTCX[ch], L_frame[ch], &sns_int_scf[0], get_igf_startline_flt( st, L_frame[ch], L_frameTCX[ch] ) ); +#endif } } diff --git a/lib_dec/stat_dec.h b/lib_dec/stat_dec.h index 1235c7b02..18313c0ba 100644 --- a/lib_dec/stat_dec.h +++ b/lib_dec/stat_dec.h @@ -361,11 +361,14 @@ typedef struct tonalmdctconceal PsychoacousticParameters psychParamsTCX10; float last_block_nrg_flt; + Word32 last_block_nrg; + Word16 last_block_nrg_exp; float curr_noise_nrg_flt; + Word32 curr_noise_nrg; + Word16 curr_noise_nrg_exp; float faded_signal_nrg_flt; - Word16 last_block_nrg; - Word16 curr_noise_nrg; - Word16 faded_signal_nrg; + Word32 faded_signal_nrg; + Word16 faded_signal_nrg_exp; float nFramesLost_float; Word16 nFramesLost; @@ -608,10 +611,13 @@ typedef struct tcx_dec_structure int16_t noise_filling_index[NB_DIV]; /* PLC - last decoded noise filling index */ int16_t tnsActive[NB_DIV]; float ltpGainMemory[N_LTP_GAIN_MEMS]; /* for smoothing noiseTransWidth */ + Word16 ltpGainMemory_fx[N_LTP_GAIN_MEMS]; /* Q15 */ uint16_t kernel_type[2]; /* transform kernel type in each subframe (MDCT or MDST) */ int16_t prev_widow_left_rect; float CngLevelBackgroundTrace_bfi; /* PLC - long term gain estimate for background level, used for PLC fade out */ + Word32 CngLevelBackgroundTrace_bfi_fx; /* PLC - long term gain estimate for background level, used for PLC fade out */ + Word16 CngLevelBackgroundTrace_bfi_exp; /* state variables for the minimum statistics used for PLC */ float NoiseLevelMemory_bfi[PLC_MIN_STAT_BUFF_SIZE]; int16_t NoiseLevelIndex_bfi; diff --git a/lib_dec/tonalMDCTconcealment_fx.c b/lib_dec/tonalMDCTconcealment_fx.c index 23a3b526d..9da79f6fa 100644 --- a/lib_dec/tonalMDCTconcealment_fx.c +++ b/lib_dec/tonalMDCTconcealment_fx.c @@ -14,7 +14,9 @@ #include "prot_fx1.h" #include "prot_fx2.h" #include "stat_com.h" +#include "prot.h" +#define CROSSFADE_THRESHOLD (32762) // close to 1.0f in Q15 such that (x == 1.0f) is true /************************************************************************************ * local functions @@ -154,6 +156,11 @@ ivas_error TonalMDCTConceal_Init_ivas_fx( move16(); hTonalMDCTConc->secondLastBlockData.scaleFactors = hTonalMDCTConc->scaleFactorsBuffers[1]; move16(); + hTonalMDCTConc->lastBlockData.scaleFactors_exp = hTonalMDCTConc->scaleFactorsBuffers_exp[0]; + move16(); + hTonalMDCTConc->secondLastBlockData.scaleFactors_exp = hTonalMDCTConc->scaleFactorsBuffers_exp[1]; + move16(); + hTonalMDCTConc->lastBlockData.blockIsValid = 0; move16(); hTonalMDCTConc->secondLastBlockData.blockIsValid = 0; @@ -169,7 +176,6 @@ ivas_error TonalMDCTConceal_Init_ivas_fx( move16(); hTonalMDCTConc->pTCI_fix = (TonalComponentsInfo_fix *) hTonalMDCTConc->timeDataBuffer; move16(); - hTonalMDCTConc->lastPitchLag = L_deposit_l( 0 ); IF( NE_16( hTonalMDCTConc->nSamples, nSamples ) ) @@ -196,8 +202,17 @@ ivas_error TonalMDCTConceal_Init_ivas_fx( hTonalMDCTConc->psychParams = NULL; hTonalMDCTConc->last_block_nrg = 0; + move16(); + hTonalMDCTConc->last_block_nrg_exp = 0; + move16(); hTonalMDCTConc->curr_noise_nrg = 0; + move16(); + hTonalMDCTConc->curr_noise_nrg_exp = 0; + move16(); hTonalMDCTConc->faded_signal_nrg = 0; + move16(); + hTonalMDCTConc->faded_signal_nrg_exp = 0; + move16(); /* Offset the pointer to the end of buffer, so that pTCI_fix is not destroyed when new time samples are stored in lastPcmOut */ @@ -210,6 +225,9 @@ ivas_error TonalMDCTConceal_Init_ivas_fx( #if 1 // TO do enable when only fix code is present currently disabled due to float array in structure assert( sizeof( *hTonalMDCTConc->pTCI_fix ) <= ( hTonalMDCTConc->lastPcmOut - hTonalMDCTConc->timeDataBuffer ) * sizeof( hTonalMDCTConc->timeDataBuffer[0] ) ); + + /* TODO: remove float code*/ + assert( sizeof( *hTonalMDCTConc->pTCI_float ) <= ( hTonalMDCTConc->lastPcmOut_float - hTonalMDCTConc->timeDataBuffer_float ) * sizeof( hTonalMDCTConc->timeDataBuffer_float[0] ) ); #endif return IVAS_ERR_OK; @@ -358,6 +376,179 @@ void TonalMDCTConceal_SaveFreqSignal( return; } +void TonalMDCTConceal_SaveFreqSignal_ivas_fx( + TonalMDCTConcealPtr hTonalMDCTConc, + const Word32 *mdctSpectrum, + const Word16 mdctSpectrum_exp, + const Word16 nNewSamples, + const Word16 nNewSamplesCore, + const Word16 *scaleFactors, + const Word16 *scaleFactors_exp, + const Word16 gain_tcx_exp, + const Word16 infoIGFStartLine ) +{ + Word16 *temp; + Word16 nOldSamples, temp_exp, s, i, max_exp; + + assert( nNewSamples > 0 && nNewSamples <= 2 * L_FRAME_MAX ); + + /* Avoid overwriting hTonalMDCTConc->secondLastPowerSpectrum stored in spectralData, + because it is needed if the second last and the current frame are lost + and concealed using the Tonal MDCT PLC */ + test(); + IF( !hTonalMDCTConc->lastBlockData.tonalConcealmentActive || NE_16( hTonalMDCTConc->lastBlockData.nSamples, nNewSamples ) ) + { + IF( LE_16( nNewSamples, L_FRAME_MAX ) ) + { + /* Shift the buffers */ + +#if 1 // TODO: Remove Float pointer movement + float *temp_flt; + temp_flt = hTonalMDCTConc->secondLastBlockData.spectralData_float; /* Save the pointer */ + hTonalMDCTConc->secondLastBlockData.spectralData_float = hTonalMDCTConc->lastBlockData.spectralData_float; + hTonalMDCTConc->lastBlockData.spectralData_float = temp_flt; + temp_flt = hTonalMDCTConc->secondLastBlockData.scaleFactors_float; + hTonalMDCTConc->secondLastBlockData.scaleFactors_float = hTonalMDCTConc->lastBlockData.scaleFactors_float; + hTonalMDCTConc->lastBlockData.scaleFactors_float = temp_flt; +#endif + + temp = hTonalMDCTConc->secondLastBlockData.spectralData; /* Save the pointer */ + move16(); + hTonalMDCTConc->secondLastBlockData.spectralData = hTonalMDCTConc->lastBlockData.spectralData; + move16(); + hTonalMDCTConc->lastBlockData.spectralData = temp; + move16(); + + temp_exp = hTonalMDCTConc->secondLastBlockData.spectralData_exp; + move16(); + hTonalMDCTConc->secondLastBlockData.spectralData_exp = hTonalMDCTConc->lastBlockData.spectralData_exp; + move16(); + hTonalMDCTConc->lastBlockData.spectralData_exp = temp_exp; + move16(); + + temp_exp = hTonalMDCTConc->secondLastBlockData.gain_tcx_exp; /* Save the pointer */ + move16(); + hTonalMDCTConc->secondLastBlockData.gain_tcx_exp = hTonalMDCTConc->lastBlockData.gain_tcx_exp; + move16(); + hTonalMDCTConc->lastBlockData.gain_tcx_exp = temp_exp; + move16(); + + temp_exp = hTonalMDCTConc->secondLastBlockData.scaleFactors_max_e; /* Save the pointer */ + move16(); + hTonalMDCTConc->secondLastBlockData.scaleFactors_max_e = hTonalMDCTConc->lastBlockData.scaleFactors_max_e; + move16(); + hTonalMDCTConc->lastBlockData.scaleFactors_max_e = temp_exp; + move16(); + + temp = hTonalMDCTConc->secondLastBlockData.scaleFactors; + move16(); + hTonalMDCTConc->secondLastBlockData.scaleFactors = hTonalMDCTConc->lastBlockData.scaleFactors; + move16(); + hTonalMDCTConc->lastBlockData.scaleFactors = temp; + move16(); + + temp = hTonalMDCTConc->secondLastBlockData.scaleFactors_exp; + move16(); + hTonalMDCTConc->secondLastBlockData.scaleFactors_exp = hTonalMDCTConc->lastBlockData.scaleFactors_exp; + move16(); + hTonalMDCTConc->lastBlockData.scaleFactors_exp = temp; + move16(); + } + ELSE + { + /* Order the buffers so that even transition frame can fit in if written into the first buffer */ + +#if 1 /* TODO: remove float code */ + hTonalMDCTConc->lastBlockData.spectralData_float = hTonalMDCTConc->spectralDataBuffers_float[0]; + hTonalMDCTConc->secondLastBlockData.spectralData_float = hTonalMDCTConc->spectralDataBuffers_float[1]; + hTonalMDCTConc->lastBlockData.scaleFactors_float = hTonalMDCTConc->scaleFactorsBuffers_float[0]; + hTonalMDCTConc->secondLastBlockData.scaleFactors_float = hTonalMDCTConc->scaleFactorsBuffers_float[1]; +#endif + + hTonalMDCTConc->lastBlockData.spectralData = hTonalMDCTConc->spectralDataBuffers[0]; + move16(); + hTonalMDCTConc->secondLastBlockData.spectralData = hTonalMDCTConc->spectralDataBuffers[1]; + move16(); + hTonalMDCTConc->lastBlockData.scaleFactors = hTonalMDCTConc->scaleFactorsBuffers[0]; + move16(); + hTonalMDCTConc->secondLastBlockData.scaleFactors = hTonalMDCTConc->scaleFactorsBuffers[1]; + move16(); + hTonalMDCTConc->lastBlockData.scaleFactors_exp = hTonalMDCTConc->scaleFactorsBuffers_exp[0]; + move16(); + hTonalMDCTConc->secondLastBlockData.scaleFactors_exp = hTonalMDCTConc->scaleFactorsBuffers_exp[1]; + move16(); + } + nOldSamples = hTonalMDCTConc->lastBlockData.nSamples; + move16(); + hTonalMDCTConc->lastBlockData.nSamples = nNewSamples; + move16(); + hTonalMDCTConc->secondLastBlockData.nSamples = nOldSamples; + move16(); + nOldSamples = hTonalMDCTConc->lastBlockData.nSamplesCore; + move16(); + hTonalMDCTConc->lastBlockData.nSamplesCore = nNewSamplesCore; + move16(); + hTonalMDCTConc->secondLastBlockData.nSamplesCore = nOldSamples; + move16(); + } + + test(); + IF( ( nNewSamples > 0 ) && ( LE_16( nNewSamples, 2 * L_FRAME_MAX ) ) ) + { + /* Store new data */ + hTonalMDCTConc->last_block_nrg = 0; + + FOR( i = 0; i < infoIGFStartLine; i++ ) + { + Word16 tmp = extract_h( mdctSpectrum[i] ); + hTonalMDCTConc->last_block_nrg = L_add( hTonalMDCTConc->last_block_nrg, + L_shr( L_mult0( tmp, tmp ), 16 ) ); + } + hTonalMDCTConc->last_block_nrg_exp = 31 - ( ( 15 - mdctSpectrum_exp ) * 2 - 16 ); + +#if 1 /* TODO: remove float code */ + FOR( i = 0; i < nNewSamples; i++ ) + { + hTonalMDCTConc->lastBlockData.spectralData_float[i] = me2f( mdctSpectrum[i], mdctSpectrum_exp ); + } +#endif + /* Store new data */ + s = getScaleFactor32( mdctSpectrum, nNewSamples ); + + max_exp = 0; + FOR( i = 0; i < hTonalMDCTConc->nScaleFactors; i++ ) + { + hTonalMDCTConc->lastBlockData.scaleFactors_exp[i] = scaleFactors_exp[i]; + move16(); + max_exp = s_max( max_exp, scaleFactors_exp[i] ); + } + + /*s = sub(s, max_exp);*/ + hTonalMDCTConc->lastBlockData.scaleFactors_max_e = max_exp; + + FOR( i = 0; i < nNewSamples; i++ ) + { + hTonalMDCTConc->lastBlockData.spectralData[i] = extract_h( L_shl( mdctSpectrum[i], s ) ); + move16(); + } + hTonalMDCTConc->lastBlockData.spectralData_exp = sub( mdctSpectrum_exp, s ); + move16(); + + hTonalMDCTConc->lastBlockData.gain_tcx_exp = gain_tcx_exp; + Copy( scaleFactors, hTonalMDCTConc->lastBlockData.scaleFactors, hTonalMDCTConc->nScaleFactors ); + +#if 1 /* TODO: remove float code. */ + for ( i = 0; i < hTonalMDCTConc->nScaleFactors; i++ ) + { + hTonalMDCTConc->lastBlockData.scaleFactors_float[i] = me2f_16( scaleFactors[i], hTonalMDCTConc->lastBlockData.scaleFactors_exp[i] ); + } +#endif + } + + return; +} + + TONALMDCTCONCEAL_ERROR TonalMDCTConceal_UpdateState(TonalMDCTConcealPtr hTonalMDCTConc, Word16 nNewSamples, Word32 pitchLag, @@ -849,6 +1040,741 @@ void TonalMDCTConceal_Detect( return ; } +void TonalMDCTConceal_InsertNoise_ivas_fx( + const TonalMDCTConcealPtr hTonalMDCTConc, /*IN */ + Word32 *mdctSpectrum, + Word16 *mdctSpectrum_exp, + const Word16 tonalConcealmentActive, + Word16 *pSeed, /*IN/OUT*/ + const Word16 tiltCompFactor, + const Word16 crossfadeGain_const, + const Word32 concealment_noise[L_FRAME48k], + const Word16 concealment_noise_e, + const Word32 cngLevelBackgroundTrace_bfi, + const Word16 cngLevelBackgroundTrace_bfi_e, + const Word16 crossOverFreq ) +{ + Word16 i, l, ld, fac; + Word16 rnd; + + Word16 tmp, g, tilt, exp_last, exp_noise, tiltFactor, crossfadeGain; + Word32 L_tmp, L_tmp2, nrgNoiseInLastFrame, nrgWhiteNoise; + Word16 inv_exp, inv_samples, exp; + Word32 last_block_nrg_correct; + Word16 last_block_nrg_correct_e; + + crossfadeGain = crossfadeGain_const; + + push_wmops( "InsertNoise" ); + + g = sub( MAX16B, crossfadeGain ); + + IF( !hTonalMDCTConc->lastBlockData.blockIsConcealed ) + { + rnd = 1977; + } + ELSE + { + rnd = *pSeed; + } + + /* based on what is done in tcx_noise_filling() */ + /* always initialize these to avoid compiler warnings */ + hTonalMDCTConc->faded_signal_nrg = L_deposit_h( 0 ); + + L_tmp = 805306368l /*0.375f Q31*/; + inv_exp = 15; + move16(); + inv_samples = Inv16( hTonalMDCTConc->lastBlockData.nSamples, &inv_exp ); + tiltFactor = round_fx( BASOP_Util_fPow( L_max( L_tmp, L_deposit_h( tiltCompFactor ) ), 0, L_deposit_h( inv_samples ), inv_exp, &exp ) ); + BASOP_SATURATE_WARNING_OFF_EVS /*next op may result in 32768*/ + tiltFactor = shl( tiltFactor, exp ); + BASOP_SATURATE_WARNING_ON_EVS + tilt = MAX16B; + move16(); + nrgNoiseInLastFrame = L_deposit_h( 0 ); + nrgWhiteNoise = L_deposit_h( 0 ); + last_block_nrg_correct = L_deposit_h( 0 ); + last_block_nrg_correct_e = 0; + + exp_last = exp_noise = 0; + + IF( !hTonalMDCTConc->lastBlockData.blockIsValid ) + { + /* may just become active if the very first frame is lost */ + set32_fx( mdctSpectrum, 0, hTonalMDCTConc->nSamples ); + } + ELSE IF( concealment_noise != NULL ) + { + IF( !tonalConcealmentActive ) + { + /* if fadeout has not started yet, only apply sign scrambling */ + IF( GE_16( crossfadeGain, CROSSFADE_THRESHOLD ) ) + { + FOR( i = 0; i < crossOverFreq; i++ ) + { + IF( GT_32( concealment_noise[i], 0 ) ) + { + mdctSpectrum[i] = L_shl( L_deposit_l( hTonalMDCTConc->lastBlockData.spectralData[i] ), 16 ); + } + ELSE + { + mdctSpectrum[i] = L_negate( L_shl( L_deposit_l( hTonalMDCTConc->lastBlockData.spectralData[i] ), 16 ) ); + } + } + + FOR( l = crossOverFreq; l < hTonalMDCTConc->lastBlockData.nSamples; l++ ) + { + mdctSpectrum[l] = L_shl( L_deposit_l( hTonalMDCTConc->lastBlockData.spectralData[l] ), 16 ); + } + + *mdctSpectrum_exp = hTonalMDCTConc->lastBlockData.spectralData_exp; + } + /* actual fadeout is done in this case */ + ELSE + { + Word32 num, den; + Word16 exp_num, exp_den; + + exp_num = cngLevelBackgroundTrace_bfi_e; + exp_den = hTonalMDCTConc->curr_noise_nrg_exp; + + ld = norm_l( cngLevelBackgroundTrace_bfi ); + num = L_shl( cngLevelBackgroundTrace_bfi, ld ); + exp_num = sub( exp_num, ld ); + ld = norm_l( hTonalMDCTConc->curr_noise_nrg ); + den = L_shl( hTonalMDCTConc->curr_noise_nrg, ld ); + exp_den = sub( exp_den, ld ); + + exp = sub( exp_num, exp_den ); + + IF( GT_32( num, den ) ) + { + num = L_shr( num, 1 ); + exp = add( exp, 1 ); + } + tmp = div_l( num, round_fx( den ) ); + tmp = Sqrt16( tmp, &exp ); + g = mult_r( g, tmp ); // exponent of g = exp + + L_tmp = L_deposit_h( 0 ); + exp = sub( hTonalMDCTConc->lastBlockData.spectralData_exp, add( concealment_noise_e, exp ) ); + + IF( GT_16( exp, 0 ) ) + { + g = shr( g, exp ); + *mdctSpectrum_exp = hTonalMDCTConc->lastBlockData.spectralData_exp; + } + ELSE + { + crossfadeGain = shl( crossfadeGain, exp ); + *mdctSpectrum_exp = sub( hTonalMDCTConc->lastBlockData.spectralData_exp, exp ); + } + /*make a headroom for mdct_shaping*/ + exp = sub( *mdctSpectrum_exp, SPEC_EXP_DEC ); + /* assert(exp < 0);*/ + IF( exp < 0 ) + { + *mdctSpectrum_exp = SPEC_EXP_DEC; + } + ELSE + { + exp = 0; + } + + FOR( i = 0; i < crossOverFreq; i++ ) + { + Word16 x = hTonalMDCTConc->lastBlockData.spectralData[i]; + Word32 y = concealment_noise[i]; + + IF( GT_16( g, 0 ) ) + { + L_tmp = Mpy_32_16_1( y, g ); + } + + L_tmp2 = L_msu( L_tmp, crossfadeGain, x ); + IF( GT_32( y, 0 ) ) + { + L_tmp2 = L_mac( L_tmp, crossfadeGain, x ); + } + mdctSpectrum[i] = L_shl( L_tmp2, exp ); + move32(); + + hTonalMDCTConc->faded_signal_nrg = L_add( hTonalMDCTConc->faded_signal_nrg, Mpy_32_32( mdctSpectrum[i], mdctSpectrum[i] ) ); + } + + hTonalMDCTConc->faded_signal_nrg_exp = shl( *mdctSpectrum_exp, 1 ); + + FOR( i = crossOverFreq; i < hTonalMDCTConc->lastBlockData.nSamples; i++ ) + { + mdctSpectrum[i] = 0; + move32(); + } + } + } + ELSE + { + assert( hTonalMDCTConc->pTCI_float->numIndexes > 0 ); + + /* initialize bins of tonal components with zero: basically not + necessary, but currently the whole spectrum is rescaled in + mdct_noiseShaping() and then there would be a processing of + uninitialized values */ + + ld = sub( 14, norm_s( hTonalMDCTConc->lastBlockData.nSamples ) ); + fac = shr( -32768, ld ); + + FOR( i = 0; i < hTonalMDCTConc->pTCI_float->numIndexes; i++ ) + { + FOR( l = hTonalMDCTConc->pTCI_float->lowerIndex[i]; l <= hTonalMDCTConc->pTCI_float->upperIndex[i]; l++ ) + { + mdctSpectrum[l] = L_deposit_h( 0 ); + IF( LT_16( l, crossOverFreq ) ) + { + Word16 x = hTonalMDCTConc->lastBlockData.spectralData[l]; + Word32 y = concealment_noise[l]; + last_block_nrg_correct = L_add( last_block_nrg_correct, Mpy_32_16_1( L_msu( 0, x, fac ), x ) ); // exp = 2 * x_exp + ld + y = L_negate( Mpy_32_32( y, y ) ); + hTonalMDCTConc->curr_noise_nrg = BASOP_Util_Add_Mant32Exp( hTonalMDCTConc->curr_noise_nrg, hTonalMDCTConc->curr_noise_nrg_exp, y, 2 * concealment_noise_e, &hTonalMDCTConc->curr_noise_nrg_exp); + } + } + } + last_block_nrg_correct_e = hTonalMDCTConc->lastBlockData.spectralData_exp * 2 + ld; + + /* if fadeout has not started yet, only apply sign scrambling */ + IF( GE_16( crossfadeGain, CROSSFADE_THRESHOLD ) ) + { + FOR( l = 0; l < hTonalMDCTConc->pTCI_float->lowerIndex[0]; l++ ) + { + IF( GT_32( concealment_noise[l], 0 ) ) + { + mdctSpectrum[l] = L_shl( L_deposit_l( hTonalMDCTConc->lastBlockData.spectralData[l] ), 16 ); + } + ELSE + { + mdctSpectrum[l] = L_negate( L_shl( L_deposit_l( hTonalMDCTConc->lastBlockData.spectralData[l] ), 16 ) ); + } + } + FOR( i = 1; i < hTonalMDCTConc->pTCI_float->numIndexes; i++ ) + { + FOR( l = hTonalMDCTConc->pTCI_float->upperIndex[i - 1] + 1; l < hTonalMDCTConc->pTCI_float->lowerIndex[i]; l++ ) + { + IF( GT_32( concealment_noise[l], 0 ) ) + { + mdctSpectrum[l] = L_shl( L_deposit_l( hTonalMDCTConc->lastBlockData.spectralData[l] ), 16 ); + } + ELSE + { + mdctSpectrum[l] = L_negate( L_shl( L_deposit_l( hTonalMDCTConc->lastBlockData.spectralData[l] ), 16 ) ); + } + } + } + + FOR( l = hTonalMDCTConc->pTCI_float->upperIndex[hTonalMDCTConc->pTCI_float->numIndexes - 1] + 1; l < crossOverFreq; l++ ) + { + IF( GT_32( concealment_noise[l], 0 ) ) + { + mdctSpectrum[l] = L_shl( L_deposit_l( hTonalMDCTConc->lastBlockData.spectralData[l] ), 16 ); + } + ELSE + { + mdctSpectrum[l] = L_negate( L_shl( L_deposit_l( hTonalMDCTConc->lastBlockData.spectralData[l] ), 16 ) ); + } + } + + FOR( l = crossOverFreq; l < hTonalMDCTConc->lastBlockData.nSamples; l++ ) + { + mdctSpectrum[l] = L_shl( L_deposit_l( hTonalMDCTConc->lastBlockData.spectralData[l] ), 16 ); + } + + *mdctSpectrum_exp = hTonalMDCTConc->lastBlockData.spectralData_exp; + } + /* actual fadeout is done in this case */ + ELSE + { + Word32 num, den; + Word16 exp_num, exp_den; + + exp_num = cngLevelBackgroundTrace_bfi_e; + exp_den = hTonalMDCTConc->curr_noise_nrg_exp; + + ld = norm_l( cngLevelBackgroundTrace_bfi ); + num = L_shl( cngLevelBackgroundTrace_bfi, ld ); + exp_num = sub( exp_num, ld ); + ld = norm_l( hTonalMDCTConc->curr_noise_nrg ); + den = L_shl( hTonalMDCTConc->curr_noise_nrg, ld ); + exp_den = sub( exp_den, ld ); + + exp = sub( exp_num, exp_den ); + + IF( GT_32( num, den ) ) + { + num = L_shr( num, 1 ); + exp = add( exp, 1 ); + } + tmp = div_l( num, round_fx( den ) ); + tmp = Sqrt16( tmp, &exp ); + g = mult_r( g, tmp ); // exponent of g = exp + + L_tmp = L_deposit_h( 0 ); + exp = sub( hTonalMDCTConc->lastBlockData.spectralData_exp, add( concealment_noise_e, exp ) ); + + IF( GT_16( exp, 0 ) ) + { + g = shr( g, exp ); + *mdctSpectrum_exp = hTonalMDCTConc->lastBlockData.spectralData_exp; + } + ELSE + { + crossfadeGain = shl( crossfadeGain, exp ); + *mdctSpectrum_exp = sub( hTonalMDCTConc->lastBlockData.spectralData_exp, exp ); + } + /*make a headroom for mdct_shaping*/ + exp = sub( *mdctSpectrum_exp, SPEC_EXP_DEC ); + /* assert(exp < 0);*/ + IF( exp < 0 ) + { + *mdctSpectrum_exp = SPEC_EXP_DEC; + } + ELSE + { + exp = 0; + } + + FOR( l = 0; l < hTonalMDCTConc->pTCI_float->lowerIndex[0]; l++ ) + { + Word16 x = hTonalMDCTConc->lastBlockData.spectralData[l]; + Word32 y = concealment_noise[l]; + + IF( GT_16( g, 0 ) ) + { + L_tmp = Mpy_32_16_1( y, g ); + } + + L_tmp2 = L_msu( L_tmp, crossfadeGain, x ); + IF( GT_32( y, 0 ) ) + { + L_tmp2 = L_mac( L_tmp, crossfadeGain, x ); + } + mdctSpectrum[l] = L_shl( L_tmp2, exp ); + move32(); + + hTonalMDCTConc->faded_signal_nrg = L_add( hTonalMDCTConc->faded_signal_nrg, Mpy_32_32( mdctSpectrum[l], mdctSpectrum[l] ) ); + } + + FOR( i = 1; i < hTonalMDCTConc->pTCI_float->numIndexes; i++ ) + { + FOR( l = hTonalMDCTConc->pTCI_float->upperIndex[i - 1] + 1; l < hTonalMDCTConc->pTCI_float->lowerIndex[i]; l++ ) + { + Word16 x = hTonalMDCTConc->lastBlockData.spectralData[l]; + Word32 y = concealment_noise[l]; + + L_tmp = Mpy_32_16_1( y, g ); + L_tmp2 = L_msu( L_tmp, crossfadeGain, x ); + IF( GT_32( y, 0 ) ) + { + L_tmp2 = L_mac( L_tmp, crossfadeGain, x ); + } + mdctSpectrum[l] = L_shl( L_tmp2, exp ); + + hTonalMDCTConc->faded_signal_nrg = L_add( hTonalMDCTConc->faded_signal_nrg, Mpy_32_32( mdctSpectrum[l], mdctSpectrum[l] ) ); + } + } + + FOR( l = hTonalMDCTConc->pTCI_float->upperIndex[hTonalMDCTConc->pTCI_float->numIndexes - 1] + 1; l < crossOverFreq; l++ ) + { + Word16 x = hTonalMDCTConc->lastBlockData.spectralData[l]; + Word32 y = concealment_noise[l]; + + L_tmp = Mpy_32_16_1( y, g ); + L_tmp2 = L_msu( L_tmp, crossfadeGain, x ); + IF( GT_32( y, 0 ) ) + { + L_tmp2 = L_mac( L_tmp, crossfadeGain, x ); + } + mdctSpectrum[l] = L_shl( L_tmp2, exp ); + + hTonalMDCTConc->faded_signal_nrg = L_add( hTonalMDCTConc->faded_signal_nrg, Mpy_32_32( mdctSpectrum[l], mdctSpectrum[l] ) ); + } + + FOR( l = crossOverFreq; l < hTonalMDCTConc->lastBlockData.nSamples; l++ ) + { + mdctSpectrum[l] = L_deposit_h( 0 ); + } + + hTonalMDCTConc->faded_signal_nrg_exp = shl( *mdctSpectrum_exp, 1 ); + } + } + + // Compare curr_noise_nrg with MDCT_ST_PLC_FADEOUT_MIN_NOISE_NRG + Flag flag; + flag = EQ_16( hTonalMDCTConc->curr_noise_nrg_exp, 0 ) && GT_32( hTonalMDCTConc->curr_noise_nrg, MDCT_ST_PLC_FADEOUT_MIN_NOISE_NRG_Q31 ); + flag = flag || GT_16( hTonalMDCTConc->curr_noise_nrg_exp, 0 ); + + IF( GT_32( hTonalMDCTConc->faded_signal_nrg, 0 ) && flag ) + { + Word16 num_exp, den_exp; + Word32 num, den; + + num = BASOP_Util_Add_Mant32Exp( hTonalMDCTConc->last_block_nrg, hTonalMDCTConc->last_block_nrg_exp, L_negate( last_block_nrg_correct ), last_block_nrg_correct_e, &num_exp ); + + den = hTonalMDCTConc->faded_signal_nrg; + den_exp = hTonalMDCTConc->faded_signal_nrg_exp; + + ld = norm_l( num ); + num = L_shl( num, ld ); + num_exp = sub( num_exp, ld ); + + ld = norm_l( den ); + den = L_shl( den, ld ); + den_exp = sub( den_exp, ld ); + + exp = sub( num_exp, den_exp ); + + IF( GT_32( num, den ) ) + { + num = L_shr( num, 1 ); + exp = add( exp, 1 ); + } + tmp = div_l( num, round_fx( den ) ); + tmp = Sqrt16( tmp, &exp ); + + FOR( i = 0; i < crossOverFreq; i++ ) + { + mdctSpectrum[i] = Mpy_32_16_1( mdctSpectrum[i], tmp ); + } + *mdctSpectrum_exp = add( *mdctSpectrum_exp, exp ); + } + } + ELSE + { + IF( !tonalConcealmentActive ) + { + ld = sub( 14, norm_s( hTonalMDCTConc->lastBlockData.nSamples ) ); + fac = shr( -32768, ld ); + + FOR( i = 0; i < crossOverFreq; i++ ) + { + Word16 x = hTonalMDCTConc->lastBlockData.spectralData[i]; + Word32 y; + rnd = extract_l( L_mac0( 13849, rnd, 31821 ) ); /* Q0 */ + y = L_mult( tilt, rnd ); /* 15Q16 */ + + nrgNoiseInLastFrame = L_add( nrgNoiseInLastFrame, Mpy_32_16_1( L_msu( 0, x, fac ), x ) ); // Q(31 - x_exp - ld) + Q(15 - x_exp) - 15 = Q(31 - x_exp * 2 - ld) + x = round_fx( y ); /* 15Q16 -> 15Q0 */ + nrgWhiteNoise = L_add( nrgWhiteNoise, Mpy_32_16_1( L_msu( 0, x, fac ), x ) ); // Q(31 - (15 - 0) - ld) + Q(0) - 15 = Q(1 - ld) + + mdctSpectrum[i] = y; /* 15Q16 */ + move32(); + + tilt = mult_r( tilt, tiltFactor ); /* Q15 */ + } + + IF( nrgNoiseInLastFrame == 0 ) + { + set32_fx( mdctSpectrum, 0, crossOverFreq ); + *mdctSpectrum_exp = SPEC_EXP_DEC; + } + ELSE + { + exp_last = add( ld, shl( hTonalMDCTConc->lastBlockData.spectralData_exp, 1 ) ); + exp_noise = add( ld, 30 ); + + IF( nrgWhiteNoise > 0 ) + { + ld = norm_l( nrgNoiseInLastFrame ); + nrgNoiseInLastFrame = L_shl( nrgNoiseInLastFrame, ld ); + exp_last = sub( exp_last, ld ); + ld = norm_l( nrgWhiteNoise ); + nrgWhiteNoise = L_shl( nrgWhiteNoise, ld ); + exp_noise = sub( exp_noise, ld ); + + exp = sub( exp_last, exp_noise ); + + IF( nrgNoiseInLastFrame > nrgWhiteNoise ) + { + nrgNoiseInLastFrame = L_shr( nrgNoiseInLastFrame, 1 ); + exp = add( exp, 1 ); + } + tmp = div_l( nrgNoiseInLastFrame, round_fx( nrgWhiteNoise ) ); + tmp = Sqrt16( tmp, &exp ); + g = mult_r( g, tmp ); // exponent of g = exp + + L_tmp = L_deposit_h( 0 ); + ld = sub( hTonalMDCTConc->lastBlockData.spectralData_exp, 15 ); + exp = sub( ld, exp ); + + IF( exp > 0 ) + { + g = shr( g, exp ); + *mdctSpectrum_exp = hTonalMDCTConc->lastBlockData.spectralData_exp; + } + ELSE + { + crossfadeGain = shl( crossfadeGain, exp ); + *mdctSpectrum_exp = sub( hTonalMDCTConc->lastBlockData.spectralData_exp, exp ); + } + /*make a headroom for mdct_shaping*/ + exp = sub( *mdctSpectrum_exp, SPEC_EXP_DEC ); + /* assert(exp < 0);*/ + IF( exp < 0 ) + { + *mdctSpectrum_exp = SPEC_EXP_DEC; + } + ELSE + { + exp = 0; + } + } + FOR( i = 0; i < crossOverFreq; i++ ) + { + Word16 const x = hTonalMDCTConc->lastBlockData.spectralData[i]; + Word32 const y = mdctSpectrum[i]; + + IF( GT_16( g, 0 ) ) + { + L_tmp = Mpy_32_16_1( y, g ); + } + + L_tmp2 = L_msu( L_tmp, crossfadeGain, x ); + IF( GT_32( y, 0 ) ) + { + L_tmp2 = L_mac( L_tmp, crossfadeGain, x ); + } + mdctSpectrum[i] = L_shl( L_tmp2, exp ); + move32(); + } + } + exp = sub( hTonalMDCTConc->lastBlockData.spectralData_exp, sub( *mdctSpectrum_exp, 16 ) ); + FOR( i = crossOverFreq; i < hTonalMDCTConc->lastBlockData.nSamples; i++ ) + { + mdctSpectrum[i] = L_shl( L_deposit_l( hTonalMDCTConc->lastBlockData.spectralData[i] ), exp ); + move32(); + } + } + ELSE + { + assert( hTonalMDCTConc->pTCI_float->numIndexes > 0 ); + FOR( l = hTonalMDCTConc->pTCI_float->lowerIndex[0]; l <= hTonalMDCTConc->pTCI_float->upperIndex[0]; l++ ) + { + mdctSpectrum[l] = L_deposit_l( 0 ); + } + + ld = sub( 14, norm_s( hTonalMDCTConc->lastBlockData.nSamples ) ); + fac = shr( -32768, ld ); + FOR( l = 0; l < hTonalMDCTConc->pTCI_float->lowerIndex[0]; l++ ) + { + Word16 x = hTonalMDCTConc->lastBlockData.spectralData[l]; + Word32 y; + + rnd = extract_l( L_mac0( 13849, rnd, 31821 ) ); + y = L_mult( tilt, rnd ); // 15Q16 + + nrgNoiseInLastFrame = L_add( nrgNoiseInLastFrame, Mpy_32_16_1( L_msu( 0, x, fac ), x ) ); // Q(31 - x_exp - ld) + Q(15 - x_exp) - 15 = Q(31 - x_exp * 2 - ld) + x = round_fx( y ); // 15Q16 -> Q15 + nrgWhiteNoise = L_add( nrgWhiteNoise, Mpy_32_16_1( L_msu( 0, x, fac ), x ) ); // Q(31 - (15 - 0) - ld) + Q(0) - 15 = Q(1 - ld) + + mdctSpectrum[l] = y; /* 15Q16 L_deposit_l(y);*/ + move32(); + + tilt = mult_r( tilt, tiltFactor ); /* Q15 */ + } + + FOR( i = 1; i < hTonalMDCTConc->pTCI_float->numIndexes; i++ ) + { + tmp = round_fx( BASOP_Util_fPow( L_deposit_h( tiltFactor ), 0, L_deposit_h( hTonalMDCTConc->pTCI_float->upperIndex[i - 1] - hTonalMDCTConc->pTCI_float->lowerIndex[i - 1] + 1 ), 15, &exp ) ); + tmp = shl( tmp, exp ); + tilt = mult_r( tilt, tmp ); // Q15 + + FOR( l = hTonalMDCTConc->pTCI_float->lowerIndex[i]; l <= hTonalMDCTConc->pTCI_float->upperIndex[i]; l++ ) + { + mdctSpectrum[l] = L_deposit_l( 0 ); + } + FOR( l = hTonalMDCTConc->pTCI_float->upperIndex[i - 1] + 1; l < hTonalMDCTConc->pTCI_float->lowerIndex[i]; l++ ) + { + Word16 x = hTonalMDCTConc->lastBlockData.spectralData[l]; + Word32 y; + + rnd = extract_l( L_mac0( 13849, rnd, 31821 ) ); + y = L_mult( tilt, rnd ); + + nrgNoiseInLastFrame = L_add( nrgNoiseInLastFrame, Mpy_32_16_1( L_msu( 0, x, fac ), x ) ); // Q(31 - hTonalMDCTConc->lastBlockData.spectralData_exp * 2 - ld) + x = round_fx( y ); // Q15 + nrgWhiteNoise = L_add( nrgWhiteNoise, Mpy_32_16_1( L_msu( 0, x, fac ), x ) ); // Q(1 - ld) + + mdctSpectrum[l] = y; /* 15Q16 L_deposit_l(y);*/ + move32(); + + tilt = mult_r( tilt, tiltFactor ); // Q15 + } + } + + tmp = round_fx( BASOP_Util_fPow( L_deposit_h( tiltFactor ), 0, + L_deposit_h( hTonalMDCTConc->pTCI_float->upperIndex[hTonalMDCTConc->pTCI_float->numIndexes - 1] - hTonalMDCTConc->pTCI_float->lowerIndex[hTonalMDCTConc->pTCI_float->numIndexes - 1] + 1 ), 15, &exp ) ); + BASOP_SATURATE_WARNING_OFF_EVS /*next op may result in 32768*/ + tmp = shl( tmp, exp ); + BASOP_SATURATE_WARNING_ON_EVS + tilt = mult_r( tilt, tmp ); + + FOR( l = add( hTonalMDCTConc->pTCI_float->upperIndex[hTonalMDCTConc->pTCI_float->numIndexes - 1], 1 ); l < crossOverFreq; l++ ) + { + Word16 x = hTonalMDCTConc->lastBlockData.spectralData[l]; + Word32 y; + rnd = extract_l( L_mac0( 13849, rnd, 31821 ) ); + y = L_mult( tilt, rnd ); + + nrgNoiseInLastFrame = L_add( nrgNoiseInLastFrame, Mpy_32_16_1( L_msu( 0, x, fac ), x ) ); + x = round_fx( y ); + nrgWhiteNoise = L_add( nrgWhiteNoise, Mpy_32_16_1( L_msu( 0, x, fac ), x ) ); + + mdctSpectrum[l] = y; /* 15Q16 L_deposit_l(y);*/ + move32(); + + tilt = mult_r( tilt, tiltFactor ); + } + + IF( EQ_32( nrgNoiseInLastFrame, 0 ) ) + { + set32_fx( mdctSpectrum, 0, crossOverFreq ); + *mdctSpectrum_exp = SPEC_EXP_DEC; + } + ELSE + { + exp_last = add( ld, shl( hTonalMDCTConc->lastBlockData.spectralData_exp, 1 ) ); + exp_noise = add( ld, shl( 15, 1 ) ); + + ld = norm_l( nrgNoiseInLastFrame ); + nrgNoiseInLastFrame = L_shl( nrgNoiseInLastFrame, ld ); + exp_last = sub( exp_last, ld ); + ld = norm_l( nrgWhiteNoise ); + nrgWhiteNoise = L_shl( nrgWhiteNoise, ld ); + exp_noise = sub( exp_noise, ld ); + + exp = sub( exp_last, exp_noise ); + + IF( nrgNoiseInLastFrame > nrgWhiteNoise ) + { + nrgNoiseInLastFrame = L_shr( nrgNoiseInLastFrame, 1 ); + exp = add( exp, 1 ); + } + tmp = div_l( nrgNoiseInLastFrame, round_fx( nrgWhiteNoise ) ); + tmp = Sqrt16( tmp, &exp ); + g = mult_r( g, tmp ); + + L_tmp = L_deposit_h( 0 ); + ld = sub( hTonalMDCTConc->lastBlockData.spectralData_exp, 15 ); + exp = sub( ld, exp ); + IF( exp > 0 ) + { + g = shr( g, exp ); + *mdctSpectrum_exp = hTonalMDCTConc->lastBlockData.spectralData_exp; + } + ELSE + { + crossfadeGain = shl( crossfadeGain, exp ); + *mdctSpectrum_exp = sub( hTonalMDCTConc->lastBlockData.spectralData_exp, exp ); + } + /*make a headroom for mdct_shaping*/ + exp = sub( *mdctSpectrum_exp, SPEC_EXP_DEC ); + + IF( exp < 0 ) + { + *mdctSpectrum_exp = SPEC_EXP_DEC; + } + ELSE + { + exp = 0; + } + + FOR( l = 0; l < hTonalMDCTConc->pTCI_float->lowerIndex[0]; l++ ) + { + Word16 const x = hTonalMDCTConc->lastBlockData.spectralData[l]; + Word32 const y = mdctSpectrum[l]; + + IF( GT_16( g, 0 ) ) + { + L_tmp = Mpy_32_16_1( y, g ); + } + + L_tmp2 = L_msu( L_tmp, crossfadeGain, x ); + IF( GT_32( y, 0 ) ) + { + L_tmp2 = L_mac( L_tmp, crossfadeGain, x ); + } + mdctSpectrum[l] = L_shl( L_tmp2, exp ); + move32(); + } + + FOR( i = 1; i < hTonalMDCTConc->pTCI_float->numIndexes; i++ ) + { + FOR( l = hTonalMDCTConc->pTCI_float->upperIndex[i - 1] + 1; l < hTonalMDCTConc->pTCI_float->lowerIndex[i]; l++ ) + { + Word16 const x = hTonalMDCTConc->lastBlockData.spectralData[l]; + Word32 const y = mdctSpectrum[l]; + + IF( GT_16( g, 0 ) ) + { + L_tmp = Mpy_32_16_1( y, g ); + } + + L_tmp2 = L_msu( L_tmp, crossfadeGain, x ); + IF( GT_32( y, 0 ) ) + { + L_tmp2 = L_mac( L_tmp, crossfadeGain, x ); + } + mdctSpectrum[l] = L_shl( L_tmp2, exp ); + move32(); + } + } + + /* initialize bins of tonal components with zero: basically not + necessary, but currently the whole spectrum is rescaled in + mdct_noiseShaping() and then there would be a processing of + uninitialized values */ + FOR( i = 0; i < hTonalMDCTConc->pTCI_float->numIndexes; i++ ) + { + FOR( l = hTonalMDCTConc->pTCI_float->lowerIndex[i]; l <= hTonalMDCTConc->pTCI_float->upperIndex[i]; l++ ) + { + mdctSpectrum[l] = L_deposit_l( 0 ); + } + } + + FOR( l = add( hTonalMDCTConc->pTCI_float->upperIndex[hTonalMDCTConc->pTCI_float->numIndexes - 1], 1 ); l < crossOverFreq; l++ ) + { + Word16 const x = hTonalMDCTConc->lastBlockData.spectralData[l]; + Word32 const y = mdctSpectrum[l]; + + IF( GT_16( g, 0 ) ) + { + L_tmp = Mpy_32_16_1( y, g ); + } + + L_tmp2 = L_msu( L_tmp, crossfadeGain, x ); + IF( GT_32( y, 0 ) ) + { + L_tmp2 = L_mac( L_tmp, crossfadeGain, x ); + } + mdctSpectrum[l] = L_shl( L_tmp2, exp ); + move32(); + } + } + exp = sub( hTonalMDCTConc->lastBlockData.spectralData_exp, sub( *mdctSpectrum_exp, 16 ) ); + FOR( l = crossOverFreq; l < hTonalMDCTConc->lastBlockData.nSamples; l++ ) + { + mdctSpectrum[l] = L_shl( L_deposit_l( hTonalMDCTConc->lastBlockData.spectralData[l] ), exp ); + move32(); + } + } + } + + *pSeed = rnd; + + pop_wmops(); + + return; +} + + void TonalMDCTConceal_InsertNoise( const TonalMDCTConcealPtr hTonalMDCTConc, /*IN */ Word32* mdctSpectrum, /*OUT*/ -- GitLab