From 0b7b4432d4aeb816be36272cf855beaaac1b7d97 Mon Sep 17 00:00:00 2001 From: Sandesh Venkatesh Date: Thu, 1 Feb 2024 14:26:52 +0530 Subject: [PATCH] Ported functions in ivas_ism_renderer.c file [x] Ported ivas_jbm_dec_get_adapted_linear_interpolator, ivas_ism_render_sf, ivas_ism_renderer_open, vbap_determine_gains, vector_matrix_multiply_3x3, determine_best_triplet_and_gains, ivas_ism_renderer_close, ivas_omasa_separate_object_render_jbm, ivas_omasa_separate_object_renderer_close, ivas_omasa_separate_object_renderer_open, ivas_ism_get_stereo_gains, ivas_omasa_separate_object_render_jbm functions. [x] Added fix for assert failures in renderer smoke test. --- lib_com/ivas_omasa_com.c | 7 +- lib_com/ivas_prot.h | 2 +- lib_com/ivas_prot_fx.h | 38 +++ lib_com/ivas_rom_com.c | 14 - lib_com/ivas_rom_com.h | 14 - lib_com/ivas_rom_com_fx.c | 22 ++ lib_com/ivas_rom_com_fx.h | 14 + lib_com/ivas_spar_com.c | 2 +- lib_com/ivas_stat_com.h | 10 +- lib_dec/ivas_init_dec.c | 41 +++ lib_dec/ivas_ism_dec.c | 21 ++ lib_dec/ivas_ism_param_dec.c | 7 + lib_dec/ivas_ism_renderer.c | 613 ++++++++++++++++++++++++++++++++++- lib_dec/ivas_jbm_dec.c | 280 +++++++++++++++- lib_dec/ivas_ls_custom_dec.c | 15 +- lib_dec/ivas_omasa_dec.c | 188 +++++++++++ lib_dec/ivas_sba_dec.c | 20 ++ lib_dec/ivas_stat_dec.h | 16 +- lib_rend/ivas_omasa_ana.c | 9 +- lib_rend/ivas_orient_trk.c | 6 +- lib_rend/ivas_output_init.c | 29 ++ lib_rend/ivas_prot_rend.h | 9 + lib_rend/ivas_stat_rend.h | 29 +- lib_rend/ivas_vbap.c | 348 ++++++++++++++++++++ lib_rend/lib_rend.c | 15 +- 25 files changed, 1706 insertions(+), 63 deletions(-) diff --git a/lib_com/ivas_omasa_com.c b/lib_com/ivas_omasa_com.c index b98e6e302..d04ce0c12 100644 --- a/lib_com/ivas_omasa_com.c +++ b/lib_com/ivas_omasa_com.c @@ -34,6 +34,7 @@ #include #include "ivas_cnst.h" #include "ivas_prot.h" +#include "ivas_prot_fx.h" #include "prot.h" #include "prot_fx1.h" #include "ivas_rom_com.h" @@ -1011,7 +1012,7 @@ void ivas_get_stereo_panning_gains( #define SIN_NEG_30_DEGREES_Q15 ( (Word16) 0xC000 ) #define SIN_30_DEGREES_Q15 ( (Word16) 0x4000 ) -static void get_panning_gain( +void get_panning_gain( const Word16 sinAngleMapped, Word16 *panningGains ) { @@ -1121,10 +1122,10 @@ void ivas_get_stereo_panning_gains_fx( } WHILE( LT_16( azSubEl, -180 ) ) { - azSubEl = sub( azSubEl, 360 ); + azSubEl = add( azSubEl, 360 ); } // sin_az_cos_el = (ptr_sin_az[azAddEl] + ptr_sin_az[azSubEl])/2; - Word16 sin_az_cos_el = extract_l( L_shr( L_add( L_deposit_l( ptr_sin_az[azAddEl] ), L_deposit_l( ptr_sin_az[azSubEl] ) ), 1 ) ); + Word16 sin_az_cos_el = extract_l( L_shr( L_add( L_deposit_l( ptr_sin_az[azAddEl + 180] ), L_deposit_l( ptr_sin_az[azSubEl + 180] ) ), 1 ) ); IF( GE_16( sin_az_cos_el, SIN_30_DEGREES_Q15 ) ) { /* Left side */ diff --git a/lib_com/ivas_prot.h b/lib_com/ivas_prot.h index c5b72e895..a3251fff8 100644 --- a/lib_com/ivas_prot.h +++ b/lib_com/ivas_prot.h @@ -5531,7 +5531,7 @@ ivas_error ivas_ls_custom_output_init( void ivas_ls_custom_setup( IVAS_OUTPUT_SETUP_HANDLE hOutSetup, /* o : IVAS output setup handle */ - const LSSETUP_CUSTOM_STRUCT *hLsSetupCustom /* i : Custom loudspeaker setup handle */ + LSSETUP_CUSTOM_STRUCT *hLsSetupCustom /* i : Custom loudspeaker setup handle */ ); diff --git a/lib_com/ivas_prot_fx.h b/lib_com/ivas_prot_fx.h index f16dfa1b1..3857939d0 100644 --- a/lib_com/ivas_prot_fx.h +++ b/lib_com/ivas_prot_fx.h @@ -740,4 +740,42 @@ ivas_error ivas_ls_custom_output_init_fx( ivas_error ivas_ls_custom_open_fx( LSSETUP_CUSTOM_HANDLE *hLsSetupCustom /* o : Custom loudspeaker setup handle */ ); + +ivas_error ivas_ism_renderer_open_fx( + Decoder_Struct *st_ivas /* i/o: IVAS decoder structure */ +); + +void ivas_ism_render_sf_fx( + Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */ + Word32 *output_fx[], /* i/o: core-coder transport channels/object output */ + const Word16 n_samples_to_render /* i : output frame length per channel */ +); + +void ivas_jbm_dec_get_adapted_linear_interpolator_fx( + const Word16 default_interp_length, /* i : default length of the (full-frame) interpolator */ + const Word16 interp_length, /* i : length of the interpolator to be created */ + Word16 *interpolator_fx /* o : the interpolator */ +); + +void ivas_omasa_separate_object_render_jbm_fx( + Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */ + const UWord16 nSamplesRendered, /* i : number of samples rendered */ + Word32 input_fx_in[][L_FRAME48k], /* i : separated object signal */ + Word32 *output_fx[], /* o : rendered time signal */ + const Word16 subframes_rendered, /* i : number of subframes rendered */ + const Word16 slots_rendered /* i : number of CLDFB slots rendered */ +); + +void get_panning_gain( + const Word16 sinAngleMapped, + Word16 *panningGains +); + +void ivas_ism_get_stereo_gains_fx( + const Word16 aziDeg, /* i : object azimuth */ + const Word16 eleDeg, /* i : object elevation */ + Word16 *left_gain_fx, /* o : left channel gain */ + Word16 *right_gain_fx /* o : right channel gain */ +); + #endif diff --git a/lib_com/ivas_rom_com.c b/lib_com/ivas_rom_com.c index 7fd4e9f80..9ce55d69c 100644 --- a/lib_com/ivas_rom_com.c +++ b/lib_com/ivas_rom_com.c @@ -2891,20 +2891,6 @@ const uint8_t masa_twodir_bands_joined[IVAS_NUM_ACTIVE_BRATES] = /*----------------------------------------------------------------------------------* * Multi-channel LS setups *----------------------------------------------------------------------------------*/ -#ifdef IVAS_FLOAT_FIXED -const Word16 ls_azimuth_CICP2_fx[2] = { 30, -30 };/*Q-0*/ -const Word16 ls_elevation_CICP2_fx[2] = { 0, 0 };/*Q-0*/ -const Word16 ls_azimuth_CICP6_fx[5] = { 30, -30, 0, 110, -110 };/*Q-0*/ -const Word16 ls_elevation_CICP6_fx[5] = { 0, 0, 0, 0, 0 };/*Q-0*/ -const Word16 ls_azimuth_CICP12_fx[7] = { 30, -30, 0, 110, -110, 135, -135 };/*Q-0*/ -const Word16 ls_elevation_CICP12_fx[7] = { 0, 0, 0, 0, 0, 0, 0 };/*Q-0*/ -const Word16 ls_azimuth_CICP14_fx[7] = { 30, -30, 0, 110, -110, 30, -30 };/*Q-0*/ -const Word16 ls_elevation_CICP14_fx[7] = { 0, 0, 0, 0, 0, 35, 35 };/*Q-0*/ -const Word16 ls_azimuth_CICP16_fx[9] = { 30, -30, 0, 110, -110, 30, -30, 110, -110 };/*Q-0*/ -const Word16 ls_elevation_CICP16_fx[9] = { 0, 0, 0, 0, 0, 35, 35, 35, 35 };/*Q-0*/ -const Word16 ls_azimuth_CICP19_fx[11] = { 30, -30, 0, 135, -135, 90, -90, 30, -30, 135, -135 };/*Q-0*/ -const Word16 ls_elevation_CICP19_fx[11] = { 0, 0, 0, 0, 0, 0, 0, 35, 35, 35, 35 };/*Q-0*/ -#endif // IVAS_FLOAT_FIXED const float ls_azimuth_CICP2[2] = { 30.0f, -30.0f }; const float ls_elevation_CICP2[2] = { 0.0f, 0.0f }; diff --git a/lib_com/ivas_rom_com.h b/lib_com/ivas_rom_com.h index e1f312ca8..e2f1b564e 100644 --- a/lib_com/ivas_rom_com.h +++ b/lib_com/ivas_rom_com.h @@ -313,20 +313,6 @@ extern const float diffuseness_reconstructions_hr[HR_MASA_ER_LEVELS]; extern const float diffuseness_thresholds_hr[HR_MASA_ER_LEVELS + 1]; extern const Word64 diffuseness_reconstructions_hr_fx[HR_MASA_ER_LEVELS]; extern const Word32 diffuseness_thresholds_hr_fx[HR_MASA_ER_LEVELS + 1]; -#ifdef IVAS_FLOAT_FIXED -extern const Word16 ls_azimuth_CICP2_fx[2]; -extern const Word16 ls_elevation_CICP2_fx[2]; -extern const Word16 ls_azimuth_CICP6_fx[5]; -extern const Word16 ls_elevation_CICP6_fx[5]; -extern const Word16 ls_azimuth_CICP12_fx[7]; -extern const Word16 ls_elevation_CICP12_fx[7]; -extern const Word16 ls_azimuth_CICP14_fx[7]; -extern const Word16 ls_elevation_CICP14_fx[7]; -extern const Word16 ls_azimuth_CICP16_fx[9]; -extern const Word16 ls_elevation_CICP16_fx[9]; -extern const Word16 ls_azimuth_CICP19_fx[11]; -extern const Word16 ls_elevation_CICP19_fx[11]; -#endif // IVAS_FLOAT_FIXED /* Multi-channel input and output setups */ extern const float ls_azimuth_CICP2[2]; diff --git a/lib_com/ivas_rom_com_fx.c b/lib_com/ivas_rom_com_fx.c index c194b6285..6a5b4c853 100644 --- a/lib_com/ivas_rom_com_fx.c +++ b/lib_com/ivas_rom_com_fx.c @@ -320,4 +320,26 @@ const Word16 McMASA_LFEGain_vectors_fx_q13[64] = { -6553, -12943, 6717, 11632, -17530, 2129, 6881, 8355 }; +/*----------------------------------------------------------------------------------* + * Multi-channel LS setups + *----------------------------------------------------------------------------------*/ + +const Word32 ls_azimuth_CICP2_fx[2] = { 125829120, -125829120 }; +const Word32 ls_elevation_CICP2_fx[2] = { 0, 0 }; + +const Word32 ls_azimuth_CICP6_fx[5] = { 125829120, -125829120, 0, 461373440, -461373440 }; +const Word32 ls_elevation_CICP6_fx[5] = { 0, 0, 0, 0, 0 }; + +const Word32 ls_azimuth_CICP12_fx[7] = { 125829120, -125829120, 0, 461373440, -461373440, 566231040, -566231040 }; +const Word32 ls_elevation_CICP12_fx[7] = { 0, 0, 0, 0, 0, 0, 0 }; + +const Word32 ls_azimuth_CICP14_fx[7] = { 125829120, -125829120, 0, 461373440, -461373440, 125829120, -125829120 }; +const Word32 ls_elevation_CICP14_fx[7] = { 0, 0, 0, 0, 0, 146800640, 146800640 }; + +const Word32 ls_azimuth_CICP16_fx[9] = { 125829120, -125829120, 0, 461373440, -461373440, 125829120, -125829120, 461373440, -461373440 }; +const Word32 ls_elevation_CICP16_fx[9] = { 0, 0, 0, 0, 0, 146800640, 146800640, 146800640, 146800640 }; + +const Word32 ls_azimuth_CICP19_fx[11] = { 125829120, -125829120, 0, 566231040, -566231040, 377487360, -377487360, 125829120, -125829120, 566231040, -566231040 }; +const Word32 ls_elevation_CICP19_fx[11] = { 0, 0, 0, 0, 0, 0, 0, 146800640, 146800640, 146800640, 146800640 }; + /* clang-format on */ diff --git a/lib_com/ivas_rom_com_fx.h b/lib_com/ivas_rom_com_fx.h index e23fe5c34..5d5e93267 100644 --- a/lib_com/ivas_rom_com_fx.h +++ b/lib_com/ivas_rom_com_fx.h @@ -60,4 +60,18 @@ extern const Word16 ivas_divde_255[256]; extern const Word32 ism_azimuth_borders_fx[4]; extern const Word32 ism_elevation_borders_fx[4]; +/* Multi-channel input and output setups */ +extern const Word32 ls_azimuth_CICP2_fx[2]; +extern const Word32 ls_elevation_CICP2_fx[2]; +extern const Word32 ls_azimuth_CICP6_fx[5]; +extern const Word32 ls_elevation_CICP6_fx[5]; +extern const Word32 ls_azimuth_CICP12_fx[7]; +extern const Word32 ls_elevation_CICP12_fx[7]; +extern const Word32 ls_azimuth_CICP14_fx[7]; +extern const Word32 ls_elevation_CICP14_fx[7]; +extern const Word32 ls_azimuth_CICP16_fx[9]; +extern const Word32 ls_elevation_CICP16_fx[9]; +extern const Word32 ls_azimuth_CICP19_fx[11]; +extern const Word32 ls_elevation_CICP19_fx[11]; + #endif \ No newline at end of file diff --git a/lib_com/ivas_spar_com.c b/lib_com/ivas_spar_com.c index 14880d9aa..11bb7f932 100644 --- a/lib_com/ivas_spar_com.c +++ b/lib_com/ivas_spar_com.c @@ -1912,7 +1912,7 @@ void ivas_dirac_dec_get_response_fixed( cos_az[2] = L_sub( Mpy_32_32( Mpy_32_32( ( 1 << Q30 ), cos_1 ), cos_az[1] ) << 4, cos_az[0] ); // Q29 sin_az[0] = sin_1 << 2; // Q29 sin_az[1] = Mpy_32_32( Mpy_32_32( sin_1, ( 1 << Q30 ) ), cos_1 ) << 6; // Q29 - sin_az[2] = Mpy_32_32( sin_1, L_sub( Mpy_32_32( ( 1 << Q30 ), cos_2 ) << 5, ( 1 << 29 ) ) ) << 4; + sin_az[2] = Mpy_32_32( sin_1, L_sub( L_shl_sat(Mpy_32_32( ( 1 << Q30 ), cos_2 ), 5), ( 1 << 29 ) ) ) << 4; response[0] = ( 1 << 29 ); /* Un-optimized code - for reference */ diff --git a/lib_com/ivas_stat_com.h b/lib_com/ivas_stat_com.h index d096e39c5..d8712d001 100644 --- a/lib_com/ivas_stat_com.h +++ b/lib_com/ivas_stat_com.h @@ -65,11 +65,11 @@ typedef struct float yaw; /* yaw value read from the input metadata file */ float pitch; /* pitch value read from the input metadata file */ #ifdef IVAS_FLOAT_FIXED - Word32 azimuth_fx; /* azimuth value read from the input metadata file */ - Word32 elevation_fx; /* elevation value read from the input metadata file */ - Word16 radius_fx; /* radius value read from the input metadata file */ - Word32 yaw_fx; /* yaw value read from the input metadata file */ - Word32 pitch_fx; /* pitch value read from the input metadata file */ + Word32 azimuth_fx; /* azimuth value read from the input metadata file */ // q = 22 + Word32 elevation_fx; /* elevation value read from the input metadata file */ // q = 22 + Word16 radius_fx; /* radius value read from the input metadata file */ // q = 9 + Word32 yaw_fx; /* yaw value read from the input metadata file */ // q = 22 + Word32 pitch_fx; /* pitch value read from the input metadata file */ // q = 22 #endif int16_t non_diegetic_flag; /* Non-diegetic (non-headtracked) object flag */ diff --git a/lib_dec/ivas_init_dec.c b/lib_dec/ivas_init_dec.c index da1c7e2bd..b71b3001e 100644 --- a/lib_dec/ivas_init_dec.c +++ b/lib_dec/ivas_init_dec.c @@ -938,6 +938,11 @@ ivas_error ivas_init_decoder( IF ( output_config == IVAS_AUDIO_CONFIG_LS_CUSTOM ) { #ifdef IVAS_FLOAT_FIXED + FOR(int ind = 0; ind < MAX_OUTPUT_CHANNELS; ind++) + { + st_ivas->hLsSetupCustom->ls_azimuth_fx[ind] = (Word32)(st_ivas->hLsSetupCustom->ls_azimuth[ind] * (1 << 22)); + st_ivas->hLsSetupCustom->ls_elevation_fx[ind] = (Word32)(st_ivas->hLsSetupCustom->ls_elevation[ind] * (1 << 22)); + } IF ( ( error = ivas_ls_custom_output_init_fx( st_ivas ) ) == IVAS_ERR_OK ) { st_ivas->hOutSetup.ls_azimuth = st_ivas->hLsSetupCustom->ls_azimuth; @@ -1851,10 +1856,30 @@ ivas_error ivas_init_decoder( st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV_ROOM || st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV_ROOM ) ) { +#ifdef IVAS_FLOAT_FIXED + IF ( ( error = ivas_ism_renderer_open_fx( st_ivas ) ) != IVAS_ERR_OK ) + { + return error; + } + FOR(Word16 ind = 0; ind < st_ivas->hDecoderConfig->output_Fs / FRAMES_PER_SEC; ind++) + { + st_ivas->hIsmRendererData->interpolator[ind] = (float)(st_ivas->hIsmRendererData->interpolator_fx[ind]) / (float)(1 << 15); + } + FOR(Word16 ind1 = 0; ind1 < MAX_NUM_OBJECTS; ind1++) + { + FOR(Word16 ind2 = 0; ind2 < MAX_OUTPUT_CHANNELS; ind2++) + { + // q factors might be different. Here we are just initializing to zero + st_ivas->hIsmRendererData->prev_gains[ind1][ind2] = (float)(st_ivas->hIsmRendererData->prev_gains_fx[ind1][ind2]) / (float)(1<<31); + st_ivas->hIsmRendererData->gains[ind1][ind2] = (float)(st_ivas->hIsmRendererData->gains_fx[ind1][ind2]) / (float)(1<<31); + } + } +#else IF ( ( error = ivas_ism_renderer_open( st_ivas ) ) != IVAS_ERR_OK ) { return error; } +#endif } IF ( st_ivas->ivas_format == SBA_ISM_FORMAT ) @@ -2009,11 +2034,20 @@ ivas_error ivas_init_decoder( { return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for floating-point output audio buffer!\n" ) ); } +#ifdef IVAS_FLOAT_FIXED + IF ( ( st_ivas->p_output_fx[n] = (Word32 *) malloc( ( 48000 / FRAMES_PER_SEC ) * sizeof( Word32 ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for floating-point output audio buffer!\n" ) ); + } +#endif } FOR ( ; n < MAX_OUTPUT_CHANNELS + MAX_NUM_OBJECTS; n++ ) { st_ivas->p_output_f[n] = NULL; +#ifdef IVAS_FLOAT_FIXED + st_ivas->p_output_fx[n] = NULL; +#endif } @@ -2254,6 +2288,9 @@ void ivas_initialize_handles_dec( FOR ( i = 0; i < MAX_OUTPUT_CHANNELS + MAX_NUM_OBJECTS; i++ ) { st_ivas->p_output_f[i] = NULL; +#ifdef IVAS_FLOAT_FIXED + st_ivas->p_output_f[i] = NULL; +#endif } return; @@ -2480,6 +2517,10 @@ void ivas_destroy_dec( { free( st_ivas->p_output_f[i] ); st_ivas->p_output_f[i] = NULL; +#ifdef IVAS_FLOAT_FIXED + free( st_ivas->p_output_fx[i] ); + st_ivas->p_output_fx[i] = NULL; +#endif } } diff --git a/lib_dec/ivas_ism_dec.c b/lib_dec/ivas_ism_dec.c index c63051f25..aa2c4752c 100644 --- a/lib_dec/ivas_ism_dec.c +++ b/lib_dec/ivas_ism_dec.c @@ -34,6 +34,7 @@ #include "options.h" #include "prot.h" #include "ivas_prot.h" +#include "ivas_prot_fx.h" #include "ivas_prot_rend.h" #include "wmc_auto.h" #ifdef IVAS_FLOAT_FIXED @@ -213,10 +214,30 @@ static ivas_error ivas_ism_bitrate_switching_dec( /* close the ISM renderer and reinitialize */ ivas_ism_renderer_close( &st_ivas->hIsmRendererData ); +#ifdef IVAS_FLOAT_FIXED + IF ( ( error = ivas_ism_renderer_open_fx( st_ivas ) ) != IVAS_ERR_OK ) + { + return error; + } + FOR(Word16 ind = 0; ind < st_ivas->hDecoderConfig->output_Fs / FRAMES_PER_SEC; ind++) + { + st_ivas->hIsmRendererData->interpolator[ind] = (float)(st_ivas->hIsmRendererData->interpolator_fx[ind]) / (float)(1 << 15); + } + FOR(Word16 ind1 = 0; ind1 < MAX_NUM_OBJECTS; ind1++) + { + FOR(Word16 ind2 = 0; ind2 < MAX_OUTPUT_CHANNELS; ind2++) + { + // q factors might be different. Here we are just initializing to zero + st_ivas->hIsmRendererData->prev_gains[ind1][ind2] = (float)(st_ivas->hIsmRendererData->prev_gains_fx[ind1][ind2]) / (float)(1<<31); + st_ivas->hIsmRendererData->gains[ind1][ind2] = (float)(st_ivas->hIsmRendererData->gains_fx[ind1][ind2]) / (float)(1<<31); + } + } +#else if ( ( error = ivas_ism_renderer_open( st_ivas ) ) != IVAS_ERR_OK ) { return error; } +#endif } if ( st_ivas->hOutSetup.output_config == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) diff --git a/lib_dec/ivas_ism_param_dec.c b/lib_dec/ivas_ism_param_dec.c index 863e455d1..e9ae7005d 100644 --- a/lib_dec/ivas_ism_param_dec.c +++ b/lib_dec/ivas_ism_param_dec.c @@ -1175,7 +1175,14 @@ void ivas_ism_dec_digest_tc( if ( st_ivas->intern_config == IVAS_AUDIO_CONFIG_STEREO ) { +#ifdef IVAS_FLOAT_FIXED + Word16 gains_fx[2]; + ivas_ism_get_stereo_gains_fx( (Word16)st_ivas->hIsmMetaData[i]->azimuth, (Word16)st_ivas->hIsmMetaData[i]->elevation, &gains_fx[0], &gains_fx[1] ); + st_ivas->hIsmRendererData->gains[i][0] = (float)gains_fx[0] / 32768.f; + st_ivas->hIsmRendererData->gains[i][1] = (float)gains_fx[1] / 32768.f; +#else ivas_ism_get_stereo_gains( st_ivas->hIsmMetaData[i]->azimuth, st_ivas->hIsmMetaData[i]->elevation, &st_ivas->hIsmRendererData->gains[i][0], &st_ivas->hIsmRendererData->gains[i][1] ); +#endif } else { diff --git a/lib_dec/ivas_ism_renderer.c b/lib_dec/ivas_ism_renderer.c index 002bf77ec..4032564ed 100644 --- a/lib_dec/ivas_ism_renderer.c +++ b/lib_dec/ivas_ism_renderer.c @@ -34,10 +34,13 @@ #include "options.h" #include "ivas_cnst.h" #include "prot.h" +#include "prot_fx2.h" #include "ivas_prot.h" +#include "ivas_prot_fx.h" #include "ivas_prot_rend.h" #include "ivas_stat_com.h" #include "ivas_rom_com.h" +#include "rom_com.h" #include "ivas_rom_dec.h" #include #include "wmc_auto.h" @@ -92,6 +95,12 @@ ivas_error ivas_ism_renderer_open( { return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for ISM renderer interpolator\n" ) ); } +#ifdef IVAS_FLOAT_FIXED + if ( ( st_ivas->hIsmRendererData->interpolator_fx = (Word16 *) malloc( sizeof( Word16 ) * init_interpolator_length ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for ISM renderer interpolator\n" ) ); + } +#endif for ( i = 0; i < interpolator_length; i++ ) { @@ -101,13 +110,82 @@ ivas_error ivas_ism_renderer_open( return IVAS_ERR_OK; } +#ifdef IVAS_FLOAT_FIXED +ivas_error ivas_ism_renderer_open_fx( + Decoder_Struct *st_ivas /* i/o: IVAS decoder structure */ +) +{ + Word16 i; + UWord16 interpolator_length; + UWord16 init_interpolator_length; + ivas_error error; + + IF ( ( st_ivas->hIsmRendererData = (ISM_RENDERER_HANDLE) malloc( sizeof( ISM_RENDERER_DATA ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for ISM renderer\n" ) ); + } + + IF ( st_ivas->hIntSetup.is_loudspeaker_setup && st_ivas->hIntSetup.ls_azimuth != NULL && st_ivas->hIntSetup.ls_elevation != NULL && st_ivas->hEFAPdata == NULL ) + { + IF ( ( error = efap_init_data_fixed( &( st_ivas->hEFAPdata ), st_ivas->hIntSetup.ls_azimuth_fx, st_ivas->hIntSetup.ls_elevation_fx, st_ivas->hIntSetup.nchan_out_woLFE, EFAP_MODE_EFAP ) ) != IVAS_ERR_OK ) + { + return error; + } + } + + FOR ( i = 0; i < MAX_NUM_OBJECTS; i++ ) + { + set32_fx( st_ivas->hIsmRendererData->prev_gains_fx[i], 0, MAX_OUTPUT_CHANNELS ); + set32_fx( st_ivas->hIsmRendererData->gains_fx[i], 0, MAX_OUTPUT_CHANNELS ); + } + + IF ( st_ivas->hDecoderConfig->Opt_tsm ) + { + init_interpolator_length = NS2SA( st_ivas->hDecoderConfig->output_Fs, MAX_JBM_CLDFB_TIMESLOTS * CLDFB_SLOT_NS ); + move16(); + interpolator_length = (UWord16) ( st_ivas->hDecoderConfig->output_Fs / FRAMES_PER_SEC ); + move16(); + } + ELSE + { + init_interpolator_length = (UWord16) ( st_ivas->hDecoderConfig->output_Fs / FRAMES_PER_SEC ); + move16(); + interpolator_length = init_interpolator_length; + move16(); + } + IF ( ( st_ivas->hIsmRendererData->interpolator_fx = (Word16 *) malloc( sizeof( Word16 ) * init_interpolator_length ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for ISM renderer interpolator\n" ) ); + } + + FOR ( i = 0; i < interpolator_length - 1; i++ ) + { + st_ivas->hIsmRendererData->interpolator_fx[i] = div_s( i, interpolator_length - 1 ); + } + st_ivas->hIsmRendererData->interpolator_fx[interpolator_length - 1] = 32767; + // To be removed later ///////////////////////////////////////////////////////////////////////////////////////////////////////// + IF ( ( st_ivas->hIsmRendererData->interpolator = (float *) malloc( sizeof( float ) * init_interpolator_length ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for ISM renderer interpolator\n" ) ); + } + + FOR ( i = 0; i < interpolator_length; i++ ) + { + st_ivas->hIsmRendererData->interpolator[i] = (float) i / ( (float) interpolator_length - 1 ); + } + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + return IVAS_ERR_OK; +} +#endif + /*-------------------------------------------------------------------------* * ivas_ism_renderer_close() * * Close struct for object rendering. *-------------------------------------------------------------------------*/ - +#ifndef IVAS_FLOAT_FIXED void ivas_ism_renderer_close( ISM_RENDERER_HANDLE *hIsmRendererData /* i/o: ISM renderer handle */ ) @@ -128,7 +206,35 @@ void ivas_ism_renderer_close( return; } +#else +void ivas_ism_renderer_close( + ISM_RENDERER_HANDLE *hIsmRendererData /* i/o: ISM renderer handle */ +) +{ + IF ( hIsmRendererData == NULL || *hIsmRendererData == NULL ) + { + return; + } + IF ( ( *hIsmRendererData )->interpolator_fx != NULL ) + { + free( ( *hIsmRendererData )->interpolator_fx ); + ( *hIsmRendererData )->interpolator_fx = NULL; + } + // To be removed later ///////////////////////////// + IF ((*hIsmRendererData)->interpolator != NULL) + { + free((*hIsmRendererData)->interpolator); + (*hIsmRendererData)->interpolator = NULL; + } + //////////////////////////////////////////////////// + + free( *hIsmRendererData ); + *hIsmRendererData = NULL; + + return; +} +#endif /*-------------------------------------------------------------------------* * ivas_ism_render_sf() @@ -237,6 +343,127 @@ void ivas_ism_render_sf( return; } +#ifdef IVAS_FLOAT_FIXED +void ivas_ism_render_sf_fx( + Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */ + Word32 *output_fx[], /* i/o: core-coder transport channels/object output */ + const Word16 n_samples_to_render /* i : output frame length per channel */ +) +{ + Word16 i, j, k, j2; + Word16 *g1_fx, g2_fx; + Word32 *tc_fx; + Word16 num_objects, nchan_out_woLFE, lfe_index; + Word16 azimuth, elevation; + Word16 tc_offset; + Word16 interp_offset; + Word32 gain_fx, prev_gain_fx; + Word32 tc_local_fx[MAX_NUM_OBJECTS][L_FRAME48k]; + Word32 *p_tc_fx[MAX_NUM_OBJECTS]; + + num_objects = st_ivas->nchan_transport; + move16(); + IF ( st_ivas->ivas_format == SBA_ISM_FORMAT ) + { + num_objects = st_ivas->nchan_ism; + move16(); + } + + nchan_out_woLFE = st_ivas->hIntSetup.nchan_out_woLFE; + move16(); + + tc_offset = st_ivas->hTcBuffer->n_samples_rendered; + move16(); + interp_offset = st_ivas->hTcBuffer->n_samples_rendered; + move16(); + + IF ( st_ivas->hDecoderConfig->Opt_tsm ) + { + FOR ( i = 0; i < num_objects; i++ ) + { + p_tc_fx[i] = &st_ivas->hTcBuffer->tc_fx[i][tc_offset]; + move16(); + } + } + ELSE + { + FOR ( i = 0; i < num_objects; i++ ) + { + mvl2l( &output_fx[i][tc_offset], tc_local_fx[i], n_samples_to_render ); + p_tc_fx[i] = tc_local_fx[i]; + move16(); + } + } + + FOR ( i = 0; i < nchan_out_woLFE + st_ivas->hIntSetup.num_lfe; i++ ) + { + set32_fx( output_fx[i], 0, n_samples_to_render ); + } + + IF ( st_ivas->hCombinedOrientationData && st_ivas->hCombinedOrientationData->enableCombinedOrientation[st_ivas->hCombinedOrientationData->subframe_idx] == 1 ) + { + ivas_jbm_dec_get_adapted_linear_interpolator_fx( n_samples_to_render, n_samples_to_render, st_ivas->hIsmRendererData->interpolator_fx ); + interp_offset = 0; + move16(); + } + + FOR ( i = 0; i < num_objects; i++ ) + { + /* Combined rotation: rotate the object positions depending the head and external orientations */ + IF ( st_ivas->hCombinedOrientationData != NULL && st_ivas->hCombinedOrientationData->enableCombinedOrientation[st_ivas->hCombinedOrientationData->subframe_idx] == 1 ) + { + rotateAziEle_fx( (Word16)L_shr(st_ivas->hIsmMetaData[i]->azimuth_fx, 22), (Word16)L_shr(st_ivas->hIsmMetaData[i]->elevation_fx, 22), &azimuth, &elevation, st_ivas->hCombinedOrientationData->Rmat_fx[0], st_ivas->hIntSetup.is_planar_setup ); + move32(); + move32(); + + IF ( st_ivas->hEFAPdata != NULL ) + { + efap_determine_gains_fixed( st_ivas->hEFAPdata, st_ivas->hIsmRendererData->gains_fx[i], L_shl(azimuth, 22), L_shl(elevation, 22), EFAP_MODE_EFAP ); + } + } + + lfe_index = 0; + move16(); + FOR ( (j = 0, j2 = 0); j < nchan_out_woLFE; (j++, j2++) ) + { + IF ( ( st_ivas->hIntSetup.num_lfe > 0 ) && ( st_ivas->hIntSetup.index_lfe[lfe_index] == j ) ) + { + ( lfe_index < ( st_ivas->hIntSetup.num_lfe - 1 ) ) ? ( lfe_index++, j2++ ) : j2++; + move16(); + move16(); + + } + + gain_fx = st_ivas->hIsmRendererData->gains_fx[i][j]; + move32(); + prev_gain_fx = st_ivas->hIsmRendererData->prev_gains_fx[i][j]; + move32(); + IF ( GT_32(L_abs( gain_fx ), 0) || GT_32(L_abs( prev_gain_fx ), 0) ) + { + g1_fx = &st_ivas->hIsmRendererData->interpolator_fx[interp_offset]; + tc_fx = p_tc_fx[i]; + FOR ( k = 0; k < n_samples_to_render; k++ ) + { + g2_fx = sub(32767, *g1_fx); + output_fx[j2][k] = L_add(output_fx[j2][k], L_shl(Mpy_32_32(L_add( Mpy_32_16_1(gain_fx, *( g1_fx++ )), Mpy_32_16_1(prev_gain_fx, g2_fx) ), *( tc_fx++ )), 1)); + } + } + + /* update here only in case of head rotation */ + IF ( st_ivas->hCombinedOrientationData != NULL && st_ivas->hCombinedOrientationData->enableCombinedOrientation[st_ivas->hCombinedOrientationData->subframe_idx] == 1 ) + { + st_ivas->hIsmRendererData->prev_gains_fx[i][j] = gain_fx; + move32(); + } + } + } + + /* update combined orientation access index */ + ivas_combined_orientation_update_index( st_ivas->hCombinedOrientationData, n_samples_to_render ); + + return; +} +#endif /*-------------------------------------------------------------------------* @@ -285,6 +512,70 @@ void ivas_ism_get_stereo_gains( return; } +#ifdef IVAS_FLOAT_FIXED + +#define SIN_NEG_30_DEGREES_Q15 ( (Word16) 0xC000 ) +#define SIN_30_DEGREES_Q15 ( (Word16) 0x4000 ) + +void ivas_ism_get_stereo_gains_fx( + const Word16 aziDeg, /* i : object azimuth */ + const Word16 eleDeg, /* i : object elevation */ + Word16 *left_gain_fx, /* o : left channel gain */ + Word16 *right_gain_fx /* o : right channel gain */ +) +{ + /* Convert azi and ele to an azi value of the cone of confusion */ + Word16 azAddEl = add( aziDeg, eleDeg ); + Word16 azSubEl = sub( aziDeg, eleDeg ); + Word16 gains[2]; + + const Word16 *ptr_sin_az = ivas_sin_az_fx; + + WHILE( GT_16( azAddEl, 180 ) ) + { + azAddEl = sub( azAddEl, 360 ); + } + WHILE( LT_16( azAddEl, -180 ) ) + { + azAddEl = add( azAddEl, 360 ); + } + WHILE( GT_16( azSubEl, 180 ) ) + { + azSubEl = sub( azSubEl, 360 ); + } + WHILE( LT_16( azSubEl, -180 ) ) + { + azSubEl = add( azSubEl, 360 ); + } + // sin_az_cos_el = (ptr_sin_az[azAddEl] + ptr_sin_az[azSubEl])/2; + Word16 sin_az_cos_el = extract_l( L_shr( L_add( L_deposit_l( ptr_sin_az[azAddEl + 180] ), L_deposit_l( ptr_sin_az[azSubEl + 180] ) ), 1 ) ); + //Word16 sin_az_cos_el = extract_l( L_shr( L_add( L_deposit_l( ptr_sin_az[azAddEl] ), L_deposit_l( ptr_sin_az[azSubEl] ) ), 1 ) ); + + IF( GE_16( sin_az_cos_el, SIN_30_DEGREES_Q15 ) ) + { /* Left side */ + gains[0] = (Word16) 0x7fff; + move16(); + gains[1] = 0; + move16(); + } + ELSE IF( LE_16( sin_az_cos_el, SIN_NEG_30_DEGREES_Q15 ) ) + { /* Right side */ + gains[0] = 0; + move16(); + gains[1] = (Word16) 0x7fff; + move16(); + } + ELSE /* Tangent panning law */ + { + get_panning_gain( sin_az_cos_el, gains ); + } + + *left_gain_fx = gains[0]; + *right_gain_fx = gains[1]; + + return; +} +#endif /*-------------------------------------------------------------------------* @@ -293,6 +584,7 @@ void ivas_ism_get_stereo_gains( * Open structures, reserve memory, and init values. *-------------------------------------------------------------------------*/ +#ifndef IVAS_FLOAT_FIXED ivas_error ivas_omasa_separate_object_renderer_open( Decoder_Struct *st_ivas /* i/o: IVAS decoder structure */ ) @@ -313,6 +605,7 @@ ivas_error ivas_omasa_separate_object_renderer_open( init_interpolator_length = (int16_t) ( st_ivas->hDecoderConfig->output_Fs / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES ); interpolator_length = init_interpolator_length; + st_ivas->hIsmRendererData->interpolator = (float *) malloc( sizeof( float ) * init_interpolator_length ); for ( i = 0; i < interpolator_length; i++ ) @@ -348,6 +641,95 @@ ivas_error ivas_omasa_separate_object_renderer_open( return IVAS_ERR_OK; } +#else +ivas_error ivas_omasa_separate_object_renderer_open( + Decoder_Struct *st_ivas /* i/o: IVAS decoder structure */ +) +{ + Word16 interpolator_length; + Word16 i; + Word16 init_interpolator_length; + + IF ( ( st_ivas->hIsmRendererData = (ISM_RENDERER_HANDLE) malloc( sizeof( ISM_RENDERER_DATA ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for MASA ISM renderer \n" ) ); + } + + FOR ( i = 0; i < MAX_NUM_OBJECTS; i++ ) + { + set32_fx( st_ivas->hIsmRendererData->prev_gains_fx[i], 0, MAX_OUTPUT_CHANNELS ); + } + + init_interpolator_length = (Word16) ( st_ivas->hDecoderConfig->output_Fs / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES ); + move32(); + interpolator_length = init_interpolator_length; + move16(); + + st_ivas->hIsmRendererData->interpolator_fx = (Word16 *) malloc( sizeof( Word16 ) * init_interpolator_length ); + + FOR ( i = 0; i < interpolator_length; i++ ) + { + st_ivas->hIsmRendererData->interpolator_fx[i] = div_s(i, interpolator_length); + } + st_ivas->hIsmRendererData->interpolator_length = interpolator_length; + move16(); + + st_ivas->hMasaIsmData->delayBuffer_size = (Word16) ( ( st_ivas->hDecoderConfig->output_Fs / 50 ) / MAX_PARAM_SPATIAL_SUBFRAMES ); + move16(); + + IF ( st_ivas->ism_mode == ISM_MASA_MODE_MASA_ONE_OBJ || st_ivas->ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ ) + { + st_ivas->hMasaIsmData->delayBuffer_nchan = 1; + move16(); + } + ELSE + { + st_ivas->hMasaIsmData->delayBuffer_nchan = st_ivas->nchan_ism; + move16(); + } + + IF ( ( st_ivas->hMasaIsmData->delayBuffer_fx = (Word32 **) malloc( st_ivas->hMasaIsmData->delayBuffer_nchan * sizeof( Word32 * ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for MASA ISM delay buffer \n" ) ); + } + + FOR ( i = 0; i < st_ivas->hMasaIsmData->delayBuffer_nchan; i++ ) + { + IF ( ( st_ivas->hMasaIsmData->delayBuffer_fx[i] = (Word32 *) malloc( st_ivas->hMasaIsmData->delayBuffer_size * sizeof( Word32 ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for MASA ISM delay buffer \n" ) ); + } + set32_fx( st_ivas->hMasaIsmData->delayBuffer_fx[i], 0, st_ivas->hMasaIsmData->delayBuffer_size ); + } + + // To be removed later ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + FOR ( i = 0; i < MAX_NUM_OBJECTS; i++ ) + { + set_f( st_ivas->hIsmRendererData->prev_gains[i], 0.0f, MAX_OUTPUT_CHANNELS ); + } + st_ivas->hIsmRendererData->interpolator = (float *) malloc( sizeof( float ) * init_interpolator_length ); + FOR ( i = 0; i < interpolator_length; i++ ) + { + st_ivas->hIsmRendererData->interpolator[i] = (float) i / ( (float) interpolator_length ); + } + IF ( ( st_ivas->hMasaIsmData->delayBuffer = (float **) malloc( st_ivas->hMasaIsmData->delayBuffer_nchan * sizeof( float * ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for MASA ISM delay buffer \n" ) ); + } + + FOR ( i = 0; i < st_ivas->hMasaIsmData->delayBuffer_nchan; i++ ) + { + IF ( ( st_ivas->hMasaIsmData->delayBuffer[i] = (float *) malloc( st_ivas->hMasaIsmData->delayBuffer_size * sizeof( float ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for MASA ISM delay buffer \n" ) ); + } + set_zero( st_ivas->hMasaIsmData->delayBuffer[i], st_ivas->hMasaIsmData->delayBuffer_size ); + } + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + return IVAS_ERR_OK; +} +#endif /*-------------------------------------------------------------------------* @@ -356,6 +738,7 @@ ivas_error ivas_omasa_separate_object_renderer_open( * Close structures, free memory. *-------------------------------------------------------------------------*/ +#ifndef IVAS_FLOAT_FIXED void ivas_omasa_separate_object_renderer_close( Decoder_Struct *st_ivas /* i/o: IVAS decoder structure */ ) @@ -384,6 +767,50 @@ void ivas_omasa_separate_object_renderer_close( return; } +#else +void ivas_omasa_separate_object_renderer_close( + Decoder_Struct *st_ivas /* i/o: IVAS decoder structure */ +) +{ + Word16 i; + + IF ( st_ivas->hMasaIsmData != NULL ) + { + IF ( st_ivas->hMasaIsmData->delayBuffer_fx != NULL ) + { + FOR ( i = 0; i < st_ivas->hMasaIsmData->delayBuffer_nchan; i++ ) + { + IF ( st_ivas->hMasaIsmData->delayBuffer_fx[i] != NULL ) + { + free( st_ivas->hMasaIsmData->delayBuffer_fx[i] ); + st_ivas->hMasaIsmData->delayBuffer_fx[i] = NULL; + } + } + + free( st_ivas->hMasaIsmData->delayBuffer_fx ); + st_ivas->hMasaIsmData->delayBuffer_fx = NULL; + // To be removed later ////////////////////////////////////////////////// + FOR ( i = 0; i < st_ivas->hMasaIsmData->delayBuffer_nchan; i++ ) + { + IF ( st_ivas->hMasaIsmData->delayBuffer[i] != NULL ) + { + free( st_ivas->hMasaIsmData->delayBuffer[i] ); + st_ivas->hMasaIsmData->delayBuffer[i] = NULL; + } + } + + free( st_ivas->hMasaIsmData->delayBuffer ); + st_ivas->hMasaIsmData->delayBuffer = NULL; + ////////////////////////////////////////////////////////////////////////// + + } + } + + ivas_ism_renderer_close( &st_ivas->hIsmRendererData ); + + return; +} +#endif /*-------------------------------------------------------------------------* @@ -517,6 +944,9 @@ void ivas_omasa_separate_object_render_jbm( if ( hVBAPdata != NULL ) { vbap_determine_gains( hVBAPdata, gains, azimuth, elevation, 1 ); + /*Word32 gains_fx[16]; + vbap_determine_gains_fx( hVBAPdata, gains_fx, azimuth, elevation, 1 ); + for (j = 0; j < nchan_out_woLFE; j++) gains[j] = (float)gains_fx[j] / (float)(1 << 29);*/ } else { @@ -552,3 +982,184 @@ void ivas_omasa_separate_object_render_jbm( return; } +#ifdef IVAS_FLOAT_FIXED +void ivas_omasa_separate_object_render_jbm_fx( + Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */ + const UWord16 nSamplesRendered, /* i : number of samples rendered */ + Word32 input_fx_in[][L_FRAME48k], /* i : separated object signal */ + Word32 *output_fx[], /* o : rendered time signal */ + const Word16 subframes_rendered, /* i : number of subframes rendered */ + const Word16 slots_rendered /* i : number of CLDFB slots rendered */ +) +{ + VBAP_HANDLE hVBAPdata; + DIRAC_REND_HANDLE hDirACRend; + SPAT_PARAM_REND_COMMON_DATA_HANDLE hSpatParamRendCom; + Word16 nchan_out_woLFE, num_lfe; + ISM_RENDERER_HANDLE hRendererData; + Word16 j, k, j2; + Word16 obj; + Word32 gains_fx[MAX_OUTPUT_CHANNELS]; + Word16 g1_fx, g2_fx; + Word16 lfe_index; + Word16 azimuth, elevation; + Word16 num_objects; + UWord8 single_separated; + Word32 *input_fx[MAX_TRANSPORT_CHANNELS]; + Word32 *output_fx_local[MAX_OUTPUT_CHANNELS]; + Word16 offsetSamples; + Word16 n_samples_sf, md_idx; + Word16 slots_to_render, first_sf, last_sf, subframe_idx; + + hVBAPdata = st_ivas->hVBAPdata; + hDirACRend = st_ivas->hDirACRend; + hSpatParamRendCom = st_ivas->hSpatParamRendCom; + nchan_out_woLFE = st_ivas->hIntSetup.nchan_out_woLFE; + move16(); + num_lfe = st_ivas->hIntSetup.num_lfe; + move16(); + hRendererData = st_ivas->hIsmRendererData; + lfe_index = hDirACRend->hOutSetup.index_lfe[0]; + move16(); + + IF ( st_ivas->ism_mode == ISM_MASA_MODE_MASA_ONE_OBJ || st_ivas->ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ ) + { + single_separated = 1; + num_objects = 1; + move16(); + } + ELSE + { + single_separated = 0; + num_objects = st_ivas->nchan_ism; + move16(); + } + + offsetSamples = i_mult(slots_rendered, hSpatParamRendCom->slot_size); + + FOR ( j = 0; j < nchan_out_woLFE + num_lfe; j++ ) + { + output_fx_local[j] = output_fx[j]; + } + + IF ( st_ivas->hDecoderConfig->Opt_tsm ) + { + FOR ( obj = 0; obj < num_objects; obj++ ) + { + input_fx[obj] = &st_ivas->hTcBuffer->tc_fx[obj + 2][offsetSamples]; + } + } + ELSE + { + FOR ( obj = 0; obj < num_objects; obj++ ) + { + input_fx[obj] = input_fx_in[obj]; + } + } + + slots_to_render = nSamplesRendered / hSpatParamRendCom->slot_size; + move16(); + first_sf = subframes_rendered; + move16(); + last_sf = first_sf; + move16(); + + WHILE ( slots_to_render > 0 ) + { + slots_to_render = sub(slots_to_render, hSpatParamRendCom->subframe_nbslots[last_sf]); + last_sf = add(last_sf, 1); + } + + FOR ( obj = 0; obj < num_objects; obj++ ) + { + /* Delay the signal to match CLDFB delay. Delay the whole buffer with the first rendering call of the stretched buffer. */ + IF ( slots_rendered == 0 ) + { + Word16 tcBufferSize; + + tcBufferSize = i_mult(hSpatParamRendCom->num_slots, hSpatParamRendCom->slot_size); + delay_signal_fx( input_fx[obj], tcBufferSize, st_ivas->hMasaIsmData->delayBuffer_fx[obj], st_ivas->hMasaIsmData->delayBuffer_size ); + } + offsetSamples = 0; + + FOR ( subframe_idx = first_sf; subframe_idx < last_sf; subframe_idx++ ) + { + n_samples_sf = i_mult(hSpatParamRendCom->subframe_nbslots[subframe_idx], hSpatParamRendCom->slot_size); + IF ( n_samples_sf != hRendererData->interpolator_length ) + { + FOR ( k = 0; k < n_samples_sf; k++ ) + { + hRendererData->interpolator_fx[k] = div_s( k, n_samples_sf ); + } + hRendererData->interpolator_length = n_samples_sf; + move16(); + } + + md_idx = hSpatParamRendCom->render_to_md_map[subframe_idx]; + move16(); + + IF ( single_separated ) + { + azimuth = st_ivas->hMasaIsmData->azimuth_separated_ism[md_idx]; + move16(); + elevation = st_ivas->hMasaIsmData->elevation_separated_ism[md_idx]; + move16(); + } + ELSE + { + azimuth = st_ivas->hMasaIsmData->azimuth_ism[obj][md_idx]; + move16(); + elevation = st_ivas->hMasaIsmData->elevation_ism[obj][md_idx]; + move16(); + } + + IF ( st_ivas->hOutSetup.is_planar_setup ) + { + /* If no elevation support in output format, then rendering should be done with zero elevation */ + elevation = 0; + move16(); + } + + IF ( hVBAPdata != NULL ) + { + vbap_determine_gains_fx( hVBAPdata, gains_fx, azimuth, elevation, 1 ); + } + ELSE + { + ivas_dirac_dec_get_response_fixed( azimuth, elevation, gains_fx, hDirACRend->hOutSetup.ambisonics_order ); + } + + FOR ( j = 0; j < nchan_out_woLFE; j++ ) + { + IF ( GT_16(hDirACRend->hOutSetup.num_lfe, 0) ) + { + j2 = add(j, (Word16)GE_16( j, lfe_index )); + } + ELSE + { + j2 = j; + move16(); + } + + IF ( GT_32(L_abs( gains_fx[j] ), 0) || GT_32(L_abs( hRendererData->prev_gains_fx[obj][j] ), 0) ) + { + FOR ( k = 0; k < n_samples_sf; k++ ) + { + g1_fx = hRendererData->interpolator_fx[k]; + move16(); + g2_fx = sub(32767, g1_fx); + move16(); + output_fx_local[j2][k + offsetSamples] = L_add(output_fx_local[j2][k + offsetSamples], L_add(L_shl(Mpy_32_32(Mpy_32_16_1(input_fx[obj][k + offsetSamples], g1_fx), gains_fx[j]), 2), L_shl(Mpy_32_32(Mpy_32_16_1(input_fx[obj][k + offsetSamples], g2_fx), hRendererData->prev_gains_fx[obj][j]), 2))); + } + } + hRendererData->prev_gains_fx[obj][j] = gains_fx[j]; + move32(); + } + + offsetSamples = add(offsetSamples, n_samples_sf); + } + } + + return; +} +#endif diff --git a/lib_dec/ivas_jbm_dec.c b/lib_dec/ivas_jbm_dec.c index 329ae0059..879fa29db 100644 --- a/lib_dec/ivas_jbm_dec.c +++ b/lib_dec/ivas_jbm_dec.c @@ -110,6 +110,9 @@ ivas_error ivas_jbm_dec_tc( for ( n = 0; n < ivas_get_nchan_buffers_dec( st_ivas, st_ivas->sba_analysis_order, st_ivas->hDecoderConfig->ivas_total_brate ); n++ ) { st_ivas->hTcBuffer->tc[n] = st_ivas->p_output_f[n]; +#ifdef IVAS_FLOAT_FIXED + st_ivas->hTcBuffer->tc_fx[n] = st_ivas->p_output_fx[n]; +#endif } } @@ -1393,6 +1396,7 @@ ivas_error ivas_jbm_dec_render( ivas_error error; float *p_output[MAX_OUTPUT_CHANNELS + MAX_NUM_OBJECTS]; float *p_tc[MAX_TRANSPORT_CHANNELS + MAX_NUM_OBJECTS]; + Word32 *p_output_fx[MAX_OUTPUT_CHANNELS + MAX_NUM_OBJECTS]; SPAT_PARAM_REND_COMMON_DATA_HANDLE hSpatParamRendCom; push_wmops( "ivas_dec_render" ); @@ -1410,6 +1414,9 @@ ivas_error ivas_jbm_dec_render( for ( n = 0; n < MAX_OUTPUT_CHANNELS + MAX_NUM_OBJECTS; n++ ) { p_output[n] = st_ivas->p_output_f[n]; +#ifdef IVAS_FLOAT_FIXED + p_output_fx[n] = st_ivas->p_output_fx[n]; +#endif } if ( !st_ivas->hDecoderConfig->Opt_tsm ) @@ -1422,6 +1429,9 @@ ivas_error ivas_jbm_dec_render( for ( n = 0; n < MAX_TRANSPORT_CHANNELS + MAX_NUM_OBJECTS; n++ ) { st_ivas->hTcBuffer->tc[n] = p_output[n]; +#ifdef IVAS_FLOAT_FIXED + st_ivas->hTcBuffer->tc_fx[n] = st_ivas->p_output_fx[n]; +#endif } } else @@ -1498,7 +1508,78 @@ ivas_error ivas_jbm_dec_render( if ( st_ivas->renderer_type == RENDERER_TD_PANNING || st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV_ROOM ) { /* Convert to CICPxx; used also for ISM->CICP19->binaural_room rendering */ +#ifdef IVAS_FLOAT_FIXED + Word16 q = 11; + FOR(Word16 ind1 = 0; ind1 < s_max(st_ivas->hIntSetup.nchan_out_woLFE + st_ivas->hIntSetup.num_lfe, s_max(st_ivas->nchan_transport, st_ivas->nchan_ism)); ind1++) + { + FOR(Word16 ind2 = 0; ind2 < *nSamplesRendered; ind2++) + { + p_output_fx[ind1][ind2] = (Word16)(p_output[ind1][ind2] * (1 << q)); + } + FOR(Word16 ind2 = 0; ind2 < *nSamplesRendered; ind2++) + { + st_ivas->hTcBuffer->tc_fx[ind1][ind2] = (Word32)(st_ivas->hTcBuffer->tc[ind1][ind2] * (1 << q)); + } + } + + FOR(Word16 ind1 = 0; ind1 < MAX_OUTPUT_CHANNELS + MAX_NUM_OBJECTS; ind1++) + { + FOR(Word16 ind2 = 0; ind2 < *nSamplesRendered; ind2++) + { + } + } + FOR(Word16 ind1 = 0; ind1 < st_ivas->hDecoderConfig->output_Fs / FRAMES_PER_SEC; ind1++) + { + st_ivas->hIsmRendererData->interpolator_fx[ind1] = (Word16)(st_ivas->hIsmRendererData->interpolator[ind1] * (32767)); + } + FOR(Word16 ind1 = 0; ind1 < MAX_CICP_CHANNELS - 1; ind1++) + { + FOR(Word16 ind2 = 0; ind2 < MAX_OUTPUT_CHANNELS; ind2++) + { + st_ivas->hIsmRendererData->gains_fx[ind1][ind2] = (Word32)(st_ivas->hIsmRendererData->gains[ind1][ind2] * (1 << 30)); + st_ivas->hIsmRendererData->prev_gains_fx[ind1][ind2] = (Word32)(st_ivas->hIsmRendererData->prev_gains[ind1][ind2] * (1 << 30)); + } + } + FOR(Word16 ind1 = 0; ind1 < MAX_NUM_OBJECTS; ind1++) { + st_ivas->hIsmMetaData[ind1]->azimuth_fx = (Word32)(st_ivas->hIsmMetaData[ind1]->azimuth * (1 << 22)); + st_ivas->hIsmMetaData[ind1]->elevation_fx = (Word32)(st_ivas->hIsmMetaData[ind1]->elevation * (1 << 22)); + } + IF(st_ivas->hCombinedOrientationData) FOR(Word16 ind1 = 0; ind1 < 3; ind1++) + { + FOR(Word16 ind2 = 0; ind2 < 3; ind2++) + { + st_ivas->hCombinedOrientationData->Rmat_fx[0][ind1][ind2] = (Word32)(st_ivas->hCombinedOrientationData->Rmat[0][ind1][ind2] * (1 << 15)); + } + } + + ivas_ism_render_sf_fx( st_ivas, p_output_fx, *nSamplesRendered ); + FOR(Word16 ind1 = 0; ind1 < s_max(st_ivas->hIntSetup.nchan_out_woLFE + st_ivas->hIntSetup.num_lfe, s_max(st_ivas->nchan_transport, st_ivas->nchan_ism)); ind1++) + { + FOR(Word16 ind2 = 0; ind2 < *nSamplesRendered; ind2++) + { + p_output[ind1][ind2] = (float)(p_output_fx[ind1][ind2]) / (float)(1 << q); + } + } + FOR(Word16 ind1 = 0; ind1 < st_ivas->hDecoderConfig->output_Fs / FRAMES_PER_SEC; ind1++) + { + st_ivas->hIsmRendererData->interpolator[ind1] = (float)(st_ivas->hIsmRendererData->interpolator_fx[ind1]) / (float)(1 << 15); + } + FOR(Word16 ind1 = 0; ind1 < MAX_CICP_CHANNELS - 1; ind1++) + { + FOR(Word16 ind2 = 0; ind2 < MAX_OUTPUT_CHANNELS; ind2++) + { + st_ivas->hIsmRendererData->gains[ind1][ind2] = (float)(st_ivas->hIsmRendererData->gains_fx[ind1][ind2]) / (1 << 30); + st_ivas->hIsmRendererData->prev_gains[ind1][ind2] = (float)(st_ivas->hIsmRendererData->prev_gains_fx[ind1][ind2]) / (1 << 30); + } + } + FOR(Word16 ind1 = 0; ind1 < MAX_NUM_OBJECTS; ind1++) { + st_ivas->hIsmMetaData[ind1]->azimuth = (float)(st_ivas->hIsmMetaData[ind1]->azimuth_fx) / (float)(1 << 22); + st_ivas->hIsmMetaData[ind1]->elevation = (float)(st_ivas->hIsmMetaData[ind1]->elevation_fx) / (float)(1 << 22); + } + +#else ivas_ism_render_sf( st_ivas, p_output, *nSamplesRendered ); +#endif } else if ( st_ivas->renderer_type == RENDERER_NON_DIEGETIC_DOWNMIX ) { @@ -1615,7 +1696,78 @@ ivas_error ivas_jbm_dec_render( } /* render objects */ +#ifdef IVAS_FLOAT_FIXED + Word16 q = 15; + FOR(Word16 ind1 = 0; ind1 < s_max(st_ivas->hIntSetup.nchan_out_woLFE + st_ivas->hIntSetup.num_lfe, s_max(st_ivas->nchan_transport, st_ivas->nchan_ism)); ind1++) + { + FOR(Word16 ind2 = 0; ind2 < *nSamplesRendered; ind2++) + { + p_output_fx[ind1][ind2] = (Word16)(p_output[ind1][ind2] * (1 << q)); + } + IF(st_ivas->hTcBuffer->tc) FOR(Word16 ind2 = 0; ind2 < *nSamplesRendered; ind2++) + { + st_ivas->hTcBuffer->tc_fx[ind1][ind2] = (Word32)(st_ivas->hTcBuffer->tc[ind1][ind2] * (1 << q)); + } + } + + FOR(Word16 ind1 = 0; ind1 < MAX_OUTPUT_CHANNELS + MAX_NUM_OBJECTS; ind1++) + { + FOR(Word16 ind2 = 0; ind2 < *nSamplesRendered; ind2++) + { + } + } + FOR(Word16 ind1 = 0; ind1 < st_ivas->hDecoderConfig->output_Fs / FRAMES_PER_SEC; ind1++) + { + st_ivas->hIsmRendererData->interpolator_fx[ind1] = (Word16)(st_ivas->hIsmRendererData->interpolator[ind1] * (32767)); + } + FOR(Word16 ind1 = 0; ind1 < MAX_CICP_CHANNELS - 1; ind1++) + { + FOR(Word16 ind2 = 0; ind2 < MAX_OUTPUT_CHANNELS; ind2++) + { + st_ivas->hIsmRendererData->gains_fx[ind1][ind2] = (Word32)(st_ivas->hIsmRendererData->gains[ind1][ind2] * (1 << 30)); + st_ivas->hIsmRendererData->prev_gains_fx[ind1][ind2] = (Word32)(st_ivas->hIsmRendererData->prev_gains[ind1][ind2] * (1 << 30)); + } + } + FOR(Word16 ind1 = 0; ind1 < MAX_NUM_OBJECTS; ind1++) { + st_ivas->hIsmMetaData[ind1]->azimuth_fx = (Word32)(st_ivas->hIsmMetaData[ind1]->azimuth * (1 << 22)); + st_ivas->hIsmMetaData[ind1]->elevation_fx = (Word32)(st_ivas->hIsmMetaData[ind1]->elevation * (1 << 22)); + } + IF(st_ivas->hCombinedOrientationData) FOR(Word16 ind1 = 0; ind1 < 3; ind1++) + { + FOR(Word16 ind2 = 0; ind2 < 3; ind2++) + { + st_ivas->hCombinedOrientationData->Rmat_fx[0][ind1][ind2] = (Word32)(st_ivas->hCombinedOrientationData->Rmat[0][ind1][ind2] * (1 << 15)); + } + } + + ivas_ism_render_sf_fx( st_ivas, p_output_fx, *nSamplesRendered ); + FOR(Word16 ind1 = 0; ind1 < s_max(st_ivas->hIntSetup.nchan_out_woLFE + st_ivas->hIntSetup.num_lfe, s_max(st_ivas->nchan_transport, st_ivas->nchan_ism)); ind1++) + { + FOR(Word16 ind2 = 0; ind2 < *nSamplesRendered; ind2++) + { + p_output[ind1][ind2] = (float)(p_output_fx[ind1][ind2]) / (float)(1 << q); + } + } + FOR(Word16 ind1 = 0; ind1 < st_ivas->hDecoderConfig->output_Fs / FRAMES_PER_SEC; ind1++) + { + st_ivas->hIsmRendererData->interpolator[ind1] = (float)(st_ivas->hIsmRendererData->interpolator_fx[ind1]) / (float)(1 << 15); + } + FOR(Word16 ind1 = 0; ind1 < MAX_CICP_CHANNELS - 1; ind1++) + { + FOR(Word16 ind2 = 0; ind2 < MAX_OUTPUT_CHANNELS; ind2++) + { + st_ivas->hIsmRendererData->gains[ind1][ind2] = (float)(st_ivas->hIsmRendererData->gains_fx[ind1][ind2]) / (1 << 30); + st_ivas->hIsmRendererData->prev_gains[ind1][ind2] = (float)(st_ivas->hIsmRendererData->prev_gains_fx[ind1][ind2]) / (1 << 30); + } + } + FOR(Word16 ind1 = 0; ind1 < MAX_NUM_OBJECTS; ind1++) { + st_ivas->hIsmMetaData[ind1]->azimuth = (float)(st_ivas->hIsmMetaData[ind1]->azimuth_fx) / (float)(1 << 22); + st_ivas->hIsmMetaData[ind1]->elevation = (float)(st_ivas->hIsmMetaData[ind1]->elevation_fx) / (float)(1 << 22); + } + +#else ivas_ism_render_sf( st_ivas, p_output, *nSamplesRendered ); +#endif /* add already rendered SBA part */ for ( n = 0; n < nchan_out; n++ ) @@ -1872,7 +2024,9 @@ ivas_error ivas_jbm_dec_flush_renderer( int16_t n_samples_to_render; DECODER_TC_BUFFER_HANDLE hTcBuffer; float output[MAX_CICP_CHANNELS][L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES]; + Word32 output_fx[MAX_CICP_CHANNELS][L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES]; float *p_output[MAX_CICP_CHANNELS]; + Word32 *p_output_fx[MAX_CICP_CHANNELS]; if ( !st_ivas->hDecoderConfig->Opt_tsm ) { @@ -1924,6 +2078,9 @@ ivas_error ivas_jbm_dec_flush_renderer( for ( ch_idx = 0; ch_idx < MAX_CICP_CHANNELS; ch_idx++ ) { p_output[ch_idx] = output[ch_idx]; +#ifdef IVAS_FLOAT_FIXED + p_output_fx[ch_idx] = output_fx[ch_idx]; +#endif } if ( st_ivas->ivas_format == ISM_FORMAT ) @@ -1943,7 +2100,78 @@ ivas_error ivas_jbm_dec_flush_renderer( /* Convert to CICPxx; used also for ISM->CICP19->binaural_room rendering */ set_f( st_ivas->hIsmRendererData->interpolator, 1.0f, hTcBuffer->n_samples_granularity ); +#ifdef IVAS_FLOAT_FIXED + Word16 q = 15; + FOR(Word16 ind1 = 0; ind1 < s_max(st_ivas->hIntSetup.nchan_out_woLFE + st_ivas->hIntSetup.num_lfe, s_max(st_ivas->nchan_transport, st_ivas->nchan_ism)); ind1++) + { + FOR(Word16 ind2 = 0; ind2 < *nSamplesRendered; ind2++) + { + p_output_fx[ind1][ind2] = (Word16)(p_output[ind1][ind2] * (1 << q)); + } + IF(st_ivas->hTcBuffer->tc) FOR(Word16 ind2 = 0; ind2 < *nSamplesRendered; ind2++) + { + st_ivas->hTcBuffer->tc_fx[ind1][ind2] = (Word32)(st_ivas->hTcBuffer->tc[ind1][ind2] * (1 << q)); + } + } + + FOR(Word16 ind1 = 0; ind1 < MAX_OUTPUT_CHANNELS + MAX_NUM_OBJECTS; ind1++) + { + FOR(Word16 ind2 = 0; ind2 < *nSamplesRendered; ind2++) + { + } + } + FOR(Word16 ind1 = 0; ind1 < st_ivas->hDecoderConfig->output_Fs / FRAMES_PER_SEC; ind1++) + { + st_ivas->hIsmRendererData->interpolator_fx[ind1] = (Word16)(st_ivas->hIsmRendererData->interpolator[ind1] * (32767)); + } + FOR(Word16 ind1 = 0; ind1 < MAX_CICP_CHANNELS - 1; ind1++) + { + FOR(Word16 ind2 = 0; ind2 < MAX_OUTPUT_CHANNELS; ind2++) + { + st_ivas->hIsmRendererData->gains_fx[ind1][ind2] = (Word32)(st_ivas->hIsmRendererData->gains[ind1][ind2] * (1 << 30)); + st_ivas->hIsmRendererData->prev_gains_fx[ind1][ind2] = (Word32)(st_ivas->hIsmRendererData->prev_gains[ind1][ind2] * (1 << 30)); + } + } + FOR(Word16 ind1 = 0; ind1 < MAX_NUM_OBJECTS; ind1++) { + st_ivas->hIsmMetaData[ind1]->azimuth_fx = (Word32)(st_ivas->hIsmMetaData[ind1]->azimuth * (1 << 22)); + st_ivas->hIsmMetaData[ind1]->elevation_fx = (Word32)(st_ivas->hIsmMetaData[ind1]->elevation * (1 << 22)); + } + IF(st_ivas->hCombinedOrientationData) FOR(Word16 ind1 = 0; ind1 < 3; ind1++) + { + FOR(Word16 ind2 = 0; ind2 < 3; ind2++) + { + st_ivas->hCombinedOrientationData->Rmat_fx[0][ind1][ind2] = (Word32)(st_ivas->hCombinedOrientationData->Rmat[0][ind1][ind2] * (1 << 15)); + } + } + + ivas_ism_render_sf_fx( st_ivas, p_output_fx, *nSamplesRendered ); + FOR(Word16 ind1 = 0; ind1 < s_max(st_ivas->hIntSetup.nchan_out_woLFE + st_ivas->hIntSetup.num_lfe, s_max(st_ivas->nchan_transport, st_ivas->nchan_ism)); ind1++) + { + FOR(Word16 ind2 = 0; ind2 < *nSamplesRendered; ind2++) + { + p_output[ind1][ind2] = (float)(p_output_fx[ind1][ind2]) / (float)(1 << q); + } + } + FOR(Word16 ind1 = 0; ind1 < st_ivas->hDecoderConfig->output_Fs / FRAMES_PER_SEC; ind1++) + { + st_ivas->hIsmRendererData->interpolator[ind1] = (float)(st_ivas->hIsmRendererData->interpolator_fx[ind1]) / (float)(1 << 15); + } + FOR(Word16 ind1 = 0; ind1 < MAX_CICP_CHANNELS - 1; ind1++) + { + FOR(Word16 ind2 = 0; ind2 < MAX_OUTPUT_CHANNELS; ind2++) + { + st_ivas->hIsmRendererData->gains[ind1][ind2] = (float)(st_ivas->hIsmRendererData->gains_fx[ind1][ind2]) / (1 << 30); + st_ivas->hIsmRendererData->prev_gains[ind1][ind2] = (float)(st_ivas->hIsmRendererData->prev_gains_fx[ind1][ind2]) / (1 << 30); + } + } + FOR(Word16 ind1 = 0; ind1 < MAX_NUM_OBJECTS; ind1++) { + st_ivas->hIsmMetaData[ind1]->azimuth = (float)(st_ivas->hIsmMetaData[ind1]->azimuth_fx) / (float)(1 << 22); + st_ivas->hIsmMetaData[ind1]->elevation = (float)(st_ivas->hIsmMetaData[ind1]->elevation_fx) / (float)(1 << 22); + } + +#else ivas_ism_render_sf( st_ivas, p_output, hTcBuffer->n_samples_granularity ); +#endif if ( ( error = ivas_rend_crendProcessSubframe( st_ivas->hCrendWrapper, IVAS_AUDIO_CONFIG_7_1_4, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR, st_ivas->hDecoderConfig, NULL, NULL, NULL, st_ivas->hTcBuffer, p_output, p_output, hTcBuffer->n_samples_granularity, st_ivas->hDecoderConfig->output_Fs ) ) != IVAS_ERR_OK ) @@ -2169,7 +2397,43 @@ void ivas_jbm_dec_get_adapted_linear_interpolator( return; } +#ifdef IVAS_FLOAT_FIXED +void ivas_jbm_dec_get_adapted_linear_interpolator_fx( + const Word16 default_interp_length, /* i : default length of the (full-frame) interpolator */ + const Word16 interp_length, /* i : length of the interpolator to be created */ + Word16 *interpolator_fx /* o : the interpolator */ +) +{ + Word16 jbm_segment_len, idx; + Word16 dec_fx; + jbm_segment_len = ( default_interp_length >> 1 ); + dec_fx = 32767 / default_interp_length; + move16(); + + interpolator_fx[interp_length - 1] = 32767; + FOR ( idx = interp_length - 2; idx >= jbm_segment_len; idx-- ) + { + interpolator_fx[idx] = s_max( 0, sub(interpolator_fx[idx + 1], dec_fx) ); + } + + IF ( GT_16(interpolator_fx[idx + 1], 0 ) ) + { + dec_fx = interpolator_fx[idx + 1] / ( jbm_segment_len + 1 ); + move16(); + FOR ( ; idx >= 0; idx-- ) + { + interpolator_fx[idx] = sub(interpolator_fx[idx + 1], dec_fx); + } + } + ELSE + { + set16_fx( interpolator_fx, 0, idx + 1 ); + } + + return; +} +#endif /*--------------------------------------------------------------------------* * ivas_jbm_dec_get_adapted_subframes() @@ -3020,11 +3284,11 @@ ivas_error ivas_jbm_dec_tc_buffer_open( } set_zero( hTcBuffer->tc_buffer, nsamp_to_allocate ); #ifdef IVAS_FLOAT_FIXED - IF ( ( hTcBuffer->tc_buffer_fx = (Word16 *) malloc( nsamp_to_allocate * sizeof( Word16 ) ) ) == NULL ) + IF ( ( hTcBuffer->tc_buffer_fx = (Word32 *) malloc( nsamp_to_allocate * sizeof( Word32 ) ) ) == NULL ) { return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for JBM TC Buffer\n" ) ); } - set16_fx( hTcBuffer->tc_buffer_fx, 0, nsamp_to_allocate ); + set32_fx( hTcBuffer->tc_buffer_fx, 0, nsamp_to_allocate ); #endif offset = 0; @@ -3197,11 +3461,11 @@ ivas_error ivas_jbm_dec_tc_buffer_open_fx( } set_zero( hTcBuffer->tc_buffer, nsamp_to_allocate ); #endif - IF ( ( hTcBuffer->tc_buffer_fx = (Word16 *) malloc( nsamp_to_allocate * sizeof( Word16 ) ) ) == NULL ) + IF ( ( hTcBuffer->tc_buffer_fx = (Word32 *) malloc( nsamp_to_allocate * sizeof( Word32 ) ) ) == NULL ) { return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for JBM TC Buffer\n" ) ); } - set16_fx( hTcBuffer->tc_buffer_fx, 0, nsamp_to_allocate ); + set32_fx( hTcBuffer->tc_buffer_fx, 0, nsamp_to_allocate ); offset = 0; move16(); @@ -3345,11 +3609,11 @@ ivas_error ivas_jbm_dec_tc_buffer_reconfigure( } set_zero( hTcBuffer->tc_buffer, nsamp_to_allocate ); #ifdef IVAS_FLOAT_FIXED - if ( ( hTcBuffer->tc_buffer_fx = (Word16 *) malloc( nsamp_to_allocate * sizeof( Word16 ) ) ) == NULL ) + if ( ( hTcBuffer->tc_buffer_fx = (Word32 *) malloc( nsamp_to_allocate * sizeof( Word32 ) ) ) == NULL ) { return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for JBM TC Buffer\n" ) ); } - set16_fx( hTcBuffer->tc_buffer_fx, 0, nsamp_to_allocate ); + set32_fx( hTcBuffer->tc_buffer_fx, 0, nsamp_to_allocate ); #endif offset = 0; @@ -3472,11 +3736,11 @@ ivas_error ivas_jbm_dec_tc_buffer_reconfigure_fx( IF ( st_ivas->hDecoderConfig->Opt_tsm ) { - IF ( ( hTcBuffer->tc_buffer_fx = (Word16 *) malloc( nsamp_to_allocate * sizeof( Word16 ) ) ) == NULL ) + IF ( ( hTcBuffer->tc_buffer_fx = (Word32 *) malloc( nsamp_to_allocate * sizeof( Word32 ) ) ) == NULL ) { return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory FOR JBM TC Buffer\n" ) ); } - set16_fx( hTcBuffer->tc_buffer_fx, 0, nsamp_to_allocate ); + set32_fx( hTcBuffer->tc_buffer_fx, 0, nsamp_to_allocate ); offset = 0; move16(); diff --git a/lib_dec/ivas_ls_custom_dec.c b/lib_dec/ivas_ls_custom_dec.c index 15081bd91..00f4c7e7d 100644 --- a/lib_dec/ivas_ls_custom_dec.c +++ b/lib_dec/ivas_ls_custom_dec.c @@ -85,8 +85,8 @@ ivas_error ivas_ls_custom_open_fx( ( *hLsSetupCustom )->num_spk = -1; ( *hLsSetupCustom )->is_planar_setup = -1; - set16_fx( ( *hLsSetupCustom )->ls_azimuth_fx, 0, MAX_OUTPUT_CHANNELS ); - set16_fx( ( *hLsSetupCustom )->ls_elevation_fx, 0, MAX_OUTPUT_CHANNELS ); + set32_fx( ( *hLsSetupCustom )->ls_azimuth_fx, 0, MAX_OUTPUT_CHANNELS ); + set32_fx( ( *hLsSetupCustom )->ls_elevation_fx, 0, MAX_OUTPUT_CHANNELS ); ( *hLsSetupCustom )->num_lfe = -1; set_s( ( *hLsSetupCustom )->lfe_idx, -1, MAX_OUTPUT_CHANNELS ); @@ -106,12 +106,21 @@ ivas_error ivas_ls_custom_open_fx( void ivas_ls_custom_setup( IVAS_OUTPUT_SETUP_HANDLE hOutSetup, /* o : IVAS output setup handle */ - const LSSETUP_CUSTOM_STRUCT *hLsSetupCustom /* i : Custom loudspeaker setup handle */ + LSSETUP_CUSTOM_STRUCT *hLsSetupCustom /* i : Custom loudspeaker setup handle */ // Removed const temporarily. Can be added later. ) { hOutSetup->output_config = IVAS_AUDIO_CONFIG_LS_CUSTOM; hOutSetup->nchan_out_woLFE = hLsSetupCustom->num_spk; +#ifdef IVAS_FLOAT_FIXED + FOR(int ind = 0; ind < MAX_OUTPUT_CHANNELS; ind++) + { + hLsSetupCustom->ls_azimuth_fx[ind] = (Word32)(hLsSetupCustom->ls_azimuth[ind] * (1 << 22)); + hLsSetupCustom->ls_elevation_fx[ind] = (Word32)(hLsSetupCustom->ls_elevation[ind] * (1 << 22)); + } + hOutSetup->ls_azimuth_fx = hLsSetupCustom->ls_azimuth_fx; + hOutSetup->ls_elevation_fx = hLsSetupCustom->ls_elevation_fx; +#endif hOutSetup->ls_azimuth = hLsSetupCustom->ls_azimuth; hOutSetup->ls_elevation = hLsSetupCustom->ls_elevation; diff --git a/lib_dec/ivas_omasa_dec.c b/lib_dec/ivas_omasa_dec.c index 5a8aac240..0c0b8e502 100644 --- a/lib_dec/ivas_omasa_dec.c +++ b/lib_dec/ivas_omasa_dec.c @@ -34,6 +34,7 @@ #include #include "ivas_cnst.h" #include "ivas_prot.h" +#include "ivas_prot_fx.h" #include "prot.h" #include "ivas_prot_rend.h" #include "ivas_rom_com.h" @@ -82,6 +83,9 @@ ivas_error ivas_omasa_data_open( hMasaIsmData->objectsMoved = 0; hMasaIsmData->delayBuffer = NULL; +#ifdef IVAS_FLOAT_FIXED + hMasaIsmData->delayBuffer_fx = NULL; +#endif for ( ch = 0; ch < MAX_NUM_OBJECTS; ch++ ) { @@ -138,6 +142,18 @@ void ivas_omasa_data_close( ( *hMasaIsmData )->delayBuffer = NULL; } +#ifdef IVAS_FLOAT_FIXED + IF ( ( *hMasaIsmData )->delayBuffer_fx != NULL ) + { + FOR ( i = 0; i < ( *hMasaIsmData )->delayBuffer_nchan; i++ ) + { + free( ( *hMasaIsmData )->delayBuffer_fx[i] ); + } + free( ( *hMasaIsmData )->delayBuffer_fx ); + ( *hMasaIsmData )->delayBuffer_fx = NULL; + } +#endif + free( *hMasaIsmData ); *hMasaIsmData = NULL; @@ -599,8 +615,180 @@ void ivas_omasa_dirac_rend_jbm( ivas_dirac_dec_render( st_ivas, nchan_transport, nSamplesAsked, nSamplesRendered, nSamplesAvailable, output_f ); +#ifdef IVAS_FLOAT_FIXED1 + Word16 q_output = 31, q_inverse_matrix = 31; + Word32 **output_fx, data_separated_objects_fx[4][960]; + FOR(Word16 ind = 0; ind < st_ivas->hIntSetup.nchan_out_woLFE + st_ivas->hIntSetup.num_lfe; ind++) + { + FOR(Word16 ind2 = 0; ind2 < nSamplesAsked; ind2++) + { + IF(L_abs((Word32)output_f[ind][ind2])!=0) q_output = s_min(q_output, norm_l((Word32)output_f[ind][ind2])); + IF((ind < st_ivas->nchan_ism) && L_abs((Word32)data_separated_objects[ind][ind2])!=0) q_output = s_min(q_output, norm_l((Word32)data_separated_objects[ind][ind2])); + } + } + /*FOR(Word16 ind1 = 0; ind1 < st_ivas->hDecoderConfig->Opt_tsm; ind1++) + { + FOR(Word16 ind2 = 0; ind2 < *nSamplesRendered; ind2++) + { + IF(L_abs((Word32)st_ivas->hTcBuffer->tc[ind1][ind2])!=0) q_output = s_min(q_output, norm_l((Word32)st_ivas->hTcBuffer->tc[ind1][ind2])); + } + }*/ + FOR(Word16 ind1 = 0; ind1 < st_ivas->hMasaIsmData->delayBuffer_nchan; ind1++) + { + FOR(Word16 ind2 = 0; ind2 < st_ivas->hMasaIsmData->delayBuffer_size; ind2++) + { + IF(L_abs((Word32)st_ivas->hMasaIsmData->delayBuffer[ind1][ind2])!=0)q_output = s_min(q_output, norm_l((Word32)st_ivas->hMasaIsmData->delayBuffer[ind1][ind2])); + } + } + + q_output -= 1; // guard bit + FOR(Word16 ind = 0; ind < MAX_NUM_OBJECTS; ind++) + { + FOR(Word16 ind2 = 0; ind2 < nSamplesAsked; ind2++) + { + data_separated_objects_fx[ind][ind2] = (Word32)(data_separated_objects[ind][ind2] * (1<hIntSetup.nchan_out_woLFE + st_ivas->hIntSetup.num_lfe)); + FOR(Word16 ind = 0; ind < st_ivas->hIntSetup.nchan_out_woLFE + st_ivas->hIntSetup.num_lfe; ind++) + { + output_fx[ind] = (Word32*)malloc(sizeof(Word32) * nSamplesAsked); + FOR(Word16 ind2 = 0; ind2 < nSamplesAsked; ind2++) + { + output_fx[ind][ind2] =(Word32)(output_f[ind][ind2] * (1<hVBAPdata) + FOR(Word16 ind1 = 0; ind1 < 2; ind1++) + { + FOR(Word16 ind2 = 0; ind2 < 4; ind2++) + { + FOR(Word16 ind3 = 0; ind3 < 3; ind3++) + { + FOR(Word16 ind4 = 0; ind4 < 3; ind4++) + { + IF (L_abs((Word32)st_ivas->hVBAPdata->search_struct[ind1].triplets[ind2].inverse_matrix[ind3][ind4]) != 0) + { + q_inverse_matrix = s_min(q_inverse_matrix, norm_l((Word32)st_ivas->hVBAPdata->search_struct[ind1].triplets[ind2].inverse_matrix[ind3][ind4])); + } + } + } + } + } + IF(st_ivas->hVBAPdata) + { + IF(st_ivas->hVBAPdata->back_virtual_speaker_node_division_gains) + FOR(Word16 ind = 0; ind < st_ivas->hVBAPdata->num_speaker_nodes; ind++) + { + st_ivas->hVBAPdata->back_virtual_speaker_node_division_gains_fx[ind] = (Word32)(st_ivas->hVBAPdata->back_virtual_speaker_node_division_gains[ind] * (2147483647)); + } + IF(st_ivas->hVBAPdata->bottom_virtual_speaker_node_division_gains) + FOR(Word16 ind = 0; ind < st_ivas->hVBAPdata->num_speaker_nodes; ind++) + { + st_ivas->hVBAPdata->bottom_virtual_speaker_node_division_gains_fx[ind] = (Word32)(st_ivas->hVBAPdata->bottom_virtual_speaker_node_division_gains[ind] * (2147483647)); + } + IF(st_ivas->hVBAPdata->top_virtual_speaker_node_division_gains) + FOR(Word16 ind = 0; ind < st_ivas->hVBAPdata->num_speaker_nodes; ind++) + { + st_ivas->hVBAPdata->top_virtual_speaker_node_division_gains_fx[ind] = (Word32)(st_ivas->hVBAPdata->top_virtual_speaker_node_division_gains[ind] * (2147483647)); + } + IF(st_ivas->hVBAPdata->object_mode_bottom_virtual_speaker_node_division_gains) + FOR(Word16 ind = 0; ind < st_ivas->hVBAPdata->num_speaker_nodes; ind++) + { + st_ivas->hVBAPdata->object_mode_bottom_virtual_speaker_node_division_gains_fx[ind] = (Word32)(st_ivas->hVBAPdata->object_mode_bottom_virtual_speaker_node_division_gains[ind] * (2147483647)); + } + IF(st_ivas->hVBAPdata->object_mode_back_virtual_speaker_node_division_gains) + FOR(Word16 ind = 0; ind < st_ivas->hVBAPdata->num_speaker_nodes; ind++) + { + st_ivas->hVBAPdata->object_mode_back_virtual_speaker_node_division_gains_fx[ind] = (Word32)(st_ivas->hVBAPdata->object_mode_back_virtual_speaker_node_division_gains[ind] * (2147483647)); + } + IF(st_ivas->hVBAPdata->object_mode_top_virtual_speaker_node_division_gains) + FOR(Word16 ind = 0; ind < st_ivas->hVBAPdata->num_speaker_nodes; ind++) + { + st_ivas->hVBAPdata->object_mode_top_virtual_speaker_node_division_gains_fx[ind] = (Word32)(st_ivas->hVBAPdata->object_mode_top_virtual_speaker_node_division_gains[ind] * (2147483647)); + } + } + IF(st_ivas->hVBAPdata) + FOR(Word16 ind1 = 0; ind1 < 2; ind1++) + { + FOR(Word16 ind2 = 0; ind2 < st_ivas->hVBAPdata->search_struct[ind1].num_triplets; ind2++) + { + st_ivas->hVBAPdata->search_struct[ind1].triplets[ind2].q_inverse_matrix = q_inverse_matrix; + FOR(Word16 ind3 = 0; ind3 < 3; ind3++) + { + FOR(Word16 ind4 = 0; ind4 < 3; ind4++) + { + st_ivas->hVBAPdata->search_struct[ind1].triplets[ind2].inverse_matrix_fx[ind3][ind4] = (Word32)(st_ivas->hVBAPdata->search_struct[ind1].triplets[ind2].inverse_matrix[ind3][ind4] * (1 << q_inverse_matrix)); + } + } + } + } + FOR(Word16 ind1 = 0; ind1 < st_ivas->hDecoderConfig->Opt_tsm; ind1++) + { + FOR(Word16 ind2 = 0; ind2 < *nSamplesRendered; ind2++) + { + st_ivas->hTcBuffer->tc_fx[ind1][ind2] = (Word32)(st_ivas->hTcBuffer->tc[ind1][ind2] * (1 << q_output)); + } + } + FOR(Word16 ind1 = 0; ind1 < st_ivas->hMasaIsmData->delayBuffer_nchan; ind1++) + { + FOR(Word16 ind2 = 0; ind2 < st_ivas->hMasaIsmData->delayBuffer_size; ind2++) + { + st_ivas->hMasaIsmData->delayBuffer_fx[ind1][ind2] = (Word32)(st_ivas->hMasaIsmData->delayBuffer[ind1][ind2] * (1 << q_output)); + } + } + FOR ( Word16 k = 0; k < st_ivas->hIsmRendererData->interpolator_length; k++ ) + { + st_ivas->hIsmRendererData->interpolator_fx[k] = (Word16)(st_ivas->hIsmRendererData->interpolator[k] * (1<<15)); + } + FOR(Word16 ind1 = 0; ind1 < MAX_CICP_CHANNELS - 1; ind1++) + { + FOR(Word16 ind2 = 0; ind2 < MAX_OUTPUT_CHANNELS; ind2++) + { + st_ivas->hIsmRendererData->prev_gains_fx[ind1][ind2] = (Word32)(st_ivas->hIsmRendererData->prev_gains[ind1][ind2] * (1 << 29)); + } + } + + //ivas_omasa_separate_object_render_jbm_fx( st_ivas, *nSamplesRendered, data_separated_objects_fx, output_fx, subframes_rendered, slots_rendered ); ivas_omasa_separate_object_render_jbm( st_ivas, *nSamplesRendered, data_separated_objects, output_f, subframes_rendered, slots_rendered ); + /*FOR(Word16 ind = 0; ind < st_ivas->hIntSetup.nchan_out_woLFE + st_ivas->hIntSetup.num_lfe; ind++) + { + FOR(Word16 ind2 = 0; ind2 < nSamplesAsked; ind2++) + { + output_f[ind][ind2] =(float)(output_fx[ind][ind2]) / (float)(1<hIsmRendererData->prev_gains[ind1][ind2] = (float)(st_ivas->hIsmRendererData->prev_gains_fx[ind1][ind2]) / (float)(1 << 29); + } + } + FOR(Word16 ind1 = 0; ind1 < st_ivas->hDecoderConfig->Opt_tsm; ind1++) + { + FOR(Word16 ind2 = 0; ind2 < *nSamplesRendered; ind2++) + { + st_ivas->hTcBuffer->tc[ind1][ind2] = (float)(st_ivas->hTcBuffer->tc_fx[ind1][ind2]) / (float)(1 << q_output); + } + } + FOR(Word16 ind1 = 0; ind1 < st_ivas->hMasaIsmData->delayBuffer_nchan; ind1++) + { + FOR(Word16 ind2 = 0; ind2 < st_ivas->hMasaIsmData->delayBuffer_size; ind2++) + { + st_ivas->hMasaIsmData->delayBuffer[ind1][ind2] = (float)(st_ivas->hMasaIsmData->delayBuffer_fx[ind1][ind2]) / (float)(1 << q_output); + } + } + FOR ( Word16 k = 0; k < st_ivas->hIsmRendererData->interpolator_length; k++ ) + { + st_ivas->hIsmRendererData->interpolator[k] = (float)st_ivas->hIsmRendererData->interpolator_fx[k] / (float)(1<<15); + }*/ +#else + ivas_omasa_separate_object_render_jbm( st_ivas, *nSamplesRendered, data_separated_objects, output_f, subframes_rendered, slots_rendered ); +#endif return; } diff --git a/lib_dec/ivas_sba_dec.c b/lib_dec/ivas_sba_dec.c index af31ff535..55fd202fe 100644 --- a/lib_dec/ivas_sba_dec.c +++ b/lib_dec/ivas_sba_dec.c @@ -494,10 +494,30 @@ ivas_error ivas_sba_dec_reconfigure( st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV_ROOM || st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV_ROOM ) ) { +#ifdef IVAS_FLOAT_FIXED + IF ( ( error = ivas_ism_renderer_open_fx( st_ivas ) ) != IVAS_ERR_OK ) + { + return error; + } + FOR(Word16 ind = 0; ind < st_ivas->hDecoderConfig->output_Fs / FRAMES_PER_SEC; ind++) + { + st_ivas->hIsmRendererData->interpolator[ind] = (float)(st_ivas->hIsmRendererData->interpolator_fx[ind]) / (float)(1 << 15); + } + FOR(Word16 ind1 = 0; ind1 < MAX_NUM_OBJECTS; ind1++) + { + FOR(Word16 ind2 = 0; ind2 < MAX_OUTPUT_CHANNELS; ind2++) + { + // q factors might be different. Here we are just initializing to zero + st_ivas->hIsmRendererData->prev_gains[ind1][ind2] = (float)(st_ivas->hIsmRendererData->prev_gains_fx[ind1][ind2]) / (float)(1<<31); + st_ivas->hIsmRendererData->gains[ind1][ind2] = (float)(st_ivas->hIsmRendererData->gains_fx[ind1][ind2]) / (float)(1<<31); + } + } +#else if ( ( error = ivas_ism_renderer_open( st_ivas ) ) != IVAS_ERR_OK ) { return error; } +#endif } if ( st_ivas->renderer_type == RENDERER_MONO_DOWNMIX ) diff --git a/lib_dec/ivas_stat_dec.h b/lib_dec/ivas_stat_dec.h index ec070d505..51dba7ff5 100644 --- a/lib_dec/ivas_stat_dec.h +++ b/lib_dec/ivas_stat_dec.h @@ -886,6 +886,11 @@ typedef struct renderer_struct { float prev_gains[MAX_CICP_CHANNELS - 1][MAX_OUTPUT_CHANNELS]; float *interpolator; +#ifdef IVAS_FLOAT_FIXED + Word32 prev_gains_fx[MAX_CICP_CHANNELS - 1][MAX_OUTPUT_CHANNELS]; + Word16 *interpolator_fx; + Word32 gains_fx[MAX_CICP_CHANNELS - 1][MAX_OUTPUT_CHANNELS]; +#endif int16_t interpolator_length; float gains[MAX_CICP_CHANNELS - 1][MAX_OUTPUT_CHANNELS]; @@ -987,6 +992,10 @@ typedef struct ivas_masa_ism_data_structure float preprocEneRealized[CLDFB_NO_CHANNELS_MAX]; float **delayBuffer; +#ifdef IVAS_FLOAT_FIXED + Word32 **delayBuffer_fx; +#endif + int16_t delayBuffer_size; int16_t delayBuffer_nchan; @@ -1002,8 +1011,8 @@ typedef struct decoder_tc_buffer_structure float *tc_buffer; /* the buffer itself */ float *tc[MAX_OUTPUT_CHANNELS + MAX_NUM_OBJECTS]; /* pointers into the buffer to the beginning of each tc */ // VE2SB: TBV #ifdef IVAS_FLOAT_FIXED - Word16 *tc_buffer_fx; /* the buffer itself */ - Word16 *tc_fx[MAX_OUTPUT_CHANNELS + MAX_NUM_OBJECTS]; /* pointers into the buffer to the beginning of each tc */ // VE2SB: TBV + Word32 *tc_buffer_fx; /* the buffer itself */ + Word32 *tc_fx[MAX_OUTPUT_CHANNELS + MAX_NUM_OBJECTS]; /* pointers into the buffer to the beginning of each tc */ // VE2SB: TBV #endif TC_BUFFER_MODE tc_buffer_mode; /* mode of the buffer (no buffering, render buffering, out buffering) */ int16_t nchan_transport_jbm; /* number of TCs after TC decoding */ @@ -1112,6 +1121,9 @@ typedef struct Decoder_Struct IVAS_LIMITER_HANDLE hLimiter; /* Limiter handle */ float *p_output_f[MAX_OUTPUT_CHANNELS+MAX_NUM_OBJECTS]; /* floating-point output audio buffers */ +#ifdef IVAS_FLOAT_FIXED + Word32 *p_output_fx[MAX_OUTPUT_CHANNELS+MAX_NUM_OBJECTS]; /* floating-point output audio buffers */ +#endif /* core-decoder modules */ int16_t nSCE; /* number of total SCEs */ diff --git a/lib_rend/ivas_omasa_ana.c b/lib_rend/ivas_omasa_ana.c index 8c4c5a458..31ed3e6ab 100644 --- a/lib_rend/ivas_omasa_ana.c +++ b/lib_rend/ivas_omasa_ana.c @@ -36,6 +36,7 @@ #include "ivas_cnst.h" #include "ivas_prot_rend.h" #include "ivas_prot.h" +#include "ivas_prot_fx.h" #include "prot.h" #include "ivas_stat_rend.h" #include "ivas_rom_com.h" @@ -489,8 +490,14 @@ static void ivas_omasa_dmx( { azimuth = ism_azimuth[i]; elevation = ism_elevation[i]; - +#ifdef IVAS_FLOAT_FIXED + Word16 gains_fx[2]; + ivas_ism_get_stereo_gains_fx( (Word16)azimuth, (Word16)elevation, &gains_fx[0], &gains_fx[1] ); + gains[0] = (float)gains_fx[0] / 32768.f; + gains[1] = (float)gains_fx[1] / 32768.f; +#else ivas_ism_get_stereo_gains( azimuth, elevation, &gains[0], &gains[1] ); +#endif /* Downmix using the panning gains */ for ( j = 0; j < nchan_transport; j++ ) diff --git a/lib_rend/ivas_orient_trk.c b/lib_rend/ivas_orient_trk.c index d355bc5a7..57bede878 100644 --- a/lib_rend/ivas_orient_trk.c +++ b/lib_rend/ivas_orient_trk.c @@ -477,7 +477,7 @@ static IVAS_VECTOR3_FX VectorSubtract_fx( result.z_fx = L_sub( p1.z_fx, p2.z_fx ); result.x_qfact = p1.x_qfact; result.y_qfact = p1.y_qfact; - result.y_qfact = p1.y_qfact; + result.z_qfact = p1.z_qfact; return result; } @@ -914,8 +914,8 @@ ivas_error ivas_orient_trk_SetReferenceVector( case IVAS_HEAD_ORIENT_TRK_AVG: case IVAS_HEAD_ORIENT_TRK_REF_VEC: #ifdef IVAS_FLOAT_FIXED - listenerPos_fx.x_qfact = listenerPos_fx.y_qfact = listenerPos_fx.z_qfact = Q29; - refPos_fx.x_qfact = refPos_fx.y_qfact = refPos_fx.z_qfact = Q29; + listenerPos_fx.x_qfact = listenerPos_fx.y_qfact = listenerPos_fx.z_qfact = Q27; + refPos_fx.x_qfact = refPos_fx.y_qfact = refPos_fx.z_qfact = Q27; listenerPos_fx.x_fx = float_to_fix( listenerPos.x, listenerPos_fx.x_qfact ); listenerPos_fx.y_fx = float_to_fix( listenerPos.y, listenerPos_fx.y_qfact ); listenerPos_fx.z_fx = float_to_fix( listenerPos.z, listenerPos_fx.z_qfact ); diff --git a/lib_rend/ivas_output_init.c b/lib_rend/ivas_output_init.c index c04424820..370409e5a 100644 --- a/lib_rend/ivas_output_init.c +++ b/lib_rend/ivas_output_init.c @@ -36,6 +36,7 @@ #include "prot.h" #include "ivas_prot_rend.h" #include "ivas_rom_com.h" +#include "ivas_rom_com_fx.h" #include "ivas_prot.h" #include "wmc_auto.h" #ifdef IVAS_FLOAT_FIXED @@ -389,6 +390,10 @@ void ivas_output_init( /* Set default values for all other than custom LS setup */ hOutSetup->ls_azimuth = NULL; hOutSetup->ls_elevation = NULL; +#ifdef IVAS_FLOAT_FIXED + hOutSetup->ls_azimuth_fx = NULL; + hOutSetup->ls_elevation_fx = NULL; +#endif hOutSetup->num_lfe = 0; hOutSetup->index_lfe[0] = -1; hOutSetup->is_planar_setup = 0; @@ -403,6 +408,10 @@ void ivas_output_init( hOutSetup->is_loudspeaker_setup = 1; hOutSetup->ls_azimuth = ls_azimuth_CICP2; hOutSetup->ls_elevation = ls_elevation_CICP2; +#ifdef IVAS_FLOAT_FIXED + hOutSetup->ls_azimuth_fx = ls_azimuth_CICP2_fx; + hOutSetup->ls_elevation_fx = ls_elevation_CICP2_fx; +#endif break; case IVAS_AUDIO_CONFIG_FOA: hOutSetup->ambisonics_order = SBA_FOA_ORDER; @@ -419,6 +428,10 @@ void ivas_output_init( hOutSetup->is_loudspeaker_setup = 1; hOutSetup->ls_azimuth = ls_azimuth_CICP6; hOutSetup->ls_elevation = ls_elevation_CICP6; +#ifdef IVAS_FLOAT_FIXED + hOutSetup->ls_azimuth_fx = ls_azimuth_CICP6_fx; + hOutSetup->ls_elevation_fx = ls_elevation_CICP6_fx; +#endif hOutSetup->is_planar_setup = 1; break; case IVAS_AUDIO_CONFIG_7_1: @@ -427,6 +440,10 @@ void ivas_output_init( hOutSetup->is_loudspeaker_setup = 1; hOutSetup->ls_azimuth = ls_azimuth_CICP12; hOutSetup->ls_elevation = ls_elevation_CICP12; +#ifdef IVAS_FLOAT_FIXED + hOutSetup->ls_azimuth_fx = ls_azimuth_CICP12_fx; + hOutSetup->ls_elevation_fx = ls_elevation_CICP12_fx; +#endif hOutSetup->is_planar_setup = 1; break; case IVAS_AUDIO_CONFIG_5_1_2: @@ -435,6 +452,10 @@ void ivas_output_init( hOutSetup->is_loudspeaker_setup = 1; hOutSetup->ls_azimuth = ls_azimuth_CICP14; hOutSetup->ls_elevation = ls_elevation_CICP14; +#ifdef IVAS_FLOAT_FIXED + hOutSetup->ls_azimuth_fx = ls_azimuth_CICP14_fx; + hOutSetup->ls_elevation_fx = ls_elevation_CICP14_fx; +#endif hOutSetup->is_planar_setup = 0; break; case IVAS_AUDIO_CONFIG_5_1_4: @@ -443,6 +464,10 @@ void ivas_output_init( hOutSetup->is_loudspeaker_setup = 1; hOutSetup->ls_azimuth = ls_azimuth_CICP16; hOutSetup->ls_elevation = ls_elevation_CICP16; +#ifdef IVAS_FLOAT_FIXED + hOutSetup->ls_azimuth_fx = ls_azimuth_CICP16_fx; + hOutSetup->ls_elevation_fx = ls_elevation_CICP16_fx; +#endif hOutSetup->is_planar_setup = 0; break; case IVAS_AUDIO_CONFIG_7_1_4: @@ -451,6 +476,10 @@ void ivas_output_init( hOutSetup->is_loudspeaker_setup = 1; hOutSetup->ls_azimuth = ls_azimuth_CICP19; hOutSetup->ls_elevation = ls_elevation_CICP19; +#ifdef IVAS_FLOAT_FIXED + hOutSetup->ls_azimuth_fx = ls_azimuth_CICP19_fx; + hOutSetup->ls_elevation_fx = ls_elevation_CICP19_fx; +#endif hOutSetup->is_planar_setup = 0; break; case IVAS_AUDIO_CONFIG_BINAURAL: diff --git a/lib_rend/ivas_prot_rend.h b/lib_rend/ivas_prot_rend.h index 350cd9eba..d9dec4a6a 100644 --- a/lib_rend/ivas_prot_rend.h +++ b/lib_rend/ivas_prot_rend.h @@ -261,6 +261,15 @@ void vbap_determine_gains( const int16_t ele_deg, /* i : elevation in degrees for panning direction (positive up) */ const int16_t use_object_mode /* i : select between object mode panning and spatial mode panning */ ); +#ifdef IVAS_FLOAT_FIXED +void vbap_determine_gains_fx( + const VBAP_HANDLE hVBAPdata, /* i : prepared VBAP structure */ + Word32 *gains_fx, /* o : gain vector for loudspeakers for given direction */ + const Word16 azi_deg, /* i : azimuth in degrees for panning direction (positive left) */ + const Word16 ele_deg, /* i : elevation in degrees for panning direction (positive up) */ + const Word16 use_object_mode /* i : select between object mode panning and spatial mode panning */ +); +#endif /*----------------------------------------------------------------------------------* diff --git a/lib_rend/ivas_stat_rend.h b/lib_rend/ivas_stat_rend.h index de84dd633..5edd1f889 100644 --- a/lib_rend/ivas_stat_rend.h +++ b/lib_rend/ivas_stat_rend.h @@ -58,10 +58,13 @@ typedef struct ivas_output_setup_structure Word16 num_lfe; Word16 index_lfe[1]; - const Word16 *ls_azimuth_fx; const float *ls_azimuth; const float *ls_elevation; - const Word16 *ls_elevation_fx; +#ifdef IVAS_FLOAT_FIXED + const Word32 *ls_azimuth_fx; + const Word32 *ls_elevation_fx; +#endif + UWord8 separateChannelEnabled; Word16 separateChannelIndex; @@ -82,8 +85,8 @@ typedef struct ivas_output_setup_structure const float *ls_azimuth; const float *ls_elevation; - const Word16 *ls_azimuth_fx; - const Word16 *ls_elevation_fx; + const Word32 *ls_azimuth_fx; + const Word32 *ls_elevation_fx; uint8_t separateChannelEnabled; int16_t separateChannelIndex; @@ -483,6 +486,10 @@ typedef struct vbap_vs_triplet_structure { uint8_t speaker_node[3]; float inverse_matrix[3][3]; +#ifdef IVAS_FLOAT_FIXED + Word32 inverse_matrix_fx[3][3]; + Word16 q_inverse_matrix; +#endif } VBAP_VS_TRIPLET; @@ -513,6 +520,14 @@ typedef struct vbap_data_structure float *object_mode_bottom_virtual_speaker_node_division_gains; float *object_mode_top_virtual_speaker_node_division_gains; float *object_mode_back_virtual_speaker_node_division_gains; +#ifdef IVAS_FLOAT_FIXED + Word32 *bottom_virtual_speaker_node_division_gains_fx; + Word32 *top_virtual_speaker_node_division_gains_fx; + Word32 *back_virtual_speaker_node_division_gains_fx; + Word32 *object_mode_bottom_virtual_speaker_node_division_gains_fx; + Word32 *object_mode_top_virtual_speaker_node_division_gains_fx; + Word32 *object_mode_back_virtual_speaker_node_division_gains_fx; +#endif } VBAP_DATA, *VBAP_HANDLE; @@ -1729,13 +1744,15 @@ typedef struct ivas_LS_setup_custom int16_t num_spk; /* number of custom loudspeakers */ float ls_azimuth[MAX_OUTPUT_CHANNELS]; /* custom loudspeaker azimuths */ float ls_elevation[MAX_OUTPUT_CHANNELS]; /* custom loudspeaker elevations */ +#ifdef IVAS_FLOAT_FIXED + Word32 ls_azimuth_fx[MAX_OUTPUT_CHANNELS]; /* custom loudspeaker azimuths */ + Word32 ls_elevation_fx[MAX_OUTPUT_CHANNELS]; /* custom loudspeaker elevations */ +#endif int16_t num_lfe; /* number of LFE channels */ int16_t lfe_idx[MAX_OUTPUT_CHANNELS]; /* index for LFE channel insertion */ int16_t separate_ch_found; /* flag to indicate if a center channel was found */ float separate_ch_gains[MAX_OUTPUT_CHANNELS]; /* gains to pan McMASA separateChannel in case no center channel is present */ - Word16 ls_azimuth_fx[MAX_OUTPUT_CHANNELS]; /* custom loudspeaker azimuths */ - Word16 ls_elevation_fx[MAX_OUTPUT_CHANNELS]; /* custom loudspeaker elevations */ Word16 separate_ch_gains_fx[MAX_OUTPUT_CHANNELS]; /* gains to pan McMASA separateChannel in case no center channel is present */ } LSSETUP_CUSTOM_STRUCT, *LSSETUP_CUSTOM_HANDLE; diff --git a/lib_rend/ivas_vbap.c b/lib_rend/ivas_vbap.c index 38a7a86c0..e33555d32 100644 --- a/lib_rend/ivas_vbap.c +++ b/lib_rend/ivas_vbap.c @@ -35,6 +35,7 @@ #include #include #include "prot.h" +#include "prot_fx2.h" #include "ivas_prot.h" #include "ivas_prot_rend.h" #include "ivas_stat_dec.h" @@ -139,6 +140,10 @@ static enum VirtualSpeakerNodeType check_need_of_virtual_speaker_node( VBAP_HAND static int16_t determine_best_triplet_and_gains( VBAP_SEARCH_STRUCT *search_struct, const float panning_unit_vec[3], const int16_t azi_deg, float gains[3] ); +#ifdef IVAS_FLOAT_FIXED +static Word16 determine_best_triplet_and_gains_fx( VBAP_SEARCH_STRUCT *search_struct, const Word16 panning_unit_vec_fx[3], const Word16 azi_deg, Word32 gains_fx[3] ); +#endif + static void determine_virtual_speaker_node_division_gains( const int16_t virtual_speaker_node_index, float *virtual_node_division_gains, int16_t connections[][2], const enum VirtualSpeakerNodeType type, const int16_t max_num_connections, const int16_t num_speaker_nodes, const int16_t use_object_mode ); static void reorder_triplets( VBAP_VS_TRIPLET *triplets, const int16_t *target_order, const int16_t num_triplets ); @@ -209,6 +214,14 @@ ivas_error vbap_init_data( vbap->object_mode_bottom_virtual_speaker_node_division_gains = NULL; vbap->object_mode_top_virtual_speaker_node_division_gains = NULL; vbap->object_mode_back_virtual_speaker_node_division_gains = NULL; +#ifdef IVAS_FLOAT_FIXED + vbap->bottom_virtual_speaker_node_division_gains_fx = NULL; + vbap->top_virtual_speaker_node_division_gains_fx = NULL; + vbap->back_virtual_speaker_node_division_gains_fx = NULL; + vbap->object_mode_bottom_virtual_speaker_node_division_gains_fx = NULL; + vbap->object_mode_top_virtual_speaker_node_division_gains_fx = NULL; + vbap->object_mode_back_virtual_speaker_node_division_gains_fx = NULL; +#endif vbap->num_speaker_nodes = num_speaker_nodes; vbap->num_speaker_nodes_internal = num_speaker_nodes; @@ -230,6 +243,13 @@ ivas_error vbap_init_data( return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for VBAP data\n" ) ); } set_zero( vbap->bottom_virtual_speaker_node_division_gains, num_speaker_nodes ); +#ifdef IVAS_FLOAT_FIXED + IF ( ( vbap->bottom_virtual_speaker_node_division_gains_fx = (Word32 *) malloc( num_speaker_nodes * sizeof( Word32 ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for VBAP data\n" ) ); + } + set32_fx( vbap->bottom_virtual_speaker_node_division_gains_fx, 0, num_speaker_nodes ); +#endif is_success &= vbap->bottom_virtual_speaker_node_division_gains != NULL; if ( ivas_format == MASA_ISM_FORMAT ) @@ -239,6 +259,13 @@ ivas_error vbap_init_data( return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for VBAP data\n" ) ); } set_zero( vbap->object_mode_bottom_virtual_speaker_node_division_gains, num_speaker_nodes ); +#ifdef IVAS_FLOAT_FIXED + IF ( ( vbap->object_mode_bottom_virtual_speaker_node_division_gains_fx = (Word32 *) malloc( num_speaker_nodes * sizeof( Word32 ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for VBAP data\n" ) ); + } + set32_fx( vbap->object_mode_bottom_virtual_speaker_node_division_gains_fx, 0, num_speaker_nodes ); +#endif is_success &= vbap->object_mode_bottom_virtual_speaker_node_division_gains != NULL; } @@ -253,6 +280,13 @@ ivas_error vbap_init_data( return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for VBAP data\n" ) ); } set_zero( vbap->top_virtual_speaker_node_division_gains, num_speaker_nodes ); +#ifdef IVAS_FLOAT_FIXED + IF ( ( vbap->top_virtual_speaker_node_division_gains_fx = (Word32 *) malloc( num_speaker_nodes * sizeof( Word32 ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for VBAP data\n" ) ); + } + set32_fx( vbap->top_virtual_speaker_node_division_gains_fx, 0, num_speaker_nodes ); +#endif is_success &= vbap->top_virtual_speaker_node_division_gains != NULL; if ( ivas_format == MASA_ISM_FORMAT ) @@ -262,6 +296,13 @@ ivas_error vbap_init_data( return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for VBAP data\n" ) ); } set_zero( vbap->object_mode_top_virtual_speaker_node_division_gains, num_speaker_nodes ); +#ifdef IVAS_FLOAT_FIXED + IF ( ( vbap->object_mode_top_virtual_speaker_node_division_gains_fx = (Word32 *) malloc( num_speaker_nodes * sizeof( Word32 ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for VBAP data\n" ) ); + } + set32_fx( vbap->object_mode_top_virtual_speaker_node_division_gains_fx, 0, num_speaker_nodes ); +#endif is_success &= vbap->object_mode_top_virtual_speaker_node_division_gains != NULL; } @@ -276,6 +317,13 @@ ivas_error vbap_init_data( return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for VBAP data\n" ) ); } set_zero( vbap->back_virtual_speaker_node_division_gains, num_speaker_nodes ); +#ifdef IVAS_FLOAT_FIXED + IF ( ( vbap->back_virtual_speaker_node_division_gains_fx = (Word32 *) malloc( num_speaker_nodes * sizeof( Word32 ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for VBAP data\n" ) ); + } + set32_fx( vbap->back_virtual_speaker_node_division_gains_fx, 0, num_speaker_nodes ); +#endif is_success &= vbap->back_virtual_speaker_node_division_gains != NULL; if ( ivas_format == MASA_ISM_FORMAT ) @@ -285,6 +333,13 @@ ivas_error vbap_init_data( return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for VBAP data\n" ) ); } set_zero( vbap->object_mode_back_virtual_speaker_node_division_gains, num_speaker_nodes ); +#ifdef IVAS_FLOAT_FIXED + IF ( ( vbap->object_mode_back_virtual_speaker_node_division_gains_fx = (Word32 *) malloc( num_speaker_nodes * sizeof( Word32 ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for VBAP data\n" ) ); + } + set32_fx( vbap->object_mode_back_virtual_speaker_node_division_gains_fx, 0, num_speaker_nodes ); +#endif is_success &= vbap->object_mode_back_virtual_speaker_node_division_gains != NULL; } speaker_node_azi_deg_internal[vbap->back_virtual_speaker_node_index] = 180.0f; @@ -441,6 +496,32 @@ void vbap_free_data( { free( ( *hVBAPdata )->object_mode_back_virtual_speaker_node_division_gains ); } +#ifdef IVAS_FLOAT_FIXED + IF ( ( *hVBAPdata )->bottom_virtual_speaker_node_division_gains_fx != NULL ) + { + free( ( *hVBAPdata )->bottom_virtual_speaker_node_division_gains_fx ); + } + IF ( ( *hVBAPdata )->top_virtual_speaker_node_division_gains_fx != NULL ) + { + free( ( *hVBAPdata )->top_virtual_speaker_node_division_gains_fx ); + } + IF ( ( *hVBAPdata )->back_virtual_speaker_node_division_gains_fx != NULL ) + { + free( ( *hVBAPdata )->back_virtual_speaker_node_division_gains_fx ); + } + IF ( ( *hVBAPdata )->object_mode_bottom_virtual_speaker_node_division_gains_fx != NULL ) + { + free( ( *hVBAPdata )->object_mode_bottom_virtual_speaker_node_division_gains_fx ); + } + IF ( ( *hVBAPdata )->object_mode_top_virtual_speaker_node_division_gains_fx != NULL ) + { + free( ( *hVBAPdata )->object_mode_top_virtual_speaker_node_division_gains_fx ); + } + IF ( ( *hVBAPdata )->object_mode_back_virtual_speaker_node_division_gains_fx != NULL ) + { + free( ( *hVBAPdata )->object_mode_back_virtual_speaker_node_division_gains_fx ); + } +#endif if ( ( *hVBAPdata )->search_struct[0].triplets != NULL ) { free( ( *hVBAPdata )->search_struct[0].triplets ); @@ -591,6 +672,143 @@ void vbap_determine_gains( return; } +#ifdef IVAS_FLOAT_FIXED +void vbap_determine_gains_fx( + const VBAP_HANDLE hVBAPdata, /* i : prepared VBAP structure */ + Word32 *gains_fx, /* o : gain vector for loudspeakers for given direction */ + const Word16 azi_deg, /* i : azimuth in degrees for panning direction (positive left) */ + const Word16 ele_deg, /* i : elevation in degrees for panning direction (positive up) */ + const Word16 use_object_mode /* i : select between object mode panning and spatial mode panning */ +) +{ + /* This function formulates gains for the given angle. The triplet-selection has been pre-formulated. */ + Word16 ch, ch2; + Word16 triplet_ch; + Word16 triplet_index; + Word16 panning_unit_vec_fx[3]; + Word32 gain_triplet_fx[3]; + Word32 norm_value_fx; + Word32 gain_ene_fx; + Word32 azi_norm; + Word32 ele_norm; + Word32 azi_temp_fx; + Word32 ele_temp_fx; + Word16 num_speaker_nodes; + Word16 bottom_virtual_speaker_node_index; + Word16 top_virtual_speaker_node_index; + Word16 back_virtual_speaker_node_index; + VBAP_VS_TRIPLET *selected_triplet; + Word32 *bottom_virtual_speaker_node_division_gains_fx; + Word32 *top_virtual_speaker_node_division_gains_fx; + Word32 *back_virtual_speaker_node_division_gains_fx; + + + push_wmops( "vbap_gains" ); + num_speaker_nodes = hVBAPdata->num_speaker_nodes; + move16(); + bottom_virtual_speaker_node_index = hVBAPdata->bottom_virtual_speaker_node_index; + move16(); + top_virtual_speaker_node_index = hVBAPdata->top_virtual_speaker_node_index; + move16(); + back_virtual_speaker_node_index = hVBAPdata->back_virtual_speaker_node_index; + move16(); + + IF ( use_object_mode ) + { + bottom_virtual_speaker_node_division_gains_fx = hVBAPdata->object_mode_bottom_virtual_speaker_node_division_gains_fx; + top_virtual_speaker_node_division_gains_fx = hVBAPdata->object_mode_top_virtual_speaker_node_division_gains_fx; + back_virtual_speaker_node_division_gains_fx = hVBAPdata->object_mode_back_virtual_speaker_node_division_gains_fx; + } + ELSE + { + bottom_virtual_speaker_node_division_gains_fx = hVBAPdata->bottom_virtual_speaker_node_division_gains_fx; + top_virtual_speaker_node_division_gains_fx = hVBAPdata->top_virtual_speaker_node_division_gains_fx; + back_virtual_speaker_node_division_gains_fx = hVBAPdata->back_virtual_speaker_node_division_gains_fx; + } + + panning_wrap_angles_fixed( (Word32)azi_deg * (1 << 22), (Word32)ele_deg * (1<<22), &azi_temp_fx, &ele_temp_fx ); + azi_norm = L_shr(Mpy_32_16_1(azi_temp_fx, 91), 7); + ele_norm = L_shr(Mpy_32_16_1(ele_temp_fx, 91), 7); + + panning_unit_vec_fx[0] = mult(getCosWord16R2( (Word16) azi_norm ), getCosWord16R2( (Word16) ele_norm )); + panning_unit_vec_fx[1] = mult(getSineWord16R2( (Word16) azi_norm ), getCosWord16R2( (Word16) ele_norm )); + panning_unit_vec_fx[2] = getSineWord16R2( (Word16) ele_norm ); + + /* Find the best VS triplet and speaker node gains for the panning direction using the prepared search structures. */ + IF ( EQ_16(hVBAPdata->num_search_structs, 2) && GT_16(ele_deg, 0) ) + { + triplet_index = determine_best_triplet_and_gains_fx( &( hVBAPdata->search_struct[1] ), panning_unit_vec_fx, azi_deg, gain_triplet_fx ); + move16(); + selected_triplet = &hVBAPdata->search_struct[1].triplets[triplet_index]; + } + ELSE + { + triplet_index = determine_best_triplet_and_gains_fx( &( hVBAPdata->search_struct[0] ), panning_unit_vec_fx, azi_deg, gain_triplet_fx ); + move16(); + selected_triplet = &hVBAPdata->search_struct[0].triplets[triplet_index]; + } + + /* Normalize to unit energy */ + gain_ene_fx = 1; /* Add small value to avoid divide by zero. */ + move32(); + FOR ( ch = 0; ch < 3; ch++ ) + { + gain_ene_fx = L_add(gain_ene_fx, Mpy_32_32(gain_triplet_fx[ch], gain_triplet_fx[ch])); // 2q -31 = 27 + } + + norm_value_fx = Isqrt( L_shr(gain_ene_fx, 1) ); // q = 47 - hVBAPdata->search_struct[0].triplets->q_inverse_matrix = 18 + + FOR ( ch = 0; ch < 3; ch++ ) + { + gain_triplet_fx[ch] = Mpy_32_32(gain_triplet_fx[ch], norm_value_fx); // Q16 + + /* Sanity check for rounding issues */ + IF ( LT_32(gain_triplet_fx[ch], 0) ) + { + gain_triplet_fx[ch] = 0; + } + } + + /* Flush gain target */ + set32_fx( gains_fx, 0, num_speaker_nodes ); + + /* Map gain triplet (internal speaker node configuration) to speaker node output (actual speaker node configuration) */ + FOR ( ch = 0; ch < 3; ch++ ) + { + triplet_ch = selected_triplet->speaker_node[ch]; + + IF ( EQ_16(triplet_ch, bottom_virtual_speaker_node_index) ) + { + FOR ( ch2 = 0; ch2 < num_speaker_nodes; ch2++ ) + { + gains_fx[ch2] = L_add(gains_fx[ch2], L_shl(Mpy_32_32(bottom_virtual_speaker_node_division_gains_fx[ch2], gain_triplet_fx[ch]), 13)); // Q29 + } + } + ELSE IF ( EQ_16(triplet_ch, top_virtual_speaker_node_index) ) + { + FOR ( ch2 = 0; ch2 < num_speaker_nodes; ch2++ ) + { + gains_fx[ch2] = L_add(gains_fx[ch2], L_shl(Mpy_32_32(top_virtual_speaker_node_division_gains_fx[ch2], gain_triplet_fx[ch]), 13)); // Q29 + } + } + ELSE IF ( EQ_16(triplet_ch, back_virtual_speaker_node_index) ) + { + FOR ( ch2 = 0; ch2 < num_speaker_nodes; ch2++ ) + { + gains_fx[ch2] = L_add(gains_fx[ch2], L_shl(Mpy_32_32(back_virtual_speaker_node_division_gains_fx[ch2], gain_triplet_fx[ch]), 13)); // Q29 + } + } + ELSE + { + gains_fx[triplet_ch] = L_add(gains_fx[triplet_ch], L_shl(gain_triplet_fx[ch], 13)); // Q29 + } + } + + pop_wmops(); + + return; +} +#endif /*-----------------------------------------------------------------------* * Local functions @@ -658,6 +876,45 @@ static uint8_t vector_matrix_multiply_3x3( return 1; } +#ifdef IVAS_FLOAT_FIXED +/*! r: Status result if triplet is usable for panning. Allows early exit. */ +static uint8_t vector_matrix_multiply_3x3_fx( + const Word16 *src_vector, /* i : input vector */ + Word32 matrix[3][3], /* i : input matrix */ + Word32 *result, /* o : output vector */ + Word16 q_matrix +) +{ + result[0] = Mpy_32_16_1(matrix[0][0], src_vector[0]); // q = q_matrix + result[0] = L_add(result[0], Mpy_32_16_1(matrix[1][0], src_vector[1])); + result[0] = L_add(result[0], Mpy_32_16_1(matrix[2][0], src_vector[2])); + + IF ( result[0] < Mpy_32_16_1( 1 << q_matrix, -327) ) // 327 = 0.01 in Q = 15 + { + return 0; + } + + result[1] = Mpy_32_16_1(matrix[0][1], src_vector[0]); + result[1] = L_add(result[1], Mpy_32_16_1(matrix[1][1], src_vector[1])); + result[1] = L_add(result[1], Mpy_32_16_1(matrix[2][1], src_vector[2])); + + IF ( result[1] < Mpy_32_16_1( 1 << q_matrix, -327) ) + { + return 0; + } + + result[2] = Mpy_32_16_1(matrix[0][2], src_vector[0]); + result[2] = L_add(result[2], Mpy_32_16_1(matrix[1][2], src_vector[1])); + result[2] = L_add(result[2], Mpy_32_16_1(matrix[2][2], src_vector[2])); + + IF ( result[2] < Mpy_32_16_1( 1 << q_matrix, -327) ) + { + return 0; + } + + return 1; +} +#endif /*----------------------------------------------------------------------------------------------* @@ -745,6 +1002,97 @@ static int16_t determine_best_triplet_and_gains( return best_triplet; } +#ifdef IVAS_FLOAT_FIXED +static Word16 determine_best_triplet_and_gains_fx( + VBAP_SEARCH_STRUCT *search_struct, /* i : VBAP search struct */ + const Word16 panning_unit_vec_fx[3], /* i : panning unit vector */ + const Word16 azi_deg, /* i : panning azimuth */ + Word32 gains_fx[3] /* o : panning gains */ +) +{ + Word16 i, tr, k; + UWord8 triplet_ok; + Word16 best_triplet; + Word32 best_min_gain_fx; + Word32 min_gain_this_fx; + Word32 unnormalized_gains_fx[3]; + Word16 sector; + Word16 first_triplet; + Word16 jump; + Word16 num_triplets; + + num_triplets = search_struct->num_triplets; + move16(); + best_min_gain_fx = -2147483647; + move32(); + best_triplet = 0; + move16(); + set32_fx( gains_fx, 0, 3 ); + + /* Determine the correct search sector for that target panning direction using an optimized algorithm for + * the chosen four sectors. */ + IF ( GT_16(abs_s( azi_deg ), 90) ) + { + sector = azi_deg < 0 ? 2 : 1; + move16(); + } + ELSE + { + sector = azi_deg < 0 ? 3 : 0; + move16(); + } + first_triplet = search_struct->initial_search_indices[sector]; + move16(); + + tr = first_triplet; + move16(); + jump = 1; + move16(); + FOR ( i = 0; i < num_triplets; i++ ) + { + triplet_ok = vector_matrix_multiply_3x3_fx( panning_unit_vec_fx, search_struct->triplets[tr].inverse_matrix_fx, unnormalized_gains_fx, search_struct->triplets[tr].q_inverse_matrix ); + IF ( triplet_ok ) + { + min_gain_this_fx = L_min( ( L_min( unnormalized_gains_fx[0], unnormalized_gains_fx[1] ) ), unnormalized_gains_fx[2] ); + move32(); + + IF ( GT_32(min_gain_this_fx, best_min_gain_fx) ) + { + best_min_gain_fx = min_gain_this_fx; + move32(); + best_triplet = tr; + move16(); + FOR ( k = 0; k < 3; k++ ) + { + gains_fx[k] = unnormalized_gains_fx[k]; + move32(); + } + IF ( !( best_min_gain_fx < 0 ) ) + { + return best_triplet; + } + } + } + tr = add(first_triplet, jump); + IF ( LT_16(tr, 0) ) + { + tr = add(tr, num_triplets); + } + ELSE IF ( GE_16(tr, num_triplets) ) + { + tr = sub(tr, num_triplets); + } + + jump = negate(jump); + IF ( GT_16(jump, 0) ) + { + jump = add(jump, 1); + } + } + + return best_triplet; +} +#endif /*-------------------------------------------------------------------------* * determine_virtual_speaker_node_division_gains() * diff --git a/lib_rend/lib_rend.c b/lib_rend/lib_rend.c index 5379d6449..a4cd1a9fb 100644 --- a/lib_rend/lib_rend.c +++ b/lib_rend/lib_rend.c @@ -34,6 +34,7 @@ #include "lib_rend.h" #include "prot.h" #include "ivas_prot.h" +#include "ivas_prot_fx.h" #include "ivas_prot_rend.h" #include "ivas_cnst.h" #include "ivas_rom_com.h" @@ -5820,11 +5821,23 @@ static ivas_error renderIsmToMc( { set_zero( currentPanGains, MAX_OUTPUT_CHANNELS ); +#ifdef IVAS_FLOAT_FIXED + Word16 gains_fx[2]; + ivas_ism_get_stereo_gains_fx( (Word16)ismInput->currentPos.azimuth, (Word16)ismInput->currentPos.elevation, &gains_fx[0], &gains_fx[1] ); + currentPanGains[0] = (float)gains_fx[0] / 32768.f; + currentPanGains[1] = (float)gains_fx[1] / 32768.f; +#else ivas_ism_get_stereo_gains( ismInput->currentPos.azimuth, ismInput->currentPos.elevation, ¤tPanGains[0], ¤tPanGains[1] ); +#endif set_zero( ismInput->prev_pan_gains, MAX_OUTPUT_CHANNELS ); - +#ifdef IVAS_FLOAT_FIXED + ivas_ism_get_stereo_gains_fx( (Word16)ismInput->previousPos.azimuth, (Word16)ismInput->previousPos.elevation, &gains_fx[0], &gains_fx[1] ); + ismInput->prev_pan_gains[0] = (float)gains_fx[0] / 32768.f; + ismInput->prev_pan_gains[1] = (float)gains_fx[1] / 32768.f; +#else ivas_ism_get_stereo_gains( ismInput->previousPos.azimuth, ismInput->previousPos.elevation, &ismInput->prev_pan_gains[0], &ismInput->prev_pan_gains[1] ); +#endif } } else -- GitLab