diff --git a/lib_com/ivas_prot.h b/lib_com/ivas_prot.h index 3cfacb4b191208e202e425e3e2843ddf43b65f9a..5c0c6a91fce3624f0159311dbbd7fba6c7096278 100644 --- a/lib_com/ivas_prot.h +++ b/lib_com/ivas_prot.h @@ -3329,7 +3329,32 @@ void dequantize_sns( float snsQ_out[CPE_CHANNELS][NB_DIV][M], Decoder_State **sts ); +#ifdef IVAS_FLOAT_FIXED +void sns_avq_cod_fx( + const Word32 *sns_fx, /* i : Input sns vectors */ + Word16 exp_sns, + const Word32 *snsmid_fx, /* i : Input mid-sns vectors */ + Word16 exp_snsmid, + Word32 *sns_q_fx, /* o : Quantized LFS vectors Q16 */ + Word32 *snsmid_q_fx, /* o : Quantized mid-LFS vectors Q16 */ + Word16 *index, /* o : Quantization indices */ + const Word16 core, /* i : core */ + const Word16 L_frame, + const Word16 low_brate_mode /* i : flag low bit operating mode */ +); +void sns_avq_cod_stereo_fx( + const Word32 *snsl_fx, /* i : Input sns vector (left channel) */ + Word16 exp_snl, + const Word32 *snsr_fx, /* i : Input sns vector (right channel) */ + Word16 exp_snr, + const Word16 L_frame, + Word32 *snsl_q_fx, /* o : Quantized sns vector (left channel) Q16 */ + Word32 *snsr_q_fx, /* o : Quantized sns vector (right channel) Q16 */ + Word16 *indexl, /* o : Quantization indices (left channel) */ + Word16 *indexr /* o : Quantization indices (right channel) */ +); +#else void sns_avq_cod( const float *sns, /* i : Input sns vectors */ const float *snsmid, /* i : Input mid-sns vectors */ @@ -3340,7 +3365,6 @@ void sns_avq_cod( const int16_t L_frame, const int16_t low_brate_mode /* i : flag low bit operating mode */ ); - void sns_avq_cod_stereo( const float *snsl, /* i : Input sns vector (left channel) */ const float *snsr, /* i : Input sns vector (right channel) */ @@ -3350,6 +3374,7 @@ void sns_avq_cod_stereo( int16_t *indexl, /* o : Quantization indices (left channel) */ int16_t *indexr /* o : Quantization indices (right channel) */ ); +#endif void sns_avq_dec( int16_t *index, /* i : Quantization indices */ diff --git a/lib_com/ivas_rom_com_fx.c b/lib_com/ivas_rom_com_fx.c index 42176bf82d51ad39af8b391fedd2a928f2b8ee28..affd420b94eb44e1325d8fb7fdcd7c3bad5380f4 100644 --- a/lib_com/ivas_rom_com_fx.c +++ b/lib_com/ivas_rom_com_fx.c @@ -1288,6 +1288,7 @@ const Word16 pow_10_icbwe_gsMappingDFT_tbl_fx[128] = { * TD Stereo ROM tables *----------------------------------------------------------------------------------*/ +// Q31 const UWord32 tdm_ratio_tabl_fx[TDM_NQ + 1] = { 0, 0, 23407572, 52613348, 92771296, 143881408, 205084688, 275736896, 355193792, 442596384, 536870912, @@ -1297,6 +1298,14 @@ const UWord32 tdm_ratio_tabl_fx[TDM_NQ + 1] = { 2147483647, 2147483647, 2147483647 }; +// Q24 +const Word32 tdm_ratio_tabl_fx_Q24[TDM_NQ + 1] = { + 0, 0, 182871, 411041, 724775, 1124073, 1602224, 2154194, + 2774951, 3457784, 4194304, 4976122, 5796528, 6643777, 7511159, 8388608, + 9266056, 10133438, 10980688, 11801094, 12582912, 13319432, 14002264, 14623021, + 15174992, 15653143, 16052440, 16366174, 16594344, 16777216, 16777216, 16777216 +}; + const UWord32 tdm_den_ratio_tabl_fx[TDM_NQ + 1] = { 1073741824, 1073741824, 1097471488, 1127536256, 1170593280, 1227179520, 1297939072, 1383409024, 1483374336, 1596009856, 1717986944, diff --git a/lib_com/ivas_rom_com_fx.h b/lib_com/ivas_rom_com_fx.h index 29a5b21cf6cc9ae796e7b903a7c2bc083699e101..6692f0afd9713eac8bd2f0078baadd5a04cb058a 100644 --- a/lib_com/ivas_rom_com_fx.h +++ b/lib_com/ivas_rom_com_fx.h @@ -106,6 +106,7 @@ extern const Word16 pow_10_icbwe_gsMappingDFT_tbl_fx[]; *----------------------------------------------------------------------------------*/ extern const UWord32 tdm_ratio_tabl_fx[TDM_NQ + 1]; +extern const Word32 tdm_ratio_tabl_fx_Q24[TDM_NQ + 1]; extern const UWord32 tdm_den_ratio_tabl_fx[]; /* LSFs Intra-frame prediction tables */ diff --git a/lib_enc/enc_prm.c b/lib_enc/enc_prm.c index d3c52faec12fd4a9189edf4cbecbd37f93af48be..7c58087d982bfd70386641a6141d4185fc129c4b 100644 --- a/lib_enc/enc_prm.c +++ b/lib_enc/enc_prm.c @@ -49,6 +49,159 @@ * write TCX mode *--------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED +void writeTCXMode( + Encoder_State *st, /* i/o: encoder state structure */ + BSTR_ENC_HANDLE hBstr, /* i/o: bitstream handle */ + const Word16 MCT_flag, /* i : hMCT handle allocated (1) or not (0) */ + Word16 *nbits_start /* o : nbits start */ +) +{ + UWord16 index; + Word16 idx, start_idx; + Word16 nBits; + + IF( st->tcxonly ) + { + push_next_indice( hBstr, (UWord16) EQ_16( st->core, TCX_10_CORE ), 1 ); + + test(); + IF( EQ_16( st->clas, UNVOICED_CLAS ) ) + { + index = 0; + move16(); + } + ELSE IF( EQ_16( st->clas, VOICED_TRANSITION ) || EQ_16( st->clas, UNVOICED_TRANSITION ) ) + { + index = 1; + move16(); + } + ELSE IF( EQ_16( st->clas, VOICED_CLAS ) ) + { + index = 2; + move16(); + } + ELSE + { + index = 3; + move16(); + } + + push_next_indice( hBstr, index, 2 ); + + test(); + IF( EQ_16( st->element_mode, IVAS_CPE_MDCT ) && !MCT_flag ) + { + push_next_indice( hBstr, st->vad_flag, 1 ); + } + } + ELSE + { + IF( EQ_16( st->core, ACELP_CORE ) ) + { + /* write the RF signaling information */ + IF( EQ_16( st->rf_mode, 1 ) ) + { + /* find the section in the ACELP signaling table corresponding to bitrate */ + idx = 0; + move16(); + WHILE( NE_32( acelp_sig_tbl[idx], st->total_brate ) ) /* total bitrate is kept at 13.2kbps */ + { + idx = add( idx, 1 ); + } + + /* retrieve the number of bits for signaling */ + idx = add( idx, 1 ); + nBits = extract_l( acelp_sig_tbl[idx] ); + + /* retrieve the signaling index */ + idx = add( idx, 1 ); + start_idx = idx; + move16(); + WHILE( NE_32( acelp_sig_tbl[idx], SIG2IND( st->coder_type, st->bwidth, st->sharpFlag, st->rf_mode ) ) ) + { + idx = add( idx, 1 ); + } + push_next_indice( hBstr, sub( idx, start_idx ), nBits ); + push_next_indice( hBstr, 0, 1 ); /* Indicate to the decoder that the core is ACELP*/ + *nbits_start = 3; + move16(); + } + ELSE + { + push_next_indice( hBstr, st->coder_type, 3 ); + } + } + ELSE + { + IF( EQ_16( st->mdct_sw, MODE1 ) ) + { + /* 2 bits instead of 3 as TCX is already signaled */ + push_next_indice( hBstr, st->hTcxCfg->coder_type, 2 ); + } + ELSE + { + IF( EQ_16( st->mdct_sw_enable, MODE2 ) ) + { + push_next_indice( hBstr, 1, 1 ); /* TCX */ + push_next_indice( hBstr, 0, 1 ); /* not HQ_CORE */ + push_next_indice( hBstr, st->hTcxCfg->coder_type, 2 ); + } + ELSE + { + /*write the RF signaling information*/ + IF( EQ_16( st->rf_mode, 1 ) ) + { + /* find the section in the ACELP signaling table corresponding to bitrate */ + idx = 0; + move16(); + WHILE( NE_32( acelp_sig_tbl[idx], st->total_brate ) ) + { + idx = add( idx, 1 ); + } + + /* retrieve the number of bits for signaling */ + idx = add( idx, 1 ); + nBits = extract_l( acelp_sig_tbl[idx] ); + + test(); + test(); + IF( EQ_16( st->hTcxCfg->coder_type, VOICED ) || EQ_16( st->hTcxCfg->coder_type, GENERIC ) || EQ_16( st->hTcxCfg->coder_type, TRANSITION ) ) + { + st->sharpFlag = 1; + move16(); + } + ELSE + { + st->sharpFlag = 0; + move16(); + } + + /* retrieve the signaling index */ + idx = add( idx, 1 ); + start_idx = idx; + move16(); + WHILE( NE_32( acelp_sig_tbl[idx], SIG2IND( st->hTcxCfg->coder_type, st->bwidth, st->sharpFlag, st->rf_mode ) ) ) + { + idx = add( idx, 1 ); + } + push_next_indice( hBstr, sub( idx, start_idx ), nBits ); + push_next_indice( hBstr, 1, 1 ); /* Indicate to the decoder that the core is TCX*/ + *nbits_start = 3; + move16(); + } + ELSE + { + push_next_indice( hBstr, add( ACELP_MODE_MAX, st->hTcxCfg->coder_type ), 3 ); + } + } + } + } + } + + return; +} +#else void writeTCXMode( Encoder_State *st, /* i/o: encoder state structure */ BSTR_ENC_HANDLE hBstr, /* i/o: bitstream handle */ @@ -180,6 +333,7 @@ void writeTCXMode( return; } +#endif /*-------------------------------------------------------------------* @@ -188,6 +342,29 @@ void writeTCXMode( * write TCX transform type *-------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED +void writeTCXWindowing( + BSTR_ENC_HANDLE hBstr, /* i/o: bitstream handle */ + const Word16 overlap_mode /* i : overlap mode */ +) +{ + + IF( EQ_16( overlap_mode, MIN_OVERLAP ) ) + { + push_next_indice( hBstr, 2, 2 ); + } + ELSE IF( EQ_16( overlap_mode, HALF_OVERLAP ) ) + { + push_next_indice( hBstr, 3, 2 ); + } + ELSE + { + push_next_indice( hBstr, 0, 1 ); + } + + return; +} +#else void writeTCXWindowing( BSTR_ENC_HANDLE hBstr, /* i/o: bitstream handle */ const int16_t overlap_mode /* i : overlap mode */ @@ -209,6 +386,7 @@ void writeTCXWindowing( return; } +#endif /*-------------------------------------------------------------------* diff --git a/lib_enc/ivas_mdct_core_enc.c b/lib_enc/ivas_mdct_core_enc.c index f2e7125969483ac56a90450e56b8bdf533b43614..180594fa97281a6c14121f422a7ec608e1b06817 100644 --- a/lib_enc/ivas_mdct_core_enc.c +++ b/lib_enc/ivas_mdct_core_enc.c @@ -41,6 +41,11 @@ #include "rom_com.h" #include "ivas_rom_com.h" #include "wmc_auto.h" +#ifdef IVAS_FLOAT_FIXED +#include "prot_fx_enc.h" +#include "prot_fx.h" +#endif + /*--------------------------------------------------------------* * Local constants @@ -582,6 +587,10 @@ void ivas_mdct_core_whitening_enc( Encoder_State *st, **sts; float scf[CPE_CHANNELS][NB_DIV][M]; float scf_q[CPE_CHANNELS][NB_DIV][M]; +#ifdef IVAS_FLOAT_FIXED + Word32 scf_fx[CPE_CHANNELS][NB_DIV][M]; + Word32 scf_q_fx[CPE_CHANNELS][NB_DIV][M]; +#endif float chE[2], chE_tot; int8_t sns_low_br_mode; int16_t nbits_start_sns; @@ -599,7 +608,11 @@ void ivas_mdct_core_whitening_enc( for ( ch = 0; ch < CPE_CHANNELS; ch++ ) { +#ifdef IVAS_FLOAT_FIXED + stereo_tcx_init_enc_fx( sts[ch] ); +#else stereo_tcx_init_enc( sts[ch] ); +#endif set_s( tnsSize[ch], 0, 2 ); set_s( tnsBits[ch], 0, 2 ); @@ -898,7 +911,20 @@ void ivas_mdct_core_whitening_enc( if ( sts[0]->hTcxEnc->tcxMode == TCX_20 && sts[1]->hTcxEnc->tcxMode == TCX_20 && sts[0]->mct_chan_mode == MCT_CHAN_MODE_REGULAR && sts[1]->mct_chan_mode == MCT_CHAN_MODE_REGULAR ) { +#ifdef IVAS_FLOAT_FIXED + /*=================flt-2-fix==============*/ + Word16 exp_snl = 0, exp_snr = 0; + f2me_buf( scf[0][0], scf_fx[0][0], &exp_snl, M ); + f2me_buf( scf[1][0], scf_fx[1][0], &exp_snr, M ); + /*=================flt-2-fix==============*/ + sns_avq_cod_stereo_fx( scf_fx[0][0], exp_snl, scf_fx[1][0], exp_snr, sts[0]->L_frame, scf_q_fx[0][0], scf_q_fx[1][0], param_lpc[0], param_lpc[1] ); + /*===============fix-2-flt==========================*/ + fixedToFloat_arrL( scf_q_fx[0][0], scf_q[0][0], Q16, M ); + fixedToFloat_arrL( scf_q_fx[1][0], scf_q[1][0], Q16, M ); + /*===============fix-2-flt==========================*/ +#else sns_avq_cod_stereo( scf[0][0], scf[1][0], sts[0]->L_frame, scf_q[0][0], scf_q[1][0], param_lpc[0], param_lpc[1] ); +#endif } else { @@ -910,7 +936,31 @@ void ivas_mdct_core_whitening_enc( continue; } st = sts[ch]; - +#ifdef IVAS_FLOAT_FIXED + Word16 exp_scf_1 = 0, exp_scf_0 = 0; + IF( st->hTcxEnc->tcxMode == TCX_20 ) + { + /*===============flt-2-fix==========================*/ + f2me_buf( scf[ch][0], scf_fx[ch][0], &exp_scf_0, M ); + /*===============flt-2-fix==========================*/ + sns_avq_cod_fx( scf_fx[ch][0], exp_scf_0, NULL, 0, scf_q_fx[ch][0], NULL, ¶m_lpc[ch][1], st->hTcxEnc->tcxMode, st->L_frame, sns_low_br_mode ); + /*===============fix-2-flt==========================*/ + fixedToFloat_arrL( scf_q_fx[ch][0], scf_q[ch][0], Q16, M ); + /*===============fix-2-flt==========================*/ + } + ELSE + { + /*===============flt-2-fix==========================*/ + f2me_buf( scf[ch][1], scf_fx[ch][1], &exp_scf_1, M ); + f2me_buf( scf[ch][0], scf_fx[ch][0], &exp_scf_0, M ); + /*===============flt-2-fix==========================*/ + sns_avq_cod_fx( scf_fx[ch][1], exp_scf_1, scf_fx[ch][0], exp_scf_0, scf_q_fx[ch][1], scf_q_fx[ch][0], ¶m_lpc[ch][1], st->hTcxEnc->tcxMode, st->L_frame, sns_low_br_mode ); + /*===============fix-2-flt==========================*/ + fixedToFloat_arrL( scf_q_fx[ch][0], scf_q[ch][0], Q16, M ); + fixedToFloat_arrL( scf_q_fx[ch][1], scf_q[ch][1], Q16, M ); + /*===============fix-2-flt==========================*/ + } +#else if ( st->hTcxEnc->tcxMode == TCX_20 ) { sns_avq_cod( scf[ch][0], NULL, scf_q[ch][0], NULL, ¶m_lpc[ch][1], st->hTcxEnc->tcxMode, st->L_frame, sns_low_br_mode ); @@ -919,6 +969,7 @@ void ivas_mdct_core_whitening_enc( { sns_avq_cod( scf[ch][1], scf[ch][0], scf_q[ch][1], scf_q[ch][0], ¶m_lpc[ch][1], st->hTcxEnc->tcxMode, st->L_frame, sns_low_br_mode ); } +#endif } } } diff --git a/lib_enc/ivas_sns_enc.c b/lib_enc/ivas_sns_enc.c index 673df674ffbb6fb4fd7191b8d08d50ab2b1813c9..1373e8a6238339c24c7b06f06faa6f1068f7a031 100644 --- a/lib_enc/ivas_sns_enc.c +++ b/lib_enc/ivas_sns_enc.c @@ -43,8 +43,7 @@ #include "ivas_rom_com.h" #include "ivas_cnst.h" #include "wmc_auto.h" - - +#include "prot_fx_enc.h" /*------------------------------------------------------------------- * sns_1st_cod() * @@ -52,6 +51,126 @@ *-------------------------------------------------------------------*/ /* r : codebook index */ +#ifdef IVAS_FLOAT_FIXED +static Word16 sns_1st_cod_fx( + const Word32 *sns_fx, /* i : vector to quantize */ + Word16 exp_sns, + const Word16 L_frame, + const Word16 core, + Word32 *snsq_fx /* o : quantized sns Q16 */ +) +{ + Word16 index; + const Word16 split_len = M / 2; + move16(); + const Word16 *means; + const Word16 means_fix = 2; // Q15 + move16(); + /* remove means */ + means = NULL; + SWITCH( L_frame ) + { + case L_FRAME16k: + means = &sns_1st_means_16k[core - 1][0]; + break; + case L_FRAME25_6k: + means = &sns_1st_means_25k6[core - 1][0]; + break; + case L_FRAME32k: + means = &sns_1st_means_32k[core - 1][0]; + break; + default: + assert( !"illegal frame length in sns_1st_cod" ); + } + Word16 exp_snsq_buffer[M] = { 0 }, exp_snsq = 0; + move16(); + move16(); + FOR( Word16 i = 0; i < M; ++i ) + { + Word32 tmp = L_mult( means[i], means_fix ); // Q16 + exp_snsq_buffer[i] = 0; + move16(); + snsq_fx[i] = BASOP_Util_Add_Mant32Exp( sns_fx[i], exp_sns, L_negate( tmp ), 15, &exp_snsq_buffer[i] ); + move32(); + } + FOR( int i = 0; i < M; i++ ) + { + exp_snsq = s_max( exp_snsq_buffer[i], exp_snsq ); + } + FOR( int i = 0; i < M; i++ ) + { + snsq_fx[i] = L_shr( snsq_fx[i], exp_snsq - exp_snsq_buffer[i] ); + move32(); + } + + index = 0; + move16(); + FOR( Word16 split = 0; split < 2; ++split ) + { + const Word16 *cdbk_ptr; + Word16 j0, j1, index_split; + Word32 dist_min_fx; + const Word16 cdbk_fix = 8; // 1.f / powf( 2, SNS_CDBKS_BITS_4_FRAC ) in Q15 + move16(); + const Word16 *const cdbk = &sns_1st_cdbk[split][core - 1][0]; + + j0 = imult1616( split, split_len ); + j1 = add( j0, split_len ); + + cdbk_ptr = cdbk; + dist_min_fx = MAXVAL_WORD32; + Word16 exp_dist_min = 31; + index_split = 0; + FOR( Word16 i = 0; i < 32; ++i ) + { + Word32 dist_fx = 0; + move32(); + Word16 exp_dist = 0; + move16(); + FOR( Word16 j = j0; j < j1; ++j ) + { + Word32 tmp_fx; + Word16 exp_tmp = 0; + move16(); + Word32 tmp_1 = L_mult( ( *cdbk_ptr++ ), cdbk_fix ); // Q16 + tmp_fx = BASOP_Util_Add_Mant32Exp( snsq_fx[j], exp_snsq, L_negate( tmp_1 ), 15, &exp_tmp ); + Word32 tmp_2 = Mpy_32_32( tmp_fx, tmp_fx ); // exp_tmp*2 + dist_fx = BASOP_Util_Add_Mant32Exp( dist_fx, exp_dist, tmp_2, exp_tmp * 2, &exp_dist ); // exp_tmp*2 + } + + IF( EQ_16( BASOP_Util_Cmp_Mant32Exp( dist_fx, exp_dist, dist_min_fx, exp_dist_min ), -1 ) ) + { + dist_min_fx = dist_fx; + move32(); + exp_dist_min = exp_dist; + move16(); + index_split = i; + move16(); + } + } + + /* set quantized vector */ + cdbk_ptr = &cdbk[imult1616( index_split, split_len )]; + FOR( Word16 j = j0; j < j1; ++j ) + { + Word32 tmp_3 = L_mult( means[j], means_fix ); // Q16 + Word32 tmp_4 = L_mult( ( *cdbk_ptr++ ), cdbk_fix ); // Q16 + snsq_fx[j] = L_add( tmp_4, tmp_3 ); // Q16 + move32(); + } + + /* for second split shift by five bits to store both indices as one 10 bit value */ + IF( EQ_16( split, 1 ) ) + { + index_split = shl( index_split, 5 ); + } + + index = add( index, index_split ); + } + + return index; +} +#else static int16_t sns_1st_cod( const float *sns, /* i : vector to quantize */ const int16_t L_frame, @@ -63,7 +182,6 @@ static int16_t sns_1st_cod( const int16_t split_len = M / 2; const int16_t *means; const float means_fix2float = 1.f / powf( 2, SNS_MEANS_BITS_4_FRAC ); - /* remove means */ means = NULL; switch ( L_frame ) @@ -80,12 +198,10 @@ static int16_t sns_1st_cod( default: assert( !"illegal frame length in sns_1st_cod" ); } - for ( int16_t i = 0; i < M; ++i ) { snsq[i] = sns[i] - means[i] * means_fix2float; } - index = 0; for ( int16_t split = 0; split < 2; ++split ) { @@ -104,12 +220,10 @@ static int16_t sns_1st_cod( for ( int16_t i = 0; i < 32; ++i ) { float dist; - dist = 0.f; for ( int16_t j = j0; j < j1; ++j ) { float tmp; - tmp = snsq[j] - ( *cdbk_ptr++ ) * cdbk_fix2float; dist += tmp * tmp; } @@ -139,7 +253,7 @@ static int16_t sns_1st_cod( return index; } - +#endif /*------------------------------------------------------------------- * sns_2st_cod() @@ -148,6 +262,82 @@ static int16_t sns_1st_cod( *-------------------------------------------------------------------*/ /* r : number of allocated bits */ +#ifdef IVAS_FLOAT_FIXED +static Word16 sns_2st_cod_fx( + const Word32 *sns_fx, /* i : normalized vector to quantize */ + Word16 exp_sns, + Word32 *snsq_fx, /* i/o: i:1st stage o:1st+2nd stage Q16 */ + Word16 exp_snsq, + Word16 *indx /* o : index[] (4 bits per words) */ +) +{ + Word16 i, nbits; + + Word16 x_fx[M] = { 0 }; + move16(); + Word16 xq_fx[M]; + Word16 exp_x_buff[M] = { 0 }, exp_x = 0; + move16(); + move16(); + Word32 scale_fx = 858993472; // Q31 + move32(); + Word16 nq; + + FOR( i = 0; i < M; i++ ) + { + Word16 exp_tmp = 0; + move16(); + Word32 tmp = BASOP_Util_Add_Mant32Exp( sns_fx[i], exp_sns, L_negate( snsq_fx[i] ), exp_snsq, &exp_tmp ); + x_fx[i] = BASOP_Util_Divide3232_Scale( tmp, scale_fx, &exp_x_buff[i] ); + move16(); + exp_x_buff[i] = add( exp_x_buff[i], exp_tmp ); + move16(); + } + FOR( i = 0; i < M; i++ ) + { + exp_x = s_max( exp_x, exp_x_buff[i] ); + } + FOR( i = 0; i < M; i++ ) + { + x_fx[i] = shr( x_fx[i], sub( ( 15 - Q10 ), exp_x_buff[i] ) ); + move16(); + } + + /* quantize */ + AVQ_cod_lpc_fx( x_fx, xq_fx, indx, 2 ); + FOR( i = 0; i < M; i++ ) + { + Word32 tmp_1 = Mpy_32_16_1( scale_fx, xq_fx[i] ); // Q31 + Q10 - 15 + tmp_1 = L_shr( tmp_1, 10 ); // Q16 + snsq_fx[i] = L_add( snsq_fx[i], tmp_1 ); // Q16 + move32(); + } + + /* total number of bits using entropic code to index the quantizer number */ + nbits = 0; + move16(); + FOR( i = 0; i < 2; i++ ) + { + nq = indx[i]; + nbits = add( nbits, ( add( 2, ( shl( nq, 2 ) ) ) ) ); /* 2 bits to specify Q2,Q3,Q4,ext */ + + IF( GT_16( nq, 6 ) ) + { + nbits = add( nbits, sub( nq, 3 ) ); /* unary code (Q7=1110, ...) */ + } + ELSE IF( GT_16( nq, 4 ) ) + { + nbits = add( nbits, sub( nq, 4 ) ); /* Q5=0, Q6=10 */ + } + ELSE IF( nq == 0 ) + { + nbits = add( nbits, 3 ); /* Q0=110 */ + } + } + + return ( nbits ); +} +#else static int16_t sns_2st_cod( const float *sns, /* i : normalized vector to quantize */ float *snsq, /* i/o: i:1st stage o:1st+2nd stage */ @@ -196,14 +386,115 @@ static int16_t sns_2st_cod( return ( nbits ); } - +#endif /*------------------------------------------------------------------- * sns_avq_cod() * * Stereo noise-shaping AVQ encoder for 1 channel *-------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED +void sns_avq_cod_fx( + const Word32 *sns_fx, /* i : Input sns vectors */ + Word16 exp_sns, + const Word32 *snsmid_fx, /* i : Input mid-sns vectors */ + Word16 exp_snsmid, + Word32 *sns_q_fx, /* o : Quantized LFS vectors Q16 */ + Word32 *snsmid_q_fx, /* o : Quantized mid-LFS vectors Q16 */ + Word16 *index, /* o : Quantization indices */ + const Word16 core, /* i : core */ + const Word16 L_frame, + const Word16 low_brate_mode /* i : flag low bit operating mode */ +) +{ + Word16 i; + Word16 indxt[256], nbits, nbt, nit; + Word32 snsmid_q0_fx[M]; + + index[0] = sns_1st_cod_fx( sns_fx, exp_sns, L_frame, core, sns_q_fx ); + move16(); + nit = 1 + 2; + move16(); + IF( !low_brate_mode ) + { + nbt = sns_2st_cod_fx( sns_fx, exp_sns, sns_q_fx, 31 - Q16, &index[1] ); + nit = add( nit, add( index[1], index[2] ) ); + } + ELSE + { + index[1] = SNS_LOW_BR_MODE; + move16(); + index[2] = 0; + move16(); + } + index += nit; + nit = 0; + move16(); + *index = 0; + move16(); + + IF( EQ_16( core, TCX_10_CORE ) ) + { + index++; + + index[0] = sns_1st_cod_fx( snsmid_fx, exp_snsmid, L_frame, core, snsmid_q_fx ); + move16(); + nit = 1 + 2; + move16(); + IF( !low_brate_mode ) + { + nbits = sns_2st_cod_fx( snsmid_fx, exp_snsmid, snsmid_q_fx, 31 - Q16, &index[1] ); + nit = add( nit, add( index[1], index[2] ) ); + } + ELSE + { + index[1] = SNS_LOW_BR_MODE; + move16(); + index[2] = 0; + move16(); + nbits = 0; + move16(); + } + + + nbt = add( 10, nbits ); + + IF( !low_brate_mode ) + { + FOR( i = 0; i < M; i++ ) + { + snsmid_q0_fx[i] = sns_q_fx[i]; + move32(); + } + nbits = sns_2st_cod_fx( snsmid_fx, exp_snsmid, snsmid_q0_fx, 31 - Q16, indxt ); + + IF( LT_16( nbits, nbt ) ) + { + nbt = nbits; + move16(); + nit = add( 2, add( indxt[0], indxt[1] ) ); + index[-1] = 1; + move16(); + + FOR( i = 0; i < M; i++ ) + { + snsmid_q_fx[i] = snsmid_q0_fx[i]; + move32(); + } + + FOR( i = 0; i < nit; i++ ) + { + index[i] = indxt[i]; + move16(); + } + } + } + index += nit; + } + return; +} +#else void sns_avq_cod( const float *sns, /* i : Input sns vectors */ const float *snsmid, /* i : Input mid-sns vectors */ @@ -286,7 +577,7 @@ void sns_avq_cod( return; } - +#endif /*------------------------------------------------------------------- * sns_avq_cod_stereo() @@ -294,6 +585,141 @@ void sns_avq_cod( * Stereo noise-shaping AVQ encoder for 2 channels *-------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED +void sns_avq_cod_stereo_fx( + const Word32 *snsl_fx, /* i : Input sns vector (left channel) */ + Word16 exp_snl, + const Word32 *snsr_fx, /* i : Input sns vector (right channel) */ + Word16 exp_snr, + const Word16 L_frame, + Word32 *snsl_q_fx, /* o : Quantized sns vector (left channel) Q16 */ + Word32 *snsr_q_fx, /* o : Quantized sns vector (right channel) Q16 */ + Word16 *indexl, /* o : Quantization indices (left channel) */ + Word16 *indexr /* o : Quantization indices (right channel) */ +) +{ + Word16 i, flag_zero; + Word32 mid_fx[M], side_fx[M], mid_q_fx[M], side_q_fx[M], ener_side_fx; + Word16 exp_ener_side = 0, exp_side_buffer[M] = { 0 }, exp_side = MIN16B; + move16(); + move16(); + move16(); + + /* Compute side */ + ener_side_fx = 0; + move16(); + FOR( i = 0; i < M; i++ ) + { + side_fx[i] = BASOP_Util_Add_Mant32Exp( snsl_fx[i], exp_snl, L_negate( snsr_fx[i] ), exp_snr, &exp_side_buffer[i] ); + move32(); + Word32 tmp = Mpy_32_32( side_fx[i], side_fx[i] ); // exp_side[i] * 2 + ener_side_fx = BASOP_Util_Add_Mant32Exp( ener_side_fx, exp_ener_side, tmp, exp_side_buffer[i] * 2, &exp_ener_side ); + } + FOR( i = 0; i < M; i++ ) + { + exp_side = s_max( exp_side, exp_side_buffer[i] ); + } + FOR( i = 0; i < M; i++ ) + { + side_fx[i] = L_shr( side_fx[i], exp_side - exp_side_buffer[i] ); + move32(); + } + + Word16 flag = BASOP_Util_Cmp_Mant32Exp( ener_side_fx, exp_ener_side, 24576, 31 - Q11 ); + IF( EQ_16( flag, -1 ) ) + { + /* MS coding */ + *indexl++ = 2; + move16(); + *indexr++ = 3; + move16(); + + /* Compute mid */ + Word16 exp_mid_buffer[M] = { 0 }; + move16(); + FOR( i = 0; i < M; i++ ) + { + mid_fx[i] = BASOP_Util_Add_Mant32Exp( snsl_fx[i], exp_snl, snsr_fx[i], exp_snr, &exp_mid_buffer[i] ); + move32(); + mid_fx[i] = L_shr( mid_fx[i], 1 ); + move32(); + } + + /* Quantize mid */ + Word16 exp_mid = 0; + move16(); + FOR( i = 0; i < M; i++ ) + { + exp_mid = s_max( exp_mid, exp_mid_buffer[i] ); + } + FOR( i = 0; i < M; i++ ) + { + mid_fx[i] = L_shr( mid_fx[i], exp_mid - exp_mid_buffer[i] ); + move32(); + } + indexl[0] = sns_1st_cod_fx( mid_fx, exp_mid, L_frame, TCX_20_CORE, mid_q_fx ); + move16(); + sns_2st_cod_fx( mid_fx, exp_mid, mid_q_fx, ( 31 - Q16 ), &indexl[1] ); + + /* Quantize side */ + indexr[0] = -1; + move16(); + FOR( i = 0; i < M; i++ ) + { + side_q_fx[i] = 0; + move32(); + } + sns_2st_cod_fx( side_fx, exp_side, side_q_fx, 31 - Q16, &indexr[1] ); + + /* Detect zero side */ + flag_zero = 1; + move16(); + FOR( i = 0; i < M; i++ ) + { + if ( side_q_fx[i] != 0 ) + { + flag_zero = 0; + move16(); + break; + } + } + if ( flag_zero ) + { + indexr[0] = -2; + move16(); + } + + /* Go back to LR */ + FOR( i = 0; i < M; i++ ) + { + Word32 a = L_shr( side_q_fx[i], 1 ); + snsl_q_fx[i] = L_add( mid_q_fx[i], a ); + move32(); + snsr_q_fx[i] = L_sub( mid_q_fx[i], a ); + move32(); + } + } + ELSE + { + /* LR coding */ + *indexl++ = 0; + move16(); + *indexr++ = 1; + move16(); + + /* Quantize left */ + indexl[0] = sns_1st_cod_fx( snsl_fx, exp_snl, L_frame, TCX_20_CORE, snsl_q_fx ); + move16(); + sns_2st_cod_fx( snsl_fx, exp_snl, snsl_q_fx, ( 31 - Q16 ), &indexl[1] ); + + /* Quantize right */ + indexr[0] = sns_1st_cod_fx( snsr_fx, exp_snr, L_frame, TCX_20_CORE, snsr_q_fx ); + move16(); + sns_2st_cod_fx( snsr_fx, exp_snr, snsr_q_fx, ( 31 - Q16 ), &indexr[1] ); + } + return; +} +#else void sns_avq_cod_stereo( const float *snsl, /* i : Input sns vector (left channel) */ const float *snsr, /* i : Input sns vector (right channel) */ @@ -378,6 +804,7 @@ void sns_avq_cod_stereo( return; } +#endif int16_t quantize_sns( float sns_in[CPE_CHANNELS][NB_DIV][M], diff --git a/lib_enc/ivas_stat_enc.h b/lib_enc/ivas_stat_enc.h index 36fa5a0c733247c6b0c01e13ad2b5f6632cb68fd..c778a30711027da8b5af5543ef6d23c699cc1e31 100644 --- a/lib_enc/ivas_stat_enc.h +++ b/lib_enc/ivas_stat_enc.h @@ -436,11 +436,12 @@ typedef struct stereo_td_enc_data_structure Word32 tdm_lt_corr_RM_fx; /* Long term right-mono correlation */ Word32 tdm_lt_corr_LM_fx; /* Long term left-mono correlation */ Word32 tdm_last_diff_lt_corr_fx; /* long term correlation difference mem */ - Word32 tdm_last_ratio_fx; /* Last TDM ratio */ - Word32 tdm_lt_rms_L_fx; /* Left channel long term rms */ - Word32 tdm_lt_rms_R_fx; /* Right channel long term rms */ - Word32 tdm_last_ener_lt_R_fx; /* Right channel long term energy */ - Word32 tdm_last_ener_lt_L_fx; /* Left channel long term energy */ + Word16 q_tdm_last_diff_lt_corr; + Word32 tdm_last_ratio_fx; /* Last TDM ratio */ + Word32 tdm_lt_rms_L_fx; /* Left channel long term rms */ + Word32 tdm_lt_rms_R_fx; /* Right channel long term rms */ + Word32 tdm_last_ener_lt_R_fx; /* Right channel long term energy */ + Word32 tdm_last_ener_lt_L_fx; /* Left channel long term energy */ Word16 tdm_last_ratio_idx; /* last TDM ratio index */ Word16 tdm_last_SM_flag; /* Flag to signal a SM encoding scheme -> better for some music item */ @@ -467,11 +468,12 @@ typedef struct stereo_td_enc_data_structure Word32 tdm_lt_corr_RM_SM_fx; /* Long term right-mono correlation in SM mode*/ Word32 tdm_lt_corr_LM_SM_fx; /* Long term left-mono correlation in SM mode*/ Word32 tdm_last_diff_lt_corr_SM_fx; /* long term correlation difference mem in SM mode*/ - Word32 tdm_last_ratio_SM_fx; /* Last TDM ratio in SM mode*/ - Word32 tdm_lt_rms_L_SM_fx; /* Left channel long term rms in SM mode*/ - Word32 tdm_lt_rms_R_SM_fx; /* Right channel long term rms in SM mode*/ - Word32 tdm_last_ener_lt_R_SM_fx; /* Right channel long term energy in SM mode*/ - Word32 tdm_last_ener_lt_L_SM_fx; /* Left channel long term energy in SM mode*/ + Word16 q_tdm_last_diff_lt_corr_SM; + Word32 tdm_last_ratio_SM_fx; /* Last TDM ratio in SM mode*/ + Word32 tdm_lt_rms_L_SM_fx; /* Left channel long term rms in SM mode*/ + Word32 tdm_lt_rms_R_SM_fx; /* Right channel long term rms in SM mode*/ + Word32 tdm_last_ener_lt_R_SM_fx; /* Right channel long term energy in SM mode*/ + Word32 tdm_last_ener_lt_L_SM_fx; /* Left channel long term energy in SM mode*/ Word16 tdm_last_ratio_idx_SM; /* last TDM ratio index in SM mode*/ Word16 tdm_last_SM_flag_noop; /* Flag to signal a SM encoding scheme -> better for some music item in SM mode*/ diff --git a/lib_enc/ivas_stereo_td_analysis.c b/lib_enc/ivas_stereo_td_analysis.c index fc2ace3e5dc99b44d23f89a0c4351f3d7f14e397..03288fd136357e26eb9abedbb1462376a1c0f2ae 100644 --- a/lib_enc/ivas_stereo_td_analysis.c +++ b/lib_enc/ivas_stereo_td_analysis.c @@ -41,17 +41,40 @@ #include "ivas_cnst.h" #include "rom_enc.h" #include "wmc_auto.h" +#ifdef IVAS_FLOAT_FIXED +#include "ivas_prot_fx.h" +#include "prot_fx.h" +#include "ivas_rom_com_fx.h" +#endif /*-------------------------------------------------------------------* * Local constants *-------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED +#define RMS_MIN_FX_Q20 ( 1572864000 ) /* 1500 in Q20 */ /* Minimum energy for ratio index*/ +#define RMS_MIN2_FX_Q21 ( 2097152000 ) /* 1000 in Q21 */ /* Minimum energy for LR encoding*/ +#define CORR_THRES_FX_Q15 ( 31130 ) /* 0.95f in Q15 */ /* Maximal open loop correlation */ +#define DT_ENER_THR_FX_Q23 ( 1677721600 ) /* 200 in Q24 */ /* Energy variation threshold */ +#endif + #define RMS_MIN 1500 /* Minimum energy for ratio index*/ #define RMS_MIN2 1000 /* Minimum energy for LR encoding*/ #define CORR_THRES 0.95f /* Maximal open loop correlation */ #define DT_ENER_THR 200 /* Energy variation threshold */ +#ifdef IVAS_FLOAT_FIXED +#define ALP_REF_FX_Q31 ( 1717986918 ) /* 0.8f in Q31 */ /* smoothing factor */ +#define BET_REF_FX_Q31 ( ONE_IN_Q31 - ALP_REF_FX_Q31 ) + +#define ALP1_FX_Q31 ( 1073741824 ) /* 0.5f in Q31 */ /* smoothing factor in case of correlation are going in different directions */ +#define BET1_FX_Q31 ( ONE_IN_Q31 - ALP1_FX_Q31 ) /* increase the update rate */ + +#define ALP2_FX_Q31 ( 429496729 ) /* 0.2f in Q31 */ /* smoothing factor in case of correlation are going in different directions in SM mode*/ +#define BET2_FX_Q31 ( ONE_IN_Q31 - ALP2_FX_Q31 ) /* increase the update rate in SM mode*/ +#endif + #define ALP_REF 0.8f /* smoothing factor */ #define BET_REF ( 1.0f - ALP_REF ) @@ -62,11 +85,25 @@ #define BET2 ( 1.0f - ALP2 ) /* increase the update rate in SM mode*/ #define RATIO_MAX 1.5f /* Maximum correlation ratio */ +#ifdef IVAS_FLOAT_FIXED +#define RATIO_MAX_FX_Q30 ( 1610612736 ) /* 0.15f in Q30 */ /* Maximum correlation ratio */ +#define RATIO_MAX_FX_Q24 ( 2516582 ) /* 0.15f in Q24 */ /* Maximum correlation ratio */ +#define RATIO_MAX_FX_Q23 ( 1258291 ) /* 0.15f in Q23 */ /* Maximum correlation ratio */ +#endif + #define LIMIT_ADAP_FAC 0.15f #define MIN_ADAP_FAC 0.1f #define M_ADAP 0.0009f #define B_ADAP 0.16f +#ifdef IVAS_FLOAT_FIXED +#define LIMIT_ADAP_FAC_FX_Q24 ( 2516582 ) /* 0.15f in Q24 */ +#define MIN_ADAP_FAC_FX_Q24 ( 1677722 ) /*0.1f in Q24*/ +#define M_ADAP_FX_Q31 ( 1932735 ) /* 0.0009f in Q31 */ +#define B_ADAP_FX_Q24 ( 2684355 ) /* 0.16f in Q24 */ +// #define B_ADAP_FX_Q31 ( 343597384 ) /* 0.16f in Q31 */ +#endif + #define PC_LIMIT 64 #define RATIO_PG_HR 0.94f #define RATIO_PG 0.92f @@ -81,29 +118,61 @@ #define IVAS_BRATE_OMASA_STEREO_SW_THR 15000 +#ifdef IVAS_FLOAT_FIXED +// #define ONE_BY_100_Q15 ( 328 ) +#define ONE_BY_100_Q31 ( 21474896 ) +#define TEN_IN_Q27 ( 1342177280 ) /* 10.0f in Q27 */ +#define TEN_IN_Q24 ( 167772160 ) /* 10.0f in Q24 */ +#endif /*-------------------------------------------------------------------* * Local function prototypes *-------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED +static Word16 stereo_tdm_ener_analysis_SM_fx( CPE_ENC_HANDLE hCPE, Encoder_State **sts, const Word16 input_frame, Word16 *tdm_SM_flag ); + +static void Get_corr_n_fx( const Word16 L[], const Word16 R[], Word32 *ic_Lm, Word16 *q_ic_Lm, Word32 *ic_Rm, Word16 *q_ic_Rm, const Word16 len, Word32 *es_em, const Word16 tdm_SM_calc_flag ); +#else static int16_t stereo_tdm_ener_analysis_SM( CPE_ENC_HANDLE hCPE, Encoder_State **sts, const int16_t input_frame, int16_t *tdm_SM_flag ); +#endif static void Get_corr_n( const float L[], const float R[], float *ic_Lm, float *ic_Rm, const int16_t len, float *es_em, const int16_t tdm_SM_calc_flag ); + +#ifdef IVAS_FLOAT_FIXED +static Word16 stereo_smooth_LR_transition_fx( Word16 *tdm_prev_stable_idx, Word16 *tdm_ratio_transition_mov_flag, Word16 tdm_last_ratio_idx, Word16 *tdm_prev_desired_idx, Word16 *tdm_ratio_transition_cnt, const Word16 tdm_SM_flag, Word16 desired_idx ); + +static Word16 limit_idx_Dwnmix_fx( const Word16 idx_in, const Word16 unclr_decision, const Word16 inst_idx, const Word16 previous_idx, const Word16 tdm_last_LRTD_PriCh_cnt, const Word16 tdm_last_LRTD_frame_cnt ); +#else static int16_t stereo_smooth_LR_transition( int16_t *tdm_prev_stable_idx, int16_t *tdm_ratio_transition_mov_flag, int16_t tdm_last_ratio_idx, int16_t *tdm_prev_desired_idx, int16_t *tdm_ratio_transition_cnt, const int16_t tdm_SM_flag, int16_t desired_idx ); static int16_t limit_idx_Dwnmix( const int16_t idx_in, const int16_t unclr_decision, const int16_t inst_idx, const int16_t previous_idx, const int16_t tdm_last_LRTD_PriCh_cnt, const int16_t tdm_last_LRTD_frame_cnt ); +#endif static int16_t limit_idx_NoDwnmix( const int16_t idx_in, const int16_t side_can_change, const float d_lt_corr_raw ); +#ifdef IVAS_FLOAT_FIXED +static void Get_LR_rms_fx( const Word16 *Left_in, const Word16 *Right_in, const Word16 input_frame, Word32 *rms_L, Word16 *q_rms_L, Word32 *rms_R, Word16 *q_rms_R ); +#else +#endif static void Get_LR_rms( const float *Left_in, const float *Right_in, const int16_t input_frame, float *rms_L, float *rms_R ); +#ifdef IVAS_FLOAT_FIXED +static Word16 Get_dt_lt_ener_fx( CPE_ENC_HANDLE hCPE, const Word16 IsSideMono, const Word16 input_frame, const Word16 tdm_last_SM_flag, const Word32 rms_L, const Word16 q_rms_L, const Word32 rms_R, const Word16 q_rms_R, Word32 *tdm_lt_rms_L, Word32 *tdm_lt_rms_R, Word32 *tdm_last_ener_lt_L, Word32 *tdm_last_ener_lt_R, Word32 *tdm_LT_es_em, Word16 *tdm_hyst_cnt, Word16 *tdm_NOOP_SM_flag_loc, Word32 *ener_R_dt, Word32 *ener_L_dt, Word32 *corr_LM, Word16 *q_corr_LM, Word32 *corr_RM, Word16 *q_corr_RM ); +#else +#endif static int16_t Get_dt_lt_ener( CPE_ENC_HANDLE hCPE, const int16_t IsSideMono, const int16_t input_frame, const int16_t tdm_last_SM_flag, const float rms_L, const float rms_R, float *tdm_lt_rms_L, float *tdm_lt_rms_R, float *tdm_last_ener_lt_L, float *tdm_last_ener_lt_R, float *tdm_LT_es_em, int16_t *tdm_hyst_cnt, int16_t *tdm_NOOP_SM_flag_loc, float *ener_R_dt, float *ener_L_dt, float *corr_LM, float *corr_RM ); static void NOOP_decision( CPE_ENC_HANDLE hCPE, const int16_t tdm_NOOP_flag_loc, const int16_t tmp_SM_flag, const float rms_L, const float rms_R, int16_t *tdm_SM_flag_loc ); +#ifdef IVAS_FLOAT_FIXED +static Word32 Comp_diff_lt_corr_fx( CPE_ENC_HANDLE hCPE, const Word16 IsSideMono, const Word32 rms_L, const Word16 q_rms_L, const Word32 rms_R, const Word16 q_rms_R, const Word32 ener_L_dt, const Word32 ener_R_dt, Word32 corr_LM, Word16 q_corr_LM, Word32 corr_RM, Word16 q_corr_RM, const Word32 tdm_lt_rms_L, const Word32 tdm_lt_rms_R, Word32 *tdm_lt_corr_LM, Word32 *tdm_lt_corr_RM, Word32 *tdm_last_diff_lt_corr, Word16 *q_tdm_last_diff_lt_corr, Word32 *inst_ratio_L_out, Word32 *diff_lt_corr, Word16 *q_d_lt_corr_raw ); +#else +#endif static float Comp_diff_lt_corr( CPE_ENC_HANDLE hCPE, const int16_t IsSideMono, const float rms_L, const float rms_R, const float ener_L_dt, const float ener_R_dt, float corr_LM, float corr_RM, const float tdm_lt_rms_L, const float tdm_lt_rms_R, float *tdm_lt_corr_LM, float *tdm_lt_corr_RM, float *tdm_last_diff_lt_corr, float *inst_ratio_L_out, float *diff_lt_corr ); + /*-------------------------------------------------------------------* * Function stereo_tdm_ener_analysis() * @@ -371,7 +440,11 @@ int16_t stereo_tdm_ener_analysis( } } +#ifdef IVAS_FLOAT_FIXED + idx = stereo_smooth_LR_transition_fx( &hStereoTD->tdm_prev_stable_idx, &hStereoTD->tdm_ratio_transition_mov_flag, hStereoTD->tdm_last_ratio_idx, &hStereoTD->tdm_prev_desired_idx, &hStereoTD->tdm_ratio_transition_cnt, tdm_SM_flag_loc, desired_idx ); +#else idx = stereo_smooth_LR_transition( &hStereoTD->tdm_prev_stable_idx, &hStereoTD->tdm_ratio_transition_mov_flag, hStereoTD->tdm_last_ratio_idx, &hStereoTD->tdm_prev_desired_idx, &hStereoTD->tdm_ratio_transition_cnt, tdm_SM_flag_loc, desired_idx ); +#endif /* Change the switching level in case of dual mono (in case the scenario still accept left right switching */ /* This logic is needed in case the content is exactly the same in the 2 channel and it is expected to get back to LRTD, to prevent the secondary channel to be completely empty */ @@ -458,7 +531,11 @@ int16_t stereo_tdm_ener_analysis( } else { +#ifdef IVAS_FLOAT_FIXED + idx = limit_idx_Dwnmix_fx( idx, ( hCPE->hStereoClassif->unclr_decision || ( sts[0]->flag_noisy_speech_snr == 1 && hCPE->hStereoClassif->xtalk_wscore > 0.1f ) ), desired_idx, hStereoTD->tdm_last_ratio_idx, hStereoTD->tdm_last_LRTD_PriCh_cnt, hStereoTD->tdm_last_LRTD_frame_cnt ); +#else idx = limit_idx_Dwnmix( idx, ( hCPE->hStereoClassif->unclr_decision || ( sts[0]->flag_noisy_speech_snr == 1 && hCPE->hStereoClassif->xtalk_wscore > 0.1f ) ), desired_idx, hStereoTD->tdm_last_ratio_idx, hStereoTD->tdm_last_LRTD_PriCh_cnt, hStereoTD->tdm_last_LRTD_frame_cnt ); +#endif } if ( abs( hStereoTD->tdm_last_ratio_idx - idx ) > LRTD_STEREO_MID_IS_PRIM ) @@ -512,7 +589,38 @@ int16_t stereo_tdm_ener_analysis( hStereoTD->tdm_hyst_cnt_SM = 0; } +#ifdef IVAS_FLOAT_FIXED + hStereoTD->tdm_lt_rms_L_SM_fx = floatToFixed_32( hStereoTD->tdm_lt_rms_L_SM, Q24 ); + hStereoTD->tdm_lt_rms_R_SM_fx = floatToFixed_32( hStereoTD->tdm_lt_rms_R_SM, Q24 ); + hStereoTD->tdm_LT_es_em_SM_fx = floatToFixed_32( hStereoTD->tdm_LT_es_em_SM, Q21 ); + sts[0]->hNoiseEst->Etot_last_fx = float_to_fix16( sts[0]->hNoiseEst->Etot_last, Q8 ); + sts[1]->hNoiseEst->Etot_last_fx = float_to_fix16( sts[1]->hNoiseEst->Etot_last, Q8 ); + + hStereoTD->q_tdm_last_diff_lt_corr_SM = Q31; + hStereoTD->tdm_last_diff_lt_corr_SM_fx = floatToFixed_32( hStereoTD->tdm_last_diff_lt_corr_SM, hStereoTD->q_tdm_last_diff_lt_corr_SM ); +#endif + +#ifdef IVAS_FLOAT_FIXED + *tdm_ratio_idx_SM = stereo_tdm_ener_analysis_SM_fx( hCPE, sts, input_frame, &tdm_NOOP_flag ); +#else *tdm_ratio_idx_SM = stereo_tdm_ener_analysis_SM( hCPE, sts, input_frame, &tdm_NOOP_flag ); +#endif + +#ifdef IVAS_FLOAT_FIXED + hStereoTD->tdm_lt_rms_L_SM = fixedToFloat_32( hStereoTD->tdm_lt_rms_L_SM_fx, Q24 ); + hStereoTD->tdm_lt_rms_R_SM = fixedToFloat_32( hStereoTD->tdm_lt_rms_R_SM_fx, Q24 ); + hStereoTD->tdm_last_ener_lt_L_SM = fixedToFloat_32( hStereoTD->tdm_last_ener_lt_L_SM_fx, Q24 ); + hStereoTD->tdm_last_ener_lt_R_SM = fixedToFloat_32( hStereoTD->tdm_last_ener_lt_R_SM_fx, Q24 ); + hStereoTD->tdm_LT_es_em_SM = fixedToFloat_32( hStereoTD->tdm_LT_es_em_SM_fx, Q21 ); + sts[0]->hNoiseEst->Etot_last = fix16_to_float( sts[0]->hNoiseEst->Etot_last_fx, Q8 ); + sts[1]->hNoiseEst->Etot_last = fix16_to_float( sts[1]->hNoiseEst->Etot_last_fx, Q8 ); + hCPE->hStereoClassif->xtalk_fv[E_diff_corrLM_corrRM] = fixedToFloat( hCPE->hStereoClassif->xtalk_fv_fx[E_diff_corrLM_corrRM], Q21 ); + hCPE->hStereoClassif->xtalk_fv[E_tdm_LT_es_em] = fixedToFloat( hCPE->hStereoClassif->xtalk_fv_fx[E_tdm_LT_es_em], Q21 ); + + hStereoTD->tdm_lt_corr_LM_SM = fixedToFloat_32( hStereoTD->tdm_lt_corr_LM_SM_fx, Q24 ); + hStereoTD->tdm_lt_corr_RM_SM = fixedToFloat_32( hStereoTD->tdm_lt_corr_RM_SM_fx, Q24 ); + hStereoTD->tdm_last_diff_lt_corr_SM = fixedToFloat_32( hStereoTD->tdm_last_diff_lt_corr_SM_fx, hStereoTD->q_tdm_last_diff_lt_corr_SM ); +#endif } else { @@ -536,6 +644,88 @@ int16_t stereo_tdm_ener_analysis( return ( idx ); } +#ifdef IVAS_FLOAT_FIXED +/*-------------------------------------------------------------------* + * Function Get_LR_rms_fx() + * + * Get current frame left and right rms values + *-------------------------------------------------------------------*/ + +static void Get_LR_rms_fx( + const Word16 *Left_in, + const Word16 *Right_in, + const Word16 input_frame, + Word32 *rms_L, + Word16 *q_rms_L, + Word32 *rms_R, + Word16 *q_rms_R ) +{ + Word32 ener_l, ener_r; + Word32 ener_l_tmp, ener_r_tmp; + Word64 ener_l_tmp_64bit, ener_r_tmp_64bit; + Word16 q_shift; + Word16 i; + Word16 exp_out_l, exp_out_r, exp_diff; + + ener_l_tmp_64bit = 0; + move64(); + ener_r_tmp_64bit = 0; + move64(); + ener_l = ONE_BY_100_Q31; + move32(); + ener_r = ONE_BY_100_Q31; + move32(); + + FOR( i = 0; i < input_frame; i++ ) + { + ener_l_tmp_64bit = W_add( ener_l_tmp_64bit, W_deposit32_l( L_mult0( Left_in[i], Left_in[i] ) ) ); // Q0 + ener_r_tmp_64bit = W_add( ener_r_tmp_64bit, W_deposit32_l( L_mult0( Right_in[i], Right_in[i] ) ) ); // Q0 + } + + q_shift = 31; + move16(); + IF( ener_l_tmp_64bit != 0 ) + { + q_shift = s_min( q_shift, W_norm( ener_l_tmp_64bit ) ); + } + IF( ener_r_tmp_64bit != 0 ) + { + q_shift = s_min( q_shift, W_norm( ener_r_tmp_64bit ) ); + } + ener_l_tmp = W_extract_l( W_shl_nosat( ener_l_tmp_64bit, sub( q_shift, 32 ) ) ); // (q_shift - 32) + ener_r_tmp = W_extract_l( W_shl_nosat( ener_r_tmp_64bit, sub( q_shift, 32 ) ) ); // (q_shift - 32) + /* perform rounding towards lower value for negative results */ + IF( ener_l_tmp < 0 ) + { + ener_l_tmp = L_add( ener_l_tmp, 1 ); + } + IF( ener_r_tmp < 0 ) + { + ener_r_tmp = L_add( ener_r_tmp, 1 ); + } + + ener_l = BASOP_Util_Add_Mant32Exp( ener_l, 0, ener_l_tmp, sub( Q31, sub( q_shift, 32 ) ), &exp_out_l ); + ener_r = BASOP_Util_Add_Mant32Exp( ener_r, 0, ener_r_tmp, sub( Q31, sub( q_shift, 32 ) ), &exp_out_r ); + + ener_l_tmp = BASOP_Util_Divide3232_Scale( ener_l, input_frame, &exp_diff ); + exp_out_l = sub( add( exp_diff, exp_out_l ), Q15 ); + ener_r_tmp = BASOP_Util_Divide3232_Scale( ener_r, input_frame, &exp_diff ); + exp_out_r = sub( add( exp_diff, exp_out_r ), Q15 ); + + *rms_L = Sqrt32( ener_l_tmp, &exp_out_l ); // Q31 - exp_out_l + move32(); + *q_rms_L = sub( Q31, exp_out_l ); + move16(); + *rms_R = Sqrt32( ener_r_tmp, &exp_out_r ); // Q31 - exp_out_r + move32(); + *q_rms_R = sub( Q31, exp_out_r ); + move16(); + + return; +} +#endif + + /*-------------------------------------------------------------------* * Function Get_LR_rms() * @@ -567,6 +757,181 @@ static void Get_LR_rms( } +#ifdef IVAS_FLOAT_FIXED +/*-------------------------------------------------------------------* + * Function Get_dt_lt_ener_fx() + * + * Compute the gain of L&R channel compared to mono + * - estimate the long term evolution of the L to Mono gain + * - estimate the long term evolution of the R to Mono gain + * - estimate the long term difference between the long term + * - evolution of the L and R to Mono gain + *-------------------------------------------------------------------*/ + +static Word16 Get_dt_lt_ener_fx( + CPE_ENC_HANDLE hCPE, + const Word16 IsSideMono, + const Word16 input_frame, + const Word16 tdm_last_SM_flag, + const Word32 rms_L, + const Word16 q_rms_L, + const Word32 rms_R, + const Word16 q_rms_R, + Word32 *tdm_lt_rms_L, + Word32 *tdm_lt_rms_R, + Word32 *tdm_last_ener_lt_L, + Word32 *tdm_last_ener_lt_R, + Word32 *tdm_LT_es_em, + Word16 *tdm_hyst_cnt, + Word16 *tdm_NOOP_SM_flag_loc, + Word32 *ener_R_dt, + Word32 *ener_L_dt, + Word32 *corr_LM, + Word16 *q_corr_LM, + Word32 *corr_RM, + Word16 *q_corr_RM ) +{ + Encoder_State **sts; + Word16 Left_in_fx[L_FRAME48k], Right_in_fx[L_FRAME48k]; + Word16 q_Left_in, q_Right_in; + Word32 es_em_fx; + Word16 tmp_SM_flag, tdm_SM_flag_loc; + Word32 L_tmp, L_tmp1; + Word16 exp_diff; + + sts = hCPE->hCoreCoder; +#if 0 + Left_in_fx = sts[0]->input_fx; /* Left channel */ + Right_in_fx = sts[1]->input_fx; /* Right channel */ +#else + /* This part has f2f conversions as sts[0]->input_fx and sts[1]->input_fx are in Q0. Precision loss is observed in later functions.*/ + q_Left_in = Q_factor_arr( sts[0]->input, input_frame ); + q_Right_in = Q_factor_arr( sts[1]->input, input_frame ); + q_Left_in = s_min( q_Left_in, q_Right_in ); + q_Left_in = sub( q_Left_in, Q1 ); + floatToFixed_arr16( sts[0]->input, Left_in_fx, q_Left_in, input_frame ); + floatToFixed_arr16( sts[1]->input, Right_in_fx, q_Left_in, input_frame ); +#endif + + tdm_SM_flag_loc = tdm_last_SM_flag; + move16(); + + test(); + IF( NE_16( hCPE->last_element_mode, IVAS_CPE_TD ) && IsSideMono == 0 ) /* last coding mode not TD and normal mono/side case, quick update of lt energy */ + { + *tdm_lt_rms_L = L_shl( Mpy_32_32( 1932735282 /* 0.9f in Q31 */, rms_L ), sub( Q24, q_rms_L ) ); // (Q31, q_rms_L) -> q_rms_L -> Q24 + move32(); + *tdm_lt_rms_R = L_shl( Mpy_32_32( 1932735282 /* 0.9f in Q31 */, rms_R ), sub( Q24, q_rms_R ) ); // (Q31, q_rms_R) -> q_rms_R -> Q24 + move32(); + L_tmp = Mpy_32_16_1( 1932735282 /* 0.9f in Q31 */, sts[0]->hNoiseEst->Etot_last_fx ); //(Q31, Q8) -> Q24 + sts[1]->hNoiseEst->Etot_last_fx = extract_h( L_tmp ); // (Q24 >> Q16) -> Q8 + sts[1]->hVAD->hangover_cnt = 0; + move16(); + } + ELSE + { + L_tmp = Mpy_32_32( 1288490188 /* 0.6f in Q31 */, *tdm_lt_rms_L ); // Q24 + L_tmp1 = Mpy_32_32( 858993459 /* 0.4f in Q31 */, rms_L ); // q_rms_L + *tdm_lt_rms_L = BASOP_Util_Add_Mant32Exp( L_tmp, Q31 - Q24, L_tmp1, sub( Q31, q_rms_L ), &exp_diff ); //(Q31 - exp_diff) + move32(); + *tdm_lt_rms_L = L_shl( *tdm_lt_rms_L, sub( Q24, sub( Q31, exp_diff ) ) ); // Q24 + move32(); + L_tmp = Mpy_32_32( 1288490188 /* 0.6f in Q31 */, *tdm_lt_rms_R ); // Q24 + L_tmp1 = Mpy_32_32( 858993459 /* 0.4f in Q31 */, rms_R ); // q_rms_L + *tdm_lt_rms_R = BASOP_Util_Add_Mant32Exp( L_tmp, Q31 - Q24, L_tmp1, sub( Q31, q_rms_R ), &exp_diff ); //(Q31 - exp_diff) + move32(); + *tdm_lt_rms_R = L_shl( *tdm_lt_rms_R, sub( Q24, sub( Q31, exp_diff ) ) ); // Q24 + move32(); + } + + /*----------------------------------------------------------------* + * Compute the 1st order energy difference difference + *----------------------------------------------------------------*/ + + *ener_R_dt = L_sub( *tdm_lt_rms_R, *tdm_last_ener_lt_R ); // Q24 + move32(); + *tdm_last_ener_lt_R = *tdm_lt_rms_R; // Q24 + move32(); + + *ener_L_dt = L_sub( *tdm_lt_rms_L, *tdm_last_ener_lt_L ); // Q24 + move32(); + *tdm_last_ener_lt_L = *tdm_lt_rms_L; // Q24 + move32(); + + /*----------------------------------------------------------------* + * Compute the gain of L&R channel compared to mono + * - estimate the long term evolution of the L to Mono gain + * - estimate the long term evolution of the R to Mono gain + * - estimate the long term difference between the long term + * - evolution of the L and R to Mono gain + *----------------------------------------------------------------*/ + + Get_corr_n_fx( Left_in_fx, Right_in_fx, corr_LM, q_corr_LM, corr_RM, q_corr_RM, input_frame, &es_em_fx, IsSideMono ); + + hCPE->hStereoClassif->xtalk_fv_fx[E_diff_corrLM_corrRM] = BASOP_Util_Add_Mant32Exp( *corr_LM, sub( Q31, *q_corr_LM ), L_negate( *corr_RM ), sub( Q31, *q_corr_RM ), &exp_diff ); + move32(); + hCPE->hStereoClassif->xtalk_fv_fx[E_diff_corrLM_corrRM] = L_shl( hCPE->hStereoClassif->xtalk_fv_fx[E_diff_corrLM_corrRM], sub( Q21, sub( Q31, exp_diff ) ) ); + move32(); + + IF( sts[0]->hVAD->hangover_cnt != 0 ) + { + *tdm_LT_es_em = Mpy_32_32( 1932735282 /* 0.9f in Q31 */, *tdm_LT_es_em ); // Q21 + move32(); + } + ELSE + { + *tdm_LT_es_em = L_add( Mpy_32_32( 1932735282 /* 0.9f in Q31 */, *tdm_LT_es_em ), Mpy_32_32( 214748365 /* 0.1f in Q31 */, es_em_fx ) ); // Q21 + move32(); + } + + hCPE->hStereoClassif->xtalk_fv_fx[E_tdm_LT_es_em] = *tdm_LT_es_em; // Q21 + move32(); + + tmp_SM_flag = 0; + move16(); + if ( LT_16( s_min( sts[0]->old_corr_fx, sts[1]->old_corr_fx ), 27853 /* 0.85f in Q15 */ ) && LT_16( s_max( sts[0]->old_corr_fx, sts[1]->old_corr_fx ), 30147 /* 0.92f in Q15 */ ) && + ( GT_32( *tdm_LT_es_em, ONE_IN_Q22 /* 2.0f in Q21 */ ) || GT_32( es_em_fx, 5242880 /* 2.5f in Q21 */ ) ) && ( LE_16( sts[0]->hVAD->hangover_cnt, 1 ) && LE_16( sts[1]->hVAD->hangover_cnt, 3 ) && sts[0]->tdm_LRTD_flag == 0 ) ) + { + tmp_SM_flag = 1; + move16(); + } + if ( IsSideMono == 0 ) + { + *tdm_NOOP_SM_flag_loc = tdm_SM_flag_loc; + move16(); + } + + IF( NE_16( tmp_SM_flag, tdm_SM_flag_loc ) ) + { + IF( GE_16( *tdm_hyst_cnt, 2 ) && EQ_16( tmp_SM_flag, 1 ) && ( GT_16( sts[0]->tdm_pc, PC_LIMIT ) || GT_16( sts[1]->tdm_pc, PC_LIMIT ) ) ) + { + tdm_hyst_cnt++; + *tdm_NOOP_SM_flag_loc = tmp_SM_flag; + move16(); + *tdm_hyst_cnt = 0; + move16(); + } + ELSE IF( GE_16( *tdm_hyst_cnt, 20 ) && tmp_SM_flag == 0 && + ( GT_16( sts[0]->tdm_pc, PC_LIMIT ) || GT_16( sts[1]->tdm_pc, PC_LIMIT ) ) && ( LE_32( *tdm_LT_es_em, ONE_IN_Q20 /* 0.5f in Q21 */ ) || LT_32( es_em_fx, -20971520 /* -10.0f in Q21 */ ) ) ) + { + tdm_hyst_cnt++; + *tdm_NOOP_SM_flag_loc = tmp_SM_flag; + move16(); + *tdm_hyst_cnt = 0; + move16(); + } + } + ELSE + { + *tdm_hyst_cnt = 0; + move16(); + } + + return tmp_SM_flag; +} +#endif + + /*-------------------------------------------------------------------* * Function Get_dt_lt_ener() * @@ -802,6 +1167,220 @@ static void NOOP_decision( } +#ifdef IVAS_FLOAT_FIXED +/*-------------------------------------------------------------------* + * Function Comp_diff_lt_corr_fx() + * + * Adjust stereo downmixing adaptation rate factor + * in function of the signal energy. + *-------------------------------------------------------------------*/ + +static Word32 Comp_diff_lt_corr_fx( + CPE_ENC_HANDLE hCPE, + const Word16 IsSideMono, + const Word32 rms_L, + const Word16 q_rms_L, + const Word32 rms_R, + const Word16 q_rms_R, + const Word32 ener_L_dt, + const Word32 ener_R_dt, + Word32 corr_LM, + Word16 q_corr_LM, + Word32 corr_RM, + Word16 q_corr_RM, + const Word32 tdm_lt_rms_L, + const Word32 tdm_lt_rms_R, + Word32 *tdm_lt_corr_LM, + Word32 *tdm_lt_corr_RM, + Word32 *tdm_last_diff_lt_corr, + Word16 *q_tdm_last_diff_lt_corr, + Word32 *inst_ratio_L_out, + Word32 *diff_lt_corr, + Word16 *q_d_lt_corr_raw ) +{ + Encoder_State **sts; + Word32 adaprate_fx; + Word32 adaprate_tmp_fx; + Word32 madaprate_fx; + Word32 d_lt_corr_raw_fx; + Word32 L_tmp, L_tmp1; + Word16 q_tmp, q_tmp1; + Word16 exp_diff; + Word32 inst_ratio_L_fx; + Word16 angle; + Word32 diff_lt_corr_LM_tmp_fx, diff_lt_corr_RM_tmp_fx; + Word16 q_diff_lt_corr_LM_tmp, q_diff_lt_corr_RM_tmp; + Word32 diff_lt_corr_tmp_fx; + Word16 q_diff_lt_corr_tmp; + Word32 d_lt_corr_fx; + Word16 q_d_lt_corr; + Word16 d_lt_corr_shift, shift, q_com; + + sts = hCPE->hCoreCoder; + + /*----------------------------------------------------------------* + * Adjust stereo downmixing adaptation rate factor + * in function of the signal energy. If signal energy is low, + * adaptation rate factor is lower. This prevent stereo image + * move on speech offset + *----------------------------------------------------------------*/ + + IF( IsSideMono == 0 && EQ_16( hCPE->hStereoClassif->lrtd_mode, 1 ) && ( GT_32( tdm_lt_rms_R, L_shl( tdm_lt_rms_L, Q1 ) ) || GT_32( tdm_lt_rms_L, L_shl( tdm_lt_rms_R, Q1 ) ) ) ) + { + adaprate_fx = L_add( Mpy_32_32( M_ADAP_FX_Q31, L_max( tdm_lt_rms_R, tdm_lt_rms_L ) ), B_ADAP_FX_Q24 ); // Q24 + } + ELSE + { + adaprate_fx = L_add( Mpy_32_32( M_ADAP_FX_Q31, L_min( tdm_lt_rms_R, tdm_lt_rms_L ) ), B_ADAP_FX_Q24 ); // Q24 + } + + adaprate_fx = check_bounds_l( adaprate_fx, MIN_ADAP_FAC_FX_Q24, ONE_IN_Q24 ); // Q24 + + /*----------------------------------------------------------------* + * In case of unvoiced content (expect when it is part of an onset), + * the adaptation rate is minimal. + *----------------------------------------------------------------*/ + + IF( GT_16( sts[0]->ini_frame, 2 ) && + ( ( LE_16( sts[0]->last_clas, VOICED_TRANSITION ) && sts[0]->hVAD->hangover_cnt == 0 ) || + ( LE_16( sts[1]->last_clas, VOICED_TRANSITION ) && sts[1]->hVAD->hangover_cnt == 0 ) ) ) + { + adaprate_fx = L_min( adaprate_fx, LIMIT_ADAP_FAC_FX_Q24 ); + } + + d_lt_corr_raw_fx = 0; + move32(); + IF( IsSideMono == 0 ) + { + if ( NE_16( hCPE->last_element_mode, IVAS_CPE_TD ) || ( ( LT_32( tdm_lt_rms_R, ONE_IN_Q24 ) || LT_32( tdm_lt_rms_L, ONE_IN_Q24 ) ) && EQ_16( hCPE->hStereoClassif->lrtd_mode, 1 ) && LT_32( L_max( tdm_lt_rms_R, tdm_lt_rms_L ), TEN_IN_Q24 ) ) ) + { + adaprate_fx = 16441672; /* 0.98f in Q24 */ /* speed up the adaptation of the long term values to the current values after coming from DFT */ + move32(); + } + adaprate_tmp_fx = L_max( adaprate_fx, 13421773 /* 0.8f in Q24 */ ); // Q24 + madaprate_fx = L_sub( ONE_IN_Q24, adaprate_tmp_fx ); /* madaprate has temporary value, will updated few lines below */ // Q24 + + L_tmp = Mpy_32_32( adaprate_tmp_fx, corr_LM ); // (Q24, q_corr_LM) -> q_corr_LM - Q7 + L_tmp1 = Mpy_32_32( madaprate_fx, *tdm_lt_corr_LM ); // (Q24, Q24) -> Q17 + L_tmp = BASOP_Util_Add_Mant32Exp( L_tmp, sub( Q31, sub( q_corr_LM, Q7 ) ), L_tmp1, Q31 - Q17, &exp_diff ); // Q31 - exp_diff + q_tmp = sub( Q31, exp_diff ); + + L_tmp = Mpy_32_32( adaprate_tmp_fx, corr_RM ); // (Q24, q_corr_RM) -> q_corr_RM - Q7 + L_tmp1 = Mpy_32_32( madaprate_fx, *tdm_lt_corr_RM ); // (Q24, Q24) -> Q17 + L_tmp1 = BASOP_Util_Add_Mant32Exp( L_tmp, sub( Q31, sub( q_corr_RM, Q7 ) ), L_tmp1, Q31 - Q17, &exp_diff ); // Q31 - exp_diff + q_tmp1 = sub( Q31, exp_diff ); + + d_lt_corr_raw_fx = BASOP_Util_Add_Mant32Exp( L_tmp, sub( Q31, q_tmp ), L_tmp1, sub( Q31, q_tmp1 ), &exp_diff ); // Q31 - exp_diff + *q_d_lt_corr_raw = sub( Q31, exp_diff ); + move16(); + q_com = s_min( *q_d_lt_corr_raw, Q30 ); + + inst_ratio_L_fx = 0; + move32(); + inst_ratio_L_fx = L_max( L_shl( d_lt_corr_raw_fx, sub( q_com, *q_d_lt_corr_raw ) ), L_negate( L_shl( RATIO_MAX_FX_Q30, sub( q_com, Q30 ) ) ) ); // q_com + inst_ratio_L_fx = L_min( inst_ratio_L_fx, L_shl( RATIO_MAX_FX_Q30, sub( q_com, Q30 ) ) ); // q_com + inst_ratio_L_fx = L_add( Mpy_32_32( 1432371593 /* 0.667f in Q31 */, inst_ratio_L_fx ), L_shl( 1, q_com ) ); // q_com + angle = extract_l( L_shl( Mpy_32_16_1( inst_ratio_L_fx, EVS_PI_FX ), sub( Q13, sub( q_com, Q2 ) ) ) ); // (q_com, Q13) -> q_com - Q2 >> Q1 -> q_com - Q3 -> Q13 + *inst_ratio_L_out = L_shl( L_shr( L_sub( ONE_IN_Q14, L_deposit_l( getCosWord16( angle ) ) ), Q1 ), Q24 - Q14 ); // Q14 << Q10 -> Q24 + } + madaprate_fx = L_sub( ONE_IN_Q24, adaprate_fx ); // Q24 + corr_RM = BASOP_Util_Add_Mant32Exp( Mpy_32_32( adaprate_fx, corr_RM ), sub( Q31, sub( q_corr_RM, Q7 ) ), Mpy_32_32( madaprate_fx, *tdm_lt_corr_RM ), Q31 - Q17, &exp_diff ); // Q31 - exp_diff + q_corr_RM = sub( Q31, exp_diff ); + corr_LM = BASOP_Util_Add_Mant32Exp( Mpy_32_32( adaprate_fx, corr_LM ), sub( Q31, sub( q_corr_LM, Q7 ) ), Mpy_32_32( madaprate_fx, *tdm_lt_corr_LM ), Q31 - Q17, &exp_diff ); // Q31 - exp_diff + q_corr_LM = sub( Q31, exp_diff ); + + L_tmp = Mpy_32_32( ALP_REF_FX_Q31, *tdm_lt_corr_LM ); // Q24 + L_tmp1 = Mpy_32_32( BET_REF_FX_Q31, corr_LM ); // q_corr_LM + diff_lt_corr_LM_tmp_fx = BASOP_Util_Add_Mant32Exp( L_tmp, sub( Q31, q_corr_LM ), L_tmp1, Q31 - Q24, &exp_diff ); + q_diff_lt_corr_LM_tmp = sub( Q31, exp_diff ); + L_tmp = Mpy_32_32( ALP_REF_FX_Q31, *tdm_lt_corr_RM ); // Q24 + L_tmp1 = Mpy_32_32( BET_REF_FX_Q31, corr_RM ); // q_corr_RM + diff_lt_corr_RM_tmp_fx = BASOP_Util_Add_Mant32Exp( L_tmp, sub( Q31, q_corr_RM ), L_tmp1, Q31 - Q24, &exp_diff ); + q_diff_lt_corr_RM_tmp = sub( Q31, exp_diff ); + diff_lt_corr_tmp_fx = BASOP_Util_Add_Mant32Exp( diff_lt_corr_LM_tmp_fx, sub( Q31, q_diff_lt_corr_LM_tmp ), L_negate( diff_lt_corr_RM_tmp_fx ), sub( Q31, q_diff_lt_corr_RM_tmp ), &exp_diff ); // (Q31 - exp_diff) + q_diff_lt_corr_tmp = sub( Q31, exp_diff ); + + d_lt_corr_fx = BASOP_Util_Add_Mant32Exp( diff_lt_corr_tmp_fx, sub( Q31, q_diff_lt_corr_tmp ), L_negate( *tdm_last_diff_lt_corr ), sub( Q31, *q_tdm_last_diff_lt_corr ), &exp_diff ); // (Q31 - exp_diff) + q_d_lt_corr = sub( Q31, exp_diff ); + IF( GT_16( q_d_lt_corr, Q31 ) ) + { + d_lt_corr_shift = sub( Q31, q_d_lt_corr ); + shift = 0; + move16(); + } + ELSE + { + d_lt_corr_shift = 0; + move16(); + shift = sub( q_d_lt_corr, Q31 ); + } + *tdm_last_diff_lt_corr = diff_lt_corr_tmp_fx; + move32(); + *q_tdm_last_diff_lt_corr = q_diff_lt_corr_tmp; + move16(); + + /*----------------------------------------------------------------* + * Correct the estimation depending of channels energies evolution + *----------------------------------------------------------------*/ + + IF( EQ_16( IsSideMono, 1 ) && + ( ( LT_32( L_shl( rms_L, sub( Q21, q_rms_L ) ), RMS_MIN2_FX_Q21 ) && + LT_32( L_shl( rms_R, sub( Q21, q_rms_R ) ), RMS_MIN2_FX_Q21 ) ) && + ( LT_32( tdm_lt_rms_L, L_shl( Mpy_32_32( 1717986918 /* 0.8f in Q31 */, rms_L ), sub( Q24, q_rms_L ) ) ) && + LT_32( tdm_lt_rms_R, L_shl( Mpy_32_32( 1717986918 /* 0.8f in Q31 */, rms_R ), sub( Q24, q_rms_R ) ) ) ) && + ( GT_32( tdm_lt_rms_L, L_shl( tdm_lt_rms_R, Q1 ) ) || + LT_32( tdm_lt_rms_L, L_shr( tdm_lt_rms_R, Q1 ) ) ) ) ) + { + L_tmp = Mpy_32_32( ALP2_FX_Q31, *tdm_lt_corr_LM ); // Q24 + L_tmp1 = Mpy_32_32( BET2_FX_Q31, corr_LM ); // q_corr_LM + L_tmp = BASOP_Util_Add_Mant32Exp( L_tmp, Q31 - Q24, L_tmp1, sub( Q31, q_corr_LM ), &exp_diff ); // (Q31 - exp_diff) + *tdm_lt_corr_LM = L_shl( L_tmp, sub( Q24, sub( Q31, exp_diff ) ) ); // Q24 + move32(); + L_tmp = Mpy_32_32( ALP2_FX_Q31, *tdm_lt_corr_RM ); // Q24 + L_tmp1 = Mpy_32_32( BET2_FX_Q31, corr_RM ); // q_corr_RM + L_tmp = BASOP_Util_Add_Mant32Exp( L_tmp, Q31 - Q24, L_tmp1, sub( Q31, q_corr_RM ), &exp_diff ); // (Q31 - exp_diff) + *tdm_lt_corr_RM = L_shl( L_tmp, sub( Q24, sub( Q31, exp_diff ) ) ); // Q24 + move32(); + + *tdm_lt_corr_LM = L_shl( Mpy_32_32( *tdm_lt_corr_LM, 1342177280 /* 2.5f in Q29 */ ), Q24 - Q22 ); // ((Q24, Q29) -> Q22 << 2) -> Q24 + move32(); + *tdm_lt_corr_RM = L_shl( Mpy_32_32( *tdm_lt_corr_RM, 1342177280 /* 2.5f in Q29 */ ), Q24 - Q22 ); // ((Q24, Q29) -> Q22 << 2) -> Q24 + move32(); + } + ELSE IF( ( !( ( GT_32( L_shr( ener_R_dt, Q1 ), DT_ENER_THR_FX_Q23 ) && LT_32( L_shr( ener_L_dt, Q1 ), DT_ENER_THR_FX_Q23 ) ) || + ( LT_32( L_shr( ener_R_dt, Q1 ), DT_ENER_THR_FX_Q23 ) && GT_32( L_shr( ener_L_dt, Q1 ), DT_ENER_THR_FX_Q23 ) ) ) /* Energy are going in the same direction */ + && ( LT_32( L_abs( L_shl( d_lt_corr_fx, d_lt_corr_shift ) ), L_shl( 665719931 /* 0.31f in Q31 */, shift ) ) /* small difference regarding the difference gain evolution */ + || GT_32( L_shr( tdm_lt_rms_L, Q24 - Q20 ), RMS_MIN2_FX_Q21 ) || GT_32( L_shr( tdm_lt_rms_R, Q24 - Q20 ), RMS_MIN2_FX_Q21 ) ) ) /* Energy of at least one of the channel is not low */ + ) + { + /* Use estimated results */ + *tdm_lt_corr_LM = L_shl( diff_lt_corr_LM_tmp_fx, sub( Q24, q_diff_lt_corr_LM_tmp ) ); + move32(); + *tdm_lt_corr_RM = L_shl( diff_lt_corr_RM_tmp_fx, sub( Q24, q_diff_lt_corr_RM_tmp ) ); + move32(); + } + ELSE + { + L_tmp = Mpy_32_32( ALP1_FX_Q31, *tdm_lt_corr_LM ); // Q24 + L_tmp1 = Mpy_32_32( BET1_FX_Q31, corr_LM ); // q_corr_LM + L_tmp = BASOP_Util_Add_Mant32Exp( L_tmp, Q31 - Q24, L_tmp1, sub( Q31, q_corr_LM ), &exp_diff ); // (Q31 - exp_diff) + *tdm_lt_corr_LM = L_shl( L_tmp, sub( Q24, sub( Q31, exp_diff ) ) ); // Q24 + move32(); + L_tmp = Mpy_32_32( ALP1_FX_Q31, *tdm_lt_corr_RM ); // Q24 + L_tmp1 = Mpy_32_32( BET1_FX_Q31, corr_RM ); // q_corr_RM + L_tmp = BASOP_Util_Add_Mant32Exp( L_tmp, Q31 - Q24, L_tmp1, sub( Q31, q_corr_RM ), &exp_diff ); // (Q31 - exp_diff) + *tdm_lt_corr_RM = L_shl( L_tmp, sub( Q24, sub( Q31, exp_diff ) ) ); // Q24 + move32(); + } + + *diff_lt_corr = L_sub( *tdm_lt_corr_LM, *tdm_lt_corr_RM ); /* update the difference */ // Q24 + move32(); + + return d_lt_corr_raw_fx; +} +#endif + + /*-------------------------------------------------------------------* * Function Comp_diff_lt_corr() * @@ -925,6 +1504,63 @@ static float Comp_diff_lt_corr( } +#ifdef IVAS_FLOAT_FIXED +/*-------------------------------------------------------------------* + * Function limit_idx_Dnwmix_fx() + * + * + *-------------------------------------------------------------------*/ + +static Word16 limit_idx_Dwnmix_fx( + const Word16 idx_in, + const Word16 unclr_decision, + const Word16 inst_idx, + const Word16 previous_idx, + const Word16 tdm_last_LRTD_PriCh_cnt, + const Word16 tdm_last_LRTD_frame_cnt ) +{ + Word16 idx; + + idx = idx_in; + move16(); + idx = check_bounds_s_fx( idx, 1, 29 ); + + IF( EQ_16( unclr_decision, 1 ) && GT_16( tdm_last_LRTD_frame_cnt, 1 ) ) + { + IF( tdm_last_LRTD_PriCh_cnt > 0 ) + { + IF( LE_16( idx, LRTD_STEREO_MID_IS_PRIM ) && LT_16( inst_idx, LRTD_STEREO_MID_IS_PRIM + 2 ) ) + { + idx = s_min( 1, idx ); + } + ELSE IF( GE_16( idx, LRTD_STEREO_MID_IS_PRIM ) && GT_16( inst_idx, LRTD_STEREO_MID_IS_PRIM - 2 ) ) + { + idx = s_max( 29, idx ); + } + ELSE IF( LT_16( inst_idx, LRTD_STEREO_MID_IS_PRIM - 4 ) ) + { + idx = s_min( 1, idx ); + } + ELSE IF( GT_16( inst_idx, LRTD_STEREO_MID_IS_PRIM + 4 ) ) + { + idx = s_max( 29, idx ); + } + ELSE + { + idx = previous_idx; + move16(); + } + } + ELSE + { + idx = previous_idx; + move16(); + } + } + + return idx; +} +#else /*-------------------------------------------------------------------* * Function limit_idx_Dnwmix() * @@ -977,6 +1613,7 @@ static int16_t limit_idx_Dwnmix( return idx; } +#endif /*-------------------------------------------------------------------* @@ -1017,6 +1654,194 @@ static int16_t limit_idx_NoDwnmix( } +#ifdef IVAS_FLOAT_FIXED +/*-------------------------------------------------------------------* + * Function stereo_tdm_ener_analysis_SM_fx() + * + * + *-------------------------------------------------------------------*/ + +static Word16 stereo_tdm_ener_analysis_SM_fx( + CPE_ENC_HANDLE hCPE, /* i : CPE encoder structure */ + Encoder_State **sts, /* i/o: Encoder static variables structure */ + const Word16 input_frame, /* i : Number of samples */ + Word16 *tdm_SM_flag /* i/o: channel combination scheme flag */ +) +{ + Word32 rms_R_fx, rms_L_fx; + Word16 q_rms_R, q_rms_L; + Word32 corr_RM_fx, corr_LM_fx; + Word16 q_corr_LM, q_corr_RM; + Word32 diff_lt_corr_fx; + Word32 ratio_L_fx; + Word32 dist_fx; + Word16 i, side_can_change; + Word16 idx, tdm_SM_flag_loc; + Word32 es_em_fx; + Word32 ener_R_dt_fx, ener_L_dt_fx; + Word16 desired_idx; + STEREO_TD_ENC_DATA_HANDLE hStereoTD; + Word16 angle; + + hStereoTD = hCPE->hStereoTD; + desired_idx = 0; + move16(); + es_em_fx = 20972; /* 0.01f in Q21 */ + move32(); + + /*----------------------------------------------------------------* + * set SM flag + *----------------------------------------------------------------*/ + + /* Simple logic to set SM flag, should be done in the frequency domain for low SM correlation signal, especially for music item such as Music_1_org_s */ + tdm_SM_flag_loc = hStereoTD->tdm_last_SM_flag_noop; + move16(); + + /*----------------------------------------------------------------* + * Compute L and R energy and Long term RMS of each channel + *----------------------------------------------------------------*/ + + Get_LR_rms_fx( sts[0]->input_fx, sts[1]->input_fx, input_frame, &rms_L_fx, &q_rms_L, &rms_R_fx, &q_rms_R ); + + /*----------------------------------------------------------------* + * Compute the 1st order energy difference difference + * Compute the gain of L&R channel compared to mono + * - estimate the long term evolution of the L to Mono gain + * - estimate the long term evolution of the R to Mono gain + * - estimate the long term difference between the long term + * - evolution of the L and R to Mono gain + *----------------------------------------------------------------*/ + + Get_dt_lt_ener_fx( hCPE, 1, input_frame, hStereoTD->tdm_last_SM_flag_noop, rms_L_fx, q_rms_L, rms_R_fx, q_rms_R, + &hStereoTD->tdm_lt_rms_L_SM_fx, &hStereoTD->tdm_lt_rms_R_SM_fx, &hStereoTD->tdm_last_ener_lt_L_SM_fx, &hStereoTD->tdm_last_ener_lt_R_SM_fx, &hStereoTD->tdm_LT_es_em_SM_fx, &hStereoTD->tdm_hyst_cnt_SM, &tdm_SM_flag_loc, + &ener_R_dt_fx, &ener_L_dt_fx, &corr_LM_fx, &q_corr_LM, &corr_RM_fx, &q_corr_RM ); + + hStereoTD->tdm_SM_reset_flag = 0; + move16(); + + /*----------------------------------------------------------------* + * Adjust stereo downmixing adaptation rate factor + * in function of the signal energy. If signal energy is low, + * adaptation rate factor is lower. This prevent stereo image + * move on speech offset + *----------------------------------------------------------------*/ + + Comp_diff_lt_corr_fx( hCPE, 1, rms_L_fx, q_rms_L, rms_R_fx, q_rms_R, ener_L_dt_fx, ener_R_dt_fx, corr_LM_fx, q_corr_LM, corr_RM_fx, q_corr_RM, hStereoTD->tdm_lt_rms_L_SM_fx, hStereoTD->tdm_lt_rms_R_SM_fx, &hStereoTD->tdm_lt_corr_LM_SM_fx, + &hStereoTD->tdm_lt_corr_RM_SM_fx, &hStereoTD->tdm_last_diff_lt_corr_SM_fx, &hStereoTD->q_tdm_last_diff_lt_corr_SM, NULL, &diff_lt_corr_fx, NULL ); + + side_can_change = 0; + move16(); + + /*----------------------------------------------------------------* + * When the energies of channels are low enough, compute the ratio + * of L and R needed to create new mono/side signals + *----------------------------------------------------------------*/ + + IF( ( LE_32( L_shl( hStereoTD->tdm_lt_rms_L_SM_fx, Q20 - Q24 ), RMS_MIN_FX_Q20 ) && LE_32( L_shl( hStereoTD->tdm_lt_rms_R_SM_fx, Q19 /* adjusted for 2 in RHS */ - Q24 ), RMS_MIN_FX_Q20 ) ) || + ( LE_32( L_shl( hStereoTD->tdm_lt_rms_R_SM_fx, Q20 - Q24 ), RMS_MIN_FX_Q20 ) && LE_32( L_shl( hStereoTD->tdm_lt_rms_L_SM_fx, Q19 /* adjusted for 2 in RHS */ - Q24 ), RMS_MIN_FX_Q20 ) ) ) + { + if ( ( LT_16( sts[0]->old_corr_fx, CORR_THRES_FX_Q15 ) && LT_16( sts[1]->old_corr_fx, CORR_THRES_FX_Q15 ) ) || + ( LE_32( L_shl( hStereoTD->tdm_lt_rms_L_SM_fx, Q21 - Q24 ), RMS_MIN2_FX_Q21 ) && LE_32( L_shl( hStereoTD->tdm_lt_rms_R_SM_fx, Q21 - Q24 ), RMS_MIN2_FX_Q21 ) ) ) + { + side_can_change = 1; + move16(); + } + } + + IF( ( LE_32( L_shl( hStereoTD->tdm_lt_rms_L_SM_fx, Q21 - Q24 ), RMS_MIN2_FX_Q21 ) && LE_32( L_shl( hStereoTD->tdm_lt_rms_R_SM_fx, Q20 /* adjusted for 2 in RHS */ - Q24 ), RMS_MIN2_FX_Q21 ) ) || + ( LE_32( L_shl( hStereoTD->tdm_lt_rms_R_SM_fx, Q21 - Q24 ), RMS_MIN2_FX_Q21 ) && LE_32( L_shl( hStereoTD->tdm_lt_rms_L_SM_fx, Q20 /* adjusted for 2 in RHS */ - Q24 ), RMS_MIN2_FX_Q21 ) ) ) + { + IF( ( ( NE_16( hStereoTD->tdm_last_SM_flag_noop, tdm_SM_flag_loc ) ) && hStereoTD->tdm_noop_cnt == 0 ) || + EQ_16( hStereoTD->tdm_noop_mov_flag, 1 ) || NE_16( hStereoTD->tdm_prev_desired_idx_SM, hStereoTD->tdm_prev_stable_idx_SM ) ) + { + hStereoTD->tdm_noop_mov_flag = 1; + move16(); + if ( hStereoTD->tdm_last_ratio_idx_SM != 0 && NE_16( hStereoTD->tdm_last_ratio_idx_SM, ( TDM_NQ - 1 ) ) ) + { + side_can_change = 1; + move16(); + } + } + } + + if ( side_can_change == 0 && EQ_16( tdm_SM_flag_loc, 1 ) && GT_32( es_em_fx, 31457280 /* 15.0f in Q21 */ ) ) + { + side_can_change = 1; + move16(); + } + + IF( side_can_change ) + { + ratio_L_fx = L_max( diff_lt_corr_fx, -RATIO_MAX_FX_Q24 ); // Q24 + ratio_L_fx = L_min( ratio_L_fx, RATIO_MAX_FX_Q24 ); // Q24 + + IF( GT_32( ratio_L_fx, RATIO_MAX_FX_Q23 ) ) + { + ratio_L_fx = L_add( Mpy_32_32( 1159641170 /* 1.08f in Q30 */, ratio_L_fx ), 3187671 /* 0.38f in Q23 */ ); // (Q30, Q24) -> Q23 + } + ELSE IF( LT_32( ratio_L_fx, -RATIO_MAX_FX_Q23 ) ) + { + ratio_L_fx = L_add( Mpy_32_32( 687194767 /* 0.64f in Q30 */, ratio_L_fx ), 10737418 /* 1.28f in Q23 */ ); // (Q30, Q24) -> Q23 + } + ELSE + { + ratio_L_fx = L_add( Mpy_32_32( 279172874 /* 0.26f in Q30 */, ratio_L_fx ), 8346665 /* 0.995f in Q23 */ ); // (Q30, Q24) -> Q23 + } + + angle = extract_l( L_shl( Mpy_32_16_1( ratio_L_fx, EVS_PI_FX ), Q13 - Q21 - Q1 ) ); // (Q23, Q13) -> Q21 >> Q1 -> Q22 -> Q13 + ratio_L_fx = L_shl( L_shr( L_sub( ONE_IN_Q14, L_deposit_l( getCosWord16( angle ) ) ), Q1 ), Q24 - Q14 ); // Q14 << Q10 -> Q24 + + dist_fx = L_abs( L_sub( ratio_L_fx, tdm_ratio_tabl_fx_Q24[0] ) ); // Q24 + + desired_idx = 0; + move16(); + FOR( i = 1; i < TDM_NQ; i++ ) + { + IF( LE_32( L_abs( L_sub( ratio_L_fx, tdm_ratio_tabl_fx_Q24[i] ) ), dist_fx ) ) + { + dist_fx = L_abs( L_sub( ratio_L_fx, tdm_ratio_tabl_fx_Q24[i] ) ); // Q24 + desired_idx = i; + move16(); + } + } + + idx = stereo_smooth_LR_transition_fx( &hStereoTD->tdm_prev_stable_idx_SM, &hStereoTD->tdm_noop_mov_flag, hStereoTD->tdm_last_ratio_idx_SM, &hStereoTD->tdm_prev_desired_idx_SM, &hStereoTD->tdm_noop_cnt, tdm_SM_flag_loc, desired_idx ); + + idx = extract_l( L_add( Mpy_32_32( 1717986918 /* 0.8f in Q31 */, idx ), Mpy_32_32( 429496729 /* 0.2f in Q31 */, hStereoTD->tdm_last_ratio_idx_SM ) ) ); // (Q31, Q0) -> Q0 + + ratio_L_fx = tdm_ratio_tabl_fx_Q24[idx]; + move32(); + } + else + { + ratio_L_fx = hStereoTD->tdm_last_ratio_SM_fx; + move32(); + idx = hStereoTD->tdm_last_ratio_idx_SM; + move16(); + } + + IF( ( EQ_16( hStereoTD->tdm_noop_mov_flag, 1 ) && GE_16( hStereoTD->tdm_noop_cnt, 31 ) ) || ( ( EQ_16( hStereoTD->tdm_last_SM_flag_noop, tdm_SM_flag_loc ) ) && ( EQ_16( idx, hStereoTD->tdm_prev_stable_idx_SM ) ) ) ) + { + hStereoTD->tdm_noop_cnt = 0; + move16(); + hStereoTD->tdm_noop_mov_flag = 0; + move16(); + } + + if ( hStereoTD->tdm_noop_mov_flag == 0 || tdm_SM_flag_loc == 0 ) + { + hStereoTD->tdm_prev_stable_idx_SM = idx; + move16(); + } + + hStereoTD->tdm_last_SM_flag_noop = tdm_SM_flag_loc; + move16(); + *tdm_SM_flag = tdm_SM_flag_loc; + move16(); + + return ( idx ); +} +#else /*-------------------------------------------------------------------* * Function stereo_tdm_ener_analysis_SM() * @@ -1172,6 +1997,7 @@ static int16_t stereo_tdm_ener_analysis_SM( return ( idx ); } +#endif /*-------------------------------------------------------------------* @@ -1328,6 +2154,112 @@ void tdm_ol_pitch_comparison( } +#ifdef IVAS_FLOAT_FIXED +/*-------------------------------------------------------------------* + * Function Get_corr_n_fx() + * + * + *-------------------------------------------------------------------*/ + +static void Get_corr_n_fx( + const Word16 L[], /* i : Left signal */ + const Word16 R[], /* i : Right signal */ + Word32 *ic_Lm, /* o : Left signal */ + Word16 *q_ic_Lm, /* o : Q factor of Left signal */ + Word32 *ic_Rm, /* o : Right signal */ + Word16 *q_ic_Rm, /* o : Q factor of Right signal */ + const Word16 len, /* i : segment length */ + Word32 *es_em, /* o : return the difference between the side and mono energy */ + const Word16 tdm_SM_calc_flag /* i : Flag that indicates that it is for SM mode */ +) +{ + Word32 corrL, corrR, ener; + Word16 mono_i; + Word16 i; + Word32 ener_side; + Word16 side_i; + Word16 exp_diff; + Word32 L_tmp; + Word16 guard_bits; + + corrL = 0; + move32(); + corrR = 0; + move32(); + ener = EPSILON_FX; + move32(); + ener_side = EPSILON_FX; + move32(); + guard_bits = find_guarded_bits_fx( len ); + + /*----------------------------------------------------------------* + * Find the normalized correlation between: left/mono and right/mono based + *----------------------------------------------------------------*/ + + IF( tdm_SM_calc_flag ) + { + FOR( i = 0; i < len; i++ ) + { + mono_i = sub( shr( L[i], Q1 ), shr( R[i], Q1 ) ); // q_in + corrL = L_add( corrL, L_shr( L_mult0( abs_s( L[i] ), abs_s( mono_i ) ), guard_bits ) ); // (q_in + q_in - guard_bits) + corrR = L_add( corrR, L_shr( L_mult0( abs_s( R[i] ), abs_s( mono_i ) ), guard_bits ) ); // (q_in + q_in - guard_bits) + ener = L_add( ener, L_shr( L_mult0( mono_i, mono_i ), guard_bits ) ); // (q_in + q_in - guard_bits) + side_i = add( shr( L[i], Q1 ), shr( R[i], Q1 ) ); // q_in + ener_side = L_add( ener_side, L_shr( L_mult0( side_i, side_i ), guard_bits ) ); // (q_in + q_in - guard_bits) + } + } + ELSE + { + FOR( i = 0; i < len; i++ ) + { + mono_i = add( shr( L[i], Q1 ), shr( R[i], Q1 ) ); // q_in + corrL = L_add( corrL, L_shr( L_mult0( L[i], mono_i ), guard_bits ) ); // (q_in + q_in - guard_bits) + corrR = L_add( corrR, L_shr( L_mult0( R[i], mono_i ), guard_bits ) ); // (q_in + q_in - guard_bits) + ener = L_add( ener, L_shr( L_mult0( mono_i, mono_i ), guard_bits ) ); // (q_in + q_in - guard_bits) + side_i = sub( shr( L[i], Q1 ), shr( R[i], Q1 ) ); // q_in + ener_side = L_add( ener_side, L_shr( L_mult0( side_i, side_i ), guard_bits ) ); // (q_in + q_in - guard_bits) + } + } + + *ic_Lm = BASOP_Util_Divide3232_Scale_cadence( corrL, ener, &exp_diff ); // (Q31 - exp_diff) + move32(); + IF( *ic_Lm == 0 ) + { + *q_ic_Lm = Q31; + move16(); + } + ELSE + { + *q_ic_Lm = sub( Q31, exp_diff ); + move16(); + } + *ic_Rm = BASOP_Util_Divide3232_Scale_cadence( corrR, ener, &exp_diff ); // (Q31 - exp_diff) + move16(); + IF( *ic_Rm == 0 ) + { + *q_ic_Rm = Q31; + move16(); + } + ELSE + { + *q_ic_Rm = sub( Q31, exp_diff ); + move16(); + } + + /* *es_em = 10 * ( log10f( sqrtf( ener_side / len ) ) - log10f( sqrtf( ener / len ) ) ); + is simplified to + *es_em = 10 * ( log10f( sqrtf( ener_side / ener ) ) ); */ + L_tmp = BASOP_Util_Divide3232_Scale_cadence( ener_side, ener, &exp_diff ); // (Q31 - exp_diff) + L_tmp = Sqrt32( L_tmp, &exp_diff ); + L_tmp = BASOP_Util_Log2( L_tmp ); + *es_em = Mpy_32_32( Mpy_32_32( L_add( L_tmp, L_shl( exp_diff, Q25 ) ), LOG10_2_Q31 ), TEN_IN_Q27 ); // (Q25, Q27) -> Q21 + move32(); + + return; +} +#endif + + /*-------------------------------------------------------------------* * Function Get_corr_n() * @@ -1391,6 +2323,77 @@ static void Get_corr_n( } +#ifdef IVAS_FLOAT_FIXED +/*-------------------------------------------------------------------* + * Function stereo_smooth_LR_transition_fx() + * + *-------------------------------------------------------------------*/ + +/*! r: smoothed position */ +static Word16 stereo_smooth_LR_transition_fx( + Word16 *tdm_prev_stable_idx, /* i/o: Previous Transmitted ratio index */ + Word16 *tdm_ratio_transition_mov_flag, /* i/o: Flag that indicates that L-R energy is changing */ + Word16 tdm_last_ratio_idx, /* i : last TDM ratio index */ + Word16 *tdm_prev_desired_idx, /* i/o: Previous Transmitted ratio index */ + Word16 *tdm_ratio_transition_cnt, /* i/o: Counter */ + const Word16 tdm_SM_flag, /* i : channel combination scheme flag for current frame */ + Word16 desired_idx /* i : desired final position */ +) +{ + Word16 idx; + + if ( EQ_16( tdm_SM_flag, 1 ) ) + { + desired_idx = 15; + move16(); + } + + if ( NE_16( desired_idx, *tdm_prev_stable_idx ) ) + { + *tdm_ratio_transition_mov_flag = 1; + move16(); + } + + IF( EQ_16( *tdm_ratio_transition_mov_flag, 1 ) ) + { + IF( NE_16( desired_idx, *tdm_prev_desired_idx ) ) + { + *tdm_prev_stable_idx = tdm_last_ratio_idx; + move16(); + *tdm_ratio_transition_cnt = 0; + move16(); + } + + *tdm_ratio_transition_cnt = add( *tdm_ratio_transition_cnt, 4 ); + move16(); + IF( LT_16( desired_idx, sub( *tdm_prev_stable_idx, 2 ) ) ) + { + idx = sub( *tdm_prev_stable_idx, *tdm_ratio_transition_cnt ); + idx = s_max( desired_idx, idx ); + } + ELSE IF( GT_16( desired_idx, add( *tdm_prev_stable_idx, 2 ) ) ) + { + idx = add( *tdm_prev_stable_idx, *tdm_ratio_transition_cnt ); + idx = s_min( desired_idx, idx ); + } + ELSE + { + idx = desired_idx; + move16(); + } + } + ELSE + { + idx = desired_idx; + move16(); + } + + *tdm_prev_desired_idx = desired_idx; + move16(); + + return idx; +} +#else /*-------------------------------------------------------------------* * Function stereo_smooth_LR_transition() * @@ -1452,3 +2455,4 @@ static int16_t stereo_smooth_LR_transition( return idx; } +#endif diff --git a/lib_enc/ivas_stereo_td_enc.c b/lib_enc/ivas_stereo_td_enc.c index 2dc3884cc5bf6bbfd977804318f8e6d7decaf91a..ce1a4ff8fece90c83ac9f45e1d047471f246f231 100644 --- a/lib_enc/ivas_stereo_td_enc.c +++ b/lib_enc/ivas_stereo_td_enc.c @@ -142,6 +142,7 @@ void stereo_td_init_enc_fx( hStereoTD->tdm_lt_rms_L_fx = 671088640; // Q24 hStereoTD->tdm_lt_rms_R_fx = 671088640; // Q24 hStereoTD->tdm_last_diff_lt_corr_fx = 0; + hStereoTD->q_tdm_last_diff_lt_corr = Q31; hStereoTD->tdm_last_ener_lt_R_fx = 0; hStereoTD->tdm_last_ener_lt_L_fx = 0; @@ -165,6 +166,7 @@ void stereo_td_init_enc_fx( hStereoTD->tdm_lt_rms_L_SM_fx = 671088640; // Q24 hStereoTD->tdm_lt_rms_R_SM_fx = 671088640; // Q24 hStereoTD->tdm_last_diff_lt_corr_SM_fx = 0; + hStereoTD->q_tdm_last_diff_lt_corr_SM = Q31; hStereoTD->tdm_last_ener_lt_R_SM_fx = 0; hStereoTD->tdm_last_ener_lt_L_SM_fx = 0; hStereoTD->tdm_noop_mov_flag = 0; diff --git a/lib_enc/ivas_tcx_core_enc.c b/lib_enc/ivas_tcx_core_enc.c index 836abd67d692b4ef6d2f48dcb2d0c368a1027049..76ca272563883c67527e209332787b1bbea15eb1 100644 --- a/lib_enc/ivas_tcx_core_enc.c +++ b/lib_enc/ivas_tcx_core_enc.c @@ -40,6 +40,10 @@ #include "basop_proto_func.h" #include "wmc_auto.h" #include "ivas_prot.h" +#ifdef IVAS_FLOAT_FIXED +#include "prot_fx.h" +#include "prot_fx_enc.h" +#endif /*-------------------------------------------------------------------* * stereo_tcx_init_enc() @@ -47,6 +51,104 @@ * Initialize stereo TCX encoder *-------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED +void stereo_tcx_init_enc_fx( + Encoder_State *st /* i/o: encoder state structure */ +) +{ + Word16 prev_IsTNSAllowed; + Word32 total_brate; + assert( st->core_brate != SID_2k40 && st->core_brate != FRAME_NO_DATA ); + + /* Get the raw coder type from signal analysis*/ + st->coder_type = st->coder_type_raw; + move16(); + IF( !st->localVAD ) + { + st->coder_type = INACTIVE; + move16(); + } + ELSE IF( GT_16( st->coder_type, GENERIC ) ) + { + st->coder_type = GENERIC; + move16(); + } + + if ( st->tcxonly ) + { + st->coder_type = GENERIC; + move16(); + } + + st->hTcxCfg->coder_type = st->coder_type; + move16(); + test(); + test(); + IF( !st->tcxonly && !st->localVAD && EQ_16( st->hTcxCfg->coder_type, GENERIC ) ) + { + st->hTcxCfg->coder_type = UNVOICED; + move16(); + } + + /*sampling rate*/ + total_brate = L_mult0( st->bits_frame_nominal, FRAMES_PER_SEC ); + st->sr_core = getCoreSamplerateMode2( st->element_mode, total_brate, st->bwidth, st->flag_ACELP16k, st->rf_mode, st->is_ism_format ); + move32(); + st->fscale = sr2fscale_fx( st->sr_core ); + move16(); + + /*frame size*/ + st->L_frame = extract_l( Mpy_32_32( st->sr_core, ONE_BY_FRAMES_PER_SEC_Q31 ) ); + move16(); + st->hTcxEnc->L_frameTCX = extract_l( Mpy_32_32( st->input_Fs, ONE_BY_FRAMES_PER_SEC_Q31 ) ); + move16(); + + test(); + test(); + test(); + test(); + IF( ( EQ_16( st->L_frame, L_FRAME16k ) && LE_32( total_brate, MAX_ACELP_BRATE ) ) || ( st->tcxonly && ( EQ_32( st->sr_core, INT_FS_16k ) || EQ_32( st->sr_core, INT_FS_16k ) ) ) ) + { + st->nb_subfr = NB_SUBFR16k; + move16(); + } + ELSE + { + st->nb_subfr = NB_SUBFR; + move16(); + } + + /*TCX tools*/ + st->hTcxCfg->ctx_hm = getCtxHm( st->element_mode, total_brate, st->rf_mode ); + move16(); + st->hTcxCfg->resq = getResq( total_brate ); + move16(); + st->hTcxEnc->tcx_lpc_shaped_ari = getTcxLpcShapedAri( total_brate, st->rf_mode, st->element_mode ); + move16(); + st->igf = getIgfPresent_fx( st->element_mode, total_brate, st->bwidth, st->rf_mode ); + move16(); + prev_IsTNSAllowed = st->hTcxCfg->fIsTNSAllowed; + move16(); + IF( NE_16( st->element_mode, EVS_MONO ) ) + { + st->hTcxCfg->fIsTNSAllowed = getTnsAllowed( total_brate, st->igf, st->element_mode ); + move16(); + } + test(); + test(); + IF( !prev_IsTNSAllowed && st->hTcxCfg->fIsTNSAllowed && EQ_16( st->element_mode, IVAS_CPE_DFT ) ) /* may happen in unified stereo when switching stereo technologies */ + { + InitTnsConfigs( st->bwidth, st->hTcxCfg->tcx_coded_lines, st->hTcxCfg->tnsConfig, st->hIGFEnc->infoStopFrequency, total_brate, st->element_mode, 0 ); + + SetAllowTnsOnWhite( st->hTcxCfg->tnsConfig, 0 ); + } + st->core_brate = st->total_brate; + move32(); + + return; +} +#endif + void stereo_tcx_init_enc( Encoder_State *st /* i/o: encoder state structure */ ) @@ -133,6 +235,129 @@ void stereo_tcx_core_enc( const int16_t vad_hover_flag /* i : VAD hangover flag */ ) { +#ifdef IVAS_FLOAT_FIXED + TCX_ENC_HANDLE hTcxEnc; + Word16 i, n; + + /*size and windowing*/ + const float *p_new_samples; + Word16 n_subframes; + Word16 last_core_orig; + + /*Bits*/ + Word16 nbits_start, total_nbbits, nbits_header; + Word16 target_bits[2], bitsAvailable; + Word16 nbits_lpc[2]; + Word16 tnsSize[2]; /* number of tns parameters put into prm */ + Word16 tnsBits[2]; /* number of tns bits in the frame */ + Word16 ltpBits; + + /*Parameters*/ + Word16 param_lpc[NPRM_LPC_NEW]; + Word16 param_core[2 * NPRM_DIV]; + Word16 bits_param_lpc[10], no_param_lpc; + + /*LPC*/ + float lsf_q[M], lsp_q[M], lsp[M], lsf[M]; + float lspmid_q[M]; + float A_q[M + 1]; + float gainlpc[2][FDNS_NPTS]; + float lsp_tcx_q[M], lsf_tcx_q[M]; + int16_t tcx_lpc_cdk; + Word16 A_q_ind[M + 1]; /*for LPC-based AC*/ + Word16 lspq_ind[M]; /*for LPC-based AC*/ + + /*TCX-LTP*/ + Word16 T_op[3]; + + /*HM*/ + Word16 indexBuffer[2 * ( ( N_MAX / 2 ) + 1 )]; + + CONTEXT_HM_CONFIG hm_cfg[2]; + + /* bitstream */ + BSTR_ENC_HANDLE hBstr = st->hBstr; + + + push_wmops( "stereo_tcx_core_enc" ); + + /*Sanity check*/ + assert( st->mdct_sw == MODE1 && "MDCT switching should be in TCX MODE 1\n" ); + assert( st->rf_mode == 0 && "Channel aware not supported! " ); + + no_param_lpc = 0; + move16(); + n_subframes = 1; + move16(); + + hTcxEnc = st->hTcxEnc; + + /*--------------------------------------------------------------* + * Configuration of TCX + *---------------------------------------------------------------*/ + + stereo_tcx_init_enc_fx( st ); + + /*--------------------------------------------------------------* + * Initialization + *---------------------------------------------------------------*/ + + /* Subtract the bits of common header */ + st->bits_frame_core = extract_l( L_sub( Mpy_32_32( st->total_brate, ONE_BY_FRAMES_PER_SEC_Q31 ), hBstr->nb_bits_tot ) ); + + /*Get Bits of TCX header*/ + nbits_header = 3; /* Coder types (2) + last_core for bfi (1) */ + move16(); + + IF( st->tcxonly ) + { + /* TCX20/10 flag */ + nbits_header = add( nbits_header, 1 ); + } + + /* bits for TCX overlap mode (1 bit: full, 2 bits: half or no overlap) */ + IF( EQ_16( st->hTcxCfg->tcx_curr_overlap_mode, HALF_OVERLAP ) || EQ_16( st->hTcxCfg->tcx_curr_overlap_mode, MIN_OVERLAP ) ) + { + nbits_header = add( nbits_header, 2 ); + } + ELSE + { + nbits_header = add( nbits_header, 1 ); + } + + hm_cfg[0].indexBuffer = &indexBuffer[0]; + hm_cfg[1].indexBuffer = &indexBuffer[N_MAX / 2 + 1]; + + set16_fx( tnsSize, 0, 2 ); + set16_fx( tnsBits, 0, 2 ); + set16_fx( nbits_lpc, 0, 2 ); + ltpBits = 0; + move16(); + + FOR( i = 0; i < 3; i++ ) + { + T_op[i] = st->pitch[i]; + move16(); + + /* check minimum pitch for quantization */ + IF( LT_16( T_op[i], PIT_MIN_SHORTER ) ) + { + T_op[i] = shl( T_op[i], 1 ); + } + + /* convert pitch values to core sampling-rate */ + IF( NE_16( st->L_frame, L_FRAME ) ) + { + Word16 s; + Word16 fac = BASOP_Util_Divide1616_Scale( st->L_frame, L_FRAME, &s ); // exp: s + Word32 mul = L_mult0( T_op[i], fac ); // exp: 15 + s + 1 = 16 + s + Word32 half = L_shr( ONE_IN_Q14 /*0.5 in Q15*/, s ); // exp: 16 + s + Word32 sum = L_add( mul, half ); // exp: 16 + s + T_op[i] = extract_l( L_shr( sum, sub( 15, s ) ) ); // exp: 31 (Q0) + // T_op[i] = (int16_t)(T_op[i] * (float)st->L_frame / (float)L_FRAME + 0.5f); + } + } +#else TCX_ENC_HANDLE hTcxEnc; int16_t i, n; @@ -169,6 +394,7 @@ void stereo_tcx_core_enc( /*HM*/ int16_t indexBuffer[2 * ( ( N_MAX / 2 ) + 1 )]; + CONTEXT_HM_CONFIG hm_cfg[2]; /* bitstream */ @@ -235,6 +461,7 @@ void stereo_tcx_core_enc( T_op[i] = (int16_t) ( T_op[i] * (float) st->L_frame / (float) L_FRAME + 0.5f ); } } +#endif if ( st->L_frame == L_FRAME ) { @@ -327,7 +554,11 @@ void stereo_tcx_core_enc( /* Get the envelope */ if ( st->enableTcxLpc ) { +#ifdef IVAS_FLOAT_FIXED + tcx_lpc_cdk = tcxlpc_get_cdk( st->hTcxCfg->coder_type ); +#else tcx_lpc_cdk = tcxlpc_get_cdk_float( st->hTcxCfg->coder_type ); +#endif /* Get the envelope corresponding to the current frame */ E_LPC_int_lpc_tcx_float( st->lspold_enc, lsp_new, A_q ); diff --git a/lib_enc/prot_fx_enc.h b/lib_enc/prot_fx_enc.h index 37b8eb340a9ad5a3d902e127e50e911e4ed99e25..1e9121daacebd20184c1d06971512eb749bb832a 100644 --- a/lib_enc/prot_fx_enc.h +++ b/lib_enc/prot_fx_enc.h @@ -2116,6 +2116,11 @@ void qlpc_avq_fx( const Word32 sr_core /* i : internal sampling rate */ ); +/* ivas_tcx_core_enc.c */ +void stereo_tcx_init_enc_fx( + Encoder_State *st /* i/o: encoder state structure */ +); + /* IGFEnc.c */ void IGFEncApplyMono_fx( const IGF_ENC_INSTANCE_HANDLE hInstance, /**< in: | instance handle of IGF Encoder */ const Word16 igfGridIdx, /**< in: Q0 | IGF grid index */