From a323f1f58b5978e3556d24e02821a029476d8c4a Mon Sep 17 00:00:00 2001 From: Kacper Sagnowski Date: Mon, 13 Oct 2025 17:57:36 +0200 Subject: [PATCH 01/11] Port some formatting and documentation changes that were omitted in port 171 of float MR 1527 Not all changes from the original MR were ported, which makes porting following MRs more difficult than it should be. This commit ports some of the missing changes in preparation for work on port 391: https://forge.3gpp.org/rep/sa4/audio/ivas-basop/-/issues/2102 Original float MR: https://forge.3gpp.org/rep/ivas-codec-pc/ivas-codec/-/merge_requests/1527 Incomplete port to ivas-float-update: https://forge.3gpp.org/rep/sa4/audio/ivas-basop/-/merge_requests/1978 --- lib_isar/isar_prot.h | 304 +++++++++++++++++++++++++------------------ 1 file changed, 176 insertions(+), 128 deletions(-) diff --git a/lib_isar/isar_prot.h b/lib_isar/isar_prot.h index 85a99aa90..a06309018 100644 --- a/lib_isar/isar_prot.h +++ b/lib_isar/isar_prot.h @@ -33,18 +33,21 @@ #ifndef ISAR_PROT_H #define ISAR_PROT_H - #include "isar_stat.h" - - #include #include "options.h" #include "ivas_error.h" #include "lib_isar_post_rend.h" + +/* clang-format off */ +/*----------------------------------------------------------------------------------* + * General ISAR prototypes + *----------------------------------------------------------------------------------*/ + ivas_error isar_splitBinPreRendOpen( - ISAR_BIN_HR_SPLIT_PRE_REND_HANDLE *hBinHrSplitPreRend, - MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData + ISAR_BIN_HR_SPLIT_PRE_REND_HANDLE *hBinHrSplitPreRend, /* i/o: binaural pre-renderer handle */ + MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData /* i/o: pose correction data handle */ #ifdef SPLIT_REND_WITH_HEAD_ROT_DEBUG , const int32_t output_Fs @@ -52,58 +55,70 @@ ivas_error isar_splitBinPreRendOpen( ); ivas_error split_renderer_open_lc3plus( - SPLIT_REND_WRAPPER *hSplitRendWrapper, - const ISAR_SPLIT_REND_CONFIG_DATA *pSplitRendConfig, - const int32_t OutSampleRate, - const IVAS_RENDER_FRAMESIZE ivas_frame_size ); + SPLIT_REND_WRAPPER *hSplitRendWrapper, /* i/o: Split renderer pre-renderer handle */ + const ISAR_SPLIT_REND_CONFIG_DATA *pSplitRendConfig, /* i : Split renderer pre-renderer config */ + const int32_t output_Fs, /* i : output sampling rate */ + const IVAS_RENDER_FRAMESIZE ivas_frame_size /* i : IVAS frame size */ +); void isar_splitBinPreRendClose( - ISAR_BIN_HR_SPLIT_PRE_REND_HANDLE *hBinHrSplitPreRend ); + ISAR_BIN_HR_SPLIT_PRE_REND_HANDLE *hBinHrSplitPreRend /* i/o: binaural pre-renderer handle */ +); void lc3plusTimeAlignCldfbPoseCorr( - SPLIT_REND_WRAPPER *hSplitBin, - float Cldfb_In_BinReal[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], - float Cldfb_In_BinImag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX] ); + SPLIT_REND_WRAPPER *hSplitBin, /* i/o: Split renderer pre-renderer handle */ + float Cldfb_In_BinReal[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], /* i/o: Binaural signals, real part */ + float Cldfb_In_BinImag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX] /* i/o: Binaural signals, imag. part */ +); ivas_error splitRendLc3plusEncodeAndWrite( - SPLIT_REND_WRAPPER *hSplitBin, - ISAR_SPLIT_REND_BITS_HANDLE pBits, - const int32_t available_bits, - float *in[] ); + SPLIT_REND_WRAPPER *hSplitBin, /* i/o: Split renderer pre-renderer handle */ + ISAR_SPLIT_REND_BITS_HANDLE pBits, /* i/o: ISAR bits handle */ + const int32_t available_bits, /* i : available bit-budget */ + float *in[] /* i/o: PCM in/out buffer */ +); +/*! r: parameter value */ int32_t ISAR_SPLIT_REND_BITStream_read_int32( - ISAR_SPLIT_REND_BITS_HANDLE pBits, - const int32_t bits ); + ISAR_SPLIT_REND_BITS_HANDLE pBits, /* i/o: ISAR bits handle */ + const int32_t bits /* i : number of bits to be read */ +); void ISAR_SPLIT_REND_BITStream_write_int32( - ISAR_SPLIT_REND_BITS_HANDLE pBits, - const int32_t val, - const int32_t bits ); + ISAR_SPLIT_REND_BITS_HANDLE pBits, /* i/o: ISAR bits handle */ + const int32_t val, /* i : parameter value */ + const int32_t bits /* i : number of bits to be written */ +); ivas_error isar_splitBinLCLDEncOpen( - ISAR_BIN_HR_SPLIT_LCLD_ENC_HANDLE *hSplitBinLCLDEnc, + ISAR_BIN_HR_SPLIT_LCLD_ENC_HANDLE *hSplitBinLCLDEnc, /* o : ISAR LCLD encoder handle */ const int32_t iSampleRate, const int16_t iChannels, const int32_t iDataRate, const int16_t iNumBlocks, - const int16_t iNumIterations ); + const int16_t iNumIterations +); ivas_error isar_splitBinRendPLCOpen( - ISAR_SPLIT_REND_PLC_HANDLE *phSplitRendPLC, - const int16_t iNumSubSets ); + ISAR_SPLIT_REND_PLC_HANDLE *phSplitRendPLC, /* i/o: ISAR PLC handle */ + const int16_t iNumSubSets +); void isar_splitBinRendPLCClose( - ISAR_SPLIT_REND_PLC_HANDLE *phSplitRendPLC ); + ISAR_SPLIT_REND_PLC_HANDLE *phSplitRendPLC /* i/o: ISAR PLC handle */ +); ivas_error isar_splitBinLCLDDecOpen( - ISAR_BIN_HR_SPLIT_LCLD_DEC_HANDLE *hSplitBinLCLDDec, + ISAR_BIN_HR_SPLIT_LCLD_DEC_HANDLE *hSplitBinLCLDDec, /* i/o: ISAR LCLD decoder handle */ const int32_t iSampleRate, const int16_t iChannels, const int16_t iNumBlocks, - const int16_t iNumIterations ); + const int16_t iNumIterations +); void isar_splitBinLCLDDecClose( - ISAR_BIN_HR_SPLIT_LCLD_DEC_HANDLE *hSplitBinLCLDDec ); + ISAR_BIN_HR_SPLIT_LCLD_DEC_HANDLE *hSplitBinLCLDDec /* o : ISAR LCLD decoder handle */ +); void isar_splitBinRendPLCsaveState( ISAR_SPLIT_REND_PLC_HANDLE hSplitRendPLC, @@ -111,7 +126,8 @@ void isar_splitBinRendPLCsaveState( float Cldfb_ImagBuffer_Binaural[BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], const int16_t num_chs, const int16_t iNumBlocks, - const int16_t iNumIterations ); + const int16_t iNumIterations +); void isar_splitBinRendPLC_xf( ISAR_SPLIT_REND_PLC_HANDLE hSplitRendPLC, @@ -121,7 +137,8 @@ void isar_splitBinRendPLC_xf( const int16_t iNumBlocks, const int16_t iNumIterations, int32_t **ppiDecodingFailed, - int32_t **ppiDecodingFailedPrev ); + int32_t **ppiDecodingFailedPrev +); void isar_splitBinRendPLC( ISAR_SPLIT_REND_PLC_HANDLE hSplitRendPLC, @@ -130,7 +147,8 @@ void isar_splitBinRendPLC( const int16_t num_chs, const int16_t iNumBlocks, const int16_t iNumIterations, - int32_t **ppiDecodingFailed ); + int32_t **ppiDecodingFailed +); #ifdef SPLIT_REND_WITH_HEAD_ROT_DEBUG void isar_log_cldfb2wav_data( @@ -142,51 +160,61 @@ void isar_log_cldfb2wav_data( const int32_t output_Fs, const int16_t start_slot_idx, const int16_t md_band_idx, - const char *filename ); -#endif + const char *filename +); +#endif void isar_splitBinLCLDDecProcess( - ISAR_BIN_HR_SPLIT_LCLD_DEC_HANDLE hSplitBinLCLDDec, - ISAR_SPLIT_REND_BITS_HANDLE pBits, - float Cldfb_Out_Real[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], - float Cldfb_Out_Imag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], - const int16_t bfi ); + ISAR_BIN_HR_SPLIT_LCLD_DEC_HANDLE hSplitBinLCLDDec, /* i/o: ISAR LCLD decoder handle */ + ISAR_SPLIT_REND_BITS_HANDLE pBits, /* i/o: ISAR bits handle */ + float Cldfb_Out_Real[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], /* i : Binaural signals, real part */ + float Cldfb_Out_Imag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], /* i : Binaural signals, imag. part */ + const int16_t bfi /* i : BFI flag */ +); void set_fix_rotation_mat( float fix_pos_rot_mat[][BINAURAL_CHANNELS][BINAURAL_CHANNELS], - MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData ); + MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData /* i/o: pose correction data handle */ +); void isar_splitBinLCLDEncClose( - ISAR_BIN_HR_SPLIT_LCLD_ENC_HANDLE *hSplitBinLCLDEnc ); + ISAR_BIN_HR_SPLIT_LCLD_ENC_HANDLE *hSplitBinLCLDEnc /* i/o: ISAR LCLD encoder handle */ +); void isar_splitBinLCLDEncProcess( - ISAR_BIN_HR_SPLIT_LCLD_ENC_HANDLE hSplitBinLCLDEnc, + ISAR_BIN_HR_SPLIT_LCLD_ENC_HANDLE hSplitBinLCLDEnc, /* i/o: ISAR LCLD encoder handle */ float Cldfb_In_Real[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], float Cldfb_In_Imag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], const int32_t available_bits, - ISAR_SPLIT_REND_BITS_HANDLE pBits ); + ISAR_SPLIT_REND_BITS_HANDLE pBits /* i/o: ISAR bits handle */ +); void set_pose_types( - ISAR_SPLIT_REND_POSE_TYPE pose_type[MAX_HEAD_ROT_POSES - 1], - MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData ); + ISAR_SPLIT_REND_POSE_TYPE pose_type[MAX_HEAD_ROT_POSES - 1],/* o : ISAR pose type */ + MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData /* i/o: pose correction data handle */ +); void isar_split_rend_init_huff_cfg( - ISAR_BIN_HR_SPLIT_REND_HUFF_HANDLE pHuff_cfg ); + ISAR_BIN_HR_SPLIT_REND_HUFF_HANDLE pHuff_cfg +); ivas_error isar_splitBinPostRendOpen( - ISAR_BIN_HR_SPLIT_POST_REND_HANDLE *hBinHrSplitPostRend, - MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData, - const int32_t output_Fs ); + ISAR_BIN_HR_SPLIT_POST_REND_HANDLE *hBinHrSplitPostRend, /* i/o: binaural post-renderer handle */ + MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData, /* i/o: pose correction data handle */ + const int32_t output_Fs /* i : output sampling rate */ +); void isar_splitBinPostRendClose( - ISAR_BIN_HR_SPLIT_POST_REND_HANDLE *hBinHrSplitPostRend ); + ISAR_BIN_HR_SPLIT_POST_REND_HANDLE *hBinHrSplitPostRend /* i/o: binaural post-renderer handle */ +); void isar_SplitRenderer_getdiagdiff( int16_t in_idx[BINAURAL_CHANNELS][BINAURAL_CHANNELS], int16_t out_idx[BINAURAL_CHANNELS][BINAURAL_CHANNELS], const int16_t sign, const int16_t min_val, - const int16_t max_val ); + const int16_t max_val +); void isar_split_rend_get_quant_params( const int16_t num_md_bands, @@ -200,24 +228,24 @@ void isar_split_rend_get_quant_params( int16_t pred_real_bands_roll[ISAR_SPLIT_REND_NUM_QUANT_STRATS], int16_t pred_imag_bands_roll[ISAR_SPLIT_REND_NUM_QUANT_STRATS], const int16_t ro_flag, - int16_t *num_quant_strats ); + int16_t *num_quant_strats +); void isar_splitBinPostRendMdDec( - ISAR_SPLIT_REND_BITS_HANDLE pBits, - ISAR_BIN_HR_SPLIT_POST_REND_HANDLE hBinHrSplitPostRend, + ISAR_SPLIT_REND_BITS_HANDLE pBits, /* i/o: ISAR bits handle */ + ISAR_BIN_HR_SPLIT_POST_REND_HANDLE hBinHrSplitPostRend, /* i/o: binaural post-renderer handle */ + MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData /* i/o: pose correction data handle */ #ifdef SPLIT_REND_WITH_HEAD_ROT_DEBUG - MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData, - BIN_HR_SPLIT_PRE_REND_HANDLE hBinHrSplitPreRend -#else - MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData + , + BIN_HR_SPLIT_PRE_REND_HANDLE hBinHrSplitPreRend /* i/o: binaural pre-renderer handle */ #endif ); void Quat2EulerDegree( - const IVAS_QUATERNION quat, /* i : quaternion describing the rotation */ - float *yaw, /* o : yaw */ - float *pitch, /* o : pitch */ - float *roll /* o : roll */ + const IVAS_QUATERNION quat, /* i : quaternion describing the rotation */ + float *yaw, /* o : yaw */ + float *pitch, /* o : pitch */ + float *roll /* o : roll */ ); void isar_mat_mult_2by2_complex( @@ -226,122 +254,142 @@ void isar_mat_mult_2by2_complex( float in_re2[2][2], float in_im2[2][2], float out_re2[2][2], - float out_im2[2][2] ); + float out_im2[2][2] +); void isar_rend_CldfbSplitPostRendProcess( - ISAR_BIN_HR_SPLIT_POST_REND_HANDLE hBinHrSplitPostRend, - MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData, + ISAR_BIN_HR_SPLIT_POST_REND_HANDLE hBinHrSplitPostRend, /* i/o: binaural post-renderer handle */ + MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData, /* i/o: pose correction data handle */ const IVAS_QUATERNION QuaternionPost, float Cldfb_RealBuffer_Binaural[][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX], float Cldfb_ImagBuffer_Binaural[][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX], float output[][L_FRAME48k], - const int16_t cldfb_in_flag ); + const int16_t cldfb_in_flag +); void isar_rend_CldfbSplitPreRendProcess( - const ISAR_BIN_HR_SPLIT_PRE_REND_HANDLE hBinHrSplitPreRend, - const IVAS_QUATERNION headPosition, - MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData, - float Cldfb_In_BinReal[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], - float Cldfb_In_BinImag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], - ISAR_SPLIT_REND_BITS_HANDLE pBits, - const int32_t target_md_bits, - const int16_t low_res_pre_rend_rot, - const int16_t ro_md_flag ); + const ISAR_BIN_HR_SPLIT_PRE_REND_HANDLE hBinHrSplitPreRend, /* i : binaural pre-renderer handle */ + const IVAS_QUATERNION headPosition, /* i : head rotation QUATERNION */ + MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData, /* i/o: pose correction data handle */ + float Cldfb_In_BinReal[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], /* i : Binaural signals, real part */ + float Cldfb_In_BinImag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], /* i : Binaural signals, imag. part */ + ISAR_SPLIT_REND_BITS_HANDLE pBits, /* i/o: ISAR bits handle */ + const int32_t target_md_bits, /* i : ISAR MD bitrate */ + const int16_t low_res_pre_rend_rot, /* i : low time resolution pre-renderer flag */ + const int16_t ro_md_flag /* i : real only metadata for yaw flag */ +); ivas_error isar_renderMultiTDBinToSplitBinaural( - SPLIT_REND_WRAPPER *hSplitBin, - const IVAS_QUATERNION headPosition, - const int32_t SplitRendBitRate, - const int16_t isar_frame_size_ms, - const int16_t codec_frame_size_ms, - ISAR_SPLIT_REND_BITS_HANDLE pBits, - const int16_t max_bands, - float *in[], - const int16_t low_res_pre_rend_rot, - const int16_t pcm_out_flag, - const int16_t ro_md_flag ); + SPLIT_REND_WRAPPER *hSplitBin, /* i/o: Split renderer pre-renderer handle */ + const IVAS_QUATERNION headPosition, /* i : head rotation QUATERNION */ + const int32_t SplitRendBitRate, /* i : ISAR bitrate */ + const int16_t isar_frame_size_ms, /* i : ISAR bit stream frame size in ms */ + const int16_t codec_frame_size_ms, /* i : ISAR frame length in ms */ + ISAR_SPLIT_REND_BITS_HANDLE pBits, /* i/o: ISAR bits handle */ + const int16_t max_bands, /* i : CLDFB bands */ + float *in[], /* i/o: PCM in/out buffer */ + const int16_t low_res_pre_rend_rot, /* i : low time resolution pre-renderer flag */ + const int16_t pcm_out_flag, /* i : flag to indicate PCM output */ + const int16_t ro_md_flag /* i : real only metadata for yaw flag */ +); void isar_init_multi_bin_pose_data( - MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData ); + MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData /* i/o: pose correction data handle */ +); void isar_renderSplitGetMultiBinPoseData( - const ISAR_SPLIT_REND_CONFIG_DATA *pSplit_rend_config, - MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData, - const ISAR_SPLIT_REND_ROT_AXIS rot_axis ); + const ISAR_SPLIT_REND_CONFIG_DATA *pSplit_rend_config, /* i : Split renderer pre-renderer config */ + MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData, /* i/o: pose correction data handle */ + const ISAR_SPLIT_REND_ROT_AXIS rot_axis /* i : external control for rotation axis for split rendering */ +); int16_t isar_renderSplitGetRot_axisNumBits( - const int16_t dof ); + const int16_t dof +); ISAR_SPLIT_REND_ROT_AXIS isar_renderSplitGetRot_axisFromCode( const int16_t dof, - const int16_t code ); + const int16_t code +); int16_t isar_renderSplitGetCodeFromRot_axis( const int16_t dof, const ISAR_SPLIT_REND_ROT_AXIS rot_axis, - int16_t *num_bits ); + int16_t *num_bits +); void isar_init_split_post_rend_handles( - ISAR_SPLIT_POST_REND_WRAPPER *hSplitRendWrapper ); + ISAR_SPLIT_POST_REND_WRAPPER *hSplitRendWrapper /* i/o: Split renderer post-renderer handle */ +); void isar_set_split_rend_ht_setup( - SPLIT_REND_WRAPPER *hSplitrend, - IVAS_QUATERNION Quaternions[MAX_PARAM_SPATIAL_SUBFRAMES], - float Rmat[MAX_PARAM_SPATIAL_SUBFRAMES][3][3] ); - + SPLIT_REND_WRAPPER *hSplitrend, /* i/o: Split renderer pre-renderer handle */ + IVAS_QUATERNION Quaternions[MAX_PARAM_SPATIAL_SUBFRAMES], /* i/o: External orientation in quaternions */ + float Rmat[MAX_PARAM_SPATIAL_SUBFRAMES][3][3] /* o : real-space rotation matrix */ +); int32_t isar_get_lc3plus_bitrate( - const int32_t SplitRendBitRate, - const ISAR_SPLIT_REND_POSE_CORRECTION_MODE poseCorrectionMode, - const int32_t nChannels, - const int32_t codecFrameDurationUs ); + const int32_t SplitRendBitRate, /* i : ISAR bitrate */ + const ISAR_SPLIT_REND_POSE_CORRECTION_MODE poseCorrectionMode, /* i : ISAR pose correction mode */ + const int32_t nChannels, /* i : number of channels */ + const int32_t lc3plus_frame_duration_us /* i : ISAR frame length in us */ +); ivas_error isar_split_rend_validate_config( - const ISAR_SPLIT_REND_CONFIG_DATA *pSplitRendConfig, - const int16_t pcm_out_flag ); + const ISAR_SPLIT_REND_CONFIG_DATA *pSplitRendConfig, /* i : Split renderer pre-renderer config */ + const int16_t pcm_out_flag /* i : flag to indicate PCM output */ +); +/*! r: LCLD codec bitrate */ int32_t isar_get_lcld_bitrate( - const int32_t SplitRendBitRate, - const ISAR_SPLIT_REND_POSE_CORRECTION_MODE poseCorrectionMode ); - + const int32_t SplitRendBitRate, /* i : ISAR bitrate */ + const ISAR_SPLIT_REND_POSE_CORRECTION_MODE poseCorrectionMode /* i : ISAR pose correction mode */ +); +/*! r: ISAR MD bitrate */ int32_t isar_get_split_rend_md_target_brate( - const int32_t SplitRendBitRate, - const int16_t pcm_out_flag ); + const int32_t SplitRendBitRate, /* i : ISAR bitrate */ + const int16_t pcm_out_flag /* i : flag to indicate PCM output */ +); ivas_error isar_framesize_to_ms( - const IVAS_RENDER_FRAMESIZE frame_size, /* i : frame size enum */ - int16_t *ms /* o : frame size in ms */ + const IVAS_RENDER_FRAMESIZE frame_size, /* i : frame size enum */ + int16_t *ms /* o : frame size in ms */ ); ivas_error isar_split_rend_choose_default_codec( - ISAR_SPLIT_REND_CODEC *pCodec, /* i/o: pointer to codec setting */ - int16_t *pIsar_frame_size_ms, /* i/o: pointer to isar frame size setting */ - int16_t *pCodec_frame_size_ms, /* i/o: pointer to codec frame size setting */ - const int16_t cldfb_in_flag, /* i : flag indicating rendering in TD */ - const int16_t pcm_out_flag, /* i : flag to indicate PCM output */ - const int16_t num_subframes /* i : number of subframes */ + ISAR_SPLIT_REND_CODEC *pCodec, /* i/o: pointer to codec setting */ + int16_t *pIsar_frame_size_ms, /* i/o: pointer to ISAR frame size setting */ + int16_t *pCodec_frame_size_ms, /* i/o: pointer to codec frame size setting */ + const int16_t cldfb_in_flag, /* i : flag indicating rendering in TD */ + const int16_t pcm_out_flag, /* i : flag to indicate PCM output */ + const int16_t num_subframes /* i : number of subframes */ ); -void ISAR_SPLIT_REND_BITStream_init( - ISAR_SPLIT_REND_BITS_HANDLE pBits, - const int32_t buf_len_bytes, - uint8_t *pbuf ); - void isar_renderSplitUpdateNoCorrectionPoseData( - const ISAR_SPLIT_REND_CONFIG_DATA *pSplit_rend_config, - MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData ); + const ISAR_SPLIT_REND_CONFIG_DATA *pSplit_rend_config, /* i : Split renderer pre-renderer config */ + MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData /* i/o: pose correction data handle */ +); int32_t get_bit( const int32_t state, - const int32_t bit_id ); + const int32_t bit_id +); +/*! r: ISAR audio type */ ISAR_POST_REND_AudioConfigType isar_getAudioConfigType( - const IVAS_AUDIO_CONFIG config ); + const IVAS_AUDIO_CONFIG config /* i : audio configuration */ +); void isar_init_split_rend_handles( - SPLIT_REND_WRAPPER *hSplitRendWrapper ); + SPLIT_REND_WRAPPER *hSplitRendWrapper /* i/o: Split renderer pre-renderer handle */ +); +void ISAR_SPLIT_REND_BITStream_init( + ISAR_SPLIT_REND_BITS_HANDLE pBits, + const int32_t buf_len_bytes, + uint8_t *pbuf +); /* clang-format on */ -- GitLab From e5639a061c94156805147a60e0d9ce1d98c7a9b5 Mon Sep 17 00:00:00 2001 From: Kacper Sagnowski Date: Mon, 6 Oct 2025 16:44:04 +0200 Subject: [PATCH 02/11] [WIP] Port split rendering support in VoIP mode --- Workspace_msvc/lib_isar.vcxproj | 2 +- Workspace_msvc/lib_rend.vcxproj | 1 + Workspace_msvc/lib_rend.vcxproj.filters | 3 + apps/decoder.c | 129 +++- apps/isar_post_rend.c | 13 + lib_com/ivas_prot.h | 37 ++ lib_com/options.h | 3 +- lib_dec/ivas_dirac_dec.c | 16 +- lib_dec/ivas_init_dec.c | 4 + lib_dec/ivas_jbm_dec.c | 6 + lib_dec/ivas_mc_param_dec.c | 8 + lib_dec/ivas_mc_paramupmix_dec.c | 8 + lib_dec/ivas_omasa_dec.c | 11 +- lib_dec/ivas_osba_dec.c | 15 +- lib_dec/ivas_output_config.c | 12 +- lib_dec/ivas_stat_dec.h | 18 +- lib_dec/lib_dec.c | 615 ++++++++++++++++++- lib_dec/lib_dec.h | 20 + lib_isar/isar_prot.h | 17 +- lib_isar/isar_splitRend_lcld_enc.c | 10 +- lib_isar/isar_splitRendererPre.c | 119 +++- lib_isar/isar_stat.h | 13 + lib_isar/lib_isar_pre_rend.c | 39 +- lib_isar/lib_isar_pre_rend.h | 5 + lib_rend/ivas_cldfb_ring_buffer.c | 299 +++++++++ lib_rend/ivas_dirac_dec_binaural_functions.c | 17 +- lib_rend/ivas_prot_rend.h | 60 ++ lib_rend/ivas_stat_rend.h | 16 + lib_rend/ivas_td_ring_buffer.c | 420 +++++++++++++ lib_rend/lib_rend.c | 25 +- 30 files changed, 1881 insertions(+), 80 deletions(-) create mode 100644 lib_rend/ivas_cldfb_ring_buffer.c create mode 100644 lib_rend/ivas_td_ring_buffer.c diff --git a/Workspace_msvc/lib_isar.vcxproj b/Workspace_msvc/lib_isar.vcxproj index 5bee82704..fceeb731c 100644 --- a/Workspace_msvc/lib_isar.vcxproj +++ b/Workspace_msvc/lib_isar.vcxproj @@ -197,4 +197,4 @@ - \ No newline at end of file + diff --git a/Workspace_msvc/lib_rend.vcxproj b/Workspace_msvc/lib_rend.vcxproj index 27d4a19a6..55f598ecf 100644 --- a/Workspace_msvc/lib_rend.vcxproj +++ b/Workspace_msvc/lib_rend.vcxproj @@ -138,6 +138,7 @@ + diff --git a/Workspace_msvc/lib_rend.vcxproj.filters b/Workspace_msvc/lib_rend.vcxproj.filters index 63e83fc9b..ebcb9060c 100644 --- a/Workspace_msvc/lib_rend.vcxproj.filters +++ b/Workspace_msvc/lib_rend.vcxproj.filters @@ -116,6 +116,9 @@ rend_c + + rend_c + diff --git a/apps/decoder.c b/apps/decoder.c index 936a3e4f9..c7bda2a5a 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -181,7 +181,11 @@ static bool parseCmdlIVAS_dec( int16_t argc, char **argv, DecArguments *arg ); static void usage_dec( void ); #ifdef FIX_1217_OBJECT_EDIT_FILE_INTERFACE static ivas_error decodeG192( DecArguments arg, BS_READER_HANDLE hBsReader, IVAS_DEC_HRTF_BINARY_WRAPPER *hHrtfBinary, RotFileReader *headRotReader, RotFileReader *externalOrientationFileReader, RotFileReader *refRotReader, Vector3PairFileReader *referenceVectorReader, ObjectEditFileReader *objectEditFileReader, ISAR_SPLIT_REND_BITS_DATA *splitRendBits, IVAS_DEC_HANDLE hIvasDec, int16_t *pcmBuf ); +#ifdef FIX_1119_SPLIT_RENDERING_VOIP +static ivas_error decodeVoIP( DecArguments arg, BS_READER_HANDLE hBsReader, IVAS_DEC_HRTF_BINARY_WRAPPER *hHrtf, RotFileReader *headRotReader, RotFileReader *externalOrientationFileReader, RotFileReader *refRotReader, Vector3PairFileReader *referenceVectorReader, ObjectEditFileReader *objectEditFileReader, ISAR_SPLIT_REND_BITS_DATA *splitRendBits, IVAS_DEC_HANDLE hIvasDec, int16_t *pcmBuf ); +#else static ivas_error decodeVoIP( DecArguments arg, BS_READER_HANDLE hBsReader, IVAS_DEC_HRTF_BINARY_WRAPPER *hHrtfBinary, RotFileReader *headRotReader, RotFileReader *externalOrientationFileReader, RotFileReader *refRotReader, Vector3PairFileReader *referenceVectorReader, ObjectEditFileReader *objectEditFileReader, IVAS_DEC_HANDLE hIvasDec, int16_t *pcmBuf ); +#endif #else static ivas_error decodeG192( DecArguments arg, BS_READER_HANDLE hBsReader, IVAS_DEC_HRTF_BINARY_WRAPPER *hHrtfBinary, RotFileReader *headRotReader, RotFileReader *externalOrientationFileReader, RotFileReader *refRotReader, Vector3PairFileReader *referenceVectorReader, ISAR_SPLIT_REND_BITS_DATA *splitRendBits, IVAS_DEC_HANDLE hIvasDec, int16_t *pcmBuf ); static ivas_error decodeVoIP( DecArguments arg, BS_READER_HANDLE hBsReader, IVAS_DEC_HRTF_BINARY_WRAPPER *hHrtfBinary, RotFileReader *headRotReader, RotFileReader *externalOrientationFileReader, RotFileReader *refRotReader, Vector3PairFileReader *referenceVectorReader, IVAS_DEC_HANDLE hIvasDec, int16_t *pcmBuf ); @@ -781,7 +785,11 @@ int main( if ( arg.voipMode ) { #ifdef FIX_1217_OBJECT_EDIT_FILE_INTERFACE +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + error = decodeVoIP( arg, hBsReader, &hHrtfBinary, headRotReader, externalOrientationFileReader, refRotReader, referenceVectorReader, objectEditFileReader, &splitRendBits, hIvasDec, pcmBuf ); +#else error = decodeVoIP( arg, hBsReader, &hHrtfBinary, headRotReader, externalOrientationFileReader, refRotReader, referenceVectorReader, objectEditFileReader, hIvasDec, pcmBuf ); +#endif #else error = decodeVoIP( arg, hBsReader, &hHrtfBinary, headRotReader, externalOrientationFileReader, refRotReader, referenceVectorReader, hIvasDec, pcmBuf ); #endif @@ -2009,7 +2017,11 @@ static ivas_error initOnFirstGoodFrame( for ( int16_t i = 0; i < numInitialBadFrames; ++i ) { +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + if ( isSplitRend ) +#else if ( *splitRendWriter != NULL ) +#endif { ISAR_SPLIT_REND_BITS_DATA splitRendBitsZero; splitRendBitsZero.bits_buf = NULL; @@ -2027,7 +2039,12 @@ static ivas_error initOnFirstGoodFrame( return error; } } + +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + if ( !isSplitCoded ) +#else else +#endif { if ( *pRemainingDelayNumSamples < *numOutSamples ) @@ -2248,6 +2265,14 @@ static ivas_error decodeG192( return error; } +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + if ( !isSplitRend ) + { + /* Ensure split rendering output struct is not used when not outputting to a split rendering output configuration */ + splitRendBits = NULL; + } +#endif + if ( ( error = IVAS_DEC_is_split_rendering_coded_out( hIvasDec, &isSplitCoded ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nError in IVAS_DEC_is_split_rendering_coded_out, code: %d\n", error ); @@ -2579,7 +2604,11 @@ static ivas_error decodeG192( } /* decode transport channels, do TSM and feed to renderer */ +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + if ( ( error = IVAS_DEC_GetSamplesDecoder( hIvasDec, splitRendBits ) ) != IVAS_ERR_OK ) +#else if ( ( error = IVAS_DEC_GetSamplesDecoder( hIvasDec, isSplitRend, splitRendBits ) ) != IVAS_ERR_OK ) +#endif { return error; } @@ -3140,6 +3169,9 @@ static ivas_error decodeVoIP( Vector3PairFileReader *referenceVectorReader, #ifdef FIX_1217_OBJECT_EDIT_FILE_INTERFACE ObjectEditFileReader *objectEditFileReader, +#endif +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + ISAR_SPLIT_REND_BITS_DATA *splitRendBits, #endif IVAS_DEC_HANDLE hIvasDec, int16_t *pcmBuf ) @@ -3190,6 +3222,29 @@ static ivas_error decodeVoIP( bool parametersAvailableForEditing = false; uint16_t nSamplesRendered; +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + SplitFileReadWrite *splitRendWriter = NULL; + int16_t isSplitRend, isSplitCoded; + + if ( ( error = IVAS_DEC_is_split_rendering_enabled( hIvasDec, &isSplitRend ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError in IVAS_DEC_is_split_rendering_enabled, code: %d\n", error ); + return error; + } + + if ( !isSplitRend ) + { + /* Ensure split rendering output struct is not used when not outputting to a split rendering format */ + splitRendBits = NULL; + } + + if ( ( error = IVAS_DEC_is_split_rendering_coded_out( hIvasDec, &isSplitCoded ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError in IVAS_DEC_is_split_rendering_coded_out, code: %d\n", error ); + return error; + } +#endif + vec_pos_update = 0; if ( ( error = IVAS_DEC_GetRenderFramesizeMs( hIvasDec, &systemTimeInc_ms ) ) != IVAS_ERR_OK ) { @@ -3487,6 +3542,22 @@ static ivas_error decodeVoIP( /* decode and get samples */ while ( nSamplesRendered < nOutSamples ) { +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + if ( isSplitRend ) + { +#ifdef SUPPORT_JBM_TRACEFILE + if ( ( error = IVAS_DEC_VoIP_GetSplitBinauralBitstream( hIvasDec, (void *) pcmBuf, splitRendBits, writeJbmTraceFileFrameWrapper, jbmTraceWriter, &bitstreamReadDone, &nSamplesRendered, ¶metersAvailableForEditing, systemTime_ms ) ) != IVAS_ERR_OK ) +#else + if ( ( error = IVAS_DEC_VoIP_GetSplitBinauralBitstream( hIvasDec, (void *) pcmBuf, splitRendBits, &bitstreamReadDone, &nSamplesRendered, ¶metersAvailableForEditing, systemTime_ms ) ) != IVAS_ERR_OK ) +#endif + { + fprintf( stderr, "\nError in IVAS_DEC_VoIP_GetSplitBinauralBitstream: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + } + else + { +#endif #ifdef SUPPORT_JBM_TRACEFILE if ( ( error = IVAS_DEC_VoIP_GetSamples( hIvasDec, nOutSamples, IVAS_DEC_PCM_INT16, (void *) pcmBuf, writeJbmTraceFileFrameWrapper, jbmTraceWriter, &bitstreamReadDone, &nSamplesRendered, ¶metersAvailableForEditing, systemTime_ms ) ) != IVAS_ERR_OK ) #else @@ -3496,6 +3567,9 @@ static ivas_error decodeVoIP( fprintf( stderr, "\nError in IVAS_DEC_VoIP_GetSamples: %s\n", IVAS_DEC_GetErrorMessage( error ) ); goto cleanup; } +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + } +#endif if ( bitstreamReadDone == true ) { @@ -3583,9 +3657,15 @@ static ivas_error decodeVoIP( /* Once good frame decoded, catch up */ if ( decodedGoodFrame ) { +#ifndef FIX_1119_SPLIT_RENDERING_VOIP SplitFileReadWrite *splitRendWriter = NULL; +#endif +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + if ( ( error = initOnFirstGoodFrame( hIvasDec, arg, numInitialBadFrames, &nOutSamples, &vec_pos_len, delayNumSamples_orig, &delayNumSamples, &delayTimeScale, +#else if ( ( error = initOnFirstGoodFrame( hIvasDec, arg, numInitialBadFrames, &nOutSamples, NULL, delayNumSamples_orig, &delayNumSamples, &delayTimeScale, +#endif &bsFormat, &afWriter, &masaWriter, ismWriters, &nOutChannels, &numObj, &splitRendWriter ) ) != IVAS_ERR_OK ) { #ifdef LIB_DEC_REVISION @@ -3603,19 +3683,35 @@ static ivas_error decodeVoIP( /* Write current frame */ if ( decodedGoodFrame ) { - if ( delayNumSamples < nOutSamples ) +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + if ( isSplitRend ) { - if ( ( error = AudioFileWriter_write( afWriter, &pcmBuf[delayNumSamples * nOutChannels], nOutSamples * nOutChannels - ( delayNumSamples * nOutChannels ) ) ) != IVAS_ERR_OK ) + if ( split_rend_write_bitstream_to_file( splitRendWriter, splitRendBits->bits_buf, &splitRendBits->bits_read, &splitRendBits->bits_written ) != IVAS_ERR_OK ) { - fprintf( stderr, "\nOutput audio file writer error\n" ); + fprintf( stderr, "\nUnable to write to bitstream file!\n" ); goto cleanup; } - delayNumSamples = 0; } - else + + if ( !isSplitCoded ) { - delayNumSamples -= nOutSamples; +#endif + if ( delayNumSamples < nOutSamples ) + { + if ( ( error = AudioFileWriter_write( afWriter, &pcmBuf[delayNumSamples * nOutChannels], nOutSamples * nOutChannels - ( delayNumSamples * nOutChannels ) ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nOutput audio file writer error\n" ); + goto cleanup; + } + delayNumSamples = 0; + } + else + { + delayNumSamples -= nOutSamples; + } +#ifdef FIX_1119_SPLIT_RENDERING_VOIP } +#endif /* Write ISM metadata to external file(s) */ if ( decodedGoodFrame && arg.outputConfig == IVAS_AUDIO_CONFIG_EXTERNAL ) @@ -3714,7 +3810,11 @@ static ivas_error decodeVoIP( goto cleanup; } +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + if ( nSamplesFlushed && !isSplitCoded ) +#else if ( nSamplesFlushed ) +#endif { /* Write current frame */ if ( ( error = AudioFileWriter_write( afWriter, pcmBuf, nSamplesFlushed * nOutChannels ) ) != IVAS_ERR_OK ) @@ -3785,11 +3885,19 @@ static ivas_error decodeVoIP( *------------------------------------------------------------------------------------------*/ memset( pcmBuf, 0, delayNumSamples_orig[0] * nOutChannels * sizeof( int16_t ) ); - if ( ( error = AudioFileWriter_write( afWriter, pcmBuf, delayNumSamples_orig[0] * nOutChannels ) ) != IVAS_ERR_OK ) + +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + if ( afWriter != NULL ) { - fprintf( stderr, "\nError writing output file: %s\n", ivas_error_to_string( error ) ); - goto cleanup; +#endif + if ( ( error = AudioFileWriter_write( afWriter, pcmBuf, delayNumSamples_orig[0] * nOutChannels ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError writing output file: %s\n", ivas_error_to_string( error ) ); + goto cleanup; + } +#ifdef FIX_1119_SPLIT_RENDERING_VOIP } +#endif /*------------------------------------------------------------------------------------------* * Printouts after decoding has finished @@ -3834,6 +3942,9 @@ cleanup: EVS_RTPDUMP_DEPACKER_close( &rtpdumpDepacker ); AudioFileWriter_close( &afWriter ); +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + split_rend_reader_writer_close( &splitRendWriter ); +#endif JbmOffsetFileWriter_close( &jbmOffsetWriter ); #ifdef SUPPORT_JBM_TRACEFILE JbmTraceFileWriter_close( &jbmTraceWriter ); diff --git a/apps/isar_post_rend.c b/apps/isar_post_rend.c index f7b3e479f..a2c538e81 100644 --- a/apps/isar_post_rend.c +++ b/apps/isar_post_rend.c @@ -1086,6 +1086,19 @@ int main( fprintf( stderr, "\nISAR_POST_REND_FeedSplitBinauralBitstream failed: %s\n", ivas_error_to_string( error ) ); goto cleanup; } + +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + /* Set BFI if frame is empty */ + int16_t frameEmpty = (int16_t) ( bitsBuffer.config.bitsWritten == 0 ); + if ( frameEmpty ) + { + if ( ( error = ISAR_POST_REND_SetSplitRendBFI( hIsarPostRend, 1 ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "Error in ISAR_POST_REND_SetSplitRendBFI(): %s\n", ivas_error_to_string( error ) ); + goto cleanup; + } + } +#endif } } diff --git a/lib_com/ivas_prot.h b/lib_com/ivas_prot.h index 8e2b32d4d..8a0ef7891 100644 --- a/lib_com/ivas_prot.h +++ b/lib_com/ivas_prot.h @@ -5219,6 +5219,43 @@ void ivas_binaural_add_LFE( float *output_f[] /* o : synthesized core-coder transport channels/DirAC output */ ); +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + +/*---------------------------------------------------------------------------------* + * Multi-pose ring buffer Prototypes +*-----------------------------------------------------------------------------------*/ + +ivas_error ivas_CLDFB_RINGBUF_Open( + ISAR_CLDFB_RINGBUF_HANDLE *ph, + const int16_t capacity_columns +); + +void ivas_CLDFB_RINGBUF_Close( + ISAR_CLDFB_RINGBUF_HANDLE *ph +); + +void ivas_CLDFB_RINGBUF_Push( + ISAR_CLDFB_RINGBUF_HANDLE h, + const float *real, + const float *imag, + const int16_t num_bands +); + +void ivas_CLDFB_RINGBUF_Pop( + ISAR_CLDFB_RINGBUF_HANDLE h, + float *real, + float *imag, + const int16_t num_bands +); + +void ivas_CLDFB_RINGBUF_GetByIdx( + ISAR_CLDFB_RINGBUF_HANDLE h, + float **p_real, + float **p_imag, + const int16_t idx +); + +#endif /*----------------------------------------------------------------------------------* * renderer prototypes diff --git a/lib_com/options.h b/lib_com/options.h index 70ad3bf4a..792a7a38e 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -173,7 +173,8 @@ #define FIX_1053_REVERB_RECONFIGURATION #define FIX_1179_USAN_PHASEECU /* Eri: issue 1179: better handling of 16 bit wrap around for very long(>200ms) FER-bursts */ #define NONBE_1246_INF_COHERENCE_IN_HIGH_LEVEL_DTX /* Ericsson: Issue 1246: High level input which triggers DTX can lead to numerical overflow in coherence calculation */ -#define TMP_FIX_1119_SPLIT_RENDERING_VOIP /* FhG: Add error check for unsupported config: split rendering with VoIP mode */ +#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_1113_EXTREND_ISAR /* FhG: issue 1113: fix external renderer asserts for FOA/HOA2 and CLDFB config */ #define NONBE_1122_KEEP_EVS_MODE_UNCHANGED /* FhG: Disables fix for issue 1122 in EVS mode to keep BE tests green. This switch should be removed once the 1122 fix is added to EVS via a CR. */ #define FIX_938_COMPILER_WARNING /* FhG: Fix compiler warning in ivas_mdct_core_reconstruct() */ diff --git a/lib_dec/ivas_dirac_dec.c b/lib_dec/ivas_dirac_dec.c index 7d1336f45..142cac7e5 100644 --- a/lib_dec/ivas_dirac_dec.c +++ b/lib_dec/ivas_dirac_dec.c @@ -1657,7 +1657,9 @@ static void binRenderer_split( float Cldfb_ImagBuffer_Binaural[][BINAURAL_CHANNELS][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX], /* o : Rotated Binaural signals */ float RealBuffer[][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX], /* i : LS signals */ float ImagBuffer[][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX], /* i : LS signals */ +#ifndef FIX_1119_SPLIT_RENDERING_VOIP const int16_t slot_idx_start, +#endif const int16_t num_freq_bands, const int16_t nchan_out ) { @@ -1687,8 +1689,16 @@ static void binRenderer_split( { for ( ch = 0; ch < nchan_out; ch++ ) { +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + ivas_CLDFB_RINGBUF_Push( + hSplitBinRend->hMultiBinCldfbData[pos_idx * BINAURAL_CHANNELS + ch], + Cldfb_RealBuffer_Binaural_loc[pos_idx][ch][slot_idx], + Cldfb_ImagBuffer_Binaural_loc[pos_idx][ch][slot_idx], + num_freq_bands ); +#else mvr2r( Cldfb_RealBuffer_Binaural_loc[pos_idx][ch][slot_idx], hSplitBinRend->hMultiBinCldfbData->Cldfb_RealBuffer_Binaural[( pos_idx * BINAURAL_CHANNELS ) + ch][slot_idx_start + slot_idx], num_freq_bands ); mvr2r( Cldfb_ImagBuffer_Binaural_loc[pos_idx][ch][slot_idx], hSplitBinRend->hMultiBinCldfbData->Cldfb_ImagBuffer_Binaural[( pos_idx * BINAURAL_CHANNELS ) + ch][slot_idx_start + slot_idx], num_freq_bands ); +#endif } } } @@ -2443,7 +2453,11 @@ void ivas_dirac_dec_render_sf( if ( st_ivas->hDecoderConfig->output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || st_ivas->hDecoderConfig->output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) { binRenderer_split( st_ivas->hBinRenderer, st_ivas->hSplitBinRend, st_ivas->hCombinedOrientationData, hSpatParamRendCom->subframe_nbslots[subframe_idx], - Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, Cldfb_RealBuffer, Cldfb_ImagBuffer, slot_idx_start, hSpatParamRendCom->num_freq_bands, st_ivas->hDecoderConfig->nchan_out ); + Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, Cldfb_RealBuffer, Cldfb_ImagBuffer, +#ifndef FIX_1119_SPLIT_RENDERING_VOIP + slot_idx_start, +#endif + hSpatParamRendCom->num_freq_bands, st_ivas->hDecoderConfig->nchan_out ); } else { diff --git a/lib_dec/ivas_init_dec.c b/lib_dec/ivas_init_dec.c index 697eaa0c5..56baa8a1c 100644 --- a/lib_dec/ivas_init_dec.c +++ b/lib_dec/ivas_init_dec.c @@ -1240,6 +1240,10 @@ ivas_error ivas_init_decoder_front( } } +#ifdef TMP_1342_WORKAROUND_DEC_FLUSH_BROKEN_IN_SR + st_ivas->flushing = 0; +#endif + return error; } diff --git a/lib_dec/ivas_jbm_dec.c b/lib_dec/ivas_jbm_dec.c index a168da91e..100bbc7af 100644 --- a/lib_dec/ivas_jbm_dec.c +++ b/lib_dec/ivas_jbm_dec.c @@ -1487,6 +1487,12 @@ ivas_error ivas_jbm_dec_render( if ( output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) { nchan_out_syn_output = BINAURAL_CHANNELS * st_ivas->hSplitBinRend->splitrend.multiBinPoseData.num_poses; +#ifdef TMP_1342_WORKAROUND_DEC_FLUSH_BROKEN_IN_SR + if ( st_ivas->flushing ) + { + nchan_out_syn_output = BINAURAL_CHANNELS; + } +#endif } else { diff --git a/lib_dec/ivas_mc_param_dec.c b/lib_dec/ivas_mc_param_dec.c index b91dddb1d..27206b048 100644 --- a/lib_dec/ivas_mc_param_dec.c +++ b/lib_dec/ivas_mc_param_dec.c @@ -1827,8 +1827,16 @@ void ivas_param_mc_dec_render( { for ( ch = 0; ch < nchan_out_cldfb; ch++ ) { +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + ivas_CLDFB_RINGBUF_Push( + st_ivas->hSplitBinRend->hMultiBinCldfbData[pos_idx * BINAURAL_CHANNELS + ch], + Cldfb_RealBuffer_Binaural[pos_idx][ch][slot_idx], + Cldfb_ImagBuffer_Binaural[pos_idx][ch][slot_idx], + hParamMC->num_freq_bands ); +#else mvr2r( Cldfb_RealBuffer_Binaural[pos_idx][ch][slot_idx], st_ivas->hSplitBinRend->hMultiBinCldfbData->Cldfb_RealBuffer_Binaural[( pos_idx * BINAURAL_CHANNELS ) + ch][slot_idx_start + slot_idx], hParamMC->num_freq_bands ); mvr2r( Cldfb_ImagBuffer_Binaural[pos_idx][ch][slot_idx], st_ivas->hSplitBinRend->hMultiBinCldfbData->Cldfb_ImagBuffer_Binaural[( pos_idx * BINAURAL_CHANNELS ) + ch][slot_idx_start + slot_idx], hParamMC->num_freq_bands ); +#endif } } } diff --git a/lib_dec/ivas_mc_paramupmix_dec.c b/lib_dec/ivas_mc_paramupmix_dec.c index 2c4aebdcf..b7c677831 100644 --- a/lib_dec/ivas_mc_paramupmix_dec.c +++ b/lib_dec/ivas_mc_paramupmix_dec.c @@ -796,8 +796,16 @@ static void ivas_mc_paramupmix_dec_sf( { for ( ch = 0; ch < st_ivas->hDecoderConfig->nchan_out; ch++ ) { +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + ivas_CLDFB_RINGBUF_Push( + st_ivas->hSplitBinRend->hMultiBinCldfbData[pos_idx * BINAURAL_CHANNELS + ch], + Cldfb_RealBuffer_Binaural[pos_idx][ch][slot_idx], + Cldfb_ImagBuffer_Binaural[pos_idx][ch][slot_idx], + maxBand ); +#else mvr2r( Cldfb_RealBuffer_Binaural[pos_idx][ch][slot_idx], st_ivas->hSplitBinRend->hMultiBinCldfbData->Cldfb_RealBuffer_Binaural[( pos_idx * BINAURAL_CHANNELS ) + ch][slot_index_start + slot_idx], maxBand ); mvr2r( Cldfb_ImagBuffer_Binaural[pos_idx][ch][slot_idx], st_ivas->hSplitBinRend->hMultiBinCldfbData->Cldfb_ImagBuffer_Binaural[( pos_idx * BINAURAL_CHANNELS ) + ch][slot_index_start + slot_idx], maxBand ); +#endif } } } diff --git a/lib_dec/ivas_omasa_dec.c b/lib_dec/ivas_omasa_dec.c index 43f102d12..1b550feee 100644 --- a/lib_dec/ivas_omasa_dec.c +++ b/lib_dec/ivas_omasa_dec.c @@ -748,9 +748,13 @@ ivas_error ivas_omasa_dirac_td_binaural_jbm( float data_separated_objects[BINAURAL_CHANNELS][L_FRAME48k]; ivas_error error; float *p_sepobj[BINAURAL_CHANNELS]; +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + float *re, *im; +#else int16_t slot_idx_start; slot_idx_start = st_ivas->hSpatParamRendCom->slots_rendered; +#endif for ( n = 0; n < BINAURAL_CHANNELS; n++ ) { @@ -791,9 +795,14 @@ ivas_error ivas_omasa_dirac_td_binaural_jbm( { cldfbAnalysis_ts( &( p_rend_obj[n][num_cldfb_bands * slot_idx] ), Cldfb_RealBuffer, Cldfb_ImagBuffer, num_cldfb_bands, st_ivas->hSplitBinRend->splitrend.hCldfbHandles->cldfbAna[n] ); - /* note: this intentionally differs from OSBA by: no scaling by 0.5 */ +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + ivas_CLDFB_RINGBUF_GetByIdx( st_ivas->hSplitBinRend->hMultiBinCldfbData[n], &re, &im, slot_idx - cldfb_slots ); + v_add( re, Cldfb_RealBuffer, re, num_cldfb_bands ); + v_add( im, Cldfb_ImagBuffer, im, num_cldfb_bands ); +#else v_add( st_ivas->hSplitBinRend->hMultiBinCldfbData->Cldfb_RealBuffer_Binaural[n][slot_idx_start + slot_idx], Cldfb_RealBuffer, st_ivas->hSplitBinRend->hMultiBinCldfbData->Cldfb_RealBuffer_Binaural[n][slot_idx_start + slot_idx], num_cldfb_bands ); v_add( st_ivas->hSplitBinRend->hMultiBinCldfbData->Cldfb_ImagBuffer_Binaural[n][slot_idx_start + slot_idx], Cldfb_ImagBuffer, st_ivas->hSplitBinRend->hMultiBinCldfbData->Cldfb_ImagBuffer_Binaural[n][slot_idx_start + slot_idx], num_cldfb_bands ); +#endif } } } diff --git a/lib_dec/ivas_osba_dec.c b/lib_dec/ivas_osba_dec.c index d85777ec7..09a2bd2f4 100644 --- a/lib_dec/ivas_osba_dec.c +++ b/lib_dec/ivas_osba_dec.c @@ -137,9 +137,13 @@ ivas_error ivas_osba_dirac_td_binaural_jbm( float output_separated_objects[BINAURAL_CHANNELS][L_FRAME48k]; float *p_sepobj[BINAURAL_CHANNELS]; int16_t channel_offset; +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + float *re, *im; +#else int16_t slot_idx_start; slot_idx_start = st_ivas->hSpatParamRendCom->slots_rendered; +#endif for ( n = 0; n < BINAURAL_CHANNELS; n++ ) { @@ -158,7 +162,10 @@ ivas_error ivas_osba_dirac_td_binaural_jbm( if ( st_ivas->hDecoderConfig->output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || st_ivas->hDecoderConfig->output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) { - int16_t slot_idx, num_cldfb_bands, b, nchan_transport_orig; + int16_t slot_idx, num_cldfb_bands, nchan_transport_orig; +#ifndef FIX_1119_SPLIT_RENDERING_VOIP + int16_t b; +#endif int16_t cldfb_slots; float Cldfb_RealBuffer[CLDFB_NO_CHANNELS_MAX]; float Cldfb_ImagBuffer[CLDFB_NO_CHANNELS_MAX]; @@ -179,6 +186,11 @@ ivas_error ivas_osba_dirac_td_binaural_jbm( { cldfbAnalysis_ts( &( output_f[n][num_cldfb_bands * slot_idx] ), Cldfb_RealBuffer, Cldfb_ImagBuffer, num_cldfb_bands, st_ivas->hSplitBinRend->splitrend.hCldfbHandles->cldfbAna[n] ); +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + ivas_CLDFB_RINGBUF_GetByIdx( st_ivas->hSplitBinRend->hMultiBinCldfbData[n], &re, &im, slot_idx - cldfb_slots ); + v_add( re, Cldfb_RealBuffer, re, num_cldfb_bands ); + v_add( im, Cldfb_ImagBuffer, im, num_cldfb_bands ); +#else for ( b = 0; b < num_cldfb_bands; b++ ) { st_ivas->hSplitBinRend->hMultiBinCldfbData->Cldfb_RealBuffer_Binaural[n][slot_idx_start + slot_idx][b] = @@ -187,6 +199,7 @@ ivas_error ivas_osba_dirac_td_binaural_jbm( st_ivas->hSplitBinRend->hMultiBinCldfbData->Cldfb_ImagBuffer_Binaural[n][slot_idx_start + slot_idx][b] = st_ivas->hSplitBinRend->hMultiBinCldfbData->Cldfb_ImagBuffer_Binaural[n][slot_idx_start + slot_idx][b] + Cldfb_ImagBuffer[b]; } +#endif } } } diff --git a/lib_dec/ivas_output_config.c b/lib_dec/ivas_output_config.c index 2175ecf08..fa4ff1c7d 100644 --- a/lib_dec/ivas_output_config.c +++ b/lib_dec/ivas_output_config.c @@ -500,11 +500,21 @@ RENDERER_TYPE ivas_renderer_secondary_select( renderer_type = RENDERER_DISABLE; output_config = st_ivas->hDecoderConfig->output_config; - if ( st_ivas->ivas_format == MASA_ISM_FORMAT && st_ivas->ism_mode == ISM_MASA_MODE_DISC && output_config == IVAS_AUDIO_CONFIG_BINAURAL ) + if ( st_ivas->ivas_format == MASA_ISM_FORMAT && st_ivas->ism_mode == ISM_MASA_MODE_DISC && +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + ( output_config == IVAS_AUDIO_CONFIG_BINAURAL || output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) +#else + output_config == IVAS_AUDIO_CONFIG_BINAURAL +#endif + ) { renderer_type = RENDERER_BINAURAL_OBJECTS_TD; } +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + else if ( st_ivas->ivas_format == SBA_ISM_FORMAT && st_ivas->ism_mode == ISM_SBA_MODE_DISC && ( output_config == IVAS_AUDIO_CONFIG_BINAURAL || output_config == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB || output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ) +#else else if ( st_ivas->ivas_format == SBA_ISM_FORMAT && st_ivas->ism_mode == ISM_SBA_MODE_DISC && ( output_config == IVAS_AUDIO_CONFIG_BINAURAL || output_config == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) ) +#endif { renderer_type = RENDERER_BINAURAL_OBJECTS_TD; } diff --git a/lib_dec/ivas_stat_dec.h b/lib_dec/ivas_stat_dec.h index 1d3694d61..dc6efc6e2 100644 --- a/lib_dec/ivas_stat_dec.h +++ b/lib_dec/ivas_stat_dec.h @@ -821,6 +821,7 @@ typedef struct renderer_struct * IVAS decoder specific ISAR wrapper structures *----------------------------------------------------------------------------------*/ +#ifndef FIX_1119_SPLIT_RENDERING_VOIP typedef struct { float Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; @@ -828,18 +829,29 @@ typedef struct } ISAR_DEC_SPLIT_REND_MULTI_BIN_CLDFB_DATA, *ISAR_DEC_SPLIT_REND_MULTI_BIN_CLDFB_DATA_HANDLE; +#endif typedef struct { +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + float Cldfb_RealBuffer[MAX_OUTPUT_CHANNELS][2 * CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; /* Double space to account for TSM */ + float Cldfb_ImagBuffer[MAX_OUTPUT_CHANNELS][2 * CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; +#else float Cldfb_RealBuffer[MAX_OUTPUT_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; float Cldfb_ImagBuffer[MAX_OUTPUT_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; +#endif IVAS_AUDIO_CONFIG config; } ISAR_DEC_SPLIT_REND_CLDFB_OUT_DATA, *ISAR_DEC_SPLIT_REND_CLDFB_OUT_DATA_HANDLE; typedef struct { +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + TD_RINGBUF_HANDLE hMultiBinTdData; + ISAR_CLDFB_RINGBUF_HANDLE hMultiBinCldfbData[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS]; +#else ISAR_DEC_SPLIT_REND_MULTI_BIN_CLDFB_DATA_HANDLE hMultiBinCldfbData; /*scratch buffer for frame by frame processing*/ - ISAR_SPLIT_REND_BITS_HANDLE hSplitRendBits; /*scratch buffer for frame by frame processing*/ +#endif + ISAR_SPLIT_REND_BITS_HANDLE hSplitRendBits; /*scratch buffer for frame by frame processing*/ SPLIT_REND_WRAPPER splitrend; ISAR_DEC_SPLIT_REND_CLDFB_OUT_DATA_HANDLE hCldfbDataOut; /*buffer to store cldfb data before binauralization*/ int16_t numTdSamplesPerChannelCached; @@ -1132,6 +1144,10 @@ typedef struct Decoder_Struct int16_t ism_extmeta_active; /* Extended metadata active in decoder */ int16_t ism_extmeta_cnt; /* Change frame counter for extended metadata */ +#ifdef TMP_1342_WORKAROUND_DEC_FLUSH_BROKEN_IN_SR + int16_t flushing; +#endif + } Decoder_Struct; /* clang-format on */ diff --git a/lib_dec/lib_dec.c b/lib_dec/lib_dec.c index c6db4c74b..c1bf34e15 100644 --- a/lib_dec/lib_dec.c +++ b/lib_dec/lib_dec.c @@ -130,7 +130,11 @@ static ivas_error evs_dec_main( Decoder_Struct *st_ivas, const int16_t nOutSampl static ivas_error input_format_API_to_internal( IVAS_DEC_INPUT_FORMAT input_format, int16_t *bitstream_format_internal, int16_t *sdp_hf_only, const bool is_voip_enabled ); static void init_decoder_config( DECODER_CONFIG_HANDLE hDecoderConfig ); #ifdef LIB_DEC_REVISION +#ifdef FIX_1119_SPLIT_RENDERING_VOIP +static ivas_error ivas_dec_setup_all( IVAS_DEC_HANDLE hIvasDec, uint8_t *nTransportChannels, ISAR_SPLIT_REND_BITS_DATA *splitRendBits ); +#else static ivas_error ivas_dec_setup_all( IVAS_DEC_HANDLE hIvasDec, uint8_t *nTransportChannels, const int16_t isSplitRend, ISAR_SPLIT_REND_BITS_DATA *splitRendBits ); +#endif static ivas_error apa_setup( IVAS_DEC_HANDLE hIvasDec, const bool isInitialized_voip, const uint16_t nTransportChannels ); #else static ivas_error IVAS_DEC_VoIP_reconfigure( IVAS_DEC_HANDLE hIvasDec, const uint16_t nTransportChannels, const uint16_t l_ts ); @@ -149,6 +153,10 @@ static ivas_error ivas_dec_reconfig_split_rend( Decoder_Struct *st_ivas ); static ivas_error ivas_dec_init_split_rend( Decoder_Struct *st_ivas ); static void ivas_destroy_handle_isar( ISAR_DEC_SPLIT_REND_WRAPPER_HANDLE *hSplitBinRend_out ); static int16_t get_render_frame_size_ms( IVAS_RENDER_FRAMESIZE render_framesize ); +#ifdef FIX_1119_SPLIT_RENDERING_VOIP +static int16_t get_render_frame_size_samples( const DECODER_CONFIG_HANDLE hDecoderConfig ); +static int16_t ivas_dec_split_rend_cldfb_in( const RENDERER_TYPE renderer_type ); +#endif static void update_voip_rendered20ms( IVAS_DEC_HANDLE hIvasDec, const int16_t nSamplesRendered ); /*---------------------------------------------------------------------* @@ -694,6 +702,23 @@ ivas_error IVAS_DEC_GetRenderFramesize( return IVAS_ERR_OK; } + +#ifdef FIX_1119_SPLIT_RENDERING_VOIP +/*---------------------------------------------------------------------* + * get_render_frame_size_samples( ) + * + * + *---------------------------------------------------------------------*/ + +static int16_t get_render_frame_size_samples( + const DECODER_CONFIG_HANDLE hDecoderConfig /* i : configuration structure */ +) +{ + return (int16_t) ( hDecoderConfig->output_Fs * hDecoderConfig->render_framesize / ( FRAMES_PER_SEC * IVAS_MAX_PARAM_SPATIAL_SUBFRAMES ) ); +} +#endif + + /*---------------------------------------------------------------------* * IVAS_DEC_GetGetRenderFramesizeSamples( ) * @@ -710,7 +735,11 @@ ivas_error IVAS_DEC_GetRenderFramesizeSamples( return IVAS_ERR_UNEXPECTED_NULL_POINTER; } +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + *render_framesize = get_render_frame_size_samples( hIvasDec->st_ivas->hDecoderConfig ); +#else *render_framesize = (int16_t) ( hIvasDec->st_ivas->hDecoderConfig->output_Fs * hIvasDec->st_ivas->hDecoderConfig->render_framesize / ( FRAMES_PER_SEC * IVAS_MAX_PARAM_SPATIAL_SUBFRAMES ) ); +#endif return IVAS_ERR_OK; } @@ -1218,8 +1247,10 @@ ivas_error IVAS_DEC_ReadFormat( *---------------------------------------------------------------------*/ ivas_error IVAS_DEC_GetSamplesDecoder( - IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ - const int16_t isSplitRend, /* i : split rendering enabled flag */ + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ +#ifndef FIX_1119_SPLIT_RENDERING_VOIP + const int16_t isSplitRend, /* i : split rendering enabled flag */ +#endif ISAR_SPLIT_REND_BITS_DATA *splitRendBits /* o : output split rendering bits */ ) { @@ -1256,7 +1287,11 @@ ivas_error IVAS_DEC_GetSamplesDecoder( * Setup all decoder parts (IVAS decoder, ISAR) *-----------------------------------------------------------------*/ +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + if ( ( error = ivas_dec_setup_all( hIvasDec, &nTransportChannels, splitRendBits ) ) != IVAS_ERR_OK ) +#else if ( ( error = ivas_dec_setup_all( hIvasDec, &nTransportChannels, isSplitRend, splitRendBits ) ) != IVAS_ERR_OK ) +#endif { return error; } @@ -1893,6 +1928,198 @@ ivas_error IVAS_DEC_PrepareRenderer( return IVAS_ERR_OK; } +#ifdef FIX_1119_SPLIT_RENDERING_VOIP +/*---------------------------------------------------------------------* + * isar_get_frame_size( ) + * + * + *---------------------------------------------------------------------*/ + +static int16_t isar_get_frame_size( + Decoder_Struct *st_ivas /* i : IVAS decoder handle */ +) +{ + int32_t output_Fs; + int16_t nSamplesPerChannel; + + output_Fs = st_ivas->hDecoderConfig->output_Fs; + + if ( st_ivas->hDecoderConfig->render_framesize != IVAS_RENDER_FRAMESIZE_20MS && + ( st_ivas->hRenderConfig->split_rend_config.poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE || + st_ivas->hRenderConfig->split_rend_config.dof == 0 ) ) + { + nSamplesPerChannel = (int16_t) ( output_Fs / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES ); + nSamplesPerChannel *= (int16_t) st_ivas->hDecoderConfig->render_framesize; + } + else + { + nSamplesPerChannel = (int16_t) ( output_Fs / FRAMES_PER_SEC ); + } + + return nSamplesPerChannel; +} + + +/*---------------------------------------------------------------------* + * isar_render_poses( ) + * + * + *---------------------------------------------------------------------*/ + +static ivas_error isar_render_poses( + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + const int16_t nSamplesAsked, /* i : number of samples wanted by the caller */ + int16_t *nOutSamples, /* o : number of samples per channel written to output buffer */ + bool *needNewFrame /* o : indication that the decoder needs a new frame */ +) +{ + float pcmBuf[BINAURAL_CHANNELS * MAX_HEAD_ROT_POSES * L_FRAME48k]; + Decoder_Struct *st_ivas; + ivas_error error; + int16_t numPoses; + + if ( hIvasDec == NULL || hIvasDec->st_ivas == NULL ) + { + return IVAS_ERR_UNEXPECTED_NULL_POINTER; + } + + *needNewFrame = false; + + st_ivas = hIvasDec->st_ivas; + + numPoses = st_ivas->hSplitBinRend->splitrend.multiBinPoseData.num_poses; + + /* init flush buffer for rate switch if not already initizalized */ + if ( hIvasDec->flushbuffer == NULL ) + { + hIvasDec->flushbuffer = (void *) malloc( numPoses * BINAURAL_CHANNELS * hIvasDec->nSamplesFrame / IVAS_MAX_PARAM_SPATIAL_SUBFRAMES * sizeof( float ) ); + if ( hIvasDec->flushbuffer == NULL ) + { + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Could not allocate flush buffer" ); + } + hIvasDec->pcmType = IVAS_DEC_PCM_FLOAT; + set_zero( (float *) hIvasDec->flushbuffer, numPoses * BINAURAL_CHANNELS * hIvasDec->nSamplesFrame / IVAS_MAX_PARAM_SPATIAL_SUBFRAMES ); + } + + /* render */ + if ( ( error = IVAS_DEC_GetSamplesRenderer( hIvasDec, nSamplesAsked, IVAS_DEC_PCM_FLOAT, pcmBuf, nOutSamples, needNewFrame ) ) != IVAS_ERR_OK ) + { + return error; + } + + if ( !hIvasDec->hasBeenFedFirstGoodFrame ) + { + return IVAS_ERR_OK; + } + + if ( !ivas_dec_split_rend_cldfb_in( st_ivas->renderer_type ) ) + { + ivas_TD_RINGBUF_PushInterleaved( st_ivas->hSplitBinRend->hMultiBinTdData, pcmBuf, *nOutSamples ); + } + + return error; +} + + +/*---------------------------------------------------------------------* + * isar_generate_metadata_and_bitstream( ) + * + * + *---------------------------------------------------------------------*/ + +static ivas_error isar_generate_metadata_and_bitstream( + Decoder_Struct *st_ivas, /* i/o: IVAS decoder handle */ + float **p_head_pose_buf, /* i/o: PCM buffer with head-pose data */ + int16_t nSamples, /* i : duration of audio (in samples per channel) for which metadata should be generated */ + ISAR_SPLIT_REND_BITS_DATA *splitRendBits /* o : output split rendering bits */ +) +{ + ivas_error error; + ISAR_DEC_SPLIT_REND_WRAPPER_HANDLE hSplitBinRend; + int16_t max_band; + int16_t pcm_out_flag; + int16_t cldfb_in_flag; + int16_t ro_md_flag; + IVAS_QUATERNION Quaternion; + int16_t i, j, num_poses, num_cldfb_slots, n_samples_in_cldfb_slot; + float *p_Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX]; + float *p_Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX]; + + hSplitBinRend = st_ivas->hSplitBinRend; + + max_band = (int16_t) ( ( BINAURAL_MAXBANDS * st_ivas->hDecoderConfig->output_Fs ) / 48000 ); + pcm_out_flag = ( st_ivas->hDecoderConfig->output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ? 1 : 0; + cldfb_in_flag = ivas_dec_split_rend_cldfb_in( st_ivas->renderer_type ); + + if ( cldfb_in_flag ) + { + n_samples_in_cldfb_slot = NS2SA( st_ivas->hDecoderConfig->output_Fs, CLDFB_SLOT_NS ); + assert( nSamples % n_samples_in_cldfb_slot == 0 ); + num_cldfb_slots = nSamples / n_samples_in_cldfb_slot; + + num_poses = hSplitBinRend->splitrend.multiBinPoseData.num_poses; + + for ( i = 0; i < BINAURAL_CHANNELS * num_poses; ++i ) + { + for ( j = 0; j < num_cldfb_slots; ++j ) + { + /* Save pointers to first CLDFB column in the ring buffer. Allows us to save + * significant amounts of memory by not copying CLDFB values into a separate buffer. */ + ivas_CLDFB_RINGBUF_GetByIdx( hSplitBinRend->hMultiBinCldfbData[i], &p_Cldfb_RealBuffer_Binaural[i][j], &p_Cldfb_ImagBuffer_Binaural[i][j], 0 ); + + /* Pop the CLDFB column we just saved pointers to. This is fine as long as we use + * the saved columns only before any new columns are pushed to the buffer - the new + * columns could potentially overwrite the old columns we wanted to use. + * This requirement is fulfilled in this case. */ + ivas_CLDFB_RINGBUF_Pop( hSplitBinRend->hMultiBinCldfbData[i], NULL, NULL, CLDFB_NO_CHANNELS_MAX ); + } + } + } + else + { + ivas_TD_RINGBUF_PopChannels( st_ivas->hSplitBinRend->hMultiBinTdData, p_head_pose_buf, nSamples ); + } + + + if ( st_ivas->hBinRendererTd != NULL ) + { + ro_md_flag = 1; + } + else + { + ro_md_flag = 0; + } + + if ( st_ivas->hHeadTrackData != NULL ) + { + Quaternion = st_ivas->hHeadTrackData->Quaternions[0]; + } + else + { + Quaternion.w = -3.0f; + Quaternion.x = 0.0f; + Quaternion.y = 0.0f; + Quaternion.z = 0.0f; + } + + if ( ( error = ISAR_PRE_REND_MultiBinToSplitBinaural( &hSplitBinRend->splitrend, + Quaternion, + st_ivas->hRenderConfig->split_rend_config.splitRendBitRate, + st_ivas->hRenderConfig->split_rend_config.codec, + st_ivas->hRenderConfig->split_rend_config.isar_frame_size_ms, + st_ivas->hRenderConfig->split_rend_config.codec_frame_size_ms, + splitRendBits, + p_Cldfb_RealBuffer_Binaural, + p_Cldfb_ImagBuffer_Binaural, + max_band, p_head_pose_buf, 1, cldfb_in_flag, pcm_out_flag, ro_md_flag ) ) != IVAS_ERR_OK ) + { + return error; + } + + return IVAS_ERR_OK; +} +#endif /* FIX_1119_SPLIT_RENDERING_VOIP */ + /*---------------------------------------------------------------------* * IVAS_DEC_GetSamplesRenderer( ) @@ -2104,6 +2331,70 @@ ivas_error IVAS_DEC_GetSplitBinauralBitstream( bool *needNewFrame /* o : indication that the decoder needs a new frame */ ) { +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + Decoder_Struct *st_ivas; + ivas_error error; + float head_pose_buf[BINAURAL_CHANNELS * MAX_HEAD_ROT_POSES][L_FRAME48k]; + float *p_head_pose_buf[BINAURAL_CHANNELS * MAX_HEAD_ROT_POSES]; + int16_t i; + int16_t pcm_out_flag; + int16_t numSamplesPerChannelToOutput; + + if ( hIvasDec == NULL || hIvasDec->st_ivas == NULL ) + { + return IVAS_ERR_UNEXPECTED_NULL_POINTER; + } + + st_ivas = hIvasDec->st_ivas; + + if ( is_split_rendering_enabled( st_ivas->hDecoderConfig, st_ivas->hRenderConfig ) == 0 ) + { + return IVAS_ERR_WRONG_PARAMS; + } + + pcm_out_flag = ( st_ivas->hDecoderConfig->output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ? 1 : 0; + numSamplesPerChannelToOutput = isar_get_frame_size( st_ivas ); + + if ( ( error = isar_render_poses( hIvasDec, numSamplesPerChannelToOutput, nOutSamples, needNewFrame ) ) != IVAS_ERR_OK ) + { + return error; + } + + if ( !hIvasDec->hasBeenFedFirstGoodFrame ) + { + return IVAS_ERR_OK; + } + + for ( i = 0; i < BINAURAL_CHANNELS * MAX_HEAD_ROT_POSES; ++i ) + { + p_head_pose_buf[i] = head_pose_buf[i]; + } + + if ( ( error = isar_generate_metadata_and_bitstream( st_ivas, p_head_pose_buf, *nOutSamples, splitRendBits ) ) != IVAS_ERR_OK ) + { + return error; + } + + /* convert to int16 with limiting for BINAURAL_SPLIT_PCM */ + if ( pcm_out_flag ) + { + if ( st_ivas->hDecoderConfig->render_framesize == IVAS_RENDER_FRAMESIZE_5MS ) + { +#ifndef DISABLE_LIMITER + ivas_limiter_dec( st_ivas->hLimiter, p_head_pose_buf, st_ivas->hDecoderConfig->nchan_out, numSamplesPerChannelToOutput, st_ivas->BER_detect ); +#endif + } + else + { + ivas_limiter_dec( st_ivas->hLimiter, p_head_pose_buf, st_ivas->hDecoderConfig->nchan_out, numSamplesPerChannelToOutput, st_ivas->BER_detect ); + } + +#ifdef DEBUGGING + st_ivas->noClipping += +#endif + ivas_syn_output( p_head_pose_buf, numSamplesPerChannelToOutput, st_ivas->hDecoderConfig->nchan_out, (int16_t *) pcmBuf_out ); + } +#else Decoder_Struct *st_ivas; AUDIO_CONFIG output_config; int32_t output_Fs; @@ -2296,7 +2587,9 @@ ivas_error IVAS_DEC_GetSplitBinauralBitstream( #ifndef TMP_FIX_SPLIT_REND free( st_ivas->hSplitBinRend->hMultiBinCldfbData ); #endif - return error; +#endif + + return IVAS_ERR_OK; } @@ -2308,9 +2601,11 @@ ivas_error IVAS_DEC_GetSplitBinauralBitstream( *---------------------------------------------------------------------*/ static ivas_error ivas_dec_setup_all( - IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ - uint8_t *nTransportChannels, /* o : number of decoded transport PCM channels */ - const int16_t isSplitRend, /* i : split rendering enabled flag */ + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + uint8_t *nTransportChannels, /* o : number of decoded transport PCM channels */ +#ifndef FIX_1119_SPLIT_RENDERING_VOIP + const int16_t isSplitRend, /* i : split rendering enabled flag */ +#endif ISAR_SPLIT_REND_BITS_DATA *splitRendBits /* o : output split rendering bits */ ) #else @@ -2348,7 +2643,11 @@ static ivas_error IVAS_DEC_Setup( #ifdef LIB_DEC_REVISION /* Setup IVAS split rendering */ +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + if ( splitRendBits != NULL ) +#else if ( isSplitRend ) +#endif { if ( ( error = isar_set_split_rend_setup( st_ivas->hSplitBinRend, &st_ivas->hRenderConfig->split_rend_config, st_ivas->hCombinedOrientationData, splitRendBits ) ) != IVAS_ERR_OK ) { @@ -2385,7 +2684,11 @@ static ivas_error IVAS_DEC_Setup( *-----------------------------------------------------------------*/ #ifdef LIB_DEC_REVISION +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + if ( st_ivas->ini_frame == 0 && splitRendBits != NULL ) +#else if ( st_ivas->ini_frame == 0 && isSplitRend ) +#endif #else if ( st_ivas->ini_frame == 0 && ( is_split_rendering_enabled( st_ivas->hDecoderConfig, st_ivas->hRenderConfig ) ) ) #endif @@ -3910,20 +4213,38 @@ ivas_error IVAS_DEC_TSM_SetQuality( #endif +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + +/*---------------------------------------------------------------------* + * ivas_dec_voip_get_samples_common( ) + * + * Main function to output one frame in VoIP. Holds common code for + * regular output configs and split rendering configs. + *---------------------------------------------------------------------*/ + +static ivas_error ivas_dec_voip_get_samples_common + +#else /*---------------------------------------------------------------------* * IVAS_DEC_VoIP_GetSamples( ) * * Main function to decode one frame in VoIP *---------------------------------------------------------------------*/ -ivas_error IVAS_DEC_VoIP_GetSamples( - IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ - uint16_t nSamplesPerChannel, /* i : number of samples per channel requested to be written to output buffer */ - const IVAS_DEC_PCM_TYPE pcmType, - void *pcmBuf, +ivas_error IVAS_DEC_VoIP_GetSamples +#endif + ( + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + uint16_t nSamplesPerChannel, /* i : number of samples per channel requested to be written to output buffer */ + const IVAS_DEC_PCM_TYPE pcmType, /* i : type for the decoded PCM resolution */ + void *pcmBuf, /* o : output synthesis signal */ +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + ISAR_SPLIT_REND_BITS_DATA *splitRendBits, /* o : output split rendering bits */ + float **p_head_pose_buf, /* i : PCM buffer with head-pose data */ +#endif #ifdef SUPPORT_JBM_TRACEFILE - JbmTraceFileWriterFn jbmWriterFn, - void *jbmWriter, + JbmTraceFileWriterFn jbmWriterFn, + void *jbmWriter, #endif bool *bitstreamReadDone, /* o : flag indicating that bitstream was read */ uint16_t *nSamplesRendered, /* o : number of samples rendered */ @@ -3957,12 +4278,20 @@ ivas_error IVAS_DEC_VoIP_GetSamples( return IVAS_ERR_WRONG_PARAMS; } -#ifdef TMP_FIX_1119_SPLIT_RENDERING_VOIP +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + if ( ( hDecoderConfig->output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM || + hDecoderConfig->output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) && + splitRendBits == NULL ) + { + return IVAS_ERR_UNEXPECTED_NULL_POINTER; + } +#else if ( hDecoderConfig->output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM || hDecoderConfig->output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) { return IVAS_ERROR( IVAS_ERR_NOT_IMPLEMENTED, "Split rendering is not integrated with VoIP mode" ); } + #endif /* make sure that the FIFO after decoder/scaler contains at least one sound card frame (i.e. 20ms) */ @@ -4133,7 +4462,12 @@ ivas_error IVAS_DEC_VoIP_GetSamples( #ifndef LIB_DEC_REVISION uint16_t nSamplesFlushed_ref = hIvasDec->nSamplesFlushed; #endif + +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + if ( ( error = IVAS_DEC_GetSamplesDecoder( hIvasDec, splitRendBits ) ) != IVAS_ERR_OK ) +#else if ( ( error = IVAS_DEC_GetSamplesDecoder( hIvasDec, 0, 0 ) ) != IVAS_ERR_OK ) +#endif { return error; } @@ -4160,24 +4494,169 @@ ivas_error IVAS_DEC_VoIP_GetSamples( } } - /* render IVAS frames directly to the output buffer */ +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + if ( splitRendBits != NULL ) + { + /* Render head poses from time-scaled transport channels */ + if ( ( error = isar_render_poses( hIvasDec, nSamplesToRender, &nSamplesRendered_loop, &tmp ) ) != IVAS_ERR_OK ) + { + return error; + } + } + else + { +#endif + /* render IVAS frames directly to the output buffer */ #ifdef LIB_DEC_REVISION - if ( ( error = IVAS_DEC_GetSamplesRenderer( hIvasDec, nSamplesToRender, pcmType, pcm_buffer_offset( pcmBuf, pcmType, *nSamplesRendered * nOutChannels ), &nSamplesRendered_loop, &tmp ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_DEC_GetSamplesRenderer( hIvasDec, nSamplesToRender, pcmType, pcm_buffer_offset( pcmBuf, pcmType, *nSamplesRendered * nOutChannels ), &nSamplesRendered_loop, &tmp ) ) != IVAS_ERR_OK ) #else - if ( ( error = IVAS_DEC_GetSamples( hIvasDec, nSamplesToRender, pcmType, pcm_buffer_offset( pcmBuf, pcmType, *nSamplesRendered * nOutChannels ), &nSamplesRendered_loop, &tmp ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_DEC_GetSamples( hIvasDec, nSamplesToRender, pcmType, pcm_buffer_offset( pcmBuf, pcmType, *nSamplesRendered * nOutChannels ), &nSamplesRendered_loop, &tmp ) ) != IVAS_ERR_OK ) #endif - { - return error; + { + return error; + } +#ifdef FIX_1119_SPLIT_RENDERING_VOIP } +#endif *nSamplesRendered += nSamplesRendered_loop; update_voip_rendered20ms( hIvasDec, nSamplesRendered_loop ); } } +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + if ( hIvasDec->hasDecodedFirstGoodFrame && splitRendBits != NULL ) + { + /* Analyse head poses over entire frame, generate ISAR metadata and maybe encode if split coded */ + if ( ( error = isar_generate_metadata_and_bitstream( st_ivas, p_head_pose_buf, *nSamplesRendered, splitRendBits ) ) != IVAS_ERR_OK ) + { + return error; + } + + /* Synthesise PCM output if split PCM */ + if ( st_ivas->hDecoderConfig->output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) + { + if ( st_ivas->hDecoderConfig->render_framesize == IVAS_RENDER_FRAMESIZE_5MS ) + { +#ifndef DISABLE_LIMITER + ivas_limiter_dec( st_ivas->hLimiter, p_head_pose_buf, st_ivas->hDecoderConfig->nchan_out, *nSamplesRendered, st_ivas->BER_detect ); +#endif + } + else + { + ivas_limiter_dec( st_ivas->hLimiter, p_head_pose_buf, st_ivas->hDecoderConfig->nchan_out, *nSamplesRendered, st_ivas->BER_detect ); + } + +#ifdef DEBUGGING + st_ivas->noClipping += +#endif + ivas_syn_output( p_head_pose_buf, *nSamplesRendered, st_ivas->hDecoderConfig->nchan_out, (int16_t *) pcmBuf ); + } + } +#endif + return IVAS_ERR_OK; } +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + +/*---------------------------------------------------------------------* + * IVAS_DEC_VoIP_GetSamples( ) + * + * Main function to decode one frame in VoIP + *---------------------------------------------------------------------*/ + +ivas_error IVAS_DEC_VoIP_GetSamples( + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + uint16_t nSamplesPerChannel, /* i : number of samples per channel requested to be written to output buffer */ + const IVAS_DEC_PCM_TYPE pcmType, /* i : type for the decoded PCM resolution */ + void *pcmBuf, /* o : output synthesis signal */ +#ifdef SUPPORT_JBM_TRACEFILE + JbmTraceFileWriterFn jbmWriterFn, + void *jbmWriter, +#endif + bool *bitstreamReadDone, /* o : flag indicating that bitstream was read */ + uint16_t *nSamplesRendered, /* o : number of samples rendered */ + bool *parametersAvailableForEditing, /* o : indicates whether objects editing is available */ + const uint32_t systemTimestamp_ms /* i : current system timestamp */ +) +{ + return ivas_dec_voip_get_samples_common( + hIvasDec, + nSamplesPerChannel, + pcmType, + pcmBuf, + NULL, + NULL, +#ifdef SUPPORT_JBM_TRACEFILE + jbmWriterFn, + jbmWriter, +#endif + bitstreamReadDone, + nSamplesRendered, + parametersAvailableForEditing, + systemTimestamp_ms ); +} + + +/*---------------------------------------------------------------------* + * IVAS_DEC_VoIP_GetSplitBinauralBitstream( ) + * + * Main function to decode one split-rendering frame in VoIP + *---------------------------------------------------------------------*/ + +/*! r: error code */ +ivas_error IVAS_DEC_VoIP_GetSplitBinauralBitstream( + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + /* const IVAS_DEC_PCM_TYPE pcmType, */ /* i : type for the decoded PCM resolution */ + void *pcmBuf, /* o : output synthesis signal */ + ISAR_SPLIT_REND_BITS_DATA *splitRendBits, /* o : output split rendering bits */ +#ifdef SUPPORT_JBM_TRACEFILE + JbmTraceFileWriterFn jbmWriterFn, + void *jbmWriter, +#endif + bool *bitstreamReadDone, /* o : flag indicating that bitstream was read */ + uint16_t *nSamplesRendered, /* o : number of samples rendered */ + bool *parametersAvailableForEditing, /* o : indicates whether objects editing is available */ + const uint32_t systemTimestamp_ms /* i : current system timestamp */ +) +{ + int16_t i; + float head_pose_buf[BINAURAL_CHANNELS * MAX_HEAD_ROT_POSES][L_FRAME48k]; + float *pp_head_pose_buf[BINAURAL_CHANNELS * MAX_HEAD_ROT_POSES]; + ivas_error error = IVAS_ERR_UNKNOWN; + int16_t nSamplesPerChannel = 0; + + if ( ( error = IVAS_DEC_GetRenderFramesizeSamples( hIvasDec, &nSamplesPerChannel ) ) != IVAS_ERR_OK ) + { + return error; + } + + /* Set pointers to beginning of head pose buffers */ + for ( i = 0; i < BINAURAL_CHANNELS * MAX_HEAD_ROT_POSES; ++i ) + { + pp_head_pose_buf[i] = head_pose_buf[i]; + } + + return ivas_dec_voip_get_samples_common( + hIvasDec, + nSamplesPerChannel, + IVAS_DEC_PCM_INT16, + pcmBuf, + splitRendBits, + pp_head_pose_buf, +#ifdef SUPPORT_JBM_TRACEFILE + jbmWriterFn, + jbmWriter, +#endif + bitstreamReadDone, + nSamplesRendered, + parametersAvailableForEditing, + systemTimestamp_ms ); +} +#endif + + /*---------------------------------------------------------------------* * update_voip_rendered20ms( ) * @@ -4236,6 +4715,10 @@ ivas_error IVAS_DEC_Flush( return IVAS_ERR_UNEXPECTED_NULL_POINTER; } +#ifdef TMP_1342_WORKAROUND_DEC_FLUSH_BROKEN_IN_SR + hIvasDec->st_ivas->flushing = 1; +#endif + *nSamplesFlushed = min( nSamplesPerChannel, hIvasDec->nSamplesAvailableNext ); nSamplesToRender = (uint16_t) *nSamplesFlushed; @@ -4255,6 +4738,10 @@ ivas_error IVAS_DEC_Flush( *nSamplesFlushed = 0; } +#ifdef TMP_1342_WORKAROUND_DEC_FLUSH_BROKEN_IN_SR + hIvasDec->st_ivas->flushing = 0; +#endif + return error; } @@ -5359,6 +5846,9 @@ static ivas_error ivas_create_handle_isar( ) { ISAR_DEC_SPLIT_REND_WRAPPER_HANDLE hSplitBinRend; +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + int16_t i; +#endif if ( ( hSplitBinRend = (ISAR_DEC_SPLIT_REND_WRAPPER_HANDLE) malloc( sizeof( ISAR_DEC_SPLIT_REND_WRAPPER ) ) ) == NULL ) { @@ -5367,7 +5857,15 @@ static ivas_error ivas_create_handle_isar( isar_init_split_rend_handles( &hSplitBinRend->splitrend ); +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + hSplitBinRend->hMultiBinTdData = NULL; + for ( i = 0; i < MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS; ++i ) + { + hSplitBinRend->hMultiBinCldfbData[i] = NULL; + } +#else hSplitBinRend->hMultiBinCldfbData = NULL; +#endif hSplitBinRend->hCldfbDataOut = NULL; hSplitBinRend->numTdSamplesPerChannelCached = 0; @@ -5387,13 +5885,31 @@ static void ivas_destroy_handle_isar( ISAR_DEC_SPLIT_REND_WRAPPER_HANDLE *hSplitBinRend /* i/o: ISAR split binaural rendering handle */ ) { +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + int16_t i; +#endif + if ( *hSplitBinRend != NULL ) { +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + if ( ( *hSplitBinRend )->hMultiBinTdData != NULL ) + { + ivas_TD_RINGBUF_Close( &( *hSplitBinRend )->hMultiBinTdData ); + } + for ( i = 0; i < MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS; ++i ) + { + if ( ( *hSplitBinRend )->hMultiBinCldfbData[i] != NULL ) + { + ivas_CLDFB_RINGBUF_Close( &( *hSplitBinRend )->hMultiBinCldfbData[i] ); + } + } +#else #ifdef TMP_FIX_SPLIT_REND free( ( *hSplitBinRend )->hMultiBinCldfbData ); ( *hSplitBinRend )->hMultiBinCldfbData = NULL; - #endif +#endif + ISAR_PRE_REND_close( &( *hSplitBinRend )->splitrend, NULL ); if ( ( *hSplitBinRend )->hCldfbDataOut != NULL ) @@ -5566,6 +6082,32 @@ static ivas_error ivas_dec_reconfig_split_rend( } +#ifdef FIX_1119_SPLIT_RENDERING_VOIP +/*-------------------------------------------------------------------* + * ivas_dec_split_rend_cldfb_in() + * + * + *-------------------------------------------------------------------*/ + +static int16_t ivas_dec_split_rend_cldfb_in( + const RENDERER_TYPE renderer_type /* i : renderer type */ +) +{ + if ( renderer_type == RENDERER_BINAURAL_FASTCONV || + renderer_type == RENDERER_BINAURAL_FASTCONV_ROOM || + renderer_type == RENDERER_BINAURAL_PARAMETRIC || + renderer_type == RENDERER_BINAURAL_PARAMETRIC_ROOM ) + { + return 1; + } + else + { + return 0; + } +} +#endif + + /*-------------------------------------------------------------------* * ivas_dec_init_split_rend() * @@ -5579,10 +6121,16 @@ static ivas_error ivas_dec_init_split_rend( ivas_error error; int16_t cldfb_in_flag, pcm_out_flag; int16_t mixed_td_cldfb_flag; +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + int16_t i, num_poses; +#endif pcm_out_flag = ( st_ivas->hDecoderConfig->output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ? 1 : 0; cldfb_in_flag = 0; +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + cldfb_in_flag = ivas_dec_split_rend_cldfb_in( st_ivas->renderer_type ); +#else if ( st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV || st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV_ROOM || st_ivas->renderer_type == RENDERER_BINAURAL_PARAMETRIC || @@ -5590,7 +6138,33 @@ static ivas_error ivas_dec_init_split_rend( { cldfb_in_flag = 1; } +#endif + +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + ISAR_PRE_REND_GetMultiBinPoseData( &st_ivas->hRenderConfig->split_rend_config, &st_ivas->hSplitBinRend->splitrend.multiBinPoseData, ( st_ivas->hHeadTrackData != NULL ) ? st_ivas->hHeadTrackData->sr_pose_pred_axis : DEFAULT_AXIS ); + num_poses = st_ivas->hSplitBinRend->splitrend.multiBinPoseData.num_poses; + assert( num_poses <= MAX_HEAD_ROT_POSES ); + + if ( cldfb_in_flag ) + { + for ( i = 0; i < num_poses * BINAURAL_CHANNELS; ++i ) + { + /* note: this is intra-frame heap memory */ + if ( ( error = ivas_CLDFB_RINGBUF_Open( &st_ivas->hSplitBinRend->hMultiBinCldfbData[i], CLDFB_NO_COL_MAX ) ) != IVAS_ERR_OK ) + { + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for split rendering structure" ); + } + } + } + else + { + if ( ( error = ivas_TD_RINGBUF_Open( &st_ivas->hSplitBinRend->hMultiBinTdData, get_render_frame_size_samples( st_ivas->hDecoderConfig ), num_poses * BINAURAL_CHANNELS ) ) != IVAS_ERR_OK ) + { + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for split rendering structure" ); + } + } +#else #ifdef TMP_FIX_SPLIT_REND /* note: this is intra-frame heap memory */ if ( ( st_ivas->hSplitBinRend->hMultiBinCldfbData = (ISAR_DEC_SPLIT_REND_MULTI_BIN_CLDFB_DATA_HANDLE) malloc( sizeof( ISAR_DEC_SPLIT_REND_MULTI_BIN_CLDFB_DATA ) ) ) == NULL ) @@ -5600,6 +6174,7 @@ static ivas_error ivas_dec_init_split_rend( #endif ISAR_PRE_REND_GetMultiBinPoseData( &st_ivas->hRenderConfig->split_rend_config, &st_ivas->hSplitBinRend->splitrend.multiBinPoseData, ( st_ivas->hHeadTrackData != NULL ) ? st_ivas->hHeadTrackData->sr_pose_pred_axis : DEFAULT_AXIS ); +#endif if ( cldfb_in_flag == 1 && ( st_ivas->hSplitBinRend->splitrend.multiBinPoseData.poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE ) ) { diff --git a/lib_dec/lib_dec.h b/lib_dec/lib_dec.h index 8a45d8670..81895f322 100644 --- a/lib_dec/lib_dec.h +++ b/lib_dec/lib_dec.h @@ -163,7 +163,9 @@ ivas_error IVAS_DEC_ReadFormat( ivas_error IVAS_DEC_GetSamplesDecoder( IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ +#ifndef FIX_1119_SPLIT_RENDERING_VOIP const int16_t isSplitRend, /* i : split rendering enabled flag */ +#endif ISAR_SPLIT_REND_BITS_DATA *splitRendBits /* o : output split rendering bits */ ); @@ -326,6 +328,24 @@ ivas_error IVAS_DEC_VoIP_GetSamples( const uint32_t systemTimestamp_ms /* i : current system timestamp */ ); +#ifdef FIX_1119_SPLIT_RENDERING_VOIP +/*! r: error code */ +ivas_error IVAS_DEC_VoIP_GetSplitBinauralBitstream( + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + /* const IVAS_DEC_PCM_TYPE pcmType, */ /* i : type for the decoded PCM resolution */ + void *pcmBuf, /* o : output synthesis signal */ + ISAR_SPLIT_REND_BITS_DATA *splitRendBits, /* o : output split rendering bits */ +#ifdef SUPPORT_JBM_TRACEFILE + JbmTraceFileWriterFn jbmWriterFn, + void* jbmWriter, +#endif + bool *bitstreamReadDone, /* o : flag indicating that bitstream was read */ + uint16_t *nSamplesRendered, /* o : number of samples rendered */ + bool *parametersAvailableForEditing, /* o : indicates whether objects editing is available */ + const uint32_t systemTimestamp_ms /* i : current system timestamp */ +); +#endif + ivas_error IVAS_DEC_Flush( IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ const int16_t nSamplesPerChannel, /* i : number of samples per channel requested to be written to output buffer */ diff --git a/lib_isar/isar_prot.h b/lib_isar/isar_prot.h index a06309018..fb77001e5 100644 --- a/lib_isar/isar_prot.h +++ b/lib_isar/isar_prot.h @@ -67,8 +67,13 @@ void isar_splitBinPreRendClose( void lc3plusTimeAlignCldfbPoseCorr( SPLIT_REND_WRAPPER *hSplitBin, /* i/o: Split renderer pre-renderer handle */ +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + float *Cldfb_In_BinReal[][CLDFB_NO_COL_MAX], /* i/o: Binaural signals, real part */ + float *Cldfb_In_BinImag[][CLDFB_NO_COL_MAX] /* i/o: Binaural signals, imag. part */ +#else float Cldfb_In_BinReal[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], /* i/o: Binaural signals, real part */ float Cldfb_In_BinImag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX] /* i/o: Binaural signals, imag. part */ +#endif ); ivas_error splitRendLc3plusEncodeAndWrite( @@ -183,9 +188,14 @@ void isar_splitBinLCLDEncClose( void isar_splitBinLCLDEncProcess( ISAR_BIN_HR_SPLIT_LCLD_ENC_HANDLE hSplitBinLCLDEnc, /* i/o: ISAR LCLD encoder handle */ +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + float *Cldfb_In_Real[][CLDFB_NO_COL_MAX], /* i/o: Binaural signals, real part */ + float *Cldfb_In_Imag[][CLDFB_NO_COL_MAX], /* i/o: Binaural signals, imag. part */ +#else float Cldfb_In_Real[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], float Cldfb_In_Imag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], - const int32_t available_bits, +#endif + const int32_t available_bits, /* i : available bit-budget */ ISAR_SPLIT_REND_BITS_HANDLE pBits /* i/o: ISAR bits handle */ ); @@ -271,8 +281,13 @@ void isar_rend_CldfbSplitPreRendProcess( const ISAR_BIN_HR_SPLIT_PRE_REND_HANDLE hBinHrSplitPreRend, /* i : binaural pre-renderer handle */ const IVAS_QUATERNION headPosition, /* i : head rotation QUATERNION */ MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData, /* i/o: pose correction data handle */ +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + float* Cldfb_In_BinReal[][CLDFB_NO_COL_MAX], /* i : Binaural signals, real part */ + float* Cldfb_In_BinImag[][CLDFB_NO_COL_MAX], /* i : Binaural signals, imag. part */ +#else float Cldfb_In_BinReal[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], /* i : Binaural signals, real part */ float Cldfb_In_BinImag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], /* i : Binaural signals, imag. part */ +#endif ISAR_SPLIT_REND_BITS_HANDLE pBits, /* i/o: ISAR bits handle */ const int32_t target_md_bits, /* i : ISAR MD bitrate */ const int16_t low_res_pre_rend_rot, /* i : low time resolution pre-renderer flag */ diff --git a/lib_isar/isar_splitRend_lcld_enc.c b/lib_isar/isar_splitRend_lcld_enc.c index 518c4226e..412e220ad 100644 --- a/lib_isar/isar_splitRend_lcld_enc.c +++ b/lib_isar/isar_splitRend_lcld_enc.c @@ -157,10 +157,16 @@ void isar_splitBinLCLDEncClose( void isar_splitBinLCLDEncProcess( ISAR_BIN_HR_SPLIT_LCLD_ENC_HANDLE hSplitBinLCLDEnc, +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + float *Cldfb_In_Real[][CLDFB_NO_COL_MAX], /* i/o: Binaural signals, real part */ + float *Cldfb_In_Imag[][CLDFB_NO_COL_MAX], /* i/o: Binaural signals, imag. part */ +#else float Cldfb_In_Real[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], float Cldfb_In_Imag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], - const int32_t available_bits, - ISAR_SPLIT_REND_BITS_HANDLE pBits ) +#endif + const int32_t available_bits, /* i : available bit-budget */ + ISAR_SPLIT_REND_BITS_HANDLE pBits /* i/o: ISAR bits handle */ +) { int32_t iBitsWritten, itr, available_bits_itr, rem_itr, available_bits_local; push_wmops( "isar_splitBinLCLDEncProcess" ); diff --git a/lib_isar/isar_splitRendererPre.c b/lib_isar/isar_splitRendererPre.c index 372c924ad..734daae97 100644 --- a/lib_isar/isar_splitRendererPre.c +++ b/lib_isar/isar_splitRendererPre.c @@ -53,13 +53,16 @@ * Local function declarations *---------------------------------------------------------------------*/ -static void isar_SplitRenderer_GetRotMd( - ISAR_BIN_HR_SPLIT_PRE_REND_HANDLE hBinHrSplitPreRend, /* i/o: binaural renderer handle */ - MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData, - float Cldfb_RealBuffer_Ref_Binaural[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], /* o : Reference Binaural signals */ - float Cldfb_ImagBuffer_Ref_Binaural[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], /* o : Reference Binaural signals */ - const int16_t low_res, - const int16_t ro_md_flag ); +static void isar_SplitRenderer_GetRotMd( ISAR_BIN_HR_SPLIT_PRE_REND_HANDLE hBinHrSplitPreRend, MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData, +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + float *Cldfb_RealBuffer_Ref_Binaural[][CLDFB_NO_COL_MAX], + float *Cldfb_ImagBuffer_Ref_Binaural[][CLDFB_NO_COL_MAX], +#else + float Cldfb_RealBuffer_Ref_Binaural[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], + float Cldfb_ImagBuffer_Ref_Binaural[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], +#endif + const int16_t low_res, + const int16_t ro_md_flag ); /*------------------------------------------------------------------------- * Local functions @@ -276,11 +279,21 @@ static void ComputePostPredCov( static void ComputeBandedCrossCov( +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + float *Cldfb_RealBuffer1[][CLDFB_NO_COL_MAX], + float *Cldfb_ImagBuffer1[][CLDFB_NO_COL_MAX], +#else float Cldfb_RealBuffer1[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], float Cldfb_ImagBuffer1[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], +#endif const int16_t ch_start_idx1, +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + float *Cldfb_RealBuffer2[][CLDFB_NO_COL_MAX], + float *Cldfb_ImagBuffer2[][CLDFB_NO_COL_MAX], +#else float Cldfb_RealBuffer2[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], float Cldfb_ImagBuffer2[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], +#endif const int16_t ch_start_idx2, float out_cov_re[BINAURAL_CHANNELS][BINAURAL_CHANNELS], float out_cov_im[BINAURAL_CHANNELS][BINAURAL_CHANNELS], @@ -345,8 +358,13 @@ static void ComputeBandedCrossCov( static void ComputeBandedCov( +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + float *Cldfb_RealBuffer[][CLDFB_NO_COL_MAX], + float *Cldfb_ImagBuffer[][CLDFB_NO_COL_MAX], +#else float Cldfb_RealBuffer[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], float Cldfb_ImagBuffer[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], +#endif const int16_t ch_start_idx, float out_cov_re[][BINAURAL_CHANNELS], float out_cov_im[][BINAURAL_CHANNELS], @@ -1335,9 +1353,14 @@ static void isar_SplitRenderer_quant_code( static void isar_SplitRenderer_GetRotMd( ISAR_BIN_HR_SPLIT_PRE_REND_HANDLE hBinHrSplitPreRend, /* i/o: binaural renderer handle */ - MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData, + MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData, /* i/o: pose correction data handle */ +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + float *Cldfb_RealBuffer_Ref_Binaural[][CLDFB_NO_COL_MAX], /* o : Reference Binaural signals */ + float *Cldfb_ImagBuffer_Ref_Binaural[][CLDFB_NO_COL_MAX], /* o : Reference Binaural signals */ +#else float Cldfb_RealBuffer_Ref_Binaural[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], /* o : Reference Binaural signals */ float Cldfb_ImagBuffer_Ref_Binaural[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], /* o : Reference Binaural signals */ +#endif const int16_t low_res, const int16_t ro_md_flag ) { @@ -1418,15 +1441,21 @@ static void isar_SplitRenderer_GetRotMd( *------------------------------------------------------------------------*/ void isar_rend_CldfbSplitPreRendProcess( - const ISAR_BIN_HR_SPLIT_PRE_REND_HANDLE hBinHrSplitPreRend, - const IVAS_QUATERNION headPosition, - MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData, - float Cldfb_In_BinReal[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], - float Cldfb_In_BinImag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], - ISAR_SPLIT_REND_BITS_HANDLE pBits, - const int32_t target_md_bits, - const int16_t low_res_pre_rend_rot, - const int16_t ro_md_flag ) + const ISAR_BIN_HR_SPLIT_PRE_REND_HANDLE hBinHrSplitPreRend, /* i : binaural pre-renderer handle */ + const IVAS_QUATERNION headPosition, /* i : head rotation QUATERNION */ + MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData, /* i/o: pose correction data handle */ +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + float *Cldfb_In_BinReal[][CLDFB_NO_COL_MAX], /* i : Binaural signals, real part */ + float *Cldfb_In_BinImag[][CLDFB_NO_COL_MAX], /* i : Binaural signals, imag. part */ +#else + float Cldfb_In_BinReal[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], /* i : Binaural signals, real part */ + float Cldfb_In_BinImag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], /* i : Binaural signals, imag. part */ +#endif + ISAR_SPLIT_REND_BITS_HANDLE pBits, /* i/o: ISAR bits handle */ + const int32_t target_md_bits, /* i : ISAR MD bitrate */ + const int16_t low_res_pre_rend_rot, /* i : low time resolution pre-renderer flag */ + const int16_t ro_md_flag /* i : real only metadata for yaw flag */ +) { push_wmops( "isar_rend_CldfbSplitPreRendProcess" ); @@ -1873,6 +1902,11 @@ ivas_error isar_renderMultiTDBinToSplitBinaural( uint8_t useLc3plus; float *in_delayed[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS]; int16_t i; +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + int16_t j; + float *p_Cldfb_In_BinReal[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX]; + float *p_Cldfb_In_BinImag[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX]; +#endif int32_t num_slots; push_wmops( "isar_renderMultiTDBinToSplitBinaural" ); @@ -1882,6 +1916,17 @@ ivas_error isar_renderMultiTDBinToSplitBinaural( useLc3plus = hSplitBin->hLc3plusEnc != NULL; +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + for ( i = 0; i < MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS; ++i ) + { + for ( j = 0; j < CLDFB_NO_COL_MAX; ++j ) + { + p_Cldfb_In_BinReal[i][j] = Cldfb_In_BinReal[i][j]; + p_Cldfb_In_BinImag[i][j] = Cldfb_In_BinImag[i][j]; + } + } +#endif + if ( useLc3plus ) { /*this should always have the time resolution of pose correction MD. Note that this does not change frame size of LC3plus*/ @@ -1944,7 +1989,21 @@ ivas_error isar_renderMultiTDBinToSplitBinaural( target_md_bits = isar_get_split_rend_md_target_brate( SplitRendBitRate, pcm_out_flag ) * L_FRAME48k / 48000; - isar_rend_CldfbSplitPreRendProcess( hSplitBin->hBinHrSplitPreRend, headPosition, &hSplitBin->multiBinPoseData, Cldfb_In_BinReal, Cldfb_In_BinImag, pBits, target_md_bits, low_res_pre_rend_rot, ro_md_flag ); + isar_rend_CldfbSplitPreRendProcess( + hSplitBin->hBinHrSplitPreRend, + headPosition, + &hSplitBin->multiBinPoseData, +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + p_Cldfb_In_BinReal, + p_Cldfb_In_BinImag, +#else + Cldfb_In_BinReal, + Cldfb_In_BinImag, +#endif + pBits, + target_md_bits, + low_res_pre_rend_rot, + ro_md_flag ); } if ( pcm_out_flag == 0 ) @@ -1959,7 +2018,17 @@ ivas_error isar_renderMultiTDBinToSplitBinaural( pBits->codec_frame_size_ms = codec_frame_size_ms; pBits->isar_frame_size_ms = isar_frame_size_ms; - isar_splitBinLCLDEncProcess( hSplitBin->hSplitBinLCLDEnc, Cldfb_In_BinReal, Cldfb_In_BinImag, available_bits, pBits ); + isar_splitBinLCLDEncProcess( + hSplitBin->hSplitBinLCLDEnc, +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + p_Cldfb_In_BinReal, + p_Cldfb_In_BinImag, +#else + Cldfb_In_BinReal, + Cldfb_In_BinImag, +#endif + available_bits, + pBits ); } else { @@ -2019,9 +2088,15 @@ ivas_error isar_renderMultiTDBinToSplitBinaural( *------------------------------------------------------------------------*/ void lc3plusTimeAlignCldfbPoseCorr( - SPLIT_REND_WRAPPER *hSplitBin, - float Cldfb_In_BinReal[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], - float Cldfb_In_BinImag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX] ) + SPLIT_REND_WRAPPER *hSplitBin, /* i/o: Split renderer pre-renderer handle */ +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + float *Cldfb_In_BinReal[][CLDFB_NO_COL_MAX], /* i/o: Binaural signals, real part */ + float *Cldfb_In_BinImag[][CLDFB_NO_COL_MAX] /* i/o: Binaural signals, imag. part */ +#else + float Cldfb_In_BinReal[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], /* i/o: Binaural signals, real part */ + float Cldfb_In_BinImag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX] /* ii/: Binaural signals, imag. part */ +#endif +) { float Cldfb_In_BinReal_tmp[MAX_HEAD_ROT_POSES][BINAURAL_CHANNELS][2][CLDFB_NO_CHANNELS_MAX]; float Cldfb_In_BinImag_tmp[MAX_HEAD_ROT_POSES][BINAURAL_CHANNELS][2][CLDFB_NO_CHANNELS_MAX]; diff --git a/lib_isar/isar_stat.h b/lib_isar/isar_stat.h index 587c3c8ea..b244370dd 100644 --- a/lib_isar/isar_stat.h +++ b/lib_isar/isar_stat.h @@ -345,4 +345,17 @@ typedef struct } SPLIT_REND_WRAPPER; +#ifdef FIX_1119_SPLIT_RENDERING_VOIP +typedef struct +{ + float *real; + float *imag; + uint32_t capacity; + uint32_t write_pos; + uint32_t read_pos; + int16_t is_full; + +} ISAR_CLDFB_RINGBUF, *ISAR_CLDFB_RINGBUF_HANDLE; +#endif + #endif /* ISAR_STAT_H */ diff --git a/lib_isar/lib_isar_pre_rend.c b/lib_isar/lib_isar_pre_rend.c index 2e6c70b47..7203c97b2 100644 --- a/lib_isar/lib_isar_pre_rend.c +++ b/lib_isar/lib_isar_pre_rend.c @@ -294,21 +294,26 @@ void ISAR_PRE_REND_GetMultiBinPoseData( *------------------------------------------------------------------------*/ ivas_error ISAR_PRE_REND_MultiBinToSplitBinaural( - SPLIT_REND_WRAPPER *hSplitBin, /* i/o: Split renderer pre-renerer handle */ - const IVAS_QUATERNION headPosition, /* i: head rotation QUATERNION */ - const int32_t SplitRendBitRate, /* i: Split renderer bitrate */ - ISAR_SPLIT_REND_CODEC splitCodec, /* i/o: Split renderer codec */ - const int16_t isar_frame_size_ms, /* i: ISAR framesize */ - int16_t codec_frame_size_ms, /* i/o: ISAR transport codec framesize */ - ISAR_SPLIT_REND_BITS_HANDLE pBits, /* i/o: ISAR bits struct handle */ + SPLIT_REND_WRAPPER *hSplitBin, /* i/o: Split renderer pre-renerer handle */ + const IVAS_QUATERNION headPosition, /* i : head rotation QUATERNION */ + const int32_t SplitRendBitRate, /* i : Split renderer bitrate */ + ISAR_SPLIT_REND_CODEC splitCodec, /* i/o: Split renderer codec */ + const int16_t isar_frame_size_ms, /* i : ISAR framesize */ + int16_t codec_frame_size_ms, /* i/o: ISAR transport codec framesize */ + ISAR_SPLIT_REND_BITS_HANDLE pBits, /* i/o: ISAR bits struct handle */ +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + float *Cldfb_In_BinReal[][CLDFB_NO_COL_MAX], /* i/o: CLDFB real buffer */ + float *Cldfb_In_BinImag[][CLDFB_NO_COL_MAX], /* i/o: CLDFB imag buffer */ +#else float Cldfb_In_BinReal[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], /* i/o: CLDFB real buffer */ float Cldfb_In_BinImag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], /* i/o: CLDFB imag buffer */ - const int16_t max_bands, /* i: CLDFB bands */ - float *output[], /* i/o: PCM in/out buffer */ - const int16_t low_res_pre_rend_rot, /* i: low time resolution pre-renderer flag */ - const int16_t cldfb_in_flag, /* i: Flag to indicate CLDFB or time doamin input */ - const int16_t pcm_out_flag, /* i: Flag to indicate PCM output */ - const int16_t ro_md_flag /* i: Flag to indicate real only metadata for yaw */ +#endif + const int16_t max_bands, /* i : CLDFB bands */ + float *output[], /* i/o: PCM in/out buffer */ + const int16_t low_res_pre_rend_rot, /* i : low time resolution pre-renderer flag */ + const int16_t cldfb_in_flag, /* i : Flag to indicate CLDFB or time domain input */ + const int16_t pcm_out_flag, /* i : Flag to indicate PCM output */ + const int16_t ro_md_flag /* i : Flag to indicate real only metadata for yaw */ ) { ivas_error error; @@ -406,20 +411,22 @@ ivas_error ISAR_PRE_REND_MultiBinToSplitBinaural( } else { - int16_t ch, slot_idx; + int16_t ch, slot_idx, num_slots; + num_slots = (int16_t) ( isar_frame_size_ms * 1000000 / CLDFB_SLOT_NS ); + /* CLDFB synthesis of main pose */ for ( ch = 0; ch < BINAURAL_CHANNELS; ch++ ) { float *Cldfb_In_BinReal_p[CLDFB_NO_COL_MAX]; float *Cldfb_In_BinImag_p[CLDFB_NO_COL_MAX]; - for ( slot_idx = 0; slot_idx < CLDFB_NO_COL_MAX; slot_idx++ ) + for ( slot_idx = 0; slot_idx < num_slots; slot_idx++ ) { Cldfb_In_BinReal_p[slot_idx] = Cldfb_In_BinReal[ch][slot_idx]; Cldfb_In_BinImag_p[slot_idx] = Cldfb_In_BinImag[ch][slot_idx]; } - cldfbSynthesis( Cldfb_In_BinReal_p, Cldfb_In_BinImag_p, output[ch], hSplitBin->hCldfbHandles->cldfbSyn[0]->no_channels * CLDFB_NO_COL_MAX, hSplitBin->hCldfbHandles->cldfbSyn[ch] ); + cldfbSynthesis( Cldfb_In_BinReal_p, Cldfb_In_BinImag_p, output[ch], hSplitBin->hCldfbHandles->cldfbSyn[0]->no_channels * num_slots, hSplitBin->hCldfbHandles->cldfbSyn[ch] ); } pBits->pose_correction = hSplitBin->multiBinPoseData.poseCorrectionMode; diff --git a/lib_isar/lib_isar_pre_rend.h b/lib_isar/lib_isar_pre_rend.h index 201b46cd0..7f75f5a22 100644 --- a/lib_isar/lib_isar_pre_rend.h +++ b/lib_isar/lib_isar_pre_rend.h @@ -66,8 +66,13 @@ ivas_error ISAR_PRE_REND_MultiBinToSplitBinaural( const int16_t isar_frame_size_ms, /* i: ISAR framesize */ int16_t codec_frame_size_ms, /* i/o: ISAR transport codec framesize */ ISAR_SPLIT_REND_BITS_HANDLE pBits, /* i/o: ISAR bits struct handle */ +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + float* Cldfb_In_BinReal[][CLDFB_NO_COL_MAX], /* i/o: CLDFB real buffer */ + float* Cldfb_In_BinImag[][CLDFB_NO_COL_MAX], /* i/o: CLDFB imag buffer */ +#else float Cldfb_In_BinReal[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], /* i/o: CLDFB real buffer */ float Cldfb_In_BinImag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], /* i/o: CLDFB imag buffer */ +#endif const int16_t max_bands, /* i: CLDFB bands */ float *output[], /* i/o: PCM in/out buffer */ const int16_t low_res_pre_rend_rot, /* i: low time resolution pre-renderer flag */ diff --git a/lib_rend/ivas_cldfb_ring_buffer.c b/lib_rend/ivas_cldfb_ring_buffer.c new file mode 100644 index 000000000..5d1d2a055 --- /dev/null +++ b/lib_rend/ivas_cldfb_ring_buffer.c @@ -0,0 +1,299 @@ +/****************************************************************************************************** + + (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#include +#include "options.h" +#include "cnst.h" +#include "prot.h" +#include "ivas_prot.h" +#include +#ifdef DEBUGGING +#include "debug.h" +#endif +#include "wmc_auto.h" + +#ifdef FIX_1119_SPLIT_RENDERING_VOIP +/*---------------------------------------------------------------------* + * CLDFB ring-buffer functions needed in split-rendering outputs + *---------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------* + * ivas_cldfb_ringbuf_IsEmpty() + * + * Returns 1 if the ring buffer is empty, or 0 otherwise. + *---------------------------------------------------------------------*/ + +static int16_t ivas_cldfb_ringbuf_IsEmpty( + ISAR_CLDFB_RINGBUF_HANDLE h ) +{ + return (int16_t) ( h->read_pos == h->write_pos && !h->is_full ); +} + + +/*---------------------------------------------------------------------* + * ivas_cldfb_ringbuf_IsFull() + * + * Returns 1 if the ring buffer is full, or 0 otherwise. + *---------------------------------------------------------------------*/ + +static int16_t ivas_cldfb_ringbuf_IsFull( + ISAR_CLDFB_RINGBUF_HANDLE h ) +{ + return h->is_full; +} + + +/*---------------------------------------------------------------------* + * ivas_CLDFB_RINGBUF_Open() + * + * Allocate a ring buffer for CLDFB data with the given capacity of CLDFB columns. + * Each column is expected to contain at most CLDFB_NO_CHANNELS_MAX frequency bands. + * + * May return IVAS_ERR_FAILED_ALLOC on failed allocation, or IVAS_ERR_OK otherwise. + *---------------------------------------------------------------------*/ + +ivas_error ivas_CLDFB_RINGBUF_Open( + ISAR_CLDFB_RINGBUF_HANDLE *ph, + const int16_t capacity_columns ) +{ + ISAR_CLDFB_RINGBUF_HANDLE h; + int32_t capacity; + + capacity = capacity_columns * CLDFB_NO_CHANNELS_MAX; + + if ( ( h = malloc( sizeof( ISAR_CLDFB_RINGBUF ) ) ) == NULL ) + { + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Failed to allocate memory for CLDFB ring buffer\n" ); + } + h->real = NULL; + h->imag = NULL; + h->capacity = 0; + h->write_pos = 0; + h->read_pos = 0; + h->is_full = 0; + *ph = h; + + if ( ( h->real = malloc( capacity * sizeof( float ) ) ) == NULL ) + { + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Failed to allocate memory for CLDFB ring buffer\n" ); + } + if ( ( h->imag = malloc( capacity * sizeof( float ) ) ) == NULL ) + { + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Failed to allocate memory for CLDFB ring buffer\n" ); + } + h->capacity = capacity; + + return IVAS_ERR_OK; +} + + +/*---------------------------------------------------------------------* + * ivas_CLDFB_RINGBUF_Close() + * + * Dellocate CLDFB ring buffer. The given handle will be set to NULL. + *---------------------------------------------------------------------*/ + +void ivas_CLDFB_RINGBUF_Close( + ISAR_CLDFB_RINGBUF_HANDLE *ph ) +{ + ISAR_CLDFB_RINGBUF_HANDLE h; + + if ( ph == NULL ) + { + return; + } + h = *ph; + + if ( h == NULL ) + { + return; + } + + if ( h->real != NULL ) + { + free( h->real ); + } + if ( h->imag != NULL ) + { + free( h->imag ); + } + + free( h ); + *ph = NULL; + + return; +} + + +/*---------------------------------------------------------------------* + * ivas_CLDFB_RINGBUF_Push() + * + * Push a single column onto the back of the CLDFB ring buffer from real and imag arrays. + *---------------------------------------------------------------------*/ + +void ivas_CLDFB_RINGBUF_Push( + ISAR_CLDFB_RINGBUF_HANDLE h, + const float *real, + const float *imag, + const int16_t num_bands ) +{ + assert( num_bands <= CLDFB_NO_CHANNELS_MAX ); + assert( !ivas_cldfb_ringbuf_IsFull( h ) ); + + mvr2r( real, &h->real[h->write_pos], num_bands ); + mvr2r( imag, &h->imag[h->write_pos], num_bands ); + + h->write_pos += CLDFB_NO_CHANNELS_MAX; + if ( h->write_pos == h->capacity ) + { + h->write_pos = 0; + } + + if ( h->read_pos == h->write_pos ) + { + h->is_full = 1; + } + + return; +} + + +/*---------------------------------------------------------------------* + * ivas_CLDFB_RINGBUF_Pop() + * + * Pop a single column from the front of the CLDFB ring buffer into real and imag arrays. + *---------------------------------------------------------------------*/ + +void ivas_CLDFB_RINGBUF_Pop( + ISAR_CLDFB_RINGBUF_HANDLE h, + float *real, + float *imag, + const int16_t num_bands ) +{ + assert( num_bands <= CLDFB_NO_CHANNELS_MAX ); + assert( !ivas_cldfb_ringbuf_IsEmpty( h ) ); + + if ( real != NULL ) + { + mvr2r( &h->real[h->read_pos], real, num_bands ); + } + if ( imag != NULL ) + { + mvr2r( &h->imag[h->read_pos], imag, num_bands ); + } + + h->read_pos += CLDFB_NO_CHANNELS_MAX; + if ( h->read_pos == h->capacity ) + { + h->read_pos = 0; + } + + h->is_full = 0; + + return; +} + + +/*---------------------------------------------------------------------* + * ivas_cldfb_ringbuf_total_size() + * + * Returns total number of buffered samples (including number of channels) + *---------------------------------------------------------------------*/ + +static uint32_t ivas_cldfb_ringbuf_total_size( + ISAR_CLDFB_RINGBUF_HANDLE h ) +{ + if ( ivas_cldfb_ringbuf_IsFull( h ) ) + { + return h->capacity; + } + + if ( h->read_pos <= h->write_pos ) + { + return h->write_pos - h->read_pos; + } + + /* else wrap around */ + return h->write_pos + h->capacity - h->read_pos; +} + + +/*---------------------------------------------------------------------* + * ivas_CLDFB_RINGBUF_GetByIdx() + * + * Get pointers into a specific column in the CLDFB ring buffer based on given index. + * Non-negative indices access from the front of the ring buffer, negative indexes access + * from the back, similar to Python arrays. For example: + * + * - index 0 accesses the front of the buffer, i.e. the oldest CLDFB column in the queue. + * - index -1 accesses the back of the buffer, i.e. the newest (last pushed) CLDFB column in the queue. + *---------------------------------------------------------------------*/ + +void ivas_CLDFB_RINGBUF_GetByIdx( + ISAR_CLDFB_RINGBUF_HANDLE h, + float **p_real, + float **p_imag, + const int16_t col_idx ) +{ + int32_t idx = col_idx * CLDFB_NO_CHANNELS_MAX; + int32_t num_floats = (int32_t) ivas_cldfb_ringbuf_total_size( h ); + uint32_t offset, uidx; + + assert( -num_floats <= idx && idx <= num_floats ); + + if ( idx >= 0 ) + { + offset = h->read_pos + idx; + if ( h->capacity <= offset ) + { + offset -= h->capacity; + } + } + else + { + uidx = (uint32_t) -idx; + if ( uidx <= h->write_pos ) + { + offset = h->write_pos - uidx; + } + else + { + offset = h->write_pos + h->capacity - uidx; + } + } + + *p_real = &h->real[offset]; + *p_imag = &h->imag[offset]; + + return; +} +#endif diff --git a/lib_rend/ivas_dirac_dec_binaural_functions.c b/lib_rend/ivas_dirac_dec_binaural_functions.c index 83a8f6bb4..907a87df9 100644 --- a/lib_rend/ivas_dirac_dec_binaural_functions.c +++ b/lib_rend/ivas_dirac_dec_binaural_functions.c @@ -832,8 +832,12 @@ static void ivas_dirac_dec_binaural_internal( { for ( i = 0; i < hSpatParamRendCom->subframe_nbslots[subframe]; i++ ) { +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + ivas_CLDFB_RINGBUF_Push( st_ivas->hSplitBinRend->hMultiBinCldfbData[ch], tmp_Cldfb_out_re[ch][i], tmp_Cldfb_out_im[ch][i], CLDFB_NO_CHANNELS_MAX ); +#else mvr2r( tmp_Cldfb_out_re[ch][i], st_ivas->hSplitBinRend->hMultiBinCldfbData->Cldfb_RealBuffer_Binaural[ch][hSpatParamRendCom->slots_rendered + i], CLDFB_NO_CHANNELS_MAX ); mvr2r( tmp_Cldfb_out_im[ch][i], st_ivas->hSplitBinRend->hMultiBinCldfbData->Cldfb_ImagBuffer_Binaural[ch][hSpatParamRendCom->slots_rendered + i], CLDFB_NO_CHANNELS_MAX ); +#endif } } } @@ -883,14 +887,21 @@ static void ivas_dirac_dec_binaural_internal( mvr2r( st_ivas->hDiracDecBin[0]->ChCrossIm, hDiracDecBin->ChCrossIm, hSpatParamRendCom->num_freq_bands ); ivas_dirac_dec_binaural_formulate_target_covariance_matrices( hDiracDecBin, hSpatParamRendCom, &config_data, Rmat_local, subframe, +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + hCombinedOrientationData && hCombinedOrientationData->enableCombinedOrientation[hCombinedOrientationData->subframe_idx] > 0, +#else hCombinedOrientationData && hCombinedOrientationData->enableCombinedOrientation[subframe] > 0, +#endif subFrameTotalEne, IIReneLimiter, st_ivas->hMasaIsmData ); ivas_dirac_dec_binaural_determine_processing_matrices( hDiracDecBin, hSpatParamRendCom, &config_data, max_band_decorr, Rmat_local, subframe, +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + hCombinedOrientationData && hCombinedOrientationData->enableCombinedOrientation[hCombinedOrientationData->subframe_idx] > 0, +#else hCombinedOrientationData && hCombinedOrientationData->enableCombinedOrientation[subframe] > 0, +#endif nchanSeparateChannels, st_ivas->hMasaIsmData ); - /* re-use reverb and decorr from main direction for the sides */ ivas_dirac_dec_binaural_process_output( hDiracDecBin, hSpatParamRendCom, st_ivas->cldfbSynDec, output_f, Cldfb_RealBuffer_in, Cldfb_ImagBuffer_in, max_band_decorr, numInChannels, config_data.processReverb, subframe, tmp_Cldfb_out_re, tmp_Cldfb_out_im, @@ -901,8 +912,12 @@ static void ivas_dirac_dec_binaural_internal( { for ( i = 0; i < hSpatParamRendCom->subframe_nbslots[subframe]; i++ ) { +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + ivas_CLDFB_RINGBUF_Push( st_ivas->hSplitBinRend->hMultiBinCldfbData[pos_idx * BINAURAL_CHANNELS + ch], tmp_Cldfb_out_re[ch][i], tmp_Cldfb_out_im[ch][i], CLDFB_NO_CHANNELS_MAX ); +#else mvr2r( tmp_Cldfb_out_re[ch][i], st_ivas->hSplitBinRend->hMultiBinCldfbData->Cldfb_RealBuffer_Binaural[pos_idx * BINAURAL_CHANNELS + ch][hSpatParamRendCom->slots_rendered + i], CLDFB_NO_CHANNELS_MAX ); mvr2r( tmp_Cldfb_out_im[ch][i], st_ivas->hSplitBinRend->hMultiBinCldfbData->Cldfb_ImagBuffer_Binaural[pos_idx * BINAURAL_CHANNELS + ch][hSpatParamRendCom->slots_rendered + i], CLDFB_NO_CHANNELS_MAX ); +#endif } } diff --git a/lib_rend/ivas_prot_rend.h b/lib_rend/ivas_prot_rend.h index 1e9c4df5a..54b11994b 100644 --- a/lib_rend/ivas_prot_rend.h +++ b/lib_rend/ivas_prot_rend.h @@ -1593,6 +1593,66 @@ void ivas_rend_closeCldfbRend( CLDFB_REND_WRAPPER *pCldfbRend ); +/*----------------------------------------------------------------------------------* + * Time domain ring buffer prototypes + *----------------------------------------------------------------------------------*/ + +ivas_error ivas_TD_RINGBUF_Open( + TD_RINGBUF_HANDLE *ph, /* i/o: Ring buffer handle */ + const uint32_t capacity_per_channel, /* i : Number of samples stored per channel */ + const uint16_t num_channels /* i : Number of channels */ +); + +void ivas_TD_RINGBUF_Close( + TD_RINGBUF_HANDLE *ph /* i/o: Ring buffer handle */ +); + +#ifdef FIX_1119_SPLIT_RENDERING_VOIP +void ivas_TD_RINGBUF_PushInterleaved( + TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ + const float *data, /* i : Input audio in interleaved channels layout */ + const uint32_t num_samples_per_channel /* i : Number of samples per channel to push */ +); + +void ivas_TD_RINGBUF_PushChannels( + TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ + const float *p_channels[], /* i : Array of pointers to each input channel */ + const uint32_t num_samples_per_channel /* i : Number of samples per channel to store */ +); + +void ivas_TD_RINGBUF_PushConstant( + TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ + const float value, /* i : Value to push */ + const uint32_t num_samples_per_channel /* i : Number of samples per channel to push */ +); + +void ivas_TD_RINGBUF_PopChannels( + TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ + float *p_channels[], /* i : Array of pointers to each output channel */ + const uint32_t num_samples_per_channel /* i : Number of samples per channel to pop */ +); +#else +void ivas_TD_RINGBUF_Push( + TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ + const float *data, /* i : Input data */ + const uint32_t num_samples_per_channel /* i : Number of samples per channel to store */ +); + +void ivas_TD_RINGBUF_PushZeros( + TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ + const uint32_t num_samples_per_channel /* i : Number of zeros per channel to store */ +); + +void ivas_TD_RINGBUF_Pop( + TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ + float *data, /* i : Output data */ + const uint32_t num_samples_per_channel /* i : Number of samples per channel to retrieve*/ +); +#endif + +uint32_t ivas_TD_RINGBUF_Size( + const TD_RINGBUF_HANDLE h /* i : Ring buffer handle */ +); /* clang-format on */ diff --git a/lib_rend/ivas_stat_rend.h b/lib_rend/ivas_stat_rend.h index bba88de8e..6b6cff629 100644 --- a/lib_rend/ivas_stat_rend.h +++ b/lib_rend/ivas_stat_rend.h @@ -1375,6 +1375,22 @@ typedef struct } CLDFB_REND_WRAPPER; +/*----------------------------------------------------------------------------------* + * Time domain ring buffer structure + *----------------------------------------------------------------------------------*/ + +typedef struct +{ + float *data; /* samples in interleaved layout */ + uint32_t capacity; + uint16_t num_channels; + uint32_t write_pos; + uint32_t read_pos; + int16_t is_full; + +} TD_RINGBUF_DATA, *TD_RINGBUF_HANDLE; + + /*----------------------------------------------------------------------------------* * MASA external renderer structure *----------------------------------------------------------------------------------*/ diff --git a/lib_rend/ivas_td_ring_buffer.c b/lib_rend/ivas_td_ring_buffer.c new file mode 100644 index 000000000..f1fdab3af --- /dev/null +++ b/lib_rend/ivas_td_ring_buffer.c @@ -0,0 +1,420 @@ +/****************************************************************************************************** + + (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#include +#include +#include "ivas_error_utils.h" +#include "ivas_prot_rend.h" +#include "options.h" +#include "wmc_auto.h" + + +/*-----------------------------------------------------------------------* + * Local function prototypes + *-----------------------------------------------------------------------*/ + +static uint32_t ivas_td_ringbuf_total_size( + TD_RINGBUF_HANDLE h ) +{ + if ( h->is_full ) + { + return h->capacity; + } + + if ( h->read_pos <= h->write_pos ) + { + return h->write_pos - h->read_pos; + } + /* else wrap around */ + return h->write_pos + h->capacity - h->read_pos; +} + + +static int16_t ivas_td_ringbuf_has_space_for_num_samples( + TD_RINGBUF_HANDLE h, + const uint32_t num_samples ) +{ + return (int16_t) ( ivas_td_ringbuf_total_size( h ) + num_samples <= h->capacity ); +} + + +#ifdef FIX_1119_SPLIT_RENDERING_VOIP +static void ivas_td_ringbuf_push_interleaved( + TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ + const float *data, /* i : Input audio in interleaved channels layout */ + const uint32_t num_samples_per_channel, /* i : Number of samples per channel to push */ + const uint16_t read_stride /* i: : 1 for normal operation, 0 for reading from a single input value */ +) +{ + uint32_t s, read_s; + + assert( h != NULL ); + assert( data != NULL ); + assert( read_stride == 0 || read_stride == 1 ); + assert( ivas_td_ringbuf_has_space_for_num_samples( h, num_samples_per_channel * h->num_channels ) ); + + for ( s = 0, read_s = 0; s < num_samples_per_channel * h->num_channels; ++s, read_s += read_stride ) + { + h->data[h->write_pos] = data[read_s]; + ++h->write_pos; + + if ( h->write_pos == h->capacity ) + { + h->write_pos = 0; + } + } + + if ( h->read_pos == h->write_pos ) + { + h->is_full = 1; + } + + return; +} +#endif + + +/*-----------------------------------------------------------------------* + * Global function definitions + *-----------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------* + * ivas_TD_RINGBUF_Open() + * + * Allocate a ring buffer for TD data with the given capacity of TD samples per channel. + * + * May return IVAS_ERR_FAILED_ALLOC on failed allocation, or IVAS_ERR_OK otherwise. + *---------------------------------------------------------------------*/ + +ivas_error ivas_TD_RINGBUF_Open( + TD_RINGBUF_HANDLE *ph, /* i/o: Ring buffer handle */ + const uint32_t capacity_per_channel, /* i : Number of samples stored per channel */ + const uint16_t num_channels /* i : Number of channels */ +) +{ + TD_RINGBUF_HANDLE h; + uint32_t capacity; + + capacity = capacity_per_channel * num_channels; + + h = malloc( sizeof( TD_RINGBUF_DATA ) ); + if ( h == NULL ) + { + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Failed to allocate memory for TD ring buffer\n" ); + } + h->data = NULL; + h->capacity = 0; + h->num_channels = num_channels; + h->write_pos = 0; + h->read_pos = 0; + h->is_full = 0; + *ph = h; + + h->data = malloc( capacity * sizeof( float ) ); + if ( h->data == NULL ) + { + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Failed to allocate memory for TD ring buffer\n" ); + } + h->capacity = capacity; + + return IVAS_ERR_OK; +} + + +/*---------------------------------------------------------------------* + * ivas_TD_RINGBUF_Close() + * + * Dellocate TD ring buffer. The given handle will be set to NULL. + + *---------------------------------------------------------------------*/ + +void ivas_TD_RINGBUF_Close( + TD_RINGBUF_HANDLE *ph /* i/o: Ring buffer handle */ +) +{ + TD_RINGBUF_HANDLE h; + + if ( ph == NULL ) + { + return; + } + h = *ph; + + if ( h == NULL ) + { + return; + } + + if ( h->data != NULL ) + { + free( h->data ); + } + + free( h ); + *ph = NULL; + + return; +} + + +#ifdef FIX_1119_SPLIT_RENDERING_VOIP +/*---------------------------------------------------------------------* + * ivas_TD_RINGBUF_PushInterleaved() + * + * Push samples from a buffer with interleaved channel layout onto the back of the TD ring buffer. + *---------------------------------------------------------------------*/ + +void ivas_TD_RINGBUF_PushInterleaved( + TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ + const float *data, /* i : Input audio in interleaved channels layout */ + const uint32_t num_samples_per_channel /* i : Number of samples per channel to push */ +) +{ + ivas_td_ringbuf_push_interleaved( h, data, num_samples_per_channel, 1 ); + + return; +} + + +/*---------------------------------------------------------------------* + * ivas_TD_RINGBUF_PushChannels() + * + * Push samples from channel pointers onto the back of the TD ring buffer. + *---------------------------------------------------------------------*/ + +void ivas_TD_RINGBUF_PushChannels( + TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ + const float *p_channels[], /* i : Array of pointers to each input channel */ + const uint32_t num_samples_per_channel /* i : Number of samples per channel to push */ +) +#else +/*---------------------------------------------------------------------* + * ivas_TD_RINGBUF_Push() + * + * Push samples onto the back of the TD ring buffer. + * Returns total number of buffered samples (includes number of channels) + *---------------------------------------------------------------------*/ + +void ivas_TD_RINGBUF_Push( + TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ + const float *data, /* i : Input data */ + const uint32_t num_samples_per_channel /* i : Number of samples per channel to store */ +) +#endif +{ + uint32_t s; + uint16_t c; + +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + assert( h != NULL ); + assert( p_channels != NULL ); + for ( c = 0; c < h->num_channels; ++c ) + { + assert( p_channels[c] != NULL ); + } +#endif + assert( ivas_td_ringbuf_has_space_for_num_samples( h, num_samples_per_channel * h->num_channels ) ); + + for ( s = 0; s < num_samples_per_channel; ++s ) + { + for ( c = 0; c < h->num_channels; ++c ) + { +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + h->data[h->write_pos] = p_channels[c][s]; +#else + h->data[h->write_pos] = *( data + c * num_samples_per_channel + s ); +#endif + ++h->write_pos; + + if ( h->write_pos == h->capacity ) + { + h->write_pos = 0; + } + } + } + + if ( h->read_pos == h->write_pos ) + { + h->is_full = 1; + } + + return; +} + + +#ifdef FIX_1119_SPLIT_RENDERING_VOIP +/*---------------------------------------------------------------------* + * ivas_TD_RINGBUF_PushConstant() + * + * Push samples with a constant value onto the back of the TD ring buffer. + *---------------------------------------------------------------------*/ + +void ivas_TD_RINGBUF_PushConstant( + TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ + const float value, /* i : Value to push */ + const uint32_t num_samples_per_channel /* i : Number of samples per channel to push */ +) +{ + ivas_td_ringbuf_push_interleaved( h, &value, num_samples_per_channel, 0 ); + + return; +} +#else +/*---------------------------------------------------------------------* + * ivas_TD_RINGBUF_PushZeros() + * + * Push zero samples onto the back of the TD ring buffer. + *---------------------------------------------------------------------*/ + +void ivas_TD_RINGBUF_PushZeros( + TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ + const uint32_t num_samples_per_channel /* i : Number of zeros per channel to store */ +) +{ + uint32_t s; + uint16_t c; + + assert( ivas_td_ringbuf_has_space_for_num_samples( h, num_samples_per_channel * h->num_channels ) ); + if ( !num_samples_per_channel ) + { + return; + } + + for ( s = 0; s < num_samples_per_channel; ++s ) + { + for ( c = 0; c < h->num_channels; ++c ) + { + h->data[h->write_pos] = 0.f; + ++h->write_pos; + + if ( h->write_pos == h->capacity ) + { + h->write_pos = 0; + } + } + } + + if ( h->read_pos == h->write_pos ) + { + h->is_full = 1; + } + + return; +} +#endif + + +#ifdef FIX_1119_SPLIT_RENDERING_VOIP +/*---------------------------------------------------------------------* + * ivas_TD_RINGBUF_PopChannels() + * + * Pop samples from the front of the TD ring buffer to an array of channel pointers. + *---------------------------------------------------------------------*/ + +void ivas_TD_RINGBUF_PopChannels( + TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ + float *p_channels[], /* i : Array of pointers to each output channel */ + const uint32_t num_samples_per_channel /* i : Number of samples per channel to pop */ +) +#else +/*---------------------------------------------------------------------* + * ivas_TD_RINGBUF_Pop() + * + * Pop samples from the front of the TD ring buffer. + *---------------------------------------------------------------------*/ + +void ivas_TD_RINGBUF_Pop( + TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ + float *data, /* i : Output data */ + const uint32_t num_samples_per_channel /* i : Number of samples per channel to retrieve */ +) +#endif +{ + uint32_t s; + uint16_t c; + +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + assert( h != NULL ); + assert( p_channels != NULL ); + for ( c = 0; c < h->num_channels; ++c ) + { + assert( p_channels[c] != NULL ); + } +#endif + assert( ivas_td_ringbuf_total_size( h ) >= num_samples_per_channel * h->num_channels ); + + for ( s = 0; s < num_samples_per_channel; ++s ) + { + for ( c = 0; c < h->num_channels; ++c ) + { +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + p_channels[c][s] = h->data[h->read_pos]; +#else + *( data + c * num_samples_per_channel + s ) = h->data[h->read_pos]; +#endif + ++h->read_pos; + + if ( h->read_pos == h->capacity ) + { + h->read_pos = 0; + } + } + } + +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + if ( num_samples_per_channel != 0 ) + { + h->is_full = 0; + } +#else + if ( h->is_full ) + { + h->is_full = 0; + } +#endif + + return; +} + + +/*---------------------------------------------------------------------* + * ivas_TD_RINGBUF_Size() + * + * Returns number of buffered samples per channel. + *---------------------------------------------------------------------*/ + +uint32_t ivas_TD_RINGBUF_Size( + const TD_RINGBUF_HANDLE h /* i : Ring buffer handle */ +) +{ + return ivas_td_ringbuf_total_size( h ) / (uint32_t) h->num_channels; +} diff --git a/lib_rend/lib_rend.c b/lib_rend/lib_rend.c index 3de67f9fd..351670c42 100644 --- a/lib_rend/lib_rend.c +++ b/lib_rend/lib_rend.c @@ -7535,6 +7535,22 @@ static ivas_error getSamplesInternal( int16_t i, ro_md_flag; float *tmpBinaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS], tmpBinaural_buff[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k]; +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + // TODO(sgi): This doesn't match the original MR. BASOP main too far behind. + float *p_Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX]; + float *p_Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX]; + int16_t j; + + for ( i = 0; i < BINAURAL_CHANNELS * MAX_HEAD_ROT_POSES; ++i ) + { + for ( j = 0; j < CLDFB_NO_COL_MAX; ++j ) + { + p_Cldfb_RealBuffer_Binaural[i][j] = Cldfb_RealBuffer_Binaural[i][j]; + p_Cldfb_ImagBuffer_Binaural[i][j] = Cldfb_ImagBuffer_Binaural[i][j]; + } + } +#endif + for ( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ ) { tmpBinaural[ch] = tmpBinaural_buff[ch]; @@ -7571,8 +7587,13 @@ static ivas_error getSamplesInternal( hIvasRend->hRendererConfig->split_rend_config.isar_frame_size_ms, hIvasRend->hRendererConfig->split_rend_config.codec_frame_size_ms, &bits, - Cldfb_RealBuffer_Binaural, - Cldfb_ImagBuffer_Binaural, +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + p_Cldfb_RealBuffer_Binaural, + p_Cldfb_ImagBuffer_Binaural, +#else + Cldfb_RealBuffer_Binaural, + Cldfb_ImagBuffer_Binaural, +#endif ( const int16_t )( ( BINAURAL_MAXBANDS * hIvasRend->sampleRateOut ) / 48000 ), tmpBinaural, 1, -- GitLab From 9f8e0b3e05273f50ee2814dba905cdbbf912b44e Mon Sep 17 00:00:00 2001 From: Kacper Sagnowski Date: Thu, 30 Oct 2025 20:45:50 +0100 Subject: [PATCH 03/11] Align changes with port 369 --- Workspace_msvc/lib_rend.vcxproj | 1 + apps/renderer.c | 114 +++-- lib_rend/ivas_prot_rend.h | 20 +- lib_rend/ivas_stat_rend.h | 10 +- lib_rend/ivas_td_ring_buffer.c | 69 +-- lib_rend/lib_rend.c | 858 ++++++++++++++++++++++---------- lib_rend/lib_rend.h | 31 +- 7 files changed, 731 insertions(+), 372 deletions(-) diff --git a/Workspace_msvc/lib_rend.vcxproj b/Workspace_msvc/lib_rend.vcxproj index 55f598ecf..1d55ed194 100644 --- a/Workspace_msvc/lib_rend.vcxproj +++ b/Workspace_msvc/lib_rend.vcxproj @@ -176,6 +176,7 @@ + diff --git a/apps/renderer.c b/apps/renderer.c index e57df6db7..91a6021f1 100644 --- a/apps/renderer.c +++ b/apps/renderer.c @@ -33,6 +33,7 @@ #include "lib_rend.h" #include #include +#include #include #include "audio_file_reader.h" #include "audio_file_writer.h" @@ -190,7 +191,7 @@ typedef struct float lfeConfigElevation; bool lfeCustomRoutingEnabled; char inLfePanningMatrixFile[RENDERER_MAX_CLI_ARG_LENGTH]; - float syncMdDelay; + int16_t syncMdDelay; IVAS_RENDER_FRAMESIZE render_framesize; uint16_t directivityPatternId[RENDERER_MAX_ISM_INPUTS]; AcousticEnvironmentSequence aeSequence; @@ -720,6 +721,7 @@ int main( SplitFileReadWrite *hSplitRendFileReadWrite; int16_t delayNumSamples_temp; int32_t delayTimeScale_temp; + bool flushRendererLastFrame = false; int16_t numSamplesRead; int16_t delayNumSamples = -1; int16_t delayNumSamples_orig = 0; @@ -766,8 +768,11 @@ int main( CmdlnArgs args = parseCmdlnArgs( argc, argv ); - if ( args.nonDiegeticPan && !( ( args.inConfig.numAudioObjects == 0 && args.inConfig.multiChannelBuses[0].audioConfig == IVAS_AUDIO_CONFIG_MONO ) || - ( args.inConfig.numAudioObjects > 0 && args.inConfig.audioObjects[0].audioConfig == IVAS_AUDIO_CONFIG_OBA && args.inConfig.numAudioObjects == 1 ) ) ) + if ( args.nonDiegeticPan && + !( ( args.inConfig.numAudioObjects == 0 && + args.inConfig.multiChannelBuses[0].audioConfig == IVAS_AUDIO_CONFIG_MONO ) || + ( args.inConfig.numAudioObjects > 0 && + args.inConfig.audioObjects[0].audioConfig == IVAS_AUDIO_CONFIG_OBA && args.inConfig.numAudioObjects == 1 ) ) ) { fprintf( stderr, "\ninvalid configuration - non-diegetic panning requires mono or ISM1 input\n" ); goto cleanup; @@ -1088,7 +1093,10 @@ int main( IVAS_RENDER_CONFIG_DATA renderConfig; #endif /* sanity check */ - if ( ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL ) && ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) && ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) && !is_split_pre_rend_mode( &args ) ) + if ( ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL ) && + ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) && + ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) && + !is_split_pre_rend_mode( &args ) ) { fprintf( stderr, "\nExternal Renderer Config is supported only when binaural output configurations is used as output OR when Split pre-rendering mode is enabled. Exiting. \n" ); goto cleanup; @@ -1402,7 +1410,7 @@ int main( } int16_t numOutChannels; - if ( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_GetNumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nError in IVAS_REND_NumOutChannels(): %s\n", ivas_error_to_string( error ) ); goto cleanup; @@ -1417,8 +1425,16 @@ int main( } } - if ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) + if ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) { + char *outFile = args.outMetadataFilePath; + + if ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) + { + outFile = args.outputFilePath; + audioWriter = NULL; + } + if ( ( error = IVAS_REND_GetSplitRendBitstreamHeader( hIvasRend, &bitsBuffer.config.codec, &bitsBuffer.config.poseCorrection, &bitsBuffer.config.codec_frame_size_ms, &bitsBuffer.config.isar_frame_size_ms ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nError in IVAS_REND_GetSplitRendBitstreamHeader()!\n" ); @@ -1431,36 +1447,15 @@ int main( goto cleanup; } - if ( ( error = split_rend_writer_open( &hSplitRendFileReadWrite, args.outputFilePath, delayNumSamples_temp, delayTimeScale_temp, bitsBuffer.config.codec, bitsBuffer.config.poseCorrection, bitsBuffer.config.codec_frame_size_ms, bitsBuffer.config.isar_frame_size_ms, args.sampleRate, bitsBuffer.config.lc3plus_highres ) ) != IVAS_ERR_OK ) + if ( ( error = split_rend_writer_open( &hSplitRendFileReadWrite, outFile, delayNumSamples_temp, delayTimeScale_temp, bitsBuffer.config.codec, bitsBuffer.config.poseCorrection, bitsBuffer.config.codec_frame_size_ms, bitsBuffer.config.isar_frame_size_ms, args.sampleRate, bitsBuffer.config.lc3plus_highres ) ) != IVAS_ERR_OK ) { - fprintf( stderr, "\nCould not open split rend metadata file %s\n", args.outputFilePath ); + fprintf( stderr, "\nCould not open split rend metadata file %s\n", outFile ); goto cleanup; } - audioWriter = NULL; } - else - { - if ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) - { - if ( ( error = IVAS_REND_GetSplitRendBitstreamHeader( hIvasRend, &bitsBuffer.config.codec, &bitsBuffer.config.poseCorrection, &bitsBuffer.config.codec_frame_size_ms, &bitsBuffer.config.isar_frame_size_ms ) ) != IVAS_ERR_OK ) - { - fprintf( stderr, "\nError in IVAS_REND_GetSplitRendBitstreamHeader()!\n" ); - goto cleanup; - } - - if ( IVAS_REND_GetDelay( hIvasRend, &delayNumSamples_temp, &delayTimeScale_temp ) != IVAS_ERR_OK ) - { - fprintf( stderr, "\nUnable to get delay of renderer!\n" ); - goto cleanup; - } - - if ( ( error = split_rend_writer_open( &hSplitRendFileReadWrite, args.outMetadataFilePath, delayNumSamples_temp, delayTimeScale_temp, bitsBuffer.config.codec, bitsBuffer.config.poseCorrection, bitsBuffer.config.codec_frame_size_ms, bitsBuffer.config.isar_frame_size_ms, args.sampleRate, bitsBuffer.config.lc3plus_highres ) ) != IVAS_ERR_OK ) - { - fprintf( stderr, "\nCould not open split rend metadata file %s\n", args.outMetadataFilePath ); - goto cleanup; - } - } + if ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) + { if ( AudioFileWriter_open( &audioWriter, args.outputFilePath, args.sampleRate, numOutChannels ) != IVAS_ERR_OK ) { fprintf( stderr, "\nFailed to open file: %s\n", args.outputFilePath ); @@ -1590,16 +1585,23 @@ int main( if ( numSamplesRead == 0 ) { /* end of input data */ - break; + flushRendererLastFrame = true; } /* Convert from int to float and from interleaved to packed */ - convertInputBuffer( inpInt16Buffer, numSamplesRead, inBuffer.config.numSamplesPerChannel, num_in_channels, inFloatBuffer, inBuffer.config.is_cldfb, cldfbAna ); + if ( !flushRendererLastFrame ) + { + convertInputBuffer( inpInt16Buffer, numSamplesRead, inBuffer.config.numSamplesPerChannel, num_in_channels, inFloatBuffer, inBuffer.config.is_cldfb, cldfbAna ); + } + else + { + memset( inBuffer.data, 0, inBuffer.config.numChannels * inBuffer.config.numSamplesPerChannel * sizeof( float ) ); + } int16_t num_subframes, sf_idx; num_subframes = (int16_t) args.render_framesize; - if ( isCurrentFrameMultipleOf20ms ) + if ( isCurrentFrameMultipleOf20ms && !flushRendererLastFrame ) { IsmPositionProvider_getNextFrame( positionProvider, &mtdBuffer ); @@ -1711,7 +1713,7 @@ int main( } IVAS_REND_ReadOnlyAudioBuffer tmpBuffer = getReadOnlySubBuffer( inBuffer, (int16_t) args.inConfig.multiChannelBuses[i].inputChannelIndex, numChannels ); - if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, mcIds[i], tmpBuffer ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, mcIds[i], tmpBuffer, flushRendererLastFrame ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nIVAS_REND_FeedInputAudio failed: %s\n", ivas_error_to_string( error ) ); goto cleanup; @@ -1726,7 +1728,7 @@ int main( { IVAS_REND_ReadOnlyAudioBuffer tmpBuffer = getReadOnlySubBuffer( inBuffer, (int16_t) args.inConfig.audioObjects[i].inputChannelIndex, args.inConfig.numAudioObjects ); - if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, ismIds[i], tmpBuffer ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, ismIds[i], tmpBuffer, flushRendererLastFrame ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nIVAS_REND_FeedInputAudio failed: %s\n", ivas_error_to_string( error ) ); goto cleanup; @@ -1743,7 +1745,7 @@ int main( { IVAS_REND_ReadOnlyAudioBuffer tmpBuffer = getReadOnlySubBuffer( inBuffer, (int16_t) args.inConfig.audioObjects[i].inputChannelIndex, 1 ); - if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, ismIds[i], tmpBuffer ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, ismIds[i], tmpBuffer, flushRendererLastFrame ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nIVAS_REND_FeedInputAudio failed: %s\n", ivas_error_to_string( error ) ); goto cleanup; @@ -1766,7 +1768,7 @@ int main( } IVAS_REND_ReadOnlyAudioBuffer tmpBuffer = getReadOnlySubBuffer( inBuffer, (int16_t) args.inConfig.ambisonicsBuses[i].inputChannelIndex, numChannels ); - if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, sbaIds[i], tmpBuffer ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, sbaIds[i], tmpBuffer, flushRendererLastFrame ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nIVAS_REND_FeedInputAudio failed: %s\n", ivas_error_to_string( error ) ); goto cleanup; @@ -1782,13 +1784,13 @@ int main( } IVAS_REND_ReadOnlyAudioBuffer tmpBuffer = getReadOnlySubBuffer( inBuffer, (int16_t) args.inConfig.masaBuses[i].inputChannelIndex, numChannels ); - if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, masaIds[i], tmpBuffer ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, masaIds[i], tmpBuffer, flushRendererLastFrame ) ) != IVAS_ERR_OK ) { fprintf( stderr, "IVAS_REND_FeedInputAudio failed: %s\n", ivas_error_to_string( error ) ); goto cleanup; } - if ( isCurrentFrameMultipleOf20ms ) + if ( isCurrentFrameMultipleOf20ms && !flushRendererLastFrame ) { if ( masaReaders[i] != NULL ) { @@ -1851,7 +1853,7 @@ int main( zeroPad = delayNumSamples; } - if ( is_split_pre_rend_mode( &args ) ) + if ( is_split_pre_rend_mode( &args ) && !flushRendererLastFrame ) { if ( split_rend_write_bitstream_to_file( hSplitRendFileReadWrite, bitsBuffer.bits, &bitsBuffer.config.bitsRead, &bitsBuffer.config.bitsWritten ) != IVAS_ERR_OK ) @@ -1861,7 +1863,7 @@ int main( } } - if ( audioWriter != NULL ) + if ( audioWriter != NULL && !flushRendererLastFrame ) { if ( delayNumSamples * num_out_channels < outBufferSize ) { @@ -1882,7 +1884,7 @@ int main( bitsBuffer.config.bitsWritten = 0; /* Write MASA metadata for MASA outputs */ - if ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_MASA1 || args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_MASA2 ) + if ( !flushRendererLastFrame && ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_MASA1 || args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_MASA2 ) ) { IVAS_REND_AudioConfigType inputType1; IVAS_REND_AudioConfigType inputType2; @@ -1954,7 +1956,8 @@ int main( } } - if ( ( args.inConfig.numAmbisonicsBuses > 0 || args.inConfig.numMultiChannelBuses > 0 || args.inConfig.numMasaBuses > 0 ) && args.inConfig.numAudioObjects > 0 ) + if ( ( args.inConfig.numAmbisonicsBuses > 0 || args.inConfig.numMultiChannelBuses > 0 || args.inConfig.numMasaBuses > 0 ) && + args.inConfig.numAudioObjects > 0 ) { inputType2 = IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED; if ( ( error = IVAS_REND_MergeMasaMetadata( hIvasRend, &hMetaOutput, inputType1, inputType2 ) ) != IVAS_ERR_OK ) @@ -1970,6 +1973,13 @@ int main( } } + /* no new input was actually read, only delay buffers were flushed + * therefore this is not a real frame */ + if ( flushRendererLastFrame ) + { + break; + } + frame++; if ( !args.quietModeEnabled ) { @@ -1982,12 +1992,13 @@ int main( #endif } - /* add zeros at the end to have equal length of synthesized signals */ + /* add zeros at the end to have equal length of synthesized signals + * the output buffer will contain either leftover input samples from delay aligned inputs + * or zeros for padding */ if ( audioWriter != NULL ) { for ( zeroPadToWrite = zeroPad; zeroPadToWrite > frameSize_smpls; zeroPadToWrite -= frameSize_smpls ) { - memset( outInt16Buffer, 0, outBufferSize * sizeof( int16_t ) ); if ( ( error = AudioFileWriter_write( audioWriter, outInt16Buffer, outBufferSize ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nOutput audio file writer error\n" ); @@ -1995,7 +2006,6 @@ int main( } } - memset( outInt16Buffer, 0, zeroPadToWrite * outBuffer.config.numChannels * sizeof( int16_t ) ); if ( ( error = AudioFileWriter_write( audioWriter, outInt16Buffer, zeroPadToWrite * outBuffer.config.numChannels ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nOutput audio file writer error\n" ); @@ -2004,9 +2014,10 @@ int main( zeroPadToWrite = 0; } - if ( args.inConfig.numAudioObjects != 0 && ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL || args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) ) + if ( args.inConfig.numAudioObjects != 0 && + ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL || args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) ) { - fprintf( stdout, "\n\nMetadata delayed %d subframes\n\n", (int16_t) round( args.syncMdDelay / ( 1000 / IVAS_NUM_FRAMES_PER_SEC / IVAS_MAX_PARAM_SPATIAL_SUBFRAMES ) ) ); + fprintf( stdout, "\n\nMetadata delayed %d subframes\n\n", (int16_t) round( args.syncMdDelay / ( 1000.f / IVAS_NUM_FRAMES_PER_SEC / IVAS_MAX_PARAM_SPATIAL_SUBFRAMES ) ) ); } if ( !args.quietModeEnabled && args.delayCompensationEnabled ) @@ -2917,7 +2928,7 @@ static void parseOption( case CmdLnOptionId_syncMdDelay: assert( numOptionValues == 1 ); /* Metadata Delay to sync with audio delay in ms */ - args->syncMdDelay = strtof( optionValues[0], NULL ); + args->syncMdDelay = (int16_t) strtol( optionValues[0], NULL, 10 ); break; default: assert( 0 && "This should be unreachable - all command line options should be explicitly handled." ); @@ -3400,7 +3411,8 @@ static void parseObjectPosition( *positionDuration = (uint16_t) strtol( line, &endptr, 10 ); readNextMetadataChunk( line, "\n" ); - read_values = (int16_t) sscanf( line, "%f,%f,%f,%f,%f,%f,%f,%f", &meta_prm[0], &meta_prm[1], &meta_prm[2], &meta_prm[3], &meta_prm[4], &meta_prm[5], &meta_prm[6], &meta_prm[7] ); + read_values = (int16_t) sscanf( line, "%f,%f,%f,%f,%f,%f,%f,%f", + &meta_prm[0], &meta_prm[1], &meta_prm[2], &meta_prm[3], &meta_prm[4], &meta_prm[5], &meta_prm[6], &meta_prm[7] ); if ( read_values < 2 ) { diff --git a/lib_rend/ivas_prot_rend.h b/lib_rend/ivas_prot_rend.h index 54b11994b..d20958172 100644 --- a/lib_rend/ivas_prot_rend.h +++ b/lib_rend/ivas_prot_rend.h @@ -1599,8 +1599,8 @@ void ivas_rend_closeCldfbRend( ivas_error ivas_TD_RINGBUF_Open( TD_RINGBUF_HANDLE *ph, /* i/o: Ring buffer handle */ - const uint32_t capacity_per_channel, /* i : Number of samples stored per channel */ - const uint16_t num_channels /* i : Number of channels */ + const int16_t capacity_per_channel, /* i : Number of samples stored per channel */ + const int16_t num_channels /* i : Number of channels */ ); void ivas_TD_RINGBUF_Close( @@ -1611,46 +1611,46 @@ void ivas_TD_RINGBUF_Close( void ivas_TD_RINGBUF_PushInterleaved( TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ const float *data, /* i : Input audio in interleaved channels layout */ - const uint32_t num_samples_per_channel /* i : Number of samples per channel to push */ + const int16_t num_samples_per_channel /* i : Number of samples per channel to push */ ); void ivas_TD_RINGBUF_PushChannels( TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ const float *p_channels[], /* i : Array of pointers to each input channel */ - const uint32_t num_samples_per_channel /* i : Number of samples per channel to store */ + const int16_t num_samples_per_channel /* i : Number of samples per channel to store */ ); void ivas_TD_RINGBUF_PushConstant( TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ const float value, /* i : Value to push */ - const uint32_t num_samples_per_channel /* i : Number of samples per channel to push */ + const int16_t num_samples_per_channel /* i : Number of samples per channel to push */ ); void ivas_TD_RINGBUF_PopChannels( TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ float *p_channels[], /* i : Array of pointers to each output channel */ - const uint32_t num_samples_per_channel /* i : Number of samples per channel to pop */ + const int16_t num_samples_per_channel /* i : Number of samples per channel to pop */ ); #else void ivas_TD_RINGBUF_Push( TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ const float *data, /* i : Input data */ - const uint32_t num_samples_per_channel /* i : Number of samples per channel to store */ + const uint16_t num_samples_per_channel /* i : Number of samples per channel to store */ ); void ivas_TD_RINGBUF_PushZeros( TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ - const uint32_t num_samples_per_channel /* i : Number of zeros per channel to store */ + const uint16_t num_samples_per_channel /* i : Number of zeros per channel to store */ ); void ivas_TD_RINGBUF_Pop( TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ float *data, /* i : Output data */ - const uint32_t num_samples_per_channel /* i : Number of samples per channel to retrieve*/ + const uint16_t num_samples_per_channel /* i : Number of samples per channel to retrieve*/ ); #endif -uint32_t ivas_TD_RINGBUF_Size( +int16_t ivas_TD_RINGBUF_Size( const TD_RINGBUF_HANDLE h /* i : Ring buffer handle */ ); diff --git a/lib_rend/ivas_stat_rend.h b/lib_rend/ivas_stat_rend.h index 6b6cff629..451a60d1a 100644 --- a/lib_rend/ivas_stat_rend.h +++ b/lib_rend/ivas_stat_rend.h @@ -1381,11 +1381,11 @@ typedef struct typedef struct { - float *data; /* samples in interleaved layout */ - uint32_t capacity; - uint16_t num_channels; - uint32_t write_pos; - uint32_t read_pos; + float *data; /* samples in interleaved layout, e.g. for channels A, B, C, samples are stored: A1, B1, C1, A2, B2, C2, ... */ + int32_t capacity; /* max number of float values that can be stored */ + int16_t num_channels; + int32_t write_pos; + int32_t read_pos; int16_t is_full; } TD_RINGBUF_DATA, *TD_RINGBUF_HANDLE; diff --git a/lib_rend/ivas_td_ring_buffer.c b/lib_rend/ivas_td_ring_buffer.c index f1fdab3af..c1aa84a9b 100644 --- a/lib_rend/ivas_td_ring_buffer.c +++ b/lib_rend/ivas_td_ring_buffer.c @@ -31,6 +31,7 @@ *******************************************************************************************************/ #include +#include #include #include "ivas_error_utils.h" #include "ivas_prot_rend.h" @@ -42,7 +43,13 @@ * Local function prototypes *-----------------------------------------------------------------------*/ -static uint32_t ivas_td_ringbuf_total_size( +/*---------------------------------------------------------------------* + * ivas_td_ringbuf_total_size() + * + * Returns total number of buffered samples (including number of channels) + *---------------------------------------------------------------------*/ + +static int32_t ivas_td_ringbuf_total_size( TD_RINGBUF_HANDLE h ) { if ( h->is_full ) @@ -61,7 +68,7 @@ static uint32_t ivas_td_ringbuf_total_size( static int16_t ivas_td_ringbuf_has_space_for_num_samples( TD_RINGBUF_HANDLE h, - const uint32_t num_samples ) + const int32_t num_samples ) { return (int16_t) ( ivas_td_ringbuf_total_size( h ) + num_samples <= h->capacity ); } @@ -71,18 +78,18 @@ static int16_t ivas_td_ringbuf_has_space_for_num_samples( static void ivas_td_ringbuf_push_interleaved( TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ const float *data, /* i : Input audio in interleaved channels layout */ - const uint32_t num_samples_per_channel, /* i : Number of samples per channel to push */ - const uint16_t read_stride /* i: : 1 for normal operation, 0 for reading from a single input value */ + const int16_t num_samples_per_channel, /* i : Number of samples per channel to push */ + const int16_t read_stride /* i: : 1 for normal operation, 0 for reading from a single input value */ ) { - uint32_t s, read_s; + int32_t s, read_s; assert( h != NULL ); assert( data != NULL ); assert( read_stride == 0 || read_stride == 1 ); - assert( ivas_td_ringbuf_has_space_for_num_samples( h, num_samples_per_channel * h->num_channels ) ); + assert( ivas_td_ringbuf_has_space_for_num_samples( h, (int32_t) num_samples_per_channel * h->num_channels ) ); - for ( s = 0, read_s = 0; s < num_samples_per_channel * h->num_channels; ++s, read_s += read_stride ) + for ( s = 0, read_s = 0; s < (int32_t) num_samples_per_channel * h->num_channels; ++s, read_s += read_stride ) { h->data[h->write_pos] = data[read_s]; ++h->write_pos; @@ -110,21 +117,21 @@ static void ivas_td_ringbuf_push_interleaved( /*---------------------------------------------------------------------* * ivas_TD_RINGBUF_Open() * - * Allocate a ring buffer for TD data with the given capacity of TD samples per channel. + * Allocates a ring buffer for TD data with the given capacity of TD samples per channel. * * May return IVAS_ERR_FAILED_ALLOC on failed allocation, or IVAS_ERR_OK otherwise. *---------------------------------------------------------------------*/ ivas_error ivas_TD_RINGBUF_Open( TD_RINGBUF_HANDLE *ph, /* i/o: Ring buffer handle */ - const uint32_t capacity_per_channel, /* i : Number of samples stored per channel */ - const uint16_t num_channels /* i : Number of channels */ + const int16_t capacity_per_channel, /* i : Number of samples stored per channel */ + const int16_t num_channels /* i : Number of channels */ ) { TD_RINGBUF_HANDLE h; - uint32_t capacity; + int32_t capacity; - capacity = capacity_per_channel * num_channels; + capacity = (int32_t) capacity_per_channel * num_channels; h = malloc( sizeof( TD_RINGBUF_DATA ) ); if ( h == NULL ) @@ -153,8 +160,7 @@ ivas_error ivas_TD_RINGBUF_Open( /*---------------------------------------------------------------------* * ivas_TD_RINGBUF_Close() * - * Dellocate TD ring buffer. The given handle will be set to NULL. - + * Dellocates TD ring buffer. The given handle will be set to NULL. *---------------------------------------------------------------------*/ void ivas_TD_RINGBUF_Close( @@ -190,13 +196,13 @@ void ivas_TD_RINGBUF_Close( /*---------------------------------------------------------------------* * ivas_TD_RINGBUF_PushInterleaved() * - * Push samples from a buffer with interleaved channel layout onto the back of the TD ring buffer. + * Pushes samples from a buffer with interleaved channel layout onto the back of the TD ring buffer. *---------------------------------------------------------------------*/ void ivas_TD_RINGBUF_PushInterleaved( TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ const float *data, /* i : Input audio in interleaved channels layout */ - const uint32_t num_samples_per_channel /* i : Number of samples per channel to push */ + const int16_t num_samples_per_channel /* i : Number of samples per channel to push */ ) { ivas_td_ringbuf_push_interleaved( h, data, num_samples_per_channel, 1 ); @@ -214,7 +220,7 @@ void ivas_TD_RINGBUF_PushInterleaved( void ivas_TD_RINGBUF_PushChannels( TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ const float *p_channels[], /* i : Array of pointers to each input channel */ - const uint32_t num_samples_per_channel /* i : Number of samples per channel to push */ + const int16_t num_samples_per_channel /* i : Number of samples per channel to push */ ) #else /*---------------------------------------------------------------------* @@ -227,12 +233,12 @@ void ivas_TD_RINGBUF_PushChannels( void ivas_TD_RINGBUF_Push( TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ const float *data, /* i : Input data */ - const uint32_t num_samples_per_channel /* i : Number of samples per channel to store */ + const uint16_t num_samples_per_channel /* i : Number of samples per channel to store */ ) #endif { - uint32_t s; - uint16_t c; + int32_t s; + int16_t c; #ifdef FIX_1119_SPLIT_RENDERING_VOIP assert( h != NULL ); @@ -242,7 +248,7 @@ void ivas_TD_RINGBUF_Push( assert( p_channels[c] != NULL ); } #endif - assert( ivas_td_ringbuf_has_space_for_num_samples( h, num_samples_per_channel * h->num_channels ) ); + assert( ivas_td_ringbuf_has_space_for_num_samples( h, (int32_t) num_samples_per_channel * h->num_channels ) ); for ( s = 0; s < num_samples_per_channel; ++s ) { @@ -281,7 +287,7 @@ void ivas_TD_RINGBUF_Push( void ivas_TD_RINGBUF_PushConstant( TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ const float value, /* i : Value to push */ - const uint32_t num_samples_per_channel /* i : Number of samples per channel to push */ + const int16_t num_samples_per_channel /* i : Number of samples per channel to push */ ) { ivas_td_ringbuf_push_interleaved( h, &value, num_samples_per_channel, 0 ); @@ -297,11 +303,10 @@ void ivas_TD_RINGBUF_PushConstant( void ivas_TD_RINGBUF_PushZeros( TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ - const uint32_t num_samples_per_channel /* i : Number of zeros per channel to store */ + const uint16_t num_samples_per_channel /* i : Number of zeros per channel to store */ ) { - uint32_t s; - uint16_t c; + uint16_t c, s; assert( ivas_td_ringbuf_has_space_for_num_samples( h, num_samples_per_channel * h->num_channels ) ); if ( !num_samples_per_channel ) @@ -343,7 +348,7 @@ void ivas_TD_RINGBUF_PushZeros( void ivas_TD_RINGBUF_PopChannels( TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ float *p_channels[], /* i : Array of pointers to each output channel */ - const uint32_t num_samples_per_channel /* i : Number of samples per channel to pop */ + const int16_t num_samples_per_channel /* i : Number of samples per channel to pop */ ) #else /*---------------------------------------------------------------------* @@ -355,12 +360,12 @@ void ivas_TD_RINGBUF_PopChannels( void ivas_TD_RINGBUF_Pop( TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ float *data, /* i : Output data */ - const uint32_t num_samples_per_channel /* i : Number of samples per channel to retrieve */ + const uint16_t num_samples_per_channel /* i : Number of samples per channel to retrieve */ ) #endif { - uint32_t s; - uint16_t c; + int32_t s; + int16_t c; #ifdef FIX_1119_SPLIT_RENDERING_VOIP assert( h != NULL ); @@ -370,7 +375,7 @@ void ivas_TD_RINGBUF_Pop( assert( p_channels[c] != NULL ); } #endif - assert( ivas_td_ringbuf_total_size( h ) >= num_samples_per_channel * h->num_channels ); + assert( ivas_td_ringbuf_total_size( h ) >= (int32_t) num_samples_per_channel * h->num_channels ); for ( s = 0; s < num_samples_per_channel; ++s ) { @@ -412,9 +417,9 @@ void ivas_TD_RINGBUF_Pop( * Returns number of buffered samples per channel. *---------------------------------------------------------------------*/ -uint32_t ivas_TD_RINGBUF_Size( +int16_t ivas_TD_RINGBUF_Size( const TD_RINGBUF_HANDLE h /* i : Ring buffer handle */ ) { - return ivas_td_ringbuf_total_size( h ) / (uint32_t) h->num_channels; + return (int16_t) ( ivas_td_ringbuf_total_size( h ) / h->num_channels ); } diff --git a/lib_rend/lib_rend.c b/lib_rend/lib_rend.c index 12568c4c8..29c486187 100644 --- a/lib_rend/lib_rend.c +++ b/lib_rend/lib_rend.c @@ -44,6 +44,7 @@ #include #include #include "wmc_auto.h" +#include /*-------------------------------------------------------------------* @@ -81,6 +82,7 @@ typedef struct typedef struct { const int32_t *pOutSampleRate; + const int32_t *pMaxGlobalDelayNs; const AUDIO_CONFIG *pOutConfig; const LSSETUP_CUSTOM_STRUCT *pCustomLsOut; const EFAP_WRAPPER *pEfapOutWrapper; @@ -97,9 +99,11 @@ typedef struct AUDIO_CONFIG inConfig; IVAS_REND_InputId id; IVAS_REND_AudioBuffer inputBuffer; + TD_RINGBUF_HANDLE delayBuffer; float gain; /* Linear, not in dB */ rendering_context ctx; int32_t numNewSamplesPerChannel; /* Used to keep track how much new audio was fed before rendering current frame */ + int16_t delayNumSamples; } input_base; typedef struct @@ -122,7 +126,7 @@ typedef struct #ifdef NONBE_1377_REND_DIRATT_CONF int16_t object_id; #endif - float ism_metadata_delay_ms; + int16_t ism_metadata_delay_ms; } input_ism; typedef struct @@ -192,6 +196,7 @@ typedef struct hrtf_handles struct IVAS_REND { int32_t sampleRateOut; + int32_t maxGlobalDelayNs; IVAS_LIMITER_HANDLE hLimiter; #ifdef DEBUGGING @@ -207,11 +212,12 @@ struct IVAS_REND AUDIO_CONFIG outputConfig; EFAP_WRAPPER efapOutWrapper; IVAS_LSSETUP_CUSTOM_STRUCT customLsOut; + + int16_t splitRendBFI; SPLIT_REND_WRAPPER *splitRendWrapper; IVAS_REND_AudioBuffer splitRendEncBuffer; IVAS_REND_HeadRotData headRotData; - int16_t splitRendBFI; EXTERNAL_ORIENTATION_HANDLE hExternalOrientationData; COMBINED_ORIENTATION_HANDLE hCombinedOrientationData; @@ -262,6 +268,13 @@ static void freeInputBaseBufferData( return; } +static int16_t latencyNsToSamples( + int32_t sampleRate, + int32_t latency_ns ) +{ + return (int16_t) roundf( (float) ( latency_ns ) * ( sampleRate / 1000000000.f ) ); +} + static ivas_error allocateMcLfeDelayBuffer( float **lfeDelayBuffer, const int16_t data_size ) @@ -369,7 +382,7 @@ static void copyBufferToCLDFBarray( static void accumulateCLDFBArrayToBuffer( float re[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], float im[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], - IVAS_REND_AudioBuffer *buffer ) + const IVAS_REND_AudioBuffer *buffer ) { uint32_t smplIdx, slotIdx; uint32_t numCldfbSamples, num_bands; @@ -1165,6 +1178,8 @@ static void initRendInputBase( inputBase->gain = 1.0f; inputBase->ctx = rendCtx; inputBase->numNewSamplesPerChannel = 0; + inputBase->delayNumSamples = 0; + inputBase->delayBuffer = NULL; inputBase->inputBuffer.config.numSamplesPerChannel = 0; inputBase->inputBuffer.config.numChannels = 0; @@ -1213,6 +1228,7 @@ static rendering_context getRendCtx( /* Note: when refactoring this, always take the ADDRESS of a member of the * renderer struct, so that the context stores a POINTER to the member, even * if the member is a pointer or handle itself. */ + ctx.pMaxGlobalDelayNs = &hIvasRend->maxGlobalDelayNs; ctx.pOutConfig = &hIvasRend->outputConfig; ctx.pOutSampleRate = &hIvasRend->sampleRateOut; ctx.pCustomLsOut = &hIvasRend->customLsOut; @@ -1255,6 +1271,294 @@ static bool isIoConfigPairSupported( } +static int32_t getRendInputDelayIsm( + const input_ism *inputIsm, + bool splitPreRendCldfb ) +{ + int32_t latency_ns; + latency_ns = 0; + (void) ( splitPreRendCldfb ); /* unused */ + + /* set the rendering delay in InputBase */ + latency_ns = max( latency_ns, + inputIsm->tdRendWrapper.binaural_latency_ns ); + if ( inputIsm->crendWrapper != NULL ) + { + latency_ns = max( latency_ns, + inputIsm->crendWrapper->binaural_latency_ns ); + } + + return latency_ns; +} + + +static void setRendInputDelayIsm( + void *input, + bool splitPreRendCldfb ) +{ + input_ism *inputIsm; + inputIsm = (input_ism *) input; + + inputIsm->base.delayNumSamples = latencyNsToSamples( *inputIsm->base.ctx.pOutSampleRate, + getRendInputDelayIsm( inputIsm, splitPreRendCldfb ) ); +} + + +static int32_t getRendInputDelayMc( + const input_mc *inputMc, + bool splitPreRendCldfb ) +{ + int32_t latency_ns; + latency_ns = 0; + (void) ( splitPreRendCldfb ); /* unused */ + + latency_ns = max( latency_ns, + inputMc->tdRendWrapper.binaural_latency_ns ); + if ( inputMc->crendWrapper != NULL ) + { + latency_ns = max( latency_ns, + inputMc->crendWrapper->binaural_latency_ns ); + } + + return latency_ns; +} + + +static void setRendInputDelayMc( + void *input, + bool splitPreRendCldfb ) +{ + input_mc *inputMc; + inputMc = (input_mc *) input; + + inputMc->base.delayNumSamples = latencyNsToSamples( *inputMc->base.ctx.pOutSampleRate, + getRendInputDelayMc( inputMc, splitPreRendCldfb ) ); +} + + +static int32_t getRendInputDelaySba( + const input_sba *inputSba, + bool splitPreRendCldfb ) +{ + int32_t latency_ns; + latency_ns = 0; + + if ( inputSba->cldfbRendWrapper.hCldfbRend != NULL ) + { + latency_ns = max( latency_ns, + inputSba->cldfbRendWrapper.binaural_latency_ns + + ( splitPreRendCldfb ? 0 : IVAS_FB_DEC_DELAY_NS ) ); + } + if ( inputSba->crendWrapper != NULL ) + { + latency_ns = max( latency_ns, + inputSba->crendWrapper->binaural_latency_ns ); + } + + return latency_ns; +} + + +static void setRendInputDelaySba( + void *input, + bool splitPreRendCldfb ) +{ + input_sba *inputSba; + inputSba = (input_sba *) input; + + inputSba->base.delayNumSamples = latencyNsToSamples( *inputSba->base.ctx.pOutSampleRate, + getRendInputDelaySba( inputSba, splitPreRendCldfb ) ); +} + + +static int32_t getRendInputDelayMasa( + const input_masa *inputMasa, + bool splitPreRendCldfb ) +{ + int32_t latency_ns; + + latency_ns = 0; + + if ( ( inputMasa->base.inConfig == IVAS_AUDIO_CONFIG_MASA1 && *inputMasa->base.ctx.pOutConfig == IVAS_AUDIO_CONFIG_MONO ) || + ( getAudioConfigType( *inputMasa->base.ctx.pOutConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) ) + { + return 0; /* no delay */ + } + else + { + /* no delay applied for split rendering */ + latency_ns = max( latency_ns, + (int32_t) ( ( splitPreRendCldfb ? 0 : (float) IVAS_FB_DEC_DELAY_NS + 0.5f ) ) ); + } + return latency_ns; +} + + +static void setRendInputDelayMasa( + void *input, + bool splitPreRendCldfb ) +{ + input_masa *inputMasa; + inputMasa = (input_masa *) input; + + inputMasa->base.delayNumSamples = latencyNsToSamples( *inputMasa->base.ctx.pOutSampleRate, + getRendInputDelayMasa( inputMasa, splitPreRendCldfb ) ); +} + + +static int32_t getMaxGlobalDelayNs( IVAS_REND_CONST_HANDLE hIvasRend ) +{ + int16_t i; + int32_t latency_ns; + int32_t max_latency_ns; + bool splitPreRendCldfb; + + max_latency_ns = 0; + /*assumes that input has been added which means codec has been set to either lcld or lc3plus (even if render config specified default)*/ + if ( hIvasRend->hRendererConfig != NULL ) + { + splitPreRendCldfb = ( hIvasRend->hRendererConfig->split_rend_config.codec == ISAR_SPLIT_REND_CODEC_LCLD ); + } + else + { + splitPreRendCldfb = false; + } + + /* Compute the maximum delay across all inputs */ + for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; i++ ) + { + if ( hIvasRend->inputsIsm[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) + { + latency_ns = getRendInputDelayIsm( &hIvasRend->inputsIsm[i], splitPreRendCldfb ); + max_latency_ns = max( max_latency_ns, latency_ns ); + } + } + + for ( i = 0; i < RENDERER_MAX_MC_INPUTS; i++ ) + { + if ( hIvasRend->inputsMc[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) + { + latency_ns = getRendInputDelayMc( &hIvasRend->inputsMc[i], splitPreRendCldfb ); + max_latency_ns = max( max_latency_ns, latency_ns ); + } + } + + for ( i = 0; i < RENDERER_MAX_SBA_INPUTS; i++ ) + { + if ( hIvasRend->inputsSba[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) + { + latency_ns = getRendInputDelaySba( &hIvasRend->inputsSba[i], splitPreRendCldfb ); + max_latency_ns = max( max_latency_ns, latency_ns ); + } + } + + for ( i = 0; i < RENDERER_MAX_MASA_INPUTS; i++ ) + { + if ( hIvasRend->inputsMasa[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) + { + latency_ns = getRendInputDelayMasa( &hIvasRend->inputsMasa[i], splitPreRendCldfb ); + max_latency_ns = max( max_latency_ns, latency_ns ); + } + } + + return max_latency_ns; +} + + +static void setMaxGlobalDelayNs( IVAS_REND_HANDLE hIvasRend ) +{ + hIvasRend->maxGlobalDelayNs = getMaxGlobalDelayNs( (IVAS_REND_CONST_HANDLE) hIvasRend ); +} + +static ivas_error alignInputDelay( + input_base *inputBase, + const IVAS_REND_ReadOnlyAudioBuffer inputAudio, + const int32_t maxGlobalDelayNs, + const int32_t sampleRateOut, + const int16_t cldfb2tdSampleFact, + const bool flushInputs ) +{ + ivas_error error; + input_ism *inputIsm; + int16_t maxGlobalDelaySamples, numSamplesToPop, numSamplesToPush; + uint16_t ringBufferSize, preDelay; +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + int16_t i; + const float *p_read_channels[MAX_INPUT_CHANNELS]; + float *p_write_channels[MAX_INPUT_CHANNELS]; +#endif + + maxGlobalDelaySamples = latencyNsToSamples( sampleRateOut, maxGlobalDelayNs ); + maxGlobalDelaySamples *= cldfb2tdSampleFact; + + /* check if we need to open the delay buffer */ + if ( inputBase->delayBuffer == NULL ) + { + /* buffer has to accomodate maxGlobalDelaySamples + 2 * frameSize */ + ringBufferSize = maxGlobalDelaySamples + 2 * inputAudio.config.numSamplesPerChannel; + + /* pre delay for this input is maximum delay - input delay */ + preDelay = maxGlobalDelaySamples - inputBase->delayNumSamples * cldfb2tdSampleFact; + + if ( preDelay > 0 ) + { + if ( ( error = ivas_TD_RINGBUF_Open( &inputBase->delayBuffer, ringBufferSize, inputAudio.config.numChannels ) ) != IVAS_ERR_OK ) + { + return error; + } + + /* for the first frame we need to push zeros to align the input delay to the global delay + * and then push a frame of actual data */ +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + ivas_TD_RINGBUF_PushConstant( inputBase->delayBuffer, 0, preDelay ); +#else + ivas_TD_RINGBUF_PushZeros( inputBase->delayBuffer, preDelay ); +#endif + + /* for ISM inputs, ensure the metadata sync delay is updated */ + if ( getAudioConfigType( inputBase->inConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) + { + inputIsm = (input_ism *) inputBase; + inputIsm->ism_metadata_delay_ms = (int16_t) roundf( inputIsm->ism_metadata_delay_ms + maxGlobalDelayNs / 1e6f ); + } + } + } + + if ( inputBase->delayBuffer != NULL ) + { + /* push in the new input data and pop to retrieve a complete input frame + * if we are flushing the inputs, we don't push in any new data */ + numSamplesToPush = flushInputs ? 0 : inputAudio.config.numSamplesPerChannel; + numSamplesToPop = flushInputs ? ivas_TD_RINGBUF_Size( inputBase->delayBuffer ) : inputAudio.config.numSamplesPerChannel; + +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + for ( i = -1; i < inputAudio.config.numChannels; ++i ) + { + p_read_channels[i] = inputAudio.data + i * numSamplesToPush; + } + ivas_TD_RINGBUF_PushChannels( inputBase->delayBuffer, p_read_channels, numSamplesToPush ); + + for ( i = 0; i < inputAudio.config.numChannels; ++i ) + { + p_write_channels[i] = inputBase->inputBuffer.data + i * numSamplesToPop; + } + ivas_TD_RINGBUF_PopChannels( inputBase->delayBuffer, p_write_channels, numSamplesToPop ); +#else + ivas_TD_RINGBUF_Push( inputBase->delayBuffer, inputAudio.data, numSamplesToPush ); + ivas_TD_RINGBUF_Pop( inputBase->delayBuffer, inputBase->inputBuffer.data, numSamplesToPop ); +#endif + } + else + { + /* delay buffer isn't open - we don't need it */ + mvr2r( inputAudio.data, + inputBase->inputBuffer.data, + inputAudio.config.numSamplesPerChannel * inputAudio.config.numChannels ); + } + + return IVAS_ERR_OK; +} + static ivas_error initIsmMasaRendering( input_ism *inputIsm, const int32_t inSampleRate ) @@ -1401,6 +1705,8 @@ static void clearInputIsm( rendCtx = inputIsm->base.ctx; freeInputBaseBufferData( &inputIsm->base.inputBuffer.data ); + ivas_TD_RINGBUF_Close( &inputIsm->base.delayBuffer ); + initRendInputBase( &inputIsm->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 ); /* Free input's internal handles */ @@ -2179,7 +2485,7 @@ static ivas_error initMcBinauralRendering( /* determine binaural delay ( used for aligning LFE to output signal ) */ binauralDelayNs = max( ( inputMc->crendWrapper != NULL ) ? inputMc->crendWrapper->binaural_latency_ns : 0, inputMc->tdRendWrapper.binaural_latency_ns ); - inputMc->binauralDelaySmp = (int16_t) roundf( (float) binauralDelayNs * *inputMc->base.ctx.pOutSampleRate / 1000000000.f ); + inputMc->binauralDelaySmp = latencyNsToSamples( *inputMc->base.ctx.pOutSampleRate, binauralDelayNs ); if ( inputMc->binauralDelaySmp > MAX_BIN_DELAY_SAMPLES ) { @@ -2378,6 +2684,8 @@ static void clearInputMc( freeMcLfeDelayBuffer( &inputMc->lfeDelayBuffer ); freeInputBaseBufferData( &inputMc->bufferData ); + ivas_TD_RINGBUF_Close( &inputMc->base.delayBuffer ); + initRendInputBase( &inputMc->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 ); /* Free input's internal handles */ @@ -2669,7 +2977,7 @@ static ivas_error setRendInputActiveSba( return error; } - return error; + return IVAS_ERR_OK; } @@ -2681,6 +2989,7 @@ static void clearInputSba( rendCtx = inputSba->base.ctx; freeInputBaseBufferData( &inputSba->bufferData ); + ivas_TD_RINGBUF_Close( &inputSba->base.delayBuffer ); initRendInputBase( &inputSba->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 ); @@ -2761,6 +3070,7 @@ static void clearInputMasa( rendCtx = inputMasa->base.ctx; freeInputBaseBufferData( &inputMasa->bufferData ); + ivas_TD_RINGBUF_Close( &inputMasa->base.delayBuffer ); masaPrerendClose( &inputMasa->hMasaPrerend ); freeMasaExtRenderer( &inputMasa->hMasaExtRend ); @@ -2829,7 +3139,7 @@ ivas_error IVAS_REND_Open( hIvasRend->num_subframes = num_subframes; /* Initialize limiter */ - if ( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_GetNumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK ) { return error; } @@ -2886,9 +3196,10 @@ ivas_error IVAS_REND_Open( isar_init_split_rend_handles( hIvasRend->splitRendWrapper ); } -#ifdef TEMP_FIX_2088_MSAN_INIT_ERROR hIvasRend->splitRendEncBuffer.data = NULL; -#endif + hIvasRend->splitRendEncBuffer.config.is_cldfb = 0; + hIvasRend->splitRendEncBuffer.config.numChannels = 0; + hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel = 0; for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i ) { @@ -3084,7 +3395,7 @@ ivas_error IVAS_REND_ConfigureCustomOutputLoudspeakerLayout( hIvasRend->customLsOut = makeCustomLsSetup( layout ); /* Re-initialize limiter - number of output channels may have changed */ - if ( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_GetNumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK ) { return error; } @@ -3141,12 +3452,12 @@ ivas_error IVAS_REND_ConfigureCustomOutputLoudspeakerLayout( /*-------------------------------------------------------------------* - * IVAS_REND_NumOutChannels() + * IVAS_REND_GetNumOutChannels() * * *-------------------------------------------------------------------*/ -ivas_error IVAS_REND_NumOutChannels( +ivas_error IVAS_REND_GetNumOutChannels( IVAS_REND_CONST_HANDLE hIvasRend, int16_t *numOutChannels ) { @@ -3414,10 +3725,15 @@ static int16_t getCldfbRendFlag( const IVAS_REND_AudioConfigType new_configType ) { int16_t i; - int16_t numMasaInputs = 0, numSbaInputs = 0, numIsmInputs = 0, numMcInputs = 0; + int16_t numMasaInputs = 0, numSbaInputs = 0; int16_t isCldfbRend; isCldfbRend = 0; + /* This function is called during three different phases of renderer processing: + * - IVAS_REND_AddInput() + * - IVAS_REND_FeedRenderConfig() + * - IVAS_REND_GetSplitBinauralBitstream() + * Only the last case can assume all inputs are present for the current frame to be rendered */ if ( hIvasRend->hRendererConfig != NULL ) { for ( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i ) @@ -3428,20 +3744,8 @@ static int16_t getCldfbRendFlag( { numSbaInputs += ( hIvasRend->inputsSba[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) ? 0 : 1; } - for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i ) - { - numIsmInputs += ( hIvasRend->inputsIsm[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) ? 0 : 1; - } - for ( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i ) - { - numMcInputs += ( hIvasRend->inputsMc[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) ? 0 : 1; - } - if ( numIsmInputs > 0 || numMcInputs > 0 ) - { - isCldfbRend = 0; - } - else if ( ( numMasaInputs > 0 ) || ( numSbaInputs > 0 && hIvasRend->hRendererConfig->split_rend_config.rendererSelection == IVAS_BIN_RENDERER_TYPE_FASTCONV ) ) + if ( ( numMasaInputs > 0 ) || ( numSbaInputs > 0 && hIvasRend->hRendererConfig->split_rend_config.rendererSelection == IVAS_BIN_RENDERER_TYPE_FASTCONV ) ) { isCldfbRend = 1; } @@ -3451,12 +3755,12 @@ static int16_t getCldfbRendFlag( } /*------------------------------------------------------------------------- - * Function ivas_pre_rend_init() + * Function isar_pre_rend_init() * * *------------------------------------------------------------------------*/ -static ivas_error ivas_pre_rend_init( +static ivas_error isar_pre_rend_init( SPLIT_REND_WRAPPER *pSplitRendWrapper, IVAS_REND_AudioBuffer *pSplitRendEncBuffer, ISAR_SPLIT_REND_CONFIG_DATA *pSplit_rend_config, @@ -3466,10 +3770,20 @@ static ivas_error ivas_pre_rend_init( const int16_t cldfb_in_flag, const int16_t num_subframes ) { + bool realloc; ivas_error error; IVAS_REND_AudioBufferConfig bufConfig; - if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) + realloc = false; + + /* only perform init if split rendering output */ + if ( outConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED && outConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) + { + return IVAS_ERR_OK; + } + + /* these functions should only be called once during initial allocation */ + if ( pSplitRendEncBuffer->data == NULL ) { if ( pSplit_rend_config->poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB ) { @@ -3484,28 +3798,34 @@ static ivas_error ivas_pre_rend_init( { return error; } + } - /*allocate for CLDFB in and change to TD during process if needed*/ - bufConfig.numSamplesPerChannel = MAX_CLDFB_BUFFER_LENGTH_PER_CHANNEL; + /* We may need to change the allocated buffer size if a new input is added. + * If the cldfb_in_flag is different from what was previously allocated for the buffer, change the size */ + if ( pSplitRendEncBuffer->data != NULL && ( cldfb_in_flag != pSplitRendEncBuffer->config.is_cldfb ) ) + { + realloc = true; + } + + if ( pSplitRendEncBuffer->data == NULL || realloc ) + { + /* set buffer config */ + bufConfig.is_cldfb = cldfb_in_flag; + bufConfig.numSamplesPerChannel = cldfb_in_flag ? MAX_CLDFB_BUFFER_LENGTH_PER_CHANNEL : L_FRAME_MAX; bufConfig.numChannels = BINAURAL_CHANNELS * pSplitRendWrapper->multiBinPoseData.num_poses; - bufConfig.is_cldfb = 1; pSplitRendEncBuffer->config = bufConfig; + /* allocate memory */ + if ( realloc ) + { + free( pSplitRendEncBuffer->data ); + } + if ( ( pSplitRendEncBuffer->data = malloc( bufConfig.numChannels * bufConfig.numSamplesPerChannel * sizeof( float ) ) ) == NULL ) { return IVAS_ERR_FAILED_ALLOC; } } - else - { - IVAS_REND_AudioBufferConfig bufConfig2; - - bufConfig2.numSamplesPerChannel = 0; - bufConfig2.numChannels = 0; - bufConfig2.is_cldfb = 0; - pSplitRendEncBuffer->config = bufConfig2; - pSplitRendEncBuffer->data = NULL; - } return IVAS_ERR_OK; } @@ -3532,7 +3852,10 @@ ivas_error IVAS_REND_AddInput( int32_t inputStructSize; #endif ivas_error ( *activateInput )( void *, AUDIO_CONFIG, IVAS_REND_InputId, RENDER_CONFIG_DATA *, hrtf_handles *hrtfs ); + void ( *setInputDelay )( void *, bool ); int32_t inputIndex; + bool splitPreRendCldfb; + splitPreRendCldfb = false; /* Validate function arguments */ if ( hIvasRend == NULL || inputId == NULL ) @@ -3540,15 +3863,24 @@ ivas_error IVAS_REND_AddInput( return IVAS_ERR_UNEXPECTED_NULL_POINTER; } - if ( ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) && hIvasRend->splitRendEncBuffer.data == NULL && hIvasRend->hRendererConfig != NULL ) + if ( hIvasRend->hRendererConfig != NULL ) { int16_t cldfb_in_flag; cldfb_in_flag = getCldfbRendFlag( hIvasRend, getAudioConfigType( inConfig ) ); - if ( ( error = ivas_pre_rend_init( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer, &hIvasRend->hRendererConfig->split_rend_config, hIvasRend->headRotData, hIvasRend->sampleRateOut, hIvasRend->outputConfig, cldfb_in_flag, hIvasRend->num_subframes ) ) != IVAS_ERR_OK ) + if ( ( error = isar_pre_rend_init( hIvasRend->splitRendWrapper, + &hIvasRend->splitRendEncBuffer, + &hIvasRend->hRendererConfig->split_rend_config, + hIvasRend->headRotData, + hIvasRend->sampleRateOut, + hIvasRend->outputConfig, + cldfb_in_flag, + hIvasRend->num_subframes ) ) != IVAS_ERR_OK ) { return error; } + /*assumes that input has been added which means codec has been set to either lcld or lc3plus (even if render config specified default)*/ + splitPreRendCldfb = ( hIvasRend->hRendererConfig->split_rend_config.codec == ISAR_SPLIT_REND_CODEC_LCLD ); } #ifdef CODE_IMPROVEMENTS @@ -3565,6 +3897,7 @@ ivas_error IVAS_REND_AddInput( inputStructSize = sizeof( *hIvasRend->inputsIsm ); #endif activateInput = setRendInputActiveIsm; + setInputDelay = setRendInputDelayIsm; break; case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED: maxNumInputsOfType = RENDERER_MAX_MC_INPUTS; @@ -3573,6 +3906,7 @@ ivas_error IVAS_REND_AddInput( inputStructSize = sizeof( *hIvasRend->inputsMc ); #endif activateInput = setRendInputActiveMc; + setInputDelay = setRendInputDelayMc; break; case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS: maxNumInputsOfType = RENDERER_MAX_SBA_INPUTS; @@ -3581,6 +3915,7 @@ ivas_error IVAS_REND_AddInput( inputStructSize = sizeof( *hIvasRend->inputsSba ); #endif activateInput = setRendInputActiveSba; + setInputDelay = setRendInputDelaySba; break; case IVAS_REND_AUDIO_CONFIG_TYPE_MASA: maxNumInputsOfType = RENDERER_MAX_MASA_INPUTS; @@ -3589,6 +3924,7 @@ ivas_error IVAS_REND_AddInput( inputStructSize = sizeof( *hIvasRend->inputsMasa ); #endif activateInput = setRendInputActiveMasa; + setInputDelay = setRendInputDelayMasa; break; default: return IVAS_ERR_INVALID_INPUT_FORMAT; @@ -3613,6 +3949,14 @@ ivas_error IVAS_REND_AddInput( { return error; } +#ifdef CODE_IMPROVEMENTS + setInputDelay( getInputByIndex( inputsArray, inputIndex, inputType ), splitPreRendCldfb ); +#else + setInputDelay( (uint8_t *) inputsArray + inputStructSize * inputIndex, splitPreRendCldfb ); +#endif + + /* set global maximum delay after adding an input */ + setMaxGlobalDelayNs( hIvasRend ); return IVAS_ERR_OK; } @@ -3895,6 +4239,9 @@ ivas_error IVAS_REND_RemoveInput( return IVAS_ERR_INVALID_INPUT_FORMAT; } + /* set global maximum delay after removing an input */ + setMaxGlobalDelayNs( hIvasRend ); + return IVAS_ERR_OK; } @@ -3971,11 +4318,6 @@ ivas_error IVAS_REND_GetDelay( int32_t *timeScale /* o : Time scale of the delay, equal to renderer output sampling rate */ ) { - /* TODO tmu : this function only returns the maximum delay across all inputs - * Ideally each input has its own delay buffer and everything is aligned (binaural and LFE filtering delays are nonuniform) - */ - int16_t i; - int32_t latency_ns; int32_t max_latency_ns; /* Validate function arguments */ @@ -3984,71 +4326,11 @@ ivas_error IVAS_REND_GetDelay( return IVAS_ERR_UNEXPECTED_NULL_POINTER; } - *timeScale = hIvasRend->sampleRateOut; *nSamples = 0; - max_latency_ns = 0; - - /* Compute the maximum delay across all inputs */ - for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; i++ ) - { - if ( hIvasRend->inputsIsm[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) - { - latency_ns = max( ( hIvasRend->inputsIsm[i].crendWrapper != NULL ) ? hIvasRend->inputsIsm[i].crendWrapper->binaural_latency_ns : 0, - hIvasRend->inputsIsm[i].tdRendWrapper.binaural_latency_ns ); - max_latency_ns = max( max_latency_ns, latency_ns ); - } - } - - for ( i = 0; i < RENDERER_MAX_MC_INPUTS; i++ ) - { - if ( hIvasRend->inputsMc[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) - { - latency_ns = max( ( hIvasRend->inputsMc[i].crendWrapper != NULL ) ? hIvasRend->inputsMc[i].crendWrapper->binaural_latency_ns : 0, - hIvasRend->inputsMc[i].tdRendWrapper.binaural_latency_ns ); - max_latency_ns = max( max_latency_ns, latency_ns ); - } - } - - for ( i = 0; i < RENDERER_MAX_SBA_INPUTS; i++ ) - { - if ( hIvasRend->inputsSba[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) - { - if ( hIvasRend->splitRendWrapper != NULL && hIvasRend->splitRendWrapper->hBinHrSplitPreRend != NULL ) - { - if ( hIvasRend->hRendererConfig->split_rend_config.rendererSelection == IVAS_BIN_RENDERER_TYPE_FASTCONV ) - { - latency_ns = hIvasRend->inputsSba[i].cldfbRendWrapper.binaural_latency_ns; - } - else - { - latency_ns = ( hIvasRend->inputsSba[i].crendWrapper != NULL ) ? hIvasRend->inputsSba[i].crendWrapper->binaural_latency_ns : 0; - } - max_latency_ns = max( max_latency_ns, latency_ns ); - } - else if ( hIvasRend->inputsSba[i].cldfbRendWrapper.hCldfbRend != NULL ) - { - latency_ns = hIvasRend->inputsSba[i].cldfbRendWrapper.binaural_latency_ns; - latency_ns += IVAS_FB_DEC_DELAY_NS; - max_latency_ns = max( max_latency_ns, latency_ns ); - } - else - { - latency_ns = ( hIvasRend->inputsSba[i].crendWrapper != NULL ) ? hIvasRend->inputsSba[i].crendWrapper->binaural_latency_ns : 0; - max_latency_ns = max( max_latency_ns, latency_ns ); - } - } - } - - for ( i = 0; i < RENDERER_MAX_MASA_INPUTS; i++ ) - { - if ( hIvasRend->inputsMasa[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) - { - latency_ns = (int32_t) ( (float) IVAS_FB_DEC_DELAY_NS + 0.5f ); - max_latency_ns = max( max_latency_ns, latency_ns ); - } - } + *timeScale = hIvasRend->sampleRateOut; + max_latency_ns = getMaxGlobalDelayNs( hIvasRend ); - *nSamples = (int16_t) roundf( (float) max_latency_ns * *timeScale / 1000000000.f ); + *nSamples = latencyNsToSamples( hIvasRend->sampleRateOut, max_latency_ns ); return IVAS_ERR_OK; } @@ -4061,9 +4343,10 @@ ivas_error IVAS_REND_GetDelay( *-------------------------------------------------------------------*/ ivas_error IVAS_REND_FeedInputAudio( - IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ - const IVAS_REND_InputId inputId, /* i : ID of the input */ - const IVAS_REND_ReadOnlyAudioBuffer inputAudio /* i : buffer with input audio */ + IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ + const IVAS_REND_InputId inputId, /* i : ID of the input */ + const IVAS_REND_ReadOnlyAudioBuffer inputAudio, /* i : buffer with input audio */ + const bool flushInputs /* i : flush input audio */ ) { ivas_error error; @@ -4119,9 +4402,16 @@ ivas_error IVAS_REND_FeedInputAudio( } inputBase->inputBuffer.config = inputAudio.config; - - mvr2r( inputAudio.data, inputBase->inputBuffer.data, inputAudio.config.numSamplesPerChannel * inputAudio.config.numChannels ); - + if ( ( error = alignInputDelay( + inputBase, + inputAudio, + hIvasRend->maxGlobalDelayNs, + hIvasRend->sampleRateOut, + cldfb2tdSampleFact, + flushInputs ) ) != IVAS_ERR_OK ) + { + return error; + } inputBase->numNewSamplesPerChannel = inputAudio.config.numSamplesPerChannel / cldfb2tdSampleFact; return IVAS_ERR_OK; @@ -4434,6 +4724,7 @@ ivas_error IVAS_REND_FeedRenderConfig( if ( pMasaInput->hMasaExtRend->hDiracDecBin[0] != NULL && pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb != NULL ) { ivas_binaural_reverb_close( &pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb ); + if ( ( error = ivas_binaural_reverb_init( &pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb, // Todo 1892 hIvasRend->hHrtfs.hHrtfStatistics, pMasaInput->hMasaExtRend->hSpatParamRendCom->num_freq_bands, @@ -4450,6 +4741,7 @@ ivas_error IVAS_REND_FeedRenderConfig( if ( pMasaInput->hMasaExtRend->hReverb != NULL ) { ivas_binaural_reverb_close( &pMasaInput->hMasaExtRend->hReverb ); + if ( ( error = ivas_binaural_reverb_init( &pMasaInput->hMasaExtRend->hReverb, // Todo 1892 hIvasRend->hHrtfs.hHrtfStatistics, pMasaInput->hMasaExtRend->hSpatParamRendCom->num_freq_bands, @@ -4482,6 +4774,7 @@ ivas_error IVAS_REND_FeedRenderConfig( return error; } } + if ( pMcInput->crendWrapper != NULL && pMcInput->crendWrapper->hCrend[0] != NULL && pMcInput->crendWrapper->hCrend[0]->hReverb != NULL ) { if ( ( error = ivas_reverb_open( &pMcInput->crendWrapper->hCrend[0]->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, hRenderConfig, *pMcInput->base.ctx.pOutSampleRate ) ) != IVAS_ERR_OK ) @@ -4532,6 +4825,7 @@ ivas_error IVAS_REND_FeedRenderConfig( { int16_t cldfb_in_flag; cldfb_in_flag = getCldfbRendFlag( hIvasRend, IVAS_REND_AUDIO_CONFIG_TYPE_UNKNOWN ); + if ( hIvasRend->splitRendWrapper != NULL ) { ISAR_PRE_REND_close( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer ); @@ -4539,7 +4833,7 @@ ivas_error IVAS_REND_FeedRenderConfig( hIvasRend->splitRendWrapper = NULL; } - if ( ( error = ivas_pre_rend_init( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer, &hIvasRend->hRendererConfig->split_rend_config, hIvasRend->headRotData, hIvasRend->sampleRateOut, hIvasRend->outputConfig, cldfb_in_flag, hIvasRend->num_subframes ) ) != IVAS_ERR_OK ) + if ( ( error = isar_pre_rend_init( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer, &hIvasRend->hRendererConfig->split_rend_config, hIvasRend->headRotData, hIvasRend->sampleRateOut, hIvasRend->outputConfig, cldfb_in_flag, hIvasRend->num_subframes ) ) != IVAS_ERR_OK ) { return error; } @@ -5268,8 +5562,9 @@ static ivas_error renderIsmToBinaural( int16_t ism_md_subframe_update_ext; push_wmops( "renderIsmToBinaural" ); + /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */ - ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / ( 1000 / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES ) ); + ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / (float) BINAURAL_RENDERING_FRAME_SIZE_MS ); copyBufferTo2dArray( ismInput->base.inputBuffer, tmpTDRendBuffer ); if ( ( error = ivas_td_binaural_renderer_ext( &ismInput->tdRendWrapper, ismInput->base.inConfig, NULL, ismInput->base.ctx.pCombinedOrientationData, &ismInput->currentPos, ismInput->hReverb, ism_md_subframe_update_ext, @@ -5472,8 +5767,7 @@ static ivas_error renderIsmToBinauralReverb( push_wmops( "renderIsmToBinauralRoom" ); /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */ - ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / ( 1000 / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES ) ); - + ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / (float) BINAURAL_RENDERING_FRAME_SIZE_MS ); copyBufferTo2dArray( ismInput->base.inputBuffer, tmpRendBuffer ); if ( ( error = ivas_td_binaural_renderer_ext( &ismInput->tdRendWrapper, ismInput->base.inConfig, NULL, ismInput->base.ctx.pCombinedOrientationData, &ismInput->currentPos, ismInput->hReverb, @@ -5638,8 +5932,10 @@ static ivas_error renderIsmToSplitBinaural( const MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData; const SPLIT_REND_WRAPPER *pSplitRendWrapper; IVAS_QUATERNION originalHeadRot[MAX_PARAM_SPATIAL_SUBFRAMES]; - int16_t i; + int16_t i, ch, slot_idx, num_bands; float tmpBinaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k]; + float tmpBinaural_CldfbRe[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; + float tmpBinaural_CldfbIm[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; int16_t output_frame = ismInput->base.inputBuffer.config.numSamplesPerChannel; COMBINED_ORIENTATION_HANDLE pCombinedOrientationData; int16_t ism_md_subframe_update_ext; @@ -5650,7 +5946,7 @@ static ivas_error renderIsmToSplitBinaural( pMultiBinPoseData = &pSplitRendWrapper->multiBinPoseData; /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */ - ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / ( 1000 / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES ) ); + ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / (float) BINAURAL_RENDERING_FRAME_SIZE_MS ); pCombinedOrientationData = *ismInput->base.ctx.pCombinedOrientationData; @@ -5706,10 +6002,29 @@ static ivas_error renderIsmToSplitBinaural( return error; } - /* Copy rendered audio to tmp storage buffer. Copying directly to output would - * overwrite original audio, which is still needed for rendering next head pose. */ - mvr2r( tmpProcessing[0], tmpBinaural[2 * pos_idx], output_frame ); - mvr2r( tmpProcessing[1], tmpBinaural[2 * pos_idx + 1], output_frame ); + if ( outAudio.config.is_cldfb ) + { + /* Perform CLDFB analysis on rendered audio, since the output buffer is CLDFB domain */ + num_bands = (int16_t) ( ( BINAURAL_MAXBANDS * *ismInput->base.ctx.pOutSampleRate ) / 48000 ); + for ( ch = 0; ch < BINAURAL_CHANNELS; ch++ ) + { + for ( slot_idx = 0; slot_idx < IVAS_CLDFB_NO_COL_MAX; slot_idx++ ) + { + cldfbAnalysis_ts( &tmpProcessing[ch][num_bands * slot_idx], + &tmpBinaural_CldfbRe[BINAURAL_CHANNELS * pos_idx + ch][slot_idx][0], + &tmpBinaural_CldfbIm[BINAURAL_CHANNELS * pos_idx + ch][slot_idx][0], + num_bands, + ismInput->base.ctx.pSplitRendWrapper->hCldfbHandles->cldfbAna[pos_idx + ch] ); + } + } + } + else + { + /* Copy rendered audio to tmp storage buffer. Copying directly to output would + * overwrite original audio, which is still needed for rendering next head pose. */ + mvr2r( tmpProcessing[0], tmpBinaural[BINAURAL_CHANNELS * pos_idx], output_frame ); + mvr2r( tmpProcessing[1], tmpBinaural[BINAURAL_CHANNELS * pos_idx + 1], output_frame ); + } /* Overwrite processing buffer with original input audio again */ copyBufferTo2dArray( ismInput->base.inputBuffer, tmpProcessing ); @@ -5721,7 +6036,14 @@ static ivas_error renderIsmToSplitBinaural( pCombinedOrientationData->Quaternions[i] = originalHeadRot[i]; } - accumulate2dArrayToBuffer( tmpBinaural, &outAudio ); + if ( outAudio.config.is_cldfb ) + { + accumulateCLDFBArrayToBuffer( tmpBinaural_CldfbRe, tmpBinaural_CldfbIm, &outAudio ); + } + else + { + accumulate2dArrayToBuffer( tmpBinaural, &outAudio ); + } pop_wmops(); /* Encoding to split rendering bitstream done at a higher level */ @@ -5756,11 +6078,13 @@ static ivas_error renderInputIsm( { ivas_error error; IVAS_REND_AudioBuffer inAudio; + int16_t cldfb2tdSampleFact; error = IVAS_ERR_OK; inAudio = ismInput->base.inputBuffer; - if ( ismInput->base.numNewSamplesPerChannel != outAudio.config.numSamplesPerChannel ) + cldfb2tdSampleFact = outAudio.config.is_cldfb ? 2 : 1; + if ( ismInput->base.numNewSamplesPerChannel * cldfb2tdSampleFact != outAudio.config.numSamplesPerChannel ) { return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Mismatch between the number of input samples vs number of requested output samples - currently not allowed" ); } @@ -5885,8 +6209,7 @@ static ivas_error renderLfeToBinaural( num_cpy_smpl_prev_frame = mcInput->binauralDelaySmp; num_cpy_smpl_cur_frame = frame_size - num_cpy_smpl_prev_frame; - /* Assuming LFE should be delayed by less that the duration of one frame */ - assert( mcInput->binauralDelaySmp < frame_size ); + assert( mcInput->binauralDelaySmp <= MAX_BIN_DELAY_SAMPLES ); /* Get delayed LFE signal from previous frame, apply gain and save in tmp buffer */ v_multc( mcInput->lfeDelayBuffer, gain, tmpLfeBuffer, num_cpy_smpl_prev_frame ); @@ -7446,7 +7769,7 @@ ivas_error IVAS_REND_SetTotalNumberOfObjects( ivas_error IVAS_REND_SetIsmMetadataDelay( IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */ - const float sync_md_delay /* i : ISM Metadata Delay in ms to sync with audio delay */ + const int16_t sync_md_delay /* i : ISM Metadata Delay in ms to sync with audio delay */ ) { int16_t i; @@ -7472,15 +7795,13 @@ ivas_error IVAS_REND_SetIsmMetadataDelay( *-------------------------------------------------------------------*/ static ivas_error getSamplesInternal( - IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ - IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */, - IVAS_REND_BitstreamBuffer *hBits /*i/o: buffer for input/output bitstream. Needed in split rendering mode*/ + IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ + IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */ ) { ivas_error error; int16_t numOutChannels; int16_t cldfb2tdSampleFact; - IVAS_REND_AudioBuffer outAudioOrig; /* Validate function arguments */ if ( hIvasRend == NULL || outAudio.data == NULL ) @@ -7540,34 +7861,21 @@ static ivas_error getSamplesInternal( } } - if ( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_GetNumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK ) { return error; } - if ( numOutChannels != outAudio.config.numChannels && hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED && hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) + if ( numOutChannels != outAudio.config.numChannels && + hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED && + hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) { return IVAS_ERR_WRONG_NUM_CHANNELS; } - /* Clear original output buffer */ + /* Clear output buffer */ set_zero( outAudio.data, outAudio.config.numChannels * outAudio.config.numSamplesPerChannel ); - outAudioOrig = outAudio; - /* Use internal buffer if outputting split rendering bitstream */ - if ( ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) || - ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ) - { - int16_t num_poses_orig; - num_poses_orig = hIvasRend->splitRendWrapper->multiBinPoseData.num_poses; - outAudio = hIvasRend->splitRendEncBuffer; - ISAR_PRE_REND_GetMultiBinPoseData( &hIvasRend->hRendererConfig->split_rend_config, &hIvasRend->splitRendWrapper->multiBinPoseData, hIvasRend->headRotData.sr_pose_pred_axis ); - assert( num_poses_orig == hIvasRend->splitRendWrapper->multiBinPoseData.num_poses && "number of poses should not change dynamically" ); - - /* Clear output buffer for split rendering bitstream */ - set_zero( outAudio.data, outAudio.config.numChannels * outAudio.config.numSamplesPerChannel ); - } - if ( ( error = renderActiveInputsIsm( hIvasRend, outAudio ) ) != IVAS_ERR_OK ) { return error; @@ -7588,18 +7896,69 @@ static ivas_error getSamplesInternal( return error; } - if ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) + return IVAS_ERR_OK; +} + + +/*-------------------------------------------------------------------* + * IVAS_REND_GetSamples() + * + * + *-------------------------------------------------------------------*/ + +ivas_error IVAS_REND_GetSamples( + IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ + IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */ +) +{ + ivas_error error; + + if ( ( error = getSamplesInternal( hIvasRend, outAudio ) ) != IVAS_ERR_OK ) { - ISAR_SPLIT_REND_BITS_DATA bits; - int16_t cldfb_in_flag; - float Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; - float Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; - int16_t ch; - int16_t i, ro_md_flag; - float *tmpBinaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS], tmpBinaural_buff[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k]; + return error; + } + if ( outAudio.config.is_cldfb == 0 ) + { +#ifndef DISABLE_LIMITER +#ifdef DEBUGGING + hIvasRend->numClipping += +#endif + limitRendererOutput( hIvasRend->hLimiter, outAudio.data, outAudio.config.numSamplesPerChannel, IVAS_LIMITER_THRESHOLD ); +#endif + } + + /* update global cominbed orientation start index */ + ivas_combined_orientation_update_start_index( hIvasRend->hCombinedOrientationData, outAudio.config.numSamplesPerChannel ); + + return IVAS_ERR_OK; +} + + +/*-------------------------------------------------------------------* + * IVAS_REND_GetSplitBinauralBitstream() + * + * + *-------------------------------------------------------------------*/ + +ivas_error IVAS_REND_GetSplitBinauralBitstream( + IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ + IVAS_REND_AudioBuffer outAudio, /* i/o: buffer for output audio */ + IVAS_REND_BitstreamBuffer *hBits /* o : buffer for output bitstream */ +) +{ + ivas_error error; + int16_t ch; + int16_t cldfb_in_flag; + int16_t i, ro_md_flag; + int16_t num_poses_orig; + float *tmpBinaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS], tmpBinaural_buff[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k]; + float Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; + float Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; + IVAS_REND_AudioBufferConfig *pSplitEncBufConfig; + ISAR_SPLIT_REND_CONFIG_HANDLE pSplitRendConfig; + ISAR_SPLIT_REND_BITS_DATA bits; #ifdef FIX_1119_SPLIT_RENDERING_VOIP - // TODO(sgi): This doesn't match the original MR. BASOP main too far behind. float *p_Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX]; float *p_Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX]; int16_t j; @@ -7614,42 +7973,73 @@ static ivas_error getSamplesInternal( } #endif - for ( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ ) - { - tmpBinaural[ch] = tmpBinaural_buff[ch]; - } + for ( ch = 0; ch < MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS; ch++ ) + { + tmpBinaural[ch] = tmpBinaural_buff[ch]; + } - if ( outAudio.config.is_cldfb == 1 ) - { - cldfb_in_flag = 1; - copyBufferToCLDFBarray( outAudio, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural ); - } - else - { - cldfb_in_flag = 0; - copyBufferTo2dArray( outAudio, tmpBinaural_buff ); - } + cldfb_in_flag = getCldfbRendFlag( hIvasRend, IVAS_REND_AUDIO_CONFIG_TYPE_UNKNOWN ); + pSplitEncBufConfig = &hIvasRend->splitRendEncBuffer.config; + pSplitRendConfig = &hIvasRend->hRendererConfig->split_rend_config; - /* Encode split rendering bitstream */ - convertBitsBufferToInternalBitsBuff( *hBits, &bits ); + /* 0 DoF / No pose correction retains frame size */ + pSplitEncBufConfig->is_cldfb = cldfb_in_flag; + if ( pSplitRendConfig->dof == 0 || pSplitRendConfig->poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE ) + { + pSplitEncBufConfig->numSamplesPerChannel = outAudio.config.numSamplesPerChannel; + } + /* Pose correction requires 20ms */ + else + { + pSplitEncBufConfig->numSamplesPerChannel = (int16_t) ( hIvasRend->sampleRateOut / FRAMES_PER_SEC ); + } + pSplitEncBufConfig->numSamplesPerChannel *= cldfb_in_flag ? 2 : 1; + + num_poses_orig = hIvasRend->splitRendWrapper->multiBinPoseData.num_poses; + ISAR_PRE_REND_GetMultiBinPoseData( pSplitRendConfig, + &hIvasRend->splitRendWrapper->multiBinPoseData, + hIvasRend->headRotData.sr_pose_pred_axis ); + assert( num_poses_orig == hIvasRend->splitRendWrapper->multiBinPoseData.num_poses && "number of poses should not change dynamically" ); - ro_md_flag = 0; - for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i ) + /* hIvasRend->splitRendEncBuffer contains multi-pose data for BINAURAL_SPLIT_CODED output + outAudio used later for main pose BINAURAL_SPLIT_PCM output */ + if ( ( error = getSamplesInternal( hIvasRend, hIvasRend->splitRendEncBuffer ) ) != IVAS_ERR_OK ) + { + return error; + } + + /* copy outputs */ + if ( hIvasRend->splitRendEncBuffer.config.is_cldfb == 1 ) + { + cldfb_in_flag = 1; + copyBufferToCLDFBarray( hIvasRend->splitRendEncBuffer, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural ); + } + else + { + cldfb_in_flag = 0; + copyBufferTo2dArray( hIvasRend->splitRendEncBuffer, tmpBinaural_buff ); + } + + /* Encode split rendering bitstream */ + convertBitsBufferToInternalBitsBuff( *hBits, &bits ); + + ro_md_flag = 0; + for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i ) + { + if ( hIvasRend->inputsIsm[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) { - if ( hIvasRend->inputsIsm[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) - { - ro_md_flag = 1; - break; - } + ro_md_flag = 1; + break; } + } - if ( ( error = ISAR_PRE_REND_MultiBinToSplitBinaural( hIvasRend->splitRendWrapper, - hIvasRend->headRotData.headPositions[0], - hIvasRend->hRendererConfig->split_rend_config.splitRendBitRate, - hIvasRend->hRendererConfig->split_rend_config.codec, - hIvasRend->hRendererConfig->split_rend_config.isar_frame_size_ms, - hIvasRend->hRendererConfig->split_rend_config.codec_frame_size_ms, - &bits, + if ( ( error = ISAR_PRE_REND_MultiBinToSplitBinaural( hIvasRend->splitRendWrapper, + hIvasRend->headRotData.headPositions[0], + pSplitRendConfig->splitRendBitRate, + pSplitRendConfig->codec, + pSplitRendConfig->isar_frame_size_ms, + pSplitRendConfig->codec_frame_size_ms, + &bits, #ifdef FIX_1119_SPLIT_RENDERING_VOIP p_Cldfb_RealBuffer_Binaural, p_Cldfb_ImagBuffer_Binaural, @@ -7657,25 +8047,24 @@ static ivas_error getSamplesInternal( Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, #endif - ( const int16_t )( ( BINAURAL_MAXBANDS * hIvasRend->sampleRateOut ) / 48000 ), - tmpBinaural, - 1, - cldfb_in_flag, - ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ? 1 : 0, - ro_md_flag ) ) != IVAS_ERR_OK ) - { - return error; - } - - convertInternalBitsBuffToBitsBuffer( hBits, bits ); + ( const int16_t )( ( BINAURAL_MAXBANDS * hIvasRend->sampleRateOut ) / 48000 ), + tmpBinaural, + 1, + cldfb_in_flag, + ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ? 1 : 0, + ro_md_flag ) ) != IVAS_ERR_OK ) + { + return error; + } - /* reset to outAudioOrig in case of PCM output */ - outAudio = outAudioOrig; + convertInternalBitsBuffToBitsBuffer( hBits, bits ); - if ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) - { - accumulate2dArrayToBuffer( tmpBinaural_buff, &outAudio ); - } + /* copy over first pose data to outAudio */ + if ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) + { + /* set outAudio to zero - getSamplesInternal only cleared splitRendEncBuffer */ + set_zero( outAudio.data, outAudio.config.numChannels * outAudio.config.numSamplesPerChannel ); + accumulate2dArrayToBuffer( tmpBinaural_buff, &outAudio ); } if ( outAudio.config.is_cldfb == 0 ) @@ -7694,55 +8083,6 @@ static ivas_error getSamplesInternal( return IVAS_ERR_OK; } - -/*-------------------------------------------------------------------* - * IVAS_REND_GetSamples() - * - * - *-------------------------------------------------------------------*/ - -ivas_error IVAS_REND_GetSamples( - IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ - IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */ -) -{ - - return getSamplesInternal( hIvasRend, outAudio, NULL ); -} - - -/*-------------------------------------------------------------------* - * IVAS_REND_GetSplitBinauralBitstream() - * - * - *-------------------------------------------------------------------*/ - -ivas_error -IVAS_REND_GetSplitBinauralBitstream( - IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ - IVAS_REND_AudioBuffer outAudio, /* i/o: buffer for output audio */ - IVAS_REND_BitstreamBuffer *hBits /* o : buffer for output bitstream */ -) -{ - int16_t cldfb_in_flag; - - cldfb_in_flag = getCldfbRendFlag( hIvasRend, IVAS_REND_AUDIO_CONFIG_TYPE_UNKNOWN ); - hIvasRend->splitRendEncBuffer.config.is_cldfb = cldfb_in_flag; - if ( hIvasRend->hRendererConfig->split_rend_config.dof == 0 || hIvasRend->hRendererConfig->split_rend_config.poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE ) - { - hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel = outAudio.config.numSamplesPerChannel; - } - else - { - hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel = (int16_t) ( hIvasRend->sampleRateOut / FRAMES_PER_SEC ); - } - hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel *= cldfb_in_flag ? 2 : 1; - - /* hIvasRend->splitRendEncBuffer used for BINAURAL_SPLIT_CODED output - outAudio used for BINAURAL_SPLIT_PCM output */ - return getSamplesInternal( hIvasRend, outAudio, hBits ); -} - ivas_error IVAS_REND_GetSplitRendBitstreamHeader( IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */ ISAR_SPLIT_REND_CODEC *pCodec, /* o: pointer to codec setting */ diff --git a/lib_rend/lib_rend.h b/lib_rend/lib_rend.h index 61c7d0094..4b6e7340f 100644 --- a/lib_rend/lib_rend.h +++ b/lib_rend/lib_rend.h @@ -113,15 +113,15 @@ typedef enum _IVAS_REND_COMPLEXITY_LEVEL /* Functions to be called before rendering */ ivas_error IVAS_REND_Open( - IVAS_REND_HANDLE *phIvasRend, /* i/o: Pointer to renderer handle */ - const int32_t outputSampleRate, /* i : output sampling rate */ - const IVAS_AUDIO_CONFIG outConfig, /* i : output audio config */ - const bool asHrtfBinary, /* i : load hrtf binary file */ - const int16_t nonDiegeticPan, /* i : non-diegetic object flag */ - const float nonDiegeticPanGain, /* i : non-diegetic panning gain */ - const int16_t Opt_Headrotation, /* i : indicates whether head-rotation is used */ - const int16_t Opt_ExternalOrientation, /* i : indicates whether external orientations are used */ - const int16_t num_subframes /* i : number of subframes */ + IVAS_REND_HANDLE *phIvasRend, /* i/o: Pointer to renderer handle */ + const int32_t outputSampleRate, /* i : output sampling rate */ + const IVAS_AUDIO_CONFIG outConfig, /* i : output audio config */ + const bool asHrtfBinary, /* i : load hrtf binary file */ + const int16_t nonDiegeticPan, /* i : non-diegetic object flag */ + const float nonDiegeticPanGain, /* i : non-diegetic panning gain */ + const int16_t Opt_Headrotation, /* i : indicates whether head-rotation is used */ + const int16_t Opt_ExternalOrientation, /* i : indicates whether external orientations are used */ + const int16_t num_subframes /* i : number of subframes */ ); /* Note: this will reset custom LFE routings set for any MC input */ @@ -133,7 +133,7 @@ ivas_error IVAS_REND_ConfigureCustomOutputLoudspeakerLayout( /* Functions to be called before/during rendering */ -ivas_error IVAS_REND_NumOutChannels( +ivas_error IVAS_REND_GetNumOutChannels( IVAS_REND_CONST_HANDLE hIvasRend, /* i : Renderer handle */ int16_t *numOutChannels /* o : number of output channels */ ); @@ -224,9 +224,10 @@ ivas_error IVAS_REND_GetHrtfStatisticsHandle( /* Functions to be called during rendering */ ivas_error IVAS_REND_FeedInputAudio( - IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ - const IVAS_REND_InputId inputId, /* i : ID of the input */ - const IVAS_REND_ReadOnlyAudioBuffer inputAudio /* i : buffer with input audio */ + IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ + const IVAS_REND_InputId inputId, /* i : ID of the input */ + const IVAS_REND_ReadOnlyAudioBuffer inputAudio, /* i : buffer with input audio */ + const bool flushInputs /* i : flush input audio */ ); ivas_error IVAS_REND_FeedInputObjectMetadata( @@ -371,7 +372,7 @@ ivas_error IVAS_REND_SetTotalNumberOfObjects( ivas_error IVAS_REND_SetIsmMetadataDelay( IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */ - const float sync_md_delay /* i : Metadata Delay in ms to sync with audio delay */ + const int16_t sync_md_delay /* i : Metadata Delay in ms to sync with audio delay */ ); ivas_error IVAS_REND_GetNumAllObjects( @@ -387,7 +388,7 @@ ivas_error IVAS_REND_GetSamples( /* Functions to be called after rendering */ void IVAS_REND_Close( - IVAS_REND_HANDLE* phIvasRend /* i/o: Pointer to renderer handle */ + IVAS_REND_HANDLE *phIvasRend /* i/o: Pointer to renderer handle */ ); -- GitLab From e3683ca5a464602340bc62403a9510329571ec0c Mon Sep 17 00:00:00 2001 From: Kacper Sagnowski Date: Thu, 30 Oct 2025 20:52:48 +0100 Subject: [PATCH 04/11] Fix formatting --- apps/decoder.c | 10 ++++----- lib_dec/ivas_stat_dec.h | 2 +- lib_dec/lib_dec.c | 10 ++++----- lib_isar/lib_isar_pre_rend.h | 30 +++++++++++++-------------- lib_rend/ivas_stat_rend.h | 2 +- lib_rend/ivas_td_ring_buffer.c | 38 +++++++++++++++++----------------- 6 files changed, 46 insertions(+), 46 deletions(-) diff --git a/apps/decoder.c b/apps/decoder.c index 8f8031b50..641445277 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -3472,14 +3472,14 @@ static ivas_error decodeVoIP( { #endif #ifdef SUPPORT_JBM_TRACEFILE - if ( ( error = IVAS_DEC_VoIP_GetSamples( hIvasDec, nOutSamples, IVAS_DEC_PCM_INT16, (void *) pcmBuf, writeJbmTraceFileFrameWrapper, jbmTraceWriter, &bitstreamReadDone, &nSamplesRendered, ¶metersAvailableForEditing, systemTime_ms ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_DEC_VoIP_GetSamples( hIvasDec, nOutSamples, IVAS_DEC_PCM_INT16, (void *) pcmBuf, writeJbmTraceFileFrameWrapper, jbmTraceWriter, &bitstreamReadDone, &nSamplesRendered, ¶metersAvailableForEditing, systemTime_ms ) ) != IVAS_ERR_OK ) #else if ( ( error = IVAS_DEC_VoIP_GetSamples( hIvasDec, nOutSamples, IVAS_DEC_PCM_INT16, (void *) pcmBuf, &bitstreamReadDone, ¶metersAvailableForEditing, systemTime_ms ) ) != IVAS_ERR_OK ) #endif - { - fprintf( stderr, "\nError in IVAS_DEC_VoIP_GetSamples: %s\n", IVAS_DEC_GetErrorMessage( error ) ); - goto cleanup; - } + { + fprintf( stderr, "\nError in IVAS_DEC_VoIP_GetSamples: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } #ifdef FIX_1119_SPLIT_RENDERING_VOIP } #endif diff --git a/lib_dec/ivas_stat_dec.h b/lib_dec/ivas_stat_dec.h index f68c24172..e924c766e 100644 --- a/lib_dec/ivas_stat_dec.h +++ b/lib_dec/ivas_stat_dec.h @@ -849,7 +849,7 @@ typedef struct TD_RINGBUF_HANDLE hMultiBinTdData; ISAR_CLDFB_RINGBUF_HANDLE hMultiBinCldfbData[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS]; #else - ISAR_DEC_SPLIT_REND_MULTI_BIN_CLDFB_DATA_HANDLE hMultiBinCldfbData; /*scratch buffer for frame by frame processing*/ + ISAR_DEC_SPLIT_REND_MULTI_BIN_CLDFB_DATA_HANDLE hMultiBinCldfbData; /*scratch buffer for frame by frame processing*/ #endif ISAR_SPLIT_REND_BITS_HANDLE hSplitRendBits; /*scratch buffer for frame by frame processing*/ SPLIT_REND_WRAPPER splitrend; diff --git a/lib_dec/lib_dec.c b/lib_dec/lib_dec.c index 4ded1eb0e..da46e5dfb 100644 --- a/lib_dec/lib_dec.c +++ b/lib_dec/lib_dec.c @@ -3782,11 +3782,11 @@ ivas_error IVAS_DEC_VoIP_GetSamples JbmTraceFileWriterFn jbmWriterFn, void *jbmWriter, #endif - bool *bitstreamReadDone, /* o : flag indicating that bitstream was read */ - uint16_t *nSamplesRendered, /* o : number of samples rendered */ - bool *parametersAvailableForEditing, - const uint32_t systemTimestamp_ms /* i : current system timestamp */ -) + bool *bitstreamReadDone, /* o : flag indicating that bitstream was read */ + uint16_t *nSamplesRendered, /* o : number of samples rendered */ + bool *parametersAvailableForEditing, + const uint32_t systemTimestamp_ms /* i : current system timestamp */ + ) { Decoder_Struct *st_ivas; DECODER_CONFIG_HANDLE hDecoderConfig; diff --git a/lib_isar/lib_isar_pre_rend.h b/lib_isar/lib_isar_pre_rend.h index 7f75f5a22..f11530e09 100644 --- a/lib_isar/lib_isar_pre_rend.h +++ b/lib_isar/lib_isar_pre_rend.h @@ -59,26 +59,26 @@ void ISAR_PRE_REND_GetMultiBinPoseData( ); ivas_error ISAR_PRE_REND_MultiBinToSplitBinaural( - SPLIT_REND_WRAPPER *hSplitBin, /* i/o: Split renderer pre-renerer handle */ - const IVAS_QUATERNION headPosition, /* i: head rotation QUATERNION */ - const int32_t SplitRendBitRate, /* i: Split renderer bitrate */ - ISAR_SPLIT_REND_CODEC splitCodec, /* i/o: Split renderer codec */ - const int16_t isar_frame_size_ms, /* i: ISAR framesize */ - int16_t codec_frame_size_ms, /* i/o: ISAR transport codec framesize */ - ISAR_SPLIT_REND_BITS_HANDLE pBits, /* i/o: ISAR bits struct handle */ + SPLIT_REND_WRAPPER *hSplitBin, /* i/o: Split renderer pre-renerer handle */ + const IVAS_QUATERNION headPosition, /* i: head rotation QUATERNION */ + const int32_t SplitRendBitRate, /* i: Split renderer bitrate */ + ISAR_SPLIT_REND_CODEC splitCodec, /* i/o: Split renderer codec */ + const int16_t isar_frame_size_ms, /* i: ISAR framesize */ + int16_t codec_frame_size_ms, /* i/o: ISAR transport codec framesize */ + ISAR_SPLIT_REND_BITS_HANDLE pBits, /* i/o: ISAR bits struct handle */ #ifdef FIX_1119_SPLIT_RENDERING_VOIP - float* Cldfb_In_BinReal[][CLDFB_NO_COL_MAX], /* i/o: CLDFB real buffer */ - float* Cldfb_In_BinImag[][CLDFB_NO_COL_MAX], /* i/o: CLDFB imag buffer */ + float *Cldfb_In_BinReal[][CLDFB_NO_COL_MAX], /* i/o: CLDFB real buffer */ + float *Cldfb_In_BinImag[][CLDFB_NO_COL_MAX], /* i/o: CLDFB imag buffer */ #else float Cldfb_In_BinReal[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], /* i/o: CLDFB real buffer */ float Cldfb_In_BinImag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], /* i/o: CLDFB imag buffer */ #endif - const int16_t max_bands, /* i: CLDFB bands */ - float *output[], /* i/o: PCM in/out buffer */ - const int16_t low_res_pre_rend_rot, /* i: low time resolution pre-renderer flag */ - const int16_t cldfb_in_flag, /* i: Flag to indicate CLDFB or time doamin input */ - const int16_t pcm_out_flag, /* i: Flag to indicate PCM output */ - const int16_t ro_md_flag /* i: Flag to indicate real only metadata for yaw */ + const int16_t max_bands, /* i: CLDFB bands */ + float *output[], /* i/o: PCM in/out buffer */ + const int16_t low_res_pre_rend_rot, /* i: low time resolution pre-renderer flag */ + const int16_t cldfb_in_flag, /* i: Flag to indicate CLDFB or time doamin input */ + const int16_t pcm_out_flag, /* i: Flag to indicate PCM output */ + const int16_t ro_md_flag /* i: Flag to indicate real only metadata for yaw */ ); #endif /* LIB_ISAR_PRE_REND_H */ diff --git a/lib_rend/ivas_stat_rend.h b/lib_rend/ivas_stat_rend.h index 451a60d1a..fe039cacb 100644 --- a/lib_rend/ivas_stat_rend.h +++ b/lib_rend/ivas_stat_rend.h @@ -1381,7 +1381,7 @@ typedef struct typedef struct { - float *data; /* samples in interleaved layout, e.g. for channels A, B, C, samples are stored: A1, B1, C1, A2, B2, C2, ... */ + float *data; /* samples in interleaved layout, e.g. for channels A, B, C, samples are stored: A1, B1, C1, A2, B2, C2, ... */ int32_t capacity; /* max number of float values that can be stored */ int16_t num_channels; int32_t write_pos; diff --git a/lib_rend/ivas_td_ring_buffer.c b/lib_rend/ivas_td_ring_buffer.c index c1aa84a9b..046c11b15 100644 --- a/lib_rend/ivas_td_ring_buffer.c +++ b/lib_rend/ivas_td_ring_buffer.c @@ -76,10 +76,10 @@ static int16_t ivas_td_ringbuf_has_space_for_num_samples( #ifdef FIX_1119_SPLIT_RENDERING_VOIP static void ivas_td_ringbuf_push_interleaved( - TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ - const float *data, /* i : Input audio in interleaved channels layout */ - const int16_t num_samples_per_channel, /* i : Number of samples per channel to push */ - const int16_t read_stride /* i: : 1 for normal operation, 0 for reading from a single input value */ + TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ + const float *data, /* i : Input audio in interleaved channels layout */ + const int16_t num_samples_per_channel, /* i : Number of samples per channel to push */ + const int16_t read_stride /* i: : 1 for normal operation, 0 for reading from a single input value */ ) { int32_t s, read_s; @@ -123,9 +123,9 @@ static void ivas_td_ringbuf_push_interleaved( *---------------------------------------------------------------------*/ ivas_error ivas_TD_RINGBUF_Open( - TD_RINGBUF_HANDLE *ph, /* i/o: Ring buffer handle */ - const int16_t capacity_per_channel, /* i : Number of samples stored per channel */ - const int16_t num_channels /* i : Number of channels */ + TD_RINGBUF_HANDLE *ph, /* i/o: Ring buffer handle */ + const int16_t capacity_per_channel, /* i : Number of samples stored per channel */ + const int16_t num_channels /* i : Number of channels */ ) { TD_RINGBUF_HANDLE h; @@ -200,9 +200,9 @@ void ivas_TD_RINGBUF_Close( *---------------------------------------------------------------------*/ void ivas_TD_RINGBUF_PushInterleaved( - TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ - const float *data, /* i : Input audio in interleaved channels layout */ - const int16_t num_samples_per_channel /* i : Number of samples per channel to push */ + TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ + const float *data, /* i : Input audio in interleaved channels layout */ + const int16_t num_samples_per_channel /* i : Number of samples per channel to push */ ) { ivas_td_ringbuf_push_interleaved( h, data, num_samples_per_channel, 1 ); @@ -218,9 +218,9 @@ void ivas_TD_RINGBUF_PushInterleaved( *---------------------------------------------------------------------*/ void ivas_TD_RINGBUF_PushChannels( - TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ - const float *p_channels[], /* i : Array of pointers to each input channel */ - const int16_t num_samples_per_channel /* i : Number of samples per channel to push */ + TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ + const float *p_channels[], /* i : Array of pointers to each input channel */ + const int16_t num_samples_per_channel /* i : Number of samples per channel to push */ ) #else /*---------------------------------------------------------------------* @@ -285,9 +285,9 @@ void ivas_TD_RINGBUF_Push( *---------------------------------------------------------------------*/ void ivas_TD_RINGBUF_PushConstant( - TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ - const float value, /* i : Value to push */ - const int16_t num_samples_per_channel /* i : Number of samples per channel to push */ + TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ + const float value, /* i : Value to push */ + const int16_t num_samples_per_channel /* i : Number of samples per channel to push */ ) { ivas_td_ringbuf_push_interleaved( h, &value, num_samples_per_channel, 0 ); @@ -346,9 +346,9 @@ void ivas_TD_RINGBUF_PushZeros( *---------------------------------------------------------------------*/ void ivas_TD_RINGBUF_PopChannels( - TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ - float *p_channels[], /* i : Array of pointers to each output channel */ - const int16_t num_samples_per_channel /* i : Number of samples per channel to pop */ + TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ + float *p_channels[], /* i : Array of pointers to each output channel */ + const int16_t num_samples_per_channel /* i : Number of samples per channel to pop */ ) #else /*---------------------------------------------------------------------* -- GitLab From c7a2a6aa97062bc4eaf2d157767cc5c8532ffd14 Mon Sep 17 00:00:00 2001 From: Kacper Sagnowski Date: Thu, 30 Oct 2025 21:07:42 +0100 Subject: [PATCH 05/11] Remove use of unsigned integers from the CLDFB ring buffer --- lib_isar/isar_stat.h | 6 +++--- lib_rend/ivas_cldfb_ring_buffer.c | 21 ++++++++++----------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/lib_isar/isar_stat.h b/lib_isar/isar_stat.h index b244370dd..4ed75ee97 100644 --- a/lib_isar/isar_stat.h +++ b/lib_isar/isar_stat.h @@ -350,9 +350,9 @@ typedef struct { float *real; float *imag; - uint32_t capacity; - uint32_t write_pos; - uint32_t read_pos; + int32_t capacity; + int32_t write_pos; + int32_t read_pos; int16_t is_full; } ISAR_CLDFB_RINGBUF, *ISAR_CLDFB_RINGBUF_HANDLE; diff --git a/lib_rend/ivas_cldfb_ring_buffer.c b/lib_rend/ivas_cldfb_ring_buffer.c index 5d1d2a055..669227540 100644 --- a/lib_rend/ivas_cldfb_ring_buffer.c +++ b/lib_rend/ivas_cldfb_ring_buffer.c @@ -75,7 +75,7 @@ static int16_t ivas_cldfb_ringbuf_IsFull( /*---------------------------------------------------------------------* * ivas_CLDFB_RINGBUF_Open() * - * Allocate a ring buffer for CLDFB data with the given capacity of CLDFB columns. + * Allocates a ring buffer for CLDFB data with the given capacity of CLDFB columns. * Each column is expected to contain at most CLDFB_NO_CHANNELS_MAX frequency bands. * * May return IVAS_ERR_FAILED_ALLOC on failed allocation, or IVAS_ERR_OK otherwise. @@ -88,7 +88,7 @@ ivas_error ivas_CLDFB_RINGBUF_Open( ISAR_CLDFB_RINGBUF_HANDLE h; int32_t capacity; - capacity = capacity_columns * CLDFB_NO_CHANNELS_MAX; + capacity = (int32_t) capacity_columns * CLDFB_NO_CHANNELS_MAX; if ( ( h = malloc( sizeof( ISAR_CLDFB_RINGBUF ) ) ) == NULL ) { @@ -119,7 +119,7 @@ ivas_error ivas_CLDFB_RINGBUF_Open( /*---------------------------------------------------------------------* * ivas_CLDFB_RINGBUF_Close() * - * Dellocate CLDFB ring buffer. The given handle will be set to NULL. + * Dellocates CLDFB ring buffer. The given handle will be set to NULL. *---------------------------------------------------------------------*/ void ivas_CLDFB_RINGBUF_Close( @@ -190,7 +190,7 @@ void ivas_CLDFB_RINGBUF_Push( /*---------------------------------------------------------------------* * ivas_CLDFB_RINGBUF_Pop() * - * Pop a single column from the front of the CLDFB ring buffer into real and imag arrays. + * Pops a single column from the front of the CLDFB ring buffer into real and imag arrays. *---------------------------------------------------------------------*/ void ivas_CLDFB_RINGBUF_Pop( @@ -229,7 +229,7 @@ void ivas_CLDFB_RINGBUF_Pop( * Returns total number of buffered samples (including number of channels) *---------------------------------------------------------------------*/ -static uint32_t ivas_cldfb_ringbuf_total_size( +static int32_t ivas_cldfb_ringbuf_total_size( ISAR_CLDFB_RINGBUF_HANDLE h ) { if ( ivas_cldfb_ringbuf_IsFull( h ) ) @@ -265,8 +265,8 @@ void ivas_CLDFB_RINGBUF_GetByIdx( const int16_t col_idx ) { int32_t idx = col_idx * CLDFB_NO_CHANNELS_MAX; - int32_t num_floats = (int32_t) ivas_cldfb_ringbuf_total_size( h ); - uint32_t offset, uidx; + int32_t num_floats = ivas_cldfb_ringbuf_total_size( h ); + int32_t offset; assert( -num_floats <= idx && idx <= num_floats ); @@ -280,14 +280,13 @@ void ivas_CLDFB_RINGBUF_GetByIdx( } else { - uidx = (uint32_t) -idx; - if ( uidx <= h->write_pos ) + if ( -idx <= h->write_pos ) { - offset = h->write_pos - uidx; + offset = h->write_pos + idx; } else { - offset = h->write_pos + h->capacity - uidx; + offset = h->write_pos + h->capacity + idx; } } -- GitLab From 26ecc3ee6d443a7df72efab90ed31883a9614dbe Mon Sep 17 00:00:00 2001 From: Kacper Sagnowski Date: Thu, 30 Oct 2025 21:34:50 +0100 Subject: [PATCH 06/11] Fix merge error --- lib_dec/lib_dec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_dec/lib_dec.c b/lib_dec/lib_dec.c index da46e5dfb..8f92eb85d 100644 --- a/lib_dec/lib_dec.c +++ b/lib_dec/lib_dec.c @@ -4002,7 +4002,7 @@ ivas_error IVAS_DEC_VoIP_GetSamples } #ifdef FIX_1119_SPLIT_RENDERING_VOIP - if ( ( error = IVAS_DEC_GetSamplesRenderer( hIvasDec, nSamplesToRender, pcmType, pcm_buffer_offset( pcmBuf, pcmType, *nSamplesRendered * nOutChannels ), &nSamplesRendered_loop, &tmp ) ) != IVAS_ERR_OK ) + if ( splitRendBits != NULL ) { /* Render head poses from time-scaled transport channels */ if ( ( error = isar_render_poses( hIvasDec, nSamplesToRender, &nSamplesRendered_loop, &tmp ) ) != IVAS_ERR_OK ) -- GitLab From 6543d2bb548809d6a17f637735b449e06c4fd993 Mon Sep 17 00:00:00 2001 From: Kacper Sagnowski Date: Thu, 30 Oct 2025 21:40:12 +0100 Subject: [PATCH 07/11] Remove unused function ISAR_SPLIT_REND_BITStream_init --- lib_isar/isar_prot.h | 6 ------ lib_isar/isar_splitRenderer_utils.c | 20 -------------------- 2 files changed, 26 deletions(-) diff --git a/lib_isar/isar_prot.h b/lib_isar/isar_prot.h index fb77001e5..a81c5d348 100644 --- a/lib_isar/isar_prot.h +++ b/lib_isar/isar_prot.h @@ -400,12 +400,6 @@ void isar_init_split_rend_handles( SPLIT_REND_WRAPPER *hSplitRendWrapper /* i/o: Split renderer pre-renderer handle */ ); -void ISAR_SPLIT_REND_BITStream_init( - ISAR_SPLIT_REND_BITS_HANDLE pBits, - const int32_t buf_len_bytes, - uint8_t *pbuf -); - /* clang-format on */ #endif /* ISAR_PROT_H */ diff --git a/lib_isar/isar_splitRenderer_utils.c b/lib_isar/isar_splitRenderer_utils.c index 02dd552ef..962e52ff1 100644 --- a/lib_isar/isar_splitRenderer_utils.c +++ b/lib_isar/isar_splitRenderer_utils.c @@ -78,26 +78,6 @@ void isar_mat_mult_2by2_complex( } -/*------------------------------------------------------------------------- - * Function ISAR_SPLIT_REND_BITStream_init() - * - * - *------------------------------------------------------------------------*/ - -void ISAR_SPLIT_REND_BITStream_init( - ISAR_SPLIT_REND_BITS_HANDLE pBits, - const int32_t buf_len_bytes, - uint8_t *pbuf ) -{ - pBits->bits_buf = pbuf; - pBits->buf_len = buf_len_bytes; - pBits->bits_read = 0; - pBits->bits_written = 0; - - return; -} - - /*------------------------------------------------------------------------- * Function isar_split_rend_huffman_dec_init_min_max_len() * -- GitLab From 15f731521755dfd0e21f6970a5cd514646a9f624 Mon Sep 17 00:00:00 2001 From: Kacper Sagnowski Date: Thu, 30 Oct 2025 22:18:41 +0100 Subject: [PATCH 08/11] Fix typo --- lib_rend/lib_rend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_rend/lib_rend.c b/lib_rend/lib_rend.c index 29c486187..e69f43e6c 100644 --- a/lib_rend/lib_rend.c +++ b/lib_rend/lib_rend.c @@ -1532,7 +1532,7 @@ static ivas_error alignInputDelay( numSamplesToPop = flushInputs ? ivas_TD_RINGBUF_Size( inputBase->delayBuffer ) : inputAudio.config.numSamplesPerChannel; #ifdef FIX_1119_SPLIT_RENDERING_VOIP - for ( i = -1; i < inputAudio.config.numChannels; ++i ) + for ( i = 0; i < inputAudio.config.numChannels; ++i ) { p_read_channels[i] = inputAudio.data + i * numSamplesToPush; } -- GitLab From cb0e42b803611f84c55ffda205aee243777a87f9 Mon Sep 17 00:00:00 2001 From: Kacper Sagnowski Date: Thu, 30 Oct 2025 22:18:50 +0100 Subject: [PATCH 09/11] Fix missing change from port 369 --- lib_isar/lib_isar_pre_rend.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib_isar/lib_isar_pre_rend.c b/lib_isar/lib_isar_pre_rend.c index 7203c97b2..ddb663f22 100644 --- a/lib_isar/lib_isar_pre_rend.c +++ b/lib_isar/lib_isar_pre_rend.c @@ -115,9 +115,7 @@ ivas_error ISAR_PRE_REND_open( isCldfbNeeded = 1; } - hSplitBinRend->hCldfbHandles = NULL; - - if ( isCldfbNeeded ) + if ( isCldfbNeeded && hSplitBinRend->hCldfbHandles == NULL ) { if ( ( hSplitBinRend->hCldfbHandles = (CLDFB_HANDLES_WRAPPER_HANDLE) malloc( sizeof( CLDFB_HANDLES_WRAPPER ) ) ) == NULL ) { -- GitLab From aae673658c7a9adbe0a821e0d3b1abb9e9da23e0 Mon Sep 17 00:00:00 2001 From: Kacper Sagnowski Date: Thu, 30 Oct 2025 22:19:07 +0100 Subject: [PATCH 10/11] Editorial --- lib_dec/lib_dec.c | 1 + lib_rend/ivas_td_ring_buffer.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib_dec/lib_dec.c b/lib_dec/lib_dec.c index 8f92eb85d..d4032c36d 100644 --- a/lib_dec/lib_dec.c +++ b/lib_dec/lib_dec.c @@ -1767,6 +1767,7 @@ ivas_error IVAS_DEC_PrepareRenderer( return IVAS_ERR_OK; } + #ifdef FIX_1119_SPLIT_RENDERING_VOIP /*---------------------------------------------------------------------* * isar_get_frame_size( ) diff --git a/lib_rend/ivas_td_ring_buffer.c b/lib_rend/ivas_td_ring_buffer.c index 046c11b15..98b3e4d15 100644 --- a/lib_rend/ivas_td_ring_buffer.c +++ b/lib_rend/ivas_td_ring_buffer.c @@ -214,7 +214,7 @@ void ivas_TD_RINGBUF_PushInterleaved( /*---------------------------------------------------------------------* * ivas_TD_RINGBUF_PushChannels() * - * Push samples from channel pointers onto the back of the TD ring buffer. + * Pushes samples from channel pointers onto the back of the TD ring buffer. *---------------------------------------------------------------------*/ void ivas_TD_RINGBUF_PushChannels( @@ -281,7 +281,7 @@ void ivas_TD_RINGBUF_Push( /*---------------------------------------------------------------------* * ivas_TD_RINGBUF_PushConstant() * - * Push samples with a constant value onto the back of the TD ring buffer. + * Pushes samples with a constant value onto the back of the TD ring buffer. *---------------------------------------------------------------------*/ void ivas_TD_RINGBUF_PushConstant( @@ -342,7 +342,7 @@ void ivas_TD_RINGBUF_PushZeros( /*---------------------------------------------------------------------* * ivas_TD_RINGBUF_PopChannels() * - * Pop samples from the front of the TD ring buffer to an array of channel pointers. + * Pops samples from the front of the TD ring buffer to an array of channel pointers. *---------------------------------------------------------------------*/ void ivas_TD_RINGBUF_PopChannels( -- GitLab From dbd615d69b8ec23d162e75abb22b46d963dde49e Mon Sep 17 00:00:00 2001 From: Kacper Sagnowski Date: Thu, 30 Oct 2025 23:40:38 +0100 Subject: [PATCH 11/11] Remove changes from port 369 --- apps/renderer.c | 114 +++-- lib_isar/lib_isar_pre_rend.c | 4 +- lib_rend/lib_rend.c | 865 +++++++++++------------------------ lib_rend/lib_rend.h | 31 +- 4 files changed, 330 insertions(+), 684 deletions(-) diff --git a/apps/renderer.c b/apps/renderer.c index 91a6021f1..e57df6db7 100644 --- a/apps/renderer.c +++ b/apps/renderer.c @@ -33,7 +33,6 @@ #include "lib_rend.h" #include #include -#include #include #include "audio_file_reader.h" #include "audio_file_writer.h" @@ -191,7 +190,7 @@ typedef struct float lfeConfigElevation; bool lfeCustomRoutingEnabled; char inLfePanningMatrixFile[RENDERER_MAX_CLI_ARG_LENGTH]; - int16_t syncMdDelay; + float syncMdDelay; IVAS_RENDER_FRAMESIZE render_framesize; uint16_t directivityPatternId[RENDERER_MAX_ISM_INPUTS]; AcousticEnvironmentSequence aeSequence; @@ -721,7 +720,6 @@ int main( SplitFileReadWrite *hSplitRendFileReadWrite; int16_t delayNumSamples_temp; int32_t delayTimeScale_temp; - bool flushRendererLastFrame = false; int16_t numSamplesRead; int16_t delayNumSamples = -1; int16_t delayNumSamples_orig = 0; @@ -768,11 +766,8 @@ int main( CmdlnArgs args = parseCmdlnArgs( argc, argv ); - if ( args.nonDiegeticPan && - !( ( args.inConfig.numAudioObjects == 0 && - args.inConfig.multiChannelBuses[0].audioConfig == IVAS_AUDIO_CONFIG_MONO ) || - ( args.inConfig.numAudioObjects > 0 && - args.inConfig.audioObjects[0].audioConfig == IVAS_AUDIO_CONFIG_OBA && args.inConfig.numAudioObjects == 1 ) ) ) + if ( args.nonDiegeticPan && !( ( args.inConfig.numAudioObjects == 0 && args.inConfig.multiChannelBuses[0].audioConfig == IVAS_AUDIO_CONFIG_MONO ) || + ( args.inConfig.numAudioObjects > 0 && args.inConfig.audioObjects[0].audioConfig == IVAS_AUDIO_CONFIG_OBA && args.inConfig.numAudioObjects == 1 ) ) ) { fprintf( stderr, "\ninvalid configuration - non-diegetic panning requires mono or ISM1 input\n" ); goto cleanup; @@ -1093,10 +1088,7 @@ int main( IVAS_RENDER_CONFIG_DATA renderConfig; #endif /* sanity check */ - if ( ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL ) && - ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) && - ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) && - !is_split_pre_rend_mode( &args ) ) + if ( ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL ) && ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) && ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) && !is_split_pre_rend_mode( &args ) ) { fprintf( stderr, "\nExternal Renderer Config is supported only when binaural output configurations is used as output OR when Split pre-rendering mode is enabled. Exiting. \n" ); goto cleanup; @@ -1410,7 +1402,7 @@ int main( } int16_t numOutChannels; - if ( ( error = IVAS_REND_GetNumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nError in IVAS_REND_NumOutChannels(): %s\n", ivas_error_to_string( error ) ); goto cleanup; @@ -1425,16 +1417,8 @@ int main( } } - if ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) + if ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) { - char *outFile = args.outMetadataFilePath; - - if ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) - { - outFile = args.outputFilePath; - audioWriter = NULL; - } - if ( ( error = IVAS_REND_GetSplitRendBitstreamHeader( hIvasRend, &bitsBuffer.config.codec, &bitsBuffer.config.poseCorrection, &bitsBuffer.config.codec_frame_size_ms, &bitsBuffer.config.isar_frame_size_ms ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nError in IVAS_REND_GetSplitRendBitstreamHeader()!\n" ); @@ -1447,15 +1431,36 @@ int main( goto cleanup; } - if ( ( error = split_rend_writer_open( &hSplitRendFileReadWrite, outFile, delayNumSamples_temp, delayTimeScale_temp, bitsBuffer.config.codec, bitsBuffer.config.poseCorrection, bitsBuffer.config.codec_frame_size_ms, bitsBuffer.config.isar_frame_size_ms, args.sampleRate, bitsBuffer.config.lc3plus_highres ) ) != IVAS_ERR_OK ) + if ( ( error = split_rend_writer_open( &hSplitRendFileReadWrite, args.outputFilePath, delayNumSamples_temp, delayTimeScale_temp, bitsBuffer.config.codec, bitsBuffer.config.poseCorrection, bitsBuffer.config.codec_frame_size_ms, bitsBuffer.config.isar_frame_size_ms, args.sampleRate, bitsBuffer.config.lc3plus_highres ) ) != IVAS_ERR_OK ) { - fprintf( stderr, "\nCould not open split rend metadata file %s\n", outFile ); + fprintf( stderr, "\nCould not open split rend metadata file %s\n", args.outputFilePath ); goto cleanup; } + audioWriter = NULL; } - - if ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) + else { + if ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) + { + if ( ( error = IVAS_REND_GetSplitRendBitstreamHeader( hIvasRend, &bitsBuffer.config.codec, &bitsBuffer.config.poseCorrection, &bitsBuffer.config.codec_frame_size_ms, &bitsBuffer.config.isar_frame_size_ms ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError in IVAS_REND_GetSplitRendBitstreamHeader()!\n" ); + goto cleanup; + } + + if ( IVAS_REND_GetDelay( hIvasRend, &delayNumSamples_temp, &delayTimeScale_temp ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nUnable to get delay of renderer!\n" ); + goto cleanup; + } + + if ( ( error = split_rend_writer_open( &hSplitRendFileReadWrite, args.outMetadataFilePath, delayNumSamples_temp, delayTimeScale_temp, bitsBuffer.config.codec, bitsBuffer.config.poseCorrection, bitsBuffer.config.codec_frame_size_ms, bitsBuffer.config.isar_frame_size_ms, args.sampleRate, bitsBuffer.config.lc3plus_highres ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nCould not open split rend metadata file %s\n", args.outMetadataFilePath ); + goto cleanup; + } + } + if ( AudioFileWriter_open( &audioWriter, args.outputFilePath, args.sampleRate, numOutChannels ) != IVAS_ERR_OK ) { fprintf( stderr, "\nFailed to open file: %s\n", args.outputFilePath ); @@ -1585,23 +1590,16 @@ int main( if ( numSamplesRead == 0 ) { /* end of input data */ - flushRendererLastFrame = true; + break; } /* Convert from int to float and from interleaved to packed */ - if ( !flushRendererLastFrame ) - { - convertInputBuffer( inpInt16Buffer, numSamplesRead, inBuffer.config.numSamplesPerChannel, num_in_channels, inFloatBuffer, inBuffer.config.is_cldfb, cldfbAna ); - } - else - { - memset( inBuffer.data, 0, inBuffer.config.numChannels * inBuffer.config.numSamplesPerChannel * sizeof( float ) ); - } + convertInputBuffer( inpInt16Buffer, numSamplesRead, inBuffer.config.numSamplesPerChannel, num_in_channels, inFloatBuffer, inBuffer.config.is_cldfb, cldfbAna ); int16_t num_subframes, sf_idx; num_subframes = (int16_t) args.render_framesize; - if ( isCurrentFrameMultipleOf20ms && !flushRendererLastFrame ) + if ( isCurrentFrameMultipleOf20ms ) { IsmPositionProvider_getNextFrame( positionProvider, &mtdBuffer ); @@ -1713,7 +1711,7 @@ int main( } IVAS_REND_ReadOnlyAudioBuffer tmpBuffer = getReadOnlySubBuffer( inBuffer, (int16_t) args.inConfig.multiChannelBuses[i].inputChannelIndex, numChannels ); - if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, mcIds[i], tmpBuffer, flushRendererLastFrame ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, mcIds[i], tmpBuffer ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nIVAS_REND_FeedInputAudio failed: %s\n", ivas_error_to_string( error ) ); goto cleanup; @@ -1728,7 +1726,7 @@ int main( { IVAS_REND_ReadOnlyAudioBuffer tmpBuffer = getReadOnlySubBuffer( inBuffer, (int16_t) args.inConfig.audioObjects[i].inputChannelIndex, args.inConfig.numAudioObjects ); - if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, ismIds[i], tmpBuffer, flushRendererLastFrame ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, ismIds[i], tmpBuffer ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nIVAS_REND_FeedInputAudio failed: %s\n", ivas_error_to_string( error ) ); goto cleanup; @@ -1745,7 +1743,7 @@ int main( { IVAS_REND_ReadOnlyAudioBuffer tmpBuffer = getReadOnlySubBuffer( inBuffer, (int16_t) args.inConfig.audioObjects[i].inputChannelIndex, 1 ); - if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, ismIds[i], tmpBuffer, flushRendererLastFrame ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, ismIds[i], tmpBuffer ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nIVAS_REND_FeedInputAudio failed: %s\n", ivas_error_to_string( error ) ); goto cleanup; @@ -1768,7 +1766,7 @@ int main( } IVAS_REND_ReadOnlyAudioBuffer tmpBuffer = getReadOnlySubBuffer( inBuffer, (int16_t) args.inConfig.ambisonicsBuses[i].inputChannelIndex, numChannels ); - if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, sbaIds[i], tmpBuffer, flushRendererLastFrame ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, sbaIds[i], tmpBuffer ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nIVAS_REND_FeedInputAudio failed: %s\n", ivas_error_to_string( error ) ); goto cleanup; @@ -1784,13 +1782,13 @@ int main( } IVAS_REND_ReadOnlyAudioBuffer tmpBuffer = getReadOnlySubBuffer( inBuffer, (int16_t) args.inConfig.masaBuses[i].inputChannelIndex, numChannels ); - if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, masaIds[i], tmpBuffer, flushRendererLastFrame ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, masaIds[i], tmpBuffer ) ) != IVAS_ERR_OK ) { fprintf( stderr, "IVAS_REND_FeedInputAudio failed: %s\n", ivas_error_to_string( error ) ); goto cleanup; } - if ( isCurrentFrameMultipleOf20ms && !flushRendererLastFrame ) + if ( isCurrentFrameMultipleOf20ms ) { if ( masaReaders[i] != NULL ) { @@ -1853,7 +1851,7 @@ int main( zeroPad = delayNumSamples; } - if ( is_split_pre_rend_mode( &args ) && !flushRendererLastFrame ) + if ( is_split_pre_rend_mode( &args ) ) { if ( split_rend_write_bitstream_to_file( hSplitRendFileReadWrite, bitsBuffer.bits, &bitsBuffer.config.bitsRead, &bitsBuffer.config.bitsWritten ) != IVAS_ERR_OK ) @@ -1863,7 +1861,7 @@ int main( } } - if ( audioWriter != NULL && !flushRendererLastFrame ) + if ( audioWriter != NULL ) { if ( delayNumSamples * num_out_channels < outBufferSize ) { @@ -1884,7 +1882,7 @@ int main( bitsBuffer.config.bitsWritten = 0; /* Write MASA metadata for MASA outputs */ - if ( !flushRendererLastFrame && ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_MASA1 || args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_MASA2 ) ) + if ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_MASA1 || args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_MASA2 ) { IVAS_REND_AudioConfigType inputType1; IVAS_REND_AudioConfigType inputType2; @@ -1956,8 +1954,7 @@ int main( } } - if ( ( args.inConfig.numAmbisonicsBuses > 0 || args.inConfig.numMultiChannelBuses > 0 || args.inConfig.numMasaBuses > 0 ) && - args.inConfig.numAudioObjects > 0 ) + if ( ( args.inConfig.numAmbisonicsBuses > 0 || args.inConfig.numMultiChannelBuses > 0 || args.inConfig.numMasaBuses > 0 ) && args.inConfig.numAudioObjects > 0 ) { inputType2 = IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED; if ( ( error = IVAS_REND_MergeMasaMetadata( hIvasRend, &hMetaOutput, inputType1, inputType2 ) ) != IVAS_ERR_OK ) @@ -1973,13 +1970,6 @@ int main( } } - /* no new input was actually read, only delay buffers were flushed - * therefore this is not a real frame */ - if ( flushRendererLastFrame ) - { - break; - } - frame++; if ( !args.quietModeEnabled ) { @@ -1992,13 +1982,12 @@ int main( #endif } - /* add zeros at the end to have equal length of synthesized signals - * the output buffer will contain either leftover input samples from delay aligned inputs - * or zeros for padding */ + /* add zeros at the end to have equal length of synthesized signals */ if ( audioWriter != NULL ) { for ( zeroPadToWrite = zeroPad; zeroPadToWrite > frameSize_smpls; zeroPadToWrite -= frameSize_smpls ) { + memset( outInt16Buffer, 0, outBufferSize * sizeof( int16_t ) ); if ( ( error = AudioFileWriter_write( audioWriter, outInt16Buffer, outBufferSize ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nOutput audio file writer error\n" ); @@ -2006,6 +1995,7 @@ int main( } } + memset( outInt16Buffer, 0, zeroPadToWrite * outBuffer.config.numChannels * sizeof( int16_t ) ); if ( ( error = AudioFileWriter_write( audioWriter, outInt16Buffer, zeroPadToWrite * outBuffer.config.numChannels ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nOutput audio file writer error\n" ); @@ -2014,10 +2004,9 @@ int main( zeroPadToWrite = 0; } - if ( args.inConfig.numAudioObjects != 0 && - ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL || args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) ) + if ( args.inConfig.numAudioObjects != 0 && ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL || args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) ) { - fprintf( stdout, "\n\nMetadata delayed %d subframes\n\n", (int16_t) round( args.syncMdDelay / ( 1000.f / IVAS_NUM_FRAMES_PER_SEC / IVAS_MAX_PARAM_SPATIAL_SUBFRAMES ) ) ); + fprintf( stdout, "\n\nMetadata delayed %d subframes\n\n", (int16_t) round( args.syncMdDelay / ( 1000 / IVAS_NUM_FRAMES_PER_SEC / IVAS_MAX_PARAM_SPATIAL_SUBFRAMES ) ) ); } if ( !args.quietModeEnabled && args.delayCompensationEnabled ) @@ -2928,7 +2917,7 @@ static void parseOption( case CmdLnOptionId_syncMdDelay: assert( numOptionValues == 1 ); /* Metadata Delay to sync with audio delay in ms */ - args->syncMdDelay = (int16_t) strtol( optionValues[0], NULL, 10 ); + args->syncMdDelay = strtof( optionValues[0], NULL ); break; default: assert( 0 && "This should be unreachable - all command line options should be explicitly handled." ); @@ -3411,8 +3400,7 @@ static void parseObjectPosition( *positionDuration = (uint16_t) strtol( line, &endptr, 10 ); readNextMetadataChunk( line, "\n" ); - read_values = (int16_t) sscanf( line, "%f,%f,%f,%f,%f,%f,%f,%f", - &meta_prm[0], &meta_prm[1], &meta_prm[2], &meta_prm[3], &meta_prm[4], &meta_prm[5], &meta_prm[6], &meta_prm[7] ); + read_values = (int16_t) sscanf( line, "%f,%f,%f,%f,%f,%f,%f,%f", &meta_prm[0], &meta_prm[1], &meta_prm[2], &meta_prm[3], &meta_prm[4], &meta_prm[5], &meta_prm[6], &meta_prm[7] ); if ( read_values < 2 ) { diff --git a/lib_isar/lib_isar_pre_rend.c b/lib_isar/lib_isar_pre_rend.c index ddb663f22..7203c97b2 100644 --- a/lib_isar/lib_isar_pre_rend.c +++ b/lib_isar/lib_isar_pre_rend.c @@ -115,7 +115,9 @@ ivas_error ISAR_PRE_REND_open( isCldfbNeeded = 1; } - if ( isCldfbNeeded && hSplitBinRend->hCldfbHandles == NULL ) + hSplitBinRend->hCldfbHandles = NULL; + + if ( isCldfbNeeded ) { if ( ( hSplitBinRend->hCldfbHandles = (CLDFB_HANDLES_WRAPPER_HANDLE) malloc( sizeof( CLDFB_HANDLES_WRAPPER ) ) ) == NULL ) { diff --git a/lib_rend/lib_rend.c b/lib_rend/lib_rend.c index e69f43e6c..e1dd767ad 100644 --- a/lib_rend/lib_rend.c +++ b/lib_rend/lib_rend.c @@ -44,7 +44,6 @@ #include #include #include "wmc_auto.h" -#include /*-------------------------------------------------------------------* @@ -82,7 +81,6 @@ typedef struct typedef struct { const int32_t *pOutSampleRate; - const int32_t *pMaxGlobalDelayNs; const AUDIO_CONFIG *pOutConfig; const LSSETUP_CUSTOM_STRUCT *pCustomLsOut; const EFAP_WRAPPER *pEfapOutWrapper; @@ -99,11 +97,9 @@ typedef struct AUDIO_CONFIG inConfig; IVAS_REND_InputId id; IVAS_REND_AudioBuffer inputBuffer; - TD_RINGBUF_HANDLE delayBuffer; float gain; /* Linear, not in dB */ rendering_context ctx; int32_t numNewSamplesPerChannel; /* Used to keep track how much new audio was fed before rendering current frame */ - int16_t delayNumSamples; } input_base; typedef struct @@ -126,7 +122,7 @@ typedef struct #ifdef NONBE_1377_REND_DIRATT_CONF int16_t object_id; #endif - int16_t ism_metadata_delay_ms; + float ism_metadata_delay_ms; } input_ism; typedef struct @@ -196,7 +192,6 @@ typedef struct hrtf_handles struct IVAS_REND { int32_t sampleRateOut; - int32_t maxGlobalDelayNs; IVAS_LIMITER_HANDLE hLimiter; #ifdef DEBUGGING @@ -212,12 +207,11 @@ struct IVAS_REND AUDIO_CONFIG outputConfig; EFAP_WRAPPER efapOutWrapper; IVAS_LSSETUP_CUSTOM_STRUCT customLsOut; - - int16_t splitRendBFI; SPLIT_REND_WRAPPER *splitRendWrapper; IVAS_REND_AudioBuffer splitRendEncBuffer; IVAS_REND_HeadRotData headRotData; + int16_t splitRendBFI; EXTERNAL_ORIENTATION_HANDLE hExternalOrientationData; COMBINED_ORIENTATION_HANDLE hCombinedOrientationData; @@ -268,13 +262,6 @@ static void freeInputBaseBufferData( return; } -static int16_t latencyNsToSamples( - int32_t sampleRate, - int32_t latency_ns ) -{ - return (int16_t) roundf( (float) ( latency_ns ) * ( sampleRate / 1000000000.f ) ); -} - static ivas_error allocateMcLfeDelayBuffer( float **lfeDelayBuffer, const int16_t data_size ) @@ -382,7 +369,7 @@ static void copyBufferToCLDFBarray( static void accumulateCLDFBArrayToBuffer( float re[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], float im[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], - const IVAS_REND_AudioBuffer *buffer ) + IVAS_REND_AudioBuffer *buffer ) { uint32_t smplIdx, slotIdx; uint32_t numCldfbSamples, num_bands; @@ -1178,8 +1165,6 @@ static void initRendInputBase( inputBase->gain = 1.0f; inputBase->ctx = rendCtx; inputBase->numNewSamplesPerChannel = 0; - inputBase->delayNumSamples = 0; - inputBase->delayBuffer = NULL; inputBase->inputBuffer.config.numSamplesPerChannel = 0; inputBase->inputBuffer.config.numChannels = 0; @@ -1228,7 +1213,6 @@ static rendering_context getRendCtx( /* Note: when refactoring this, always take the ADDRESS of a member of the * renderer struct, so that the context stores a POINTER to the member, even * if the member is a pointer or handle itself. */ - ctx.pMaxGlobalDelayNs = &hIvasRend->maxGlobalDelayNs; ctx.pOutConfig = &hIvasRend->outputConfig; ctx.pOutSampleRate = &hIvasRend->sampleRateOut; ctx.pCustomLsOut = &hIvasRend->customLsOut; @@ -1271,294 +1255,6 @@ static bool isIoConfigPairSupported( } -static int32_t getRendInputDelayIsm( - const input_ism *inputIsm, - bool splitPreRendCldfb ) -{ - int32_t latency_ns; - latency_ns = 0; - (void) ( splitPreRendCldfb ); /* unused */ - - /* set the rendering delay in InputBase */ - latency_ns = max( latency_ns, - inputIsm->tdRendWrapper.binaural_latency_ns ); - if ( inputIsm->crendWrapper != NULL ) - { - latency_ns = max( latency_ns, - inputIsm->crendWrapper->binaural_latency_ns ); - } - - return latency_ns; -} - - -static void setRendInputDelayIsm( - void *input, - bool splitPreRendCldfb ) -{ - input_ism *inputIsm; - inputIsm = (input_ism *) input; - - inputIsm->base.delayNumSamples = latencyNsToSamples( *inputIsm->base.ctx.pOutSampleRate, - getRendInputDelayIsm( inputIsm, splitPreRendCldfb ) ); -} - - -static int32_t getRendInputDelayMc( - const input_mc *inputMc, - bool splitPreRendCldfb ) -{ - int32_t latency_ns; - latency_ns = 0; - (void) ( splitPreRendCldfb ); /* unused */ - - latency_ns = max( latency_ns, - inputMc->tdRendWrapper.binaural_latency_ns ); - if ( inputMc->crendWrapper != NULL ) - { - latency_ns = max( latency_ns, - inputMc->crendWrapper->binaural_latency_ns ); - } - - return latency_ns; -} - - -static void setRendInputDelayMc( - void *input, - bool splitPreRendCldfb ) -{ - input_mc *inputMc; - inputMc = (input_mc *) input; - - inputMc->base.delayNumSamples = latencyNsToSamples( *inputMc->base.ctx.pOutSampleRate, - getRendInputDelayMc( inputMc, splitPreRendCldfb ) ); -} - - -static int32_t getRendInputDelaySba( - const input_sba *inputSba, - bool splitPreRendCldfb ) -{ - int32_t latency_ns; - latency_ns = 0; - - if ( inputSba->cldfbRendWrapper.hCldfbRend != NULL ) - { - latency_ns = max( latency_ns, - inputSba->cldfbRendWrapper.binaural_latency_ns + - ( splitPreRendCldfb ? 0 : IVAS_FB_DEC_DELAY_NS ) ); - } - if ( inputSba->crendWrapper != NULL ) - { - latency_ns = max( latency_ns, - inputSba->crendWrapper->binaural_latency_ns ); - } - - return latency_ns; -} - - -static void setRendInputDelaySba( - void *input, - bool splitPreRendCldfb ) -{ - input_sba *inputSba; - inputSba = (input_sba *) input; - - inputSba->base.delayNumSamples = latencyNsToSamples( *inputSba->base.ctx.pOutSampleRate, - getRendInputDelaySba( inputSba, splitPreRendCldfb ) ); -} - - -static int32_t getRendInputDelayMasa( - const input_masa *inputMasa, - bool splitPreRendCldfb ) -{ - int32_t latency_ns; - - latency_ns = 0; - - if ( ( inputMasa->base.inConfig == IVAS_AUDIO_CONFIG_MASA1 && *inputMasa->base.ctx.pOutConfig == IVAS_AUDIO_CONFIG_MONO ) || - ( getAudioConfigType( *inputMasa->base.ctx.pOutConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) ) - { - return 0; /* no delay */ - } - else - { - /* no delay applied for split rendering */ - latency_ns = max( latency_ns, - (int32_t) ( ( splitPreRendCldfb ? 0 : (float) IVAS_FB_DEC_DELAY_NS + 0.5f ) ) ); - } - return latency_ns; -} - - -static void setRendInputDelayMasa( - void *input, - bool splitPreRendCldfb ) -{ - input_masa *inputMasa; - inputMasa = (input_masa *) input; - - inputMasa->base.delayNumSamples = latencyNsToSamples( *inputMasa->base.ctx.pOutSampleRate, - getRendInputDelayMasa( inputMasa, splitPreRendCldfb ) ); -} - - -static int32_t getMaxGlobalDelayNs( IVAS_REND_CONST_HANDLE hIvasRend ) -{ - int16_t i; - int32_t latency_ns; - int32_t max_latency_ns; - bool splitPreRendCldfb; - - max_latency_ns = 0; - /*assumes that input has been added which means codec has been set to either lcld or lc3plus (even if render config specified default)*/ - if ( hIvasRend->hRendererConfig != NULL ) - { - splitPreRendCldfb = ( hIvasRend->hRendererConfig->split_rend_config.codec == ISAR_SPLIT_REND_CODEC_LCLD ); - } - else - { - splitPreRendCldfb = false; - } - - /* Compute the maximum delay across all inputs */ - for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; i++ ) - { - if ( hIvasRend->inputsIsm[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) - { - latency_ns = getRendInputDelayIsm( &hIvasRend->inputsIsm[i], splitPreRendCldfb ); - max_latency_ns = max( max_latency_ns, latency_ns ); - } - } - - for ( i = 0; i < RENDERER_MAX_MC_INPUTS; i++ ) - { - if ( hIvasRend->inputsMc[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) - { - latency_ns = getRendInputDelayMc( &hIvasRend->inputsMc[i], splitPreRendCldfb ); - max_latency_ns = max( max_latency_ns, latency_ns ); - } - } - - for ( i = 0; i < RENDERER_MAX_SBA_INPUTS; i++ ) - { - if ( hIvasRend->inputsSba[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) - { - latency_ns = getRendInputDelaySba( &hIvasRend->inputsSba[i], splitPreRendCldfb ); - max_latency_ns = max( max_latency_ns, latency_ns ); - } - } - - for ( i = 0; i < RENDERER_MAX_MASA_INPUTS; i++ ) - { - if ( hIvasRend->inputsMasa[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) - { - latency_ns = getRendInputDelayMasa( &hIvasRend->inputsMasa[i], splitPreRendCldfb ); - max_latency_ns = max( max_latency_ns, latency_ns ); - } - } - - return max_latency_ns; -} - - -static void setMaxGlobalDelayNs( IVAS_REND_HANDLE hIvasRend ) -{ - hIvasRend->maxGlobalDelayNs = getMaxGlobalDelayNs( (IVAS_REND_CONST_HANDLE) hIvasRend ); -} - -static ivas_error alignInputDelay( - input_base *inputBase, - const IVAS_REND_ReadOnlyAudioBuffer inputAudio, - const int32_t maxGlobalDelayNs, - const int32_t sampleRateOut, - const int16_t cldfb2tdSampleFact, - const bool flushInputs ) -{ - ivas_error error; - input_ism *inputIsm; - int16_t maxGlobalDelaySamples, numSamplesToPop, numSamplesToPush; - uint16_t ringBufferSize, preDelay; -#ifdef FIX_1119_SPLIT_RENDERING_VOIP - int16_t i; - const float *p_read_channels[MAX_INPUT_CHANNELS]; - float *p_write_channels[MAX_INPUT_CHANNELS]; -#endif - - maxGlobalDelaySamples = latencyNsToSamples( sampleRateOut, maxGlobalDelayNs ); - maxGlobalDelaySamples *= cldfb2tdSampleFact; - - /* check if we need to open the delay buffer */ - if ( inputBase->delayBuffer == NULL ) - { - /* buffer has to accomodate maxGlobalDelaySamples + 2 * frameSize */ - ringBufferSize = maxGlobalDelaySamples + 2 * inputAudio.config.numSamplesPerChannel; - - /* pre delay for this input is maximum delay - input delay */ - preDelay = maxGlobalDelaySamples - inputBase->delayNumSamples * cldfb2tdSampleFact; - - if ( preDelay > 0 ) - { - if ( ( error = ivas_TD_RINGBUF_Open( &inputBase->delayBuffer, ringBufferSize, inputAudio.config.numChannels ) ) != IVAS_ERR_OK ) - { - return error; - } - - /* for the first frame we need to push zeros to align the input delay to the global delay - * and then push a frame of actual data */ -#ifdef FIX_1119_SPLIT_RENDERING_VOIP - ivas_TD_RINGBUF_PushConstant( inputBase->delayBuffer, 0, preDelay ); -#else - ivas_TD_RINGBUF_PushZeros( inputBase->delayBuffer, preDelay ); -#endif - - /* for ISM inputs, ensure the metadata sync delay is updated */ - if ( getAudioConfigType( inputBase->inConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) - { - inputIsm = (input_ism *) inputBase; - inputIsm->ism_metadata_delay_ms = (int16_t) roundf( inputIsm->ism_metadata_delay_ms + maxGlobalDelayNs / 1e6f ); - } - } - } - - if ( inputBase->delayBuffer != NULL ) - { - /* push in the new input data and pop to retrieve a complete input frame - * if we are flushing the inputs, we don't push in any new data */ - numSamplesToPush = flushInputs ? 0 : inputAudio.config.numSamplesPerChannel; - numSamplesToPop = flushInputs ? ivas_TD_RINGBUF_Size( inputBase->delayBuffer ) : inputAudio.config.numSamplesPerChannel; - -#ifdef FIX_1119_SPLIT_RENDERING_VOIP - for ( i = 0; i < inputAudio.config.numChannels; ++i ) - { - p_read_channels[i] = inputAudio.data + i * numSamplesToPush; - } - ivas_TD_RINGBUF_PushChannels( inputBase->delayBuffer, p_read_channels, numSamplesToPush ); - - for ( i = 0; i < inputAudio.config.numChannels; ++i ) - { - p_write_channels[i] = inputBase->inputBuffer.data + i * numSamplesToPop; - } - ivas_TD_RINGBUF_PopChannels( inputBase->delayBuffer, p_write_channels, numSamplesToPop ); -#else - ivas_TD_RINGBUF_Push( inputBase->delayBuffer, inputAudio.data, numSamplesToPush ); - ivas_TD_RINGBUF_Pop( inputBase->delayBuffer, inputBase->inputBuffer.data, numSamplesToPop ); -#endif - } - else - { - /* delay buffer isn't open - we don't need it */ - mvr2r( inputAudio.data, - inputBase->inputBuffer.data, - inputAudio.config.numSamplesPerChannel * inputAudio.config.numChannels ); - } - - return IVAS_ERR_OK; -} - static ivas_error initIsmMasaRendering( input_ism *inputIsm, const int32_t inSampleRate ) @@ -1705,8 +1401,6 @@ static void clearInputIsm( rendCtx = inputIsm->base.ctx; freeInputBaseBufferData( &inputIsm->base.inputBuffer.data ); - ivas_TD_RINGBUF_Close( &inputIsm->base.delayBuffer ); - initRendInputBase( &inputIsm->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 ); /* Free input's internal handles */ @@ -2485,7 +2179,7 @@ static ivas_error initMcBinauralRendering( /* determine binaural delay ( used for aligning LFE to output signal ) */ binauralDelayNs = max( ( inputMc->crendWrapper != NULL ) ? inputMc->crendWrapper->binaural_latency_ns : 0, inputMc->tdRendWrapper.binaural_latency_ns ); - inputMc->binauralDelaySmp = latencyNsToSamples( *inputMc->base.ctx.pOutSampleRate, binauralDelayNs ); + inputMc->binauralDelaySmp = (int16_t) roundf( (float) binauralDelayNs * *inputMc->base.ctx.pOutSampleRate / 1000000000.f ); if ( inputMc->binauralDelaySmp > MAX_BIN_DELAY_SAMPLES ) { @@ -2684,8 +2378,6 @@ static void clearInputMc( freeMcLfeDelayBuffer( &inputMc->lfeDelayBuffer ); freeInputBaseBufferData( &inputMc->bufferData ); - ivas_TD_RINGBUF_Close( &inputMc->base.delayBuffer ); - initRendInputBase( &inputMc->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 ); /* Free input's internal handles */ @@ -2977,7 +2669,7 @@ static ivas_error setRendInputActiveSba( return error; } - return IVAS_ERR_OK; + return error; } @@ -2989,7 +2681,6 @@ static void clearInputSba( rendCtx = inputSba->base.ctx; freeInputBaseBufferData( &inputSba->bufferData ); - ivas_TD_RINGBUF_Close( &inputSba->base.delayBuffer ); initRendInputBase( &inputSba->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 ); @@ -3070,7 +2761,6 @@ static void clearInputMasa( rendCtx = inputMasa->base.ctx; freeInputBaseBufferData( &inputMasa->bufferData ); - ivas_TD_RINGBUF_Close( &inputMasa->base.delayBuffer ); masaPrerendClose( &inputMasa->hMasaPrerend ); freeMasaExtRenderer( &inputMasa->hMasaExtRend ); @@ -3139,7 +2829,7 @@ ivas_error IVAS_REND_Open( hIvasRend->num_subframes = num_subframes; /* Initialize limiter */ - if ( ( error = IVAS_REND_GetNumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK ) { return error; } @@ -3196,10 +2886,9 @@ ivas_error IVAS_REND_Open( isar_init_split_rend_handles( hIvasRend->splitRendWrapper ); } +#ifdef TEMP_FIX_2088_MSAN_INIT_ERROR hIvasRend->splitRendEncBuffer.data = NULL; - hIvasRend->splitRendEncBuffer.config.is_cldfb = 0; - hIvasRend->splitRendEncBuffer.config.numChannels = 0; - hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel = 0; +#endif for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i ) { @@ -3395,7 +3084,7 @@ ivas_error IVAS_REND_ConfigureCustomOutputLoudspeakerLayout( hIvasRend->customLsOut = makeCustomLsSetup( layout ); /* Re-initialize limiter - number of output channels may have changed */ - if ( ( error = IVAS_REND_GetNumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK ) { return error; } @@ -3452,12 +3141,12 @@ ivas_error IVAS_REND_ConfigureCustomOutputLoudspeakerLayout( /*-------------------------------------------------------------------* - * IVAS_REND_GetNumOutChannels() + * IVAS_REND_NumOutChannels() * * *-------------------------------------------------------------------*/ -ivas_error IVAS_REND_GetNumOutChannels( +ivas_error IVAS_REND_NumOutChannels( IVAS_REND_CONST_HANDLE hIvasRend, int16_t *numOutChannels ) { @@ -3725,15 +3414,10 @@ static int16_t getCldfbRendFlag( const IVAS_REND_AudioConfigType new_configType ) { int16_t i; - int16_t numMasaInputs = 0, numSbaInputs = 0; + int16_t numMasaInputs = 0, numSbaInputs = 0, numIsmInputs = 0, numMcInputs = 0; int16_t isCldfbRend; isCldfbRend = 0; - /* This function is called during three different phases of renderer processing: - * - IVAS_REND_AddInput() - * - IVAS_REND_FeedRenderConfig() - * - IVAS_REND_GetSplitBinauralBitstream() - * Only the last case can assume all inputs are present for the current frame to be rendered */ if ( hIvasRend->hRendererConfig != NULL ) { for ( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i ) @@ -3744,8 +3428,20 @@ static int16_t getCldfbRendFlag( { numSbaInputs += ( hIvasRend->inputsSba[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) ? 0 : 1; } + for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i ) + { + numIsmInputs += ( hIvasRend->inputsIsm[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) ? 0 : 1; + } + for ( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i ) + { + numMcInputs += ( hIvasRend->inputsMc[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) ? 0 : 1; + } - if ( ( numMasaInputs > 0 ) || ( numSbaInputs > 0 && hIvasRend->hRendererConfig->split_rend_config.rendererSelection == IVAS_BIN_RENDERER_TYPE_FASTCONV ) ) + if ( numIsmInputs > 0 || numMcInputs > 0 ) + { + isCldfbRend = 0; + } + else if ( ( numMasaInputs > 0 ) || ( numSbaInputs > 0 && hIvasRend->hRendererConfig->split_rend_config.rendererSelection == IVAS_BIN_RENDERER_TYPE_FASTCONV ) ) { isCldfbRend = 1; } @@ -3755,12 +3451,12 @@ static int16_t getCldfbRendFlag( } /*------------------------------------------------------------------------- - * Function isar_pre_rend_init() + * Function ivas_pre_rend_init() * * *------------------------------------------------------------------------*/ -static ivas_error isar_pre_rend_init( +static ivas_error ivas_pre_rend_init( SPLIT_REND_WRAPPER *pSplitRendWrapper, IVAS_REND_AudioBuffer *pSplitRendEncBuffer, ISAR_SPLIT_REND_CONFIG_DATA *pSplit_rend_config, @@ -3770,20 +3466,10 @@ static ivas_error isar_pre_rend_init( const int16_t cldfb_in_flag, const int16_t num_subframes ) { - bool realloc; ivas_error error; IVAS_REND_AudioBufferConfig bufConfig; - realloc = false; - - /* only perform init if split rendering output */ - if ( outConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED && outConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) - { - return IVAS_ERR_OK; - } - - /* these functions should only be called once during initial allocation */ - if ( pSplitRendEncBuffer->data == NULL ) + if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) { if ( pSplit_rend_config->poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB ) { @@ -3798,34 +3484,28 @@ static ivas_error isar_pre_rend_init( { return error; } - } - - /* We may need to change the allocated buffer size if a new input is added. - * If the cldfb_in_flag is different from what was previously allocated for the buffer, change the size */ - if ( pSplitRendEncBuffer->data != NULL && ( cldfb_in_flag != pSplitRendEncBuffer->config.is_cldfb ) ) - { - realloc = true; - } - if ( pSplitRendEncBuffer->data == NULL || realloc ) - { - /* set buffer config */ - bufConfig.is_cldfb = cldfb_in_flag; - bufConfig.numSamplesPerChannel = cldfb_in_flag ? MAX_CLDFB_BUFFER_LENGTH_PER_CHANNEL : L_FRAME_MAX; + /*allocate for CLDFB in and change to TD during process if needed*/ + bufConfig.numSamplesPerChannel = MAX_CLDFB_BUFFER_LENGTH_PER_CHANNEL; bufConfig.numChannels = BINAURAL_CHANNELS * pSplitRendWrapper->multiBinPoseData.num_poses; + bufConfig.is_cldfb = 1; pSplitRendEncBuffer->config = bufConfig; - /* allocate memory */ - if ( realloc ) - { - free( pSplitRendEncBuffer->data ); - } - if ( ( pSplitRendEncBuffer->data = malloc( bufConfig.numChannels * bufConfig.numSamplesPerChannel * sizeof( float ) ) ) == NULL ) { return IVAS_ERR_FAILED_ALLOC; } } + else + { + IVAS_REND_AudioBufferConfig bufConfig2; + + bufConfig2.numSamplesPerChannel = 0; + bufConfig2.numChannels = 0; + bufConfig2.is_cldfb = 0; + pSplitRendEncBuffer->config = bufConfig2; + pSplitRendEncBuffer->data = NULL; + } return IVAS_ERR_OK; } @@ -3852,10 +3532,7 @@ ivas_error IVAS_REND_AddInput( int32_t inputStructSize; #endif ivas_error ( *activateInput )( void *, AUDIO_CONFIG, IVAS_REND_InputId, RENDER_CONFIG_DATA *, hrtf_handles *hrtfs ); - void ( *setInputDelay )( void *, bool ); int32_t inputIndex; - bool splitPreRendCldfb; - splitPreRendCldfb = false; /* Validate function arguments */ if ( hIvasRend == NULL || inputId == NULL ) @@ -3863,24 +3540,15 @@ ivas_error IVAS_REND_AddInput( return IVAS_ERR_UNEXPECTED_NULL_POINTER; } - if ( hIvasRend->hRendererConfig != NULL ) + if ( ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) && hIvasRend->splitRendEncBuffer.data == NULL && hIvasRend->hRendererConfig != NULL ) { int16_t cldfb_in_flag; cldfb_in_flag = getCldfbRendFlag( hIvasRend, getAudioConfigType( inConfig ) ); - if ( ( error = isar_pre_rend_init( hIvasRend->splitRendWrapper, - &hIvasRend->splitRendEncBuffer, - &hIvasRend->hRendererConfig->split_rend_config, - hIvasRend->headRotData, - hIvasRend->sampleRateOut, - hIvasRend->outputConfig, - cldfb_in_flag, - hIvasRend->num_subframes ) ) != IVAS_ERR_OK ) + if ( ( error = ivas_pre_rend_init( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer, &hIvasRend->hRendererConfig->split_rend_config, hIvasRend->headRotData, hIvasRend->sampleRateOut, hIvasRend->outputConfig, cldfb_in_flag, hIvasRend->num_subframes ) ) != IVAS_ERR_OK ) { return error; } - /*assumes that input has been added which means codec has been set to either lcld or lc3plus (even if render config specified default)*/ - splitPreRendCldfb = ( hIvasRend->hRendererConfig->split_rend_config.codec == ISAR_SPLIT_REND_CODEC_LCLD ); } #ifdef CODE_IMPROVEMENTS @@ -3897,7 +3565,6 @@ ivas_error IVAS_REND_AddInput( inputStructSize = sizeof( *hIvasRend->inputsIsm ); #endif activateInput = setRendInputActiveIsm; - setInputDelay = setRendInputDelayIsm; break; case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED: maxNumInputsOfType = RENDERER_MAX_MC_INPUTS; @@ -3906,7 +3573,6 @@ ivas_error IVAS_REND_AddInput( inputStructSize = sizeof( *hIvasRend->inputsMc ); #endif activateInput = setRendInputActiveMc; - setInputDelay = setRendInputDelayMc; break; case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS: maxNumInputsOfType = RENDERER_MAX_SBA_INPUTS; @@ -3915,7 +3581,6 @@ ivas_error IVAS_REND_AddInput( inputStructSize = sizeof( *hIvasRend->inputsSba ); #endif activateInput = setRendInputActiveSba; - setInputDelay = setRendInputDelaySba; break; case IVAS_REND_AUDIO_CONFIG_TYPE_MASA: maxNumInputsOfType = RENDERER_MAX_MASA_INPUTS; @@ -3924,7 +3589,6 @@ ivas_error IVAS_REND_AddInput( inputStructSize = sizeof( *hIvasRend->inputsMasa ); #endif activateInput = setRendInputActiveMasa; - setInputDelay = setRendInputDelayMasa; break; default: return IVAS_ERR_INVALID_INPUT_FORMAT; @@ -3949,14 +3613,6 @@ ivas_error IVAS_REND_AddInput( { return error; } -#ifdef CODE_IMPROVEMENTS - setInputDelay( getInputByIndex( inputsArray, inputIndex, inputType ), splitPreRendCldfb ); -#else - setInputDelay( (uint8_t *) inputsArray + inputStructSize * inputIndex, splitPreRendCldfb ); -#endif - - /* set global maximum delay after adding an input */ - setMaxGlobalDelayNs( hIvasRend ); return IVAS_ERR_OK; } @@ -4239,9 +3895,6 @@ ivas_error IVAS_REND_RemoveInput( return IVAS_ERR_INVALID_INPUT_FORMAT; } - /* set global maximum delay after removing an input */ - setMaxGlobalDelayNs( hIvasRend ); - return IVAS_ERR_OK; } @@ -4318,6 +3971,11 @@ ivas_error IVAS_REND_GetDelay( int32_t *timeScale /* o : Time scale of the delay, equal to renderer output sampling rate */ ) { + /* TODO tmu : this function only returns the maximum delay across all inputs + * Ideally each input has its own delay buffer and everything is aligned (binaural and LFE filtering delays are nonuniform) + */ + int16_t i; + int32_t latency_ns; int32_t max_latency_ns; /* Validate function arguments */ @@ -4326,11 +3984,71 @@ ivas_error IVAS_REND_GetDelay( return IVAS_ERR_UNEXPECTED_NULL_POINTER; } - *nSamples = 0; *timeScale = hIvasRend->sampleRateOut; - max_latency_ns = getMaxGlobalDelayNs( hIvasRend ); + *nSamples = 0; + max_latency_ns = 0; - *nSamples = latencyNsToSamples( hIvasRend->sampleRateOut, max_latency_ns ); + /* Compute the maximum delay across all inputs */ + for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; i++ ) + { + if ( hIvasRend->inputsIsm[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) + { + latency_ns = max( ( hIvasRend->inputsIsm[i].crendWrapper != NULL ) ? hIvasRend->inputsIsm[i].crendWrapper->binaural_latency_ns : 0, + hIvasRend->inputsIsm[i].tdRendWrapper.binaural_latency_ns ); + max_latency_ns = max( max_latency_ns, latency_ns ); + } + } + + for ( i = 0; i < RENDERER_MAX_MC_INPUTS; i++ ) + { + if ( hIvasRend->inputsMc[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) + { + latency_ns = max( ( hIvasRend->inputsMc[i].crendWrapper != NULL ) ? hIvasRend->inputsMc[i].crendWrapper->binaural_latency_ns : 0, + hIvasRend->inputsMc[i].tdRendWrapper.binaural_latency_ns ); + max_latency_ns = max( max_latency_ns, latency_ns ); + } + } + + for ( i = 0; i < RENDERER_MAX_SBA_INPUTS; i++ ) + { + if ( hIvasRend->inputsSba[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) + { + if ( hIvasRend->splitRendWrapper != NULL && hIvasRend->splitRendWrapper->hBinHrSplitPreRend != NULL ) + { + if ( hIvasRend->hRendererConfig->split_rend_config.rendererSelection == IVAS_BIN_RENDERER_TYPE_FASTCONV ) + { + latency_ns = hIvasRend->inputsSba[i].cldfbRendWrapper.binaural_latency_ns; + } + else + { + latency_ns = ( hIvasRend->inputsSba[i].crendWrapper != NULL ) ? hIvasRend->inputsSba[i].crendWrapper->binaural_latency_ns : 0; + } + max_latency_ns = max( max_latency_ns, latency_ns ); + } + else if ( hIvasRend->inputsSba[i].cldfbRendWrapper.hCldfbRend != NULL ) + { + latency_ns = hIvasRend->inputsSba[i].cldfbRendWrapper.binaural_latency_ns; + latency_ns += IVAS_FB_DEC_DELAY_NS; + max_latency_ns = max( max_latency_ns, latency_ns ); + } + else + { + latency_ns = ( hIvasRend->inputsSba[i].crendWrapper != NULL ) ? hIvasRend->inputsSba[i].crendWrapper->binaural_latency_ns : 0; + max_latency_ns = max( max_latency_ns, latency_ns ); + } + } + } + + for ( i = 0; i < RENDERER_MAX_MASA_INPUTS; i++ ) + { + if ( hIvasRend->inputsMasa[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) + { + latency_ns = (int32_t) ( (float) IVAS_FB_DEC_DELAY_NS + 0.5f ); + max_latency_ns = max( max_latency_ns, latency_ns ); + } + } + + *nSamples = (int16_t) roundf( (float) max_latency_ns * *timeScale / 1000000000.f ); return IVAS_ERR_OK; } @@ -4343,10 +4061,9 @@ ivas_error IVAS_REND_GetDelay( *-------------------------------------------------------------------*/ ivas_error IVAS_REND_FeedInputAudio( - IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ - const IVAS_REND_InputId inputId, /* i : ID of the input */ - const IVAS_REND_ReadOnlyAudioBuffer inputAudio, /* i : buffer with input audio */ - const bool flushInputs /* i : flush input audio */ + IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ + const IVAS_REND_InputId inputId, /* i : ID of the input */ + const IVAS_REND_ReadOnlyAudioBuffer inputAudio /* i : buffer with input audio */ ) { ivas_error error; @@ -4402,16 +4119,9 @@ ivas_error IVAS_REND_FeedInputAudio( } inputBase->inputBuffer.config = inputAudio.config; - if ( ( error = alignInputDelay( - inputBase, - inputAudio, - hIvasRend->maxGlobalDelayNs, - hIvasRend->sampleRateOut, - cldfb2tdSampleFact, - flushInputs ) ) != IVAS_ERR_OK ) - { - return error; - } + + mvr2r( inputAudio.data, inputBase->inputBuffer.data, inputAudio.config.numSamplesPerChannel * inputAudio.config.numChannels ); + inputBase->numNewSamplesPerChannel = inputAudio.config.numSamplesPerChannel / cldfb2tdSampleFact; return IVAS_ERR_OK; @@ -4724,7 +4434,6 @@ ivas_error IVAS_REND_FeedRenderConfig( if ( pMasaInput->hMasaExtRend->hDiracDecBin[0] != NULL && pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb != NULL ) { ivas_binaural_reverb_close( &pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb ); - if ( ( error = ivas_binaural_reverb_init( &pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb, // Todo 1892 hIvasRend->hHrtfs.hHrtfStatistics, pMasaInput->hMasaExtRend->hSpatParamRendCom->num_freq_bands, @@ -4741,7 +4450,6 @@ ivas_error IVAS_REND_FeedRenderConfig( if ( pMasaInput->hMasaExtRend->hReverb != NULL ) { ivas_binaural_reverb_close( &pMasaInput->hMasaExtRend->hReverb ); - if ( ( error = ivas_binaural_reverb_init( &pMasaInput->hMasaExtRend->hReverb, // Todo 1892 hIvasRend->hHrtfs.hHrtfStatistics, pMasaInput->hMasaExtRend->hSpatParamRendCom->num_freq_bands, @@ -4774,7 +4482,6 @@ ivas_error IVAS_REND_FeedRenderConfig( return error; } } - if ( pMcInput->crendWrapper != NULL && pMcInput->crendWrapper->hCrend[0] != NULL && pMcInput->crendWrapper->hCrend[0]->hReverb != NULL ) { if ( ( error = ivas_reverb_open( &pMcInput->crendWrapper->hCrend[0]->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, hRenderConfig, *pMcInput->base.ctx.pOutSampleRate ) ) != IVAS_ERR_OK ) @@ -4825,7 +4532,6 @@ ivas_error IVAS_REND_FeedRenderConfig( { int16_t cldfb_in_flag; cldfb_in_flag = getCldfbRendFlag( hIvasRend, IVAS_REND_AUDIO_CONFIG_TYPE_UNKNOWN ); - if ( hIvasRend->splitRendWrapper != NULL ) { ISAR_PRE_REND_close( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer ); @@ -4833,7 +4539,7 @@ ivas_error IVAS_REND_FeedRenderConfig( hIvasRend->splitRendWrapper = NULL; } - if ( ( error = isar_pre_rend_init( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer, &hIvasRend->hRendererConfig->split_rend_config, hIvasRend->headRotData, hIvasRend->sampleRateOut, hIvasRend->outputConfig, cldfb_in_flag, hIvasRend->num_subframes ) ) != IVAS_ERR_OK ) + if ( ( error = ivas_pre_rend_init( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer, &hIvasRend->hRendererConfig->split_rend_config, hIvasRend->headRotData, hIvasRend->sampleRateOut, hIvasRend->outputConfig, cldfb_in_flag, hIvasRend->num_subframes ) ) != IVAS_ERR_OK ) { return error; } @@ -5562,9 +5268,8 @@ static ivas_error renderIsmToBinaural( int16_t ism_md_subframe_update_ext; push_wmops( "renderIsmToBinaural" ); - /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */ - ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / (float) BINAURAL_RENDERING_FRAME_SIZE_MS ); + ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / ( 1000 / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES ) ); copyBufferTo2dArray( ismInput->base.inputBuffer, tmpTDRendBuffer ); if ( ( error = ivas_td_binaural_renderer_ext( &ismInput->tdRendWrapper, ismInput->base.inConfig, NULL, ismInput->base.ctx.pCombinedOrientationData, &ismInput->currentPos, ismInput->hReverb, ism_md_subframe_update_ext, @@ -5767,7 +5472,8 @@ static ivas_error renderIsmToBinauralReverb( push_wmops( "renderIsmToBinauralRoom" ); /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */ - ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / (float) BINAURAL_RENDERING_FRAME_SIZE_MS ); + ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / ( 1000 / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES ) ); + copyBufferTo2dArray( ismInput->base.inputBuffer, tmpRendBuffer ); if ( ( error = ivas_td_binaural_renderer_ext( &ismInput->tdRendWrapper, ismInput->base.inConfig, NULL, ismInput->base.ctx.pCombinedOrientationData, &ismInput->currentPos, ismInput->hReverb, @@ -5932,10 +5638,8 @@ static ivas_error renderIsmToSplitBinaural( const MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData; const SPLIT_REND_WRAPPER *pSplitRendWrapper; IVAS_QUATERNION originalHeadRot[MAX_PARAM_SPATIAL_SUBFRAMES]; - int16_t i, ch, slot_idx, num_bands; + int16_t i; float tmpBinaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k]; - float tmpBinaural_CldfbRe[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; - float tmpBinaural_CldfbIm[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; int16_t output_frame = ismInput->base.inputBuffer.config.numSamplesPerChannel; COMBINED_ORIENTATION_HANDLE pCombinedOrientationData; int16_t ism_md_subframe_update_ext; @@ -5946,7 +5650,7 @@ static ivas_error renderIsmToSplitBinaural( pMultiBinPoseData = &pSplitRendWrapper->multiBinPoseData; /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */ - ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / (float) BINAURAL_RENDERING_FRAME_SIZE_MS ); + ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / ( 1000 / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES ) ); pCombinedOrientationData = *ismInput->base.ctx.pCombinedOrientationData; @@ -6002,29 +5706,10 @@ static ivas_error renderIsmToSplitBinaural( return error; } - if ( outAudio.config.is_cldfb ) - { - /* Perform CLDFB analysis on rendered audio, since the output buffer is CLDFB domain */ - num_bands = (int16_t) ( ( BINAURAL_MAXBANDS * *ismInput->base.ctx.pOutSampleRate ) / 48000 ); - for ( ch = 0; ch < BINAURAL_CHANNELS; ch++ ) - { - for ( slot_idx = 0; slot_idx < IVAS_CLDFB_NO_COL_MAX; slot_idx++ ) - { - cldfbAnalysis_ts( &tmpProcessing[ch][num_bands * slot_idx], - &tmpBinaural_CldfbRe[BINAURAL_CHANNELS * pos_idx + ch][slot_idx][0], - &tmpBinaural_CldfbIm[BINAURAL_CHANNELS * pos_idx + ch][slot_idx][0], - num_bands, - ismInput->base.ctx.pSplitRendWrapper->hCldfbHandles->cldfbAna[pos_idx + ch] ); - } - } - } - else - { - /* Copy rendered audio to tmp storage buffer. Copying directly to output would - * overwrite original audio, which is still needed for rendering next head pose. */ - mvr2r( tmpProcessing[0], tmpBinaural[BINAURAL_CHANNELS * pos_idx], output_frame ); - mvr2r( tmpProcessing[1], tmpBinaural[BINAURAL_CHANNELS * pos_idx + 1], output_frame ); - } + /* Copy rendered audio to tmp storage buffer. Copying directly to output would + * overwrite original audio, which is still needed for rendering next head pose. */ + mvr2r( tmpProcessing[0], tmpBinaural[2 * pos_idx], output_frame ); + mvr2r( tmpProcessing[1], tmpBinaural[2 * pos_idx + 1], output_frame ); /* Overwrite processing buffer with original input audio again */ copyBufferTo2dArray( ismInput->base.inputBuffer, tmpProcessing ); @@ -6036,14 +5721,7 @@ static ivas_error renderIsmToSplitBinaural( pCombinedOrientationData->Quaternions[i] = originalHeadRot[i]; } - if ( outAudio.config.is_cldfb ) - { - accumulateCLDFBArrayToBuffer( tmpBinaural_CldfbRe, tmpBinaural_CldfbIm, &outAudio ); - } - else - { - accumulate2dArrayToBuffer( tmpBinaural, &outAudio ); - } + accumulate2dArrayToBuffer( tmpBinaural, &outAudio ); pop_wmops(); /* Encoding to split rendering bitstream done at a higher level */ @@ -6078,13 +5756,11 @@ static ivas_error renderInputIsm( { ivas_error error; IVAS_REND_AudioBuffer inAudio; - int16_t cldfb2tdSampleFact; error = IVAS_ERR_OK; inAudio = ismInput->base.inputBuffer; - cldfb2tdSampleFact = outAudio.config.is_cldfb ? 2 : 1; - if ( ismInput->base.numNewSamplesPerChannel * cldfb2tdSampleFact != outAudio.config.numSamplesPerChannel ) + if ( ismInput->base.numNewSamplesPerChannel != outAudio.config.numSamplesPerChannel ) { return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Mismatch between the number of input samples vs number of requested output samples - currently not allowed" ); } @@ -6209,7 +5885,8 @@ static ivas_error renderLfeToBinaural( num_cpy_smpl_prev_frame = mcInput->binauralDelaySmp; num_cpy_smpl_cur_frame = frame_size - num_cpy_smpl_prev_frame; - assert( mcInput->binauralDelaySmp <= MAX_BIN_DELAY_SAMPLES ); + /* Assuming LFE should be delayed by less that the duration of one frame */ + assert( mcInput->binauralDelaySmp < frame_size ); /* Get delayed LFE signal from previous frame, apply gain and save in tmp buffer */ v_multc( mcInput->lfeDelayBuffer, gain, tmpLfeBuffer, num_cpy_smpl_prev_frame ); @@ -7769,7 +7446,7 @@ ivas_error IVAS_REND_SetTotalNumberOfObjects( ivas_error IVAS_REND_SetIsmMetadataDelay( IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */ - const int16_t sync_md_delay /* i : ISM Metadata Delay in ms to sync with audio delay */ + const float sync_md_delay /* i : ISM Metadata Delay in ms to sync with audio delay */ ) { int16_t i; @@ -7795,13 +7472,15 @@ ivas_error IVAS_REND_SetIsmMetadataDelay( *-------------------------------------------------------------------*/ static ivas_error getSamplesInternal( - IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ - IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */ + IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ + IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */, + IVAS_REND_BitstreamBuffer *hBits /*i/o: buffer for input/output bitstream. Needed in split rendering mode*/ ) { ivas_error error; int16_t numOutChannels; int16_t cldfb2tdSampleFact; + IVAS_REND_AudioBuffer outAudioOrig; /* Validate function arguments */ if ( hIvasRend == NULL || outAudio.data == NULL ) @@ -7861,21 +7540,34 @@ static ivas_error getSamplesInternal( } } - if ( ( error = IVAS_REND_GetNumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK ) { return error; } - if ( numOutChannels != outAudio.config.numChannels && - hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED && - hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) + if ( numOutChannels != outAudio.config.numChannels && hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED && hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) { return IVAS_ERR_WRONG_NUM_CHANNELS; } - /* Clear output buffer */ + /* Clear original output buffer */ set_zero( outAudio.data, outAudio.config.numChannels * outAudio.config.numSamplesPerChannel ); + outAudioOrig = outAudio; + /* Use internal buffer if outputting split rendering bitstream */ + if ( ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) || + ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ) + { + int16_t num_poses_orig; + num_poses_orig = hIvasRend->splitRendWrapper->multiBinPoseData.num_poses; + outAudio = hIvasRend->splitRendEncBuffer; + ISAR_PRE_REND_GetMultiBinPoseData( &hIvasRend->hRendererConfig->split_rend_config, &hIvasRend->splitRendWrapper->multiBinPoseData, hIvasRend->headRotData.sr_pose_pred_axis ); + assert( num_poses_orig == hIvasRend->splitRendWrapper->multiBinPoseData.num_poses && "number of poses should not change dynamically" ); + + /* Clear output buffer for split rendering bitstream */ + set_zero( outAudio.data, outAudio.config.numChannels * outAudio.config.numSamplesPerChannel ); + } + if ( ( error = renderActiveInputsIsm( hIvasRend, outAudio ) ) != IVAS_ERR_OK ) { return error; @@ -7896,26 +7588,91 @@ static ivas_error getSamplesInternal( return error; } - return IVAS_ERR_OK; -} + if ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) + { + ISAR_SPLIT_REND_BITS_DATA bits; + int16_t cldfb_in_flag; + float Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; + float Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; + int16_t ch; + int16_t i, ro_md_flag; + float *tmpBinaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS], tmpBinaural_buff[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k]; +#ifdef FIX_1119_SPLIT_RENDERING_VOIP /* Temporary fix. Proper implementation of port 391 can only be added once port 369 is complete. */ + float *p_Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX]; + float *p_Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX]; + + for ( ch = 0; ch < MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS; ++ch ) + { + for ( i = 0; i < CLDFB_NO_COL_MAX; ++i ) + { + p_Cldfb_RealBuffer_Binaural[ch][i] = Cldfb_RealBuffer_Binaural[ch][i]; + p_Cldfb_ImagBuffer_Binaural[ch][i] = Cldfb_ImagBuffer_Binaural[ch][i]; + } + } +#endif + for ( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ ) + { + tmpBinaural[ch] = tmpBinaural_buff[ch]; + } -/*-------------------------------------------------------------------* - * IVAS_REND_GetSamples() - * - * - *-------------------------------------------------------------------*/ + if ( outAudio.config.is_cldfb == 1 ) + { + cldfb_in_flag = 1; + copyBufferToCLDFBarray( outAudio, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural ); + } + else + { + cldfb_in_flag = 0; + copyBufferTo2dArray( outAudio, tmpBinaural_buff ); + } -ivas_error IVAS_REND_GetSamples( - IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ - IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */ -) -{ - ivas_error error; + /* Encode split rendering bitstream */ + convertBitsBufferToInternalBitsBuff( *hBits, &bits ); - if ( ( error = getSamplesInternal( hIvasRend, outAudio ) ) != IVAS_ERR_OK ) - { - return error; + ro_md_flag = 0; + for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i ) + { + if ( hIvasRend->inputsIsm[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) + { + ro_md_flag = 1; + break; + } + } + + if ( ( error = ISAR_PRE_REND_MultiBinToSplitBinaural( hIvasRend->splitRendWrapper, + hIvasRend->headRotData.headPositions[0], + hIvasRend->hRendererConfig->split_rend_config.splitRendBitRate, + hIvasRend->hRendererConfig->split_rend_config.codec, + hIvasRend->hRendererConfig->split_rend_config.isar_frame_size_ms, + hIvasRend->hRendererConfig->split_rend_config.codec_frame_size_ms, + &bits, +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + p_Cldfb_RealBuffer_Binaural, + p_Cldfb_ImagBuffer_Binaural, +#else + Cldfb_RealBuffer_Binaural, + Cldfb_ImagBuffer_Binaural, +#endif + ( const int16_t )( ( BINAURAL_MAXBANDS * hIvasRend->sampleRateOut ) / 48000 ), + tmpBinaural, + 1, + cldfb_in_flag, + ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ? 1 : 0, + ro_md_flag ) ) != IVAS_ERR_OK ) + { + return error; + } + + convertInternalBitsBuffToBitsBuffer( hBits, bits ); + + /* reset to outAudioOrig in case of PCM output */ + outAudio = outAudioOrig; + + if ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) + { + accumulate2dArrayToBuffer( tmpBinaural_buff, &outAudio ); + } } if ( outAudio.config.is_cldfb == 0 ) @@ -7935,152 +7692,52 @@ ivas_error IVAS_REND_GetSamples( } +/*-------------------------------------------------------------------* + * IVAS_REND_GetSamples() + * + * + *-------------------------------------------------------------------*/ + +ivas_error IVAS_REND_GetSamples( + IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ + IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */ +) +{ + + return getSamplesInternal( hIvasRend, outAudio, NULL ); +} + + /*-------------------------------------------------------------------* * IVAS_REND_GetSplitBinauralBitstream() * * *-------------------------------------------------------------------*/ -ivas_error IVAS_REND_GetSplitBinauralBitstream( +ivas_error +IVAS_REND_GetSplitBinauralBitstream( IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ IVAS_REND_AudioBuffer outAudio, /* i/o: buffer for output audio */ IVAS_REND_BitstreamBuffer *hBits /* o : buffer for output bitstream */ ) { - ivas_error error; - int16_t ch; int16_t cldfb_in_flag; - int16_t i, ro_md_flag; - int16_t num_poses_orig; - float *tmpBinaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS], tmpBinaural_buff[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k]; - float Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; - float Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; - IVAS_REND_AudioBufferConfig *pSplitEncBufConfig; - ISAR_SPLIT_REND_CONFIG_HANDLE pSplitRendConfig; - ISAR_SPLIT_REND_BITS_DATA bits; -#ifdef FIX_1119_SPLIT_RENDERING_VOIP - float *p_Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX]; - float *p_Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX]; - int16_t j; - - for ( i = 0; i < BINAURAL_CHANNELS * MAX_HEAD_ROT_POSES; ++i ) - { - for ( j = 0; j < CLDFB_NO_COL_MAX; ++j ) - { - p_Cldfb_RealBuffer_Binaural[i][j] = Cldfb_RealBuffer_Binaural[i][j]; - p_Cldfb_ImagBuffer_Binaural[i][j] = Cldfb_ImagBuffer_Binaural[i][j]; - } - } -#endif - - for ( ch = 0; ch < MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS; ch++ ) - { - tmpBinaural[ch] = tmpBinaural_buff[ch]; - } cldfb_in_flag = getCldfbRendFlag( hIvasRend, IVAS_REND_AUDIO_CONFIG_TYPE_UNKNOWN ); - pSplitEncBufConfig = &hIvasRend->splitRendEncBuffer.config; - pSplitRendConfig = &hIvasRend->hRendererConfig->split_rend_config; - - /* 0 DoF / No pose correction retains frame size */ - pSplitEncBufConfig->is_cldfb = cldfb_in_flag; - if ( pSplitRendConfig->dof == 0 || pSplitRendConfig->poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE ) - { - pSplitEncBufConfig->numSamplesPerChannel = outAudio.config.numSamplesPerChannel; - } - /* Pose correction requires 20ms */ - else - { - pSplitEncBufConfig->numSamplesPerChannel = (int16_t) ( hIvasRend->sampleRateOut / FRAMES_PER_SEC ); - } - pSplitEncBufConfig->numSamplesPerChannel *= cldfb_in_flag ? 2 : 1; - - num_poses_orig = hIvasRend->splitRendWrapper->multiBinPoseData.num_poses; - ISAR_PRE_REND_GetMultiBinPoseData( pSplitRendConfig, - &hIvasRend->splitRendWrapper->multiBinPoseData, - hIvasRend->headRotData.sr_pose_pred_axis ); - assert( num_poses_orig == hIvasRend->splitRendWrapper->multiBinPoseData.num_poses && "number of poses should not change dynamically" ); - - /* hIvasRend->splitRendEncBuffer contains multi-pose data for BINAURAL_SPLIT_CODED output - outAudio used later for main pose BINAURAL_SPLIT_PCM output */ - if ( ( error = getSamplesInternal( hIvasRend, hIvasRend->splitRendEncBuffer ) ) != IVAS_ERR_OK ) + hIvasRend->splitRendEncBuffer.config.is_cldfb = cldfb_in_flag; + if ( hIvasRend->hRendererConfig->split_rend_config.dof == 0 || hIvasRend->hRendererConfig->split_rend_config.poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE ) { - return error; - } - - /* copy outputs */ - if ( hIvasRend->splitRendEncBuffer.config.is_cldfb == 1 ) - { - cldfb_in_flag = 1; - copyBufferToCLDFBarray( hIvasRend->splitRendEncBuffer, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural ); + hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel = outAudio.config.numSamplesPerChannel; } else { - cldfb_in_flag = 0; - copyBufferTo2dArray( hIvasRend->splitRendEncBuffer, tmpBinaural_buff ); - } - - /* Encode split rendering bitstream */ - convertBitsBufferToInternalBitsBuff( *hBits, &bits ); - - ro_md_flag = 0; - for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i ) - { - if ( hIvasRend->inputsIsm[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) - { - ro_md_flag = 1; - break; - } - } - - if ( ( error = ISAR_PRE_REND_MultiBinToSplitBinaural( hIvasRend->splitRendWrapper, - hIvasRend->headRotData.headPositions[0], - pSplitRendConfig->splitRendBitRate, - pSplitRendConfig->codec, - pSplitRendConfig->isar_frame_size_ms, - pSplitRendConfig->codec_frame_size_ms, - &bits, -#ifdef FIX_1119_SPLIT_RENDERING_VOIP - p_Cldfb_RealBuffer_Binaural, - p_Cldfb_ImagBuffer_Binaural, -#else - Cldfb_RealBuffer_Binaural, - Cldfb_ImagBuffer_Binaural, -#endif - ( const int16_t )( ( BINAURAL_MAXBANDS * hIvasRend->sampleRateOut ) / 48000 ), - tmpBinaural, - 1, - cldfb_in_flag, - ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ? 1 : 0, - ro_md_flag ) ) != IVAS_ERR_OK ) - { - return error; - } - - convertInternalBitsBuffToBitsBuffer( hBits, bits ); - - /* copy over first pose data to outAudio */ - if ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) - { - /* set outAudio to zero - getSamplesInternal only cleared splitRendEncBuffer */ - set_zero( outAudio.data, outAudio.config.numChannels * outAudio.config.numSamplesPerChannel ); - accumulate2dArrayToBuffer( tmpBinaural_buff, &outAudio ); - } - - if ( outAudio.config.is_cldfb == 0 ) - { -#ifndef DISABLE_LIMITER -#ifdef DEBUGGING - hIvasRend->numClipping += -#endif - limitRendererOutput( hIvasRend->hLimiter, outAudio.data, outAudio.config.numSamplesPerChannel, IVAS_LIMITER_THRESHOLD ); -#endif + hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel = (int16_t) ( hIvasRend->sampleRateOut / FRAMES_PER_SEC ); } + hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel *= cldfb_in_flag ? 2 : 1; - /* update global cominbed orientation start index */ - ivas_combined_orientation_update_start_index( hIvasRend->hCombinedOrientationData, outAudio.config.numSamplesPerChannel ); - - return IVAS_ERR_OK; + /* hIvasRend->splitRendEncBuffer used for BINAURAL_SPLIT_CODED output + outAudio used for BINAURAL_SPLIT_PCM output */ + return getSamplesInternal( hIvasRend, outAudio, hBits ); } ivas_error IVAS_REND_GetSplitRendBitstreamHeader( diff --git a/lib_rend/lib_rend.h b/lib_rend/lib_rend.h index 4b6e7340f..61c7d0094 100644 --- a/lib_rend/lib_rend.h +++ b/lib_rend/lib_rend.h @@ -113,15 +113,15 @@ typedef enum _IVAS_REND_COMPLEXITY_LEVEL /* Functions to be called before rendering */ ivas_error IVAS_REND_Open( - IVAS_REND_HANDLE *phIvasRend, /* i/o: Pointer to renderer handle */ - const int32_t outputSampleRate, /* i : output sampling rate */ - const IVAS_AUDIO_CONFIG outConfig, /* i : output audio config */ - const bool asHrtfBinary, /* i : load hrtf binary file */ - const int16_t nonDiegeticPan, /* i : non-diegetic object flag */ - const float nonDiegeticPanGain, /* i : non-diegetic panning gain */ - const int16_t Opt_Headrotation, /* i : indicates whether head-rotation is used */ - const int16_t Opt_ExternalOrientation, /* i : indicates whether external orientations are used */ - const int16_t num_subframes /* i : number of subframes */ + IVAS_REND_HANDLE *phIvasRend, /* i/o: Pointer to renderer handle */ + const int32_t outputSampleRate, /* i : output sampling rate */ + const IVAS_AUDIO_CONFIG outConfig, /* i : output audio config */ + const bool asHrtfBinary, /* i : load hrtf binary file */ + const int16_t nonDiegeticPan, /* i : non-diegetic object flag */ + const float nonDiegeticPanGain, /* i : non-diegetic panning gain */ + const int16_t Opt_Headrotation, /* i : indicates whether head-rotation is used */ + const int16_t Opt_ExternalOrientation, /* i : indicates whether external orientations are used */ + const int16_t num_subframes /* i : number of subframes */ ); /* Note: this will reset custom LFE routings set for any MC input */ @@ -133,7 +133,7 @@ ivas_error IVAS_REND_ConfigureCustomOutputLoudspeakerLayout( /* Functions to be called before/during rendering */ -ivas_error IVAS_REND_GetNumOutChannels( +ivas_error IVAS_REND_NumOutChannels( IVAS_REND_CONST_HANDLE hIvasRend, /* i : Renderer handle */ int16_t *numOutChannels /* o : number of output channels */ ); @@ -224,10 +224,9 @@ ivas_error IVAS_REND_GetHrtfStatisticsHandle( /* Functions to be called during rendering */ ivas_error IVAS_REND_FeedInputAudio( - IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ - const IVAS_REND_InputId inputId, /* i : ID of the input */ - const IVAS_REND_ReadOnlyAudioBuffer inputAudio, /* i : buffer with input audio */ - const bool flushInputs /* i : flush input audio */ + IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ + const IVAS_REND_InputId inputId, /* i : ID of the input */ + const IVAS_REND_ReadOnlyAudioBuffer inputAudio /* i : buffer with input audio */ ); ivas_error IVAS_REND_FeedInputObjectMetadata( @@ -372,7 +371,7 @@ ivas_error IVAS_REND_SetTotalNumberOfObjects( ivas_error IVAS_REND_SetIsmMetadataDelay( IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */ - const int16_t sync_md_delay /* i : Metadata Delay in ms to sync with audio delay */ + const float sync_md_delay /* i : Metadata Delay in ms to sync with audio delay */ ); ivas_error IVAS_REND_GetNumAllObjects( @@ -388,7 +387,7 @@ ivas_error IVAS_REND_GetSamples( /* Functions to be called after rendering */ void IVAS_REND_Close( - IVAS_REND_HANDLE *phIvasRend /* i/o: Pointer to renderer handle */ + IVAS_REND_HANDLE* phIvasRend /* i/o: Pointer to renderer handle */ ); -- GitLab