From 85913c3ce6cc988fe9cd1c0c1a34cba3a5fc4f01 Mon Sep 17 00:00:00 2001 From: Archit Tamarapu Date: Mon, 27 Oct 2025 15:43:32 +0100 Subject: [PATCH 1/9] add FIX_1419_MONO_STEREO_UMX; enable mono/stereo rendering to all output configurations --- apps/decoder.c | 20 ++++++ lib_com/common_api_types.h | 15 ++++ lib_com/ivas_cnst.h | 4 ++ lib_com/options.h | 1 + lib_dec/ivas_init_dec.c | 58 ++++++++++++++- lib_dec/ivas_jbm_dec.c | 89 ++++++++++++++++++++++- lib_dec/ivas_output_config.c | 96 +++++++++++++++++++++++++ lib_dec/lib_dec.c | 55 ++++++++++++++ lib_rend/ivas_crend.c | 59 +++++++++++++-- lib_rend/ivas_objectRenderer.c | 11 +++ lib_rend/ivas_output_init.c | 123 ++++++++++++++++++++++++++++++++ lib_rend/ivas_prot_rend.h | 7 ++ lib_rend/ivas_render_config.c | 9 +++ lib_rend/ivas_rom_rend.c | 29 +++++++- lib_rend/ivas_rom_rend.h | 5 ++ lib_rend/ivas_rotation.c | 20 ++++++ lib_rend/lib_rend.c | 17 ++++- lib_util/render_config_reader.c | 48 +++++++++++++ 18 files changed, 655 insertions(+), 11 deletions(-) diff --git a/apps/decoder.c b/apps/decoder.c index ed96f79196..4feea3fcfd 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -150,6 +150,9 @@ typedef struct uint16_t directivityPatternId[IVAS_MAX_NUM_OBJECTS]; bool objEditEnabled; char *objEditFileName; +#ifdef FIX_1419_MONO_STEREO_UMX + bool evsMode; +#endif } DecArguments; @@ -961,6 +964,9 @@ static bool parseCmdlIVAS_dec( arg->output_Fs = IVAS_MAX_SAMPLING_RATE; arg->outputConfig = IVAS_AUDIO_CONFIG_MONO; arg->decMode = IVAS_DEC_MODE_IVAS; +#ifdef FIX_1419_MONO_STEREO_UMX + arg->evsMode = false; +#endif arg->quietModeEnabled = false; arg->delayCompensationEnabled = true; arg->voipMode = false; @@ -1502,6 +1508,14 @@ static bool parseCmdlIVAS_dec( } i++; } +#ifdef FIX_1419_MONO_STEREO_UMX + else if ( strcmp( argv_to_upper, "-EVS" ) == 0 ) + { + arg->evsMode = true; + arg->decMode = IVAS_DEC_MODE_EVS; + i++; + } +#endif /*-----------------------------------------------------------------* * Option not recognized @@ -1644,6 +1658,9 @@ static bool parseCmdlIVAS_dec( static void usage_dec( void ) { fprintf( stdout, "Usage for EVS: IVAS_dec.exe [Options] Fs bitstream_file output_file\n" ); +#ifdef FIX_1419_MONO_STEREO_UMX + fprintf( stdout, " OR usage for IVAS (below) with -evs option and OutputConf\n" ); +#endif fprintf( stdout, "Usage for IVAS: IVAS_dec.exe [Options] OutputConf Fs bitstream_file output_file\n\n" ); fprintf( stdout, "Mandatory parameters:\n" ); @@ -1660,6 +1677,9 @@ static void usage_dec( void ) fprintf( stdout, "Options:\n" ); fprintf( stdout, "--------\n" ); +#ifdef FIX_1419_MONO_STEREO_UMX + fprintf( stdout, "-evs : Specify EVS mode for supplied bitstream\n" ); +#endif fprintf( stdout, "-VOIP : VoIP mode: RTP in G192\n" ); fprintf( stdout, "-VOIP_hf_only=0 : VoIP mode: EVS RTP Payload Format hf_only=0 in rtpdump\n" ); #ifdef IVAS_RTPDUMP diff --git a/lib_com/common_api_types.h b/lib_com/common_api_types.h index 80c90d6b31..18a0aea9f6 100644 --- a/lib_com/common_api_types.h +++ b/lib_com/common_api_types.h @@ -222,6 +222,18 @@ typedef enum _ivas_binaural_renderer_type IVAS_BIN_RENDERER_TYPE_DEFAULT, } IVAS_BIN_RENDERER_TYPE; +#ifdef FIX_1419_MONO_STEREO_UMX + +typedef struct _IVAS_MS_UMX_CONF_DATA +{ + int16_t spatialEnabled; /* internal flag for spatial rendering */ + int16_t stereoLR; /* internal flag to use ±90 for BRIRs */ + float radius; + float azi[2]; + float ele[2]; + +} IVAS_MS_UMX_CONF_DATA, *IVAS_MS_UMX_CONF_HANDLE; +#endif /*----------------------------------------------------------------------------------* * Split rendering API constants, structures, and enums @@ -335,6 +347,9 @@ typedef struct _IVAS_RENDER_CONFIG #endif IVAS_ROOM_ACOUSTICS_CONFIG_DATA roomAcoustics; ISAR_SPLIT_REND_CONFIG_DATA split_rend_config; +#ifdef FIX_1419_MONO_STEREO_UMX + IVAS_MS_UMX_CONF_DATA mono_stereo_upmix_config; +#endif float directivity[IVAS_MAX_NUM_OBJECTS * 3]; float distAtt[3]; diff --git a/lib_com/ivas_cnst.h b/lib_com/ivas_cnst.h index e16553e85a..579cda77a9 100755 --- a/lib_com/ivas_cnst.h +++ b/lib_com/ivas_cnst.h @@ -1248,7 +1248,11 @@ typedef enum *----------------------------------------------------------------------------------*/ #define MC_LS_SETUP_BITS 3 /* number of bits for writing the MC LS configuration */ +#ifdef FIX_1419_MONO_STEREO_UMX +#define LS_SETUP_CONVERSION_NUM_MAPPINGS 41 /* number of mappings for LS setup conversion */ +#else #define LS_SETUP_CONVERSION_NUM_MAPPINGS 35 /* number of mappings for LS setup conversion */ +#endif typedef enum { diff --git a/lib_com/options.h b/lib_com/options.h index 4c31c1480c..a9bee24591 100755 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -169,6 +169,7 @@ #define FIX_1119_SPLIT_RENDERING_VOIP /* FhG: Add split rendering support to decoder in VoIP mode */ #define TMP_1342_WORKAROUND_DEC_FLUSH_BROKEN_IN_SR /* FhG: Temporary workaround for incorrect implementation of decoder flush with split rendering */ #define FIX_1413_IGF_INIT_PRINTOUT /* FhG: use correct variable for IGF initiliazation */ +#define FIX_1419_MONO_STEREO_UMX /* FhG: fix for issue 1418 : support upmix to all output formats for mono and stereo */ /* #################### End BE switches ################################## */ diff --git a/lib_dec/ivas_init_dec.c b/lib_dec/ivas_init_dec.c index 80b8c7e5e9..02703130bc 100644 --- a/lib_dec/ivas_init_dec.c +++ b/lib_dec/ivas_init_dec.c @@ -1279,7 +1279,15 @@ ivas_error ivas_init_decoder( if ( output_config == IVAS_AUDIO_CONFIG_EXTERNAL ) { +#ifdef FIX_1419_MONO_STEREO_UMX + if ( st_ivas->ivas_format == MONO_FORMAT ) + { + hDecoderConfig->nchan_out = 1; + } + else if ( st_ivas->ivas_format == STEREO_FORMAT ) +#else if ( st_ivas->ivas_format == STEREO_FORMAT ) +#endif { hDecoderConfig->nchan_out = CPE_CHANNELS; } @@ -1332,12 +1340,29 @@ ivas_error ivas_init_decoder( st_ivas->hOutSetup.output_config = st_ivas->intern_config; st_ivas->hOutSetup.nchan_out_woLFE = audioCfg2channels( st_ivas->intern_config ); } +#ifdef FIX_1419_MONO_STEREO_UMX + + if ( st_ivas->ivas_format == MONO_FORMAT || st_ivas->ivas_format == STEREO_FORMAT ) + { + st_ivas->transport_config = ( st_ivas->ivas_format == MONO_FORMAT ) ? IVAS_AUDIO_CONFIG_MONO : IVAS_AUDIO_CONFIG_STEREO; + } +#endif /* Only initialize transport setup if it is used */ if ( st_ivas->transport_config != IVAS_AUDIO_CONFIG_INVALID ) { ivas_output_init( &( st_ivas->hTransSetup ), st_ivas->transport_config ); } +#ifdef FIX_1419_MONO_STEREO_UMX + + /* Override transport config values from render config */ + if ( st_ivas->ivas_format == MONO_FORMAT || st_ivas->ivas_format == STEREO_FORMAT ) + { + // TODO check status of render config; is this a sanitizer issue if it is not always enabled? + st_ivas->hTransSetup.ls_azimuth = st_ivas->hRenderConfig->mono_stereo_upmix_config.azi; + st_ivas->hTransSetup.ls_elevation = st_ivas->hRenderConfig->mono_stereo_upmix_config.ele; + } +#endif if ( st_ivas->ivas_format == MC_FORMAT && st_ivas->mc_mode == MC_MODE_MCMASA ) { @@ -1414,7 +1439,9 @@ ivas_error ivas_init_decoder( else if ( st_ivas->ivas_format == STEREO_FORMAT ) { st_ivas->nchan_transport = CPE_CHANNELS; +#ifndef FIX_1419_MONO_STEREO_UMX /* already set now by renderer_select() */ st_ivas->intern_config = IVAS_AUDIO_CONFIG_STEREO; +#endif st_ivas->nSCE = 0; st_ivas->nCPE = 1; /* in stereo, there is always only one CPE */ @@ -2148,7 +2175,13 @@ ivas_error ivas_init_decoder( } else if ( st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV || st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV_ROOM ) { +#ifdef FIX_1419_MONO_STEREO_UMX + if ( ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) && + ( ( st_ivas->ivas_format == MONO_FORMAT || st_ivas->ivas_format == STEREO_FORMAT ) || + ( st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV_ROOM && st_ivas->ivas_format == MC_FORMAT ) ) ) +#else if ( st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV_ROOM && st_ivas->ivas_format == MC_FORMAT && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) ) +#endif { if ( ( error = efap_init_data( &( st_ivas->hEFAPdata ), st_ivas->hIntSetup.ls_azimuth, st_ivas->hIntSetup.ls_elevation, st_ivas->hIntSetup.nchan_out_woLFE, EFAP_MODE_EFAP ) ) != IVAS_ERR_OK ) { @@ -2304,7 +2337,8 @@ ivas_error ivas_init_decoder( } /*-----------------------------------------------------------------* - * LFE handles for rendering after rendering to adjust LFE delay to filter delay + * LFE handles for rendering after rendering to adjust LFE delay to + * filter delay *-----------------------------------------------------------------*/ if ( st_ivas->mc_mode == MC_MODE_MCT || st_ivas->mc_mode == MC_MODE_PARAMUPMIX ) @@ -3136,10 +3170,19 @@ static ivas_error doSanityChecks_IVAS( return IVAS_ERROR( IVAS_ERR_INVALID_OUTPUT_FORMAT, "Error: Non-diegetic panning not supported in this IVAS format" ); } +#ifndef FIX_1419_MONO_STEREO_UMX /* we now support basically everything for stereo */ /* Verify stereo output configuration */ if ( st_ivas->ivas_format == STEREO_FORMAT ) { - if ( output_config != IVAS_AUDIO_CONFIG_MONO && output_config != IVAS_AUDIO_CONFIG_STEREO && output_config != IVAS_AUDIO_CONFIG_5_1 && output_config != IVAS_AUDIO_CONFIG_7_1 && output_config != IVAS_AUDIO_CONFIG_5_1_2 && output_config != IVAS_AUDIO_CONFIG_5_1_4 && output_config != IVAS_AUDIO_CONFIG_7_1_4 && output_config != IVAS_AUDIO_CONFIG_LS_CUSTOM && output_config != IVAS_AUDIO_CONFIG_EXTERNAL ) + if ( output_config != IVAS_AUDIO_CONFIG_MONO && + output_config != IVAS_AUDIO_CONFIG_STEREO && + output_config != IVAS_AUDIO_CONFIG_5_1 && + output_config != IVAS_AUDIO_CONFIG_7_1 && + output_config != IVAS_AUDIO_CONFIG_5_1_2 && + output_config != IVAS_AUDIO_CONFIG_5_1_4 && + output_config != IVAS_AUDIO_CONFIG_7_1_4 && + output_config != IVAS_AUDIO_CONFIG_LS_CUSTOM && + output_config != IVAS_AUDIO_CONFIG_EXTERNAL ) { return IVAS_ERROR( IVAS_ERR_INVALID_OUTPUT_FORMAT, "Wrong output configuration specified for Stereo!" ); } @@ -3148,10 +3191,21 @@ static ivas_error doSanityChecks_IVAS( else { if ( output_config == IVAS_AUDIO_CONFIG_INVALID ) +#else /* exclude invalid configs instead of matching valid ones */ + if ( output_config == IVAS_AUDIO_CONFIG_INVALID || + output_config == IVAS_AUDIO_CONFIG_ISM1 || + output_config == IVAS_AUDIO_CONFIG_ISM2 || + output_config == IVAS_AUDIO_CONFIG_ISM3 || + output_config == IVAS_AUDIO_CONFIG_ISM4 || + output_config == IVAS_AUDIO_CONFIG_MASA1 || + output_config == IVAS_AUDIO_CONFIG_MASA2 ) +#endif { return IVAS_ERROR( IVAS_ERR_INVALID_OUTPUT_FORMAT, "Incorrect output configuration specified!" ); } +#ifndef FIX_1419_MONO_STEREO_UMX } +#endif if ( ( output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) && output_Fs != 48000 ) { diff --git a/lib_dec/ivas_jbm_dec.c b/lib_dec/ivas_jbm_dec.c index 91522f3f3d..d3eecda6f9 100644 --- a/lib_dec/ivas_jbm_dec.c +++ b/lib_dec/ivas_jbm_dec.c @@ -934,14 +934,91 @@ ivas_error ivas_jbm_dec_render( { ivas_jbm_dec_tc_buffer_playout( st_ivas, nSamplesAskedLocal, nSamplesRendered, p_output ); } +#ifdef FIX_1419_MONO_STEREO_UMX + else if ( st_ivas->ivas_format == MONO_FORMAT || st_ivas->ivas_format == STEREO_FORMAT ) +#else else if ( st_ivas->ivas_format == STEREO_FORMAT ) +#endif { + *nSamplesRendered = min( st_ivas->hTcBuffer->n_samples_available, nSamplesAskedLocal ); + /* Rendering */ if ( st_ivas->renderer_type == RENDERER_MC ) { - *nSamplesRendered = min( st_ivas->hTcBuffer->n_samples_available, nSamplesAskedLocal ); ivas_ls_setup_conversion( st_ivas, st_ivas->nchan_transport, *nSamplesRendered, p_tc, p_output ); } +#ifdef FIX_1419_MONO_STEREO_UMX + else if ( st_ivas->renderer_type == RENDERER_SBA_LINEAR_ENC ) + { + /* Only upmix to ambisonics if spatial parameters exist */ + // TODO default render config is not enabled here, the GetDefault API func is never used + if ( st_ivas->hRenderConfig != NULL && !st_ivas->hRenderConfig->mono_stereo_upmix_config.spatialEnabled ) + { + ivas_mc2sba( st_ivas->hIntSetup, p_output, p_output, *nSamplesRendered, st_ivas->hOutSetup.ambisonics_order, 0.f ); + } + else + { + if ( st_ivas->ivas_format == MONO_FORMAT ) + { + // TODO route mono to W; probably same as ivas_jbm_dec_tc_buffer_playout + } + else if ( st_ivas->ivas_format == STEREO_FORMAT ) + { + // TODO route stereo to W±Y + // p_output[0] = 0.5f * ( p_output[0] + p_output[1] ); // W = (L + R ) / 2 + // p_output[1] = 0.5f * ( p_output[0] - p_output[1] ); // Y = (L - R ) / 2 + } + } + } + else if ( st_ivas->renderer_type == RENDERER_BINAURAL_OBJECTS_TD ) + { + /* Rendering for BINAURAL, BINAURAL_ROOM_REVERB and split rendering */ + if ( output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) + { + if ( ( error = ivas_td_binaural_renderer_sf_splitBinaural( st_ivas, p_output, *nSamplesRendered ) ) != IVAS_ERR_OK ) + { + return error; + } + } + else + { + if ( ( error = ivas_td_binaural_renderer_sf( st_ivas, p_output, *nSamplesRendered ) ) != IVAS_ERR_OK ) + { + return error; + } + } + } + else if ( st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV_ROOM ) + { + /* Rendering for BINAURAL_ROOM_IR */ + if ( st_ivas->hDecoderConfig->Opt_Headrotation && st_ivas->ivas_format == MONO_FORMAT ) + { + /* Since rotation is performed on 7.1+4, we treat mono as 7.1+4 with other channels zero + * so move the mono content in index 0 to index 2 (center channel) */ + float *tmp; + tmp = p_output[2]; + p_output[2] = p_output[0]; + p_output[0] = tmp; + } + + if ( ( error = ivas_rend_crendProcessSubframe( st_ivas->hCrendWrapper, + st_ivas->intern_config, + st_ivas->hOutSetup.output_config, + st_ivas->hDecoderConfig, + st_ivas->hCombinedOrientationData, + &st_ivas->hIntSetup, + st_ivas->hEFAPdata, + st_ivas->hTcBuffer, + p_output, + p_output, + *nSamplesRendered, + output_Fs, + 0 ) ) != IVAS_ERR_OK ) + { + return error; + } + } +#endif } else if ( st_ivas->ivas_format == ISM_FORMAT ) { @@ -1928,11 +2005,15 @@ int16_t ivas_jbm_dec_get_num_tc_channels( ivas_total_brate = st_ivas->hDecoderConfig->ivas_total_brate; +#ifndef FIX_1419_MONO_STEREO_UMX /* since we support more output formats for mono, this is no longer sensible; leave it at the default from above */ if ( st_ivas->ivas_format == MONO_FORMAT ) { num_tc = st_ivas->hDecoderConfig->nchan_out; } else if ( st_ivas->ivas_format == STEREO_FORMAT && st_ivas->hDecoderConfig->nchan_out == 1 ) +#else + if ( st_ivas->ivas_format == STEREO_FORMAT && st_ivas->hDecoderConfig->nchan_out == 1 ) +#endif { num_tc = 1; } @@ -2788,7 +2869,11 @@ void ivas_dec_prepare_renderer( ivas_omasa_gain_masa_tc( st_ivas->hTcBuffer->tc, st_ivas->hMasaIsmData->gain_masa_edited, st_ivas->nchan_ism, st_ivas->hTcBuffer->n_samples_available ); } } - else if ( st_ivas->ivas_format == STEREO_FORMAT ) + else if ( +#ifdef FIX_1419_MONO_STEREO_UMX + st_ivas->ivas_format == MONO_FORMAT || +#endif + st_ivas->ivas_format == STEREO_FORMAT ) { ivas_jbm_dec_td_renderers_adapt_subframes( st_ivas ); } diff --git a/lib_dec/ivas_output_config.c b/lib_dec/ivas_output_config.c index 17ce37c4d4..9ac80ccb01 100644 --- a/lib_dec/ivas_output_config.c +++ b/lib_dec/ivas_output_config.c @@ -41,6 +41,49 @@ #endif #include "wmc_auto.h" +#ifdef FIX_1419_MONO_STEREO_UMX + +static void ms_bin_upmix_renderer_select( + const IVAS_FORMAT ivas_format, /* i : Decoder format */ + const IVAS_AUDIO_CONFIG output_config, /* i : Decoder output configuration */ + const IVAS_MS_UMX_CONF_HANDLE pMsUpmix_config, /* i : Mono/stereo upmix rendering configuration */ + const bool headrotation_enabled, /* i : Flag to signal headrotation is enabled */ + IVAS_AUDIO_CONFIG *internal_config, /* o : Internal configuration for rendering */ + RENDERER_TYPE *renderer_type /* o : Selected renderer type */ +) +{ + + *internal_config = ( ivas_format == MONO_FORMAT ) ? IVAS_AUDIO_CONFIG_MONO : IVAS_AUDIO_CONFIG_STEREO; + + /* spatial rendering disabled */ + if ( !pMsUpmix_config->spatialEnabled ) + { + if ( ivas_format == MONO_FORMAT ) + { + *renderer_type = RENDERER_NON_DIEGETIC_DOWNMIX; + } + else + { + *renderer_type = RENDERER_DISABLE; + } + return; + } + + /* spatial rendering configuration */ + if ( output_config == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) + { + if ( headrotation_enabled ) + { + *internal_config = IVAS_AUDIO_CONFIG_7_1_4; + } + *renderer_type = RENDERER_BINAURAL_MIXER_CONV_ROOM; + } + else /* HRIR based formats and split rendering */ + { + *renderer_type = RENDERER_BINAURAL_OBJECTS_TD; + } +} +#endif /*-------------------------------------------------------------------------* * ivas_renderer_select() @@ -78,7 +121,20 @@ void ivas_renderer_select( if ( output_config == IVAS_AUDIO_CONFIG_BINAURAL || output_config == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR || output_config == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB || output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) { +#ifdef FIX_1419_MONO_STEREO_UMX + if ( st_ivas->ivas_format == MONO_FORMAT || st_ivas->ivas_format == STEREO_FORMAT ) + { + ms_bin_upmix_renderer_select( st_ivas->ivas_format, + output_config, + &st_ivas->hRenderConfig->mono_stereo_upmix_config, + ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ), + internal_config, + renderer_type ); + } + else if ( st_ivas->ivas_format == ISM_FORMAT ) +#else if ( st_ivas->ivas_format == ISM_FORMAT ) +#endif { if ( st_ivas->ism_mode == ISM_MODE_PARAM ) { @@ -236,6 +292,45 @@ void ivas_renderer_select( * Non-binaural rendering configurations *-----------------------------------------------------------------*/ +#ifdef FIX_1419_MONO_STEREO_UMX + else if ( st_ivas->ivas_format == MONO_FORMAT || st_ivas->ivas_format == STEREO_FORMAT ) + { + *internal_config = ( st_ivas->ivas_format == MONO_FORMAT ) ? IVAS_AUDIO_CONFIG_MONO : IVAS_AUDIO_CONFIG_STEREO; + switch ( output_config ) + { + case IVAS_AUDIO_CONFIG_FOA: + case IVAS_AUDIO_CONFIG_HOA2: + case IVAS_AUDIO_CONFIG_HOA3: + *renderer_type = RENDERER_SBA_LINEAR_ENC; + break; + case IVAS_AUDIO_CONFIG_5_1: + case IVAS_AUDIO_CONFIG_7_1: + case IVAS_AUDIO_CONFIG_5_1_2: + case IVAS_AUDIO_CONFIG_5_1_4: + case IVAS_AUDIO_CONFIG_7_1_4: + case IVAS_AUDIO_CONFIG_LS_CUSTOM: + *renderer_type = RENDERER_MC; + break; + case IVAS_AUDIO_CONFIG_MONO: + if ( *internal_config == IVAS_AUDIO_CONFIG_STEREO ) + { + /* stereo to mono downmix */ + *renderer_type = RENDERER_MC; + } + break; + case IVAS_AUDIO_CONFIG_STEREO: + if ( *internal_config == IVAS_AUDIO_CONFIG_MONO ) + { + /* mono to stereo upmix */ + *renderer_type = RENDERER_NON_DIEGETIC_DOWNMIX; + } + break; + default: + /* RENDERER_DISABLE already set by default */ + break; + } + } +#else else if ( st_ivas->ivas_format == MONO_FORMAT ) { if ( output_config == IVAS_AUDIO_CONFIG_STEREO ) @@ -250,6 +345,7 @@ void ivas_renderer_select( *renderer_type = RENDERER_MC; } } +#endif else if ( st_ivas->ivas_format == ISM_FORMAT ) { if ( ( output_config == IVAS_AUDIO_CONFIG_STEREO ) && ( st_ivas->hDecoderConfig->Opt_non_diegetic_pan ) ) diff --git a/lib_dec/lib_dec.c b/lib_dec/lib_dec.c index fc63961eda..ecefb196ec 100644 --- a/lib_dec/lib_dec.c +++ b/lib_dec/lib_dec.c @@ -474,8 +474,19 @@ ivas_error IVAS_DEC_Configure( return IVAS_ERR_WRONG_PARAMS; } +#ifdef FIX_1419_MONO_STEREO_UMX + if ( hIvasDec->mode == IVAS_DEC_MODE_EVS && + ( outputConfig == IVAS_AUDIO_CONFIG_INVALID || + outputConfig == IVAS_AUDIO_CONFIG_ISM1 || + outputConfig == IVAS_AUDIO_CONFIG_ISM2 || + outputConfig == IVAS_AUDIO_CONFIG_ISM3 || + outputConfig == IVAS_AUDIO_CONFIG_ISM4 || + outputConfig == IVAS_AUDIO_CONFIG_MASA1 || + outputConfig == IVAS_AUDIO_CONFIG_MASA2 ) ) +#else /* we now support all output formats, so this validation is redundant */ if ( hIvasDec->mode == IVAS_DEC_MODE_EVS && !( ( outputConfig == IVAS_AUDIO_CONFIG_MONO && !non_diegetic_pan_enabled ) || ( outputConfig == IVAS_AUDIO_CONFIG_STEREO && non_diegetic_pan_enabled ) ) ) +#endif { return IVAS_ERR_WRONG_MODE; } @@ -2351,6 +2362,9 @@ static ivas_error ivas_dec_setup_all( if ( hIvasDec->mode == IVAS_DEC_MODE_EVS ) { +#ifdef FIX_1419_MONO_STEREO_UMX +// TODO split rendering for MONO +#endif if ( hIvasDec->st_ivas->renderer_type == RENDERER_NON_DIEGETIC_DOWNMIX ) { *nTransportChannels = MAX_OUTPUT_CHANNELS_IN_DIEGETIC_PAN; @@ -3220,6 +3234,11 @@ static ivas_error copyRendererConfigStruct( mvr2r( hRCin->roomAcoustics.pAcoustic_dsr, hRCout->roomAcoustics.pAcoustic_dsr, CLDFB_NO_CHANNELS_MAX ); mvr2r( hRCin->directivity, hRCout->directivity, 3 * MAX_NUM_OBJECTS ); mvr2r( hRCin->distAtt, hRCout->distAtt, 3 ); +#ifdef FIX_1419_MONO_STEREO_UMX + + /* Mono/Stereo upmix configuration */ + hRCout->mono_stereo_upmix_config = hRCin->mono_stereo_upmix_config; +#endif hRCout->split_rend_config = hRCin->split_rend_config; @@ -3373,6 +3392,28 @@ ivas_error IVAS_DEC_FeedRenderConfig( mvr2r( renderConfig.directivity, hRenderConfig->directivity, 3 * MAX_NUM_OBJECTS ); mvr2r( renderConfig.distAtt, hRenderConfig->distAtt, 3 ); +#ifdef FIX_1419_MONO_STEREO_UMX + + /* Mono/Stereo upmix configuration */ + if ( renderConfig.mono_stereo_upmix_config.spatialEnabled ) + { + /* copy data */ + hRenderConfig->mono_stereo_upmix_config.spatialEnabled = renderConfig.mono_stereo_upmix_config.spatialEnabled; + hRenderConfig->mono_stereo_upmix_config.radius = renderConfig.mono_stereo_upmix_config.radius; + hRenderConfig->mono_stereo_upmix_config.stereoLR = renderConfig.mono_stereo_upmix_config.stereoLR; + + mvr2r( renderConfig.mono_stereo_upmix_config.azi, hRenderConfig->mono_stereo_upmix_config.azi, 2 ); + mvr2r( renderConfig.mono_stereo_upmix_config.ele, hRenderConfig->mono_stereo_upmix_config.ele, 2 ); + + /* validate configuration */ + if ( ( error = ms_upmix_validate_config( &hRenderConfig->mono_stereo_upmix_config, + st_ivas->ivas_format, + st_ivas->hDecoderConfig->output_config ) ) != IVAS_ERR_OK ) + { + return error; + } + } +#endif hRenderConfig->split_rend_config = renderConfig.split_rend_config; @@ -4670,7 +4711,11 @@ static ivas_error evs_dec_main( { DEC_CORE_HANDLE *hCoreCoder; float mixer_left, mixer_rigth; +#ifdef FIX_1419_MONO_STEREO_UMX /* required now that mono can render to a higher number of output channels */ + float *p_output[MAX_TRANSPORT_CHANNELS]; +#else float *p_output[MAX_OUTPUT_CHANNELS_IN_DIEGETIC_PAN]; +#endif int16_t ch, nOutSamples; ivas_error error; @@ -4680,9 +4725,19 @@ static ivas_error evs_dec_main( mdct_switching_dec( hCoreCoder[0] ); +#ifdef FIX_1419_MONO_STEREO_UMX + for ( ch = 0; ch < MAX_TRANSPORT_CHANNELS; ch++ ) +#else for ( ch = 0; ch < MAX_OUTPUT_CHANNELS_IN_DIEGETIC_PAN; ch++ ) +#endif { p_output[ch] = st_ivas->p_output_f[ch]; +#ifdef FIX_1419_MONO_STEREO_UMX + if ( p_output[ch] != NULL ) + { + set_zero( p_output[ch], L_FRAME48k ); + } +#endif } /* run the main EVS decoding routine */ diff --git a/lib_rend/ivas_crend.c b/lib_rend/ivas_crend.c index 9134667502..500e48e883 100644 --- a/lib_rend/ivas_crend.c +++ b/lib_rend/ivas_crend.c @@ -167,6 +167,9 @@ static ivas_error ivas_rend_initCrend( const AUDIO_CONFIG outConfig, HRTFS_CREND_HANDLE hHrtfCrend, const int16_t ext_rend_flag, +#ifdef FIX_1419_MONO_STEREO_UMX + const int16_t bin_upmix_stereolr_flag, +#endif const int32_t output_Fs ) { int16_t i, j, tmp, tmp2; @@ -228,8 +231,15 @@ static ivas_error ivas_rend_initCrend( { if ( inConfigType == IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) { - hHrtf->max_num_ir -= 1; /* subtract LFE */ - hHrtf->gain_lfe = GAIN_LFE; +#ifdef FIX_1419_MONO_STEREO_UMX + if ( inConfig != IVAS_AUDIO_CONFIG_MONO && inConfig != IVAS_AUDIO_CONFIG_STEREO ) + { +#endif + hHrtf->max_num_ir -= 1; /* subtract LFE */ + hHrtf->gain_lfe = GAIN_LFE; +#ifdef FIX_1419_MONO_STEREO_UMX + } +#endif if ( output_Fs == 48000 ) { @@ -338,7 +348,20 @@ static ivas_error ivas_rend_initCrend( for ( i = 0; i < hHrtf->max_num_ir; i++ ) { +#ifdef FIX_1419_MONO_STEREO_UMX + if ( inConfig == IVAS_AUDIO_CONFIG_MONO ) + { + tmp = channelIndex_CICP1[i]; + } + else if ( inConfig == IVAS_AUDIO_CONFIG_STEREO ) + { + /* flag to select ±90 loudspeakers instead of ±30 */ + tmp = ( bin_upmix_stereolr_flag ) ? channelIndex_LR[i] : channelIndex_CICP2[i]; + } + else if ( inConfig == IVAS_AUDIO_CONFIG_5_1 ) +#else if ( inConfig == IVAS_AUDIO_CONFIG_5_1 ) +#endif { tmp = channelIndex_CICP6[i]; } @@ -360,7 +383,11 @@ static ivas_error ivas_rend_initCrend( } else { +#ifdef FIX_1419_MONO_STEREO_UMX + return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Error: Invalid channel configuration for Crend!\n\n" ); +#else return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Error: Channel configuration not specified!\n\n" ); +#endif } if ( output_Fs == 48000 ) @@ -703,8 +730,15 @@ static ivas_error ivas_rend_initCrend( { if ( inConfigType == IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) { - hHrtf->max_num_ir -= 1; /* subtract LFE */ - hHrtf->gain_lfe = GAIN_LFE; +#ifdef FIX_1419_MONO_STEREO_UMX + if ( inConfig != IVAS_AUDIO_CONFIG_MONO && inConfig != IVAS_AUDIO_CONFIG_STEREO ) + { +#endif + hHrtf->max_num_ir -= 1; /* subtract LFE */ + hHrtf->gain_lfe = GAIN_LFE; +#ifdef FIX_1419_MONO_STEREO_UMX + } +#endif } if ( ext_rend_flag == 1 ) @@ -747,7 +781,20 @@ static ivas_error ivas_rend_initCrend( for ( i = 0; i < hHrtf->max_num_ir; i++ ) { +#ifdef FIX_1419_MONO_STEREO_UMX + if ( inConfig == IVAS_AUDIO_CONFIG_MONO ) + { + tmp = channelIndex_CICP1[i]; + } + else if ( inConfig == IVAS_AUDIO_CONFIG_STEREO ) + { + /* flag to select ±90 loudspeakers instead of ±30 */ + tmp = ( bin_upmix_stereolr_flag ) ? channelIndex_LR[i] : channelIndex_CICP2[i]; + } + else if ( inConfig == IVAS_AUDIO_CONFIG_5_1 ) +#else if ( inConfig == IVAS_AUDIO_CONFIG_5_1 ) +#endif { tmp = channelIndex_CICP6[i]; } @@ -1172,7 +1219,11 @@ ivas_error ivas_rend_openCrend( if ( ( *pCrend )->hHrtfCrend == NULL ) { +#ifdef FIX_1419_MONO_STEREO_UMX + if ( ( error = ivas_rend_initCrend( *pCrend, inConfig, outConfig, hHrtfCrend, ext_rend_flag, hRendCfg->mono_stereo_upmix_config.stereoLR, output_Fs ) ) != IVAS_ERR_OK ) +#else if ( ( error = ivas_rend_initCrend( *pCrend, inConfig, outConfig, hHrtfCrend, ext_rend_flag, output_Fs ) ) != IVAS_ERR_OK ) +#endif { return error; } diff --git a/lib_rend/ivas_objectRenderer.c b/lib_rend/ivas_objectRenderer.c index a4e15c79de..eb9eaae142 100644 --- a/lib_rend/ivas_objectRenderer.c +++ b/lib_rend/ivas_objectRenderer.c @@ -138,10 +138,21 @@ ivas_error ivas_td_binaural_open_unwrap( } } +#ifdef FIX_1419_MONO_STEREO_UMX + if ( ivas_format == MONO_FORMAT || ivas_format == STEREO_FORMAT || ivas_format == MC_FORMAT ) +#else if ( ivas_format == MC_FORMAT ) +#endif { switch ( transport_config ) { +#ifdef FIX_1419_MONO_STEREO_UMX + case IVAS_AUDIO_CONFIG_MONO: + case IVAS_AUDIO_CONFIG_STEREO: + ls_azimuth = hTransSetup.ls_azimuth; + ls_elevation = hTransSetup.ls_elevation; + break; +#endif case IVAS_AUDIO_CONFIG_5_1: ls_azimuth = ls_azimuth_CICP6; ls_elevation = ls_elevation_CICP6; diff --git a/lib_rend/ivas_output_init.c b/lib_rend/ivas_output_init.c index 01e1d77231..85da653de6 100644 --- a/lib_rend/ivas_output_init.c +++ b/lib_rend/ivas_output_init.c @@ -36,7 +36,13 @@ #include "prot.h" #include "ivas_prot_rend.h" #include "ivas_rom_com.h" +#ifdef FIX_1419_MONO_STEREO_UMX +#include "ivas_rom_rend.h" +#endif #include "ivas_prot.h" +#ifdef FIX_1419_MONO_STEREO_UMX +#include +#endif #include #ifdef DEBUGGING #include "debug.h" @@ -166,9 +172,17 @@ void ivas_output_init( { case IVAS_AUDIO_CONFIG_MONO: hOutSetup->is_loudspeaker_setup = 1; +#ifdef FIX_1419_MONO_STEREO_UMX + hOutSetup->is_planar_setup = 1; + hOutSetup->ls_azimuth = ls_azimuth_CICP1; + hOutSetup->ls_elevation = ls_elevation_CICP1; +#endif break; case IVAS_AUDIO_CONFIG_STEREO: hOutSetup->is_loudspeaker_setup = 1; +#ifdef FIX_1419_MONO_STEREO_UMX + hOutSetup->is_planar_setup = 1; +#endif hOutSetup->ls_azimuth = ls_azimuth_CICP2; hOutSetup->ls_elevation = ls_elevation_CICP2; break; @@ -276,10 +290,24 @@ int16_t ivas_get_nchan_buffers_dec( if ( st_ivas->ivas_format == MONO_FORMAT ) { nchan_out_buff = st_ivas->hDecoderConfig->nchan_out; +#ifdef FIX_1419_MONO_STEREO_UMX + if ( output_config == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR && + ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) ) + { + nchan_out_buff = max( nchan_out_buff, st_ivas->hIntSetup.nchan_out_woLFE + st_ivas->hIntSetup.num_lfe ); + } +#endif } else if ( st_ivas->ivas_format == STEREO_FORMAT ) { nchan_out_buff = max( st_ivas->hDecoderConfig->nchan_out, CPE_CHANNELS ); +#ifdef FIX_1419_MONO_STEREO_UMX + if ( output_config == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR && + ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) ) + { + nchan_out_buff = max( nchan_out_buff, st_ivas->hIntSetup.nchan_out_woLFE + st_ivas->hIntSetup.num_lfe ); + } +#endif } else if ( st_ivas->ivas_format == ISM_FORMAT ) { @@ -435,6 +463,101 @@ ivas_error ivas_output_buff_dec( return IVAS_ERR_OK; } +#ifdef FIX_1419_MONO_STEREO_UMX + +/*---------------------------------------------------------------------* + * ms_upmix_validate_config() + * + * + *---------------------------------------------------------------------*/ + +ivas_error ms_upmix_validate_config( + IVAS_MS_UMX_CONF_HANDLE pMsUpmixConfig, /* i/o: Mono/Stereo upmix configuration */ + const IVAS_FORMAT ivasFormat, /* i : IVAS Decoder input configuration */ + const IVAS_AUDIO_CONFIG outConfig /* i : IVAS Decoder output configuration */ +) +{ + int16_t i; + float azi_abs[2]; + // float ele_abs[2]; + (void) ivasFormat; + + /* check custom positions */ + for ( i = 0; i < 2; i++ ) + { + azi_abs[i] = fabsf( pMsUpmixConfig->azi[i] ); + // ele_abs[i] = fabsf( pMsUpmixConfig->ele[i] ); + } + + if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) + { + if ( azi_abs[0] == 90 && azi_abs[1] == 90 ) + { + pMsUpmixConfig->stereoLR = TRUE; + } + } + +#if 0 + if ( false /* TODO no way to know if we have mono */ ) + { + if ( azi_abs[0] != 0 ) + { + fprintf( stderr, "Warning: panning mono to nonzero azimuth" ); + return IVAS_ERROR( IVAS_ERR_INVALID_RENDER_CONFIG, "Mono cannot be panned" ); + } + if ( ele_abs[0] != 0 ) + { + fprintf( stderr, "Warning: panning mono to nonzero elevation" ); + return IVAS_ERROR( IVAS_ERR_INVALID_RENDER_CONFIG, "Mono cannot be panned" ); + } + } + if ( false /* TODO no way to know if we have stereo */ ) + { + if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) + { + if ( ( azi_abs[0] != 30 && azi_abs[0] != 90 ) || + ( azi_abs[1] != 30 && azi_abs[1] != 90 ) ) + { + return IVAS_ERROR( IVAS_ERR_INVALID_RENDER_CONFIG, "BINAURAL_ROOM_IR only supports ±30 and ±90 degree azimuth" ); + } + // TODO we could allow {±30,35} front height speakers? + if ( ele_abs[0] != 0 || ele_abs[1] != 0 ) + { + fprintf( stderr, "Warning: elevation must be zero for BINAURAL_ROOM_IR" ); + return IVAS_ERROR( IVAS_ERR_INVALID_RENDER_CONFIG, "BINAURAL_ROOM_IR does not allow nonzero elevation" ); + } + } + else /* HRIR based formats and split rendering */ + { + if ( pMsUpmixConfig->azi[0] != -pMsUpmixConfig->azi[1] ) + { + fprintf( stderr, "Warning: azimuth for stereo pair must be symmetric" ); + return IVAS_ERROR( IVAS_ERR_INVALID_RENDER_CONFIG, "Panning stereo pair with asymmetric azimuth is not allowed" ); + } + if ( pMsUpmixConfig->ele[0] != pMsUpmixConfig->ele[1] ) + { + fprintf( stderr, "Warning: elevations for stereo pair must match" ); + return IVAS_ERROR( IVAS_ERR_INVALID_RENDER_CONFIG, "Panning stereo pair with differring elevation is not allowed" ); + } + if ( ( azi_abs[0] > 90 ) || + ( azi_abs[1] > 90 ) ) + { + fprintf( stderr, "Warning: panning stereo pair beyond 90deg azimuth" ); + return IVAS_ERROR( IVAS_ERR_INVALID_RENDER_CONFIG, "Panning stereo pair beyond |90| degrees azimuth is not allowed" ); + } + if ( ( ele_abs[0] > 45 ) || + ( ele_abs[1] > 45 ) ) + { + fprintf( stderr, "Warning: panning stereo pair beyond 45deg elevation" ); + return IVAS_ERROR( IVAS_ERR_INVALID_RENDER_CONFIG, "Panning stereo pair beyond |45| degrees of elevation is not allowed" ); + } + } + } +#endif + + return IVAS_ERR_OK; +} +#endif /*---------------------------------------------------------------------* * is_split_rendering_enabled() diff --git a/lib_rend/ivas_prot_rend.h b/lib_rend/ivas_prot_rend.h index ae80304ee0..6f594643f4 100644 --- a/lib_rend/ivas_prot_rend.h +++ b/lib_rend/ivas_prot_rend.h @@ -1343,6 +1343,13 @@ ivas_error ivas_render_config_init_from_rom( RENDER_CONFIG_HANDLE *hRenderConfig /* i/o: Renderer config handle */ ); +#ifdef FIX_1419_MONO_STEREO_UMX +ivas_error ms_upmix_validate_config( + IVAS_MS_UMX_CONF_HANDLE pMsUpmixConfig, /* i/o: Mono/Stereo upmix configuration */ + const IVAS_FORMAT ivasFormat, /* i : IVAS Decoder input configuration */ + const IVAS_AUDIO_CONFIG outConfig /* i : IVAS Decoder output configuration */ +); +#endif /*----------------------------------------------------------------------------------* * Quaternion operations diff --git a/lib_rend/ivas_render_config.c b/lib_rend/ivas_render_config.c index c3a39b426e..e1290b54a7 100644 --- a/lib_rend/ivas_render_config.c +++ b/lib_rend/ivas_render_config.c @@ -135,6 +135,15 @@ ivas_error ivas_render_config_init_from_rom( ( *hRenderConfig )->distAtt[0] = 15.75f; /* Default max dist */ ( *hRenderConfig )->distAtt[1] = 1.0f; /* Default ref dist */ ( *hRenderConfig )->distAtt[2] = 1.0f; /* Default rolloff factor */ +#ifdef FIX_1419_MONO_STEREO_UMX + + /* Mono/Stereo upmix configuration */ + ( *hRenderConfig )->mono_stereo_upmix_config.spatialEnabled = FALSE; + ( *hRenderConfig )->mono_stereo_upmix_config.stereoLR = FALSE; + ( *hRenderConfig )->mono_stereo_upmix_config.radius = 0.f; + set_zero( &( *hRenderConfig )->mono_stereo_upmix_config.azi[0], 2 ); + set_zero( &( *hRenderConfig )->mono_stereo_upmix_config.ele[0], 2 ); +#endif /* ISAR-related parameters */ ( *hRenderConfig )->split_rend_config.splitRendBitRate = ISAR_MAX_SPLIT_REND_BITRATE; diff --git a/lib_rend/ivas_rom_rend.c b/lib_rend/ivas_rom_rend.c index 3f4b906bd6..924f685adb 100644 --- a/lib_rend/ivas_rom_rend.c +++ b/lib_rend/ivas_rom_rend.c @@ -205,6 +205,11 @@ const int16_t sba_map_tc_512[11] = * 13 = 135, 35 * 14 = -135, 35 */ +#ifdef FIX_1419_MONO_STEREO_UMX +const int16_t channelIndex_CICP1[1] = { 2 }; +const int16_t channelIndex_CICP2[2] = { 0, 1 }; +const int16_t channelIndex_LR[2] = { 7, 8 }; +#endif const int16_t channelIndex_CICP6[5] = { 0, 1, 2, 5, 6 }; const int16_t channelIndex_CICP12[7] = { 0, 1, 2, 5, 6, 3, 4 }; const int16_t channelIndex_CICP14[7] = { 0, 1, 2, 5, 6, 9, 10 }; @@ -388,8 +393,8 @@ const float ivas_reverb_default_DSR[IVAS_REVERB_DEFAULT_N_BANDS] = *----------------------------------------------------------------------------------*/ /* CICP1 - Mono */ -const float ls_azimuth_CICP1[1] = { 0.0f }; -const float ls_elevation_CICP1[1] = { 0.0f }; +const float ls_azimuth_CICP1[1] = { 0.0f }; +const float ls_elevation_CICP1[1] = { 0.0f }; /*----------------------------------------------------------------------------------* @@ -619,6 +624,15 @@ const LS_CONVERSION_MATRIX ls_conversion_cicp19_cicp16[] = }; /* Upmix matrices */ +#ifdef FIX_1419_MONO_STEREO_UMX +const LS_CONVERSION_MATRIX ls_conversion_mono_cicpX[] = { + /* First row indicates the number of non-zero elements and the number of matrix columns */ + {1, 12.0f}, + /* Index of non-zero element, value of non-zero element*/ + {2, 1.0f}, +}; + +#endif const LS_CONVERSION_MATRIX ls_conversion_cicp12_cicp14[] = { /* First row indicates the number of non-zero elements and the number of matrix columns */ @@ -704,6 +718,9 @@ const LS_CONVERSION_MATRIX ls_conversion_cicp16_cicp19[] = const LS_CONVERSION_MAPPING ls_conversion_mapping[LS_SETUP_CONVERSION_NUM_MAPPINGS] = { /* Dowmix mappings - NULL is a special case for MONO / STEREO downmix */ +#ifdef FIX_1419_MONO_STEREO_UMX + {IVAS_AUDIO_CONFIG_STEREO, IVAS_AUDIO_CONFIG_MONO, NULL}, +#endif {IVAS_AUDIO_CONFIG_5_1, IVAS_AUDIO_CONFIG_MONO, NULL}, {IVAS_AUDIO_CONFIG_7_1, IVAS_AUDIO_CONFIG_MONO, NULL}, {IVAS_AUDIO_CONFIG_5_1_2, IVAS_AUDIO_CONFIG_MONO, NULL}, @@ -731,6 +748,14 @@ const LS_CONVERSION_MAPPING ls_conversion_mapping[LS_SETUP_CONVERSION_NUM_MAPPIN {IVAS_AUDIO_CONFIG_7_1_4, IVAS_AUDIO_CONFIG_5_1_4, ls_conversion_cicp19_cicp16}, /* Upmix mappings - NULL implies a 1:1 upmix */ +#ifdef FIX_1419_MONO_STEREO_UMX + {IVAS_AUDIO_CONFIG_MONO, IVAS_AUDIO_CONFIG_5_1, ls_conversion_mono_cicpX}, + {IVAS_AUDIO_CONFIG_MONO, IVAS_AUDIO_CONFIG_7_1, ls_conversion_mono_cicpX}, + {IVAS_AUDIO_CONFIG_MONO, IVAS_AUDIO_CONFIG_5_1_2, ls_conversion_mono_cicpX}, + {IVAS_AUDIO_CONFIG_MONO, IVAS_AUDIO_CONFIG_5_1_4, ls_conversion_mono_cicpX}, + {IVAS_AUDIO_CONFIG_MONO, IVAS_AUDIO_CONFIG_7_1_4, ls_conversion_mono_cicpX}, + +#endif {IVAS_AUDIO_CONFIG_STEREO, IVAS_AUDIO_CONFIG_5_1, NULL}, {IVAS_AUDIO_CONFIG_STEREO, IVAS_AUDIO_CONFIG_7_1, NULL}, {IVAS_AUDIO_CONFIG_STEREO, IVAS_AUDIO_CONFIG_5_1_2, NULL}, diff --git a/lib_rend/ivas_rom_rend.h b/lib_rend/ivas_rom_rend.h index 927287ecd9..2373f80ed0 100644 --- a/lib_rend/ivas_rom_rend.h +++ b/lib_rend/ivas_rom_rend.h @@ -67,6 +67,11 @@ extern const int16_t sba_map_tc_512[11]; * FASTCONV and PARAMETRIC binaural renderer ROM tables *----------------------------------------------------------------------------------*/ +#ifdef FIX_1419_MONO_STEREO_UMX +extern const int16_t channelIndex_CICP1[1]; +extern const int16_t channelIndex_CICP2[2]; +extern const int16_t channelIndex_LR[2]; +#endif extern const int16_t channelIndex_CICP6[5]; extern const int16_t channelIndex_CICP12[7]; extern const int16_t channelIndex_CICP14[7]; diff --git a/lib_rend/ivas_rotation.c b/lib_rend/ivas_rotation.c index b9286d3d96..c4c30ac160 100644 --- a/lib_rend/ivas_rotation.c +++ b/lib_rend/ivas_rotation.c @@ -361,7 +361,11 @@ void rotateFrame_sd( ) { int16_t i, j; +#ifdef FIX_1419_MONO_STEREO_UMX + int16_t nchan, num_lfe, index_lfe; +#else int16_t nchan, index_lfe; +#endif int16_t ch_in, ch_in_woLFE, ch_out, ch_out_woLFE; int16_t azimuth, elevation; @@ -374,6 +378,9 @@ void rotateFrame_sd( push_wmops( "rotateFrame_sd" ); nchan = hTransSetup.nchan_out_woLFE + hTransSetup.num_lfe; +#ifdef FIX_1419_MONO_STEREO_UMX + num_lfe = hTransSetup.num_lfe; +#endif index_lfe = hTransSetup.index_lfe[0]; tmp = 1.0f / ( subframe_len - 1 ); @@ -400,7 +407,11 @@ void rotateFrame_sd( } /* input channel index without LFE */ +#ifdef FIX_1419_MONO_STEREO_UMX + ch_in_woLFE = ( ( num_lfe > 0 ) && ( ch_in >= index_lfe ) ) ? ch_in - 1 : ch_in; +#else ch_in_woLFE = ( ch_in >= index_lfe ) ? ch_in - 1 : ch_in; +#endif /* gains for previous subframe rotation */ rotateAziEle( hTransSetup.ls_azimuth[ch_in_woLFE], hTransSetup.ls_elevation[ch_in_woLFE], &azimuth, &elevation, hCombinedOrientationData->Rmat_prev[0], hTransSetup.is_planar_setup ); @@ -417,7 +428,12 @@ void rotateFrame_sd( } /* output channel index without LFE */ +#ifdef FIX_1419_MONO_STEREO_UMX + ch_out_woLFE = ( ( num_lfe > 0 ) && ( ch_out >= index_lfe ) ) ? ch_out - 1 : ch_out; +#else ch_out_woLFE = ( ch_out >= index_lfe ) ? ch_out - 1 : ch_out; +#endif + gains_prev[ch_in][ch_out] = tmp_gains[ch_out_woLFE]; } @@ -439,7 +455,11 @@ void rotateFrame_sd( } /* output channel index without LFE */ +#ifdef FIX_1419_MONO_STEREO_UMX + ch_out_woLFE = ( ( num_lfe > 0 ) && ( ch_out >= index_lfe ) ) ? ch_out - 1 : ch_out; +#else ch_out_woLFE = ( ch_out >= index_lfe ) ? ch_out - 1 : ch_out; +#endif gains[ch_in][ch_out] = tmp_gains[ch_out_woLFE]; } diff --git a/lib_rend/lib_rend.c b/lib_rend/lib_rend.c index bba3fbb187..ceff06269a 100644 --- a/lib_rend/lib_rend.c +++ b/lib_rend/lib_rend.c @@ -1257,6 +1257,9 @@ static bool isIoConfigPairSupported( const AUDIO_CONFIG inConfig, const AUDIO_CONFIG outConfig ) { +#ifdef FIX_1419_MONO_STEREO_UMX + // TODO fix renderer +#endif /* Rendering mono or stereo to binaural is not supported */ if ( ( inConfig == IVAS_AUDIO_CONFIG_MONO || inConfig == IVAS_AUDIO_CONFIG_STEREO ) && getAudioConfigType( outConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) { @@ -2374,6 +2377,13 @@ static ivas_error initMcBinauralRendering( useTDRend = TRUE; } } +#ifdef FIX_1419_MONO_STEREO_UMX + // TODO remove after fix + if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) + { + return IVAS_ERROR( IVAS_ERR_INVALID_INPUT_FORMAT, "ROOM_IR mono/stereo binaural upmix WIP" ); + } +#endif /* if TD renderer was open and we need to use CREND, close it */ if ( !reconfigureFlag || ( !useTDRend && inputMc->tdRendWrapper.hBinRendererTd != NULL ) ) @@ -6205,7 +6215,12 @@ static ivas_error renderMcToBinaural( } } - if ( ( inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM ) || ( combinedOrientationEnabled && ( inConfig == IVAS_AUDIO_CONFIG_5_1 || inConfig == IVAS_AUDIO_CONFIG_7_1 ) ) ) +#ifdef FIX_1419_MONO_STEREO_UMX + if ( ( inConfig == IVAS_AUDIO_CONFIG_MONO || inConfig == IVAS_AUDIO_CONFIG_STEREO || inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM ) || +#else + if ( ( inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM ) || +#endif + ( combinedOrientationEnabled && ( inConfig == IVAS_AUDIO_CONFIG_5_1 || inConfig == IVAS_AUDIO_CONFIG_7_1 ) ) ) { copyBufferTo2dArray( mcInput->base.inputBuffer, tmpRendBuffer ); diff --git a/lib_util/render_config_reader.c b/lib_util/render_config_reader.c index 7729efbc7c..01bff48ac3 100644 --- a/lib_util/render_config_reader.c +++ b/lib_util/render_config_reader.c @@ -2591,6 +2591,46 @@ ivas_error RenderConfigReader_read( free( pValue ); acIdx++; } +#ifdef FIX_1419_MONO_STEREO_UMX + else if ( strcmp( chapter, "MSUPMIX" ) == 0 && strlen( pParams ) != 0 ) + { + params_idx = 0; + pValue = (char *) calloc( strlen( pParams ), sizeof( char ) ); + while ( sscanf( pParams + params_idx, "%64[^=]=%[^;];", item, pValue ) == 2 ) + { + params_idx += (int32_t) ( strlen( item ) + strlen( pValue ) + 2 ); + if ( strcmp( item, "AZIMUTH" ) == 0 ) + { + if ( read_txt_vector( pValue, 2, &hRenderConfig->mono_stereo_upmix_config.azi[0] ) ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + /* set flag to signal that spatial rendering is enabled */ + hRenderConfig->mono_stereo_upmix_config.spatialEnabled = 1; + } + else if ( strcmp( item, "ELEVATION" ) == 0 ) + { + if ( read_txt_vector( pValue, 2, &hRenderConfig->mono_stereo_upmix_config.ele[0] ) ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + /* set flag to signal that spatial rendering is enabled */ + hRenderConfig->mono_stereo_upmix_config.spatialEnabled = 1; + } + else if ( strcmp( item, "RADIUS" ) == 0 ) + { + if ( !sscanf( pValue, "%f", &hRenderConfig->mono_stereo_upmix_config.radius ) ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + } + /* set flag to signal that spatial rendering is enabled */ + hRenderConfig->mono_stereo_upmix_config.spatialEnabled = 1; + } + } + } +#endif else if ( strcmp( chapter, "SPLITREND" ) == 0 && strlen( pParams ) != 0 ) { params_idx = 0; @@ -2976,6 +3016,14 @@ ivas_error RenderConfigReader_getAcousticEnvironment( { return IVAS_ERR_UNEXPECTED_NULL_POINTER; } +#ifdef FIX_1419_MONO_STEREO_UMX + + /* case when config file contains no acoustic environment, the defaults are already set from ROM */ + if ( id == 65535 && pRenderConfigReader->nAE == 0 ) + { + return IVAS_ERR_OK; + } +#endif /* case when -aeid is not specified, select first ID from config file */ if ( id == 65535 && pRenderConfigReader->nAE > 0 ) -- GitLab From afd226c9e01eac69bc8bac8ca68db832eb7c00cd Mon Sep 17 00:00:00 2001 From: Archit Tamarapu Date: Mon, 27 Oct 2025 15:46:20 +0100 Subject: [PATCH 2/9] clang-format --- lib_dec/ivas_output_config.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lib_dec/ivas_output_config.c b/lib_dec/ivas_output_config.c index 9ac80ccb01..14dd3e4942 100644 --- a/lib_dec/ivas_output_config.c +++ b/lib_dec/ivas_output_config.c @@ -44,12 +44,12 @@ #ifdef FIX_1419_MONO_STEREO_UMX static void ms_bin_upmix_renderer_select( - const IVAS_FORMAT ivas_format, /* i : Decoder format */ - const IVAS_AUDIO_CONFIG output_config, /* i : Decoder output configuration */ - const IVAS_MS_UMX_CONF_HANDLE pMsUpmix_config, /* i : Mono/stereo upmix rendering configuration */ - const bool headrotation_enabled, /* i : Flag to signal headrotation is enabled */ - IVAS_AUDIO_CONFIG *internal_config, /* o : Internal configuration for rendering */ - RENDERER_TYPE *renderer_type /* o : Selected renderer type */ + const IVAS_FORMAT ivas_format, /* i : Decoder format */ + const IVAS_AUDIO_CONFIG output_config, /* i : Decoder output configuration */ + const IVAS_MS_UMX_CONF_HANDLE pMsUpmix_config, /* i : Mono/stereo upmix rendering configuration */ + const bool headrotation_enabled, /* i : Flag to signal headrotation is enabled */ + IVAS_AUDIO_CONFIG *internal_config, /* o : Internal configuration for rendering */ + RENDERER_TYPE *renderer_type /* o : Selected renderer type */ ) { @@ -125,11 +125,11 @@ void ivas_renderer_select( if ( st_ivas->ivas_format == MONO_FORMAT || st_ivas->ivas_format == STEREO_FORMAT ) { ms_bin_upmix_renderer_select( st_ivas->ivas_format, - output_config, - &st_ivas->hRenderConfig->mono_stereo_upmix_config, - ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ), - internal_config, - renderer_type ); + output_config, + &st_ivas->hRenderConfig->mono_stereo_upmix_config, + ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ), + internal_config, + renderer_type ); } else if ( st_ivas->ivas_format == ISM_FORMAT ) #else -- GitLab From e0f94ab2cdea33c4ad3e561cc9108e2b32796a57 Mon Sep 17 00:00:00 2001 From: Archit Tamarapu Date: Thu, 30 Oct 2025 19:35:23 +0100 Subject: [PATCH 3/9] [fix] mono split rendering and revert unintentional changes w.r.t. main --- lib_dec/ivas_init_dec.c | 10 +--------- lib_dec/ivas_jbm_dec.c | 7 ++++--- lib_dec/lib_dec.c | 22 +++++++++++++++++++--- lib_rend/ivas_objectRenderer.c | 1 + 4 files changed, 25 insertions(+), 15 deletions(-) diff --git a/lib_dec/ivas_init_dec.c b/lib_dec/ivas_init_dec.c index 02703130bc..7a79e83359 100644 --- a/lib_dec/ivas_init_dec.c +++ b/lib_dec/ivas_init_dec.c @@ -3174,15 +3174,7 @@ static ivas_error doSanityChecks_IVAS( /* Verify stereo output configuration */ if ( st_ivas->ivas_format == STEREO_FORMAT ) { - if ( output_config != IVAS_AUDIO_CONFIG_MONO && - output_config != IVAS_AUDIO_CONFIG_STEREO && - output_config != IVAS_AUDIO_CONFIG_5_1 && - output_config != IVAS_AUDIO_CONFIG_7_1 && - output_config != IVAS_AUDIO_CONFIG_5_1_2 && - output_config != IVAS_AUDIO_CONFIG_5_1_4 && - output_config != IVAS_AUDIO_CONFIG_7_1_4 && - output_config != IVAS_AUDIO_CONFIG_LS_CUSTOM && - output_config != IVAS_AUDIO_CONFIG_EXTERNAL ) + if ( output_config != IVAS_AUDIO_CONFIG_MONO && output_config != IVAS_AUDIO_CONFIG_STEREO && output_config != IVAS_AUDIO_CONFIG_5_1 && output_config != IVAS_AUDIO_CONFIG_7_1 && output_config != IVAS_AUDIO_CONFIG_5_1_2 && output_config != IVAS_AUDIO_CONFIG_5_1_4 && output_config != IVAS_AUDIO_CONFIG_7_1_4 && output_config != IVAS_AUDIO_CONFIG_LS_CUSTOM && output_config != IVAS_AUDIO_CONFIG_EXTERNAL ) { return IVAS_ERROR( IVAS_ERR_INVALID_OUTPUT_FORMAT, "Wrong output configuration specified for Stereo!" ); } diff --git a/lib_dec/ivas_jbm_dec.c b/lib_dec/ivas_jbm_dec.c index 7d1ad5045a..f1cd3ca172 100644 --- a/lib_dec/ivas_jbm_dec.c +++ b/lib_dec/ivas_jbm_dec.c @@ -945,6 +945,7 @@ ivas_error ivas_jbm_dec_render( /* Rendering */ if ( st_ivas->renderer_type == RENDERER_MC ) { + *nSamplesRendered = min( st_ivas->hTcBuffer->n_samples_available, nSamplesAskedLocal ); ivas_ls_setup_conversion( st_ivas, st_ivas->nchan_transport, *nSamplesRendered, p_tc, p_output ); } #ifdef FIX_1419_MONO_STEREO_UMX @@ -2881,11 +2882,11 @@ void ivas_dec_prepare_renderer( ivas_omasa_gain_masa_tc( st_ivas->hTcBuffer->tc, st_ivas->hMasaIsmData->gain_masa_edited, st_ivas->nchan_ism, st_ivas->hTcBuffer->n_samples_available ); } } - else if ( #ifdef FIX_1419_MONO_STEREO_UMX - st_ivas->ivas_format == MONO_FORMAT || + else if ( st_ivas->ivas_format == MONO_FORMAT || st_ivas->ivas_format == STEREO_FORMAT ) +#else + else if ( st_ivas->ivas_format == STEREO_FORMAT ) #endif - st_ivas->ivas_format == STEREO_FORMAT ) { ivas_jbm_dec_td_renderers_adapt_subframes( st_ivas ); } diff --git a/lib_dec/lib_dec.c b/lib_dec/lib_dec.c index ecefb196ec..c5f1a9f75f 100644 --- a/lib_dec/lib_dec.c +++ b/lib_dec/lib_dec.c @@ -887,6 +887,16 @@ ivas_error IVAS_DEC_FeedFrame_Serial( { hIvasDec->st_ivas->hDecoderConfig->ivas_total_brate = ACELP_8k00; +#ifdef FIX_1419_MONO_STEREO_UMX + if ( hIvasDec->st_ivas->hDecoderConfig->output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || + hIvasDec->st_ivas->hDecoderConfig->output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) + { + /* necessary to set up correct amount of memory for rendering; remaining setup happens in ivas_dec_setup_all() */ + ISAR_PRE_REND_GetMultiBinPoseData( &hIvasDec->st_ivas->hRenderConfig->split_rend_config, + &hIvasDec->st_ivas->hSplitBinRend->splitrend.multiBinPoseData, + ( hIvasDec->st_ivas->hCombinedOrientationData != NULL ) ? hIvasDec->st_ivas->hCombinedOrientationData->sr_pose_pred_axis : DEFAULT_AXIS ); + } +#endif if ( ( error = ivas_init_decoder( hIvasDec->st_ivas ) ) != IVAS_ERR_OK ) { return error; @@ -2360,11 +2370,13 @@ static ivas_error ivas_dec_setup_all( { ivas_error error; - if ( hIvasDec->mode == IVAS_DEC_MODE_EVS ) - { #ifdef FIX_1419_MONO_STEREO_UMX -// TODO split rendering for MONO + /* split rendering related functions in else are required also for mono SR */ + if ( hIvasDec->mode == IVAS_DEC_MODE_EVS && splitRendBits == NULL ) +#else + if ( hIvasDec->mode == IVAS_DEC_MODE_EVS ) #endif + { if ( hIvasDec->st_ivas->renderer_type == RENDERER_NON_DIEGETIC_DOWNMIX ) { *nTransportChannels = MAX_OUTPUT_CHANNELS_IN_DIEGETIC_PAN; @@ -2401,7 +2413,11 @@ static ivas_error ivas_dec_setup_all( * - reconfigure the decoder when the number of TC or IVAS total bitrate change *----------------------------------------------------------------*/ +#ifdef FIX_1419_MONO_STEREO_UMX + if ( st_ivas->bfi == 0 && hIvasDec->mode != IVAS_DEC_MODE_EVS ) +#else if ( st_ivas->bfi == 0 ) +#endif { if ( ( error = ivas_dec_setup( st_ivas ) ) != IVAS_ERR_OK ) { diff --git a/lib_rend/ivas_objectRenderer.c b/lib_rend/ivas_objectRenderer.c index eb9eaae142..0d9fbb8f60 100644 --- a/lib_rend/ivas_objectRenderer.c +++ b/lib_rend/ivas_objectRenderer.c @@ -149,6 +149,7 @@ ivas_error ivas_td_binaural_open_unwrap( #ifdef FIX_1419_MONO_STEREO_UMX case IVAS_AUDIO_CONFIG_MONO: case IVAS_AUDIO_CONFIG_STEREO: + /* appropriate values are set in ivas_init_decoder() */ ls_azimuth = hTransSetup.ls_azimuth; ls_elevation = hTransSetup.ls_elevation; break; -- GitLab From e33d468866fd99b98f91e089792e99303faa5a0b Mon Sep 17 00:00:00 2001 From: Archit Tamarapu Date: Fri, 31 Oct 2025 09:26:00 +0100 Subject: [PATCH 4/9] remove TODOs in lib_rend.c --- lib_rend/lib_rend.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/lib_rend/lib_rend.c b/lib_rend/lib_rend.c index ea2ce24758..87cd277184 100644 --- a/lib_rend/lib_rend.c +++ b/lib_rend/lib_rend.c @@ -1264,9 +1264,6 @@ static bool isIoConfigPairSupported( const AUDIO_CONFIG inConfig, const AUDIO_CONFIG outConfig ) { -#ifdef FIX_1419_MONO_STEREO_UMX - // TODO fix renderer -#endif /* Rendering mono or stereo to binaural is not supported */ if ( ( inConfig == IVAS_AUDIO_CONFIG_MONO || inConfig == IVAS_AUDIO_CONFIG_STEREO ) && getAudioConfigType( outConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) { @@ -2388,13 +2385,6 @@ static ivas_error initMcBinauralRendering( useTDRend = TRUE; } } -#ifdef FIX_1419_MONO_STEREO_UMX - // TODO remove after fix - if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) - { - return IVAS_ERROR( IVAS_ERR_INVALID_INPUT_FORMAT, "ROOM_IR mono/stereo binaural upmix WIP" ); - } -#endif /* if TD renderer was open and we need to use CREND, close it */ if ( !reconfigureFlag || ( !useTDRend && inputMc->tdRendWrapper.hBinRendererTd != NULL ) ) @@ -6239,11 +6229,7 @@ static ivas_error renderMcToBinaural( } } -#ifdef FIX_1419_MONO_STEREO_UMX - if ( ( inConfig == IVAS_AUDIO_CONFIG_MONO || inConfig == IVAS_AUDIO_CONFIG_STEREO || inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM ) || -#else if ( ( inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM ) || -#endif ( combinedOrientationEnabled && ( inConfig == IVAS_AUDIO_CONFIG_5_1 || inConfig == IVAS_AUDIO_CONFIG_7_1 ) ) ) { copyBufferTo2dArray( mcInput->base.inputBuffer, tmpRendBuffer ); -- GitLab From e14219c651b60ec06dcdc1401354ec4760d7c979 Mon Sep 17 00:00:00 2001 From: Archit Tamarapu Date: Fri, 31 Oct 2025 10:09:00 +0100 Subject: [PATCH 5/9] [fix] enable proper validation of render config --- lib_dec/lib_dec.c | 16 ++++++++++ lib_rend/ivas_output_init.c | 61 +++++++++++++++++++++---------------- 2 files changed, 50 insertions(+), 27 deletions(-) diff --git a/lib_dec/lib_dec.c b/lib_dec/lib_dec.c index c5f1a9f75f..7af3db646b 100644 --- a/lib_dec/lib_dec.c +++ b/lib_dec/lib_dec.c @@ -1742,6 +1742,10 @@ ivas_error IVAS_DEC_PrepareRenderer( IVAS_DEC_HANDLE hIvasDec /* i/o: IVAS decoder handle */ ) { +#ifdef FIX_1419_MONO_STEREO_UMX + ivas_error error; + +#endif if ( hIvasDec == NULL || hIvasDec->st_ivas == NULL ) { return IVAS_ERR_UNEXPECTED_NULL_POINTER; @@ -1751,6 +1755,18 @@ ivas_error IVAS_DEC_PrepareRenderer( { ivas_dec_prepare_renderer( hIvasDec->st_ivas ); } +#ifdef FIX_1419_MONO_STEREO_UMX + + if ( hIvasDec->st_ivas->hRenderConfig != NULL ) + { + if ( ( error = ms_upmix_validate_config( &hIvasDec->st_ivas->hRenderConfig->mono_stereo_upmix_config, + hIvasDec->st_ivas->ivas_format, + hIvasDec->st_ivas->hDecoderConfig->output_config ) ) != IVAS_ERR_OK ) + { + return error; + } + } +#endif hIvasDec->hasBeenPreparedRendering = true; diff --git a/lib_rend/ivas_output_init.c b/lib_rend/ivas_output_init.c index 85da653de6..6ac10a1e8d 100644 --- a/lib_rend/ivas_output_init.c +++ b/lib_rend/ivas_output_init.c @@ -479,81 +479,88 @@ ivas_error ms_upmix_validate_config( { int16_t i; float azi_abs[2]; - // float ele_abs[2]; - (void) ivasFormat; + float ele_abs[2]; - /* check custom positions */ - for ( i = 0; i < 2; i++ ) + if ( pMsUpmixConfig == NULL ) { - azi_abs[i] = fabsf( pMsUpmixConfig->azi[i] ); - // ele_abs[i] = fabsf( pMsUpmixConfig->ele[i] ); + return IVAS_ERR_UNEXPECTED_NULL_POINTER; } - if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) + /* skip validation if non spatial; values aren't used */ + if ( !pMsUpmixConfig->spatialEnabled ) { - if ( azi_abs[0] == 90 && azi_abs[1] == 90 ) - { - pMsUpmixConfig->stereoLR = TRUE; - } + return IVAS_ERR_OK; } -#if 0 - if ( false /* TODO no way to know if we have mono */ ) + /* validate radius */ + if ( pMsUpmixConfig->radius < 0.f || pMsUpmixConfig->radius > 1.f ) + { + return IVAS_ERROR( IVAS_ERR_INVALID_RENDER_CONFIG, "Radius must be between 0 and 1" ); + } + + /* obtain absolute values */ + for ( i = 0; i < 2; i++ ) + { + azi_abs[i] = fabsf( pMsUpmixConfig->azi[i] ); + ele_abs[i] = fabsf( pMsUpmixConfig->ele[i] ); + } + + /* validate speaker positions */ + if ( ivasFormat == MONO_FORMAT ) { if ( azi_abs[0] != 0 ) { - fprintf( stderr, "Warning: panning mono to nonzero azimuth" ); return IVAS_ERROR( IVAS_ERR_INVALID_RENDER_CONFIG, "Mono cannot be panned" ); } if ( ele_abs[0] != 0 ) { - fprintf( stderr, "Warning: panning mono to nonzero elevation" ); return IVAS_ERROR( IVAS_ERR_INVALID_RENDER_CONFIG, "Mono cannot be panned" ); } } - if ( false /* TODO no way to know if we have stereo */ ) + else if ( ivasFormat == STEREO_FORMAT ) { if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) { + /* validate provided positions match BRIR */ if ( ( azi_abs[0] != 30 && azi_abs[0] != 90 ) || ( azi_abs[1] != 30 && azi_abs[1] != 90 ) ) { return IVAS_ERROR( IVAS_ERR_INVALID_RENDER_CONFIG, "BINAURAL_ROOM_IR only supports ±30 and ±90 degree azimuth" ); } - // TODO we could allow {±30,35} front height speakers? if ( ele_abs[0] != 0 || ele_abs[1] != 0 ) { - fprintf( stderr, "Warning: elevation must be zero for BINAURAL_ROOM_IR" ); return IVAS_ERROR( IVAS_ERR_INVALID_RENDER_CONFIG, "BINAURAL_ROOM_IR does not allow nonzero elevation" ); } + + /* flag to select ±90 azi loudspeakers */ + if ( azi_abs[0] == 90 && azi_abs[1] == 90 ) + { + pMsUpmixConfig->stereoLR = TRUE; + } } else /* HRIR based formats and split rendering */ { + /* enforce symmetry */ if ( pMsUpmixConfig->azi[0] != -pMsUpmixConfig->azi[1] ) { - fprintf( stderr, "Warning: azimuth for stereo pair must be symmetric" ); return IVAS_ERROR( IVAS_ERR_INVALID_RENDER_CONFIG, "Panning stereo pair with asymmetric azimuth is not allowed" ); } if ( pMsUpmixConfig->ele[0] != pMsUpmixConfig->ele[1] ) { - fprintf( stderr, "Warning: elevations for stereo pair must match" ); return IVAS_ERROR( IVAS_ERR_INVALID_RENDER_CONFIG, "Panning stereo pair with differring elevation is not allowed" ); } - if ( ( azi_abs[0] > 90 ) || - ( azi_abs[1] > 90 ) ) + + /* restrict values */ + if ( ( azi_abs[0] > 90 ) || ( azi_abs[1] > 90 ) ) { - fprintf( stderr, "Warning: panning stereo pair beyond 90deg azimuth" ); return IVAS_ERROR( IVAS_ERR_INVALID_RENDER_CONFIG, "Panning stereo pair beyond |90| degrees azimuth is not allowed" ); } - if ( ( ele_abs[0] > 45 ) || - ( ele_abs[1] > 45 ) ) + if ( ( ele_abs[0] > 45 ) || ( ele_abs[1] > 45 ) ) { - fprintf( stderr, "Warning: panning stereo pair beyond 45deg elevation" ); return IVAS_ERROR( IVAS_ERR_INVALID_RENDER_CONFIG, "Panning stereo pair beyond |45| degrees of elevation is not allowed" ); } } } -#endif return IVAS_ERR_OK; } -- GitLab From c6e86bbdc68855320f4d9e0733a4977e3e3fa06f Mon Sep 17 00:00:00 2001 From: Archit Tamarapu Date: Fri, 31 Oct 2025 10:09:24 +0100 Subject: [PATCH 6/9] [fix] sanitizer error in openCrend() --- lib_rend/ivas_crend.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib_rend/ivas_crend.c b/lib_rend/ivas_crend.c index 500e48e883..880f3735ac 100644 --- a/lib_rend/ivas_crend.c +++ b/lib_rend/ivas_crend.c @@ -1220,7 +1220,13 @@ ivas_error ivas_rend_openCrend( if ( ( *pCrend )->hHrtfCrend == NULL ) { #ifdef FIX_1419_MONO_STEREO_UMX - if ( ( error = ivas_rend_initCrend( *pCrend, inConfig, outConfig, hHrtfCrend, ext_rend_flag, hRendCfg->mono_stereo_upmix_config.stereoLR, output_Fs ) ) != IVAS_ERR_OK ) + if ( ( error = ivas_rend_initCrend( *pCrend, + inConfig, + outConfig, + hHrtfCrend, + ext_rend_flag, + ( hRendCfg != NULL ) ? hRendCfg->mono_stereo_upmix_config.stereoLR : 0, + output_Fs ) ) != IVAS_ERR_OK ) #else if ( ( error = ivas_rend_initCrend( *pCrend, inConfig, outConfig, hHrtfCrend, ext_rend_flag, output_Fs ) ) != IVAS_ERR_OK ) #endif -- GitLab From eae904a48081b1166b4766798343a525b2fc3a01 Mon Sep 17 00:00:00 2001 From: Archit Tamarapu Date: Fri, 31 Oct 2025 11:26:57 +0100 Subject: [PATCH 7/9] [fix] ambisonics upmix for stereo --- lib_dec/ivas_jbm_dec.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/lib_dec/ivas_jbm_dec.c b/lib_dec/ivas_jbm_dec.c index f1cd3ca172..c97e5ff647 100644 --- a/lib_dec/ivas_jbm_dec.c +++ b/lib_dec/ivas_jbm_dec.c @@ -940,34 +940,32 @@ ivas_error ivas_jbm_dec_render( else if ( st_ivas->ivas_format == STEREO_FORMAT ) #endif { +#ifdef FIX_1419_MONO_STEREO_UMX *nSamplesRendered = min( st_ivas->hTcBuffer->n_samples_available, nSamplesAskedLocal ); +#endif /* Rendering */ if ( st_ivas->renderer_type == RENDERER_MC ) { +#ifndef FIX_1419_MONO_STEREO_UMX *nSamplesRendered = min( st_ivas->hTcBuffer->n_samples_available, nSamplesAskedLocal ); +#endif ivas_ls_setup_conversion( st_ivas, st_ivas->nchan_transport, *nSamplesRendered, p_tc, p_output ); } #ifdef FIX_1419_MONO_STEREO_UMX else if ( st_ivas->renderer_type == RENDERER_SBA_LINEAR_ENC ) { - /* Only upmix to ambisonics if spatial parameters exist */ - // TODO default render config is not enabled here, the GetDefault API func is never used - if ( st_ivas->hRenderConfig != NULL && !st_ivas->hRenderConfig->mono_stereo_upmix_config.spatialEnabled ) + if ( st_ivas->ivas_format == MONO_FORMAT ) { - ivas_mc2sba( st_ivas->hIntSetup, p_output, p_output, *nSamplesRendered, st_ivas->hOutSetup.ambisonics_order, 0.f ); + /* routed to W */ + ivas_jbm_dec_tc_buffer_playout( st_ivas, nSamplesAskedLocal, nSamplesRendered, p_output ); } - else + else if ( st_ivas->ivas_format == STEREO_FORMAT ) { - if ( st_ivas->ivas_format == MONO_FORMAT ) - { - // TODO route mono to W; probably same as ivas_jbm_dec_tc_buffer_playout - } - else if ( st_ivas->ivas_format == STEREO_FORMAT ) + for ( n = 0; n < *nSamplesRendered; n++ ) { - // TODO route stereo to W±Y - // p_output[0] = 0.5f * ( p_output[0] + p_output[1] ); // W = (L + R ) / 2 - // p_output[1] = 0.5f * ( p_output[0] - p_output[1] ); // Y = (L - R ) / 2 + p_output[0][n] = 0.5f * ( p_output[0][n] + p_output[1][n] ); /* W = 0.5 * ( L + R ) */ + p_output[1][n] = 0.5f * ( p_output[0][n] - p_output[1][n] ); /* Y = 0.5 * ( L - R ) */ } } } -- GitLab From ea5a8b5e795a546b017d86e99a2c8f9022a4bbc6 Mon Sep 17 00:00:00 2001 From: Archit Tamarapu Date: Fri, 31 Oct 2025 12:04:05 +0100 Subject: [PATCH 8/9] [fix] UBSAN when accessing render config --- lib_dec/ivas_init_dec.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib_dec/ivas_init_dec.c b/lib_dec/ivas_init_dec.c index 7a79e83359..7b4f178239 100644 --- a/lib_dec/ivas_init_dec.c +++ b/lib_dec/ivas_init_dec.c @@ -1356,9 +1356,10 @@ ivas_error ivas_init_decoder( #ifdef FIX_1419_MONO_STEREO_UMX /* Override transport config values from render config */ - if ( st_ivas->ivas_format == MONO_FORMAT || st_ivas->ivas_format == STEREO_FORMAT ) + if ( ( st_ivas->ivas_format == MONO_FORMAT || st_ivas->ivas_format == STEREO_FORMAT ) && + st_ivas->hRenderConfig != NULL && + st_ivas->hRenderConfig->mono_stereo_upmix_config.spatialEnabled ) { - // TODO check status of render config; is this a sanitizer issue if it is not always enabled? st_ivas->hTransSetup.ls_azimuth = st_ivas->hRenderConfig->mono_stereo_upmix_config.azi; st_ivas->hTransSetup.ls_elevation = st_ivas->hRenderConfig->mono_stereo_upmix_config.ele; } -- GitLab From 50d1461da57b9ecc026c84a73adfdb4d6fe78459 Mon Sep 17 00:00:00 2001 From: Archit Tamarapu Date: Fri, 31 Oct 2025 14:26:39 +0100 Subject: [PATCH 9/9] [fix] enable support for radius parameter in config --- lib_dec/ivas_objectRenderer_internal.c | 17 ++++++++++ lib_dec/lib_dec.c | 2 +- lib_rend/ivas_objectRenderer.c | 47 ++++++++++++++++++++++---- lib_rend/ivas_output_init.c | 11 ++++-- lib_rend/ivas_prot_rend.h | 3 ++ 5 files changed, 70 insertions(+), 10 deletions(-) diff --git a/lib_dec/ivas_objectRenderer_internal.c b/lib_dec/ivas_objectRenderer_internal.c index ff47b1b9a7..395d0f5997 100644 --- a/lib_dec/ivas_objectRenderer_internal.c +++ b/lib_dec/ivas_objectRenderer_internal.c @@ -66,8 +66,22 @@ ivas_error ivas_td_binaural_open( return IVAS_ERROR( IVAS_ERR_INTERNAL, "HRTF binary file present but not used in TD renderer" ); } +#ifdef FIX_1419_MONO_STEREO_UMX + return ivas_td_binaural_open_unwrap( &st_ivas->hHrtfTD, + st_ivas->hDecoderConfig->output_Fs, + num_src, + st_ivas->ivas_format, + st_ivas->transport_config, + st_ivas->hRenderConfig->directivity, + st_ivas->hRenderConfig->distAtt, + ( st_ivas->hRenderConfig != NULL ) ? &st_ivas->hRenderConfig->mono_stereo_upmix_config.radius : NULL, + st_ivas->hTransSetup, + &st_ivas->hBinRendererTd, + &st_ivas->binaural_latency_ns ); +#else return ivas_td_binaural_open_unwrap( &st_ivas->hHrtfTD, st_ivas->hDecoderConfig->output_Fs, num_src, st_ivas->ivas_format, st_ivas->transport_config, st_ivas->hRenderConfig->directivity, st_ivas->hRenderConfig->distAtt, st_ivas->hTransSetup, &st_ivas->hBinRendererTd, &st_ivas->binaural_latency_ns ); +#endif } @@ -312,6 +326,9 @@ ivas_error ivas_td_binaural_renderer_sf_splitBinaural( st_ivas->transport_config, st_ivas->hRenderConfig->directivity, st_ivas->hRenderConfig->distAtt, +#ifdef FIX_1419_MONO_STEREO_UMX + ( st_ivas->hRenderConfig != NULL ) ? &st_ivas->hRenderConfig->mono_stereo_upmix_config.radius : NULL, +#endif st_ivas->hTransSetup, &st_ivas->hTdRendHandles[i], &st_ivas->binaural_latency_ns ) ) != IVAS_ERR_OK ) diff --git a/lib_dec/lib_dec.c b/lib_dec/lib_dec.c index 7af3db646b..17fbdc9c1b 100644 --- a/lib_dec/lib_dec.c +++ b/lib_dec/lib_dec.c @@ -3437,7 +3437,7 @@ ivas_error IVAS_DEC_FeedRenderConfig( mvr2r( renderConfig.mono_stereo_upmix_config.azi, hRenderConfig->mono_stereo_upmix_config.azi, 2 ); mvr2r( renderConfig.mono_stereo_upmix_config.ele, hRenderConfig->mono_stereo_upmix_config.ele, 2 ); - /* validate configuration */ + /* validate configuration early - repeated in IVAS_DEC_PrepareRenderer when input format is available */ if ( ( error = ms_upmix_validate_config( &hRenderConfig->mono_stereo_upmix_config, st_ivas->ivas_format, st_ivas->hDecoderConfig->output_config ) ) != IVAS_ERR_OK ) diff --git a/lib_rend/ivas_objectRenderer.c b/lib_rend/ivas_objectRenderer.c index 0d9fbb8f60..3473eb42af 100644 --- a/lib_rend/ivas_objectRenderer.c +++ b/lib_rend/ivas_objectRenderer.c @@ -60,13 +60,16 @@ static void angles_to_vec( const float radius, const float azimuth, const float *---------------------------------------------------------------------*/ ivas_error ivas_td_binaural_open_unwrap( - TDREND_HRFILT_FiltSet_t **hHrtfTD, /* i/o: HR filter model (from file or NULL) */ - const int32_t output_Fs, /* i : Output sampling rate */ - const int16_t nchan_transport, /* i : Number of channels */ - const IVAS_FORMAT ivas_format, /* i : IVAS format (ISM/MC) */ - const AUDIO_CONFIG transport_config, /* i : Transport configuration */ - const float *directivity, /* i : Directivity pattern (used for ISM) */ - const float *distAtt, /* i : Distance attenuation (used for ISM) */ + TDREND_HRFILT_FiltSet_t **hHrtfTD, /* i/o: HR filter model (from file or NULL) */ + const int32_t output_Fs, /* i : Output sampling rate */ + const int16_t nchan_transport, /* i : Number of channels */ + const IVAS_FORMAT ivas_format, /* i : IVAS format (ISM/MC) */ + const AUDIO_CONFIG transport_config, /* i : Transport configuration */ + const float *directivity, /* i : Directivity pattern (used for ISM) */ + const float *distAtt, /* i : Distance attenuation (used for ISM) */ +#ifdef FIX_1419_MONO_STEREO_UMX + const float *radius_ms_umx, /* i : Radius (used for mono/stereo upmix) */ +#endif const IVAS_OUTPUT_SETUP hTransSetup, /* i : Loudspeaker layout */ BINAURAL_TD_OBJECT_RENDERER_HANDLE *hBinRendererTd, /* o : TD renderer handle */ int32_t *binaural_latency_ns /* i : Binauralization delay */ @@ -77,6 +80,9 @@ ivas_error ivas_td_binaural_open_unwrap( int16_t nS; int16_t SrcInd[MAX_NUM_TDREND_CHANNELS]; const float *ls_azimuth, *ls_elevation; +#ifdef FIX_1419_MONO_STEREO_UMX + float radius; +#endif float Pos[3]; float Dir[3]; TDREND_DirAtten_t *DirAtten_p; @@ -187,8 +193,21 @@ ivas_error ivas_td_binaural_open_unwrap( for ( nS = 0; nS < nchan_rend; nS++ ) { +#ifdef FIX_1419_MONO_STEREO_UMX + /* set radius from render configuration file for mono/stereo upmix; otherwise 1.f */ + radius = 1.f; + if ( ( transport_config == IVAS_AUDIO_CONFIG_MONO || transport_config == IVAS_AUDIO_CONFIG_STEREO ) && + radius_ms_umx != NULL ) + { + radius = *radius_ms_umx; + } + + /* Set source positions according to loudspeaker layout */ + angles_to_vec( radius, ls_azimuth[nS], ls_elevation[nS], Pos ); +#else /* Set source positions according to loudspeaker layout */ angles_to_vec( 1.0f, ls_azimuth[nS], ls_elevation[nS], Pos ); +#endif Dir[0] = 1.0f; Dir[1] = 0.0f; Dir[2] = 0.0f; @@ -722,7 +741,21 @@ ivas_error ivas_td_binaural_open_ext( distAtt = hRendCfg->distAtt; } +#ifdef FIX_1419_MONO_STEREO_UMX + return ivas_td_binaural_open_unwrap( pTDRend->hHrtfTD, + outFs, + nchan_transport, + ivas_format, + transport_config, + directivity, + distAtt, + ( hRendCfg != NULL ) ? &hRendCfg->mono_stereo_upmix_config.radius : NULL, + hTransSetup, + &pTDRend->hBinRendererTd, + &pTDRend->binaural_latency_ns ); +#else return ivas_td_binaural_open_unwrap( pTDRend->hHrtfTD, outFs, nchan_transport, ivas_format, transport_config, directivity, distAtt, hTransSetup, &pTDRend->hBinRendererTd, &pTDRend->binaural_latency_ns ); +#endif } diff --git a/lib_rend/ivas_output_init.c b/lib_rend/ivas_output_init.c index 6ac10a1e8d..33843aaba6 100644 --- a/lib_rend/ivas_output_init.c +++ b/lib_rend/ivas_output_init.c @@ -493,9 +493,16 @@ ivas_error ms_upmix_validate_config( } /* validate radius */ - if ( pMsUpmixConfig->radius < 0.f || pMsUpmixConfig->radius > 1.f ) + if ( pMsUpmixConfig->radius < 0.f || pMsUpmixConfig->radius > 15.75f ) { - return IVAS_ERROR( IVAS_ERR_INVALID_RENDER_CONFIG, "Radius must be between 0 and 1" ); + return IVAS_ERROR( IVAS_ERR_INVALID_RENDER_CONFIG, "Radius must be between 0 and 15.75" ); + } + + /* zero radius corresponds to non-spatial */ + if ( pMsUpmixConfig->radius == 0.f ) + { + pMsUpmixConfig->spatialEnabled = FALSE; + return IVAS_ERR_OK; } /* obtain absolute values */ diff --git a/lib_rend/ivas_prot_rend.h b/lib_rend/ivas_prot_rend.h index 6f594643f4..224b393c48 100644 --- a/lib_rend/ivas_prot_rend.h +++ b/lib_rend/ivas_prot_rend.h @@ -651,6 +651,9 @@ ivas_error ivas_td_binaural_open_unwrap( const AUDIO_CONFIG transport_config, /* i : Transport configuration */ const float *directivity, /* i : Directivity pattern (used for ISM) */ const float *distAtt, /* i : Distance attenuation (used for ISM) */ +#ifdef FIX_1419_MONO_STEREO_UMX + const float *radius_ms_umx, /* i : Radius (used for mono/stereo upmix) */ +#endif const IVAS_OUTPUT_SETUP hTransSetup, /* i : Loudspeaker layout */ BINAURAL_TD_OBJECT_RENDERER_HANDLE *hBinRendererTd, /* o : TD renderer handle */ int32_t *binaural_latency_ns /* i : Binauralization delay */ -- GitLab