From caeed54ea4b364b71c93671885e547b85e8401c8 Mon Sep 17 00:00:00 2001 From: Sandesh Venkatesh Date: Tue, 6 Feb 2024 09:48:47 +0530 Subject: [PATCH] Functions in ivas_out_setup_conversion converted to fixed point --- lib_com/ivas_prot_fx.h | 36 + lib_dec/ivas_init_dec.c | 15 +- lib_dec/ivas_jbm_dec.c | 189 +++++ lib_dec/ivas_mc_param_dec.c | 50 ++ lib_dec/ivas_mct_dec.c | 49 ++ lib_dec/ivas_out_setup_conversion.c | 1120 ++++++++++++++++++++++++++- lib_dec/ivas_stereo_mdct_core_dec.c | 41 + lib_rend/ivas_rom_rend.c | 349 +++++++++ lib_rend/ivas_rom_rend.h | 32 +- lib_rend/ivas_stat_rend.h | 18 + 10 files changed, 1873 insertions(+), 26 deletions(-) diff --git a/lib_com/ivas_prot_fx.h b/lib_com/ivas_prot_fx.h index 981f5f055..efdbf571d 100644 --- a/lib_com/ivas_prot_fx.h +++ b/lib_com/ivas_prot_fx.h @@ -859,6 +859,7 @@ void stereo_decoder_tcx_fx( const Word16 tmp_plc_upmix, /* i : indicates temp upmix for PLC decision */ Word16 *q_x_ch2, Word16 *q_x_ch1 ); + void v_multc_acc_32_16( const Word32 x[], /* i : Input vector */ const Word16 c, /* i : Constant */ @@ -884,4 +885,39 @@ void ivas_mono_downmix_render_passive_fx( const Word16 output_frame /* i : output frame length */ ); +void ivas_ls_setup_conversion_fx( + Decoder_Struct *st_ivas, /* i : IVAS decoder structure */ + const Word16 input_chans, /* i : number of input channels to the renderer */ + const Word16 output_frame, /* i : frame length */ + Word32 *input[], /* i : LS input/output synthesis signal */ + Word32 *output[] /* i/o: LS input/output synthesis signal */ +); + +ivas_error ivas_ls_setup_conversion_open_fx( + Decoder_Struct *st_ivas /* i/o: IVAS decoder structure */ +); + +void ivas_ls_setup_conversion_close_fx( + LSSETUP_CONVERSION_HANDLE *hLsSetUpConversion /* i/o: LS converter handle */ +); + +void ivas_ls_setup_conversion_process_mdct_fx( + Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */ + Word32 *output[] /* i/o: output synthesis signal */ +); + +void ivas_lssetupconversion_process_param_mc_fx( + Decoder_Struct *st_ivas, /* i/o: LS setup conversion renderer handle */ + const Word16 num_timeslots, + Word32 Cldfb_RealBuffer_InOut[MAX_CICP_CHANNELS][PARAM_MC_MAX_NSLOTS_IN_SUBFRAME][CLDFB_NO_CHANNELS_MAX], /* i/o: LS signals */ + Word32 Cldfb_ImagBuffer_InOut[MAX_CICP_CHANNELS][PARAM_MC_MAX_NSLOTS_IN_SUBFRAME][CLDFB_NO_CHANNELS_MAX], /* i/o: LS signals */ + Word16 channel_active[MAX_CICP_CHANNELS] /* i : bitmap indicating which output channels are active */ +); + +void convert_coeffs_to_higher_res_fx( + const Word32 *in1, /* i : first subframe input */ + const Word32 *in2, /* i : second subframe input */ + Word32 *out, /* o : converted output */ + const Word16 len /* i : length of subframes */ +); #endif diff --git a/lib_dec/ivas_init_dec.c b/lib_dec/ivas_init_dec.c index b71b3001e..690ff014d 100644 --- a/lib_dec/ivas_init_dec.c +++ b/lib_dec/ivas_init_dec.c @@ -1753,12 +1753,19 @@ ivas_error ivas_init_decoder( return error; } } - ELSE IF ( st_ivas->renderer_type == RENDERER_MC ) + ELSE IF( st_ivas->renderer_type == RENDERER_MC ) { - IF ( ( error = ivas_ls_setup_conversion_open( st_ivas ) ) != IVAS_ERR_OK ) +#ifdef IVAS_FLOAT_FIXED + IF( ( error = ivas_ls_setup_conversion_open_fx( st_ivas ) ) != IVAS_ERR_OK ) + { + return error; + } +#else + IF( ( error = ivas_ls_setup_conversion_open( st_ivas ) ) != IVAS_ERR_OK ) { return error; } +#endif } ELSE IF ( st_ivas->renderer_type == RENDERER_MONO_DOWNMIX ) { @@ -2439,7 +2446,11 @@ void ivas_destroy_dec( ivas_reverb_close( &st_ivas->hReverb ); /* LS config converter handle */ +#ifdef IVAS_FLOAT_FIXED + ivas_ls_setup_conversion_close_fx( &st_ivas->hLsSetUpConversion ); +#else ivas_ls_setup_conversion_close( &st_ivas->hLsSetUpConversion ); +#endif /* Custom LS configuration handle */ IF ( st_ivas->hLsSetupCustom != NULL ) diff --git a/lib_dec/ivas_jbm_dec.c b/lib_dec/ivas_jbm_dec.c index 9e7e234db..662aa3e58 100644 --- a/lib_dec/ivas_jbm_dec.c +++ b/lib_dec/ivas_jbm_dec.c @@ -49,6 +49,8 @@ #include "prot_fx1.h" #include "prot_fx2.h" +#include "debug.h" + /*-----------------------------------------------------------------------* * Local function prototypes *-----------------------------------------------------------------------*/ @@ -168,7 +170,31 @@ ivas_error ivas_jbm_dec_tc( if ( st_ivas->renderer_type == RENDERER_MC && st_ivas->hDecoderConfig->nchan_out == 1 ) { +#ifdef IVAS_FLOAT_FIXED + Word16 i, j, q = Q16; + Word32 *p_output_fx[12]; + q = q - find_guarded_bits_fx( st_ivas->nchan_transport ); + FOR( i = 0; i < max(st_ivas->hDecoderConfig->nchan_out, st_ivas->nchan_transport); ++i ) + { + p_output_fx[i] = malloc( L_FRAME48k * sizeof( Word32 ) ); + floatToFixed_arrL( p_output[i], p_output_fx[i], q, output_frame ); + } + FOR( i = 0; i < st_ivas->hDecoderConfig->nchan_out; i++ ) + { + FOR( j = 0; j < st_ivas->nchan_transport; j++ ) + { + st_ivas->hLsSetUpConversion->dmxMtx_fx[j][i] = float_to_fix( st_ivas->hLsSetUpConversion->dmxMtx[j][i], Q30 ); + } + } + ivas_ls_setup_conversion_fx( st_ivas, st_ivas->nchan_transport, output_frame, p_output_fx, p_output_fx); + FOR( i = 0; i < max(st_ivas->hDecoderConfig->nchan_out, st_ivas->nchan_transport); ++i ) + { + fixedToFloat_arrL( p_output_fx[i], p_output[i], q, output_frame ); + free( p_output_fx[i] ); + } +#else ivas_ls_setup_conversion( st_ivas, st_ivas->nchan_transport, output_frame, p_output, p_output ); +#endif } } else if ( st_ivas->ivas_format == ISM_FORMAT ) @@ -1105,7 +1131,31 @@ ivas_error ivas_jbm_dec_tc( { if ( st_ivas->renderer_type == RENDERER_MC ) { +#ifdef IVAS_FLOAT_FIXED + Word16 i, j, q = Q16; + Word32 *p_output_fx[12]; + q = q - find_guarded_bits_fx( st_ivas->nchan_transport ); + FOR( i = 0; i < max(st_ivas->hDecoderConfig->nchan_out, st_ivas->nchan_transport); ++i ) + { + p_output_fx[i] = malloc( L_FRAME48k * sizeof( Word32 ) ); + floatToFixed_arrL( p_output[i], p_output_fx[i], q, output_frame ); + } + FOR( i = 0; i < st_ivas->hDecoderConfig->nchan_out; i++ ) + { + FOR( j = 0; j < st_ivas->nchan_transport; j++ ) + { + st_ivas->hLsSetUpConversion->dmxMtx_fx[j][i] = float_to_fix( st_ivas->hLsSetUpConversion->dmxMtx[j][i], Q30 ); + } + } + ivas_ls_setup_conversion_fx( st_ivas, st_ivas->nchan_transport, output_frame, p_output_fx, p_output_fx ); + FOR( i = 0; i < max(st_ivas->hDecoderConfig->nchan_out, st_ivas->nchan_transport); ++i ) + { + fixedToFloat_arrL( p_output_fx[i], p_output[i], q, output_frame ); + free( p_output_fx[i] ); + } +#else ivas_ls_setup_conversion( st_ivas, st_ivas->nchan_transport, output_frame, p_output, p_output ); +#endif } else if ( st_ivas->renderer_type == RENDERER_SBA_LINEAR_ENC ) { @@ -1159,7 +1209,32 @@ ivas_error ivas_jbm_dec_tc( if ( output_config == IVAS_AUDIO_CONFIG_MONO || output_config == IVAS_AUDIO_CONFIG_STEREO ) { +#ifdef IVAS_FLOAT_FIXED + Word16 i, j, q = Q16, nchan_transport; + Word32 *p_output_fx[12]; + nchan_transport = audioCfg2channels( IVAS_AUDIO_CONFIG_5_1_2 ); + q = q - find_guarded_bits_fx( nchan_transport ); + FOR( i = 0; i < max(st_ivas->hDecoderConfig->nchan_out, nchan_transport); ++i ) + { + p_output_fx[i] = malloc( L_FRAME48k * sizeof( Word32 ) ); + floatToFixed_arrL( p_output[i], p_output_fx[i], q, output_frame ); + } + FOR( i = 0; i < st_ivas->hDecoderConfig->nchan_out; i++ ) + { + FOR( j = 0; j < nchan_transport; j++ ) + { + st_ivas->hLsSetUpConversion->dmxMtx_fx[j][i] = float_to_fix( st_ivas->hLsSetUpConversion->dmxMtx[j][i], Q30 ); + } + } + ivas_ls_setup_conversion_fx( st_ivas, nchan_transport, output_frame, p_output_fx, p_output_fx ); + FOR( i = 0; i < max(st_ivas->hDecoderConfig->nchan_out, nchan_transport); ++i ) + { + fixedToFloat_arrL( p_output_fx[i], p_output[i], q, output_frame ); + free( p_output_fx[i] ); + } +#else ivas_ls_setup_conversion( st_ivas, audioCfg2channels( IVAS_AUDIO_CONFIG_5_1_2 ), output_frame, p_output, p_output ); +#endif } } } @@ -1215,7 +1290,31 @@ ivas_error ivas_jbm_dec_tc( /* Rendering */ if ( output_config == IVAS_AUDIO_CONFIG_MONO || output_config == IVAS_AUDIO_CONFIG_STEREO ) { +#ifdef IVAS_FLOAT_FIXED + Word16 i, j, q = Q16; + Word32 *p_output_fx[12]; + q = q - find_guarded_bits_fx( st_ivas->nchan_transport ); + FOR( i = 0; i < max(st_ivas->hDecoderConfig->nchan_out, st_ivas->nchan_transport); ++i ) + { + p_output_fx[i] = malloc( L_FRAME48k * sizeof( Word32 ) ); + floatToFixed_arrL( p_output[i], p_output_fx[i], q, output_frame ); + } + FOR( i = 0; i < st_ivas->hDecoderConfig->nchan_out; i++ ) + { + FOR( j = 0; j < st_ivas->nchan_transport; j++ ) + { + st_ivas->hLsSetUpConversion->dmxMtx_fx[j][i] = float_to_fix( st_ivas->hLsSetUpConversion->dmxMtx[j][i], Q30 ); + } + } + ivas_ls_setup_conversion_fx( st_ivas, st_ivas->nchan_transport, output_frame, p_output_fx, p_output_fx ); + FOR( i = 0; i < max(st_ivas->hDecoderConfig->nchan_out, st_ivas->nchan_transport); ++i) + { + fixedToFloat_arrL( p_output_fx[i], p_output[i], q, output_frame ); + free( p_output_fx[i] ); + } +#else ivas_ls_setup_conversion( st_ivas, st_ivas->nchan_transport, output_frame, p_output, p_output ); +#endif } } else if ( st_ivas->mc_mode == MC_MODE_MCMASA ) @@ -1831,7 +1930,40 @@ ivas_error ivas_jbm_dec_render( if ( st_ivas->renderer_type == RENDERER_MC ) { *nSamplesRendered = min( st_ivas->hTcBuffer->n_samples_available, nSamplesAskedLocal ); +#ifdef IVAS_FLOAT_FIXED + Word16 i, j, q = Q16; + Word32 *p_output_fx[20]; + Word32 *p_tc_fx[16]; + q = q - find_guarded_bits_fx( st_ivas->nchan_transport ); + FOR( i = 0; i < st_ivas->nchan_transport; ++i ) + { + p_tc_fx[i] = malloc( L_FRAME48k * sizeof( Word32 ) ); + floatToFixed_arrL( p_tc[i], p_tc_fx[i], q, *nSamplesRendered ); + } + FOR( i = 0; i < st_ivas->hDecoderConfig->nchan_out; ++i ) + { + p_output_fx[i] = malloc( L_FRAME48k * sizeof( Word32 ) ); + } + FOR( i = 0; i < st_ivas->hDecoderConfig->nchan_out; i++ ) + { + FOR( j = 0; j < st_ivas->nchan_transport; j++ ) + { + st_ivas->hLsSetUpConversion->dmxMtx_fx[j][i] = float_to_fix( st_ivas->hLsSetUpConversion->dmxMtx[j][i], Q30 ); + } + } + ivas_ls_setup_conversion_fx( st_ivas, st_ivas->nchan_transport, *nSamplesRendered, p_tc_fx, p_output_fx ); + FOR( i = 0; i < st_ivas->hDecoderConfig->nchan_out; ++i ) + { + fixedToFloat_arrL( p_output_fx[i], p_output[i], q, *nSamplesRendered ); + free( p_output_fx[i] ); + } + FOR( i = 0; i < st_ivas->nchan_transport; ++i ) + { + free( p_tc_fx[i] ); + } +#else ivas_ls_setup_conversion( st_ivas, st_ivas->nchan_transport, *nSamplesRendered, p_tc, p_output ); +#endif } } else if ( st_ivas->ivas_format == ISM_FORMAT ) @@ -2257,7 +2389,40 @@ ivas_error ivas_jbm_dec_render( else if ( st_ivas->renderer_type == RENDERER_MC ) { *nSamplesRendered = min( st_ivas->hTcBuffer->n_samples_available, nSamplesAskedLocal ); +#ifdef IVAS_FLOAT_FIXED + Word16 i, j, q = Q16; + Word32 *p_output_fx[20]; + Word32 *p_tc_fx[16]; + q = q - find_guarded_bits_fx( st_ivas->nchan_transport ); + FOR( i = 0; i < st_ivas->nchan_transport; ++i ) + { + p_tc_fx[i] = malloc( L_FRAME48k * sizeof( Word32 ) ); + floatToFixed_arrL( p_tc[i], p_tc_fx[i], q, *nSamplesRendered ); + } + FOR( i = 0; i < st_ivas->hDecoderConfig->nchan_out; ++i ) + { + p_output_fx[i] = malloc( L_FRAME48k * sizeof( Word32 ) ); + } + FOR( i = 0; i < st_ivas->hDecoderConfig->nchan_out; i++ ) + { + FOR( j = 0; j < st_ivas->nchan_transport; j++ ) + { + st_ivas->hLsSetUpConversion->dmxMtx_fx[j][i] = float_to_fix( st_ivas->hLsSetUpConversion->dmxMtx[j][i], Q30 ); + } + } + ivas_ls_setup_conversion_fx( st_ivas, st_ivas->nchan_transport, *nSamplesRendered, p_tc_fx, p_output_fx ); + FOR( i = 0; i < st_ivas->hDecoderConfig->nchan_out; ++i ) + { + fixedToFloat_arrL( p_output_fx[i], p_output[i], q, *nSamplesRendered ); + free( p_output_fx[i] ); + } + FOR( i = 0; i < st_ivas->nchan_transport; ++i ) + { + free( p_tc_fx[i] ); + } +#else ivas_ls_setup_conversion( st_ivas, st_ivas->nchan_transport, *nSamplesRendered, p_tc, p_output ); +#endif } else if ( st_ivas->renderer_type == RENDERER_SBA_LINEAR_ENC ) { @@ -2287,7 +2452,31 @@ ivas_error ivas_jbm_dec_render( } else if ( st_ivas->renderer_type == RENDERER_MC ) { +#ifdef IVAS_FLOAT_FIXED + Word16 i, j, q = Q16; + Word32 *p_output_fx[20]; + q = q - find_guarded_bits_fx( MC_PARAMUPMIX_MAX_INPUT_CHANS ); + FOR( i = 0; i < max(st_ivas->hDecoderConfig->nchan_out, MC_PARAMUPMIX_MAX_INPUT_CHANS); ++i ) + { + p_output_fx[i] = malloc( L_FRAME48k * sizeof( Word32 ) ); + floatToFixed_arrL( p_output[i], p_output_fx[i], q, *nSamplesRendered ); + } + FOR( i = 0; i < st_ivas->hDecoderConfig->nchan_out; i++ ) + { + FOR( j = 0; j < MC_PARAMUPMIX_MAX_INPUT_CHANS; j++ ) + { + st_ivas->hLsSetUpConversion->dmxMtx_fx[j][i] = float_to_fix( st_ivas->hLsSetUpConversion->dmxMtx[j][i], Q30 ); + } + } + ivas_ls_setup_conversion_fx( st_ivas, MC_PARAMUPMIX_MAX_INPUT_CHANS, *nSamplesRendered, p_output_fx, p_output_fx ); + FOR( i = 0; i < max(st_ivas->hDecoderConfig->nchan_out, MC_PARAMUPMIX_MAX_INPUT_CHANS); ++i ) + { + fixedToFloat_arrL( p_output_fx[i], p_output[i], q, *nSamplesRendered); + free( p_output_fx[i] ); + } +#else ivas_ls_setup_conversion( st_ivas, MC_PARAMUPMIX_MAX_INPUT_CHANS, *nSamplesRendered, p_output, p_output ); +#endif } else if ( st_ivas->renderer_type == RENDERER_SBA_LINEAR_ENC ) { diff --git a/lib_dec/ivas_mc_param_dec.c b/lib_dec/ivas_mc_param_dec.c index da9b70bb9..d2120bf29 100644 --- a/lib_dec/ivas_mc_param_dec.c +++ b/lib_dec/ivas_mc_param_dec.c @@ -46,6 +46,8 @@ #include "wmc_auto.h" #include "rom_dec.h" #ifdef IVAS_FLOAT_FIXED +#include "prot_fx1.h" +#include "prot_fx2.h" #include "ivas_prot_fx.h" #endif @@ -270,10 +272,17 @@ ivas_error ivas_param_mc_dec_open( if ( hParamMC->synthesis_conf == PARAM_MC_SYNTH_LS_CONV_CLDFB || hParamMC->synthesis_conf == PARAM_MC_SYNTH_LS_CONV_COV || hParamMC->synthesis_conf == PARAM_MC_SYNTH_MONO_STEREO ) { +#ifdef IVAS_FLOAT_FIXED + if ( ( error = ivas_ls_setup_conversion_open_fx( st_ivas ) ) != IVAS_ERR_OK ) + { + return error; + } +#else if ( ( error = ivas_ls_setup_conversion_open( st_ivas ) ) != IVAS_ERR_OK ) { return error; } +#endif /* convert the ls conv dmx matrix into column order matrix format (nchan_out_cldfb x nchan_out) */ if ( hParamMC->synthesis_conf == PARAM_MC_SYNTH_LS_CONV_COV || hParamMC->synthesis_conf == PARAM_MC_SYNTH_MONO_STEREO ) @@ -300,7 +309,11 @@ ivas_error ivas_param_mc_dec_open( else { /* close the ls conversion handle immediately, it was only needed to get the DMX matrix in case of DMX in the covariance domain */ +#ifdef IVAS_FLOAT_FIXED + ivas_ls_setup_conversion_close_fx( &st_ivas->hLsSetUpConversion ); +#else ivas_ls_setup_conversion_close( &st_ivas->hLsSetUpConversion ); +#endif } } } @@ -733,6 +746,17 @@ ivas_error ivas_param_mc_dec_reconfig( { if ( nchan_transport_old != nchan_transport ) { +#ifdef IVAS_FLOAT_FIXED + if ( st_ivas->hLsSetUpConversion != NULL ) + { + ivas_ls_setup_conversion_close_fx( &st_ivas->hLsSetUpConversion ); + } + + if ( ( error = ivas_ls_setup_conversion_open_fx( st_ivas ) ) != IVAS_ERR_OK ) + { + return error; + } +#else if ( st_ivas->hLsSetUpConversion != NULL ) { ivas_ls_setup_conversion_close( &st_ivas->hLsSetUpConversion ); @@ -742,6 +766,7 @@ ivas_error ivas_param_mc_dec_reconfig( { return error; } +#endif /* convert the ls conv dmx matrix into column order matrix format (nchan_out_cldfb x nchan_out) */ free( hParamMC->ls_conv_dmx_matrix ); @@ -1765,7 +1790,32 @@ void ivas_param_mc_dec_render( else if ( hParamMC->synthesis_conf == PARAM_MC_SYNTH_LS_CONV_CLDFB ) { /* format conversion*/ +#ifdef IVAS_FLOAT_FIXED + Word32 Cldfb_RealBuffer_fx[MAX_CICP_CHANNELS][PARAM_MC_MAX_NSLOTS_IN_SUBFRAME][CLDFB_NO_CHANNELS_MAX]; + Word32 Cldfb_ImagBuffer_fx[MAX_CICP_CHANNELS][PARAM_MC_MAX_NSLOTS_IN_SUBFRAME][CLDFB_NO_CHANNELS_MAX]; + Word16 inChannels = st_ivas->hIntSetup.nchan_out_woLFE + st_ivas->hIntSetup.num_lfe; + Word16 num_timeslots = hParamMC->subframe_nbslots[subframe_idx]; + Word16 i, j; + FOR( i = 0; i < inChannels; ++i ) + { + FOR( j = 0; j < num_timeslots; ++j ) + { + floatToFixed_arrL( Cldfb_RealBuffer[i][j], Cldfb_RealBuffer_fx[i][j], Q9, st_ivas->hLsSetUpConversion->sfbCnt ); + floatToFixed_arrL( Cldfb_ImagBuffer[i][j], Cldfb_ImagBuffer_fx[i][j], Q9, st_ivas->hLsSetUpConversion->sfbCnt ); + } + } + ivas_lssetupconversion_process_param_mc_fx( st_ivas, hParamMC->subframe_nbslots[subframe_idx], Cldfb_RealBuffer_fx, Cldfb_ImagBuffer_fx, channel_active ); + FOR( i = 0; i < inChannels; ++i ) + { + FOR( j = 0; j < num_timeslots; ++j ) + { + fixedToFloat_arrL( Cldfb_RealBuffer_fx[i][j], Cldfb_RealBuffer[i][j], Q9, st_ivas->hLsSetUpConversion->sfbCnt ); + fixedToFloat_arrL( Cldfb_ImagBuffer_fx[i][j], Cldfb_ImagBuffer[i][j], Q9, st_ivas->hLsSetUpConversion->sfbCnt ); + } + } +#else ivas_lssetupconversion_process_param_mc( st_ivas, hParamMC->subframe_nbslots[subframe_idx], Cldfb_RealBuffer, Cldfb_ImagBuffer, channel_active ); +#endif } /* CLDFB synthesis */ diff --git a/lib_dec/ivas_mct_dec.c b/lib_dec/ivas_mct_dec.c index 2aabc85bf..888b70dfe 100644 --- a/lib_dec/ivas_mct_dec.c +++ b/lib_dec/ivas_mct_dec.c @@ -223,7 +223,22 @@ ivas_error ivas_mct_dec( if ( st_ivas->renderer_type == RENDERER_MC ) { /* Equalization in MDCT Domain */ +#ifdef IVAS_FLOAT_FIXED + Word32 *output_fx[MAX_TRANSPORT_CHANNELS]; + for ( int i = 0; i < st_ivas->nchan_transport; ++i ) + { + output_fx[i] = malloc( L_FRAME48k * sizeof( Word32 ) ); + floatToFixed_arrL( output[i], output_fx[i], Q11, L_FRAME48k ); + } + ivas_ls_setup_conversion_process_mdct_fx( st_ivas, output_fx); + for ( int i = 0; i < st_ivas->nchan_transport; ++i ) + { + fixedToFloat_arrL( output_fx[i], output[i], Q11, L_FRAME48k ); + free(output_fx[i]); + } +#else ivas_ls_setup_conversion_process_mdct( st_ivas, output ); +#endif } else if ( st_ivas->renderer_type == RENDERER_MC_PARAMMC && ( st_ivas->hDecoderConfig->output_config == IVAS_AUDIO_CONFIG_MONO || st_ivas->hDecoderConfig->output_config == IVAS_AUDIO_CONFIG_STEREO ) ) @@ -1014,13 +1029,21 @@ static ivas_error ivas_mc_dec_reconfig( ivas_param_mc_dec_close( &st_ivas->hParamMC ); /* remove ls conversion if it was allocated by ParamMC */ +#ifdef IVAS_FLOAT_FIXED + ivas_ls_setup_conversion_close_fx( &st_ivas->hLsSetUpConversion ); +#else ivas_ls_setup_conversion_close( &st_ivas->hLsSetUpConversion ); +#endif } if ( last_mc_mode == MC_MODE_PARAMUPMIX ) { ivas_mc_paramupmix_dec_close( &( st_ivas->hMCParamUpmix ) ); +#ifdef IVAS_FLOAT_FIXED + ivas_ls_setup_conversion_close_fx( &( st_ivas->hLsSetUpConversion ) ); +#else ivas_ls_setup_conversion_close( &( st_ivas->hLsSetUpConversion ) ); +#endif } /* De-allocate McMasa-related handles */ @@ -1042,10 +1065,17 @@ static ivas_error ivas_mc_dec_reconfig( /* init LS conversion if the renderer type asks for it */ if ( st_ivas->renderer_type == RENDERER_MC && st_ivas->hLsSetUpConversion == NULL ) { +#ifdef IVAS_FLOAT_FIXED + if ( ( error = ivas_ls_setup_conversion_open_fx( st_ivas ) ) != IVAS_ERR_OK ) + { + return error; + } +#else if ( ( error = ivas_ls_setup_conversion_open( st_ivas ) ) != IVAS_ERR_OK ) { return error; } +#endif } } } @@ -1063,7 +1093,11 @@ static ivas_error ivas_mc_dec_reconfig( ivas_param_mc_dec_close( &st_ivas->hParamMC ); /* remove ls conversion if it was allocated by ParamMC */ +#ifdef IVAS_FLOAT_FIXED + ivas_ls_setup_conversion_close_fx( &st_ivas->hLsSetUpConversion ); +#else ivas_ls_setup_conversion_close( &st_ivas->hLsSetUpConversion ); +#endif } #ifdef IVAS_FLOAT_FIXED @@ -1076,10 +1110,17 @@ static ivas_error ivas_mc_dec_reconfig( /* init LS conversion if the renderer type asks for it */ if ( ( st_ivas->renderer_type == RENDERER_MC ) && st_ivas->hLsSetUpConversion == NULL ) { +#ifdef IVAS_FLOAT_FIXED + if ( ( error = ivas_ls_setup_conversion_open_fx( st_ivas ) ) != IVAS_ERR_OK ) + { + return error; + } +#else if ( ( error = ivas_ls_setup_conversion_open( st_ivas ) ) != IVAS_ERR_OK ) { return error; } +#endif } if ( ( error = ivas_mc_paramupmix_dec_open( st_ivas ) ) != IVAS_ERR_OK ) @@ -1095,7 +1136,11 @@ static ivas_error ivas_mc_dec_reconfig( /* remove old ls conversion for MCT if open, gets reopened correctly within ivas_param_mc_dec_open when needed */ if ( renderer_type_old == RENDERER_MC && st_ivas->hLsSetUpConversion != NULL ) { +#ifdef IVAS_FLOAT_FIXED + ivas_ls_setup_conversion_close_fx( &st_ivas->hLsSetUpConversion ); +#else ivas_ls_setup_conversion_close( &st_ivas->hLsSetUpConversion ); +#endif } if ( ( error = ivas_param_mc_dec_open( st_ivas ) ) != IVAS_ERR_OK ) @@ -1171,7 +1216,11 @@ static ivas_error ivas_mc_dec_reconfig( /* LS conversion */ if ( st_ivas->hLsSetUpConversion != NULL ) { +#ifdef IVAS_FLOAT_FIXED + ivas_ls_setup_conversion_close_fx( &st_ivas->hLsSetUpConversion ); +#else ivas_ls_setup_conversion_close( &st_ivas->hLsSetUpConversion ); +#endif } ivas_mc_paramupmix_dec_close( &( st_ivas->hMCParamUpmix ) ); diff --git a/lib_dec/ivas_out_setup_conversion.c b/lib_dec/ivas_out_setup_conversion.c index e1d0c12e5..e713af665 100644 --- a/lib_dec/ivas_out_setup_conversion.c +++ b/lib_dec/ivas_out_setup_conversion.c @@ -40,7 +40,13 @@ #include "ivas_rom_com.h" #include "ivas_rom_rend.h" #include "wmc_auto.h" +#ifdef IVAS_FLOAT_FIXED +#include "prot_fx1.h" +#include "prot_fx2.h" +#include "ivas_prot_fx.h" +#endif +#include "debug.h" /*----------------------------------------------------------------------------------* * Local constants @@ -50,11 +56,54 @@ #define LS_OUT_CONV_CLIP_FACTOR_MAX 2.0f #define LS_OUT_CONV_CLIP_FACTOR_MIN 0.3f +#ifdef IVAS_FLOAT_FIXED +#define LS_OUT_CONV_SMOOTHING_FACTOR_Q31 93415539 +#define LS_OUT_CONV_CLIP_FACTOR_MAX_Q29 1073741824 +#define LS_OUT_CONV_CLIP_FACTOR_MAX_SQ_Q28 1073741824 +#define LS_OUT_CONV_CLIP_FACTOR_MIN_Q29 161061274 +#define LS_OUT_CONV_CLIP_FACTOR_MIN_SQ_Q28 24159191 +#define EPSILON_FX 1 +#endif + /*----------------------------------------------------------------------------------* * Local functions *----------------------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED +static void ivas_lssetupconversion_computeEQFactor_fx( + Word32 *outputEnergy, + Word32 *inputEnergy, + Word32 *EQ ) +{ + + IF( L_shr( *outputEnergy, 3 ) > Mpy_32_32( LS_OUT_CONV_CLIP_FACTOR_MAX_SQ_Q28, *inputEnergy ) ) + { + *EQ = L_shl_sat( LS_OUT_CONV_CLIP_FACTOR_MAX_Q29, 1 ); + return; + } + IF( L_shr( *outputEnergy, 3 ) < Mpy_32_32( LS_OUT_CONV_CLIP_FACTOR_MIN_SQ_Q28, *inputEnergy ) ) + { + *EQ = L_shl_sat( LS_OUT_CONV_CLIP_FACTOR_MIN_Q29, 1 ); + return; + } + + IF( *outputEnergy == 0 && *inputEnergy == 0 ) + { + *EQ = ONE_IN_Q30; + return; + } + /* Compute the Equalization Gain */ + Word16 tmp_e; + Word16 tmp = BASOP_Util_Divide3232_Scale( *outputEnergy, ( EPSILON_FX + *inputEnergy ), &tmp_e ); + Word32 tmp_32 = L_shl( (Word32) tmp, 16 ); + tmp_32 = Sqrt32( tmp_32, &tmp_e ); + *EQ = L_shr( tmp_32, 1 - tmp_e ); + + return; +} +#endif + static void ivas_lssetupconversion_computeEQFactor( float *outputEnergy, float *inputEnergy, @@ -71,6 +120,79 @@ static void ivas_lssetupconversion_computeEQFactor( } +#ifdef IVAS_FLOAT_FIXED +static void ivas_lssetupconversion_mdct_init_bands_fx( + const Word16 output_frame, /* i : output frame length */ + const Word16 tcx_mode, /* i : tcx mode (TCX10, TCX 20) */ + Word16 *sfbOffset, /* o : sfb offset table */ + Word16 *sfbCnt /* o : number of sfbs */ +) +{ + SpectrumWarping const *lpcBndsParam; + Word16 i, cnt, specStartOffset, L_frameTCX; + const UWord8 *sfbWidths; + + L_frameTCX = ( EQ_16( tcx_mode, TCX_20_CORE ) ) ? output_frame : ( shr( output_frame, 1 ) ); + + SWITCH( output_frame ) + { + case L_FRAME48k: + case L_FRAME32k: + lpcBndsParam = sw32000Hz; + BREAK; + case L_FRAME25_6k: + lpcBndsParam = sw25600Hz; + BREAK; + case L_FRAME16k: + lpcBndsParam = sw16000Hz; + BREAK; + default: + assert( !"Subband division not defined for this frame size" ); + return; + } + + sfbWidths = ( EQ_16( tcx_mode, TCX_20_CORE ) ? lpcBndsParam->bandLengthsTCX20 : lpcBndsParam->bandLengthsTCX10 ); + cnt = ( EQ_16( tcx_mode, TCX_20_CORE ) ? 64 : 32 ); + move16(); + + /* calc sfb offsets */ + specStartOffset = 0; + move16(); + + FOR( i = 0; i < cnt; i++ ) + { + sfbOffset[i] = min( specStartOffset, L_frameTCX ); + move16(); + specStartOffset = add( specStartOffset, sfbWidths[i] ); + move16(); + + IF( GE_16( sfbOffset[i], L_frameTCX ) ) + { + BREAK; + } + } + + *sfbCnt = i; + move16(); + sfbOffset[*sfbCnt] = min( specStartOffset, L_frameTCX ); + move16(); + + IF( LT_16( sfbOffset[*sfbCnt], L_frameTCX ) ) + { + Word16 nMissingBins = sub( L_frameTCX, sfbOffset[*sfbCnt] ); + + IF( LT_16( shr( (Word16) sfbWidths[i], 1 ), nMissingBins ) ) + { + ( *sfbCnt )++; + } + sfbOffset[*sfbCnt] = L_frameTCX; + move16(); + } + + return; +} +#endif + static void ivas_lssetupconversion_mdct_init_bands( const int16_t output_frame, /* i : output frame length */ const int16_t tcx_mode, /* i : tcx mode (TCX10, TCX 20) */ @@ -135,6 +257,95 @@ static void ivas_lssetupconversion_mdct_init_bands( return; } +#ifdef IVAS_FLOAT_FIXED +static void get_custom_ls_conversion_matrix_fx( + const EFAP_HANDLE hEFAPdata, /* i : EFAP handle */ + const IVAS_OUTPUT_SETUP hTransSetup, /* i : Transport channel configuration handle */ + const LSSETUP_CUSTOM_HANDLE hLsSetupCustom, /* i : Custom LS Setup handle */ + LSSETUP_CONVERSION_HANDLE hLsSetUpConversion /* o : LS Setup Conversion Handle */ +) +{ + Word16 ch_in, ch_in_woLFE; + Word16 ch_out, ch_out_woLFE; + Word16 nchan_in, nchan_out; + Word16 lfe_in_idx, lfe_out_idx; + + Word32 dmxCoeff_LFE; + /* TODO: remove the floating point dependency */ + float tmp_gains[MAX_OUTPUT_CHANNELS]; + + lfe_in_idx = -1; + move16(); + lfe_out_idx = -1; + move16(); + + nchan_in = add( hTransSetup.nchan_out_woLFE, hTransSetup.num_lfe ); + nchan_out = add( hLsSetupCustom->num_spk, hLsSetupCustom->num_lfe ); + + /* The below code will need to be restructured in case additional LFEs must be supported */ + IF( GT_16( hTransSetup.num_lfe, 0 ) ) + { + lfe_in_idx = hTransSetup.index_lfe[0]; + move16(); + } + IF( GT_16( hLsSetupCustom->num_lfe, 0 ) ) + { + lfe_out_idx = hLsSetupCustom->lfe_idx[0]; + move16(); + } + + IF( EQ_16( hTransSetup.nchan_out_woLFE, 1 ) ) + { + dmxCoeff_LFE = ONE_IN_Q30; + move32(); + } + ELSE + { + dmxCoeff_LFE = L_shl( (Word32) div_s( 1, hTransSetup.nchan_out_woLFE ), Q15 ); // Q30 + } + + FOR( ( ch_in = 0, ch_in_woLFE = 0 ); ch_in < nchan_in; ( ch_in++, ch_in_woLFE++ ) ) + { + IF( EQ_16( lfe_in_idx, ch_in ) ) + { + IF( lfe_out_idx >= 0 ) + { + /* re-route LFE */ + hLsSetUpConversion->dmxMtx_fx[ch_in][lfe_out_idx] = ONE_IN_Q30; + move32(); + } + ELSE + { + /* mix the LFE to all channels */ + set32_fx( hLsSetUpConversion->dmxMtx_fx[ch_in], dmxCoeff_LFE, nchan_out ); + } + + ch_in_woLFE--; + } + ELSE IF( NE_16( lfe_out_idx, ch_in ) ) + { + /* Set the values of hLsSetUpConversion->dmxMtx to EFAP gains, skipping LFE */ + efap_determine_gains( hEFAPdata, tmp_gains, hTransSetup.ls_azimuth[ch_in_woLFE], hTransSetup.ls_elevation[ch_in_woLFE], EFAP_MODE_EFAP ); + + FOR( ( ch_out = 0, ch_out_woLFE = 0 ); ch_out < nchan_out; ( ch_out++, ch_out_woLFE++ ) ) + { + IF( EQ_16( lfe_out_idx, ch_out ) ) + { + ch_out_woLFE--; + } + ELSE + { + // Currently efap_determine_gains returns float tmp_gains. + hLsSetUpConversion->dmxMtx_fx[ch_in][ch_out] = float_to_fix( tmp_gains[ch_out_woLFE], Q30 ); + move32(); + } + } + } + } + + return; +} +#endif static void get_custom_ls_conversion_matrix( const EFAP_HANDLE hEFAPdata, /* i : EFAP handle */ @@ -209,6 +420,101 @@ static void get_custom_ls_conversion_matrix( } +#ifdef IVAS_FLOAT_FIXED +static ivas_error get_ls_conversion_matrix_fx( + LSSETUP_CONVERSION_HANDLE hLsSetUpConversion, + const AUDIO_CONFIG input_config, + const AUDIO_CONFIG output_config ) +{ + Word16 i, k; + Word16 ch_in, ch_out; + Word16 nchan_in, nchan_out; + Word16 index; + Word32 value; + const LS_CONVERSION_MATRIX_FX *conversion_matrix_fx; + ivas_error error; + + error = IVAS_ERR_OK; + + conversion_matrix_fx = NULL; + + nchan_in = audioCfg2channels( input_config ); + nchan_out = audioCfg2channels( output_config ); + + /* Search the table for a mapping */ + FOR( i = 0; i < LS_SETUP_CONVERSION_NUM_MAPPINGS; i++ ) + { + test(); + IF( ( EQ_32( input_config, ls_conversion_mapping[i].input_config ) ) && ( EQ_32( output_config, ls_conversion_mapping[i].output_config ) ) ) + { + /* Special handling for MONO and STEREO downmix */ + test(); + IF( EQ_32( output_config, IVAS_AUDIO_CONFIG_MONO ) || EQ_32( output_config, IVAS_AUDIO_CONFIG_STEREO ) ) + { + FOR( ( ch_in = 0, k = 0 ); ch_in < nchan_in; ( ch_in++, k++ ) ) + { + /* Skip two rows in the matrix for 5.1.x formats */ + test(); + test(); + IF( EQ_16( ch_in, 6 ) && ( EQ_32( input_config, IVAS_AUDIO_CONFIG_5_1_2 ) || EQ_32( input_config, IVAS_AUDIO_CONFIG_5_1_4 ) ) ) + { + k = add( k, 2 ); + } + + FOR( ch_out = 0; ch_out < nchan_out; ch_out++ ) + { + IF( EQ_32( output_config, IVAS_AUDIO_CONFIG_MONO ) ) + { + hLsSetUpConversion->dmxMtx_fx[ch_in][ch_out] = ls_conversion_cicpX_mono_fx[k][ch_out]; + move32(); + } + ELSE + { + hLsSetUpConversion->dmxMtx_fx[ch_in][ch_out] = ls_conversion_cicpX_stereo_fx[k][ch_out]; + move32(); + } + } + } + return error; + } + ELSE + { + conversion_matrix_fx = ls_conversion_mapping_fx[i].conversion_matrix_fx; + + /* If a mapping is defined with a NULL matrix, 1:1 upmix of input channels */ + IF( conversion_matrix_fx == NULL ) + { + FOR( k = 0; k < nchan_in; k++ ) + { + hLsSetUpConversion->dmxMtx_fx[k][k] = ONE_IN_Q30; + move32(); + } + return error; + } + ELSE + { + FOR( k = 1; k < ( conversion_matrix_fx[0].index + 1 ); k++ ) + { + index = conversion_matrix_fx[k].index; + move16(); + value = conversion_matrix_fx[k].value; + move16(); + + ch_in = index / nchan_out; + ch_out = index % nchan_out; + + hLsSetUpConversion->dmxMtx_fx[ch_in][ch_out] = value; + move32(); + } + } + return error; + } + } + } + + return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "The conversion matrix between these formats is not defined!\n" ); +} +#endif static ivas_error get_ls_conversion_matrix( LSSETUP_CONVERSION_HANDLE hLsSetUpConversion, const AUDIO_CONFIG input_config, @@ -300,6 +606,203 @@ static ivas_error get_ls_conversion_matrix( * Open the LS configuration Conversion Module *-------------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED +ivas_error ivas_ls_setup_conversion_open_fx( + Decoder_Struct *st_ivas /* i/o: IVAS decoder structure */ +) +{ + LSSETUP_CONVERSION_HANDLE hLsSetUpConversion; + Word16 chIdx, inChannels, outChannels; + Word16 output_frame; + Word32 output_Fs; + Word16 nchan_out; + Word16 paramUpmixMonoStereo; + + test(); + test(); + test(); + IF( EQ_32( st_ivas->ivas_format, MC_FORMAT ) && EQ_32( st_ivas->mc_mode, MC_MODE_PARAMUPMIX ) && ( EQ_32( st_ivas->hDecoderConfig->output_config, IVAS_AUDIO_CONFIG_MONO ) || EQ_32( st_ivas->hDecoderConfig->output_config, IVAS_AUDIO_CONFIG_STEREO ) ) ) + { + paramUpmixMonoStereo = TRUE; + move16(); + } + ELSE + { + paramUpmixMonoStereo = FALSE; + move16(); + } + output_Fs = st_ivas->hDecoderConfig->output_Fs; + move32(); + nchan_out = st_ivas->hDecoderConfig->nchan_out; + move16(); + output_frame = (Word16) ( output_Fs / FRAMES_PER_SEC ); + + /* Allocate memory to the handle */ + IF( ( hLsSetUpConversion = (LSSETUP_CONVERSION_HANDLE) malloc( sizeof( LSSETUP_CONVERSION_STRUCT ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LS configuration Conversion Handle \n" ) ); + } + + assert( LE_16( nchan_out, MAX_OUTPUT_CHANNELS ) ); + + outChannels = nchan_out; + move16(); + IF( EQ_32( st_ivas->renderer_type, RENDERER_MC_PARAMMC ) ) + { + inChannels = add( st_ivas->hTransSetup.nchan_out_woLFE, st_ivas->hTransSetup.num_lfe ); + hLsSetUpConversion->sfbCnt = (Word16) ( output_Fs * INV_CLDFB_BANDWIDTH + 0.5f ); + FOR( chIdx = 0; chIdx < outChannels; chIdx++ ) + { + IF( ( hLsSetUpConversion->targetEnergyPrev_fx[chIdx] = (Word32 *) malloc( ( hLsSetUpConversion->sfbCnt ) * sizeof( Word32 ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LS configuration Conversion Handle \n" ) ); + } + IF( ( hLsSetUpConversion->dmxEnergyPrev_fx[chIdx] = (Word32 *) malloc( ( hLsSetUpConversion->sfbCnt ) * sizeof( Word32 ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LS configuration Conversion Handle \n" ) ); + } + set32_fx( hLsSetUpConversion->targetEnergyPrev_fx[chIdx], 0, hLsSetUpConversion->sfbCnt ); + set32_fx( hLsSetUpConversion->dmxEnergyPrev_fx[chIdx], 0, hLsSetUpConversion->sfbCnt ); + /* TODO: remove the floating point dependency */ + IF( ( hLsSetUpConversion->targetEnergyPrev[chIdx] = (float *) malloc( ( hLsSetUpConversion->sfbCnt ) * sizeof( float ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LS configuration Conversion Handle \n" ) ); + } + IF( ( hLsSetUpConversion->dmxEnergyPrev[chIdx] = (float *) malloc( ( hLsSetUpConversion->sfbCnt ) * sizeof( float ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LS configuration Conversion Handle \n" ) ); + } + set_f( hLsSetUpConversion->targetEnergyPrev[chIdx], 0.0f, hLsSetUpConversion->sfbCnt ); + set_f( hLsSetUpConversion->dmxEnergyPrev[chIdx], 0.0f, hLsSetUpConversion->sfbCnt ); + } + FOR( ; chIdx < MAX_CICP_CHANNELS; chIdx++ ) + { + hLsSetUpConversion->targetEnergyPrev_fx[chIdx] = NULL; + hLsSetUpConversion->dmxEnergyPrev_fx[chIdx] = NULL; + /* TODO: remove the floating point dependency */ + hLsSetUpConversion->targetEnergyPrev[chIdx] = NULL; + hLsSetUpConversion->dmxEnergyPrev[chIdx] = NULL; + } + } + ELSE + { + test(); + IF( EQ_32( st_ivas->ivas_format, MC_FORMAT ) && EQ_32( st_ivas->mc_mode, MC_MODE_PARAMUPMIX ) ) + { + IF( EQ_16( paramUpmixMonoStereo, TRUE ) ) + { + inChannels = audioCfg2channels( IVAS_AUDIO_CONFIG_5_1_2 ); + } + ELSE + { + inChannels = add( st_ivas->hTransSetup.nchan_out_woLFE, st_ivas->hTransSetup.num_lfe ); + } + } + ELSE + { + inChannels = st_ivas->nchan_transport; + move16(); + } + + /*Initialization of MDCT bands with TCX20 resolution */ + ivas_lssetupconversion_mdct_init_bands_fx( output_frame, TCX_20_CORE, &hLsSetUpConversion->sfbOffset[0], &hLsSetUpConversion->sfbCnt ); + IF( ( hLsSetUpConversion->targetEnergyPrev_fx[0] = (Word32 *) malloc( ( MAX_SFB + 2 ) * sizeof( Word32 ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LS configuration Conversion Handle \n" ) ); + } + IF( ( hLsSetUpConversion->dmxEnergyPrev_fx[0] = (Word32 *) malloc( ( MAX_SFB + 2 ) * sizeof( Word32 ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LS configuration Conversion Handle \n" ) ); + } + /* TODO: remove the floating point dependency */ + IF( ( hLsSetUpConversion->targetEnergyPrev[0] = (float *) malloc( ( MAX_SFB + 2 ) * sizeof( float ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LS configuration Conversion Handle \n" ) ); + } + IF( ( hLsSetUpConversion->dmxEnergyPrev[0] = (float *) malloc( ( MAX_SFB + 2 ) * sizeof( float ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LS configuration Conversion Handle \n" ) ); + } + + FOR( chIdx = 1; chIdx < MAX_CICP_CHANNELS; chIdx++ ) + { + hLsSetUpConversion->targetEnergyPrev_fx[chIdx] = NULL; + hLsSetUpConversion->dmxEnergyPrev_fx[chIdx] = NULL; + /* TODO: remove the floating point dependency */ + hLsSetUpConversion->targetEnergyPrev[chIdx] = NULL; + hLsSetUpConversion->dmxEnergyPrev[chIdx] = NULL; + } + set32_fx( hLsSetUpConversion->targetEnergyPrev_fx[0], 0, MAX_SFB + 2 ); + set32_fx( hLsSetUpConversion->dmxEnergyPrev_fx[0], 0, MAX_SFB + 2 ); + /* TODO: remove the floating point dependency */ + set_f( hLsSetUpConversion->targetEnergyPrev[0], 0.0f, MAX_SFB + 2 ); + set_f( hLsSetUpConversion->dmxEnergyPrev[0], 0.0f, MAX_SFB + 2 ); + } + + /* Initialize the DMX conversion matrix */ + FOR( chIdx = 0; chIdx < inChannels; chIdx++ ) + { + /* Allocate memory depending on the number of output channels */ + IF( ( hLsSetUpConversion->dmxMtx_fx[chIdx] = (Word32 *) malloc( outChannels * sizeof( Word32 ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for temp dmx matrix \n" ) ); + } + set32_fx( hLsSetUpConversion->dmxMtx_fx[chIdx], 0, outChannels ); + + /* TODO: remove the floating point dependency */ + /* Allocate memory depending on the number of output channels */ + IF( ( hLsSetUpConversion->dmxMtx[chIdx] = (float *) malloc( outChannels * sizeof( float ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory FOR temp dmx matrix \n" ) ); + } + set_zero( hLsSetUpConversion->dmxMtx[chIdx], outChannels ); + } + + FOR( ; chIdx < MAX_CICP_CHANNELS; chIdx++ ) + { + hLsSetUpConversion->dmxMtx_fx[chIdx] = NULL; + /* TODO: remove the floating point dependency */ + hLsSetUpConversion->dmxMtx[chIdx] = NULL; + } + + IF( EQ_32( st_ivas->hDecoderConfig->output_config, IVAS_AUDIO_CONFIG_LS_CUSTOM ) ) + { + get_custom_ls_conversion_matrix_fx( st_ivas->hEFAPdata, st_ivas->hTransSetup, st_ivas->hLsSetupCustom, hLsSetUpConversion ); + } + ELSE + { + IF( NE_32( st_ivas->transport_config, IVAS_AUDIO_CONFIG_INVALID ) ) + { + IF( EQ_16( paramUpmixMonoStereo, TRUE ) ) + { + get_ls_conversion_matrix_fx( hLsSetUpConversion, IVAS_AUDIO_CONFIG_5_1_2, st_ivas->hDecoderConfig->output_config ); + } + ELSE + { + get_ls_conversion_matrix_fx( hLsSetUpConversion, st_ivas->transport_config, st_ivas->hDecoderConfig->output_config ); + } + } + ELSE + { + get_ls_conversion_matrix_fx( hLsSetUpConversion, st_ivas->intern_config, st_ivas->hDecoderConfig->output_config ); + } + } + + /* TODO: remove the floating point dependency */ + FOR( Word16 i = 0; i < inChannels; ++i ) + { + FOR( Word16 j = 0; j < outChannels; ++j ) + { + hLsSetUpConversion->dmxMtx[i][j] = fix_to_float( hLsSetUpConversion->dmxMtx_fx[i][j], Q30 ); + } + } + + st_ivas->hLsSetUpConversion = hLsSetUpConversion; + + return IVAS_ERR_OK; +} +#endif + ivas_error ivas_ls_setup_conversion_open( Decoder_Struct *st_ivas /* i/o: IVAS decoder structure */ ) @@ -445,6 +948,65 @@ ivas_error ivas_ls_setup_conversion_open( * Close the LS configuration Conversion Module *-------------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED +void ivas_ls_setup_conversion_close_fx( + LSSETUP_CONVERSION_HANDLE *hLsSetUpConversion /* i/o: LS converter handle */ +) +{ + Word16 idx; + + IF( hLsSetUpConversion == NULL || *hLsSetUpConversion == NULL ) + { + return; + } + + FOR( idx = 0; idx < MAX_CICP_CHANNELS; idx++ ) + { + IF( ( *hLsSetUpConversion )->dmxMtx_fx[idx] != NULL ) + { + free( ( *hLsSetUpConversion )->dmxMtx_fx[idx] ); + ( *hLsSetUpConversion )->dmxMtx_fx[idx] = NULL; + } + + IF( ( *hLsSetUpConversion )->targetEnergyPrev_fx[idx] != NULL ) + { + free( ( *hLsSetUpConversion )->targetEnergyPrev_fx[idx] ); + ( *hLsSetUpConversion )->targetEnergyPrev_fx[idx] = NULL; + } + + IF( ( *hLsSetUpConversion )->dmxEnergyPrev_fx[idx] != NULL ) + { + free( ( *hLsSetUpConversion )->dmxEnergyPrev_fx[idx] ); + ( *hLsSetUpConversion )->dmxEnergyPrev_fx[idx] = NULL; + } + + /* TODO: remove the floating point dependency */ + IF( ( *hLsSetUpConversion )->dmxMtx[idx] != NULL ) + { + free( ( *hLsSetUpConversion )->dmxMtx[idx] ); + ( *hLsSetUpConversion )->dmxMtx[idx] = NULL; + } + + IF( ( *hLsSetUpConversion )->targetEnergyPrev[idx] != NULL ) + { + free( ( *hLsSetUpConversion )->targetEnergyPrev[idx] ); + ( *hLsSetUpConversion )->targetEnergyPrev[idx] = NULL; + } + + IF( ( *hLsSetUpConversion )->dmxEnergyPrev[idx] != NULL ) + { + free( ( *hLsSetUpConversion )->dmxEnergyPrev[idx] ); + ( *hLsSetUpConversion )->dmxEnergyPrev[idx] = NULL; + } + } + + free( *hLsSetUpConversion ); + *hLsSetUpConversion = NULL; + + return; +} +#endif + void ivas_ls_setup_conversion_close( LSSETUP_CONVERSION_HANDLE *hLsSetUpConversion /* i/o: LS converter handle */ ) @@ -477,19 +1039,81 @@ void ivas_ls_setup_conversion_close( } } - free( *hLsSetUpConversion ); - *hLsSetUpConversion = NULL; + free( *hLsSetUpConversion ); + *hLsSetUpConversion = NULL; + + return; +} + + +/*------------------------------------------------------------------------- + * ivas_ls_setup_conversion() + * + * Convert (downmix or upmix) the input LS configuration + * to output LS configuration in time domain + *-------------------------------------------------------------------------*/ + +#ifdef IVAS_FLOAT_FIXED +void ivas_ls_setup_conversion_fx( + Decoder_Struct *st_ivas, /* i : IVAS decoder structure */ + const Word16 input_chans, /* i : number of input channels to the renderer */ + const Word16 output_frame, /* i : frame length */ + Word32 *input[], /* i : LS input/output synthesis signal */ + Word32 *output[] /* i/o: LS input/output synthesis signal */ +) +{ + Word16 chInIdx, chOutIdx, idx; + LSSETUP_CONVERSION_HANDLE hLsSetUpConversion; + Word32 dmxCoeff, tmpVal; + Word32 output_tmp[MAX_OUTPUT_CHANNELS][L_FRAME48k]; + + push_wmops( "LS_Renderer" ); + + hLsSetUpConversion = st_ivas->hLsSetUpConversion; + + FOR( chOutIdx = 0; chOutIdx < st_ivas->hDecoderConfig->nchan_out; chOutIdx++ ) + { + set32_fx( output_tmp[chOutIdx], 0, output_frame ); + FOR( chInIdx = 0; chInIdx < input_chans; chInIdx++ ) + { + dmxCoeff = hLsSetUpConversion->dmxMtx_fx[chInIdx][chOutIdx]; + move32(); + + IF( EQ_32( dmxCoeff, 0 ) ) + { + CONTINUE; + } + ELSE IF( EQ_32( dmxCoeff, ONE_IN_Q30 ) ) + { + FOR( idx = 0; idx < output_frame; idx++ ) + { + output_tmp[chOutIdx][idx] = L_add( output_tmp[chOutIdx][idx], input[chInIdx][idx] ); + move32(); + } + } + ELSE + { + FOR( idx = 0; idx < output_frame; idx++ ) + { + tmpVal = Mpy_32_32( L_shl_sat( dmxCoeff, 1 ), input[chInIdx][idx] ); + output_tmp[chOutIdx][idx] = L_add( output_tmp[chOutIdx][idx], tmpVal ); + move32(); + } + } + } + } + + /* Copy to output buffer */ + FOR( chOutIdx = 0; chOutIdx < st_ivas->hDecoderConfig->nchan_out; chOutIdx++ ) + { + Copy32( output_tmp[chOutIdx], output[chOutIdx], output_frame ); + } + + pop_wmops(); return; } - - -/*------------------------------------------------------------------------- - * ivas_ls_setup_conversion() - * - * Convert (downmix or upmix) the input LS configuration - * to output LS configuration in time domain - *-------------------------------------------------------------------------*/ +#endif void ivas_ls_setup_conversion( Decoder_Struct *st_ivas, /* i : IVAS decoder structure */ @@ -555,6 +1179,307 @@ void ivas_ls_setup_conversion( * Equalization in MDCT Domain *-------------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED +void ivas_ls_setup_conversion_process_mdct_fx( + Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */ + Word32 *output[] /* i/o: output synthesis signal */ +) +{ + /* Declaration of all required variables */ + Word16 i, bandIdx, chInIdx, chOutIdx, cpe_idx, subFrameIdx, binIdx, idx, j; + Word16 inChannels, outChannels, num_CPE; + Word16 transform_type[MAX_CICP_CHANNELS][2]; + Word16 frameSize; + Word32 targetEnergy[MAX_SFB + 2], dmxEnergy[MAX_SFB + 2]; + Word32 dmxCoeff; + Word32 dmxSignalReal[L_FRAME48k], dmxSignalImag[L_FRAME48k]; + Word32 eqGain; + Word32 *sig[NB_DIV], *pTmp[NB_DIV], *x[MAX_CICP_CHANNELS][NB_DIV]; + Word32 mdst[L_FRAME48k]; + Word32 convertRes[L_FRAME48k]; + Word16 start, stop, start_tcx5, stop_tcx5; + Word16 mct_chan_mode[MAX_CICP_CHANNELS]; + + /* Declare all handles */ + LSSETUP_CONVERSION_HANDLE hLsSetUpConversion; + CPE_DEC_HANDLE hCPE[MCT_MAX_BLOCKS]; + + push_wmops( "LS_Renderer_MDCT" ); + + /* Assign all the declared variables */ + inChannels = st_ivas->nchan_transport; + move16(); + outChannels = st_ivas->hDecoderConfig->nchan_out; + move16(); + num_CPE = st_ivas->nCPE; + move16(); + + /* Assign output pointer to variable x */ + + // Scale the array + Word16 q_output = 31; + FOR( i = 0; i < inChannels; ++i ) + { + q_output = s_min( q_output, L_norm_arr( output[i], L_FRAME48k ) ); + } + + Word16 tmp_sub = sub( st_ivas->hLsSetUpConversion->sfbOffset[st_ivas->hLsSetUpConversion->sfbCnt], st_ivas->hLsSetUpConversion->sfbOffset[st_ivas->hLsSetUpConversion->sfbCnt - 1] ); + Word16 guard_1 = shr( add( find_guarded_bits_fx( tmp_sub ), 1 ), 1 ); + Word16 guard_2 = find_guarded_bits_fx( L_mult0( outChannels, inChannels ) ); + q_output = sub( q_output, s_max( guard_1, guard_2 ) ); + + FOR( i = 0; i < inChannels; ++i ) + { + FOR( j = 0; j < L_FRAME48k; ++j ) + { + output[i][j] = L_shl( output[i][j], q_output ); + } + } + + FOR( chInIdx = 0; chInIdx < inChannels; chInIdx++ ) + { + x[chInIdx][0] = output[chInIdx]; + x[chInIdx][1] = output[chInIdx] + ( L_FRAME48k / 2 ); + } + + /* Assign all the declared handles*/ + hLsSetUpConversion = st_ivas->hLsSetUpConversion; + FOR( cpe_idx = 0; cpe_idx < num_CPE; cpe_idx++ ) + { + hCPE[cpe_idx] = st_ivas->hCPE[cpe_idx]; + } + + /* Get the core type */ + FOR( cpe_idx = 0; cpe_idx < num_CPE; cpe_idx++ ) + { + FOR( idx = 0; idx < CPE_CHANNELS; idx++ ) + { + /* get the channel index */ + chInIdx = add( imult1616( cpe_idx, CPE_CHANNELS ), idx ); + assert( LE_16( chInIdx, inChannels ) ); + transform_type[chInIdx][0] = hCPE[cpe_idx]->hCoreCoder[idx]->transform_type[0]; + move16(); + transform_type[chInIdx][1] = hCPE[cpe_idx]->hCoreCoder[idx]->transform_type[1]; + move16(); + mct_chan_mode[chInIdx] = hCPE[cpe_idx]->hCoreCoder[idx]->mct_chan_mode; + move16(); + } + } + + /* set overall frequency resolution of (sub)frame to maximum of (sub)frame, requires conversion if both channels are not the same */ + frameSize = hLsSetUpConversion->sfbOffset[hLsSetUpConversion->sfbCnt]; + move16(); + + set32_fx( targetEnergy, 0, MAX_SFB + 2 ); + set32_fx( dmxEnergy, 0, MAX_SFB + 2 ); + + FOR( chOutIdx = 0; chOutIdx < outChannels; chOutIdx++ ) + { + /* Step 0: Set the buffers to zero */ + set32_fx( dmxSignalReal, 0, frameSize ); + set32_fx( dmxSignalImag, 0, frameSize ); + + FOR( chInIdx = 0; chInIdx < inChannels; chInIdx++ ) + { + dmxCoeff = hLsSetUpConversion->dmxMtx_fx[chInIdx][chOutIdx]; + move32(); + + test(); + IF( + NE_16( chInIdx, LFE_CHANNEL ) && + NE_16( mct_chan_mode[chInIdx], MCT_CHAN_MODE_IGNORE ) ) + { + /* Step 1: Compute the target energy and DMX signal (possible since we have all signals in TCX20 resolution) */ + IF( dmxCoeff ) + { + Word32 tmpDMXSig, targetEne; + + /* Convert the signal resolution to TCX20 */ + /* initially, set pointers to input; if conversion occurs in (sub)frame, set to convertRes */ + sig[0] = pTmp[0] = x[chInIdx][0]; + sig[1] = pTmp[1] = x[chInIdx][1]; + + /* convert (sub)frames to higher frequency resolution */ + IF( NE_16( transform_type[chInIdx][0], TCX_20 ) ) + { + FOR( subFrameIdx = 0; subFrameIdx < NB_DIV; subFrameIdx++ ) + { + IF( EQ_16( transform_type[chInIdx][subFrameIdx], TCX_5 ) ) + { + /* subframe is TCX5, but TCX10 or TCX20 in other channel -> convert channel with TCX5 to TCX10 resolution */ + pTmp[subFrameIdx] = sig[subFrameIdx] = convertRes + subFrameIdx * frameSize / 2; + convert_coeffs_to_higher_res_fx( x[chInIdx][subFrameIdx], x[chInIdx][subFrameIdx] + frameSize / 4, pTmp[subFrameIdx], frameSize / 4 ); + } + } + + /* convert channel with TCX10 to TCX20 resolution */ + sig[0] = convertRes; + convert_coeffs_to_higher_res_fx( pTmp[0], pTmp[1], sig[0], frameSize / 2 ); + } + + /* MDST estimate */ + mdst[0] = mdst[frameSize - 1] = 0; + move32(); + move32(); + FOR( i = 1; i < frameSize - 1; i++ ) + { + mdst[i] = L_sub( sig[0][i + 1], sig[0][i - 1] ); + } + + FOR( bandIdx = 0; bandIdx < hLsSetUpConversion->sfbCnt; bandIdx++ ) + { + start = hLsSetUpConversion->sfbOffset[bandIdx]; + move16(); + stop = hLsSetUpConversion->sfbOffset[bandIdx + 1]; + move16(); + + targetEne = 0; + move32(); + + /* Loop over all the bins in the band */ + FOR( binIdx = start; binIdx < stop; binIdx++ ) + { + tmpDMXSig = Mpy_32_32( L_shl_sat( dmxCoeff, 1 ), sig[0][binIdx] ); + dmxSignalReal[binIdx] = L_add( dmxSignalReal[binIdx], tmpDMXSig ); + move32(); + targetEne = L_add( targetEne, Mpy_32_32( tmpDMXSig, tmpDMXSig ) ); + + tmpDMXSig = Mpy_32_32( L_shl_sat( dmxCoeff, 1 ), mdst[binIdx] ); + dmxSignalImag[binIdx] = L_add( dmxSignalImag[binIdx], tmpDMXSig ); + move32(); + targetEne = L_add( targetEne, Mpy_32_32( tmpDMXSig, tmpDMXSig ) ); + } + targetEnergy[bandIdx] = L_add( targetEnergy[bandIdx], targetEne ); + move32(); + } /* end of band loop */ + } + } + } /* end of chInIdx loop */ + + FOR( bandIdx = 0; bandIdx < hLsSetUpConversion->sfbCnt; bandIdx++ ) + { + Word32 tmpReal, tmpImag, DMXEne; + + start = hLsSetUpConversion->sfbOffset[bandIdx]; + move16(); + stop = hLsSetUpConversion->sfbOffset[bandIdx + 1]; + move16(); + + /* Loop over all the bins in the band */ + DMXEne = 0; + move32(); + FOR( binIdx = start; binIdx < stop; binIdx++ ) + { + tmpReal = dmxSignalReal[binIdx]; + move32(); + tmpImag = dmxSignalImag[binIdx]; + move32(); + + DMXEne = L_add( DMXEne, L_add( Mpy_32_32( tmpReal, tmpReal ), Mpy_32_32( tmpImag, tmpImag ) ) ); + } + dmxEnergy[bandIdx] = L_add( dmxEnergy[bandIdx], DMXEne ); + move32(); + } + } /* end of out channel loop */ + + /* Step 3: Peform energy smoothing */ + FOR( bandIdx = 0; bandIdx < hLsSetUpConversion->sfbCnt; bandIdx++ ) + { + targetEnergy[bandIdx] = L_add( Mpy_32_32( LS_OUT_CONV_SMOOTHING_FACTOR_Q31, targetEnergy[bandIdx] ), Mpy_32_32( L_sub( ONE_IN_Q31, LS_OUT_CONV_SMOOTHING_FACTOR_Q31 ), hLsSetUpConversion->targetEnergyPrev_fx[0][bandIdx] ) ); + move32(); + dmxEnergy[bandIdx] = L_add( Mpy_32_32( LS_OUT_CONV_SMOOTHING_FACTOR_Q31, dmxEnergy[bandIdx] ), Mpy_32_32( L_sub( ONE_IN_Q31, LS_OUT_CONV_SMOOTHING_FACTOR_Q31 ), hLsSetUpConversion->dmxEnergyPrev_fx[0][bandIdx] ) ); + move32(); + hLsSetUpConversion->targetEnergyPrev_fx[0][bandIdx] = targetEnergy[bandIdx]; + move32(); + hLsSetUpConversion->dmxEnergyPrev_fx[0][bandIdx] = dmxEnergy[bandIdx]; + move32(); + } + + FOR( i = 0; i < inChannels; ++i ) + { + FOR( j = 0; j < L_FRAME48k; ++j ) + { + output[i][j] = L_shr( output[i][j], q_output ); + } + } + + /* Step 4: Perform equalization */ + FOR( chInIdx = 0; chInIdx < inChannels; chInIdx++ ) + { + test(); + IF( + NE_16( chInIdx, LFE_CHANNEL ) && + NE_16( mct_chan_mode[chInIdx], MCT_CHAN_MODE_IGNORE ) ) + { + IF( EQ_16( transform_type[chInIdx][0], TCX_20 ) ) + { + /* TCX20 */ + FOR( bandIdx = 0; bandIdx < hLsSetUpConversion->sfbCnt; bandIdx++ ) + { + start = hLsSetUpConversion->sfbOffset[bandIdx]; + move16(); + stop = hLsSetUpConversion->sfbOffset[bandIdx + 1]; + move16(); + + /* Compute Eq gains */ + ivas_lssetupconversion_computeEQFactor_fx( &targetEnergy[bandIdx], &dmxEnergy[bandIdx], &eqGain ); + FOR( binIdx = start; binIdx < stop; binIdx++ ) + { + x[chInIdx][0][binIdx] = Mpy_32_32( L_shl( x[chInIdx][0][binIdx], 1 ), eqGain ); // Q - 1 + move32(); + } + } + } + ELSE + { + stop_tcx5 = 0; + move16(); + FOR( bandIdx = 0; bandIdx < hLsSetUpConversion->sfbCnt; bandIdx++ ) + { + start = shr( hLsSetUpConversion->sfbOffset[bandIdx], 1 ); + move16(); + stop = shr( hLsSetUpConversion->sfbOffset[bandIdx + 1], 1 ); + move16(); + + /* Compute Eq gains */ + ivas_lssetupconversion_computeEQFactor_fx( &targetEnergy[bandIdx], &dmxEnergy[bandIdx], &eqGain ); + + FOR( subFrameIdx = 0; subFrameIdx < NB_DIV; subFrameIdx++ ) + { + IF( EQ_16( transform_type[chInIdx][subFrameIdx], TCX_10 ) ) + { + /* TCX10 */ + FOR( binIdx = start; binIdx < stop; binIdx++ ) + { + x[chInIdx][subFrameIdx][binIdx] = Mpy_32_32( L_shl( x[chInIdx][subFrameIdx][binIdx], 1 ), eqGain ); + move32(); + } + } + ELSE + { + /* TCX5*/ + start_tcx5 = stop_tcx5; + move16(); + stop_tcx5 = shr( add( stop, 1 ), 1 ); + + FOR( binIdx = start_tcx5; binIdx < stop_tcx5; binIdx++ ) + { + x[chInIdx][subFrameIdx][binIdx] = Mpy_32_32( L_shl( x[chInIdx][subFrameIdx][binIdx], 1 ), eqGain ); + move32(); + x[chInIdx][subFrameIdx][binIdx + ( frameSize >> 2 )] = Mpy_32_32( L_shl( x[chInIdx][subFrameIdx][binIdx + ( frameSize >> 2 )], 1 ), eqGain ); + move32(); + } + } + } + } + } + } + } + + pop_wmops(); + return; +} +#endif void ivas_ls_setup_conversion_process_mdct( Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */ float *output[] /* i/o: output synthesis signal */ @@ -1128,6 +2053,179 @@ void ivas_ls_setup_conversion_process_mdct_param_mc( * LS setup conversion in the CLDFB domain for Parametric MC *-------------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED +void ivas_lssetupconversion_process_param_mc_fx( + Decoder_Struct *st_ivas, /* i/o: LS setup conversion renderer handle */ + const Word16 num_timeslots, + Word32 Cldfb_RealBuffer_InOut[MAX_CICP_CHANNELS][PARAM_MC_MAX_NSLOTS_IN_SUBFRAME][CLDFB_NO_CHANNELS_MAX], /* i/o: LS signals */ + Word32 Cldfb_ImagBuffer_InOut[MAX_CICP_CHANNELS][PARAM_MC_MAX_NSLOTS_IN_SUBFRAME][CLDFB_NO_CHANNELS_MAX], /* i/o: LS signals */ + Word16 channel_active[MAX_CICP_CHANNELS] /* i : bitmap indicating which output channels are active */ +) +{ + Word16 slotIdx, chOutIdx, chInIdx, bandIdx; + Word16 inChannels, outChannels; + Word32 targetEnergy[MAX_CICP_CHANNELS][CLDFB_NO_CHANNELS_MAX]; + Word32 dmxEnergy[MAX_CICP_CHANNELS][CLDFB_NO_CHANNELS_MAX]; + Word32 tmpDMXSig, dmxCoeff, tmpReal, tmpImag; + Word32 EQ; + Word32 Cldfb_RealBuffer_tmp[MAX_CICP_CHANNELS][CLDFB_NO_CHANNELS_MAX]; + Word32 Cldfb_ImagBuffer_tmp[MAX_CICP_CHANNELS][CLDFB_NO_CHANNELS_MAX]; + LSSETUP_CONVERSION_HANDLE hLsSetUpConversion; + Word16 i, j, k; + + push_wmops( "LS_Renderer_Process_Param_MC" ); + /* inits */ + inChannels = st_ivas->hIntSetup.nchan_out_woLFE + st_ivas->hIntSetup.num_lfe; + move16(); + outChannels = st_ivas->hOutSetup.nchan_out_woLFE + st_ivas->hOutSetup.num_lfe; + move16(); + + hLsSetUpConversion = st_ivas->hLsSetUpConversion; + EQ = 0; + move32(); + + set16_fx( channel_active, 0, outChannels ); + + /* Loop over each time slots and compute dmx for each time slot */ + FOR( slotIdx = 0; slotIdx < num_timeslots; slotIdx++ ) + { + // Scale the array + Word16 q_output = 31; + FOR( i = 0; i < inChannels; ++i ) + { + q_output = s_min( q_output, L_norm_arr( Cldfb_RealBuffer_InOut[i][slotIdx], hLsSetUpConversion->sfbCnt ) ); + q_output = s_min( q_output, L_norm_arr( Cldfb_ImagBuffer_InOut[i][slotIdx], hLsSetUpConversion->sfbCnt ) ); + } + + Word16 guard_1 = find_guarded_bits_fx( inChannels ); + q_output = sub( q_output, guard_1 ); + + FOR( i = 0; i < inChannels; ++i ) + { + FOR( k = 0; k < hLsSetUpConversion->sfbCnt; ++k ) + { + Cldfb_RealBuffer_InOut[i][slotIdx][k] = L_shl( Cldfb_RealBuffer_InOut[i][slotIdx][k], q_output ); + Cldfb_ImagBuffer_InOut[i][slotIdx][k] = L_shl( Cldfb_ImagBuffer_InOut[i][slotIdx][k], q_output ); + } + } + /* copy buffers */ + FOR( chInIdx = 0; chInIdx < inChannels; chInIdx++ ) + { + Copy32( Cldfb_RealBuffer_InOut[chInIdx][slotIdx], Cldfb_RealBuffer_tmp[chInIdx], CLDFB_NO_CHANNELS_MAX ); + Copy32( Cldfb_ImagBuffer_InOut[chInIdx][slotIdx], Cldfb_ImagBuffer_tmp[chInIdx], CLDFB_NO_CHANNELS_MAX ); + } + /* set the buffers to zero */ + FOR( chOutIdx = 0; chOutIdx < outChannels; chOutIdx++ ) + { + set32_fx( Cldfb_RealBuffer_InOut[chOutIdx][slotIdx], 0, CLDFB_NO_CHANNELS_MAX ); + set32_fx( Cldfb_ImagBuffer_InOut[chOutIdx][slotIdx], 0, CLDFB_NO_CHANNELS_MAX ); + + set32_fx( dmxEnergy[chOutIdx], 0, CLDFB_NO_CHANNELS_MAX ); + set32_fx( targetEnergy[chOutIdx], 0, CLDFB_NO_CHANNELS_MAX ); + } + + /* Compute the target energy and DMX signal */ + FOR( chOutIdx = 0; chOutIdx < outChannels; chOutIdx++ ) + { + FOR( chInIdx = 0; chInIdx < inChannels; chInIdx++ ) + { + dmxCoeff = hLsSetUpConversion->dmxMtx_fx[chInIdx][chOutIdx]; + move32(); + IF( EQ_32( dmxCoeff, 0 ) ) + { + CONTINUE; + } + ELSE + { + channel_active[chOutIdx] |= 1; + FOR( bandIdx = 0; bandIdx < hLsSetUpConversion->sfbCnt; bandIdx++ ) + { + tmpDMXSig = Mpy_32_32( L_shl_sat( dmxCoeff, 1 ), Cldfb_RealBuffer_tmp[chInIdx][bandIdx] ); + Cldfb_RealBuffer_InOut[chOutIdx][slotIdx][bandIdx] = L_add( Cldfb_RealBuffer_InOut[chOutIdx][slotIdx][bandIdx], tmpDMXSig ); + move32(); + targetEnergy[chOutIdx][bandIdx] = L_add( targetEnergy[chOutIdx][bandIdx], Mpy_32_32( tmpDMXSig, tmpDMXSig ) ); + move32(); + + tmpDMXSig = Mpy_32_32( L_shl_sat( dmxCoeff, 1 ), Cldfb_ImagBuffer_tmp[chInIdx][bandIdx] ); + Cldfb_ImagBuffer_InOut[chOutIdx][slotIdx][bandIdx] = L_add( Cldfb_ImagBuffer_InOut[chOutIdx][slotIdx][bandIdx], tmpDMXSig ); + move32(); + targetEnergy[chOutIdx][bandIdx] = L_add( targetEnergy[chOutIdx][bandIdx], Mpy_32_32( tmpDMXSig, tmpDMXSig ) ); + move32(); + } + } + } + } + + /* Compute the DMX energy */ + FOR( chOutIdx = 0; chOutIdx < outChannels; chOutIdx++ ) + { + IF( channel_active[chOutIdx] ) + { + FOR( bandIdx = 0; bandIdx < hLsSetUpConversion->sfbCnt; bandIdx++ ) + { + tmpReal = Cldfb_RealBuffer_InOut[chOutIdx][slotIdx][bandIdx]; + move32(); + tmpImag = Cldfb_ImagBuffer_InOut[chOutIdx][slotIdx][bandIdx]; + move32(); + + dmxEnergy[chOutIdx][bandIdx] = L_add( Mpy_32_32( tmpReal, tmpReal ), Mpy_32_32( tmpImag, tmpImag ) ); + move32(); + } + } + } + + /* Peform energy smoothing */ + FOR( chOutIdx = 0; chOutIdx < outChannels; chOutIdx++ ) + { + IF( channel_active[chOutIdx] ) + { + FOR( bandIdx = 0; bandIdx < hLsSetUpConversion->sfbCnt; bandIdx++ ) + { + targetEnergy[chOutIdx][bandIdx] = L_add( Mpy_32_32( LS_OUT_CONV_SMOOTHING_FACTOR_Q31, targetEnergy[chOutIdx][bandIdx] ), Mpy_32_32( L_sub( ONE_IN_Q31, LS_OUT_CONV_SMOOTHING_FACTOR_Q31 ), hLsSetUpConversion->targetEnergyPrev_fx[chOutIdx][bandIdx] ) ); + move32(); + dmxEnergy[chOutIdx][bandIdx] = L_add( Mpy_32_32( LS_OUT_CONV_SMOOTHING_FACTOR_Q31, dmxEnergy[chOutIdx][bandIdx] ), Mpy_32_32( L_sub( ONE_IN_Q31, LS_OUT_CONV_SMOOTHING_FACTOR_Q31 ), hLsSetUpConversion->dmxEnergyPrev_fx[chOutIdx][bandIdx] ) ); + move32(); + hLsSetUpConversion->targetEnergyPrev_fx[chOutIdx][bandIdx] = targetEnergy[chOutIdx][bandIdx]; + move32(); + hLsSetUpConversion->dmxEnergyPrev_fx[chOutIdx][bandIdx] = dmxEnergy[chOutIdx][bandIdx]; + move32(); + } + } + } + + FOR( i = 0; i < outChannels; ++i ) + { + FOR( k = 0; k < hLsSetUpConversion->sfbCnt; ++k ) + { + Cldfb_RealBuffer_InOut[i][slotIdx][k] = L_shr( Cldfb_RealBuffer_InOut[i][slotIdx][k], q_output ); + move32(); + Cldfb_ImagBuffer_InOut[i][slotIdx][k] = L_shr( Cldfb_ImagBuffer_InOut[i][slotIdx][k], q_output ); + move32(); + } + } + + /* Compute and perform equalization */ + FOR( chOutIdx = 0; chOutIdx < outChannels; chOutIdx++ ) + { + IF( channel_active[chOutIdx] ) + { + FOR( bandIdx = 0; bandIdx < hLsSetUpConversion->sfbCnt; bandIdx++ ) + { + ivas_lssetupconversion_computeEQFactor_fx( &targetEnergy[chOutIdx][bandIdx], &dmxEnergy[chOutIdx][bandIdx], &EQ ); + Cldfb_RealBuffer_InOut[chOutIdx][slotIdx][bandIdx] = Mpy_32_32( L_shl( Cldfb_RealBuffer_InOut[chOutIdx][slotIdx][bandIdx], 1 ), EQ ); + move32(); + Cldfb_ImagBuffer_InOut[chOutIdx][slotIdx][bandIdx] = Mpy_32_32( L_shl( Cldfb_ImagBuffer_InOut[chOutIdx][slotIdx][bandIdx], 1 ), EQ ); + move32(); + } + } + } + } + + pop_wmops(); + return; +} +#endif + void ivas_lssetupconversion_process_param_mc( Decoder_Struct *st_ivas, /* i/o: LS setup conversion renderer handle */ const int16_t num_timeslots, @@ -1181,7 +2279,7 @@ void ivas_lssetupconversion_process_param_mc( for ( chInIdx = 0; chInIdx < inChannels; chInIdx++ ) { dmxCoeff = hLsSetUpConversion->dmxMtx[chInIdx][chOutIdx]; - if ( dmxCoeff == 0.0f ) + if ( dmxCoeff == 0 ) { continue; } diff --git a/lib_dec/ivas_stereo_mdct_core_dec.c b/lib_dec/ivas_stereo_mdct_core_dec.c index cdb3572f6..fb72af1d6 100644 --- a/lib_dec/ivas_stereo_mdct_core_dec.c +++ b/lib_dec/ivas_stereo_mdct_core_dec.c @@ -62,6 +62,47 @@ static void run_min_stats( Decoder_State **sts, float *x[CPE_CHANNELS][NB_DIV] ) * by applying high- and lowpass filters to subdivide bins *-------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED +#define POINT_5_Q31 ONE_IN_Q30 + +void convert_coeffs_to_higher_res_fx( + const Word32 *in1, /* i : first subframe input */ + const Word32 *in2, /* i : second subframe input */ + Word32 *out, /* o : converted output */ + const Word16 len /* i : length of subframes */ +) +{ + Word16 i; + Word32 tmp1, tmp2; + + IF( in1 == out ) + { + FOR( i = 0; i < len; i += 2 ) + { + tmp1 = Mpy_32_32( POINT_5_Q31, ( L_add( in2[i], in1[i] ) ) ); + tmp2 = Mpy_32_32( POINT_5_Q31, ( L_sub( in2[i], in1[i] ) ) ); + out[2 * i] = tmp1; + out[2 * i + 1] = tmp2; + tmp1 = Mpy_32_32( POINT_5_Q31, ( L_sub( in2[i], in1[i] ) ) ); + tmp2 = Mpy_32_32( POINT_5_Q31, ( L_add( in2[i], in1[i] ) ) ); + out[2 * i + 2] = tmp1; + out[2 * i + 3] = tmp2; + } + } + ELSE + { + FOR( i = 0; i < len; i += 2 ) + { + out[2 * i] = Mpy_32_32( POINT_5_Q31, ( L_add( in2[i], in1[i] ) ) ); + out[2 * i + 1] = Mpy_32_32( POINT_5_Q31, ( L_sub( in2[i], in1[i] ) ) ); + out[2 * i + 2] = Mpy_32_32( POINT_5_Q31, ( L_sub( in2[i + 1], in1[i + 1] ) ) ); + out[2 * i + 3] = Mpy_32_32( POINT_5_Q31, ( L_add( in2[i + 1], in1[i + 1] ) ) ); + } + } + + return; +} +#endif void convert_coeffs_to_higher_res( const float *in1, /* i : first subframe input */ const float *in2, /* i : second subframe input */ diff --git a/lib_rend/ivas_rom_rend.c b/lib_rend/ivas_rom_rend.c index abddd6399..92eb19cdb 100644 --- a/lib_rend/ivas_rom_rend.c +++ b/lib_rend/ivas_rom_rend.c @@ -852,6 +852,355 @@ const float ls_elevation_CICP1[1] = { 0.0f }; * LS Renderer ROM tables *----------------------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED + /* All matrices are stored with dimensions nchan_in x nchan_out */ + /* Downmix matrices */ +const Word32 ls_conversion_cicpX_mono_fx[12][1] = // Q30 +{ + {1073741824}, + {1073741824}, + {1073741824}, + {1073741824}, + {858993408}, + {858993408}, + {858993408}, + {858993408}, + {912680512}, + {912680512}, + {912680512}, + {912680512} +}; + +const Word32 ls_conversion_cicpX_stereo_fx[12][2] = // Q30 +{ + {1073741824, 0}, + {0, 1073741824}, + {759250112, 759250112}, + {759250112, 759250112}, + {858993408, 0}, + {0, 858993408}, + {858993408, 0}, + {0, 858993408}, + {858993408, 0}, + {0, 858993408}, + {858993408, 0}, + {0, 858993408} +}; + +const LS_CONVERSION_MATRIX_FX ls_conversion_cicp12_cicp6_fx[] = // Q30 +{ + /* First row indicates the number of non-zero elements and the number of matrix columns */ + {8, 6}, + /* Index of non-zero element, value of non-zero element*/ + {0, 1073741824}, + {7, 1073741824}, + {14, 1073741824}, + {21, 1073741824}, + {28, 1073741824}, + {35, 1073741824}, + {40, 1073741824}, + {47, 1073741824} +}; + +const LS_CONVERSION_MATRIX_FX ls_conversion_cicp14_cicp6_fx[] = // Q30 +{ + /* First row indicates the number of non-zero elements and the number of matrix columns */ + {8, 6}, + /* Index of non-zero element, value of non-zero element*/ + {0, 1073741824}, + {7, 1073741824}, + {14, 1073741824}, + {21, 1073741824}, + {28, 1073741824}, + {35, 1073741824}, + {36, 912680512}, + {43, 912680512} +}; + +const LS_CONVERSION_MATRIX_FX ls_conversion_cicp14_cicp12_fx[] = // Q30 +{ + /* First row indicates the number of non-zero elements and the number of matrix columns */ + {8, 8}, + /* Index of non-zero element, value of non-zero element*/ + {0, 1073741824}, + {9, 1073741824}, + {18, 1073741824}, + {27, 1073741824}, + {36, 1073741824}, + {45, 1073741824}, + {48, 912680512}, + {57, 912680512} +}; + +const LS_CONVERSION_MATRIX_FX ls_conversion_cicp16_cicp6_fx[] = // Q30 +{ + /* First row indicates the number of non-zero elements and the number of matrix columns */ + {10, 6}, + /* Index of non-zero element, value of non-zero element*/ + {0, 1073741824}, + {7, 1073741824}, + {14, 1073741824}, + {21, 1073741824}, + {28, 1073741824}, + {35, 1073741824}, + {36, 912680512}, + {43, 912680512}, + {52, 912680512}, + {59, 912680512} +}; + +const LS_CONVERSION_MATRIX_FX ls_conversion_cicp16_cicp12_fx[] = // Q30 +{ + /* First row indicates the number of non-zero elements and the number of matrix columns */ + {10, 8}, + /* Index of non-zero element, value of non-zero element*/ + {0, 1073741824}, + {9, 1073741824}, + {18, 1073741824}, + {27, 1073741824}, + {36, 1073741824}, + {45, 1073741824}, + {48, 912680512}, + {57, 912680512}, + {68, 912680512}, + {77, 912680512} +}; + +const LS_CONVERSION_MATRIX_FX ls_conversion_cicp16_cicp14_fx[] = // Q30 +{ + /* First row indicates the number of non-zero elements and the number of matrix columns */ + {10, 8}, + /* Index of non-zero element, value of non-zero element*/ + {0, 1073741824}, + {9, 1073741824}, + {18, 1073741824}, + {27, 1073741824}, + {36, 1073741824}, + {45, 1073741824}, + {54, 1073741824}, + {63, 1073741824}, + {68, 912680512}, + {77, 912680512}, +}; + +const LS_CONVERSION_MATRIX_FX ls_conversion_cicp19_cicp6_fx[] = // Q30 +{ + /* First row indicates the number of non-zero elements and the number of matrix columns */ + {14, 6}, + /* Index of non-zero element, value of non-zero element*/ + {0, 1073741824}, + {7, 1073741824}, + {14, 1073741824}, + {21, 1073741824}, + {28, 1073741824}, + {35, 1073741824}, + {36, 394409728}, + {40, 998680384}, + {43, 394409728}, + {47, 998680384}, + {48, 912680512}, + {55, 912680512}, + {64, 912680512}, + {71, 912680512} +}; + +const LS_CONVERSION_MATRIX_FX ls_conversion_cicp19_cicp12_fx[] = // Q30 +{ + /* First row indicates the number of non-zero elements and the number of matrix columns */ + {14, 8}, + /* Index of non-zero element, value of non-zero element*/ + {0, 1073741824}, + {9, 1073741824}, + {18, 1073741824}, + {27, 1073741824}, + {38, 1073741824}, + {47, 1073741824}, + {48, 394409728}, + {52, 998680384}, + {57, 394409728}, + {61, 998680384}, + {64, 912680512}, + {73, 912680512}, + {84, 912680512}, + {93, 912680512} +}; + +const LS_CONVERSION_MATRIX_FX ls_conversion_cicp19_cicp14_fx[] = // Q30 +{ + /* First row indicates the number of non-zero elements and the number of matrix columns */ + {14, 8}, + /* Index of non-zero element, value of non-zero element*/ + {0, 1073741824}, + {9, 1073741824}, + {18, 1073741824}, + {27, 1073741824}, + {36, 1073741824}, + {45, 1073741824}, + {48, 394409728}, + {52, 998680384}, + {57, 394409728}, + {61, 998680384}, + {70, 1073741824}, + {79, 1073741824}, + {84, 912680512}, + {93, 912680512} +}; + +const LS_CONVERSION_MATRIX_FX ls_conversion_cicp19_cicp16_fx[] = // Q30 +{ + /* First row indicates the number of non-zero elements and the number of matrix columns */ + {14, 10}, + /* Index of non-zero element, value of non-zero element*/ + {0, 1073741824}, + {11, 1073741824}, + {22, 1073741824}, + {33, 1073741824}, + {44, 1073741824}, + {55, 1073741824}, + {60, 394409728}, + {64, 998680384}, + {71, 394409728}, + {75, 998680384}, + {86, 1073741824}, + {97, 1073741824}, + {108, 1073741824}, + {119, 1073741824} +}; + +/* Upmix matrices */ +const LS_CONVERSION_MATRIX_FX ls_conversion_cicp12_cicp14_fx[] = // Q30 +{ + /* First row indicates the number of non-zero elements and the number of matrix columns */ + {8, 8}, + /* Index of non-zero element, value of non-zero element*/ + {0, 1073741824}, + {9, 1073741824}, + {18, 1073741824}, + {27, 1073741824}, + {36, 1073741824}, + {45, 1073741824}, + {52, 1073741824}, + {61, 1073741824} +}; + +const LS_CONVERSION_MATRIX_FX ls_conversion_cicp12_cicp16_fx[] = // Q30 +{ + /* First row indicates the number of non-zero elements and the number of matrix columns */ + {8, 10}, + /* Index of non-zero element, value of non-zero element*/ + {0, 1073741824}, + {11, 1073741824}, + {22, 1073741824}, + {33, 1073741824}, + {44, 1073741824}, + {55, 1073741824}, + {64, 1073741824}, + {75, 1073741824} +}; + +const LS_CONVERSION_MATRIX_FX ls_conversion_cicp12_cicp19_fx[] = // Q30 +{ + /* First row indicates the number of non-zero elements and the number of matrix columns */ + {8, 12}, + /* Index of non-zero element, value of non-zero element*/ + {0, 1073741824}, + {13, 1073741824}, + {26, 1073741824}, + {39, 1073741824}, + {54, 1073741824}, + {67, 1073741824}, + {76, 1073741824}, + {89, 1073741824} +}; + +const LS_CONVERSION_MATRIX_FX ls_conversion_cicp14_cicp19_fx[] = // Q30 +{ + /* First row indicates the number of non-zero elements and the number of matrix columns */ + {8, 12}, + /* Index of non-zero element, value of non-zero element*/ + {0, 1073741824}, + {13, 1073741824}, + {26, 1073741824}, + {39, 1073741824}, + {52, 1073741824}, + {65, 1073741824}, + {80, 1073741824}, + {93, 1073741824} +}; + +const LS_CONVERSION_MATRIX_FX ls_conversion_cicp16_cicp19_fx[] = // Q30 +{ + /* First row indicates the number of non-zero elements and the number of matrix columns */ + {10, 12}, + /* Index of non-zero element, value of non-zero element*/ + {0, 1073741824}, + {13, 1073741824}, + {26, 1073741824}, + {39, 1073741824}, + {52, 1073741824}, + {65, 1073741824}, + {80, 1073741824}, + {93, 1073741824}, + {106, 1073741824}, + {119, 1073741824} +}; + +/* + * Mapping table of input config : output config with corresponding matrix + * NULL indicates a 1:1 mapping of existing input channels to output channels ( used for upmix ) + */ + +const LS_CONVERSION_MAPPING_FX ls_conversion_mapping_fx[LS_SETUP_CONVERSION_NUM_MAPPINGS] = +{ + /* Dowmix mappings - NULL is a special case for MONO / STEREO downmix */ + {IVAS_AUDIO_CONFIG_5_1, IVAS_AUDIO_CONFIG_MONO, NULL}, + {IVAS_AUDIO_CONFIG_7_1, IVAS_AUDIO_CONFIG_MONO, NULL}, + {IVAS_AUDIO_CONFIG_5_1_2, IVAS_AUDIO_CONFIG_MONO, NULL}, + {IVAS_AUDIO_CONFIG_5_1_4, IVAS_AUDIO_CONFIG_MONO, NULL}, + {IVAS_AUDIO_CONFIG_7_1_4, IVAS_AUDIO_CONFIG_MONO, NULL}, + + {IVAS_AUDIO_CONFIG_5_1, IVAS_AUDIO_CONFIG_STEREO, NULL}, + {IVAS_AUDIO_CONFIG_7_1, IVAS_AUDIO_CONFIG_STEREO, NULL}, + {IVAS_AUDIO_CONFIG_5_1_2, IVAS_AUDIO_CONFIG_STEREO, NULL}, + {IVAS_AUDIO_CONFIG_5_1_4, IVAS_AUDIO_CONFIG_STEREO, NULL}, + {IVAS_AUDIO_CONFIG_7_1_4, IVAS_AUDIO_CONFIG_STEREO, NULL}, + + {IVAS_AUDIO_CONFIG_7_1, IVAS_AUDIO_CONFIG_5_1, ls_conversion_cicp12_cicp6_fx}, + + {IVAS_AUDIO_CONFIG_5_1_2, IVAS_AUDIO_CONFIG_5_1, ls_conversion_cicp14_cicp6_fx}, + {IVAS_AUDIO_CONFIG_5_1_2, IVAS_AUDIO_CONFIG_7_1, ls_conversion_cicp14_cicp12_fx}, + + {IVAS_AUDIO_CONFIG_5_1_4, IVAS_AUDIO_CONFIG_5_1, ls_conversion_cicp16_cicp6_fx}, + {IVAS_AUDIO_CONFIG_5_1_4, IVAS_AUDIO_CONFIG_7_1, ls_conversion_cicp16_cicp12_fx}, + {IVAS_AUDIO_CONFIG_5_1_4, IVAS_AUDIO_CONFIG_5_1_2, ls_conversion_cicp16_cicp14_fx}, + + {IVAS_AUDIO_CONFIG_7_1_4, IVAS_AUDIO_CONFIG_5_1, ls_conversion_cicp19_cicp6_fx}, + {IVAS_AUDIO_CONFIG_7_1_4, IVAS_AUDIO_CONFIG_7_1, ls_conversion_cicp19_cicp12_fx}, + {IVAS_AUDIO_CONFIG_7_1_4, IVAS_AUDIO_CONFIG_5_1_2, ls_conversion_cicp19_cicp14_fx}, + {IVAS_AUDIO_CONFIG_7_1_4, IVAS_AUDIO_CONFIG_5_1_4, ls_conversion_cicp19_cicp16_fx}, + + /* Upmix mappings - NULL implies a 1:1 upmix */ + {IVAS_AUDIO_CONFIG_STEREO, IVAS_AUDIO_CONFIG_5_1, NULL}, + {IVAS_AUDIO_CONFIG_STEREO, IVAS_AUDIO_CONFIG_7_1, NULL}, + {IVAS_AUDIO_CONFIG_STEREO, IVAS_AUDIO_CONFIG_5_1_2, NULL}, + {IVAS_AUDIO_CONFIG_STEREO, IVAS_AUDIO_CONFIG_5_1_4, NULL}, + {IVAS_AUDIO_CONFIG_STEREO, IVAS_AUDIO_CONFIG_7_1_4, NULL}, + + {IVAS_AUDIO_CONFIG_5_1, IVAS_AUDIO_CONFIG_7_1, NULL}, + {IVAS_AUDIO_CONFIG_5_1, IVAS_AUDIO_CONFIG_5_1_2, NULL}, + {IVAS_AUDIO_CONFIG_5_1, IVAS_AUDIO_CONFIG_5_1_4, NULL}, + {IVAS_AUDIO_CONFIG_5_1, IVAS_AUDIO_CONFIG_7_1_4, NULL}, + + {IVAS_AUDIO_CONFIG_7_1, IVAS_AUDIO_CONFIG_5_1_2, ls_conversion_cicp12_cicp14_fx}, + {IVAS_AUDIO_CONFIG_7_1, IVAS_AUDIO_CONFIG_5_1_4, ls_conversion_cicp12_cicp16_fx}, + {IVAS_AUDIO_CONFIG_7_1, IVAS_AUDIO_CONFIG_7_1_4, ls_conversion_cicp12_cicp19_fx}, + + {IVAS_AUDIO_CONFIG_5_1_2, IVAS_AUDIO_CONFIG_5_1_4, NULL}, + {IVAS_AUDIO_CONFIG_5_1_2, IVAS_AUDIO_CONFIG_7_1_4, ls_conversion_cicp14_cicp19_fx}, + + {IVAS_AUDIO_CONFIG_5_1_4, IVAS_AUDIO_CONFIG_7_1_4, ls_conversion_cicp16_cicp19_fx}, +}; +#endif /* All matrices are stored with dimensions nchan_in x nchan_out */ /* Downmix matrices */ const float ls_conversion_cicpX_mono[12][1] = diff --git a/lib_rend/ivas_rom_rend.h b/lib_rend/ivas_rom_rend.h index 08427af9e..0f9b43177 100644 --- a/lib_rend/ivas_rom_rend.h +++ b/lib_rend/ivas_rom_rend.h @@ -106,18 +106,18 @@ extern const float defaultHRIR_left_avg_power_16kHz[LR_IAC_LENGTH_NR_FC]; extern const float defaultHRIR_right_avg_power_16kHz[LR_IAC_LENGTH_NR_FC]; #ifdef IVAS_FLOAT_FIXED -extern const UWord16 defaultHRIR_coherence_48kHz_fx[LR_IAC_LENGTH_NR_FC];/*Q-15*/ -extern const UWord16 defaultHRIR_left_avg_power_48kHz_fx[LR_IAC_LENGTH_NR_FC];/*Q-15*/ -extern const UWord16 defaultHRIR_right_avg_power_48kHz_fx[LR_IAC_LENGTH_NR_FC];/*Q-15*/ - -extern const UWord16 defaultHRIR_coherence_32kHz_fx[LR_IAC_LENGTH_NR_FC];/*Q-15*/ -extern const UWord16 defaultHRIR_left_avg_power_32kHz_fx[LR_IAC_LENGTH_NR_FC];/*Q-15*/ -extern const UWord16 defaultHRIR_right_avg_power_32kHz_fx[LR_IAC_LENGTH_NR_FC];/*Q-15*/ - -extern const UWord16 defaultHRIR_coherence_16kHz_fx[LR_IAC_LENGTH_NR_FC];/*Q-15*/ -extern const UWord16 defaultHRIR_left_avg_power_16kHz_fx[LR_IAC_LENGTH_NR_FC];/*Q-15*/ -extern const UWord16 defaultHRIR_right_avg_power_16kHz_fx[LR_IAC_LENGTH_NR_FC];/*Q-15*/ -#endif // IVAS_FLOAT_FIXED +extern const UWord16 defaultHRIR_coherence_48kHz_fx[LR_IAC_LENGTH_NR_FC]; /*Q-15*/ +extern const UWord16 defaultHRIR_left_avg_power_48kHz_fx[LR_IAC_LENGTH_NR_FC]; /*Q-15*/ +extern const UWord16 defaultHRIR_right_avg_power_48kHz_fx[LR_IAC_LENGTH_NR_FC]; /*Q-15*/ + +extern const UWord16 defaultHRIR_coherence_32kHz_fx[LR_IAC_LENGTH_NR_FC]; /*Q-15*/ +extern const UWord16 defaultHRIR_left_avg_power_32kHz_fx[LR_IAC_LENGTH_NR_FC]; /*Q-15*/ +extern const UWord16 defaultHRIR_right_avg_power_32kHz_fx[LR_IAC_LENGTH_NR_FC]; /*Q-15*/ + +extern const UWord16 defaultHRIR_coherence_16kHz_fx[LR_IAC_LENGTH_NR_FC]; /*Q-15*/ +extern const UWord16 defaultHRIR_left_avg_power_16kHz_fx[LR_IAC_LENGTH_NR_FC]; /*Q-15*/ +extern const UWord16 defaultHRIR_right_avg_power_16kHz_fx[LR_IAC_LENGTH_NR_FC]; /*Q-15*/ +#endif // IVAS_FLOAT_FIXED /*----------------------------------------------------------------------------------* * t-design and SN3D normalization table *----------------------------------------------------------------------------------*/ @@ -159,10 +159,16 @@ extern const float ls_elevation_CICP1[1]; /* Downmix matrices */ extern const float ls_conversion_cicpX_mono[12][1]; extern const float ls_conversion_cicpX_stereo[12][2]; +#ifdef IVAS_FLOAT_FIXED +extern const Word32 ls_conversion_cicpX_mono_fx[12][1]; +extern const Word32 ls_conversion_cicpX_stereo_fx[12][2]; +#endif /* Mapping table of input config : output config with corresponding matrix */ extern const LS_CONVERSION_MAPPING ls_conversion_mapping[]; - +#ifdef IVAS_FLOAT_FIXED +extern const LS_CONVERSION_MAPPING_FX ls_conversion_mapping_fx[]; +#endif #endif /* IVAS_ROM_REND_H */ diff --git a/lib_rend/ivas_stat_rend.h b/lib_rend/ivas_stat_rend.h index b3698aabe..817a35fa2 100644 --- a/lib_rend/ivas_stat_rend.h +++ b/lib_rend/ivas_stat_rend.h @@ -1789,13 +1789,31 @@ typedef struct typedef struct ivas_LS_setupconversion_struct { float *dmxMtx[MAX_OUTPUT_CHANNELS]; + Word32 *dmxMtx_fx[MAX_OUTPUT_CHANNELS]; // Q30 float *targetEnergyPrev[MAX_OUTPUT_CHANNELS]; + Word32 *targetEnergyPrev_fx[MAX_OUTPUT_CHANNELS]; float *dmxEnergyPrev[MAX_OUTPUT_CHANNELS]; + Word32 *dmxEnergyPrev_fx[MAX_OUTPUT_CHANNELS]; int16_t sfbOffset[MAX_SFB + 2]; int16_t sfbCnt; } LSSETUP_CONVERSION_STRUCT, *LSSETUP_CONVERSION_HANDLE; +#ifdef IVAS_FLOAT_FIXED +typedef struct ivas_LS_setupconversion_matrix_fx +{ + int16_t index; + Word32 value; +} LS_CONVERSION_MATRIX_FX; + +typedef struct ivas_LS_setupconversion_mapping_fx +{ + AUDIO_CONFIG input_config; + AUDIO_CONFIG output_config; + const LS_CONVERSION_MATRIX_FX *conversion_matrix_fx; +} LS_CONVERSION_MAPPING_FX; +#endif + typedef struct ivas_LS_setupconversion_matrix { int16_t index; -- GitLab