diff --git a/lib_com/ivas_prot.h b/lib_com/ivas_prot.h index 48c54cbad2584ddf8deb0ca5c01b893d9b43f01c..72d0ff2683c35584e71b12f64e05a84d23d3d03d 100755 --- a/lib_com/ivas_prot.h +++ b/lib_com/ivas_prot.h @@ -2920,6 +2920,13 @@ int16_t check_bounds_s( const int16_t high /* i : High limit */ ); +#ifdef FIX_CRASH_LONG_BRIR +void set_zero_l( + float *vec, /* o : input vector */ + const uint32_t lvec /* i : length of the vector */ +); +#endif + ivas_error stereo_memory_enc( CPE_ENC_HANDLE hCPE, /* i : CPE encoder structure */ const int32_t input_Fs, /* i : input sampling rate */ diff --git a/lib_com/ivas_tools.c b/lib_com/ivas_tools.c index ee7a06ca7d9b7300b7fd00eff316ef8ccf6ed775..e3bb312224a684bf38bf6279652fcd720afe24b9 100644 --- a/lib_com/ivas_tools.c +++ b/lib_com/ivas_tools.c @@ -579,6 +579,28 @@ int16_t check_bounds_s( return value_adj; } +#ifdef FIX_CRASH_LONG_BRIR +/*---------------------------------------------------------------------* + * set_zero_l() + * + * Set a vector vec[] of dimension lvec to zero + *---------------------------------------------------------------------*/ + +void set_zero_l( + float *vec, /* i/o: input/output vector */ + const uint32_t lvec /* i : length of the vector */ +) +{ + uint32_t i; + + for ( i = 0; i < lvec; i++ ) + { + *vec++ = 0.0f; + } + + return; +} +#endif /****************************************************************************/ /* matrix functions */ diff --git a/lib_com/options.h b/lib_com/options.h index 3fe9b252dbcf56dfa605cac55ba1f0aa891187f5..f2bd4eddb9b73aa4ce03db397dde21b244c03f34 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -151,6 +151,7 @@ /*#define FIX_I4_OL_PITCH*/ /* fix open-loop pitch used for EVS core switching */ /*#define SPLIT_REND_WITH_HEAD_ROT */ /* Dlb,FhG: Split Rendering contributions 21 and 35 */ +#define FIX_CRASH_LONG_BRIR /* Orange : Fix crash when long BRIR is set */ #define FIX_SPLITREND_WARNINGS /* FhG: fix warnings related to split rendering observed in build jobs */ #define FIX_923_EXTERNAL_REND_COMMAND_LINE /* VA: issue 923: enable external renderer command-line options in UPPER case letters */ #define FIX_921_OMASA_DELAY_PRINTOUT /* VA: issue 921: correct OMASA decoder delay printout */ diff --git a/lib_rend/ivas_crend.c b/lib_rend/ivas_crend.c index eb6fe495e0560429187a175a7e480b866e00d2c5..89a6b80a10fa4797e7749a560e97b6184c59b21a 100644 --- a/lib_rend/ivas_crend.c +++ b/lib_rend/ivas_crend.c @@ -1248,7 +1248,11 @@ ivas_error ivas_rend_openCrend( ) { int16_t i, subframe_length; +#ifdef FIX_CRASH_LONG_BRIR + int32_t max_total_ir_len; +#else int16_t max_total_ir_len; +#endif HRTFS_HANDLE hHrtf; CREND_HANDLE hCrend; ivas_error error; @@ -1298,13 +1302,21 @@ ivas_error ivas_rend_openCrend( { return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Crend" ); } +#ifdef FIX_CRASH_LONG_BRIR + set_zero_l( hCrend->freq_buffer_re[i], max_total_ir_len ); +#else set_zero( hCrend->freq_buffer_re[i], max_total_ir_len ); +#endif if ( ( hCrend->freq_buffer_im[i] = (float *) malloc( sizeof( float ) * max_total_ir_len ) ) == NULL ) { return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Crend" ); } +#ifdef FIX_CRASH_LONG_BRIR + set_zero_l( hCrend->freq_buffer_im[i], max_total_ir_len ); +#else set_zero( hCrend->freq_buffer_im[i], max_total_ir_len ); +#endif } for ( i = 0; i < BINAURAL_CHANNELS; i++ ) @@ -1313,7 +1325,11 @@ ivas_error ivas_rend_openCrend( { return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Crend" ); } +#ifdef FIX_CRASH_LONG_BRIR + set_zero_l( hCrend->prev_out_buffer[i], subframe_length ); +#else set_zero( hCrend->prev_out_buffer[i], subframe_length ); +#endif } max_total_ir_len = hHrtf->num_iterations_diffuse[0] * subframe_length; @@ -1324,13 +1340,21 @@ ivas_error ivas_rend_openCrend( { return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Crend" ); } +#ifdef FIX_CRASH_LONG_BRIR + set_zero_l( hCrend->freq_buffer_re_diffuse, max_total_ir_len ); +#else set_zero( hCrend->freq_buffer_re_diffuse, max_total_ir_len ); +#endif if ( ( hCrend->freq_buffer_im_diffuse = (float *) malloc( sizeof( float ) * max_total_ir_len ) ) == NULL ) { return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Crend" ); } +#ifdef FIX_CRASH_LONG_BRIR + set_zero_l( hCrend->freq_buffer_im_diffuse, max_total_ir_len ); +#else set_zero( hCrend->freq_buffer_im_diffuse, max_total_ir_len ); +#endif } else { @@ -1345,7 +1369,11 @@ ivas_error ivas_rend_openCrend( { return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Crend" ); } +#ifdef FIX_CRASH_LONG_BRIR + set_zero_l( hCrend->lfe_delay_line, max_total_ir_len ); +#else set_zero( hCrend->lfe_delay_line, max_total_ir_len ); +#endif } else { @@ -1541,7 +1569,7 @@ void ivas_rend_closeCrend( #ifdef SPLIT_REND_WITH_HEAD_ROT /*------------------------------------------------------------------------- - * ivas_rend_openCldfbRend() + * ivas_rend_closeCldfbRend() * * Close CLDFB based fastconv binaural renderer memories *------------------------------------------------------------------------*/ @@ -1588,7 +1616,11 @@ static ivas_error ivas_rend_crendConvolver( int16_t i, j, k, m; int16_t subframe_length, idx_in; int16_t lfe_idx_in; +#ifdef FIX_CRASH_LONG_BRIR + int32_t offset, offset_in, offset_diffuse; +#else int16_t offset, offset_in, offset_diffuse; +#endif int16_t nchan_in, nchan_out; const float *pIn; float *pFreq_buf_re, *pFreq_buf_im; diff --git a/lib_rend/lib_rend.c b/lib_rend/lib_rend.c index 1d9fb1c32dad9967dab6167729eb9d5859d2be7f..236d7115689e487618ffbd68cf3991be2b91160a 100644 --- a/lib_rend/lib_rend.c +++ b/lib_rend/lib_rend.c @@ -4747,7 +4747,6 @@ ivas_error IVAS_REND_DisableHeadRotation( { if ( ( error = initMcBinauralRendering( &hIvasRend->inputsMc[i], hIvasRend->inputsMc[i].base.inConfig, hIvasRend->outputConfig, hIvasRend->hRendererConfig, TRUE ) ) != IVAS_ERR_OK ) { - return error; } } diff --git a/lib_util/hrtf_file_reader.c b/lib_util/hrtf_file_reader.c index 650768457954cce72d36277ef0e4f1e228d9e47b..1cc05dea41653c39408cdee686c6557a6696f256 100644 --- a/lib_util/hrtf_file_reader.c +++ b/lib_util/hrtf_file_reader.c @@ -34,7 +34,6 @@ #include #include "prot.h" #include "ivas_prot_rend.h" - #include "ivas_prot.h" /*---------------------------------------------------------------------* @@ -467,7 +466,6 @@ static ivas_error TDREND_MIX_LoadHRTF( error = IVAS_ERR_OK; - if ( ( header_check_result = read_and_check_hrtf_binary_file_header( &hrtfs_file_header, f_hrtf ) ) != IVAS_ERR_OK ) { return header_check_result; diff --git a/scripts/binauralRenderer_interface/.gitignore b/scripts/binauralRenderer_interface/.gitignore index 040f10e0c87a62f49ab42c11009f17c972d87a85..fb1ef93000e947b87f1bdf68e6d1c1f713cdf716 100644 --- a/scripts/binauralRenderer_interface/.gitignore +++ b/scripts/binauralRenderer_interface/.gitignore @@ -1,5 +1,5 @@ +build* *.cmake -CMake* Externals/ Table_Format_Converter/CMake* Table_Format_Converter/build* diff --git a/scripts/binauralRenderer_interface/BRIRs_sofa/IIS_BRIR_officialMPEG_Combined.sofa b/scripts/binauralRenderer_interface/BRIRs_sofa/IIS_BRIR_officialMPEG_Combined.sofa index 2e4d6756abd7e7be45dc82e38379c509d8cf24af..be6f183b556cbb68afccc23d4a92e9975b336c63 100644 --- a/scripts/binauralRenderer_interface/BRIRs_sofa/IIS_BRIR_officialMPEG_Combined.sofa +++ b/scripts/binauralRenderer_interface/BRIRs_sofa/IIS_BRIR_officialMPEG_Combined.sofa @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:75a4238998f5d2ab11bbad7e34aaebbd41d16b44c1f648a227c9741c06b1d4ae -size 5014808 +oid sha256:7ea6c5e502254085694938a15d440f1c776af179a5aa031e4bc49ded51775649 +size 5019132 diff --git a/scripts/binauralRenderer_interface/CMakeLists.txt b/scripts/binauralRenderer_interface/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..e51ab3b2145184c81f21c16f5db546fde6d19975 --- /dev/null +++ b/scripts/binauralRenderer_interface/CMakeLists.txt @@ -0,0 +1,85 @@ +cmake_minimum_required(VERSION 3.5) + +project(generate_crend_ivas_tables) + +set(IVAS_TRUNK_PATH "${PROJECT_SOURCE_DIR}/../..") +set(IVAS_TRUNK_UTIL_PATH ${IVAS_TRUNK_PATH}/lib_util) +string(REPLACE "/binauralRenderer_interface" "" IVAS_TRUNK_SCRIPTS_PATH ${PROJECT_SOURCE_DIR}) +set(IVAS_TRUNK_DEC_PATH ${IVAS_TRUNK_PATH}/lib_dec) +set(IVAS_TRUNK_REND_PATH ${IVAS_TRUNK_PATH}/lib_rend) +set(IVAS_TRUNK_ENC_PATH ${IVAS_TRUNK_PATH}/lib_enc) +set(IVAS_TRUNK_COM_PATH ${IVAS_TRUNK_PATH}/lib_com) +set(IVAS_TRUNK_DEBUG_PATH ${IVAS_TRUNK_PATH}/lib_debug) + +option(USE_MATLAB_ENG "Use matlab engine" OFF) # allows to use sofa file as input to the exe, but on windows requires to register matlab as a com server type in matlab "comserver('register')"" +find_package(Matlab REQUIRED) +message("Matlab_VERSION = ${Matlab_VERSION}") +message("Matlab_ROOT_DIR = ${Matlab_ROOT_DIR}") +message("Matlab_INCLUDE_DIRS = ${Matlab_INCLUDE_DIRS}") + +if(NOT Matlab_MAT_LIBRARY) + string(REPLACE "mex" "mat" Matlab_MAT_LIBRARY ${Matlab_MEX_LIBRARY}) +endif() + +message("Matlab_MAT_LIBRARY = ${Matlab_MAT_LIBRARY}") +message("Matlab_LIBRARIES = ${Matlab_LIBRARIES}") +message("Matlab_MX_LIBRARY = ${Matlab_MX_LIBRARY}") +message("Matlab_MEX_LIBRARY = ${Matlab_MEX_LIBRARY}") +message("Matlab_ENGINE_LIBRARY = ${Matlab_ENGINE_LIBRARY}") +message("Matlab_DATAARRAY_LIBRARY = ${Matlab_DATAARRAY_LIBRARY}") +include_directories(${Matlab_INCLUDE_DIRS} ${IVAS_TRUNK_UTIL_PATH} ${IVAS_TRUNK_ENC_PATH} ${IVAS_TRUNK_DEC_PATH} ${IVAS_TRUNK_REND_PATH} ${IVAS_TRUNK_COM_PATH} ${IVAS_TRUNK_DEBUG_PATH}) +if(USE_MATLAB_ENG) + string(REPLACE "mex" "eng" Matlab_ENG_LIBRARY ${Matlab_MEX_LIBRARY}) + add_definitions(-DUSE_MATLAB_ENG) +endif() + +set(SOURCE_FILES_C + ${PROJECT_SOURCE_DIR}/ivas_crend_binaural_filter_design.c + ${PROJECT_SOURCE_DIR}/config_reader.c + ${IVAS_TRUNK_COM_PATH}/basop32.c + ${IVAS_TRUNK_COM_PATH}/basop_mpy.c + ${IVAS_TRUNK_COM_PATH}/enh40.c + ${IVAS_TRUNK_COM_PATH}/fft.c + ${IVAS_TRUNK_COM_PATH}/fft_rel.c + ${IVAS_TRUNK_COM_PATH}/ifft_rel.c + ${IVAS_TRUNK_COM_PATH}/ivas_mdft_imdft.c + ${IVAS_TRUNK_COM_PATH}/rom_com.c + ${IVAS_TRUNK_COM_PATH}/ivas_rom_com.c + ${IVAS_TRUNK_COM_PATH}/tools.c + ${IVAS_TRUNK_COM_PATH}/tns_base.c + ${IVAS_TRUNK_UTIL_PATH}/cmdl_tools.c + ${IVAS_TRUNK_REND_PATH}/ivas_rom_rend.c +) + +set(SOURCE_FILES_H + ${PROJECT_SOURCE_DIR}/ivas_crend_binaural_filter_design.h + ${PROJECT_SOURCE_DIR}/config_reader.h + ${IVAS_TRUNK_REND_PATH}/ivas_stat_rend.h + ${IVAS_TRUNK_DEC_PATH}/ivas_stat_dec.h + ${IVAS_TRUNK_DEC_PATH}/stat_dec.h + ${IVAS_TRUNK_COM_PATH}/options.h + ${IVAS_TRUNK_COM_PATH}/ivas_cnst.h + ${IVAS_TRUNK_COM_PATH}/cnst.h + ${IVAS_TRUNK_COM_PATH}/prot.h + ${IVAS_TRUNK_COM_PATH}/ivas_prot.h + ${IVAS_TRUNK_COM_PATH}/common_api_types.h + ${IVAS_TRUNK_REND_PATH}/ivas_rom_rend.h +) + +add_library(${PROJECT_NAME}_lib STATIC ${SOURCE_FILES_C} ${SOURCE_FILES_H}) + +add_executable(${PROJECT_NAME} generate_crend_ivas_tables_from_sofa.c) + +target_link_libraries(${PROJECT_NAME} ${PROJECT_NAME}_lib ${Matlab_MAT_LIBRARY} ${Matlab_MX_LIBRARY}) +if(UNIX AND NOT APPLE) + target_link_libraries(${PROJECT_NAME} libstdc++.so.6 -lm -ldl) +endif() +if(USE_MATLAB_ENG) + target_link_libraries(${PROJECT_NAME} ${Matlab_ENG_LIBRARY}) +endif() + +if(WIN32) + add_compile_definitions(_CRT_SECURE_NO_WARNINGS) +endif() + +add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD VERBATIM COMMAND "${CMAKE_COMMAND}" -E copy "$" "${CMAKE_CURRENT_SOURCE_DIR}/") diff --git a/scripts/binauralRenderer_interface/HRIRs_sofa/HRIR_128_48000_dolby_SBA1.sofa b/scripts/binauralRenderer_interface/HRIRs_sofa/HRIR_128_48000_dolby_SBA1.sofa deleted file mode 100644 index 7c30b0de53d5f79843a060a72cb6254b313d1d44..0000000000000000000000000000000000000000 --- a/scripts/binauralRenderer_interface/HRIRs_sofa/HRIR_128_48000_dolby_SBA1.sofa +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:be90326a0196b802502d2d93dcaacc2bcec15f6d79f1b8d4c7e69564f32e1132 -size 46952 diff --git a/scripts/binauralRenderer_interface/HRIRs_sofa/HRIR_128_48000_dolby_SBA2.sofa b/scripts/binauralRenderer_interface/HRIRs_sofa/HRIR_128_48000_dolby_SBA2.sofa deleted file mode 100644 index 9d91f9a04dcb0004dfb1b8bb407d8281a09c48ad..0000000000000000000000000000000000000000 --- a/scripts/binauralRenderer_interface/HRIRs_sofa/HRIR_128_48000_dolby_SBA2.sofa +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6acd3ec4d8e0d586dac663b53124a90be699244fa21107d553fca00af00fa373 -size 51905 diff --git a/scripts/binauralRenderer_interface/HRIRs_sofa/HRIR_128_48000_dolby_SBA3.sofa b/scripts/binauralRenderer_interface/HRIRs_sofa/HRIR_128_48000_dolby_SBA3.sofa deleted file mode 100644 index 74e60618a02e695974dfdd09f1b85ab5dc1f18db..0000000000000000000000000000000000000000 --- a/scripts/binauralRenderer_interface/HRIRs_sofa/HRIR_128_48000_dolby_SBA3.sofa +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:872b1d794d77f1987a38f20cc3cb5627aee67bfd01ed7a50ab3514e0accedea5 -size 58924 diff --git a/scripts/binauralRenderer_interface/HRIRs_sofa/HRIR_128_Meth5_IRC_51_Q10_symL_Itrp1_48000.sofa b/scripts/binauralRenderer_interface/HRIRs_sofa/HRIR_128_Meth5_IRC_51_Q10_symL_Itrp1_48000.sofa index 42c083d6f34cd3b8348af7bddc5838398dcdd09b..e818470a52a9f3a70e7371675c15a9b9a180a8f3 100644 --- a/scripts/binauralRenderer_interface/HRIRs_sofa/HRIR_128_Meth5_IRC_51_Q10_symL_Itrp1_48000.sofa +++ b/scripts/binauralRenderer_interface/HRIRs_sofa/HRIR_128_Meth5_IRC_51_Q10_symL_Itrp1_48000.sofa @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2c368121ebd83ed0712cd1963ab44f130d1e02a14f5191bf2d403f71b7eadc0f -size 15911554 +oid sha256:e6ecaaa25464342567a19dc04a563127d89055e49c2bd177a22c9e19397a2bba +size 15915864 diff --git a/scripts/binauralRenderer_interface/HRIRs_sofa/HRIR_128_Meth5_IRC_52_Q10_symL_Itrp1_48000.sofa b/scripts/binauralRenderer_interface/HRIRs_sofa/HRIR_128_Meth5_IRC_52_Q10_symL_Itrp1_48000.sofa index 1201506e575a989c249461f74b3440b3ed18ca51..85396c986633d4b2b3577640e56166967689e04e 100644 --- a/scripts/binauralRenderer_interface/HRIRs_sofa/HRIR_128_Meth5_IRC_52_Q10_symL_Itrp1_48000.sofa +++ b/scripts/binauralRenderer_interface/HRIRs_sofa/HRIR_128_Meth5_IRC_52_Q10_symL_Itrp1_48000.sofa @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9f723f789effdcdd45dbc7165111c34d3307adbf6a40d5c7446d371454e4f8ed -size 15911554 +oid sha256:69fd24d91058cf52c1f1558c0cf077a829c904dd54f7667e6114e1274137c622 +size 15915864 diff --git a/scripts/binauralRenderer_interface/HRIRs_sofa/HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000.sofa b/scripts/binauralRenderer_interface/HRIRs_sofa/HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000.sofa index 10409fc882c1b4f20e599a6bd296834f10802bc8..d2c4cd06e2c76b1ab5631668a3801b8f52f79b6b 100644 --- a/scripts/binauralRenderer_interface/HRIRs_sofa/HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000.sofa +++ b/scripts/binauralRenderer_interface/HRIRs_sofa/HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000.sofa @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ec16781eef46a4de0067442b2f6d00740c0da1a16a3213d6af152f940692c13c -size 15911554 +oid sha256:9ce41e552139ad9e22b0a736f42e260c25fab2bd0d6db64f7d61cce731dc6d0b +size 15915864 diff --git a/scripts/binauralRenderer_interface/HRIRs_sofa/HRIR_128_Meth5_IRC_54_Q10_symL_Itrp1_48000.sofa b/scripts/binauralRenderer_interface/HRIRs_sofa/HRIR_128_Meth5_IRC_54_Q10_symL_Itrp1_48000.sofa index 8821286f1da450d9e39797ff3d6455da32dd8e8b..c163a9099284e940baaaaf1d7ea1b9a286fefa2b 100644 --- a/scripts/binauralRenderer_interface/HRIRs_sofa/HRIR_128_Meth5_IRC_54_Q10_symL_Itrp1_48000.sofa +++ b/scripts/binauralRenderer_interface/HRIRs_sofa/HRIR_128_Meth5_IRC_54_Q10_symL_Itrp1_48000.sofa @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9a48810c9a76417fdee3fa24dba5eb3859391776bcb1b99e8ab7ed26cc8ac3d9 -size 15911554 +oid sha256:22ce0956a10c86149d7a6906678bef44f318c37e32085a5845fb02c486f6e249 +size 15915864 diff --git a/scripts/binauralRenderer_interface/HRIRs_sofa/ORANGE_HRIR_53_HOA3S_48000.sofa b/scripts/binauralRenderer_interface/HRIRs_sofa/ORANGE_HRIR_53_HOA3S_48000.sofa deleted file mode 100644 index e9ecafab186bc0591044350a9e5491c2e4b63f2c..0000000000000000000000000000000000000000 --- a/scripts/binauralRenderer_interface/HRIRs_sofa/ORANGE_HRIR_53_HOA3S_48000.sofa +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f68e4cc3100f8ffced2f317c905ae501a84575b1d9c817486c9280d1c7e3c8d1 -size 110798 diff --git a/scripts/binauralRenderer_interface/README.md b/scripts/binauralRenderer_interface/README.md new file mode 100644 index 0000000000000000000000000000000000000000..ee59bbcbafbfac1d9a2c5e7ccf1e20046add3ffe --- /dev/null +++ b/scripts/binauralRenderer_interface/README.md @@ -0,0 +1,129 @@ + +# Modeling tool for all IVAS binaural renderer +# Allows to convert SOFA file(s) to rom tables files (*.c|h) or binaural binary file(s) + +## Requirements +- MATLAB >= R2020b +- Signal Processing Toolbox +- C/C++ compiler + - Linux (Ubuntu) : + ```shell + sudo apt-get update + sudo apt-get install build-essential + ``` + - Windows + - Install Visual Studio Community Edition or other: https://visualstudio.microsoft.com/fr/vs/community/ +- CMake version > 3.5 + +### Build `generate_crend_ivas_tables` + - Open a command line terminal + - Execute + ```shell + mkdir build + cd build + cmake .. + cmake --build . + cd .. + ``` + - `generate_crend_ivas_tables` executable shall be in folder [`../../scripts/binauralRenderer_interface`](../../scripts/binauralRenderer_interface) + - On Windows this executable requires DLL from MATLAB, you need to add to your path `*/matlab/version/bin/win64` + - For more details on `generate_crend_ivas_tables` see [`mixer_conv_sofa_to_rom_table_converter_readme.txt`](mixer_conv_sofa_to_rom_table_converter_readme.txt). + - On Apple Silicon Mac with Intel MATLAB, it is necessary to add `SET(CMAKE_OSX_ARCHITECTURES "x86_64")` in the `CMakeLists.txt` near the top of the file. This forces the compilation to use Intel architecture instead ofo the native one. + - if find_package do not find matlab, at the beginning of the cmakelists.txt file you can set the search path with the folowing line set(Matlab_ROOT_DIR matlab_path), for example on linux set(Matlab_ROOT_DIR ~/MATLAB/R2023b) on mac set(Matlab_ROOT_DIR /Applications/MATLAB_R2023b.app) + +### Build `tables_format_converter` + - Open a command line terminal + - Goto folder + - Execute + ```shell + cd ../../scripts/binauralRenderer_interface/Table_Format_Converter + mkdir build + cd build + cmake .. + cmake --build . --config Release + cd .. + ``` + - `tables_format_converter` executable shall be in the folder [`../../scripts/binauralRenderer_interface/Table_Format_Converter/`](../../scripts/binauralRenderer_interface/Table_Format_Converter) + +### MATLAB scripts from + - [`binauralRenderer_interface/matlab_hrir_generation_scripts`](../../scripts/binauralRenderer_interface/matlab_hrir_generation_scripts) + - See [`README.md`](../../scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/README.md) in the folder. + - Convert dense set of HRIRs into HOA to binaural filters in time domain or in CLDFB domain. + - Required by `generate_crend_ivas_tables`, ParamBin, and FastConv. + - [`binauralRenderer_interface/param_bin`](../../scripts/binauralRenderer_interface/param_bin) + - Generate part of ROM file [`ivas_rom_binauralRenderer.c`](../../lib_rend/ivas_rom_binauralRenderer.c) and/or parametric renderer binary file. + - To generate complete [`ivas_rom_binauralRenderer.c`](../../lib_rend/ivas_rom_binauralRenderer.c) ROM file see example in [`generate_ivas_binauralizer_tables_from_sofa.m`](generate_ivas_binauralizer_tables_from_sofa.m) + - [`binauralRenderer_interface/fastconv`](../../scripts/binauralRenderer_interface/fastconv) + - See [`README.txt`](../../scripts/binauralRenderer_interface/fastconv/README.txt) in the folder. + - Generate part of ROM file [`ivas_rom_binauralRenderer.c`](../../lib_rend/ivas_rom_binauralRenderer.c) and/or FastConv renderer binary file. + - To generate complete [`ivas_rom_binauralRenderer.c`](../../lib_rend/ivas_rom_binauralRenderer.c) file see example in [`generate_ivas_binauralizer_tables_from_sofa.m`](generate_ivas_binauralizer_tables_from_sofa.m). + - **Warning**: The computed values for late reverberation depend on MATLAB and OS versions used. IVAS tests are still BE. + - [`td_object_renderer`](../../scripts/td_object_renderer) + - See [`README.md`](../../scripts/td_object_renderer/modeling_tool/README.md) in the folder. + - Generate part of the ROM files [`ivas_rom_TdBinauralRenderer.h`](../../lib_rend/ivas_rom_TdBinauralRenderer.h), [`ivas_rom_TdBinauralRenderer.c`](../../lib_rend/ivas_rom_TdBinauralRenderer.c), and TD renderer binary file. + - **Warning**: The computed values depend on MATLAB and OS versions used. IVAS tests are still BE. + +### SOFA files: + - HRIRs sofa files for testing are stored in [`HRIRs_sofa`](HRIRs_sofa) folder + - BRIRs sofa files for testing are stored in [`BRIRs_sofa`](BRIRs_sofa) folder + - The current scripts have not been tested with other SOFA files. For other SOFA files some adaptations of the scripts may be required. Current scripts are provided as an example. + +See [`scripts/ThirdPartyLegalNotices`](../../scripts/ThirdPartyLegalNotices) for related information. + +## Usage +- Run the following MATLAB script: [`generate_ivas_binauralizer_tables_from_sofa.m`](generate_ivas_binauralizer_tables_from_sofa.m) + - It will generate ROM files that can be used to compile IVAS decoder or renderer. By default, the result is BE. + - It will also generate binary files that can be used with `-hrtf` flag in IVAS decoder or renderer command line. + - Using IVAS decoder or renderer with default binary files will generate BE output compare to the same command line without `-hrtf` flag. + - To test different SOFA files input you need to modify the script in the section `%% Set input files`. Other SOFA files are available in [`HRIRs_sofa`](HRIRs_sofa) folder. + - **Warning**: The script will overwrite the tables in [`lib_rend`](../../lib_rend/) + +→ Generated files are in folder [`binaural_renderers_hrtf_data`](binaural_renderers_hrtf_data) +- Generated files : + - `ivas_binaural_*kHz.bin`: file containing all tables values for all IVAS binaural renderers for one sample rate. + - `ivas_binaural_td_*kHz.bin`: file containing tables values for IVAS td binaural renderer for one sample rate. + - `ivas_binaural_reverb_*kHz.bin`: file containing tables values for IVAS td reverberation process for one sample rate. + - `ivas_binaural_fastconv_*kHz.bin`: file containing tables values for IVAS fastconv binaural renderers. Files for all sampling rate files are the same. + - `ivas_binaural_parambin_*kHz.bin`: file containing tables values for IVAS prametric binaural renderers. Files for all sampling rate files are the same. + - `ivas_binaural_td_*kHz.bin`: file containing tables values for IVAS td binaural renderers for one sample rate. + - `ivas_binaural_mixconv_hrir_*kHz.bin`: file containing tables values for IVAS mixer conv binaural renderer for HRIR for one sample rate. + - `ivas_binaural_mixconv_brir_*kHz.bin`: file containing tables values for IVAS mixer conv binaural renderer for BRIR for one sample rate. + +- Without MATLAB only binary files for mixer conv renderer BRIR can be generated. + - Run, for example, to use IVAS renderer as a BRIR convolver run successively: + ```shell + ./generate_crend_ivas_tables -lib_rend_path ./ -brir_optim_config_path ./brir_no_optim.cfg -binary_files_path ./binaural_renderers_hrtf_data -binary_common_file_name IIS_BRIR_officialMPEG_Combined_no_optim 5 ./BRIRs_sofa/IIS_BRIR_officialMPEG_Combined.sofa + ./tables_format_converter -output_file_path ../binaural_renderers_hrtf_data -output_file_name brir_no_optim -input_mixerconv_brir_file_path ../binaural_renderers_hrtf_data -input_mixerconv_brir_file_name IIS_BRIR_officialMPEG_Combined_no_optim + ``` + and then to complete, the `IVAS_rend` command line + ```shell + IVAS_rend -hrtf ./scripts/binaurelRenderer_interface/binaural_renderers_hrtf_data/brir_no_optim_48kHz.bin ... + ``` diff --git a/scripts/binauralRenderer_interface/Table_Format_Converter/CMakeLists.txt b/scripts/binauralRenderer_interface/Table_Format_Converter/CMakeLists.txt index bbd6d81b66c49d6a8f4c75676e91a9e9fba58c39..fffbd87b0a3c9387c02f741aa4991061b1d15636 100644 --- a/scripts/binauralRenderer_interface/Table_Format_Converter/CMakeLists.txt +++ b/scripts/binauralRenderer_interface/Table_Format_Converter/CMakeLists.txt @@ -26,7 +26,9 @@ include_directories(${IVAS_UTIL_PATH} ${IVAS_ENC_PATH} ${IVAS_DEC_PATH} ${IVAS_C set(SOURCE_FILES_C ${IVAS_REND_PATH}/ivas_rom_binauralRenderer.c ${IVAS_REND_PATH}/ivas_rom_binaural_crend_head.c - ${IVAS_REND_PATH}/ivas_rom_rend.c) + ${IVAS_REND_PATH}/ivas_rom_rend.c + ${IVAS_UTIL_PATH}/cmdl_tools.c + ) set(SOURCE_FILES_H ${IVAS_REND_PATH}/ivas_rom_binauralRenderer.h @@ -37,3 +39,6 @@ add_library(${PROJECT_NAME}_lib STATIC ${SOURCE_FILES_C} ${SOURCE_FILES_H}) add_executable(${PROJECT_NAME} generate_tables_from_rom_to_bin.c) target_link_libraries(${PROJECT_NAME} ${PROJECT_NAME}_lib) + +add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD VERBATIM COMMAND "${CMAKE_COMMAND}" -E copy "$" "${CMAKE_CURRENT_SOURCE_DIR}/") + diff --git a/scripts/binauralRenderer_interface/Table_Format_Converter/generate_tables_from_rom_to_bin.c b/scripts/binauralRenderer_interface/Table_Format_Converter/generate_tables_from_rom_to_bin.c index fe9c9118a77c0effa26f426c885ba19b5b0f781c..50a9cea179d041ecf9591fe5eadd7126abfca3d3 100644 --- a/scripts/binauralRenderer_interface/Table_Format_Converter/generate_tables_from_rom_to_bin.c +++ b/scripts/binauralRenderer_interface/Table_Format_Converter/generate_tables_from_rom_to_bin.c @@ -49,28 +49,28 @@ *------------------------------------------------------------------------------------------*/ #ifdef WIN32 -#define DEFAULT_PATH ".\\" +#define DEFAULT_PATH ".\\binaural_renderers_hrtf_data" #else -#define DEFAULT_PATH "./" +#define DEFAULT_PATH "./binaural_renderers_hrtf_data" #endif +#define DEFAULT_INPUT_ROM_FILE "ivas_binaural" -#define DEFAULT_INPUT_ROM_FILE "ivas_binaural" -#define DEFAULT_INPUT_TD_BIN_FILE "hrfilter_model" -#define DEFAULT_BIN_FILE_EXT ".bin" +#define DEFAULT_BIN_FILE_EXT ".bin" + +#define IVAS_NB_RENDERER_TYPE 6 +#define IVAS_NB_AUDIO_CONFIG 4 +#define IVAS_NB_SAMPLERATE 3 -#define IVAS_NB_RENDERER_TYPE 7 -#define IVAS_NB_AUDIO_CONFIG 4 -#define IVAS_NB_SAMPLERATE 3 const RENDERER_TYPE rend_types[IVAS_NB_RENDERER_TYPE] = { RENDERER_BINAURAL_FASTCONV, RENDERER_BINAURAL_FASTCONV_ROOM, RENDERER_BINAURAL_PARAMETRIC, - RENDERER_BINAURAL_PARAMETRIC_ROOM, RENDERER_BINAURAL_MIXER_CONV, RENDERER_BINAURAL_MIXER_CONV_ROOM, RENDERER_BINAURAL_OBJECTS_TD }; + const BINAURAL_INPUT_AUDIO_CONFIG input_cfgs[IVAS_NB_AUDIO_CONFIG] = { BINAURAL_INPUT_AUDIO_CONFIG_COMBINED, BINAURAL_INPUT_AUDIO_CONFIG_HOA3, @@ -123,16 +123,15 @@ void usage_tables_format_converter( void ); int rom2bin_init( int argc, char *argv[] ); void rom2bin_terminat( void ); char *to_upper( char *str ); +void convert_backslash( char *str ); char *create_hrtf_crend( RENDERER_TYPE rend_type, BINAURAL_INPUT_AUDIO_CONFIG input_cfg, int32_t frequency, int32_t *hrtf_size /*OUT*/ ); -char *create_hrtf_fastconv( RENDERER_TYPE rend_type, BINAURAL_INPUT_AUDIO_CONFIG input_cfg, int32_t frequency, int32_t *hrtf_size ); +char *create_hrtf_fastconv( RENDERER_TYPE rend_type, BINAURAL_INPUT_AUDIO_CONFIG input_cfg, int32_t *hrtf_size ); char *create_hrtf_parametric( int32_t *hrtf_size ); char *create_hrtf_tdrend( int32_t frequency, int32_t *hrtf_size /*OUT*/ ); - int32_t read_hrtf_size( char *hrtf ); int16_t check_bin_file( FILE *hrtf_bin_file ); int16_t check_hrtf_data( RENDERER_TYPE rend_type, BINAURAL_INPUT_AUDIO_CONFIG input_cfg, int32_t frequency, char *hrtf_data_in, int32_t hrtf_size_in ); - /*---------------------------------------------------------------------*/ int16_t get_crend_hrtf_tables( RENDERER_TYPE rend_type, BINAURAL_INPUT_AUDIO_CONFIG input_cfg, int32_t frequency, crend_hrtf_tables_pointers *hrtf_table_ptrs /*OUT*/, crend_hrtf_tables_dimensions *hrtf_table_dims /*OUT*/ ); @@ -154,14 +153,29 @@ void usage_tables_format_converter( void ) fprintf( stdout, "Options :\n" ); fprintf( stdout, "---------\n" ); - fprintf( stdout, "-output_file_path : Path where output file will be created (with separator, default = './').\n" ); - fprintf( stdout, "-output_file_name : Name of output file (without extension %s, default = '%s').\n", DEFAULT_BIN_FILE_EXT, DEFAULT_INPUT_ROM_FILE ); - fprintf( stdout, //"-8 : Select 8 kHz sampling frequency (no multiple values, all by default).\n" + fprintf( stdout, "-output_file_path : Path where output file will be created (default = ./binaural_renderers_hrtf_data).\n" ); + fprintf( stdout, "-output_file_name : Name of output file without extension or sample rate (default = ivas_binaural).\n" ); + fprintf( stdout, "-16 : Select 16 kHz sampling frequency (no multiple values, all frequencies by default).\n" "-32 : Select 32 kHz sampling frequency (no multiple values, all frequencies by default).\n" "-48 : Select 48 kHz sampling frequency (no multiple values, all frequencies by default).\n" ); - fprintf( stdout, "-input_td_file_path : Path of binary files for time-domain renderer (with separator, used as flag).\n" ); - fprintf( stdout, "-input_td_file_name : Name of input td file (without extension %s, default = '%s').\n", DEFAULT_BIN_FILE_EXT, DEFAULT_INPUT_TD_BIN_FILE ); + fprintf( stdout, "-input_td_file_path : if exist path of binary files for time-domain renderer.\n" ); + fprintf( stdout, "-input_td_file_name : if exist common name of input td file with extension.\n" ); + fprintf( stdout, "-input_fastconv_file_path : if exist path of binary file for fastconv renderer.\n" ); + fprintf( stdout, "-input_fastconv_file_name : if exist name of input fastconv file with extension.\n" ); + fprintf( stdout, "-input_param_file_path : if exist path of binary file for parametric renderer.\n" ); + fprintf( stdout, "-input_param_file_name : if exist name of input param file with extension.\n" ); + fprintf( stdout, "-input_mixerconv_file_hrir_path : if exist path of binary files for mixer_conv hrir renderer.\n" ); + fprintf( stdout, "-input_mixerconv_file_hrir_name : if exist common name of input mixer_conv hrir files.\n" ); + fprintf( stdout, "-input_mixerconv_file_brir_path : if exist path of binary files for mixer_conv brir renderer.\n" ); + fprintf( stdout, "-input_mixerconv_file_brir_name : if exist common name of input mixer_conv brir files.\n" ); + fprintf( stdout, "\n" ); + fprintf( stdout, "For example :\n" +#ifdef _WIN32 + ".\\tables_format_converter.exe -output_file_path ../binaural_renderers_hrtf_data -output_file_name test -input_td_file_path ../binaural_renderers_hrtf_data/IVAS_default -input_td_file_name td_HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000_model_v003 -input_param_file_path ../binaural_renderers_hrtf_data -input_param_file_name parambin_HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000_IIS_BRIR_officialMPEG_Combined.bin\n" ); +#else + "./tables_format_converter -output_file_path ../binaural_renderers_hrtf_data -output_file_name test -input_td_file_path ../binaural_renderers_hrtf_data/IVAS_default -input_td_file_name td_HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000_model_v003 -input_param_file_path ../binaural_renderers_hrtf_data -input_param_file_name parambin_HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000_IIS_BRIR_officialMPEG_Combined.bin\n" ); +#endif fprintf( stdout, "\n" ); } @@ -172,10 +186,20 @@ void usage_tables_format_converter( void ) char *output_path = NULL; char *output_file_name = NULL; char *full_out_path = NULL; +int32_t selected_frequency = 0; + char *input_td_bin_path = NULL; char *input_td_bin_file_name = NULL; -char *full_in_td_path = NULL; + +char *input_param_bin_path = NULL; +char *input_param_bin_file_name = NULL; +char *input_fastconv_bin_path = NULL; +char *input_fastconv_bin_file_name = NULL; +char *input_mixerconv_bin_hrir_path = NULL; +char *input_mixerconv_bin_brir_path = NULL; +char *input_mixerconv_bin_hrir_file_name = NULL; +char *input_mixerconv_bin_brir_file_name = NULL; int16_t nb_freq = IVAS_NB_SAMPLERATE; const int32_t *freq_ptr = sample_rates; @@ -186,7 +210,7 @@ const int32_t *freq_ptr = sample_rates; *------------------------------------------------------------------------------------------*/ int main( int argc, char *argv[] ) { - int i, j, k, l; + int i, j, k, l, startFreq; #ifdef FILE_HEADER char *file_header, *file_header_wptr; @@ -204,100 +228,208 @@ int main( int argc, char *argv[] ) return -1; } - bin_file = fopen( full_out_path, "wb" ); - if ( bin_file == NULL ) + nbHRTFMax = 0; + if ( input_mixerconv_bin_hrir_file_name != NULL ) { - fprintf( stderr, "Creation of binary file failed: %s\n\n", full_out_path ); - rom2bin_terminat(); - return -1; + nbHRTFMax = IVAS_NB_AUDIO_CONFIG * IVAS_NB_SAMPLERATE; // mixerconv HRIR } - - nbHRTFMax = IVAS_NB_RENDERER_TYPE * IVAS_NB_AUDIO_CONFIG * IVAS_NB_SAMPLERATE; - if ( input_td_bin_path != NULL ) + if ( input_mixerconv_bin_brir_file_name != NULL ) + { + nbHRTFMax += IVAS_NB_SAMPLERATE; // mixerconv BRIR + } + if ( input_fastconv_bin_file_name != NULL ) + { + nbHRTFMax += IVAS_NB_AUDIO_CONFIG + 1; // fastconv + } + if ( input_param_bin_file_name != NULL ) + { + nbHRTFMax++; // parametric + } + if ( input_td_bin_file_name != NULL ) { nbHRTFMax += IVAS_NB_SAMPLERATE; } - setOfHRTF = (char **) malloc( nbHRTFMax * sizeof( char * ) ); - memset( setOfHRTF, 0x00, nbHRTFMax * sizeof( char * ) ); - // Create the HRTF - - nbHRTF = 0; - hrtf_size_max = 0; - fileSize = 0; + startFreq = 0; + if ( selected_frequency != 0 ) + { + nb_freq = 1; + for ( i = 0; i < IVAS_NB_SAMPLERATE; i++ ) + { + if ( sample_rates[i] == selected_frequency ) + { + startFreq = i; + break; + } + } + } - for ( i = 0; i < IVAS_NB_RENDERER_TYPE; i++ ) + for ( k = 0; k < nb_freq; k++ ) { - hrtf_size = 0; - switch ( rend_types[i] ) + full_out_path = (char *) malloc( sizeof( char ) * ( strlen( output_path ) + 1 + strlen( output_file_name ) + 6 + strlen( DEFAULT_BIN_FILE_EXT ) + 1 ) ); + if ( full_out_path ) { - case RENDERER_BINAURAL_FASTCONV: - case RENDERER_BINAURAL_FASTCONV_ROOM: - for ( j = 0; j < IVAS_NB_AUDIO_CONFIG; j++ ) - { - /* Only one freq. for fastconv */ - setOfHRTF[nbHRTF] = create_hrtf_fastconv( rend_types[i], input_cfgs[j], freq_ptr[0], &hrtf_size ); - if ( hrtf_size == -1 ) +#ifdef _WIN32 + sprintf( full_out_path, "%s\\%s_%dkHz%s", output_path, output_file_name, freq_ptr[k] / 1000, DEFAULT_BIN_FILE_EXT ); +#else + sprintf( full_out_path, "%s/%s_%dkHz%s", output_path, output_file_name, freq_ptr[k] / 1000, DEFAULT_BIN_FILE_EXT ); +#endif + } + else + { + fprintf( stderr, "Memory issue for full output path!\n\n" ); + rom2bin_terminat(); + return -1; + } + + bin_file = fopen( full_out_path, "wb" ); + if ( bin_file == NULL ) + { + fprintf( stderr, "Creation of binary file failed: %s\n\n", full_out_path ); + rom2bin_terminat(); + return -1; + } + + setOfHRTF = (char **) malloc( nbHRTFMax * sizeof( char * ) ); + memset( setOfHRTF, 0x00, nbHRTFMax * sizeof( char * ) ); + + // Create the HRTF + + nbHRTF = 0; + hrtf_size_max = 0; + fileSize = 0; + + for ( i = 0; i < IVAS_NB_RENDERER_TYPE; i++ ) + { + hrtf_size = 0; + switch ( rend_types[i] ) + { + case RENDERER_BINAURAL_FASTCONV: + if ( ( input_fastconv_bin_path != NULL ) && ( input_fastconv_bin_file_name != NULL ) ) { - fprintf( stderr, "Creation of HRTF (%d, %d, %d) failed!\n\n", rend_types[i], input_cfgs[j], freq_ptr[0] ); - for ( l = 0; l < nbHRTF; l++ ) + for ( j = 0; j < IVAS_NB_AUDIO_CONFIG; j++ ) { - free( setOfHRTF[l] ); + /* Only one freq. for fastconv */ + setOfHRTF[nbHRTF] = create_hrtf_fastconv( rend_types[i], input_cfgs[j], &hrtf_size ); + if ( hrtf_size == -1 ) + { + fprintf( stderr, "Creation of HRTF (%d, %d, %d) failed!\n\n", rend_types[i], input_cfgs[j], freq_ptr[0] ); + for ( l = 0; l < nbHRTF; l++ ) + { + free( setOfHRTF[l] ); + } + free( setOfHRTF ); + rom2bin_terminat(); + return -1; + } + else + { + if ( setOfHRTF[nbHRTF] != NULL ) + { + nbHRTF++; + fileSize += hrtf_size; + if ( hrtf_size_max < hrtf_size ) + hrtf_size_max = hrtf_size; + } + } } - free( setOfHRTF ); - rom2bin_terminat(); - return -1; } - else + break; + case RENDERER_BINAURAL_FASTCONV_ROOM: + if ( ( input_fastconv_bin_path != NULL ) && ( input_fastconv_bin_file_name != NULL ) ) { - if ( setOfHRTF[nbHRTF] != NULL ) + /* Only one freq. for fastconv */ + setOfHRTF[nbHRTF] = create_hrtf_fastconv( rend_types[i], BINAURAL_INPUT_AUDIO_CONFIG_COMBINED, &hrtf_size ); + if ( hrtf_size == -1 ) + { + fprintf( stderr, "Creation of HRTF (%d, %d, %d) failed!\n\n", rend_types[i], BINAURAL_INPUT_AUDIO_CONFIG_COMBINED, freq_ptr[0] ); + for ( l = 0; l < nbHRTF; l++ ) + { + free( setOfHRTF[l] ); + } + free( setOfHRTF ); + rom2bin_terminat(); + return -1; + } + else { - nbHRTF++; - fileSize += hrtf_size; - if ( hrtf_size_max < hrtf_size ) - hrtf_size_max = hrtf_size; + if ( setOfHRTF[nbHRTF] != NULL ) + { + nbHRTF++; + fileSize += hrtf_size; + if ( hrtf_size_max < hrtf_size ) + hrtf_size_max = hrtf_size; + } } } - } - break; - case RENDERER_BINAURAL_PARAMETRIC: - /* Not handled separately. RENDERER_BINAURAL_PARAMETRIC_ROOM will contain the data. */ - break; - case RENDERER_BINAURAL_PARAMETRIC_ROOM: - /* Parametric will always have just one set regardless of input and frequency. */ - setOfHRTF[nbHRTF] = create_hrtf_parametric( &hrtf_size ); - if ( hrtf_size == -1 ) - { - fprintf( stderr, "Creation of HRTF for parametric renderer (%d) failed!\n\n", rend_types[i] ); - for ( l = 0; l < nbHRTF; l++ ) + break; + case RENDERER_BINAURAL_PARAMETRIC: + /* Parametric will always have just one set regardless of input and frequency. */ + if ( ( input_param_bin_path != NULL ) && ( input_param_bin_file_name != NULL ) ) { - free( setOfHRTF[l] ); + setOfHRTF[nbHRTF] = create_hrtf_parametric( &hrtf_size ); + if ( hrtf_size == -1 ) + { + fprintf( stderr, "Creation of HRTF for parametric renderer (%d) failed!\n\n", rend_types[i] ); + for ( l = 0; l < nbHRTF; l++ ) + { + free( setOfHRTF[l] ); + } + free( setOfHRTF ); + rom2bin_terminat(); + return -1; + } + else + { + if ( setOfHRTF[nbHRTF] != NULL ) + { + nbHRTF++; + fileSize += hrtf_size; + if ( hrtf_size_max < hrtf_size ) + hrtf_size_max = hrtf_size; + } + } } - free( setOfHRTF ); - rom2bin_terminat(); - return -1; - } - else - { - if ( setOfHRTF[nbHRTF] != NULL ) + break; + case RENDERER_BINAURAL_MIXER_CONV: + if ( ( input_mixerconv_bin_hrir_path != NULL ) && ( input_mixerconv_bin_hrir_file_name != NULL ) ) { - nbHRTF++; - fileSize += hrtf_size; - if ( hrtf_size_max < hrtf_size ) - hrtf_size_max = hrtf_size; + int start_nbHRTF = nbHRTF; + for ( j = 0; j < IVAS_NB_AUDIO_CONFIG; j++ ) + { + setOfHRTF[nbHRTF] = create_hrtf_crend( rend_types[i], input_cfgs[j], freq_ptr[k], &hrtf_size ); + if ( hrtf_size > 0 ) + { + if ( setOfHRTF[nbHRTF] != NULL ) + { + nbHRTF++; + fileSize += hrtf_size; + if ( hrtf_size_max < hrtf_size ) + hrtf_size_max = hrtf_size; + } + } + } + if ( start_nbHRTF == nbHRTF ) + { + fprintf( stderr, "Creation of HRTF (%d, %d, %d) failed!\n\n", rend_types[i], input_cfgs[j], freq_ptr[k] ); + for ( l = 0; l < nbHRTF; l++ ) + { + free( setOfHRTF[l] ); + } + free( setOfHRTF ); + rom2bin_terminat(); + return -1; + } } - } - break; - case RENDERER_BINAURAL_MIXER_CONV: - case RENDERER_BINAURAL_MIXER_CONV_ROOM: - for ( j = 0; j < IVAS_NB_AUDIO_CONFIG; j++ ) - { - for ( k = 0; k < nb_freq; k++ ) + break; + case RENDERER_BINAURAL_MIXER_CONV_ROOM: + if ( ( input_mixerconv_bin_brir_path != NULL ) && ( input_mixerconv_bin_brir_file_name != NULL ) ) { - setOfHRTF[nbHRTF] = create_hrtf_crend( rend_types[i], input_cfgs[j], freq_ptr[k], &hrtf_size ); + setOfHRTF[nbHRTF] = create_hrtf_crend( rend_types[i], BINAURAL_INPUT_AUDIO_CONFIG_COMBINED, freq_ptr[k], &hrtf_size ); + if ( hrtf_size == -1 ) { - fprintf( stderr, "Creation of HRTF (%d, %d, %d) failed!\n\n", rend_types[i], input_cfgs[j], freq_ptr[k] ); + fprintf( stderr, "Creation of HRTF (%d, %d, %d) failed!\n\n", rend_types[i], BINAURAL_INPUT_AUDIO_CONFIG_COMBINED, freq_ptr[k] ); for ( l = 0; l < nbHRTF; l++ ) { free( setOfHRTF[l] ); @@ -317,12 +449,9 @@ int main( int argc, char *argv[] ) } } } - } - break; - case RENDERER_BINAURAL_OBJECTS_TD: - if ( full_in_td_path != NULL ) - { - for ( k = 0; k < nb_freq; k++ ) + break; + case RENDERER_BINAURAL_OBJECTS_TD: + if ( ( input_td_bin_path != NULL ) && ( input_td_bin_file_name != NULL ) ) { setOfHRTF[nbHRTF] = create_hrtf_tdrend( freq_ptr[k], &hrtf_size ); if ( hrtf_size == -1 ) @@ -347,92 +476,92 @@ int main( int argc, char *argv[] ) } } } - } - break; - default: - break; + break; + default: + break; + } } - } #ifdef FILE_HEADER - // Create the file header and write it in the bin file + // Create the file header and write it in the bin file - // [Declaration of the binary file] - // File Identifier (8 bytes) - // Size of file in bytes (4 bytes) - // Number of HRTF (2 bytes) - // Max length of HRTF data (4 bytes) + // [Declaration of the binary file] + // File Identifier (8 bytes) + // Size of file in bytes (4 bytes) + // Number of HRTF (2 bytes) + // Max length of HRTF data (4 bytes) - file_header_size = file_identifier_len + sizeof( int32_t ) + sizeof( int16_t ) + sizeof( int32_t ); - file_header = (char *) malloc( file_header_size ); - if ( file_header == NULL ) - { - fprintf( stderr, "Memory allocation for the file header failed!\n\n" ); - for ( l = 0; l < nbHRTF; l++ ) + file_header_size = file_identifier_len + sizeof( int32_t ) + sizeof( int16_t ) + sizeof( int32_t ); + file_header = (char *) malloc( file_header_size ); + if ( file_header == NULL ) { - free( setOfHRTF[l] ); + fprintf( stderr, "Memory allocation for the file header failed!\n\n" ); + for ( l = 0; l < nbHRTF; l++ ) + { + free( setOfHRTF[l] ); + } + free( setOfHRTF ); + rom2bin_terminat(); + return -1; } - free( setOfHRTF ); - rom2bin_terminat(); - return -1; - } - fileSize += file_header_size; - file_header_wptr = file_header; + fileSize += file_header_size; + file_header_wptr = file_header; - memcpy( file_header_wptr, file_identifier, file_identifier_len ); - file_header_wptr += file_identifier_len; + memcpy( file_header_wptr, file_identifier, file_identifier_len ); + file_header_wptr += file_identifier_len; - memcpy( file_header_wptr, &( fileSize ), sizeof( int32_t ) ); - file_header_wptr += sizeof( int32_t ); + memcpy( file_header_wptr, &( fileSize ), sizeof( int32_t ) ); + file_header_wptr += sizeof( int32_t ); - memcpy( file_header_wptr, &( nbHRTF ), sizeof( int16_t ) ); - file_header_wptr += sizeof( int16_t ); + memcpy( file_header_wptr, &( nbHRTF ), sizeof( int16_t ) ); + file_header_wptr += sizeof( int16_t ); - hrtf_size_max -= 4 * sizeof( int32_t ); - memcpy( file_header_wptr, &( hrtf_size_max ), sizeof( int32_t ) ); - file_header_wptr += sizeof( int32_t ); + hrtf_size_max -= sizeof( ivas_hrtfs_header_t ); // Keep only the raw data size max (w/o the header of the hrtf) + memcpy( file_header_wptr, &( hrtf_size_max ), sizeof( int32_t ) ); + file_header_wptr += sizeof( int32_t ); - fwrite( file_header, file_header_size, 1, bin_file ); - free( file_header ); + fwrite( file_header, file_header_size, 1, bin_file ); + free( file_header ); #endif - // Write each HRTF in the bin file + // Write each HRTF in the bin file - for ( i = 0; i < nbHRTF; i++ ) - { - fwrite( setOfHRTF[i], read_hrtf_size( setOfHRTF[i] ), 1, bin_file ); - free( setOfHRTF[i] ); - setOfHRTF[i] = NULL; - } - free( setOfHRTF ); - setOfHRTF = NULL; + for ( i = 0; i < nbHRTF; i++ ) + { + fwrite( setOfHRTF[i], read_hrtf_size( setOfHRTF[i] ), 1, bin_file ); + free( setOfHRTF[i] ); + setOfHRTF[i] = NULL; + } + free( setOfHRTF ); + setOfHRTF = NULL; - if ( bin_file != NULL ) - { - fclose( bin_file ); - bin_file = NULL; - } + if ( bin_file != NULL ) + { + fclose( bin_file ); + bin_file = NULL; + } - // Testing of the generated file + // Testing of the generated file - bin_file = NULL; - bin_file = fopen( full_out_path, "rb" ); - if ( bin_file == NULL ) - { - fprintf( stderr, "Checking : Reading of binary file failed: %s\n\n", full_out_path ); - return -1; - } + bin_file = NULL; + bin_file = fopen( full_out_path, "rb" ); + if ( bin_file == NULL ) + { + fprintf( stderr, "Checking : Reading of binary file failed: %s\n\n", full_out_path ); + return -1; + } - if ( 0 == check_bin_file( bin_file ) ) - { - fprintf( stdout, "Binary file successfully generated.\n\n" ); - } - else - { - fprintf( stderr, "Binary file generation failed!\n\n" ); + if ( 0 == check_bin_file( bin_file ) ) + { + fprintf( stdout, "Binary file %s successfully generated.\n\n", full_out_path ); + } + else + { + fprintf( stderr, "Binary file %s generation failed!\n\n", full_out_path ); + } + fclose( bin_file ); } - fclose( bin_file ); rom2bin_terminat(); @@ -445,223 +574,140 @@ int main( int argc, char *argv[] ) *---------------------------------------------------------------------*/ char *create_hrtf_crend( RENDERER_TYPE rend_type, BINAURAL_INPUT_AUDIO_CONFIG input_cfg, int32_t frequency, int32_t *hrtf_size ) { - crend_hrtf_tables_dimensions tabs_dims; - crend_hrtf_tables_pointers tabs_ptrs; - - /* uint16_t max_num_iterations, max_num_iterations_diffuse, index_frequency_max_diffuse; */ - uint16_t iChan, iIR; - uint32_t hrtf_data_size, data_size_tmp; - uint32_t iIter, iIndex; - /* uint32_t total_num_fsamp_per_iteration, iIter, iIndex; - uint32_t total_num_fsamp_per_iteration_diff; */ - float *coeff_rptr; - char *hrtf = NULL, *hrtf_wptr; - - memset( &tabs_dims, 0x00, sizeof( crend_hrtf_tables_dimensions ) ); - memset( &tabs_ptrs, 0x00, sizeof( crend_hrtf_tables_pointers ) ); - hrtf_data_size = 0; - *hrtf_size = 0; - - /* Binary file - block description : - - latency_s => float - - max_num_ir => uint16_t - BINAURAL_CHANNELS => uint16_t (BINAURAL_CHANNELS) + int32_t mixerconv_hrtf_header_size, mixerconv_hrtf_data_size; + char *mixerconv_hrtf = NULL, *mixerconv_hrtf_wptr; - max_num_iterations => int16_t - num_iterations => uint16_t[max_num_ir][BINAURAL_CHANNELS] - pIndex_frequency_max => uint16_t[max_num_ir][BINAURAL_CHANNELS][max_num_iterations] (Pointer) - max_num_iterations_diffuse => int16_t - num_iterations_diffuse => uint16_t[BINAURAL_CHANNELS] - pIndex_frequency_max_diffuse => uint16_t[BINAURAL_CHANNELS][max_num_iterations_diffuse] (Pointer) + char *full_in_mixerconv_path = NULL; + FILE *input_mixerconv_bin_file = NULL; - index_frequency_max_diffuse => uint16_t - inv_diffuse_weight => float[max_num_ir] + // Get the HRTF raw data - max_total_num_fsamp_per_iteration => uint16_t - coeff_re => float[max_num_ir][BINAURAL_CHANNELS][max_total_num_fsamp_per_iteration] (Pointer) - coeff_im => float[max_num_ir][BINAURAL_CHANNELS][max_total_num_fsamp_per_iteration] (Pointer) + char *configuration_name = ""; - max_total_num_fsamp_per_iteration_diff => uint16_t - coeff_diffuse_re => float[BINAURAL_CHANNELS][max_total_num_fsamp_per_iteration] (Pointer) - coeff_diffuse_im => float[BINAURAL_CHANNELS][max_total_num_fsamp_per_iteration] (Pointer) - */ - - // First, get the tables and the relative dimensions - - if ( get_crend_hrtf_tables( rend_type, input_cfg, frequency, &tabs_ptrs, &tabs_dims ) == -1 ) + // Example : ivas_hrfilters_mixerconv_Combined_HRIR_48kHz.bin + if ( rend_type == RENDERER_BINAURAL_MIXER_CONV ) { - fprintf( stderr, "Get table failed!\n\n" ); - free( hrtf ); - *hrtf_size = -1; - return NULL; + if ( input_cfg == BINAURAL_INPUT_AUDIO_CONFIG_COMBINED ) + { + configuration_name = "Combined_HRIR"; + } + else if ( input_cfg == BINAURAL_INPUT_AUDIO_CONFIG_FOA ) + { + configuration_name = "FOA_HRIR"; + } + else if ( input_cfg == BINAURAL_INPUT_AUDIO_CONFIG_HOA2 ) + { + configuration_name = "HOA2_HRIR"; + } + else if ( input_cfg == BINAURAL_INPUT_AUDIO_CONFIG_HOA3 ) + { + configuration_name = "HOA3_HRIR"; + } + full_in_mixerconv_path = malloc( strlen( input_mixerconv_bin_hrir_path ) + 1 + strlen( input_mixerconv_bin_hrir_file_name ) + 1 + strlen( configuration_name ) + 1 + 5 + strlen( DEFAULT_BIN_FILE_EXT ) + 1 ); +#ifdef _WIN32 + sprintf( full_in_mixerconv_path, "%s\\%s_%s_%dkHz%s", input_mixerconv_bin_hrir_path, input_mixerconv_bin_hrir_file_name, configuration_name, frequency / 1000, DEFAULT_BIN_FILE_EXT ); +#else + sprintf( full_in_mixerconv_path, "%s/%s_%s_%dkHz%s", input_mixerconv_bin_hrir_path, input_mixerconv_bin_hrir_file_name, configuration_name, frequency / 1000, DEFAULT_BIN_FILE_EXT ); +#endif } - - if ( tabs_dims.max_num_ir == 0 ) + else if ( rend_type == RENDERER_BINAURAL_MIXER_CONV_ROOM ) { - // Table not found - *hrtf_size = 0; - return NULL; + if ( input_cfg == BINAURAL_INPUT_AUDIO_CONFIG_COMBINED ) + { + configuration_name = "Combined_BRIR"; + } + else if ( input_cfg == BINAURAL_INPUT_AUDIO_CONFIG_FOA ) + { + return NULL; + } + else if ( input_cfg == BINAURAL_INPUT_AUDIO_CONFIG_HOA2 ) + { + return NULL; + } + else if ( input_cfg == BINAURAL_INPUT_AUDIO_CONFIG_HOA3 ) + { + return NULL; + } + full_in_mixerconv_path = malloc( strlen( input_mixerconv_bin_brir_path ) + 1 + strlen( input_mixerconv_bin_brir_file_name ) + 1 + strlen( configuration_name ) + 1 + 5 + strlen( DEFAULT_BIN_FILE_EXT ) + 1 ); +#ifdef _WIN32 + sprintf( full_in_mixerconv_path, "%s\\%s_%s_%dkHz%s", input_mixerconv_bin_brir_path, input_mixerconv_bin_brir_file_name, configuration_name, frequency / 1000, DEFAULT_BIN_FILE_EXT ); +#else + sprintf( full_in_mixerconv_path, "%s/%s_%s_%dkHz%s", input_mixerconv_bin_brir_path, input_mixerconv_bin_brir_file_name, configuration_name, frequency / 1000, DEFAULT_BIN_FILE_EXT ); +#endif } - // Then, determine the block size + input_mixerconv_bin_file = fopen( full_in_mixerconv_path, "rb" ); - hrtf_data_size = compute_crend_hrtf_data_size( &tabs_ptrs, &tabs_dims ); + if ( input_mixerconv_bin_file != NULL ) + { + fseek( input_mixerconv_bin_file, 0, SEEK_END ); + mixerconv_hrtf_data_size = ftell( input_mixerconv_bin_file ); + fseek( input_mixerconv_bin_file, 0, SEEK_SET ); - // Header [Declaration of the HRTF] - // Renderer type (4 bytes) : See "RENDERER_TYPE" - // Decodeur output format (4 bytes) : See "BINAURAL_INPUT_AUDIO_CONFIG" - // Sampling Frequency (4 bytes) - // Raw data size (4 bytes) + // Header [Declaration of the HRTF] + // Renderer type (4 bytes) : See "RENDERER_TYPE" + // Decoder output format (4 bytes) : See "BINAURAL_INPUT_AUDIO_CONFIG" + // Sampling Frequency (4 bytes) + // Raw data size (4 bytes) - *hrtf_size = sizeof( ivas_hrtfs_header_t ) + hrtf_data_size; - hrtf = (char *) malloc( *hrtf_size ); - if ( hrtf == NULL ) - { - fprintf( stderr, "Memory allocation for the block failed!\n\n" ); - *hrtf_size = -1; - return NULL; - } + mixerconv_hrtf_header_size = sizeof( int32_t ) + sizeof( int32_t ) + sizeof( int32_t ) + sizeof( uint32_t ); + *hrtf_size = mixerconv_hrtf_header_size + mixerconv_hrtf_data_size; + mixerconv_hrtf = (char *) malloc( *hrtf_size ); - memset( hrtf, 0x00, *hrtf_size ); - hrtf_wptr = hrtf; + if ( mixerconv_hrtf == NULL ) + { + fprintf( stderr, "Memory allocation for the block failed!\n\n" ); + fclose( input_mixerconv_bin_file ); + *hrtf_size = -1; + return NULL; + } - // Write the HRTF header + memset( mixerconv_hrtf, 0x00, *hrtf_size ); + mixerconv_hrtf_wptr = mixerconv_hrtf; - // Renderer type - memcpy( hrtf_wptr, &( rend_type ), sizeof( int32_t ) ); - hrtf_wptr += sizeof( int32_t ); + // Get the HRTF header - // Decoder output format - memcpy( hrtf_wptr, &( input_cfg ), sizeof( int32_t ) ); - hrtf_wptr += sizeof( int32_t ); + // Renderer type + memcpy( mixerconv_hrtf_wptr, &( rend_type ), sizeof( int32_t ) ); + mixerconv_hrtf_wptr += sizeof( int32_t ); - // Sampling Frequency - memcpy( hrtf_wptr, &( frequency ), sizeof( int32_t ) ); - hrtf_wptr += sizeof( int32_t ); - - // Raw data size - memcpy( hrtf_wptr, &( hrtf_data_size ), sizeof( uint32_t ) ); - hrtf_wptr += sizeof( uint32_t ); - - // Write the HRTF raw data - - memcpy( hrtf_wptr, tabs_ptrs.latency_s, sizeof( float ) ); // latency_s - hrtf_wptr += sizeof( float ); - - memcpy( hrtf_wptr, &( tabs_dims.max_num_ir ), sizeof( uint16_t ) ); // max_num_ir - hrtf_wptr += sizeof( uint16_t ); - - uint16_t nchan_bin = BINAURAL_CHANNELS; - memcpy( hrtf_wptr, &nchan_bin, sizeof( uint16_t ) ); // BINAURAL_CHANNELS - hrtf_wptr += sizeof( uint16_t ); - - memcpy( hrtf_wptr, &( tabs_dims.max_num_iterations ), sizeof( int16_t ) ); // max_num_iterations - hrtf_wptr += sizeof( int16_t ); - - data_size_tmp = tabs_dims.max_num_ir * BINAURAL_CHANNELS * sizeof( uint16_t ); - memcpy( hrtf_wptr, tabs_ptrs.num_iterations, data_size_tmp ); // num_iterations - hrtf_wptr += data_size_tmp; - - data_size_tmp = tabs_dims.max_num_ir * BINAURAL_CHANNELS * tabs_dims.max_num_iterations * sizeof( uint16_t ); - memcpy( hrtf_wptr, tabs_ptrs.pIndex_frequency_max, data_size_tmp ); // pIndex_frequency_max - hrtf_wptr += data_size_tmp; - - memcpy( hrtf_wptr, &( tabs_dims.max_num_iterations_diffuse ), sizeof( int16_t ) ); // max_num_iterations_diffuse - hrtf_wptr += sizeof( int16_t ); - - if ( tabs_dims.max_num_iterations_diffuse != 0 ) - { - data_size_tmp = BINAURAL_CHANNELS * sizeof( uint16_t ); - memcpy( hrtf_wptr, tabs_ptrs.num_iterations_diffuse, data_size_tmp ); // num_iterations_diffuse - hrtf_wptr += data_size_tmp; - - // pIndex_frequency_max_diffuse (the size depends on num_iterations_diffuse) - for ( iChan = 0; iChan < BINAURAL_CHANNELS; iChan++ ) - { - data_size_tmp = tabs_ptrs.num_iterations_diffuse[iChan] * sizeof( uint16_t ); - memcpy( hrtf_wptr, tabs_ptrs.pIndex_frequency_max_diffuse, data_size_tmp ); - hrtf_wptr += data_size_tmp; - } - } + // Decoder output format + memcpy( mixerconv_hrtf_wptr, &( input_cfg ), sizeof( int32_t ) ); + mixerconv_hrtf_wptr += sizeof( int32_t ); - memcpy( hrtf_wptr, tabs_ptrs.index_frequency_max_diffuse, sizeof( uint16_t ) ); // index_frequency_max_diffuse - hrtf_wptr += sizeof( uint16_t ); + // Sampling Frequency + memcpy( mixerconv_hrtf_wptr, &( frequency ), sizeof( int32_t ) ); + mixerconv_hrtf_wptr += sizeof( int32_t ); - data_size_tmp = tabs_dims.max_num_ir * sizeof( float ); - memcpy( hrtf_wptr, tabs_ptrs.inv_diffuse_weight, data_size_tmp ); // inv_diffuse_weight - hrtf_wptr += data_size_tmp; + // Raw data size + memcpy( mixerconv_hrtf_wptr, &( mixerconv_hrtf_data_size ), sizeof( uint32_t ) ); + mixerconv_hrtf_wptr += sizeof( uint32_t ); - memcpy( hrtf_wptr, &( tabs_dims.max_total_num_fsamp_per_iteration ), sizeof( uint16_t ) ); // max_total_num_fsamp_per_iteration - hrtf_wptr += sizeof( uint16_t ); + // Get the HRTF raw data - // coeff_re (The size depends on pIndex_frequency_max) - for ( iIR = 0, iIndex = 0; iIR < tabs_dims.max_num_ir; iIR++ ) - { - for ( iChan = 0; iChan < BINAURAL_CHANNELS; iChan++ ) + if ( fread( mixerconv_hrtf_wptr, mixerconv_hrtf_data_size, 1, input_mixerconv_bin_file ) != 1 ) { - coeff_rptr = tabs_ptrs.coeff_re + ( iIR * BINAURAL_CHANNELS + iChan ) * tabs_dims.max_total_num_fsamp_per_iteration; - for ( iIter = 0; iIter < tabs_ptrs.num_iterations[iIR * BINAURAL_CHANNELS + iChan]; iIter++ ) - { - data_size_tmp = tabs_ptrs.pIndex_frequency_max[iIndex] * sizeof( float ); - memcpy( hrtf_wptr, coeff_rptr, data_size_tmp ); - hrtf_wptr += data_size_tmp; - coeff_rptr += tabs_ptrs.pIndex_frequency_max[iIndex++]; - } + fprintf( stderr, "Reading of the mixer_conv hrtf failed!\n\n" ); + fclose( input_mixerconv_bin_file ); + free( mixerconv_hrtf ); + *hrtf_size = -1; + return NULL; } - } - // coeff_im : The size depends on pIndex_frequency_max - for ( iIR = 0, iIndex = 0; iIR < tabs_dims.max_num_ir; iIR++ ) - { - for ( iChan = 0; iChan < BINAURAL_CHANNELS; iChan++ ) - { - coeff_rptr = tabs_ptrs.coeff_im + ( iIR * BINAURAL_CHANNELS + iChan ) * tabs_dims.max_total_num_fsamp_per_iteration; - for ( iIter = 0; iIter < tabs_ptrs.num_iterations[iIR * BINAURAL_CHANNELS + iChan]; iIter++ ) - { - data_size_tmp = tabs_ptrs.pIndex_frequency_max[iIndex] * sizeof( float ); - memcpy( hrtf_wptr, coeff_rptr, data_size_tmp ); - hrtf_wptr += data_size_tmp; - coeff_rptr += tabs_ptrs.pIndex_frequency_max[iIndex++]; - } - } + fclose( input_mixerconv_bin_file ); + input_mixerconv_bin_file = NULL; + free( full_in_mixerconv_path ); + full_in_mixerconv_path = NULL; } - - memcpy( hrtf_wptr, &( tabs_dims.max_total_num_fsamp_per_iteration_diff ), sizeof( uint16_t ) ); // max_total_num_fsamp_per_iteration_diff - hrtf_wptr += sizeof( uint16_t ); - - if ( tabs_dims.max_total_num_fsamp_per_iteration_diff != 0 ) + else { - // coeff_diffuse_re : The size depends on pIndex_frequency_max_diffuse - for ( iChan = 0, iIndex = 0; iChan < BINAURAL_CHANNELS; iChan++ ) - { - coeff_rptr = tabs_ptrs.coeff_diffuse_re + iChan * tabs_dims.max_total_num_fsamp_per_iteration_diff; - for ( iIter = 0; iIter < tabs_ptrs.num_iterations_diffuse[iChan]; iIter++ ) - { - data_size_tmp = tabs_ptrs.pIndex_frequency_max_diffuse[iIndex] * sizeof( float ); - memcpy( hrtf_wptr, coeff_rptr, data_size_tmp ); - hrtf_wptr += data_size_tmp; - coeff_rptr += tabs_ptrs.pIndex_frequency_max_diffuse[iIndex++]; - } - } - - // coeff_diffuse_im : The size depends on pIndex_frequency_max_diffuse - for ( iChan = 0, iIndex = 0; iChan < BINAURAL_CHANNELS; iChan++ ) - { - coeff_rptr = tabs_ptrs.coeff_diffuse_im + iChan * tabs_dims.max_total_num_fsamp_per_iteration_diff; - for ( iIter = 0; iIter < tabs_ptrs.num_iterations_diffuse[iChan]; iIter++ ) - { - data_size_tmp = tabs_ptrs.pIndex_frequency_max_diffuse[iIndex] * sizeof( float ); - memcpy( hrtf_wptr, coeff_rptr, data_size_tmp ); - hrtf_wptr += data_size_tmp; - coeff_rptr += tabs_ptrs.pIndex_frequency_max_diffuse[iIndex++]; - } - } + fprintf( stderr, "Opening of file %s failed!\n\n", full_in_mixerconv_path ); + *hrtf_size = -1; + return NULL; } - return hrtf; + return mixerconv_hrtf; } /*---------------------------------------------------------------------* @@ -673,7 +719,7 @@ char *create_hrtf_tdrend( int32_t frequency, int32_t *hrtf_size ) FILE *input_td_bin_file = NULL; int32_t td_hrtf_header_size, td_hrtf_data_size; - char *td_hrtf = NULL, *td_hrtf_wptr; + char *td_hrtf = NULL, *td_hrtf_wptr, *full_in_td_path = NULL; // left/right and coherences for late reverb table sizes int32_t td_hrtf_coh_and_ener_size; @@ -682,7 +728,20 @@ char *create_hrtf_tdrend( int32_t frequency, int32_t *hrtf_size ) *hrtf_size = 0; - sprintf( full_in_td_path, "%s%s_%dkHz%s", input_td_bin_path, input_td_bin_file_name, frequency / 1000, DEFAULT_BIN_FILE_EXT ); + full_in_td_path = (char *) malloc( sizeof( char ) * ( strlen( input_td_bin_path ) + 1 + strlen( input_td_bin_file_name ) + 1 + 5 + strlen( DEFAULT_BIN_FILE_EXT ) + 1 ) ); + if ( full_in_td_path == NULL ) + { + fprintf( stderr, "Memory issue for full input td path!\n\n" ); + rom2bin_terminat(); + return NULL; + } + + +#ifdef _WIN32 + sprintf( full_in_td_path, "%s\\%s_%dkHz%s", input_td_bin_path, input_td_bin_file_name, frequency / 1000, DEFAULT_BIN_FILE_EXT ); +#else + sprintf( full_in_td_path, "%s/%s_%dkHz%s", input_td_bin_path, input_td_bin_file_name, frequency / 1000, DEFAULT_BIN_FILE_EXT ); +#endif input_td_bin_file = fopen( full_in_td_path, "rb" ); if ( input_td_bin_file != NULL ) @@ -709,6 +768,8 @@ char *create_hrtf_tdrend( int32_t frequency, int32_t *hrtf_size ) fprintf( stderr, "Memory allocation for the block failed!\n\n" ); fclose( input_td_bin_file ); *hrtf_size = -1; + free( full_in_td_path ); + full_in_td_path = NULL; return NULL; } @@ -741,12 +802,13 @@ char *create_hrtf_tdrend( int32_t frequency, int32_t *hrtf_size ) fprintf( stderr, "Reading of the td hrtf failed!\n\n" ); fclose( input_td_bin_file ); free( td_hrtf ); + free( full_in_td_path ); + full_in_td_path = NULL; *hrtf_size = -1; return NULL; } td_hrtf_wptr += td_hrtf_data_size; - // Left/right and coherence late reverb tables data_size_tmp = sizeof( float ) * LR_IAC_LENGTH_NR_FC; if ( frequency == 48000 ) @@ -776,7 +838,6 @@ char *create_hrtf_tdrend( int32_t frequency, int32_t *hrtf_size ) memcpy( td_hrtf_wptr, &( defaultHRIR_coherence_16kHz ), data_size_tmp ); td_hrtf_wptr += data_size_tmp; } - fclose( input_td_bin_file ); input_td_bin_file = NULL; } @@ -787,6 +848,8 @@ char *create_hrtf_tdrend( int32_t frequency, int32_t *hrtf_size ) return NULL; } + free( full_in_td_path ); + full_in_td_path = NULL; return td_hrtf; } @@ -794,20 +857,16 @@ char *create_hrtf_tdrend( int32_t frequency, int32_t *hrtf_size ) * create_hrtf_fastconv() * *---------------------------------------------------------------------*/ -char *create_hrtf_fastconv( RENDERER_TYPE rend_type, BINAURAL_INPUT_AUDIO_CONFIG input_cfg, int32_t frequency, int32_t *hrtf_size ) +char *create_hrtf_fastconv( RENDERER_TYPE rend_type, BINAURAL_INPUT_AUDIO_CONFIG input_cfg, int32_t *hrtf_size ) { - char *hrtf = NULL, *hrtf_wptr; - uint32_t hrtf_data_size; - uint32_t data_size_tmp; - - int16_t i, j; - uint16_t binaural_convbands; - uint16_t hrtf_channels; - uint16_t num_taps; - uint16_t cldfb_nchan_max; - float latency_s; + char *fastconv_hrtf = NULL, *fastconv_hrtf_wptr; + int32_t fastconv_hrtf_data_size; + char hrtf_identifier[8] = ""; + int32_t hrtf_total_file_size = 0, hrtf_data_size = 0; + int16_t nbHrft = 0, ind; + ivas_hrtfs_header_t hrtf_header; - hrtf_data_size = 0; + fastconv_hrtf_data_size = 0; /* Binary file - block description : @@ -846,362 +905,189 @@ char *create_hrtf_fastconv( RENDERER_TYPE rend_type, BINAURAL_INPUT_AUDIO_CONFIG fastConvReverberationEneCorrection => float[CLDFB_NO_CHANNELS_MAX] */ - // Set table sizes - binaural_convbands = BINAURAL_CONVBANDS; - - if ( input_cfg == BINAURAL_INPUT_AUDIO_CONFIG_COMBINED ) - { - latency_s = FASTCONV_HRIR_latency_s; - hrtf_channels = HRTF_LS_CHANNELS; - num_taps = BINAURAL_NTAPS; - - if ( rend_type == RENDERER_BINAURAL_FASTCONV_ROOM ) - { - latency_s = FASTCONV_BRIR_latency_s; - hrtf_channels = HRTF_LS_CHANNELS; - num_taps = BINAURAL_NTAPS_MAX; - cldfb_nchan_max = CLDFB_NO_CHANNELS_MAX; - } - } - else if ( input_cfg == BINAURAL_INPUT_AUDIO_CONFIG_HOA3 ) - { - if ( rend_type == RENDERER_BINAURAL_FASTCONV_ROOM ) - { - /* No HOA3 BRIRs */ - return NULL; - } - - latency_s = FASTCONV_HOA3_latency_s; - hrtf_channels = HRTF_SH_CHANNELS; - num_taps = BINAURAL_NTAPS_SBA; - } - else if ( input_cfg == BINAURAL_INPUT_AUDIO_CONFIG_HOA2 ) - { - if ( rend_type == RENDERER_BINAURAL_FASTCONV_ROOM ) - { - /* No HOA2 BRIRs */ - return NULL; - } - latency_s = FASTCONV_HOA2_latency_s; - hrtf_channels = 9; - num_taps = BINAURAL_NTAPS_SBA; - } - else if ( input_cfg == BINAURAL_INPUT_AUDIO_CONFIG_FOA ) - { - if ( rend_type == RENDERER_BINAURAL_FASTCONV_ROOM ) - { - /* No HOA2 BRIRs */ - return NULL; - } + char *full_in_fastconv_path = NULL; + FILE *input_fastconv_bin_file = NULL; - latency_s = FASTCONV_FOA_latency_s; - hrtf_channels = 4; - num_taps = BINAURAL_NTAPS_SBA; - } - else + if ( ( rend_type == RENDERER_BINAURAL_FASTCONV_ROOM ) && ( ( input_cfg == BINAURAL_INPUT_AUDIO_CONFIG_HOA3 ) || ( input_cfg == BINAURAL_INPUT_AUDIO_CONFIG_HOA2 ) || ( input_cfg == BINAURAL_INPUT_AUDIO_CONFIG_FOA ) ) ) { - fprintf( stderr, "Unsupported renderer type in create_hrtf_fastconv()\n\n" ); + /* No FOA, HOA2, HOA3 BRIRs */ return NULL; } - // Compute total size of data to write - hrtf_data_size += sizeof( uint16_t ); // BINAURAL_CONVBANDS - hrtf_data_size += sizeof( float ); // latency_s - hrtf_data_size += sizeof( uint16_t ); // HRTF_{SH,LS}_CHANNELS - hrtf_data_size += sizeof( uint16_t ); // num_taps - hrtf_data_size += 4 * ( BINAURAL_CONVBANDS * hrtf_channels * num_taps * sizeof( float ) ); // HRTF - - if ( rend_type == RENDERER_BINAURAL_FASTCONV_ROOM && input_cfg == BINAURAL_INPUT_AUDIO_CONFIG_COMBINED ) - { - hrtf_data_size += sizeof( uint16_t ); // CLDFB_NO_CHANNELS_MAX - hrtf_data_size += CLDFB_NO_CHANNELS_MAX * sizeof( float ); // fastconvReverberationTimes - hrtf_data_size += CLDFB_NO_CHANNELS_MAX * sizeof( float ); // fastconvEneCorrections - } - - // Allocate memory - *hrtf_size = sizeof( ivas_hrtfs_header_t ) + hrtf_data_size; - hrtf = (char *) malloc( *hrtf_size ); + // Get the HRTF raw data - if ( hrtf == NULL ) + full_in_fastconv_path = (char *) malloc( sizeof( char ) * ( strlen( input_fastconv_bin_path ) + strlen( input_fastconv_bin_file_name ) + 2 ) ); + if ( full_in_fastconv_path == NULL ) { - fprintf( stderr, "Memory allocation for the block failed!\n\n" ); - *hrtf_size = -1; + fprintf( stderr, "Memory issue for full input parambin path!\n\n" ); + rom2bin_terminat(); return NULL; } - // Write - - // Header [Declaration of the HRTF] - // Renderer type (4 bytes) : See "RENDERER_TYPE" - // Decoder output format (4 bytes) : See "BINAURAL_INPUT_AUDIO_CONFIG" - // Sampling Frequency (4 bytes) - // Raw data size (4 bytes) - - memset( hrtf, 0x00, *hrtf_size ); - hrtf_wptr = hrtf; - - // Renderer type - memcpy( hrtf_wptr, &( rend_type ), sizeof( int32_t ) ); - hrtf_wptr += sizeof( int32_t ); - - // Decoder output format - memcpy( hrtf_wptr, &( input_cfg ), sizeof( int32_t ) ); - hrtf_wptr += sizeof( int32_t ); - - // Sampling Frequency - memcpy( hrtf_wptr, &( frequency ), sizeof( int32_t ) ); - hrtf_wptr += sizeof( int32_t ); - - // Raw data size - memcpy( hrtf_wptr, &( hrtf_data_size ), sizeof( uint32_t ) ); - hrtf_wptr += sizeof( uint32_t ); - - - // Write the HRTF raw data - memcpy( hrtf_wptr, &( binaural_convbands ), sizeof( uint16_t ) ); // nbands_bin => uint16_t - hrtf_wptr += sizeof( uint16_t ); +#ifdef _WIN32 + sprintf( full_in_fastconv_path, "%s\\%s", input_fastconv_bin_path, input_fastconv_bin_file_name ); +#else + sprintf( full_in_fastconv_path, "%s/%s", input_fastconv_bin_path, input_fastconv_bin_file_name ); +#endif + input_fastconv_bin_file = fopen( full_in_fastconv_path, "rb" ); - // HRIR - if ( rend_type == RENDERER_BINAURAL_FASTCONV && input_cfg == BINAURAL_INPUT_AUDIO_CONFIG_COMBINED ) + if ( input_fastconv_bin_file != NULL ) { - memcpy( hrtf_wptr, &( latency_s ), sizeof( float ) ); // latency_s => float - hrtf_wptr += sizeof( float ); + fseek( input_fastconv_bin_file, 0, SEEK_END ); + fastconv_hrtf_data_size = ftell( input_fastconv_bin_file ); + fseek( input_fastconv_bin_file, 0, SEEK_SET ); - memcpy( hrtf_wptr, &( hrtf_channels ), sizeof( uint16_t ) ); // hrtf_channels => uint16_t - hrtf_wptr += sizeof( uint16_t ); + // fwrite(f_id, 'IVASHRTF', 'char'); % identifier + // fwrite(f_id, total_file_size, 'int32'); % file size + // fwrite(f_id, length(HRTFs), 'int16'); % number of HRTFs + // fwrite(f_id, hrtf_data_size, 'int32'); % max data size (bytes to read after this header) - memcpy( hrtf_wptr, &( num_taps ), sizeof( uint16_t ) ); // num_taps => uint16_t - hrtf_wptr += sizeof( uint16_t ); - - data_size_tmp = num_taps * sizeof( float ); - for ( i = 0; i < BINAURAL_CONVBANDS; i++ ) - { - for ( j = 0; j < hrtf_channels; j++ ) - { - memcpy( hrtf_wptr, &leftHRIRReal[i][j], data_size_tmp ); - hrtf_wptr += data_size_tmp; - } - } - for ( i = 0; i < BINAURAL_CONVBANDS; i++ ) + if ( fread( &hrtf_identifier, sizeof( char ), 8, input_fastconv_bin_file ) != 8 ) { - for ( j = 0; j < hrtf_channels; j++ ) - { - memcpy( hrtf_wptr, &leftHRIRImag[i][j], data_size_tmp ); - hrtf_wptr += data_size_tmp; - } - } - for ( i = 0; i < BINAURAL_CONVBANDS; i++ ) - { - for ( j = 0; j < hrtf_channels; j++ ) - { - memcpy( hrtf_wptr, &rightHRIRReal[i][j], data_size_tmp ); - hrtf_wptr += data_size_tmp; - } + fprintf( stderr, "Reading of the fastconv hrtf failed!\n\n" ); + fclose( input_fastconv_bin_file ); + free( fastconv_hrtf ); + free( full_in_fastconv_path ); + *hrtf_size = -1; + return NULL; } - for ( i = 0; i < BINAURAL_CONVBANDS; i++ ) + + if ( fread( &hrtf_total_file_size, sizeof( int32_t ), 1, input_fastconv_bin_file ) != 1 ) { - for ( j = 0; j < hrtf_channels; j++ ) - { - memcpy( hrtf_wptr, &rightHRIRImag[i][j], data_size_tmp ); - hrtf_wptr += data_size_tmp; - } + fprintf( stderr, "Reading of the fastconv hrtf failed!\n\n" ); + fclose( input_fastconv_bin_file ); + free( fastconv_hrtf ); + free( full_in_fastconv_path ); + *hrtf_size = -1; + return NULL; } - } - // HRIR_HOA3 - else if ( rend_type == RENDERER_BINAURAL_FASTCONV && input_cfg == BINAURAL_INPUT_AUDIO_CONFIG_HOA3 ) - { - memcpy( hrtf_wptr, &( latency_s ), sizeof( float ) ); // latency_s => float - hrtf_wptr += sizeof( float ); - memcpy( hrtf_wptr, &( hrtf_channels ), sizeof( uint16_t ) ); // hrtf_channels => uint16_t - hrtf_wptr += sizeof( uint16_t ); - - memcpy( hrtf_wptr, &( num_taps ), sizeof( uint16_t ) ); // num_taps => uint16_t - hrtf_wptr += sizeof( uint16_t ); - - data_size_tmp = num_taps * sizeof( float ); - for ( i = 0; i < BINAURAL_CONVBANDS; i++ ) + if ( hrtf_total_file_size != fastconv_hrtf_data_size ) { - for ( j = 0; j < hrtf_channels; j++ ) - { - memcpy( hrtf_wptr, &leftHRIRReal_HOA3[i][j], data_size_tmp ); - hrtf_wptr += data_size_tmp; - } + fprintf( stderr, "Reading of the fastconv hrtf failed!\n\n" ); + fclose( input_fastconv_bin_file ); + free( fastconv_hrtf ); + free( full_in_fastconv_path ); + *hrtf_size = -1; + return NULL; } - for ( i = 0; i < BINAURAL_CONVBANDS; i++ ) + + if ( fread( &nbHrft, sizeof( int16_t ), 1, input_fastconv_bin_file ) != 1 ) { - for ( j = 0; j < hrtf_channels; j++ ) - { - memcpy( hrtf_wptr, &leftHRIRImag_HOA3[i][j], data_size_tmp ); - hrtf_wptr += data_size_tmp; - } + fprintf( stderr, "Reading of the fastconv hrtf failed!\n\n" ); + fclose( input_fastconv_bin_file ); + free( fastconv_hrtf ); + free( full_in_fastconv_path ); + *hrtf_size = -1; + return NULL; } - for ( i = 0; i < BINAURAL_CONVBANDS; i++ ) + + if ( fread( &hrtf_data_size, sizeof( int32_t ), 1, input_fastconv_bin_file ) != 1 ) { - for ( j = 0; j < hrtf_channels; j++ ) - { - memcpy( hrtf_wptr, &rightHRIRReal_HOA3[i][j], data_size_tmp ); - hrtf_wptr += data_size_tmp; - } + fprintf( stderr, "Reading of the fastconv hrtf failed!\n\n" ); + fclose( input_fastconv_bin_file ); + free( fastconv_hrtf ); + free( full_in_fastconv_path ); + *hrtf_size = -1; + return NULL; } - for ( i = 0; i < BINAURAL_CONVBANDS; i++ ) + + if ( hrtf_data_size != fastconv_hrtf_data_size - nbHrft * sizeof( ivas_hrtfs_header_t ) - ( sizeof( int32_t ) * 2 + sizeof( int16_t ) + sizeof( char ) * 8 ) ) { - for ( j = 0; j < hrtf_channels; j++ ) - { - memcpy( hrtf_wptr, &rightHRIRImag_HOA3[i][j], data_size_tmp ); - hrtf_wptr += data_size_tmp; - } + fprintf( stderr, "Reading of the fastconv hrtf failed!\n\n" ); + fclose( input_fastconv_bin_file ); + free( fastconv_hrtf ); + free( full_in_fastconv_path ); + *hrtf_size = -1; + return NULL; } - } - else if ( rend_type == RENDERER_BINAURAL_FASTCONV && input_cfg == BINAURAL_INPUT_AUDIO_CONFIG_HOA2 ) - { - memcpy( hrtf_wptr, &( latency_s ), sizeof( float ) ); // latency_s => float - hrtf_wptr += sizeof( float ); - - memcpy( hrtf_wptr, &( hrtf_channels ), sizeof( uint16_t ) ); // hrtf_channels => uint16_t - hrtf_wptr += sizeof( uint16_t ); - - memcpy( hrtf_wptr, &( num_taps ), sizeof( uint16_t ) ); // num_taps => uint16_t - hrtf_wptr += sizeof( uint16_t ); - data_size_tmp = num_taps * sizeof( float ); - for ( i = 0; i < BINAURAL_CONVBANDS; i++ ) + for ( ind = 0; ind < nbHrft; ind++ ) { - for ( j = 0; j < hrtf_channels; j++ ) + if ( fread( &hrtf_header, sizeof( ivas_hrtfs_header_t ), 1, input_fastconv_bin_file ) != 1 ) { - memcpy( hrtf_wptr, &leftHRIRReal_HOA2[i][j], data_size_tmp ); - hrtf_wptr += data_size_tmp; + fprintf( stderr, "Reading of the fastconv hrtf failed!\n\n" ); + fclose( input_fastconv_bin_file ); + free( fastconv_hrtf ); + free( full_in_fastconv_path ); + *hrtf_size = -1; + return NULL; } - } - for ( i = 0; i < BINAURAL_CONVBANDS; i++ ) - { - for ( j = 0; j < hrtf_channels; j++ ) + if ( ( hrtf_header.rend_type == rend_type ) && ( hrtf_header.input_cfg == input_cfg ) ) { - memcpy( hrtf_wptr, &leftHRIRImag_HOA2[i][j], data_size_tmp ); - hrtf_wptr += data_size_tmp; + fastconv_hrtf_data_size = hrtf_header.data_size; + *hrtf_size = sizeof( ivas_hrtfs_header_t ) + fastconv_hrtf_data_size; + fastconv_hrtf = (char *) malloc( *hrtf_size ); + break; } - } - for ( i = 0; i < BINAURAL_CONVBANDS; i++ ) - { - for ( j = 0; j < hrtf_channels; j++ ) + else { - memcpy( hrtf_wptr, &rightHRIRReal_HOA2[i][j], data_size_tmp ); - hrtf_wptr += data_size_tmp; + fseek( input_fastconv_bin_file, hrtf_header.data_size, SEEK_CUR ); } } - for ( i = 0; i < BINAURAL_CONVBANDS; i++ ) + + // Header [Declaration of the HRTF] + // Renderer type (4 bytes) : See "RENDERER_TYPE" + // Decoder output format (4 bytes) : See "BINAURAL_INPUT_AUDIO_CONFIG" + // Sampling Frequency (4 bytes) + // Raw data size (4 bytes) + + if ( fastconv_hrtf == NULL ) { - for ( j = 0; j < hrtf_channels; j++ ) - { - memcpy( hrtf_wptr, &rightHRIRImag_HOA2[i][j], data_size_tmp ); - hrtf_wptr += data_size_tmp; - } + fprintf( stderr, "Memory allocation for the block failed!\n\n" ); + fclose( input_fastconv_bin_file ); + free( full_in_fastconv_path ); + *hrtf_size = -1; + return NULL; } - } - // FOA - else if ( rend_type == RENDERER_BINAURAL_FASTCONV && input_cfg == BINAURAL_INPUT_AUDIO_CONFIG_FOA ) - { - memcpy( hrtf_wptr, &( latency_s ), sizeof( float ) ); // latency_s => float - hrtf_wptr += sizeof( float ); - memcpy( hrtf_wptr, &( hrtf_channels ), sizeof( uint16_t ) ); // hrtf_channels => uint16_t - hrtf_wptr += sizeof( uint16_t ); + memset( fastconv_hrtf, 0x00, *hrtf_size ); + fastconv_hrtf_wptr = fastconv_hrtf; - memcpy( hrtf_wptr, &( num_taps ), sizeof( uint16_t ) ); // num_taps => uint16_t - hrtf_wptr += sizeof( uint16_t ); + // Get the HRTF header - data_size_tmp = num_taps * sizeof( float ); - for ( i = 0; i < BINAURAL_CONVBANDS; i++ ) - { - for ( j = 0; j < hrtf_channels; j++ ) - { - memcpy( hrtf_wptr, &leftHRIRReal_FOA[i][j], data_size_tmp ); - hrtf_wptr += data_size_tmp; - } - } - for ( i = 0; i < BINAURAL_CONVBANDS; i++ ) - { - for ( j = 0; j < hrtf_channels; j++ ) - { - memcpy( hrtf_wptr, &leftHRIRImag_FOA[i][j], data_size_tmp ); - hrtf_wptr += data_size_tmp; - } - } - for ( i = 0; i < BINAURAL_CONVBANDS; i++ ) - { - for ( j = 0; j < hrtf_channels; j++ ) - { - memcpy( hrtf_wptr, &rightHRIRReal_FOA[i][j], data_size_tmp ); - hrtf_wptr += data_size_tmp; - } - } - for ( i = 0; i < BINAURAL_CONVBANDS; i++ ) - { - for ( j = 0; j < hrtf_channels; j++ ) - { - memcpy( hrtf_wptr, &rightHRIRImag_FOA[i][j], data_size_tmp ); - hrtf_wptr += data_size_tmp; - } - } - } - // BRIR - else if ( rend_type == RENDERER_BINAURAL_FASTCONV_ROOM && input_cfg == BINAURAL_INPUT_AUDIO_CONFIG_COMBINED ) - { - memcpy( hrtf_wptr, &( latency_s ), sizeof( float ) ); // latency_s => float - hrtf_wptr += sizeof( float ); + // Renderer type + memcpy( fastconv_hrtf_wptr, &( rend_type ), sizeof( int32_t ) ); + fastconv_hrtf_wptr += sizeof( int32_t ); - memcpy( hrtf_wptr, &( hrtf_channels ), sizeof( uint16_t ) ); // hrtf_channels => uint16_t - hrtf_wptr += sizeof( uint16_t ); + // Decoder output format + memcpy( fastconv_hrtf_wptr, &( input_cfg ), sizeof( int32_t ) ); + fastconv_hrtf_wptr += sizeof( int32_t ); - memcpy( hrtf_wptr, &( num_taps ), sizeof( uint16_t ) ); // num_taps => uint16_t - hrtf_wptr += sizeof( uint16_t ); + // Sampling Frequency + *( (int32_t *) ( fastconv_hrtf_wptr ) ) = 48000; + fastconv_hrtf_wptr += sizeof( int32_t ); - data_size_tmp = num_taps * sizeof( float ); - for ( i = 0; i < BINAURAL_CONVBANDS; i++ ) - { - for ( j = 0; j < hrtf_channels; j++ ) - { - memcpy( hrtf_wptr, leftBRIRReal[i][j], data_size_tmp ); - hrtf_wptr += data_size_tmp; - } - } - for ( i = 0; i < BINAURAL_CONVBANDS; i++ ) - { - for ( j = 0; j < hrtf_channels; j++ ) - { - memcpy( hrtf_wptr, &leftBRIRImag[i][j], data_size_tmp ); - hrtf_wptr += data_size_tmp; - } - } - for ( i = 0; i < BINAURAL_CONVBANDS; i++ ) - { - for ( j = 0; j < hrtf_channels; j++ ) - { - memcpy( hrtf_wptr, &rightBRIRReal[i][j], data_size_tmp ); - hrtf_wptr += data_size_tmp; - } - } - for ( i = 0; i < BINAURAL_CONVBANDS; i++ ) + // Raw data size + memcpy( fastconv_hrtf_wptr, &( fastconv_hrtf_data_size ), sizeof( uint32_t ) ); + fastconv_hrtf_wptr += sizeof( uint32_t ); + + // Get the HRTF raw data + + if ( fread( fastconv_hrtf_wptr, fastconv_hrtf_data_size, 1, input_fastconv_bin_file ) != 1 ) { - for ( j = 0; j < hrtf_channels; j++ ) - { - memcpy( hrtf_wptr, &rightBRIRImag[i][j], data_size_tmp ); - hrtf_wptr += data_size_tmp; - } + fprintf( stderr, "Reading of the fastconv hrtf failed!\n\n" ); + fclose( input_fastconv_bin_file ); + free( fastconv_hrtf ); + free( full_in_fastconv_path ); + *hrtf_size = -1; + return NULL; } - // Reverb Parameters - memcpy( hrtf_wptr, &( cldfb_nchan_max ), sizeof( uint16_t ) ); // cldfb_ncol => int16_t - hrtf_wptr += sizeof( uint16_t ); - - data_size_tmp = cldfb_nchan_max * sizeof( float ); - memcpy( hrtf_wptr, &( fastconvReverberationTimes ), data_size_tmp ); // fastconvReverberationTimes - memcpy( hrtf_wptr, &( fastconvReverberationEneCorrections ), data_size_tmp ); // fastconvEneCorrections + fclose( input_fastconv_bin_file ); + input_fastconv_bin_file = NULL; + } + else + { + fprintf( stderr, "Opening of file %s failed!\n\n", full_in_fastconv_path ); + *hrtf_size = -1; + free( full_in_fastconv_path ); + return NULL; } - return hrtf; + return fastconv_hrtf; } /*---------------------------------------------------------------------* @@ -1210,11 +1096,34 @@ char *create_hrtf_fastconv( RENDERER_TYPE rend_type, BINAURAL_INPUT_AUDIO_CONFIG *---------------------------------------------------------------------*/ char *create_hrtf_parametric( int32_t *hrtf_size ) { - char *hrtf = NULL, *hrtf_wptr; + char *hrtf = NULL, *hrtf_wptr, *full_in_param_bin_path = NULL; uint32_t hrtf_data_size; uint32_t data_size_tmp; int16_t i, j; + uint8_t file_read_ok; + + float hrtfShCoeffsReFile[BINAURAL_CHANNELS][HRTF_SH_CHANNELS][HRTF_NUM_BINS]; + float hrtfShCoeffsImFile[BINAURAL_CHANNELS][HRTF_SH_CHANNELS][HRTF_NUM_BINS]; + + float parametricReverberationTimesFile[CLDFB_NO_CHANNELS_MAX]; + float parametricReverberationEneCorrectionsFile[CLDFB_NO_CHANNELS_MAX]; + float parametricEarlyPartEneCorrectionFile[CLDFB_NO_CHANNELS_MAX]; + + FILE *input_param_bin_file = NULL; + + full_in_param_bin_path = (char *) malloc( sizeof( char ) * ( strlen( input_param_bin_path ) + strlen( input_param_bin_file_name ) + 2 ) ); + if ( full_in_param_bin_path == NULL ) + { + fprintf( stderr, "Memory issue for full input parambin path!\n\n" ); + rom2bin_terminat(); + return NULL; + } +#ifdef _WIN32 + sprintf( full_in_param_bin_path, "%s\\%s", input_param_bin_path, input_param_bin_file_name ); +#else + sprintf( full_in_param_bin_path, "%s/%s", input_param_bin_path, input_param_bin_file_name ); +#endif hrtf_data_size = 0; @@ -1227,29 +1136,88 @@ char *create_hrtf_parametric( int32_t *hrtf_size ) hrtfShCoeffsIm => float[BINAURAL_CHANNELS][HRTF_SH_CHANNELS][HRTF_NUM_BINS]; BRIR-based reverb + CLDFB_NO_CHANNELS_MAX => uint16_t + parametricReverberationTimes => float[CLDFB_NO_CHANNELS_MAX]; + parametricReverberationEneCorrections => float[CLDFB_NO_CHANNELS_MAX]; + parametricEarlyPartEneCorrection => float[CLDFB_NO_CHANNELS_MAX]; + */ + + // Compute total size of data to write + // CLDFB SH domain HRTF-data + hrtf_data_size += sizeof( uint16_t ); // HRTF_SH_CHANNELS + hrtf_data_size += sizeof( uint16_t ); // HRTF_NUM_BINS + hrtf_data_size += 2 * ( BINAURAL_CHANNELS * HRTF_SH_CHANNELS * HRTF_NUM_BINS * sizeof( float ) ); // HRTF + + // Always write also BRIR reverb data + hrtf_data_size += sizeof( uint16_t ); // CLDFB_NO_CHANNELS_MAX + hrtf_data_size += CLDFB_NO_CHANNELS_MAX * sizeof( float ); // parametricReverberationTimes + hrtf_data_size += CLDFB_NO_CHANNELS_MAX * sizeof( float ); // parametricReverberationEneCorrections + hrtf_data_size += CLDFB_NO_CHANNELS_MAX * sizeof( float ); // parametricEarlyPartEneCorrection + + file_read_ok = 0; + input_param_bin_file = fopen( full_in_param_bin_path, "rb" ); + if ( input_param_bin_file != NULL ) + { + uint16_t hrtf_sh_channels, hrtf_num_bins, cldfb_no_channels_max; + + fseek( input_param_bin_file, 0, SEEK_END ); + data_size_tmp = ftell( input_param_bin_file ); + fseek( input_param_bin_file, 0, SEEK_SET ); + + if ( data_size_tmp != hrtf_data_size ) + { + fprintf( stderr, "Inconsistent binary data file size (expected: %d, found %d). Using built-in default values.\n\n", hrtf_data_size, data_size_tmp ); + } + else + { + fread( &hrtf_sh_channels, sizeof( uint16_t ), 1, input_param_bin_file ); + fread( &hrtf_num_bins, sizeof( uint16_t ), 1, input_param_bin_file ); + if ( hrtf_sh_channels != HRTF_SH_CHANNELS ) + { + fprintf( stderr, "Warning: Inconsistent HRTF_SH_CHANNELS (expected: %d, found: %d).\n\n", HRTF_SH_CHANNELS, hrtf_sh_channels ); + } + if ( hrtf_num_bins != HRTF_NUM_BINS ) + { + fprintf( stderr, "Warning: Inconsistent HRTF_NUM_BINS (expected: %d, found: %d).\n\n", HRTF_NUM_BINS, hrtf_num_bins ); + } + + for ( size_t bin_chnl = 0; bin_chnl < BINAURAL_CHANNELS; bin_chnl++ ) + { + for ( size_t hrtf_chnl = 0; hrtf_chnl < HRTF_SH_CHANNELS; hrtf_chnl++ ) + { + fread( hrtfShCoeffsReFile[bin_chnl][hrtf_chnl], sizeof( float ), HRTF_NUM_BINS, input_param_bin_file ); + } + } + for ( size_t bin_chnl = 0; bin_chnl < BINAURAL_CHANNELS; bin_chnl++ ) + { + for ( size_t hrtf_chnl = 0; hrtf_chnl < HRTF_SH_CHANNELS; hrtf_chnl++ ) + { + fread( hrtfShCoeffsImFile[bin_chnl][hrtf_chnl], sizeof( float ), HRTF_NUM_BINS, input_param_bin_file ); + } + } - CLDFB_NO_CHANNELS_MAX => uint16_t - parametricReverberationTimes => float[CLDFB_NO_CHANNELS_MAX]; - parametricReverberationEneCorrections => float[CLDFB_NO_CHANNELS_MAX]; - parametricEarlyPartEneCorrection => float[CLDFB_NO_CHANNELS_MAX]; -*/ + /* reverb */ + fread( &cldfb_no_channels_max, sizeof( uint16_t ), 1, input_param_bin_file ); + if ( cldfb_no_channels_max != CLDFB_NO_CHANNELS_MAX ) + { + fprintf( stderr, "Warning: Inconsistent CLDFB_NO_CHANNELS_MAX (expected: %d, found: %d).\n\n", CLDFB_NO_CHANNELS_MAX, cldfb_no_channels_max ); + } - // Compute total size of data to write - // CLDFB SH domain HRTF-data - hrtf_data_size += sizeof( uint16_t ); // HRTF_SH_CHANNELS - hrtf_data_size += sizeof( uint16_t ); // HRTF_NUM_BINS - hrtf_data_size += 2 * ( BINAURAL_CHANNELS * HRTF_SH_CHANNELS * HRTF_NUM_BINS * sizeof( float ) ); // HRTF + fread( parametricReverberationTimesFile, sizeof( float ), CLDFB_NO_CHANNELS_MAX, input_param_bin_file ); + fread( parametricReverberationEneCorrectionsFile, sizeof( float ), CLDFB_NO_CHANNELS_MAX, input_param_bin_file ); + fread( parametricEarlyPartEneCorrectionFile, sizeof( float ), CLDFB_NO_CHANNELS_MAX, input_param_bin_file ); - // Always write also BRIR reverb data - hrtf_data_size += sizeof( uint16_t ); // CLDFB_NO_CHANNELS_MAX - hrtf_data_size += CLDFB_NO_CHANNELS_MAX * sizeof( float ); // parametricReverberationTimes - hrtf_data_size += CLDFB_NO_CHANNELS_MAX * sizeof( float ); // parametricReverberationEneCorrections - hrtf_data_size += CLDFB_NO_CHANNELS_MAX * sizeof( float ); // parametricEarlyPartEneCorrection + file_read_ok = 1; + } + } + else + { + fprintf( stderr, "Opening of parambin file %s failed. Using built-in default values.\n\n", full_in_param_bin_path ); + } // Allocate memory *hrtf_size = sizeof( ivas_hrtfs_header_t ) + hrtf_data_size; hrtf = (char *) malloc( *hrtf_size ); - if ( hrtf == NULL ) { fprintf( stderr, "Memory allocation for the block failed!\n\n" ); @@ -1257,6 +1225,7 @@ char *create_hrtf_parametric( int32_t *hrtf_size ) return NULL; } + // Write // Header [Declaration of the HRTF] @@ -1292,14 +1261,20 @@ char *create_hrtf_parametric( int32_t *hrtf_size ) *( (uint16_t *) ( hrtf_wptr ) ) = HRTF_NUM_BINS; hrtf_wptr += sizeof( uint16_t ); - // HRTF data_size_tmp = HRTF_NUM_BINS * sizeof( float ); for ( i = 0; i < BINAURAL_CHANNELS; i++ ) { for ( j = 0; j < HRTF_SH_CHANNELS; j++ ) { - memcpy( hrtf_wptr, &hrtfShCoeffsRe[i][j], data_size_tmp ); + if ( file_read_ok ) + { + memcpy( hrtf_wptr, &hrtfShCoeffsReFile[i][j], data_size_tmp ); + } + else + { + memcpy( hrtf_wptr, &hrtfShCoeffsRe[i][j], data_size_tmp ); + } hrtf_wptr += data_size_tmp; } } @@ -1307,7 +1282,14 @@ char *create_hrtf_parametric( int32_t *hrtf_size ) { for ( j = 0; j < HRTF_SH_CHANNELS; j++ ) { - memcpy( hrtf_wptr, &hrtfShCoeffsIm[i][j], data_size_tmp ); + if ( file_read_ok ) + { + memcpy( hrtf_wptr, &hrtfShCoeffsImFile[i][j], data_size_tmp ); + } + else + { + memcpy( hrtf_wptr, &hrtfShCoeffsIm[i][j], data_size_tmp ); + } hrtf_wptr += data_size_tmp; } } @@ -1317,13 +1299,24 @@ char *create_hrtf_parametric( int32_t *hrtf_size ) hrtf_wptr += sizeof( uint16_t ); data_size_tmp = CLDFB_NO_CHANNELS_MAX * sizeof( float ); - memcpy( hrtf_wptr, &( parametricReverberationTimes ), data_size_tmp ); // parametricReverberationTimes - hrtf_wptr += data_size_tmp; - memcpy( hrtf_wptr, &( parametricReverberationEneCorrections ), data_size_tmp ); // parametricReverberationEneCorrections - hrtf_wptr += data_size_tmp; - memcpy( hrtf_wptr, &( parametricEarlyPartEneCorrection ), data_size_tmp ); // parametricEarlyPartEneCorrection - hrtf_wptr += data_size_tmp; - + if ( file_read_ok ) + { + memcpy( hrtf_wptr, &( parametricReverberationTimesFile ), data_size_tmp ); // parametricReverberationTimes + hrtf_wptr += data_size_tmp; + memcpy( hrtf_wptr, &( parametricReverberationEneCorrectionsFile ), data_size_tmp ); // parametricReverberationEneCorrections + hrtf_wptr += data_size_tmp; + memcpy( hrtf_wptr, &( parametricEarlyPartEneCorrectionFile ), data_size_tmp ); // parametricEarlyPartEneCorrection + hrtf_wptr += data_size_tmp; + } + else + { + memcpy( hrtf_wptr, &( parametricReverberationTimes ), data_size_tmp ); // parametricReverberationTimes + hrtf_wptr += data_size_tmp; + memcpy( hrtf_wptr, &( parametricReverberationEneCorrections ), data_size_tmp ); // parametricReverberationEneCorrections + hrtf_wptr += data_size_tmp; + memcpy( hrtf_wptr, &( parametricEarlyPartEneCorrection ), data_size_tmp ); // parametricEarlyPartEneCorrection + hrtf_wptr += data_size_tmp; + } return hrtf; } @@ -1776,8 +1769,7 @@ int32_t compute_crend_hrtf_data_size( crend_hrtf_tables_pointers *hrtf_table_ptr hrtf_data_size += sizeof( uint16_t ); // index_frequency_max_diffuse hrtf_data_size += hrtf_table_dims->max_num_ir * sizeof( float ); // inv_diffuse_weight - - hrtf_data_size += sizeof( uint16_t ); // max_total_num_fsamp_per_iteration + hrtf_data_size += sizeof( uint16_t ); // max_total_num_fsamp_per_iteration // coeff_re & coeff_im : The size depends on pIndex_frequency_max for ( iIR = 0, iIndex = 0; iIR < hrtf_table_dims->max_num_ir; iIR++ ) { @@ -1819,7 +1811,7 @@ int16_t check_bin_file( FILE *hrtf_bin_file ) uint32_t hrtf_data_size_max; int16_t nbHRTF; #endif - char *file_header, *hrtf_data, *hrtf_data_rptr; + char *file_header; ivas_hrtfs_header_t hrtf_header; int16_t result; @@ -1907,38 +1899,8 @@ int16_t check_bin_file( FILE *hrtf_bin_file ) while ( fread( &hrtf_header, sizeof( ivas_hrtfs_header_t ), 1, hrtf_bin_file ) == 1 ) { #endif - hrtf_data = (char *) malloc( hrtf_header.data_size ); - if ( hrtf_data == NULL ) - { - fprintf( stderr, "Memory allocation for the hrtf failed!\n\n" ); - if ( file_header != NULL ) - free( file_header ); - return -1; - } - - if ( fread( hrtf_data, hrtf_header.data_size, 1, hrtf_bin_file ) == 1 ) - { - hrtf_data_rptr = hrtf_data; - if ( check_hrtf_data( hrtf_header.rend_type, hrtf_header.input_cfg, hrtf_header.frequency, hrtf_data_rptr, hrtf_header.data_size ) != 0 ) - { - fprintf( stderr, "HRTF data corrupted!\n\n" ); - if ( file_header != NULL ) - free( file_header ); - free( hrtf_data ); - return -1; - } - free( hrtf_data ); - } - else - { - fprintf( stderr, "Access to HRTF data failed!\n\n" ); - if ( file_header != NULL ) - free( file_header ); - free( hrtf_data ); - return -1; - } + fseek( hrtf_bin_file, hrtf_header.data_size, SEEK_CUR ); } - if ( file_header != NULL ) free( file_header ); } @@ -1972,6 +1934,7 @@ int16_t check_hrtf_data( RENDERER_TYPE rend_type, BINAURAL_INPUT_AUDIO_CONFIG in return 0; } + memset( &tabs_dims, 0x00, sizeof( crend_hrtf_tables_dimensions ) ); memset( &tabs_ptrs, 0x00, sizeof( crend_hrtf_tables_pointers ) ); @@ -1992,7 +1955,6 @@ int16_t check_hrtf_data( RENDERER_TYPE rend_type, BINAURAL_INPUT_AUDIO_CONFIG in } hrtf_data_size = compute_crend_hrtf_data_size( &tabs_ptrs, &tabs_dims ); - if ( hrtf_data_size != hrtf_size_in ) { fprintf( stderr, "check_hrtf_data of binary file failed: bad hrtf_data_size!\n\n" ); @@ -2004,7 +1966,7 @@ int16_t check_hrtf_data( RENDERER_TYPE rend_type, BINAURAL_INPUT_AUDIO_CONFIG in hrtf_data_in_rptr = hrtf_data_in; // latency_s - if ( *( tabs_ptrs.latency_s ) != *( (float *) ( hrtf_data_in_rptr ) ) ) + if ( ( *( tabs_ptrs.latency_s ) - *( (float *) ( hrtf_data_in_rptr ) ) ) > 1e-9f ) { fprintf( stderr, "check_hrtf_data of binary file failed: bad latency_s!\n\n" ); return -1; @@ -2100,6 +2062,14 @@ int16_t check_hrtf_data( RENDERER_TYPE rend_type, BINAURAL_INPUT_AUDIO_CONFIG in fprintf( stderr, "check_hrtf_data of binary file failed: bad inv_diffuse_weight!\n\n" ); return -1; } + /*for ( iCtrl = 0; iCtrl < tabs_dims.max_num_ir; iCtrl++) + { + if ( fabs( tabs_ptrs.inv_diffuse_weight[iCtrl] - ((float*)hrtf_data_in_rptr)[iCtrl] ) > 0.000001 ) + { + fprintf( stderr, "check_hrtf_data of binary file failed: bad inv_diffuse_weight!\n\n" ); + return -1; + } + }*/ hrtf_data_in_rptr += ctrl_size; // max_total_num_fsamp_per_iteration @@ -2124,6 +2094,14 @@ int16_t check_hrtf_data( RENDERER_TYPE rend_type, BINAURAL_INPUT_AUDIO_CONFIG in fprintf( stderr, "check_hrtf_data of binary file failed: bad coeff_re!\n\n" ); return -1; } + /*for ( iCtrl = 0; iCtrl < tabs_ptrs.pIndex_frequency_max[iIndex]; iCtrl++) + { + if ( fabs( coeff_rptr[iCtrl] - ((float*)hrtf_data_in_rptr)[iCtrl] ) > 0.000001 ) + { + fprintf( stderr, "check_hrtf_data of binary file failed: bad coeff_re!\n\n" ); + return -1; + } + }*/ hrtf_data_in_rptr += ctrl_size; coeff_rptr += tabs_ptrs.pIndex_frequency_max[iIndex++]; } @@ -2145,6 +2123,14 @@ int16_t check_hrtf_data( RENDERER_TYPE rend_type, BINAURAL_INPUT_AUDIO_CONFIG in fprintf( stderr, "check_hrtf_data of binary file failed: bad coeff_re!\n\n" ); return -1; } + /*for ( iCtrl = 0; iCtrl < tabs_ptrs.pIndex_frequency_max[iIndex]; iCtrl++) + { + if ( fabs( coeff_rptr[iCtrl] - ((float*)hrtf_data_in_rptr)[iCtrl] ) > 0.000001 ) + { + fprintf( stderr, "check_hrtf_data of binary file failed: bad coeff_im!\n\n" ); + return -1; + } + }*/ hrtf_data_in_rptr += ctrl_size; coeff_rptr += tabs_ptrs.pIndex_frequency_max[iIndex++]; } @@ -2173,6 +2159,14 @@ int16_t check_hrtf_data( RENDERER_TYPE rend_type, BINAURAL_INPUT_AUDIO_CONFIG in fprintf( stderr, "check_hrtf_data of binary file failed: bad coeff_diffuse_re!\n\n" ); return -1; } + /*for ( iCtrl = 0; iCtrl < tabs_ptrs.pIndex_frequency_max_diffuse[iIndex]; iCtrl++) + { + if ( fabs( coeff_rptr[iCtrl] - ((float*)hrtf_data_in_rptr)[iCtrl] ) > 0.000001 ) + { + fprintf( stderr, "check_hrtf_data of binary file failed: bad coeff_diffuse_re!\n\n" ); + return -1; + } + }*/ hrtf_data_in_rptr += ctrl_size; coeff_rptr += tabs_ptrs.pIndex_frequency_max_diffuse[iIndex++]; } @@ -2211,13 +2205,14 @@ int32_t read_hrtf_size( char *hrtf ) if ( hrtf != NULL ) { + // Get the raw data size hrtf_rptr += sizeof( int32_t ); // RENDERER_TYPE hrtf_rptr += sizeof( int32_t ); // BINAURAL_INPUT_AUDIO_CONFIG - hrtf_rptr += sizeof( int32_t ); - + hrtf_rptr += sizeof( int32_t ); // Sampling Frequency memcpy( &( hrtf_size ), hrtf_rptr, sizeof( uint32_t ) ); - hrtf_size += sizeof( int32_t ) + sizeof( int32_t ) + sizeof( int32_t ) + sizeof( int32_t ); // + hrtf header size - // hrtf_rptr += sizeof(uint32_t); + + // Add the hrtf header's size + hrtf_size += sizeof( ivas_hrtfs_header_t ); } return hrtf_size; @@ -2232,7 +2227,6 @@ int rom2bin_init( int argc, char *argv[] ) { int i; - int32_t selected_frequency = 0; if ( ( argc ) == 1 ) { @@ -2255,8 +2249,20 @@ int rom2bin_init( int argc, char *argv[] ) usage_tables_format_converter(); return -1; } + convert_backslash( argv[i] ); output_path = malloc( strlen( argv[i] ) + 1 ); strcpy( output_path, argv[i] ); +#ifdef _WIN32 + if ( output_path[strlen( output_path ) - 1] == '\\' ) + { + output_path[strlen( output_path ) - 1] = '\0'; + } +#else + if ( output_path[strlen( output_path ) - 1] == '/' ) + { + output_path[strlen( output_path ) - 1] = '\0'; + } +#endif i++; } else if ( strcmp( to_upper( argv[i] ), "-OUTPUT_FILE_NAME" ) == 0 ) @@ -2315,8 +2321,120 @@ int rom2bin_init( int argc, char *argv[] ) usage_tables_format_converter(); return -1; } + convert_backslash( argv[i] ); input_td_bin_path = malloc( strlen( argv[i] ) + 1 ); strcpy( input_td_bin_path, argv[i] ); +#ifdef _WIN32 + if ( input_td_bin_path[strlen( input_td_bin_path ) - 1] == '\\' ) + { + input_td_bin_path[strlen( input_td_bin_path ) - 1] = '\0'; + } +#else + if ( input_td_bin_path[strlen( input_td_bin_path ) - 1] == '/' ) + { + input_td_bin_path[strlen( input_td_bin_path ) - 1] = '\0'; + } +#endif + i++; + } + else if ( strcmp( to_upper( argv[i] ), "-INPUT_MIXERCONV_HRIR_FILE_PATH" ) == 0 ) + { + i++; + if ( strlen( argv[i] ) == 0 ) + { + fprintf( stderr, "Wrong input mixer_conv hrir file path: %s\n\n", argv[i] ); + usage_tables_format_converter(); + return -1; + } + convert_backslash( argv[i] ); + input_mixerconv_bin_hrir_path = malloc( strlen( argv[i] ) + 1 ); + strcpy( input_mixerconv_bin_hrir_path, argv[i] ); +#ifdef _WIN32 + if ( input_mixerconv_bin_hrir_path[strlen( input_mixerconv_bin_hrir_path ) - 1] == '\\' ) + { + input_mixerconv_bin_hrir_path[strlen( input_mixerconv_bin_hrir_path ) - 1] = '\0'; + } +#else + if ( input_mixerconv_bin_hrir_path[strlen( input_mixerconv_bin_hrir_path ) - 1] == '/' ) + { + input_mixerconv_bin_hrir_path[strlen( input_mixerconv_bin_hrir_path ) - 1] = '\0'; + } +#endif + i++; + } + else if ( strcmp( to_upper( argv[i] ), "-INPUT_MIXERCONV_BRIR_FILE_PATH" ) == 0 ) + { + i++; + if ( strlen( argv[i] ) == 0 ) + { + fprintf( stderr, "Wrong input mixer_conv brir file path: %s\n\n", argv[i] ); + usage_tables_format_converter(); + return -1; + } + convert_backslash( argv[i] ); + input_mixerconv_bin_brir_path = malloc( strlen( argv[i] ) + 1 ); + strcpy( input_mixerconv_bin_brir_path, argv[i] ); +#ifdef _WIN32 + if ( input_mixerconv_bin_brir_path[strlen( input_mixerconv_bin_brir_path ) - 1] == '\\' ) + { + input_mixerconv_bin_brir_path[strlen( input_mixerconv_bin_brir_path ) - 1] = '\0'; + } +#else + if ( input_mixerconv_bin_brir_path[strlen( input_mixerconv_bin_brir_path ) - 1] == '/' ) + { + input_mixerconv_bin_brir_path[strlen( input_mixerconv_bin_brir_path ) - 1] = '\0'; + } +#endif + i++; + } + else if ( strcmp( to_upper( argv[i] ), "-INPUT_FASTCONV_FILE_PATH" ) == 0 ) + { + i++; + if ( strlen( argv[i] ) == 0 ) + { + fprintf( stderr, "Wrong input fastconv file path: %s\n\n", argv[i] ); + usage_tables_format_converter(); + return -1; + } + convert_backslash( argv[i] ); + input_fastconv_bin_path = malloc( strlen( argv[i] ) + 1 ); + strcpy( input_fastconv_bin_path, argv[i] ); +#ifdef _WIN32 + if ( input_fastconv_bin_path[strlen( input_fastconv_bin_path ) - 1] == '\\' ) + { + input_fastconv_bin_path[strlen( input_fastconv_bin_path ) - 1] = '\0'; + } +#else + if ( input_fastconv_bin_path[strlen( input_fastconv_bin_path ) - 1] == '/' ) + { + input_fastconv_bin_path[strlen( input_fastconv_bin_path ) - 1] = '\0'; + } +#endif + i++; + } + else if ( strcmp( to_upper( argv[i] ), "-INPUT_PARAM_FILE_PATH" ) == 0 ) + { + i++; + if ( strlen( argv[i] ) == 0 ) + { + fprintf( stderr, "Wrong input td file path: %s\n\n", argv[i] ); + usage_tables_format_converter(); + return -1; + } + convert_backslash( argv[i] ); + input_param_bin_path = malloc( strlen( argv[i] ) + 1 ); + strcpy( input_param_bin_path, argv[i] ); +#ifdef _WIN32 + if ( input_param_bin_path[strlen( input_param_bin_path ) - 1] == '\\' ) + { + input_param_bin_path[strlen( input_param_bin_path ) - 1] = '\0'; + } +#else + if ( input_param_bin_path[strlen( input_param_bin_path ) - 1] == '/' ) + { + input_param_bin_path[strlen( input_param_bin_path ) - 1] = '\0'; + } +#endif i++; } else if ( strcmp( to_upper( argv[i] ), "-INPUT_TD_FILE_NAME" ) == 0 ) @@ -2332,6 +2450,58 @@ int rom2bin_init( int argc, char *argv[] ) strcpy( input_td_bin_file_name, argv[i] ); i++; } + else if ( strcmp( to_upper( argv[i] ), "-INPUT_MIXERCONV_HRIR_FILE_NAME" ) == 0 ) + { + i++; + if ( strlen( argv[i] ) == 0 ) + { + fprintf( stderr, "Wrong input mixconf hrir file name: %s\n\n", argv[i] ); + usage_tables_format_converter(); + return -1; + } + input_mixerconv_bin_hrir_file_name = malloc( strlen( argv[i] ) + 1 ); + strcpy( input_mixerconv_bin_hrir_file_name, argv[i] ); + i++; + } + else if ( strcmp( to_upper( argv[i] ), "-INPUT_MIXERCONV_BRIR_FILE_NAME" ) == 0 ) + { + i++; + if ( strlen( argv[i] ) == 0 ) + { + fprintf( stderr, "Wrong input mixconf brir file name: %s\n\n", argv[i] ); + usage_tables_format_converter(); + return -1; + } + input_mixerconv_bin_brir_file_name = malloc( strlen( argv[i] ) + 1 ); + strcpy( input_mixerconv_bin_brir_file_name, argv[i] ); + i++; + } + else if ( strcmp( to_upper( argv[i] ), "-INPUT_FASTCONV_FILE_NAME" ) == 0 ) + { + i++; + if ( strlen( argv[i] ) == 0 ) + { + fprintf( stderr, "Wrong input fastconv file name: %s\n\n", argv[i] ); + usage_tables_format_converter(); + return -1; + } + input_fastconv_bin_file_name = malloc( strlen( argv[i] ) + 1 ); + strcpy( input_fastconv_bin_file_name, argv[i] ); + i++; + } + else if ( strcmp( to_upper( argv[i] ), "-INPUT_PARAM_FILE_NAME" ) == 0 ) + { + i++; + if ( strlen( argv[i] ) == 0 ) + { + fprintf( stderr, "Wrong input parambin file name: %s\n\n", argv[i] ); + usage_tables_format_converter(); + return -1; + } + input_param_bin_file_name = malloc( strlen( argv[i] ) + 1 ); + strcpy( input_param_bin_file_name, argv[i] ); + i++; + } else { fprintf( stderr, "Unknown option: %s\n\n", argv[i] ); @@ -2370,64 +2540,6 @@ int rom2bin_init( int argc, char *argv[] ) } } - if ( selected_frequency == 0 ) - { - - full_out_path = (char *) malloc( sizeof( char ) * ( strlen( output_path ) + strlen( output_file_name ) + strlen( DEFAULT_BIN_FILE_EXT ) + 1 ) ); - sprintf( full_out_path, "%s%s%s", output_path, output_file_name, DEFAULT_BIN_FILE_EXT ); - } - else - { - - nb_freq = 1; - for ( i = 0; i < IVAS_NB_SAMPLERATE; i++ ) - { - if ( sample_rates[i] == selected_frequency ) - { - freq_ptr = &( sample_rates[i] ); - } - } - - full_out_path = (char *) malloc( sizeof( char ) * ( strlen( output_path ) + strlen( output_file_name ) + 6 + strlen( DEFAULT_BIN_FILE_EXT ) + 1 ) ); - if ( full_out_path ) - { - sprintf( full_out_path, "%s%s_%dkHz%s", output_path, output_file_name, selected_frequency / 1000, DEFAULT_BIN_FILE_EXT ); - } - else - { - fprintf( stderr, "Memory issue for full output path!\n\n" ); - rom2bin_terminat(); - return -1; - } - } - - if ( input_td_bin_path != NULL ) - { - - if ( input_td_bin_file_name == NULL ) - { - input_td_bin_file_name = (char *) malloc( sizeof( char ) * ( strlen( DEFAULT_INPUT_TD_BIN_FILE ) + 1 ) ); - if ( input_td_bin_file_name ) - { - strcpy( input_td_bin_file_name, DEFAULT_INPUT_TD_BIN_FILE ); - } - else - { - fprintf( stderr, "Memory issue for input td bin file name!\n\n" ); - rom2bin_terminat(); - return -1; - } - } - - full_in_td_path = (char *) malloc( sizeof( char ) * ( strlen( input_td_bin_path ) + strlen( input_td_bin_file_name ) + 6 + strlen( DEFAULT_BIN_FILE_EXT ) + 1 ) ); - if ( full_in_td_path == NULL ) - { - fprintf( stderr, "Memory issue for full input td path!\n\n" ); - rom2bin_terminat(); - return -1; - } - } - return 0; } @@ -2463,33 +2575,41 @@ void rom2bin_terminat( void ) free( input_td_bin_file_name ); } - if ( full_in_td_path != NULL ) + if ( input_fastconv_bin_path != NULL ) { - free( full_in_td_path ); + free( input_fastconv_bin_path ); + } + if ( input_fastconv_bin_file_name != NULL ) + { + free( input_fastconv_bin_file_name ); } -} -/*---------------------------------------------------------------------* - * to_upper() - * - * Capitalize all letters of a string. - * (normally to_upper() function would be used but it does not work in Unix) - *---------------------------------------------------------------------*/ -char *to_upper( - char *str ) -{ - int16_t i; - char *p = str; + if ( input_param_bin_path != NULL ) + { + free( input_param_bin_path ); + } + if ( input_param_bin_file_name != NULL ) + { + free( input_param_bin_file_name ); + } - i = 0; - while ( str[i] != 0 ) + if ( input_mixerconv_bin_hrir_path != NULL ) { - if ( str[i] >= 'a' && str[i] <= 'z' ) - { - str[i] -= 0x20; - } - i++; + free( input_mixerconv_bin_hrir_path ); } - return p; + if ( input_mixerconv_bin_brir_path != NULL ) + { + free( input_mixerconv_bin_brir_path ); + } + + if ( input_mixerconv_bin_hrir_file_name != NULL ) + { + free( input_mixerconv_bin_hrir_file_name ); + } + + if ( input_mixerconv_bin_brir_file_name != NULL ) + { + free( input_mixerconv_bin_brir_file_name ); + } } diff --git a/scripts/binauralRenderer_interface/Table_Format_Converter/tables_format_converter_readme.txt b/scripts/binauralRenderer_interface/Table_Format_Converter/tables_format_converter_readme.txt index 20aba7a237ac77f5a00fbc4941b31506c335ee9e..5bd00d909db209537ad0afb9def35ab4602f9622 100644 --- a/scripts/binauralRenderer_interface/Table_Format_Converter/tables_format_converter_readme.txt +++ b/scripts/binauralRenderer_interface/Table_Format_Converter/tables_format_converter_readme.txt @@ -34,12 +34,15 @@ Table Format Converter program ------------------------------ The table format converter is used to generate the file containing the binary representation of the binaural -filters for renderers (dynamic loading of generated file using –hrtf argument). -This tool is able : - - to generate binary file for MIXER_CONV, MIXER_CONV_ROOM (tables conversion from ROM); - - to aggregate the binary HR filter of OBJECTS_TD (to be done : FASTCONV and PARAMETRIC binaural) +filters for renderers (dynamic loading of generated file using –hrtf argument in IVAS decoder or renderer command). +This tool is able to aggregate the binary files generated for different IVAS renderers. -First, build the converter under scripts/binauralRenderer_interface/Table_Format_Converter/ in VSCode (using CMakeList). +First, build the converter under scripts/binauralRenderer_interface/Table_Format_Converter/ in VSCode (using CMakeList) or command line: + - mkdir build + - cd build + - cmake .. + - cmake --build . (option --config=release) + - cd .. Usage: ------ @@ -48,13 +51,24 @@ tables_format_converter [Options] Mandatory parameters : Options : --output_file_path : Path where output file will be created (with separator, default = './'). --output_file_name : Name of output file (without extension .bin, default = 'ivas_binaural'). +-output_file_path : Path where output file will be created (default = './binaural_renderers_hrtf_data'). +-output_file_name : Name of output file (without extension .bin or sample rate, default = 'ivas_binaural'). -16 : Select 16 kHz sampling frequency (no multiple values, all frequencies by default). -32 : Select 32 kHz sampling frequency (no multiple values, all frequencies by default). -48 : Select 48 kHz sampling frequency (no multiple values, all frequencies by default). --input_td_file_path : Path of binary files for time-domain renderer (with separator, used as flag). --input_td_file_name : Name of input td file (without extension .bin, default = 'hrfilter_model'). +-input_td_file_path : if exist path of binary files for time-domain renderer. +-input_td_file_name : if exist common name of input td file with extension. +-input_reverb_file_path : if exist path of binary files for reverb. +-input_reverb_file_name : if exist name of input reverb file with extension. +-input_fastconv_file_path : if exist path of binary file for fastconv renderer. +-input_fastconv_file_name : if exist name of input fastconv file with extension. +-input_param_file_path : if exist path of binary file for parametric renderer. +-input_param_file_name : if exist name of input param file with extension. +-input_mixerconv_file_hrir_path : if exist path of binary files for mixer_conv hrir renderer. +-input_mixerconv_file_hrir_name : if exist common name of input mixer_conv hrir files. +-input_mixerconv_file_brir_path : if exist path of binary files for mixer_conv brir renderer. +-input_mixerconv_file_brir_name : if exist common name of input mixer_conv brir files. For example : -tables_format_converter(.exe) -output_file_path './' -48 -input_td_file_path './../../../td_object_renderer/hrtf_data/IVAS_default/' -input_td_file_name 'hrfilter_model_v003' \ No newline at end of file + tables_format_converter(.exe) -output_file_path ../binaural_renderers_hrtf_data -output_file_name test -input_td_file_path ../binaural_renderers_hrtf_data/IVAS_default -input_td_file_name td_HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000_model_v003 -input_param_file_path ../binaural_renderers_hrtf_data -input_param_file_name parambin_HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000_IIS_BRIR_officialMPEG_Combined.bin + diff --git a/scripts/binauralRenderer_interface/brir_default_optim.cfg b/scripts/binauralRenderer_interface/brir_default_optim.cfg new file mode 100644 index 0000000000000000000000000000000000000000..58ce244b7083845ce189b26399b18c618d56914f --- /dev/null +++ b/scripts/binauralRenderer_interface/brir_default_optim.cfg @@ -0,0 +1,12 @@ +[brirOptimisationSettings] +optimize = true; +harmonizeLateReverbBinauralGain = true; +lateReverbCompensationGain = [1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0]; +directCutOffFreqThreshold = -20; +diffuseCutOffFreqThreshold = -20; +directEnergyThreshold = -25; +diffuseEnergyThreshold = -25; +beginEnergyThreshold = -50; +endEnergyThreshold = -120; +maxNumDirectBlocks = 40; +maxNumDiffuseBlocks = 40; \ No newline at end of file diff --git a/scripts/binauralRenderer_interface/brir_low_complexity_optim.cfg b/scripts/binauralRenderer_interface/brir_low_complexity_optim.cfg new file mode 100644 index 0000000000000000000000000000000000000000..4869082f51cf4d69fb1cd81bd22e2d778d598f32 --- /dev/null +++ b/scripts/binauralRenderer_interface/brir_low_complexity_optim.cfg @@ -0,0 +1,12 @@ +[brirOptimisationSettings] +optimize = true; +harmonizeLateReverbBinauralGain = false; +lateReverbCompensationGain = [1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0]; +directCutOffFreqThreshold = -15; +diffuseCutOffFreqThreshold = -10; +directEnergyThreshold = -15; +diffuseEnergyThreshold = -30; +beginEnergyThreshold = -50; +endEnergyThreshold = -120; +maxNumDirectBlocks = 40; +maxNumDiffuseBlocks = 40; \ No newline at end of file diff --git a/scripts/binauralRenderer_interface/brir_no_optim.cfg b/scripts/binauralRenderer_interface/brir_no_optim.cfg new file mode 100644 index 0000000000000000000000000000000000000000..79ad7bb13e815500342d0f7411df948ea5e20b9e --- /dev/null +++ b/scripts/binauralRenderer_interface/brir_no_optim.cfg @@ -0,0 +1,2 @@ +[brirOptimisationSettings] +optimize = false; diff --git a/scripts/binauralRenderer_interface/clearButKeepNeededVariables.m b/scripts/binauralRenderer_interface/clearButKeepNeededVariables.m new file mode 100644 index 0000000000000000000000000000000000000000..f324edabb8f163f7407bc9a9e14221af27b9a346 --- /dev/null +++ b/scripts/binauralRenderer_interface/clearButKeepNeededVariables.m @@ -0,0 +1 @@ +clear -regexp ^((?!writeRomFileOutput|writeBinaryOutput|writeEachRendererBinaryOutput|rom_file|bin_file|hrir_file|brir_file|ivas_path|binary_path|output_bin_name|param_bin_file|fastconv_bin_file|td_binary_file|binary_name|rom_path).)*$ diff --git a/scripts/binauralRenderer_interface/config_reader.c b/scripts/binauralRenderer_interface/config_reader.c new file mode 100644 index 0000000000000000000000000000000000000000..c345a9e6114f01290e3d9905094d9b9093c1691c --- /dev/null +++ b/scripts/binauralRenderer_interface/config_reader.c @@ -0,0 +1,427 @@ +/****************************************************************************************************** + + (C) 2022-2023 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 "config_reader.h" +#include +#include +#include +#include +#include +#include "cmdl_tools.h" + +/*------------------------------------------------------------------------------------------* + * PreProc Local Macros + *------------------------------------------------------------------------------------------*/ + +#define MAX_ITEM_LENGTH ( 64 ) + +/*------------------------------------------------------------------------------------------* + * Local Type definitions + *------------------------------------------------------------------------------------------*/ + + +/*------------------------------------------------------------------------------------------* + * Lookup tables + *------------------------------------------------------------------------------------------*/ + + +/*-----------------------------------------------------------------------------------------* + * Function read_txt_bool() + * Reads a boolean value from a line + *-----------------------------------------------------------------------------------------*/ +static ivas_error read_txt_bool( + const char *pLine, /* i : String to read from */ + int32_t *pTarget /* o : Output pointer */ +) +{ + char value[8 + 1]; + + if ( sscanf( pLine, "%8s", (char *) &value ) != 1 ) + { + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + + to_upper( value ); + if ( strcmp( value, "TRUE" ) == 0 ) + { + *pTarget = TRUE; + return IVAS_ERR_OK; + } + if ( strcmp( value, "FALSE" ) == 0 ) + { + *pTarget = FALSE; + return IVAS_ERR_OK; + } + return IVAS_ERR_INVALID_RENDER_CONFIG; +} + +/*-----------------------------------------------------------------------------------------* + * Function read_txt_float() + * Reads a float value from a line + *-----------------------------------------------------------------------------------------*/ +static ivas_error read_txt_float( + const char *pLine, /* i : String to read from */ + float *pTarget /* o : Output pointer */ +) +{ + float val = 0.f; + if ( sscanf( pLine, "%f", &val ) != 1 ) + { + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + + *pTarget = val; + + return IVAS_ERR_OK; +} + + +/*-----------------------------------------------------------------------------------------* + * Function read_txt_vector() + * + * Reads a vector value from a line + *-----------------------------------------------------------------------------------------*/ + +static ivas_error read_txt_vector( + char *pLine, /* i : String to read from */ + const uint32_t length, /* i : Number of expected vector elements */ + float *pTarget /* o : Output vector pointer */ +) +{ + char *tmp; + uint16_t n; + uint16_t count; + + n = (int16_t) sscanf( pLine, "[%s", pLine ); + if ( n == 0 ) + { + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + + /* Additional comma to make parsing easier */ + pLine[strlen( pLine ) - 1] = ','; + + tmp = pLine; + /* Count # of commas to determine vector length */ + for ( n = 0; tmp[n]; tmp[n] == ',' ? n++ : *tmp++ ) + ; + + count = n; + + tmp = pLine; + + /* Check for maximum vector length */ + if ( n != length ) + { + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + + for ( n = 0; n < count; n++ ) + { + if ( (int16_t) sscanf( tmp, "%f,", &pTarget[n] ) != 1 ) + { + return 1; + } + + tmp = strchr( tmp, ',' ) + 1; + } + + return IVAS_ERR_OK; +} + +/*-----------------------------------------------------------------------------------------* + * Function strip_spaces() + * + * Strips the spaces from a buffer + *-----------------------------------------------------------------------------------------*/ + +static void strip_spaces( + char *pStr /* i : String to read from */ +) +{ + int32_t read_idx = 0, write_idx = 0; + + while ( pStr[read_idx] ) + { + if ( !isspace( pStr[read_idx] ) && !iscntrl( pStr[read_idx] ) ) + { + pStr[write_idx++] = pStr[read_idx]; + } + read_idx++; + } + pStr[write_idx] = '\0'; + + return; +} + +/*-----------------------------------------------------------------------------------------* + * Function errorHandler() + * + * Prints error message and exits + *-----------------------------------------------------------------------------------------*/ + +/*! r: error accumulation */ +static int32_t errorHandler( + const char *badStr, /* i : String to complain about */ + const ERROR_CODES_t error ) +{ + static int32_t numErrors = 0; + + switch ( error ) + { + case ERROR_NONE: + break; + case ERROR_ITEM_UNKNOWN: + numErrors++; + fprintf( stderr, "Unknown variable %s in renderer configuration file.\n\n", badStr ); + break; + case ERROR_VALUE_INVALID: + numErrors++; + fprintf( stderr, "Invalid value %s in renderer configuration file.\n\n", badStr ); + break; + default: + numErrors++; + fprintf( stderr, "Unknown error while reading configuration file.\n\n" ); + } + + return numErrors; +} + +/*------------------------------------------------------------------------------------------* + * RenderConfigReader_checkValues() + * + * Verifies if the configuration parameters lie within acceptable limits + *------------------------------------------------------------------------------------------*/ + +ivas_error ConfigReader_read( + char *pConfigPath, /* i : Renderer configuration file path */ + ConfigReaderHandle hRenderConfig /* o : Renderer configuration handle */ +) +{ + int32_t file_size; + char *pConfig_str; + char *pParams; + char *pTemp; + int32_t read_idx; + int32_t params_idx; + char item[MAX_ITEM_LENGTH + 1]; + char chapter[MAX_ITEM_LENGTH + 1]; + char *pValue; + uint32_t idx; + char *pToken; + + FILE *pConfigFile; + + /* Open the configuration file */ + if ( strlen( pConfigPath ) < 1 ) + { + return IVAS_ERR_FAILED_FILE_OPEN; + } + + pConfigFile = fopen( pConfigPath, "r" ); + + if ( !pConfigFile ) + { + return IVAS_ERR_FAILED_FILE_OPEN; + } + + fseek( pConfigFile, 0, SEEK_END ); + file_size = ftell( pConfigFile ); + rewind( pConfigFile ); + pConfig_str = (char *) calloc( file_size + 1, sizeof( char ) ); + pParams = (char *) calloc( file_size + 1, sizeof( char ) ); + pTemp = (char *) calloc( file_size + 1, sizeof( char ) ); + + hRenderConfig->optimize = 0; + hRenderConfig->harmonizeLateReverbBinauralGain = 0; + for ( idx = 0; idx < MAX_INTERN_CHANNELS; idx++ ) + { + hRenderConfig->lateReverbCompensationGain[idx] = 1.f; + } + hRenderConfig->beginEnergyThreshold = DEFAULT_BEGIN_ENERGY_THRESHOLD; + hRenderConfig->endEnergyThreshold = DEFAULT_END_ENERGY_THRESHOLD; + hRenderConfig->directEnergyThreshold = DEFAULT_DIRECT_ENERGY_THRESHOLD; + hRenderConfig->diffuseEnergyThreshold = DEFAULT_DIFFUSE_ENERGY_THRESHOLD; + hRenderConfig->diffuseCutOffFreqThreshold = DEFAULT_DIFFUSE_CUT_OFF_FREQ_THRESHOLD; + hRenderConfig->directCutOffFreqThreshold = DEFAULT_DIRECT_CUT_OFF_FREQ_THRESHOLD; + /* read file line by line */ + while ( fgets( pConfig_str, file_size, pConfigFile ) != NULL ) + { + + if ( sscanf( pConfig_str, "[%64[^]]]", chapter ) == 1 ) + { + /* read line by line (except comments) until next chapter or EOF */ + pParams[0] = '\0'; + do + { + read_idx = ftell( pConfigFile ); + if ( fgets( pTemp, file_size, pConfigFile ) == NULL ) + { + break; + } + + if ( ( pTemp[0] != '#' ) && ( sscanf( pTemp, "[%64[^]]]", item ) != 1 ) ) + { + /* ignore inline comments */ + sscanf( pTemp, "%[^#]", pTemp ); + strcat( pParams, pTemp ); + } + } while ( sscanf( pTemp, "[%64[^]]]", item ) != 1 ); + + /* go back one line */ + fseek( pConfigFile, read_idx, SEEK_SET ); + + strip_spaces( pParams ); + strcpy( pTemp, pParams ); + to_upper( pParams ); + to_upper( chapter ); + + /* interpret params */ + pToken = strtok( chapter, ":" ); + if ( strcmp( chapter, "BRIROPTIMISATIONSETTINGS" ) == 0 && strlen( pParams ) != 0 ) + { + params_idx = 0; + pValue = (char *) calloc( strlen( pParams ), sizeof( char ) ); + + while ( sscanf( pParams + params_idx, "%64[^=]=%[^;];", item, pValue ) == 2 ) + { + params_idx += (int32_t) ( strlen( item ) + strlen( pValue ) + 2 ); +#ifdef DEBUGGING + fprintf( stderr, " PARAM: %s -> %s\n", item, pValue ); +#endif + if ( strcmp( item, "OPTIMIZE" ) == 0 ) + { + /* Read the number of directivity chapters */ + if ( read_txt_bool( pValue, &hRenderConfig->optimize ) != IVAS_ERR_OK ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + } + else if ( strcmp( item, "HARMONIZELATEREVERBBINAURALGAIN" ) == 0 ) + { + if ( read_txt_bool( pValue, &hRenderConfig->harmonizeLateReverbBinauralGain ) != IVAS_ERR_OK ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + } + else if ( strcmp( item, "LATEREVERBCOMPENSATIONGAIN" ) == 0 ) + { + if ( read_txt_vector( pValue, MAX_INTERN_CHANNELS, hRenderConfig->lateReverbCompensationGain ) != IVAS_ERR_OK ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + } + else if ( strcmp( item, "BEGINENERGYTHRESHOLD" ) == 0 ) + { + if ( read_txt_float( pValue, &( hRenderConfig->beginEnergyThreshold ) ) != IVAS_ERR_OK ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + } + else if ( strcmp( item, "ENDENERGYTHRESHOLD" ) == 0 ) + { + if ( read_txt_float( pValue, &hRenderConfig->endEnergyThreshold ) != IVAS_ERR_OK ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + } + else if ( strcmp( item, "DIRECTENERGYTHRESHOLD" ) == 0 ) + { + if ( read_txt_float( pValue, &hRenderConfig->directEnergyThreshold ) != IVAS_ERR_OK ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + } + else if ( strcmp( item, "DIFFUSEENERGYTHRESHOLD" ) == 0 ) + { + if ( read_txt_float( pValue, &hRenderConfig->diffuseEnergyThreshold ) != IVAS_ERR_OK ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + } + else if ( strcmp( item, "DIFFUSECUTOFFFREQTHRESHOLD" ) == 0 ) + { + if ( read_txt_float( pValue, &hRenderConfig->diffuseCutOffFreqThreshold ) != IVAS_ERR_OK ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + } + else if ( strcmp( item, "DIRECTCUTOFFFREQTHRESHOLD" ) == 0 ) + { + if ( read_txt_float( pValue, &hRenderConfig->directCutOffFreqThreshold ) != IVAS_ERR_OK ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + } + } + free( pValue ); + } + else + { + fprintf( stderr, "Unknown chapter: %s\n", chapter ); + } + } + else if ( pConfig_str[0] == '#' ) + { + /* comment lines are to be ignored */ + } +#ifdef DEBUGGING + else + { + fprintf( stderr, "Unsupported configuration property %s\n", item ); + } +#endif + } + + free( pConfig_str ); + free( pParams ); + free( pTemp ); + + if ( errorHandler( "", ERROR_NONE ) > 0 ) + { + fprintf( stderr, "Errors occurred\n" ); + return IVAS_ERR_FAILED_FILE_PARSE; + } + + fclose( pConfigFile ); + + return IVAS_ERR_OK; +} diff --git a/scripts/binauralRenderer_interface/config_reader.h b/scripts/binauralRenderer_interface/config_reader.h new file mode 100644 index 0000000000000000000000000000000000000000..fc9de4ee2d2468879f86e1fd08d0a32dc203693c --- /dev/null +++ b/scripts/binauralRenderer_interface/config_reader.h @@ -0,0 +1,75 @@ +/****************************************************************************************************** + + (C) 2022-2023 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. + +*******************************************************************************************************/ + +#ifndef CONFIG_READER_H +#define CONFIG_READER_H + +#include "common_api_types.h" +#include "ivas_cnst.h" +#include "ivas_error.h" +#include "options.h" + +#define DEFAULT_BEGIN_ENERGY_THRESHOLD ( -50.f ) +#define DEFAULT_END_ENERGY_THRESHOLD ( -120.f ) +#define DEFAULT_DIRECT_ENERGY_THRESHOLD ( -25.f ) +#define DEFAULT_DIFFUSE_ENERGY_THRESHOLD ( -25.f ) +#define DEFAULT_DIFFUSE_CUT_OFF_FREQ_THRESHOLD ( -20.f ) +#define DEFAULT_DIRECT_CUT_OFF_FREQ_THRESHOLD ( -20.f ) + + +typedef struct ConfigReader +{ + int32_t optimize; /* optimize HRIR/BRIR or not ie reduce renderer complexity */ + int32_t harmonizeLateReverbBinauralGain; /* average left/right late reverberation energy or not */ + float lateReverbCompensationGain[MAX_INTERN_CHANNELS]; /* user design additional compensation gain for late reverberation */ + float beginEnergyThreshold; /* use to find beginning of HRIR/BRIR (tb). ratio in dB between HRIR/BRIR energy before begin sample (tb) and max of all HRIR/BRIR. Reduce complexity by Removing zero or low energy samples at the beginning of the HRIR */ + float endEnergyThreshold; /* use to find end of HRIR only (te). ratio inDb between HRIR energy after te sample and energy of the whole hrir. Remove zero or low energy samples at the end of the HRIR */ + float directEnergyThreshold; /* use to find the time limit between direct HRIR/BRIR part and diffuse part (tm). It is a ratio in dB between diffuse part and complete HRIR/BRIR energies. The more the value is near zero the smallest is tm, complexity decrease. */ + float diffuseEnergyThreshold; /* use to find the time end limit of the diffuse part (te). diffuse part. It is a ratio in dB between diffuse part after te and complete diffuse HRIR/BRIR energies. The more the value is near zero the smallest is te, complexity decrease. */ + float diffuseCutOffFreqThreshold; /* threshold in dB to determine the cut off (fcdiff) frequency for each slice of the diffuse IR. ratio in dB between the energy after fcdiff and the total energy. The more the value is near zero the smallest is fcdiff, complexity decrease */ + float directCutOffFreqThreshold; /* threshold in dB to determine the cut off (fcdirect) frequency for each slice of the direct IR. Do not applied to first slice. ratio in dB between the energy after fcdirect and the total energy. The more the value is near zero the smallest is fcdirect, complexity decrease */ +} ConfigReader, *ConfigReaderHandle; + +typedef enum +{ + ERROR_NONE = 0, + ERROR_ITEM_UNKNOWN, + ERROR_VALUE_INVALID +} ERROR_CODES_t; + +/* Reads a configuration */ +ivas_error ConfigReader_read( + char *pConfigPath, /* i : renderer configuration file path */ + ConfigReaderHandle hConfig /* o : Renderer configuration handle */ +); + +#endif diff --git a/scripts/binauralRenderer_interface/fastconv/README.txt b/scripts/binauralRenderer_interface/fastconv/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..3a54d1cdf9645dcc83ba4cedf4e81ccf67fce369 --- /dev/null +++ b/scripts/binauralRenderer_interface/fastconv/README.txt @@ -0,0 +1,3 @@ +WIP: +The script to generate all FastConv Renderer tables is generate_tables_for_fastconv.m +Options can be set in the script to generate either or both ROM tables and a Binary file. \ No newline at end of file diff --git a/scripts/binauralRenderer_interface/fastconv/cldfb_prototype.mat b/scripts/binauralRenderer_interface/fastconv/cldfb_prototype.mat new file mode 100644 index 0000000000000000000000000000000000000000..6e9e08fb0ed81fcc71bbe21005140d914ffcef64 --- /dev/null +++ b/scripts/binauralRenderer_interface/fastconv/cldfb_prototype.mat @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:386bbd3a02c3b95280fff7bd8f5240ee60f8858889cad0f6147e930f5f2aa7e2 +size 1246 diff --git a/scripts/binauralRenderer_interface/fastconv/generate_BRIR_CLDFB_FASTCONV.m b/scripts/binauralRenderer_interface/fastconv/generate_BRIR_CLDFB_FASTCONV.m new file mode 100644 index 0000000000000000000000000000000000000000..bff536aecf4fa2b770784881fe10072d8b0401a6 --- /dev/null +++ b/scripts/binauralRenderer_interface/fastconv/generate_BRIR_CLDFB_FASTCONV.m @@ -0,0 +1,371 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% (C) 2022-2023 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. +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function FastConv_SD_BRIR = generate_BRIR_CLDFB_FASTCONV(sofa_file, max_band) +%% generate_BRIR_CLDFB_FASTCONV(rom_c_file, sofa_file): +% script for getting the binaural room impulse response coefficients in CLDFB domain +% - loads sphere-samples BRIRs given in sofa_file (must match requested speaker positions!) +% - converts SD BRIRs to Complex Low Delay Filter Bank (CLDFB) domain using td2cldfb.m +% - truncates CLDFB BRIRs in frequency and time +% - writes CLDFB BRIRs to c-code ROM tables +if ~exist('sofa_file','var') || isempty(sofa_file) + sofa_file = fullfile(thispath,'..','BRIRs_sofa','IIS_BRIR_officialMPEG_Combined.sofa'); +end +if ~exist('max_band', 'var') || isempty(max_band) + max_band = 50; +end + +%% Load CLDFB protopyte +load('cldfb_prototype.mat'); + +%% Load HRTFs +if isfolder("../matlab_hrir_generation_scripts") + addpath("../matlab_hrir_generation_scripts"); +end +sofaData = hrtf_library_loader(); +sofaData.readSOFA(char(sofa_file)); +ls_struct = get_ls_layout_config('Combined'); + +IR = permute(sofaData.Data.IR(:,:,:), [3 2 1]); + +% match required loudspeaker positions +brirAziRad = sofaData.PosSpherical(1, :).'; +brirEleRad = sofaData.PosSpherical(2, :).'; +refAziRad = deg2rad(ls_struct.azi)'; +refEleRad = deg2rad(ls_struct.ele)'; +refVectors = [cos(refAziRad).*cos(refEleRad) sin(refAziRad).*cos(refEleRad) sin(refEleRad)]; +sofaVectors = [cos(brirAziRad).*cos(brirEleRad) sin(brirAziRad).*cos(brirEleRad) sin(brirEleRad)]; +for ch = 1:length(refAziRad) + [~, maxIndex] = max(sofaVectors*refVectors(ch,:)'); + chSelect(ch) = maxIndex; +end +IR = IR(:, :, chSelect); + +% Resample IRs if needed +fs = sofaData.Lib_SampleRate; +if fs~=48000 + hrir_in = permute(IR,[2 3 1]); + IR = permute(resamp_hrir(hrir_in,fs),[3 1 2]); +end + +%% TD -> CLDFB +clear IR_cldfb; + +[BRIR_cldfb, rev_param] = compute_brir_parameters(IR,prototype,max_band); +BRIR_cldfb = permute(BRIR_cldfb, [3 1 4 2]); +BRIR_cldfb = BRIR_cldfb(:,1:max_band,:,:); + +FastConv_SD_BRIR.IR = BRIR_cldfb; +FastConv_SD_BRIR.rev_param = rev_param; +end + + +function [hrir,Nhrir] = resamp_hrir(hrir_in,fs) + +Nhrir_in = size(hrir_in,3); +nEar = size(hrir_in,1); +nDir = size(hrir_in,2); + +if fs ~= 48000 + + r = fs/48000; + fs = 48000; + + Nhrir = Nhrir_in/r; + + hrir = zeros([nEar,nDir,Nhrir]); + data(1:Nhrir_in) = 0.0; + + for iEar = 1:nEar + for iDir = 1:nDir + data(1:Nhrir_in) = hrir_in(iEar,iDir,:); + data(1:Nhrir) = decimate(data,r,'fir'); + hrir(iEar,iDir,1:Nhrir) = data(1:Nhrir); + end + end + +else + + hrir = hrir_in; + Nhrir = Nhrir_in; + +end + +end + + +function [IR_cldfb,reverb_parameters] = compute_brir_parameters(IR,prototype,max_band) +% Step 1: Compute the propogation time and remove the propogation time +in_struct.propogationTime = 0; +in_struct.fs = 48000; +[IR,in_struct] = compensate_prop_time(IR,in_struct); +in_struct.THR_DE = -20; +in_struct.max_band = max_band; +in_struct.max_index = 273; % Needs to be changed according to IRs + +% Step 2: TD -> CLDFB +IR_cldfb = []; +for chIdx = 1:size(IR,3) + for outChIdx = 1:size(IR,2) + IR_cldfb(:,:,outChIdx,chIdx) = td2cldfb( IR(:,outChIdx,chIdx), prototype, 60 ); + end +end + +% Step 3: Compute EDC (Energy Decay Curve) +in_struct.num_bands = size(IR_cldfb,1); +in_struct.timeSlots = size(IR_cldfb,2); +assert(in_struct.timeSlots > in_struct.max_index) +in_struct.num_channels = size(IR_cldfb,4); +EDC = get_EDC(IR_cldfb,in_struct); + +% Step 4: Determine Mixing Time +mixingTime = getMixingTime(EDC, in_struct); + +% Compute the time-slot where the IR is truncated +in_struct.NFft = floor((mixingTime)); +NFilter = max(in_struct.NFft(1:in_struct.max_band)); + +% Variable order Filtering +for idx = 1:5 + in_struct.NFft(idx) = NFilter; +end +for idx = 6:10 + in_struct.NFft(idx) = ceil(0.6*NFilter); +end +for idx = 11:20 + in_struct.NFft(idx) = ceil(0.5*NFilter); +end +for idx = 21:30 + in_struct.NFft(idx) = ceil(0.4*NFilter); +end +for idx = 31:in_struct.max_band + in_struct.NFft(idx) = ceil(0.3*NFilter); +end + +% Step 5: Compute reverb parameters +% compute rt60 and energy +reverb_parameters = get_Reverb_parameters(IR_cldfb,in_struct); +reverb_parameters.NFilter = NFilter; + +end + +function [IR_out,in_struct] = compensate_prop_time(IR_in,in_struct) + +% Get the min index +min_idx = zeros(1,size(IR_in,3)); +for chIdx = 1:size(IR_in,3) + [~,idx] = max(abs(IR_in(:,:,chIdx))); + min_idx(chIdx) = min(idx); +end + +prop_time = min(min_idx) - 15; +in_struct.propogationTime = prop_time; +in_struct.latency_s = (min(min_idx) - 1 - prop_time)/in_struct.fs + 31/in_struct.fs; + +IR_out = []; +for chIdx = 1:size(IR_in,3) + IR_out(:,:,chIdx) = IR_in(prop_time:end,:,chIdx); +end + +end + +function EDC = get_EDC(in,in_struct) + bands = in_struct.num_bands; + timeSlots = in_struct.timeSlots; + numChannels = in_struct.num_channels; + + % EDC: Energy decay curve + EDC = zeros(bands,timeSlots,2,numChannels); + for chIdx = 1:numChannels + tmp = in(:,:,:,chIdx); + for idx = 1:2 + for bandIdx = 1:bands + sum_1 = sum(abs(tmp(bandIdx,1:end,idx)).^2); + for timeIdx = 1:timeSlots + sum_2 = sum(abs(tmp(bandIdx,timeIdx:end,idx)).^2); + EDC(bandIdx,timeIdx,idx,chIdx) = 10*log10(sum_2/sum_1); + end + end + end + end +end + +function mixingTime = getMixingTime(EDC, in_struct) +THR_DE = in_struct.THR_DE; +bands = in_struct.num_bands; +numChannels = in_struct.num_channels; +N = size(EDC,2); +mixingTime = zeros(1,bands); + +for idx = 1:bands + mixingTime(idx) = 0; + for chIdx = 1:numChannels + THR = EDC(idx,1,1,chIdx) + THR_DE; + n = 2; + while( EDC(idx,n,1,chIdx) > THR ) + n = n + 1; + if(n > N) + break; + end + end + mixingTime(idx) = mixingTime(idx) + (n+1); + end + for chIdx = 1:numChannels + THR = EDC(idx,1,2,chIdx) + THR_DE; + n = 2; + while( EDC(idx,n,2,chIdx) > THR ) + n = n + 1; + if(n > N) + break; + end + end + mixingTime(idx) = mixingTime(idx) + (n+1); + end + mixingTime(idx) = mixingTime(idx)/(2*numChannels); +end +end + +function RT60 = computeRT60(in,s_idx,e_idx,in_struct) +% define t based on the length of reverb tail +end_idx = length(in); +s_i = (s_idx*in_struct.num_bands)/in_struct.fs; +e_i = (e_idx*in_struct.num_bands)/in_struct.fs; +t = linspace(s_i,e_i,end_idx); + +% compute EDC (Energy Decay curve) of the reverb tail +EDC = zeros(1,end_idx); +sum2 = sum(abs(in(1:end_idx)).^2); +for idx = 1:end_idx + sum1 = sum(abs(in(idx:end_idx)).^2); + EDC(idx) = 10*log10(sum1/sum2); +end + +% compute index, i5 and i35 +% i5 is the time required for EDC to reduce by 5dB +% i35 is the time required for EDC to reduce by 35dB +% Based on i5 and i35, we compute the T30 and estimate T60 +index = find(EDC==0,1,'last'); + +i0 = index; +i5 = i0+1; +while EDC(i5) > (EDC(i0)-5) + i5 = i5+1; +end + +i35 = i5+1; +while ((EDC(i35) > (EDC(i0) -35)) && (i35 < end_idx)) + i35 = i35 + 1; +end + +% Compute T(30) and T(60) +if (i35 > floor(length(EDC) * 0.95)) + i35 = round(length(EDC) * 0.95); + amp = EDC(i35); + fact = -65 / amp; +else + fact = 2; +end +if (i5) > length(EDC) * 0.5 + i5 = 1; +end + +RT30 = t(i35) - t(i5); +RT60 = fact * RT30; +end + +function reverbParameters = get_Reverb_parameters(IR_CLDFB,input_struct) + +% start the analysis for computing reverb parameters +ENRG = zeros(input_struct.num_bands,1); +RT60 = zeros(input_struct.num_bands,1); +ct_num = 0; +max_index = input_struct.max_index; + + +disp('Late Reverberation Analysis Started') +for chIdx = 1:input_struct.num_channels + disp(['Analyzing channel ' num2str(chIdx) '/' num2str(input_struct.num_channels)]) + for outChIdx = 1:2 + for bandIdx = 1:input_struct.num_bands + % the computation of reverb parameters starts with some overlap + s_idx = input_struct.NFft(bandIdx)-5; + + % Determine the truncation point based on noise floor estimates + end_idx = get_truncation_point(IR_CLDFB(bandIdx,s_idx:max_index,outChIdx,chIdx)); + e_idx = s_idx + end_idx; + if(e_idx > max_index) + e_idx = max_index; + end + + % Extract the reverb tail that is used for energy/RT60 + % computation + input_signal = IR_CLDFB(bandIdx,s_idx:e_idx,outChIdx,chIdx); + + % Estimate RT60 and Energy + ENRG_tmp = sum(abs(input_signal.^2)); + RT60_tmp = computeRT60(input_signal,s_idx,e_idx,input_struct); + + ENRG(bandIdx) = ENRG(bandIdx) + ENRG_tmp; + RT60(bandIdx) = RT60(bandIdx) + RT60_tmp; + end + end + ct_num = ct_num + 2; +end + +reverbParameters.latency_s = input_struct.latency_s; +reverbParameters.nrgLr = ENRG/ct_num; +reverbParameters.rt60 = RT60/ct_num; +reverbParameters.kAna = input_struct.num_bands; +end + +function end_index = get_truncation_point(in) +end_idx = length(in); + +% Compute the energy in log domain +log_energy = 10*log10(abs(in(1:end_idx)).^2); +noisefloor = mean(log_energy); + +% Decay line(Line Fitting to EDC) +x = 1:end_idx; +order = 1; % order of the polynomial that is used to fit +% p(1) is the slope, p(2) is the bias +p = polyfit(x,log_energy,order); +decay = p(1)*x + p(2); % Straight line equation + +% find the intersection point +cp = find(decay < noisefloor, 1, 'first'); +if isempty(cp) + cp = end_idx; +end + +end_index = cp; +end + diff --git a/scripts/binauralRenderer_interface/fastconv/generate_tables_for_fastconv.m b/scripts/binauralRenderer_interface/fastconv/generate_tables_for_fastconv.m new file mode 100644 index 0000000000000000000000000000000000000000..d310ca2efd74841529c48c53afe836ab101ad8b5 --- /dev/null +++ b/scripts/binauralRenderer_interface/fastconv/generate_tables_for_fastconv.m @@ -0,0 +1,94 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% (C) 2022-2023 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. +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if exist('clearButKeepNeededVariables') + clearButKeepNeededVariables; +else + clear all; +end +close all; +clc; + +%% add path for hrtf_library_loader.m +if isfolder(['..' filesep() 'matlab_hrir_generation_scripts/']) + addpath(['..' filesep() 'matlab_hrir_generation_scripts/']); +end + +%% Set arguments +if ~exist("writeRomFileOutput",'var') + writeRomFileOutput = true; +end +if ~exist("writeBinaryOutput",'var') + writeBinaryOutput = true; +end +if ~exist("rom_file",'var') + rom_file = fullfile('.', 'ivas_rom_binauralRenderer.c'); +end +if ~exist("bin_file",'var') + bin_file = fullfile('.', 'fastconv_rom.bin'); +end +%% Set input files +if ~exist("hrir_file",'var') + hrir_file = fullfile('..', 'HRIRs_sofa', 'HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000.sofa'); +end +if ~exist("brir_file",'var') + brir_file = fullfile('..', 'BRIRs_sofa', 'IIS_BRIR_officialMPEG_Combined.sofa'); +end + +if ~exist("ivas_path",'var') + ivas_path = ['..' filesep '..' filesep '..' filesep]; +end + +%% Generate C-code tables for RENDERER_BINAURAL_FASTCONV (SHD) +disp('Processing HRIRs (FOA) for FastConv renderer...'); +FastConv_SHD_IR_FOA = SHD_2_ROM(hrir_file, 1, 128); + +disp('Processing HRIRs (HOA2) for FastConv renderer...'); +FastConv_SHD_IR_HOA2 = SHD_2_ROM(hrir_file, 2, 128); + +disp('Processing HRIRs (HOA3) for FastConv renderer...'); +FastConv_SHD_IR_HOA3 = SHD_2_ROM(hrir_file, 3, 128); + +%% Generate C-code tables for RENDERER_BINAURAL_FASTCONV (SD) +disp('Processing HRIRs (SD) for FastConv renderer...'); +FastConv_SD_IR = SD_2_ROM(hrir_file); + +%% Generate C-code tables for RENDERER_BINAURAL_FASTCONV_ROOM (SD) +disp('Processing BRIRs (SD) for FastConv renderer...'); +FastConv_SD_BRIR = generate_BRIR_CLDFB_FASTCONV(brir_file); + +if writeRomFileOutput + write_fastconv_rom_table(rom_file, FastConv_SHD_IR_FOA, FastConv_SHD_IR_HOA2, FastConv_SHD_IR_HOA3, FastConv_SD_IR, FastConv_SD_BRIR); +end + +if writeBinaryOutput + write_fastconv_binary_data(ivas_path, bin_file, FastConv_SHD_IR_FOA, FastConv_SHD_IR_HOA2, FastConv_SHD_IR_HOA3, FastConv_SD_IR, FastConv_SD_BRIR); +end diff --git a/scripts/binauralRenderer_interface/fastconv/get_ivas_binary_header.m b/scripts/binauralRenderer_interface/fastconv/get_ivas_binary_header.m new file mode 100644 index 0000000000000000000000000000000000000000..4ded6be201be508baf600a413865917208879f0d --- /dev/null +++ b/scripts/binauralRenderer_interface/fastconv/get_ivas_binary_header.m @@ -0,0 +1,87 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% (C) 2022-2023 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. +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function header = get_ivas_binary_header(ivas_path, renderer_type, bin_in_fmt) +%GET_IVAS_BINARY_HEADER Returns the values required to write the binary +% header by parsing the IVAS enum values +% +% Header [Declaration of the HRTF] +% Renderer type (int32_t) : See "RENDERER_TYPE" +% Decoder output format / Binary input format (int32_t) : See "BINAURAL_INPUT_AUDIO_CONFIG" +% Sampling Frequency (int32_t) : Depends on RENDERER_TYPE! +% Raw data size (uint32_t): !!Not set by this function!! +% +%% placeholder values +header.renderer_type = 0; +header.in_fmt = 0; +header.fs = 48000; % TODO not relevant for FastConv/ParamBin +header.chunksize = 0; + +%% parse IVAS enum +% read the file +ivas_cnst_path = fullfile(ivas_path, 'lib_com/ivas_cnst.h'); % must be replaced if this file is moved +c = fileread(hrtf_file_reader_path); +% regex for RENDERER_TYPE +rt_expr = '^\s+(RENDERER\w+)'; +rt_tok = regexp(c, rt_expr, 'tokens', 'dotexceptnewline', 'lineanchors'); + +renderer_types = convertCharsToStrings(cat(1,rt_tok{:})); +renderer_types = strip(renderer_types); +renderer_types = replace(renderer_types, ',', ''); + +header.renderer_type = find(renderer_type == renderer_types); +if header.renderer_type + header.renderer_type = header.renderer_type - 1; % matlab index to c enum index +else + disp(renderer_types); + error('Renderer type could not be matched to IVAS enum values!'); +end + +ivas_cnst_path = fullfile(ivas_path, 'lib_com/ivas_cnst.h'); % must be replaced if this file is moved +c = fileread(ivas_cnst_path); + +% regex for BINAURAL_INPUT_AUDIO_CONFIG +ic_expr = '^\s+(BINAURAL_INPUT\w+)'; +ic_tok = regexp(c, ic_expr, 'tokens', 'dotexceptnewline', 'lineanchors'); +in_configs = convertCharsToStrings(cat(1,ic_tok{:})); +in_configs = strip(in_configs); +in_configs = replace(in_configs, ',', ''); + +header.in_fmt = find(bin_in_fmt == in_configs); +if header.in_fmt + header.in_fmt = header.in_fmt - 1; % matlab index to c enum index +else + disp(in_configs); + error('Binaural input config could not be matched to IVAS enum values!'); +end + +end + diff --git a/scripts/binauralRenderer_interface/fastconv/td2cldfb.m b/scripts/binauralRenderer_interface/fastconv/td2cldfb.m new file mode 100644 index 0000000000000000000000000000000000000000..19eb36a55d93b709ba8aebc791efb20f28e4c695 --- /dev/null +++ b/scripts/binauralRenderer_interface/fastconv/td2cldfb.m @@ -0,0 +1,60 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% (C) 2022-2023 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. +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function [ out ] = td2cldfb( in, prototype, L ) +% TD2CLDFB +% This script takes the td signal along with prototype and length and +% outputs the frequemcy domain signal + +N_in = length(in); +N_prototype = length(prototype); + +K_prototype = ceil(N_prototype/L); +K_in = ceil(N_in/L); + +N = K_prototype + K_in - 1; + +hext = zeros(L*(2*K_prototype + K_in - 2),1); +hext((K_prototype-1)*L+(1:N_in)) = in; % extend to make all shifts possible + +out=zeros(L,N); + +Nmid = N_prototype/2; % midpoint +ls = -Nmid+1:Nmid; +ns = (0:L-1)'; +E = exp(-1i*(pi/L)*(ns+.5)*ls); + +for k=1:N + shift=(k-1)*L; + out(:,k)=E*(hext(shift+(1:N_prototype)).*prototype(:)); +end +end + diff --git a/scripts/binauralRenderer_interface/fastconv/write_fastconv_binary_data.m b/scripts/binauralRenderer_interface/fastconv/write_fastconv_binary_data.m new file mode 100644 index 0000000000000000000000000000000000000000..39962bebdf7971a2f7f29da4be367e877dd3795e --- /dev/null +++ b/scripts/binauralRenderer_interface/fastconv/write_fastconv_binary_data.m @@ -0,0 +1,294 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% (C) 2022-2023 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. +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function write_fastconv_binary_data(ivas_path, bin_file, FastConv_SHD_IR_FOA, FastConv_SHD_IR_HOA2, FastConv_SHD_IR_HOA3, FastConv_SD_IR, FastConv_SD_BRIR) +% +% Writes HRIR & BRIR based data for FastConv binaural renderer into a binary file. +% +% write_fastconv_binary_data(rom_file, FastConv_SHD_IR_FOA, FastConv_SHD_IR_HOA2, FastConv_SHD_IR_HOA3, FastConv_SD_IR, FastConv_SD_BRIR) +% +% filename : string +% name of the file to be written +% +% +% Output file format: +% Header [Declaration of the HRTF] +% Renderer type (int32_t) : See "RENDERER_TYPE" +% Decoder output format (int32_t) : See "BINAURAL_INPUT_AUDIO_CONFIG" +% Sampling Frequency (int32_t) +% Raw data size (uint32_t) +% +% HRIRs +% latency_s => float32 +% BINAURAL_CONVBANDS => uint16_t +% num_channels => uint16_t +% BINAURAL_NTAPS => uint16_t +% leftHRIRReal => float32[BINAURAL_CONVBANDS][num_channels][num_taps] +% leftHRIRImag => float32[BINAURAL_CONVBANDS][num_channels][num_taps] +% rightHRIRReal => float32[BINAURAL_CONVBANDS][num_channels][num_taps] +% rightHRIRImag => float32[BINAURAL_CONVBANDS][num_channels][num_taps] +% +% BRIRs +% latency_s => float32 +% num_channels => uint16_t +% BINAURAL_NTAPS_MAX => uint16_t +% leftBRIRReal => float32[BINAURAL_CONVBANDS][num_channels][num_taps] +% leftBRIRImag => float32[BINAURAL_CONVBANDS][num_channels][num_taps] +% rightBRIRReal => float32[BINAURAL_CONVBANDS][num_channels][num_taps] +% rightBRIRImag => float32[BINAURAL_CONVBANDS][num_channels][num_taps] +% CLDFB_NO_CHANNELS_MAX => uint16_t +% fastConvReverberationTimes => float32[CLDFB_NO_CHANNELS_MAX] +% fastConvReverberationEneCorrections => float32[CLDFB_NO_CHANNELS_MAX] +% + +[f_id, err_msg] = fopen(bin_file, 'wb'); + +if f_id == -1 + error('Could not open file %s for writing. Error message:\n%s', filename, err_msg); +end + +%% File header +% We need to get the chunksize of all IRs to get total size +% SHD HRIRs +% FOA +IR = FastConv_SHD_IR_FOA; +[~, binaural_convbands, num_channels, binaural_ntaps] = size(IR.IR); + +header = get_ivas_binary_header(ivas_path,'HRTF_READER_RENDERER_BINAURAL_FASTCONV', ['BINAURAL_INPUT_AUDIO_CONFIG_' IR.order]); +header.chunksize = header.chunksize + 4; % latency_s +header.chunksize = header.chunksize + 2; % BINAURAL_CONVBANDS +header.chunksize = header.chunksize + 2; % num_channels +header.chunksize = header.chunksize + 2; % num_taps +header.chunksize = header.chunksize + 4 * (binaural_convbands * num_channels * binaural_ntaps * 4 ); % HRTF L/R Re/Im + +IR.header = header; +FastConv_SHD_IR_FOA = IR; + +% HOA2 +IR = FastConv_SHD_IR_HOA2; +[~, binaural_convbands, num_channels, binaural_ntaps] = size(IR.IR); + +header = get_ivas_binary_header(ivas_path, 'HRTF_READER_RENDERER_BINAURAL_FASTCONV', ['BINAURAL_INPUT_AUDIO_CONFIG_' IR.order]); +header.chunksize = header.chunksize + 4; % latency_s +header.chunksize = header.chunksize + 2; % BINAURAL_CONVBANDS +header.chunksize = header.chunksize + 2; % num_channels +header.chunksize = header.chunksize + 2; % num_taps +header.chunksize = header.chunksize + 4 * (binaural_convbands * num_channels * binaural_ntaps * 4 ); % HRTF L/R Re/Im + +IR.header = header; +FastConv_SHD_IR_HOA2 = IR; + +% HOA3 +IR = FastConv_SHD_IR_HOA3; +[~, binaural_convbands, num_channels, binaural_ntaps] = size(IR.IR); + +header = get_ivas_binary_header(ivas_path, 'HRTF_READER_RENDERER_BINAURAL_FASTCONV', ['BINAURAL_INPUT_AUDIO_CONFIG_' IR.order]); +header.chunksize = header.chunksize + 4; % latency_s +header.chunksize = header.chunksize + 2; % BINAURAL_CONVBANDS +header.chunksize = header.chunksize + 2; % num_channels +header.chunksize = header.chunksize + 2; % num_taps +header.chunksize = header.chunksize + 4 * (binaural_convbands * num_channels * binaural_ntaps * 4 ); % HRTF L/R Re/Im + +IR.header = header; +FastConv_SHD_IR_HOA3 = IR; + +% SD HRIRs +IR = FastConv_SD_IR; +[~, binaural_convbands, num_channels, binaural_ntaps] = size(IR.IR); + +header = get_ivas_binary_header(ivas_path, 'HRTF_READER_RENDERER_BINAURAL_FASTCONV', 'BINAURAL_INPUT_AUDIO_CONFIG_COMBINED'); +header.chunksize = header.chunksize + 4; % latency_s +header.chunksize = header.chunksize + 2; % BINAURAL_CONVBANDS +header.chunksize = header.chunksize + 2; % num_channels +header.chunksize = header.chunksize + 2; % num_taps +header.chunksize = header.chunksize + 4 * (binaural_convbands * num_channels * binaural_ntaps * 4 ); % HRTF L/R Re/Im + +IR.header = header; +FastConv_SD_IR = IR; + +% SD BRIRs +IR = FastConv_SD_BRIR; +[~, binaural_convbands, num_channels, ~] = size(IR.IR); +cldfb_no_channels_max = IR.rev_param.kAna; + +header = get_ivas_binary_header(ivas_path, 'HRTF_READER_RENDERER_BINAURAL_FASTCONV_ROOM', 'BINAURAL_INPUT_AUDIO_CONFIG_COMBINED'); +header.chunksize = header.chunksize + 4; % latency_s +header.chunksize = header.chunksize + 2; % BINAURAL_CONVBANDS +header.chunksize = header.chunksize + 2; % num_channels +header.chunksize = header.chunksize + 2; % num_taps +header.chunksize = header.chunksize + 4 * (binaural_convbands * num_channels * IR.rev_param.NFilter * 4 ); % HRTF L/R Re/Im +header.chunksize = header.chunksize + 2; % CLDFB_NO_CHANNELS_MAX +header.chunksize = header.chunksize + cldfb_no_channels_max * 4; % rt60 +header.chunksize = header.chunksize + cldfb_no_channels_max * 4; % nrgLr + +IR.header = header; +FastConv_SD_BRIR = IR; + +% calculate the size of all chunks +HRTFs = {FastConv_SHD_IR_FOA, FastConv_SHD_IR_HOA2, FastConv_SHD_IR_HOA3, FastConv_SD_IR, FastConv_SD_BRIR}; +hrtf_data_size = 0; +total_file_size = 0; +for i = 1:length(HRTFs) + hrtf_data_size = hrtf_data_size + HRTFs{i}.header.chunksize; + total_file_size = total_file_size + 4 * 4; % chunk header 4 (u)int32 values +end + +total_file_size = total_file_size + 8; % 'IVASHRTF' (char[8]) +total_file_size = total_file_size + 4; % file size (int32) +total_file_size = total_file_size + 2; % number of HRTFs in file (int16) +total_file_size = total_file_size + 4; % HRTF size (int32) +total_file_size = total_file_size + hrtf_data_size; % size of all HRTF data chunks + +fwrite(f_id, 'IVASHRTF', 'char'); % identifier +fwrite(f_id, total_file_size, 'int32'); % file size +fwrite(f_id, length(HRTFs), 'int16'); % number of HRTFs +fwrite(f_id, hrtf_data_size, 'int32'); % max data size (bytes to read after this header) + +%% HRIRs + +% SHD HRIRs +SHD_HRIRs = {FastConv_SHD_IR_FOA, FastConv_SHD_IR_HOA2, FastConv_SHD_IR_HOA3}; +for i = 1:length(SHD_HRIRs) + IR = SHD_HRIRs{i}; + [~, binaural_convbands, num_channels, binaural_ntaps] = size(IR.IR); + + % write header for this chunk + fwrite(f_id, IR.header.renderer_type, 'int32'); + fwrite(f_id, IR.header.in_fmt, 'int32'); + fwrite(f_id, IR.header.fs, 'int32'); + fwrite(f_id, IR.header.chunksize, 'uint32'); + + fwrite(f_id, IR.latency_s, 'float32'); + fwrite(f_id, binaural_convbands, 'uint16'); + fwrite(f_id, num_channels, 'uint16'); + fwrite(f_id, binaural_ntaps, 'uint16'); + + for band = 1:binaural_convbands + for ch = 1:num_channels + fwrite(f_id, real(squeeze(IR.IR(1, band, ch, :))), 'float32'); + end + end + for band = 1:binaural_convbands + for ch = 1:num_channels + fwrite(f_id, imag(squeeze(IR.IR(1, band, ch, :))), 'float32'); + end + end + for band = 1:binaural_convbands + for ch = 1:num_channels + fwrite(f_id, real(squeeze(IR.IR(2, band, ch, :))), 'float32'); + end + end + for band = 1:binaural_convbands + for ch = 1:num_channels + fwrite(f_id, imag(squeeze(IR.IR(2, band, ch, :))), 'float32'); + end + end +end + +% SD HRIRs +IR = FastConv_SD_IR; +[~, binaural_convbands, num_channels, binaural_ntaps] = size(IR.IR); + +% write header for this chunk +fwrite(f_id, IR.header.renderer_type, 'int32'); +fwrite(f_id, IR.header.in_fmt, 'int32'); +fwrite(f_id, IR.header.fs, 'int32'); +fwrite(f_id, IR.header.chunksize, 'uint32'); + +fwrite(f_id, IR.latency_s, 'float32'); +fwrite(f_id, binaural_convbands, 'uint16'); +fwrite(f_id, num_channels, 'uint16'); +fwrite(f_id, binaural_ntaps, 'uint16'); +for band = 1:binaural_convbands + for ch = 1:num_channels + fwrite(f_id, real(squeeze(IR.IR(1, band, ch, :))), 'float32'); + end +end +for band = 1:binaural_convbands + for ch = 1:num_channels + fwrite(f_id, imag(squeeze(IR.IR(1, band, ch, :))), 'float32'); + end +end +for band = 1:binaural_convbands + for ch = 1:num_channels + fwrite(f_id, real(squeeze(IR.IR(2, band, ch, :))), 'float32'); + end +end +for band = 1:binaural_convbands + for ch = 1:num_channels + fwrite(f_id, imag(squeeze(IR.IR(2, band, ch, :))), 'float32'); + end +end + + +% SD BRIRs +IR = FastConv_SD_BRIR; +[~, binaural_convbands, num_channels, ~] = size(IR.IR); +cldfb_no_channels_max = IR.rev_param.kAna; + +% write header for this chunk +fwrite(f_id, IR.header.renderer_type, 'int32'); +fwrite(f_id, IR.header.in_fmt, 'int32'); +fwrite(f_id, IR.header.fs, 'int32'); +fwrite(f_id, IR.header.chunksize, 'uint32'); + +fwrite(f_id, IR.rev_param.latency_s, 'float32'); +fwrite(f_id, binaural_convbands, 'uint16'); +fwrite(f_id, num_channels, 'uint16'); +fwrite(f_id, IR.rev_param.NFilter, 'uint16'); +for band = 1:binaural_convbands + for ch = 1:num_channels + fwrite(f_id, real(squeeze(IR.IR(1, band, ch, 1:IR.rev_param.NFilter))), 'float32' ); + end +end +for band = 1:binaural_convbands + for ch = 1:num_channels + fwrite(f_id, imag(squeeze(IR.IR(1, band, ch, 1:IR.rev_param.NFilter))), 'float32' ); + end +end +for band = 1:binaural_convbands + for ch = 1:num_channels + fwrite(f_id, real(squeeze(IR.IR(2, band, ch, 1:IR.rev_param.NFilter))), 'float32' ); + end +end +for band = 1:binaural_convbands + for ch = 1:num_channels + fwrite(f_id, imag(squeeze(IR.IR(2, band, ch, 1:IR.rev_param.NFilter))), 'float32' ); + end +end + +fwrite(f_id, cldfb_no_channels_max, 'uint16'); +fwrite(f_id, IR.rev_param.rt60, 'float32'); +fwrite(f_id, IR.rev_param.nrgLr, 'float32'); + +fclose(f_id); + +end \ No newline at end of file diff --git a/scripts/binauralRenderer_interface/fastconv/write_fastconv_rom_table.m b/scripts/binauralRenderer_interface/fastconv/write_fastconv_rom_table.m new file mode 100644 index 0000000000000000000000000000000000000000..ddd71dba74f6d232661fc9a5d536b3775d7a7254 --- /dev/null +++ b/scripts/binauralRenderer_interface/fastconv/write_fastconv_rom_table.m @@ -0,0 +1,101 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% (C) 2022-2023 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. +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function write_fastconv_rom_table(output_file, FastConv_SHD_IR_FOA, FastConv_SHD_IR_HOA2, FastConv_SHD_IR_HOA3, FastConv_SD_IR, FastConv_SD_BRIR) + % TODO move this to common script that writes all tables? + %% Open file and write header + if ismac + username = getenv('USER'); + else + username = getenv('username'); + end + fid = fopen(output_file, 'at'); + fprintf(fid, '/*\n'); + fprintf(fid, ' * Generated on %s with Matlab version %s by %s on %s\n', datetime("today"), version, username, computer); + fprintf(fid, '*/\n\n\n'); + + %% HRIRs (SHD) + % HOA3 + fprintf(fid, ['const float FASTCONV_' FastConv_SHD_IR_HOA3.order '_latency_s = %10.9ff;\n'], FastConv_SHD_IR_HOA3.latency_s); + writeData3L(fid, ['const float leftHRIRReal_' FastConv_SHD_IR_HOA3.order '[BINAURAL_CONVBANDS][' FastConv_SHD_IR_HOA3.order '_CHANNELS][BINAURAL_NTAPS_SBA]'], real(squeeze(FastConv_SHD_IR_HOA3.IR(1,:,:,:)))); + writeData3L(fid, ['const float leftHRIRImag_' FastConv_SHD_IR_HOA3.order '[BINAURAL_CONVBANDS][' FastConv_SHD_IR_HOA3.order '_CHANNELS][BINAURAL_NTAPS_SBA]'], imag(squeeze(FastConv_SHD_IR_HOA3.IR(1,:,:,:)))); + writeData3L(fid, ['const float rightHRIRReal_' FastConv_SHD_IR_HOA3.order '[BINAURAL_CONVBANDS][' FastConv_SHD_IR_HOA3.order '_CHANNELS][BINAURAL_NTAPS_SBA]'], real(squeeze(FastConv_SHD_IR_HOA3.IR(2,:,:,:)))); + writeData3L(fid, ['const float rightHRIRImag_' FastConv_SHD_IR_HOA3.order '[BINAURAL_CONVBANDS][' FastConv_SHD_IR_HOA3.order '_CHANNELS][BINAURAL_NTAPS_SBA]'], imag(squeeze(FastConv_SHD_IR_HOA3.IR(2,:,:,:)))); + % HOA2 + fprintf(fid, ['const float FASTCONV_' FastConv_SHD_IR_HOA2.order '_latency_s = %10.9ff;\n'], FastConv_SHD_IR_HOA2.latency_s); + writeData3L(fid, ['const float leftHRIRReal_' FastConv_SHD_IR_HOA2.order '[BINAURAL_CONVBANDS][' FastConv_SHD_IR_HOA2.order '_CHANNELS][BINAURAL_NTAPS_SBA]'], real(squeeze(FastConv_SHD_IR_HOA2.IR(1,:,:,:)))); + writeData3L(fid, ['const float leftHRIRImag_' FastConv_SHD_IR_HOA2.order '[BINAURAL_CONVBANDS][' FastConv_SHD_IR_HOA2.order '_CHANNELS][BINAURAL_NTAPS_SBA]'], imag(squeeze(FastConv_SHD_IR_HOA2.IR(1,:,:,:)))); + writeData3L(fid, ['const float rightHRIRReal_' FastConv_SHD_IR_HOA2.order '[BINAURAL_CONVBANDS][' FastConv_SHD_IR_HOA2.order '_CHANNELS][BINAURAL_NTAPS_SBA]'], real(squeeze(FastConv_SHD_IR_HOA2.IR(2,:,:,:)))); + writeData3L(fid, ['const float rightHRIRImag_' FastConv_SHD_IR_HOA2.order '[BINAURAL_CONVBANDS][' FastConv_SHD_IR_HOA2.order '_CHANNELS][BINAURAL_NTAPS_SBA]'], imag(squeeze(FastConv_SHD_IR_HOA2.IR(2,:,:,:)))); + % FOA + fprintf(fid, ['const float FASTCONV_' FastConv_SHD_IR_FOA.order '_latency_s = %10.9ff;\n'], FastConv_SHD_IR_FOA.latency_s); + writeData3L(fid, ['const float leftHRIRReal_' FastConv_SHD_IR_FOA.order '[BINAURAL_CONVBANDS][' FastConv_SHD_IR_FOA.order '_CHANNELS][BINAURAL_NTAPS_SBA]'], real(squeeze(FastConv_SHD_IR_FOA.IR(1,:,:,:)))); + writeData3L(fid, ['const float leftHRIRImag_' FastConv_SHD_IR_FOA.order '[BINAURAL_CONVBANDS][' FastConv_SHD_IR_FOA.order '_CHANNELS][BINAURAL_NTAPS_SBA]'], imag(squeeze(FastConv_SHD_IR_FOA.IR(1,:,:,:)))); + writeData3L(fid, ['const float rightHRIRReal_' FastConv_SHD_IR_FOA.order '[BINAURAL_CONVBANDS][' FastConv_SHD_IR_FOA.order '_CHANNELS][BINAURAL_NTAPS_SBA]'], real(squeeze(FastConv_SHD_IR_FOA.IR(2,:,:,:)))); + writeData3L(fid, ['const float rightHRIRImag_' FastConv_SHD_IR_FOA.order '[BINAURAL_CONVBANDS][' FastConv_SHD_IR_FOA.order '_CHANNELS][BINAURAL_NTAPS_SBA]'], imag(squeeze(FastConv_SHD_IR_FOA.IR(2,:,:,:)))); + + %% HRIRs (SD) + fprintf(fid, 'const float FASTCONV_HRIR_latency_s = %10.9ff;\n', FastConv_SD_IR.latency_s); + writeData3L(fid, 'const float leftHRIRReal[BINAURAL_CONVBANDS][HRTF_LS_CHANNELS][BINAURAL_NTAPS]', real(squeeze(FastConv_SD_IR.IR(1,:,:,:)))); + writeData3L(fid, 'const float leftHRIRImag[BINAURAL_CONVBANDS][HRTF_LS_CHANNELS][BINAURAL_NTAPS]', imag(squeeze(FastConv_SD_IR.IR(1,:,:,:)))); + writeData3L(fid, 'const float rightHRIRReal[BINAURAL_CONVBANDS][HRTF_LS_CHANNELS][BINAURAL_NTAPS]', real(squeeze(FastConv_SD_IR.IR(2,:,:,:)))); + writeData3L(fid, 'const float rightHRIRImag[BINAURAL_CONVBANDS][HRTF_LS_CHANNELS][BINAURAL_NTAPS]', imag(squeeze(FastConv_SD_IR.IR(2,:,:,:)))); + + %% BRIRs (SD) + fprintf(fid, '/* Binaural rendering data set based on BRIRs \n'); + fprintf(fid, ' * Tables derived from Mozart IIS BRIRs.*/\n'); + fprintf(fid, 'const float FASTCONV_BRIR_latency_s = %10.9ff;\n', FastConv_SD_BRIR.rev_param.latency_s); + writeData3L(fid, 'const float leftBRIRReal[BINAURAL_CONVBANDS][HRTF_LS_CHANNELS][BINAURAL_NTAPS_MAX]', real(squeeze(FastConv_SD_BRIR.IR(1,:,:,1:FastConv_SD_BRIR.rev_param.NFilter)))); + writeData3L(fid, 'const float leftBRIRImag[BINAURAL_CONVBANDS][HRTF_LS_CHANNELS][BINAURAL_NTAPS_MAX]', imag(squeeze(FastConv_SD_BRIR.IR(1,:,:,1:FastConv_SD_BRIR.rev_param.NFilter)))); + writeData3L(fid, 'const float rightBRIRReal[BINAURAL_CONVBANDS][HRTF_LS_CHANNELS][BINAURAL_NTAPS_MAX]', real(squeeze(FastConv_SD_BRIR.IR(2,:,:,1:FastConv_SD_BRIR.rev_param.NFilter)))); + writeData3L(fid, 'const float rightBRIRImag[BINAURAL_CONVBANDS][HRTF_LS_CHANNELS][BINAURAL_NTAPS_MAX]', imag(squeeze(FastConv_SD_BRIR.IR(2,:,:,1:FastConv_SD_BRIR.rev_param.NFilter)))); + + % RT60 + fprintf(fid,'const float fastconvReverberationTimes[CLDFB_NO_CHANNELS_MAX] = \n{'); + fprintf(fid,'\n\t'); + for bandIdx = 1:FastConv_SD_BRIR.rev_param.kAna + fprintf(fid,'%f%s, ', FastConv_SD_BRIR.rev_param.rt60(bandIdx),'f'); + end + fprintf(fid,'\n};\n'); + fprintf(fid,'\n\n'); + + % energyReverb + fprintf(fid,'const float fastconvReverberationEneCorrections[CLDFB_NO_CHANNELS_MAX] = \n{'); + fprintf(fid,'\n\t'); + for bandIdx = 1:FastConv_SD_BRIR.rev_param.kAna + fprintf(fid,'%f%s, ', FastConv_SD_BRIR.rev_param.nrgLr(bandIdx),'f'); + end + fprintf(fid,'\n};\n'); + fprintf(fid,'\n\n'); + + fclose(fid); + +end \ No newline at end of file diff --git a/scripts/binauralRenderer_interface/generate_crend_ivas_tables_from_sofa.c b/scripts/binauralRenderer_interface/generate_crend_ivas_tables_from_sofa.c index a5b86d8698cea7e5ff4d3e264b3626600a7b57e4..0d9b03fa2f5d3220f5e4181cf60ff5737e56316e 100644 --- a/scripts/binauralRenderer_interface/generate_crend_ivas_tables_from_sofa.c +++ b/scripts/binauralRenderer_interface/generate_crend_ivas_tables_from_sofa.c @@ -29,54 +29,77 @@ the United Nations Convention on Contracts on the International Sales of Goods. *******************************************************************************************************/ - -#include -#include #include - +#include +#ifdef _WIN32 +#include +#define getcwd _getcwd +#define MAX_PATH _MAX_PATH +#else +#include +#define MAX_PATH PATH_MAX +#endif +#ifdef _WIN32 #define _USE_MATH_DEFINES +#endif #include - -#include #include "options.h" #include "ivas_cnst.h" #include "prot.h" #include "ivas_prot.h" +#include "ivas_prot_rend.h" #include "ivas_stat_dec.h" #include "lib_dec.h" #include "ivas_rom_com.h" +#include "ivas_rom_rend.h" #include "cmdl_tools.h" +#include "config_reader.h" #include "ivas_crend_binaural_filter_design.h" #ifdef M #undef M #endif -#include "hrtf/mysofa.h" - +#include "mat.h" +#ifdef USE_MATLAB_ENG +#include "engine.h" +#endif /*------------------------------------------------------------------------------------------* * Constants *------------------------------------------------------------------------------------------*/ -#define MAX_DIFF_AZI 1 /* angle in degree */ -#define MAX_DIFF_ELE 10 /* angle in degree */ -#define DEFAULT_SAMPLERATE 48000 /* Hz */ -#define TEMPLTATE_C_ROM_FILE_NAME "ivas_rom_binaural_crend_head.template" -#define FORCE_COPY_TO_LIB_DEC -#define ROM_FILE_NAME "ivas_rom_binaural_crend_head" -#define FORMAT_FLOAT "%8.6f" -#define NUM_SAMPLES_PER_LINES 96 -#define DECLARATION_NAME "CRendBin" -#define TAB_WITH_SPACE_OR_NOT " " /* "\t" */ +#define MAX_DIFF_AZI 1 /* angle in degree */ +#define MAX_DIFF_ELE 10 /* angle in degree */ +#define DEFAULT_SAMPLERATE 48000 /* Hz */ +#define TEMPLTATE_C_ROM_FILE_NAME "ivas_license_header.template" +#define ROM_FILE_NAME "ivas_rom_binaural_crend_head" +#define FORMAT_FLOAT "%8.6f" +#define NUM_SAMPLES_PER_LINES 96 +#define NUM_SAMPLES_PER_LINES_REVERB 9 +#define DECLARATION_NAME "CRendBin" +#define TAB_WITH_SPACE_OR_NOT " " /* "\t" */ +#define NUM_ITERATIONS_TO_ALLOW_OPTIM_5_MS 5 /* no optimisation if hrir length is lower then 20 ms*/ +#define NUM_ITERATIONS_TO_ALLOW_OPTIM_20_MS 1 /* no optimisation if hrir length is lower then 20 ms*/ int32_t sample_rates[3] = { DEFAULT_SAMPLERATE, 32000, 16000 }; /* Hz */ /* 8000 Hz not supported by mdft */ +char *binary_file_path = NULL; +char *lib_rend_path = NULL; + +#define DEFAULT_BINARY_FILE_NAME "crend" +#ifdef _WIN32 +#define DEFAULT_BINARY_FILE_PATH ".\\bin" +#else +#define DEFAULT_BINARY_FILE_PATH "./bin" +#endif + /* ------------------------------------------------------------------------------------------ * Struct *------------------------------------------------------------------------------------------ */ struct ivas_layout_config { + AUDIO_CONFIG audio_config; char name[32]; int nb_channel; float azi[MAX_CICP_CHANNELS]; @@ -89,17 +112,31 @@ struct ivas_layout_config }; +typedef struct _crend_hrtf_tables_dimensions +{ + int16_t max_num_ir; + int16_t max_num_iterations; + int16_t max_num_iterations_diffuse; + uint16_t max_total_num_fsamp_per_iteration; + uint16_t max_total_num_fsamp_per_iteration_diff; + +} crend_hrtf_tables_dimensions; + /*---------------------------------------------------------------------* * Local function prototypes *---------------------------------------------------------------------*/ char *to_upper( char *str ); void usage_gen_crend_tables( void ); -void get_ls_layout_config( IVAS_DEC_AUDIO_CONFIG ls_layout_config, struct ivas_layout_config *ls_struct ); -int generate_crend_ivas_tables_from_sofa( const char *sofa_file_path, bool no_optim ); +void get_ls_layout_config( AUDIO_CONFIG ls_layout_config, struct ivas_layout_config *ls_struct ); +int generate_crend_ivas_tables_from_sofa( const char *sofa_file_path, ConfigReader *cfgReader ); void update_h_file( HRTFS_DATA *hrtf, struct ivas_layout_config lscfg, const int32_t samplerate, const int16_t frame_len ); void update_c_file( HRTFS_DATA *hrtf, struct ivas_layout_config lscfg, const int32_t samplerate, const int16_t frame_len ); +void get_binary_tables_dimensions( HRTFS_DATA *hrtf, crend_hrtf_tables_dimensions *hrtf_table_dims /*OUT*/ ); +uint32_t compute_binary_size( HRTFS_DATA *hrtf, crend_hrtf_tables_dimensions *hrtf_table_dims ); +void write_binary_file( HRTFS_DATA *hrtf, struct ivas_layout_config lscfg, const int32_t samplerate, const int16_t frame_len ); + /*---------------------------------------------------------------------* * * Avoid compiling all decoder create a false get_next_indice function @@ -122,6 +159,30 @@ uint16_t get_next_indice( return 0; } +bool read_compensation_gains( char *file, float *gains ) +{ + FILE *fp = NULL; + int16_t i = 0; + if ( gains == NULL ) + { + return false; + } + fp = fopen( file, "rt" ); + if ( fp == NULL ) + { + return false; + } + + i = 0; + + while ( ( fscanf( fp, "%f\n", &gains[i] ) != EOF ) && ( i < MAX_OUTPUT_CHANNELS ) ) + { + i++; + } + + return true; +} + /*---------------------------------------------------------------------* * usage_gen_crend_tables() @@ -135,13 +196,21 @@ void usage_gen_crend_tables( void ) fprintf( stdout, "Mandatory parameters:\n" ); fprintf( stdout, "---------------------\n" ); - fprintf( stdout, "frame_length_ms : frame size in ms (5 or 20)" ); - fprintf( stdout, "sofa_file_path1 sofa_file_path2 ... : paths of the sofa files to process %ld Hz sample rate mandatory\n", (long) DEFAULT_SAMPLERATE ); + fprintf( stdout, "frame_length_ms : frame size in ms (5 or 20)\n" ); + fprintf( stdout, "sofa_file_path1 sofa_file_path2 ... : paths of the sofa files to process %ld Hz sample rate preferred resample otherwise\n", (long) DEFAULT_SAMPLERATE ); fprintf( stdout, "Options:\n" ); fprintf( stdout, "--------\n" ); - fprintf( stdout, "-lib_rend_path path : path where header and c files will be created (lib_dec forlder for example, default = './')\n" ); - fprintf( stdout, "-no_optim : if present no BRIR optimisation is perfromed \n" ); + fprintf( stdout, "-lib_rend_path : path where header and c files will be created (if missing rom files not generated)\n" ); + fprintf( stdout, "-binary_files_path : path where binary files will be created (if missing binary files not generated)\n" ); + fprintf( stdout, "-binary_common_file_name : common name for binary files that will be created (crend_hrir-53_brir-Fhg for example)\n" ); + fprintf( stdout, "-brir_optim_config_path config_file_path : if present brir optimisation process uses parameters stored in config_file_path \n\t\t\t\t\t\tConfiguration example files are provided in folder :\n\t\t\t\t\t\t-brir_no_optim.cfg : for exact convolution of the BRIR by IVAS decoder or renderer\n\t\t\t\t\t\t-brir_default_optim.cfg : default values BRIR optimisation used by IVAS decoder or renderer\n\t\t\t\t\t\t-brir_low_complexity_optim.cfg : values for BRIR optimisation reducing IVAS decoder or renderer complexity\n" ); + fprintf( stdout, "example:\n" ); +#ifdef _WIN32 + fprintf( stdout, "%s\n", ".\\generate_crend_ivas_tables.exe -lib_rend_path ../../lib_rend 5 ./HRIRs_sofa/HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000.mat ./HRIRs_sofa/HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000_FOA.mat ./HRIRs_sofa/HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000_HOA2.mat ./HRIRs_sofa/HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000_HOA3.mat ./BRIRs_sofa/IIS_BRIR_officialMPEG_Combined.mat\n" ); +#else + fprintf( stdout, "%s\n", "./generate_crend_ivas_tables -lib_rend_path ../../lib_rend 5 ./HRIRs_sofa/HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000.mat ./HRIRs_sofa/HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000_FOA.mat ./HRIRs_sofa/HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000_HAO2.mat ./HRIRs_sofa/HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000_HOA3.mat ./BRIRs_sofa/IIS_BRIR_officialMPEG_Combined.mat\n" ); +#endif fprintf( stdout, "\n" ); } @@ -172,13 +241,32 @@ int main( int argc, char *argv[] ) FILE *fp = NULL; - char *lib_rend_path = NULL; - bool no_optim = false; + ConfigReader cfgBrirOptim = { 0 }; + + char *binary_path = NULL; + char *binary_common_file_name = NULL; + int binPathNotEndingWithSeparator = 0; + char *brir_optim_config_path = NULL; bool add_define = false; - int notEndingWithSeparator = 0; + int notEndingWithFileSeparator = 0; char *sofa_name = NULL; - int i = 1; + int i; + cfgBrirOptim.beginEnergyThreshold = DEFAULT_BEGIN_ENERGY_THRESHOLD; + cfgBrirOptim.diffuseCutOffFreqThreshold = DEFAULT_DIFFUSE_CUT_OFF_FREQ_THRESHOLD; + cfgBrirOptim.diffuseEnergyThreshold = DEFAULT_DIFFUSE_ENERGY_THRESHOLD; + cfgBrirOptim.directCutOffFreqThreshold = DEFAULT_DIRECT_CUT_OFF_FREQ_THRESHOLD; + cfgBrirOptim.directEnergyThreshold = DEFAULT_DIRECT_ENERGY_THRESHOLD; + cfgBrirOptim.endEnergyThreshold = DEFAULT_END_ENERGY_THRESHOLD; + cfgBrirOptim.harmonizeLateReverbBinauralGain = 1; + cfgBrirOptim.optimize = 1; + + for ( i = 0; i < MAX_INTERN_CHANNELS; i++ ) + { + cfgBrirOptim.lateReverbCompensationGain[i] = 1.f; + } + + i = 1; /* Optional arguments */ while ( argv[i][0] == '-' ) { @@ -187,18 +275,42 @@ int main( int argc, char *argv[] ) i++; if ( strlen( argv[i] ) == 0 ) { - fprintf( stderr, "Wrong lib_dec path: %s\n\n", argv[i] ); + fprintf( stderr, "Wrong lib_rend path: %s\n\n", argv[i] ); usage_gen_crend_tables(); return -1; } lib_rend_path = malloc( strlen( argv[i] ) + 1 ); + convert_backslash( argv[i] ); strcpy( lib_rend_path, argv[i] ); - notEndingWithSeparator = ( ( argv[i][strlen( argv[i] ) - 1] == '\\' ) || ( ( argv[i][strlen( argv[i] ) - 1] == '/' ) ) ) ? 0 : 1; + notEndingWithFileSeparator = ( ( argv[i][strlen( argv[i] ) - 1] == '\\' ) || ( ( argv[i][strlen( argv[i] ) - 1] == '/' ) ) ) ? 0 : 1; + i++; + } + else if ( strcmp( to_upper( argv[i] ), "-BINARY_FILES_PATH" ) == 0 ) + { + i++; + if ( strlen( argv[i] ) == 0 ) + { + fprintf( stderr, "Wrong binary path: %s\n\n", argv[i] ); + usage_gen_crend_tables(); + return -1; + } + convert_backslash( argv[i] ); + binary_path = malloc( strlen( argv[i] ) + 1 ); + strcpy( binary_path, argv[i] ); + binPathNotEndingWithSeparator = ( ( argv[i][strlen( argv[i] ) - 1] == '\\' ) || ( ( argv[i][strlen( argv[i] ) - 1] == '/' ) ) ) ? 0 : 1; i++; } - else if ( strcmp( to_upper( argv[i] ), "-NO_OPTIM" ) == 0 ) + else if ( strcmp( to_upper( argv[i] ), "-BINARY_COMMON_FILE_NAME" ) == 0 ) { - no_optim = true; + i++; + if ( strlen( argv[i] ) == 0 ) + { + fprintf( stderr, "Wrong binary name: %s\n\n", argv[i] ); + usage_gen_crend_tables(); + return -1; + } + binary_common_file_name = malloc( strlen( argv[i] ) + 1 ); + strcpy( binary_common_file_name, argv[i] ); i++; } else if ( strcmp( to_upper( argv[i] ), "-ADD_DEFINE" ) == 0 ) @@ -220,10 +332,13 @@ int main( int argc, char *argv[] ) usage_gen_crend_tables(); if ( lib_rend_path ) free( lib_rend_path ); + if ( binary_path ) + free( binary_path ); + if ( binary_common_file_name ) + free( binary_common_file_name ); return -1; } - frame_len_ms = atoi( argv[i] ); - i++; + frame_len_ms = atoi( argv[i++] ); if ( ( frame_len_ms != 5 ) && ( frame_len_ms != 20 ) ) { @@ -231,6 +346,10 @@ int main( int argc, char *argv[] ) usage_gen_crend_tables(); if ( lib_rend_path ) free( lib_rend_path ); + if ( binary_path ) + free( binary_path ); + if ( binary_common_file_name ) + free( binary_common_file_name ); return -1; } @@ -246,15 +365,19 @@ int main( int argc, char *argv[] ) usage_gen_crend_tables(); if ( lib_rend_path ) free( lib_rend_path ); + if ( binary_path ) + free( binary_path ); + if ( binary_common_file_name ) + free( binary_common_file_name ); return -1; } if ( lib_rend_path ) { - c_file_path = (char *) malloc( sizeof( char ) * ( strlen( lib_rend_path ) + strlen( ROM_FILE_NAME ) + 2 + 1 + notEndingWithSeparator ) ); + c_file_path = (char *) malloc( sizeof( char ) * ( strlen( lib_rend_path ) + strlen( ROM_FILE_NAME ) + 2 + 1 + notEndingWithFileSeparator ) ); if ( c_file_path ) { - if ( notEndingWithSeparator ) + if ( notEndingWithFileSeparator ) { #ifdef WIN32 sprintf( c_file_path, "%s\\%s.c", lib_rend_path, ROM_FILE_NAME ); @@ -277,25 +400,33 @@ int main( int argc, char *argv[] ) usage_gen_crend_tables(); if ( lib_rend_path ) free( lib_rend_path ); + if ( binary_path ) + free( binary_path ); + if ( binary_common_file_name ) + free( binary_common_file_name ); return -1; } fp = fopen( c_file_path, "w" ); if ( fp == NULL ) { - fprintf( stderr, "Wrong lib_dec path: %s\n\n", lib_rend_path ); + fprintf( stderr, "Wrong lib_rend path: %s\n\n", lib_rend_path ); usage_gen_crend_tables(); if ( c_file_path ) free( c_file_path ); if ( lib_rend_path ) free( lib_rend_path ); + if ( binary_path ) + free( binary_path ); + if ( binary_common_file_name ) + free( binary_common_file_name ); return -1; } fclose( fp ); - h_file_path = (char *) malloc( sizeof( char ) * ( strlen( lib_rend_path ) + strlen( ROM_FILE_NAME ) + 2 + 1 + notEndingWithSeparator ) ); + h_file_path = (char *) malloc( sizeof( char ) * ( strlen( lib_rend_path ) + strlen( ROM_FILE_NAME ) + 2 + 1 + notEndingWithFileSeparator ) ); if ( h_file_path ) { - if ( notEndingWithSeparator ) + if ( notEndingWithFileSeparator ) { #ifdef WIN32 sprintf( h_file_path, "%s\\%s.h", lib_rend_path, ROM_FILE_NAME ); @@ -306,9 +437,9 @@ int main( int argc, char *argv[] ) else { #ifdef WIN32 - sprintf( h_file_path, "%s\\%s.h", lib_rend_path, ROM_FILE_NAME ); + sprintf( h_file_path, "%s%s.h", lib_rend_path, ROM_FILE_NAME ); #else - sprintf( h_file_path, "%s/%s.h", lib_rend_path, ROM_FILE_NAME ); + sprintf( h_file_path, "%s%s.h", lib_rend_path, ROM_FILE_NAME ); #endif } } @@ -320,12 +451,16 @@ int main( int argc, char *argv[] ) free( c_file_path ); if ( lib_rend_path ) free( lib_rend_path ); + if ( binary_path ) + free( binary_path ); + if ( binary_common_file_name ) + free( binary_common_file_name ); return -1; } fp = fopen( h_file_path, "w" ); if ( fp == NULL ) { - fprintf( stderr, "Wrong lib_dec path: %s\n\n", lib_rend_path ); + fprintf( stderr, "Wrong lib_rend path: %s\n\n", lib_rend_path ); usage_gen_crend_tables(); if ( h_file_path ) free( h_file_path ); @@ -333,165 +468,330 @@ int main( int argc, char *argv[] ) free( c_file_path ); if ( lib_rend_path ) free( lib_rend_path ); + if ( binary_path ) + free( binary_path ); + if ( binary_common_file_name ) + free( binary_common_file_name ); return -1; } fclose( fp ); } - if ( c_file_path == NULL ) + if ( binary_common_file_name == NULL ) { - size_t len = ( strlen( ROM_FILE_NAME ) + 5 + ( no_optim ? strlen( "_no_optim" ) : 0 ) + 2 + 1 ); - c_file_path = (char *) malloc( sizeof( char ) * len ); - sprintf( c_file_path, "%s_%02dms%s.c", ROM_FILE_NAME, frame_len_ms, ( no_optim ? "_no_optim" : "" ) ); - c_file_path[len - 1] = '\0'; + binary_common_file_name = malloc( strlen( DEFAULT_BINARY_FILE_NAME ) + 1 ); + strcpy( binary_common_file_name, DEFAULT_BINARY_FILE_NAME ); } - if ( h_file_path == NULL ) + + if ( binary_path == NULL ) { - size_t len = ( strlen( ROM_FILE_NAME ) + 5 + ( no_optim ? strlen( "_no_optim" ) : 0 ) + 2 + 1 ); - h_file_path = (char *) malloc( sizeof( char ) * len ); - sprintf( h_file_path, "%s_%02dms%s.h", ROM_FILE_NAME, frame_len_ms, ( no_optim ? "_no_optim" : "" ) ); - h_file_path[len - 1] = '\0'; + binary_path = malloc( strlen( DEFAULT_BINARY_FILE_PATH ) + 1 ); + strcpy( binary_path, DEFAULT_BINARY_FILE_PATH ); + binPathNotEndingWithSeparator = 1; } - FILE *fpt = fopen( TEMPLTATE_C_ROM_FILE_NAME, "rb" ); - - if ( fpt ) + if ( binary_path ) { - fseek( fpt, 0, SEEK_END ); - size_t fsize = ftell( fpt ); - fseek( fpt, 0, SEEK_SET ); - char *tmpc = (char *) malloc( fsize + 1 ); - size_t ret = fread( tmpc, fsize, 1, fpt ); - tmpc[fsize] = '\0'; - if ( ret * fsize == fsize ) + if ( binary_file_path != NULL ) { - fp = fopen( c_file_path, "wb" ); - if ( fp ) + free( binary_file_path ); + binary_file_path = NULL; + } + binary_file_path = (char *) malloc( sizeof( char ) * ( strlen( binary_path ) + strlen( binary_common_file_name ) + 2 + 1 + notEndingWithFileSeparator ) ); + + if ( binary_file_path ) + { + if ( binPathNotEndingWithSeparator ) { - fwrite( tmpc, fsize, 1, fp ); - fclose( fp ); +#ifdef WIN32 + sprintf( binary_file_path, "%s\\%s", binary_path, binary_common_file_name ); +#else + sprintf( binary_file_path, "%s/%s", binary_path, binary_common_file_name ); +#endif } - - fp = fopen( h_file_path, "wb" ); - if ( fp ) + else { - fwrite( tmpc, fsize, 1, fp ); - fclose( fp ); +#ifdef WIN32 + sprintf( binary_file_path, "%s%s", binary_path, binary_common_file_name ); +#else + sprintf( binary_file_path, "%s%s", binary_path, binary_common_file_name ); +#endif } } - - fclose( fpt ); - } - fp = fopen( h_file_path, "a" ); - if ( fp ) - { - fprintf( fp, "\n#ifndef _%s_\n", to_upper( rom_file_name ) ); - fprintf( fp, "#define _%s_\n", to_upper( rom_file_name ) ); - fprintf( fp, "\n#include \n#include \"cnst.h\"\n#include \"ivas_cnst.h\"\n" ); - fclose( fp ); + else + { + fprintf( stderr, "Memory issue for binary file path\n\n" ); + usage_gen_crend_tables(); + if ( h_file_path ) + free( h_file_path ); + if ( c_file_path ) + free( c_file_path ); + if ( lib_rend_path ) + free( lib_rend_path ); + if ( binary_path ) + free( binary_path ); + if ( binary_common_file_name ) + free( binary_common_file_name ); + return -1; + } } - fp = fopen( c_file_path, "a" ); - if ( fp ) + if ( ( h_file_path != NULL ) && ( c_file_path != NULL ) ) { - fprintf( fp, "\n#include \n#include \n#include \"cnst.h\"\n#include \"ivas_cnst.h\"\n" ); - fclose( fp ); + + FILE *fpt = fopen( TEMPLTATE_C_ROM_FILE_NAME, "rb" ); + + if ( fpt ) + { + fseek( fpt, 0, SEEK_END ); + size_t fsize = ftell( fpt ); + fseek( fpt, 0, SEEK_SET ); + char *tmpc = (char *) malloc( fsize + 1 ); + size_t ret = fread( tmpc, fsize, 1, fpt ); + tmpc[fsize] = '\0'; + if ( ret * fsize == fsize ) + { + fp = fopen( c_file_path, "wb" ); + if ( fp ) + { + fwrite( tmpc, fsize, 1, fp ); + fclose( fp ); + } + + fp = fopen( h_file_path, "wb" ); + if ( fp ) + { + fwrite( tmpc, fsize, 1, fp ); + fclose( fp ); + } + } + + fclose( fpt ); + } + fp = fopen( h_file_path, "a" ); + if ( fp ) + { + fprintf( fp, "\n/* clang-format off */\n" ); + fprintf( fp, "\n/*-------------------------------------------------------------------------" ); + fprintf( fp, "\n* Binaural rendering related ROM tables" ); + fprintf( fp, "\n*------------------------------------------------------------------------*/\n" ); + fprintf( fp, "\n/* Binaural rendering data set based on HRIRs */" ); + fprintf( fp, "\n/* Tables generated by scripts/binauralRenderer_interface/generate_cren_ivas_tables.c, see mixer_conv_sofa_to_rom_table_converter_readme.txt */" ); + fprintf( fp, "\n/* Can be replaced by your own generated HRIR or BRIR tables */\n\n\n" ); + fprintf( fp, "\n#ifndef _%s_\n", to_upper( rom_file_name ) ); + fprintf( fp, "#define _%s_\n", to_upper( rom_file_name ) ); + fprintf( fp, "\n#include \"ivas_cnst.h\"\n\n" ); + fclose( fp ); + } + + fp = fopen( c_file_path, "a" ); + if ( fp ) + { + fprintf( fp, "\n/* clang-format off */\n" ); + fprintf( fp, "\n/*-------------------------------------------------------------------------" ); + fprintf( fp, "\n* Binaural rendering related ROM tables" ); + fprintf( fp, "\n*------------------------------------------------------------------------*/\n" ); + fprintf( fp, "\n/* Binaural rendering data set based on HRIRs */" ); + fprintf( fp, "\n/* Tables generated by scripts/binauralRenderer_interface/generate_cren_ivas_tables.c, see mixer_conv_sofa_to_rom_table_converter_readme.txt */" ); + fprintf( fp, "\n/* Can be replaced by your own generated HRIR or BRIR tables */\n\n\n" ); + fprintf( fp, "\n#include \n#include \"ivas_cnst.h\"\n\n/* clang-format off */\n\n#define WMC_TOOL_SKIP\n\n" ); + fclose( fp ); + } } + + char current_path[MAX_PATH]; + char ivas_path[MAX_PATH]; + + getcwd( current_path, MAX_PATH ); + strcpy( ivas_path, current_path ); +#ifdef _WIN32 + char *tmpstr = strstr( ivas_path, "\\binauralRenderer_interface" ); +#else + char *tmpstr = strstr( ivas_path, "/binauralRenderer_interface" ); +#endif + tmpstr[0] = '\0'; + int err = 0; for ( ; i < argc; i++ ) { - if ( add_define ) + if ( ( h_file_path != NULL ) && ( c_file_path != NULL ) ) { - fp = fopen( c_file_path, "a" ); - if ( fp ) + if ( add_define ) { - sofa_name = strrchr( argv[i], '/' ); - size_t size_path = strlen( sofa_name ); - sofa_name = malloc( sizeof( char ) * size_path - 5 ); - strncpy( sofa_name, strrchr( argv[i], '/' ) + 1, size_path - 5 ); - sofa_name[size_path - 6] = '\0'; - fprintf( fp, "\n#ifdef USE_%s\n", to_upper( sofa_name ) ); - fclose( fp ); + fp = fopen( c_file_path, "a" ); + if ( fp ) + { + sofa_name = strrchr( argv[i], '/' ); + size_t size_path = strlen( sofa_name ); + sofa_name = malloc( sizeof( char ) * size_path - 5 ); + strncpy( sofa_name, strrchr( argv[i], '/' ) + 1, size_path - 5 ); + sofa_name[size_path - 6] = '\0'; + fprintf( fp, "\n#ifdef USE_%s\n", to_upper( sofa_name ) ); + fclose( fp ); + } + fp = fopen( h_file_path, "a" ); + if ( fp ) + { + fprintf( fp, "\n#ifdef USE_%s\n", to_upper( sofa_name ) ); + fclose( fp ); + } } - fp = fopen( h_file_path, "a" ); - if ( fp ) + } + +#ifdef USE_MATLAB_ENG + Engine *ep = NULL; + char *tmpChar = strstr( argv[i], ".sofa" ); + if ( tmpChar != NULL ) + { + if ( !( ep = engOpen( NULL ) ) ) { - fprintf( fp, "\n#ifdef USE_%s\n", to_upper( sofa_name ) ); - fclose( fp ); + printf( "Error starting matlab engine\n" ); + return -1; } + const char addPathCmdStr[] = "addpath(['.' filesep() 'matlab_hrir_generation_scripts']);"; + const char startCmdStr[] = "SOFA_save_to_mat('"; + const char endCmdStr[] = "');"; + char *cdCmd; + char *cmdStr; + int ret; + cdCmd = (char *) malloc( strlen( current_path ) + 4 ); + sprintf( cdCmd, "cd %s", current_path ); + cmdStr = (char *) malloc( strlen( startCmdStr ) + strlen( argv[i] ) + strlen( endCmdStr ) + 1 ); + sprintf( cmdStr, "%s%s%s", startCmdStr, argv[i], endCmdStr ); + + ret = engEvalString( ep, cdCmd ); + ret = engEvalString( ep, addPathCmdStr ); + ret = engEvalString( ep, cmdStr ); + + strcpy( tmpChar, ".mat" ); + tmpChar[4] = '\0'; + + free( cdCmd ); + free( cmdStr ); + engClose( ep ); } - err = generate_crend_ivas_tables_from_sofa( argv[i], no_optim ); + +#endif + convert_backslash( argv[i] ); + + err = generate_crend_ivas_tables_from_sofa( argv[i], &cfgBrirOptim ); if ( err != 0 ) return err; - if ( add_define ) + + if ( ( h_file_path != NULL ) && ( c_file_path != NULL ) ) { + fp = fopen( c_file_path, "a" ); if ( fp ) { - fprintf( fp, "\n#endif /* USE_%s */\n", to_upper( sofa_name ) ); + fprintf( fp, "\n\n" ); fclose( fp ); } fp = fopen( h_file_path, "a" ); if ( fp ) { - fprintf( fp, "\n#endif /* USE_%s */\n", to_upper( sofa_name ) ); + fprintf( fp, "\n\n" ); fclose( fp ); } + if ( err != 0 ) + return err; + if ( add_define ) + { + fp = fopen( c_file_path, "a" ); + if ( fp ) + { + fprintf( fp, "\n#endif /* USE_%s */\n ", to_upper( sofa_name ) ); + fclose( fp ); + } + fp = fopen( h_file_path, "a" ); + if ( fp ) + { + fprintf( fp, "\n#endif /* USE_%s */\n", to_upper( sofa_name ) ); + fclose( fp ); + } + } } } - fp = fopen( h_file_path, "a" ); - if ( fp ) - { - fprintf( fp, "\n#endif /* _%s_ */\n", to_upper( rom_file_name ) ); - fclose( fp ); - } - fp = fopen( c_file_path, "a" ); - if ( fp ) + if ( ( h_file_path != NULL ) && ( c_file_path != NULL ) ) { - fprintf( fp, "\n\n" ); - fclose( fp ); - } + fp = fopen( h_file_path, "a" ); + if ( fp ) + { + fprintf( fp, "\n\n#endif /* _%s_ */\n", to_upper( rom_file_name ) ); + fclose( fp ); + } + + fp = fopen( c_file_path, "a" ); + if ( fp ) + { + fprintf( fp, "\n\n#undef WMC_TOOL_SKIP\n\n" ); + fclose( fp ); + } + } if ( c_file_path ) free( c_file_path ); if ( h_file_path ) free( h_file_path ); if ( rom_file_name ) free( rom_file_name ); + + if ( binary_path ) + free( binary_path ); + if ( binary_common_file_name ) + free( binary_common_file_name ); + if ( binary_file_path ) + free( binary_file_path ); + return err; } -struct MYSOFA_ARRAY *mysofa_getVariable( struct MYSOFA_VARIABLE *attr, char *name ) +int32_t find_pos_spheric( const double *Source_Position_Cartesian, int32_t numPos, const double dir_spheric[3] ) { - while ( attr ) - { - if ( attr->name && !strcmp( name, attr->name ) ) + double valmax = 0; + int32_t indmax = -1; + int32_t ind; + double dir_cart[3]; + double tmp; + dir_cart[0] = ( dir_spheric[2] * cos( dir_spheric[0] * M_PI / 180. ) * cos( dir_spheric[1] * M_PI / 180. ) ); + dir_cart[1] = ( dir_spheric[2] * sin( dir_spheric[0] * M_PI / 180. ) * cos( dir_spheric[1] * M_PI / 180. ) ); + dir_cart[2] = dir_spheric[2] * sin( dir_spheric[1] * M_PI / 180. ); + + for ( ind = 0; ind < numPos; ind++ ) + { + tmp = Source_Position_Cartesian[ind * 3] * dir_cart[0] + Source_Position_Cartesian[ind * 3 + 1] * dir_cart[1] + Source_Position_Cartesian[ind * 3 + 2] * dir_cart[2]; + if ( tmp > valmax ) { - return attr->value; + valmax = tmp; + indmax = ind; } - attr = attr->next; } - return NULL; + return indmax; } -int generate_crend_ivas_tables_from_sofa( const char *file_path, bool no_optim ) +int generate_crend_ivas_tables_from_sofa( const char *file_path, ConfigReader *cfgReader ) { char *sofa_file_path = NULL; - int err; int i, indSR; - unsigned ui; - - struct MYSOFA_EASY *hrtf = (struct MYSOFA_EASY *) malloc( sizeof( struct MYSOFA_EASY ) ); - if ( !hrtf ) - return 1234; - memset( hrtf, 0, sizeof( struct MYSOFA_EASY ) ); + int32_t sofa_M, sofa_N, sofa_R, sofa_N_48k; + const char *sofaDataBaseName = ""; + const char *sofaListenerName = ""; + double *data_IR_current = NULL; + double *sofa_data_IR_val_48k = NULL; + double *sofa_data_IR_val_32k = NULL; + double *sofa_data_IR_val_16k = NULL; + double *sofa_latencys = NULL; + double *sofa_delay_val = NULL; + double *sofa_src_pos_val = NULL; + double *sofa_src_pos_cart_val = NULL; + + long sofa_sample_rate = 0; + double a[3] = { 0 }; + double t[3] = { 0 }; + long nearest; - /*------------------------------------------------------------------------------------------* - * Parse command line and initialize renderer - *------------------------------------------------------------------------------------------*/ - /* Optional arguments */ sofa_file_path = (char *) malloc( sizeof( char ) * ( strlen( file_path ) + 1 ) ); if ( sofa_file_path == NULL ) { @@ -500,120 +800,184 @@ int generate_crend_ivas_tables_from_sofa( const char *file_path, bool no_optim ) } strcpy( sofa_file_path, file_path ); - hrtf->hrtf = mysofa_load( sofa_file_path, &err ); - if ( !hrtf->hrtf ) + MATFile *mat_fp = matOpen( sofa_file_path, "r" ); + if ( mat_fp == NULL ) { - mysofa_close( hrtf ); - fprintf( stderr, "Cannot open file %s!\n\n", sofa_file_path ); + printf( "Error reading existing matrix LocalDouble\n" ); usage_gen_crend_tables(); free( sofa_file_path ); - - return err; + return -1; } - hrtf->lookup = NULL; - hrtf->neighborhood = NULL; - hrtf->fir = NULL; - - if ( hrtf->hrtf->DataDelay.elements == hrtf->hrtf->M * hrtf->hrtf->R ) + mxArray *sofa = matGetVariable( mat_fp, "Sofa" ); + if ( sofa == NULL ) { - mysofa_close( hrtf ); - fprintf( stderr, "Wrong file unsupported format delay metadata %s!\n\n", sofa_file_path ); + printf( "Error reading existing matrix LocalDouble\n" ); usage_gen_crend_tables(); free( sofa_file_path ); - + matClose( mat_fp ); return -1; } - if ( hrtf->hrtf->DataSamplingRate.elements > 0 ) + matClose( mat_fp ); + + mwSize total_num_of_elements; + mwIndex index = 0; + int number_of_fields, field_index; + const char *field_name; + const mxArray *data; + const double *sampleRate; + + // total_num_of_elements = mxGetNumberOfElements( sofa ); + number_of_fields = mxGetNumberOfFields( sofa ); + + /* For the given index, walk through each field. */ + for ( field_index = 0; field_index < number_of_fields; field_index++ ) { - int hasWantedSampleRate = 0; - for ( ui = 0; ui < hrtf->hrtf->DataSamplingRate.elements; ui++ ) + // display_subscript( structure_array_ptr, index ); + field_name = mxGetFieldNameByNumber( sofa, + field_index ); + if ( strcmp( field_name, "DatabaseName" ) == 0 ) { - if ( hrtf->hrtf->DataSamplingRate.values[ui] == DEFAULT_SAMPLERATE ) + sofaDataBaseName = mxArrayToUTF8String( mxGetFieldByNumber( sofa, + index, + field_index ) ); + if ( sofaDataBaseName == NULL ) { - hasWantedSampleRate = 1; - break; + printf( "\tEmpty Field for %s\n", field_name ); } } - if ( hasWantedSampleRate == 0 ) + if ( strcmp( field_name, "ListenerShortName" ) == 0 ) { - mysofa_close( hrtf ); - fprintf( stderr, "Wrong file with wrong sample rate %s!\n\n", sofa_file_path ); - usage_gen_crend_tables(); - free( sofa_file_path ); - - return -1; + sofaListenerName = mxArrayToUTF8String( mxGetFieldByNumber( sofa, + index, + field_index ) ); + if ( sofaListenerName == NULL ) + { + printf( "\tEmpty Field for %s\n", field_name ); + } } - } - else - { - mysofa_close( hrtf ); - fprintf( stderr, "Wrong file with wrong sample rate %s!\n\n", sofa_file_path ); - usage_gen_crend_tables(); - free( sofa_file_path ); + if ( strcmp( field_name, "latencys" ) == 0 ) + { + sofa_latencys = mxGetPr( mxGetFieldByNumber( sofa, + index, + field_index ) ); + if ( sofa_latencys == NULL ) + { + printf( "\tEmpty Field for %s\n", field_name ); + } + } + if ( strcmp( field_name, "DataResampled" ) == 0 ) + { + data = mxGetFieldByNumber( sofa, + index, + field_index ); + if ( data == NULL ) + { + mxDestroyArray( sofa ); + printf( "\tEmpty Field for %s\n", field_name ); + free( sofa_file_path ); + return -1; + } - return -1; - } + total_num_of_elements = mxGetNumberOfElements( data ); - /* err = mysofa_check( hrtf->hrtf ); - if ( err != MYSOFA_OK ) - { - mysofa_close( hrtf ); - return err; - }*/ + for ( indSR = 0; indSR < total_num_of_elements; indSR++ ) + { + sampleRate = mxGetPr( mxGetFieldByNumber( data, + indSR, + 1 ) ); + if ( *sampleRate == 48000 ) + { + const mwSize *dims = mxGetDimensions( mxGetFieldByNumber( data, + indSR, + 0 ) ); + sofa_N = sofa_N_48k = (int32_t) dims[0]; + sofa_R = (int32_t) dims[1]; + sofa_M = (int32_t) dims[2]; + sofa_data_IR_val_48k = mxGetPr( mxGetFieldByNumber( data, + indSR, + 0 ) ); + } + if ( *sampleRate == 32000 ) + { + sofa_data_IR_val_32k = mxGetPr( mxGetFieldByNumber( data, + indSR, + 0 ) ); + } + if ( *sampleRate == 16000 ) + { + sofa_data_IR_val_16k = mxGetPr( mxGetFieldByNumber( data, + indSR, + 0 ) ); + } + } + } + if ( strcmp( field_name, "PosCartesian" ) == 0 ) + { + sofa_src_pos_cart_val = mxGetPr( mxGetFieldByNumber( sofa, + index, + field_index ) ); + if ( sofa_src_pos_cart_val == NULL ) + { + mxDestroyArray( sofa ); + printf( "\tEmpty Field for %s\n", field_name ); + free( sofa_file_path ); + return -1; + } + } + if ( strcmp( field_name, "PosSpherical" ) == 0 ) + { + sofa_src_pos_val = mxGetPr( mxGetFieldByNumber( sofa, + index, + field_index ) ); + if ( sofa_src_pos_val == NULL ) + { + mxDestroyArray( sofa ); + printf( "\tEmpty Field for %s\n", field_name ); + free( sofa_file_path ); + return -1; + } + } + } struct ivas_layout_config lscfg; - if ( hrtf->hrtf->M == 4 ) - get_ls_layout_config( IVAS_DEC_OUTPUT_FOA, &lscfg ); - else if ( hrtf->hrtf->M == 9 ) - get_ls_layout_config( IVAS_DEC_OUTPUT_HOA2, &lscfg ); - else if ( hrtf->hrtf->M == 16 ) - get_ls_layout_config( IVAS_DEC_OUTPUT_HOA3, &lscfg ); - else if ( hrtf->hrtf->M == 6 ) - get_ls_layout_config( IVAS_DEC_OUTPUT_5_1, &lscfg ); - else if ( ( hrtf->hrtf->M == 8 ) && ( strstr( sofa_file_path, "710" ) != 0 ) ) - get_ls_layout_config( IVAS_DEC_OUTPUT_7_1, &lscfg ); - else if ( ( hrtf->hrtf->M == 8 ) && ( strstr( sofa_file_path, "512" ) != 0 ) ) - get_ls_layout_config( IVAS_DEC_OUTPUT_5_1_2, &lscfg ); - else if ( hrtf->hrtf->M == 10 ) - get_ls_layout_config( IVAS_DEC_OUTPUT_5_1_4, &lscfg ); - else if ( hrtf->hrtf->M == 12 ) - get_ls_layout_config( IVAS_DEC_OUTPUT_7_1_4, &lscfg ); + if ( sofa_M == 4 ) + get_ls_layout_config( IVAS_AUDIO_CONFIG_FOA, &lscfg ); + else if ( sofa_M == 9 ) + get_ls_layout_config( IVAS_AUDIO_CONFIG_HOA2, &lscfg ); + else if ( sofa_M == 16 ) + get_ls_layout_config( IVAS_AUDIO_CONFIG_HOA3, &lscfg ); + else if ( sofa_M == 6 ) + get_ls_layout_config( IVAS_AUDIO_CONFIG_5_1, &lscfg ); + else if ( ( sofa_M == 8 ) && ( strstr( sofa_file_path, "710" ) != 0 ) ) + get_ls_layout_config( IVAS_AUDIO_CONFIG_7_1, &lscfg ); + else if ( ( sofa_M == 8 ) && ( strstr( sofa_file_path, "512" ) != 0 ) ) + get_ls_layout_config( IVAS_AUDIO_CONFIG_5_1_2, &lscfg ); + else if ( sofa_M == 10 ) + get_ls_layout_config( IVAS_AUDIO_CONFIG_5_1_4, &lscfg ); + else if ( sofa_M == 12 ) + get_ls_layout_config( IVAS_AUDIO_CONFIG_7_1_4, &lscfg ); else - get_ls_layout_config( IVAS_DEC_OUTPUT_EXT, &lscfg ); + get_ls_layout_config( IVAS_AUDIO_CONFIG_EXTERNAL, &lscfg ); /* general information about the loaded HRTF set */ - fprintf( stderr, "Number of HRTFs: %d\n", hrtf->hrtf->M ); - fprintf( stderr, "Filter length: %d samples\n", hrtf->hrtf->N ); - fprintf( stderr, "Database: %s\n", mysofa_getAttribute( hrtf->hrtf->attributes, "DatabaseName" ) ); - fprintf( stderr, "Listener: %s\n", mysofa_getAttribute( hrtf->hrtf->attributes, "ListenerShortName" ) ); - - struct MYSOFA_ARRAY *latency_s = mysofa_getVariable( hrtf->hrtf->variables, "latencys" ); + fprintf( stderr, "Number of HRTFs: %d\n", sofa_M ); + fprintf( stderr, "Filter length: %d samples\n", sofa_N ); + fprintf( stderr, "Database: %s\n", sofaDataBaseName ); + fprintf( stderr, "Listener: %s\n", sofaListenerName ); if ( lscfg.isloudspeaker && ( lscfg.nb_channel > 11 ) ) { - mysofa_tocartesian( hrtf->hrtf ); - - hrtf->lookup = mysofa_lookup_init( hrtf->hrtf ); - if ( hrtf->lookup == NULL ) - { - err = MYSOFA_INTERNAL_ERROR; - mysofa_close( hrtf ); - free( sofa_file_path ); - - return err; - } - hrtf->neighborhood = mysofa_neighborhood_init( hrtf->hrtf, hrtf->lookup ); - fprintf( stderr, "Radius min: %f, max: %f\n", hrtf->lookup->radius_min, hrtf->lookup->radius_max ); + long nearest = 0; } /* get index to a position given in t (in spherical) */ int *index_pos = (int *) malloc( sizeof( int ) * lscfg.nb_channel ); uint32_t maxDel48kHz = 0; if ( index_pos == NULL ) { - mysofa_close( hrtf ); + mxDestroyArray( sofa ); free( sofa_file_path ); fprintf( stderr, "Cannot alloc sofa_file_path !\n\n" ); return -1; @@ -622,19 +986,34 @@ int generate_crend_ivas_tables_from_sofa( const char *file_path, bool no_optim ) { if ( lscfg.isloudspeaker && ( lscfg.nb_channel > 11 ) ) { - float t[3], a[3]; - t[0] = lscfg.azi[i]; /* azimuth in deg */ - t[1] = lscfg.ele[i]; /* elevation in deg */ - t[2] = hrtf->lookup->radius_min; /* radius in m */ - fprintf( stderr, "Wanted Position: %f, %f, %f\n", t[0], t[1], t[2] ); - mysofa_s2c( t ); - int nearest = mysofa_lookup( hrtf->lookup, t ); - a[0] = hrtf->hrtf->SourcePosition.values[3 * nearest]; - a[1] = hrtf->hrtf->SourcePosition.values[3 * nearest + 1]; - a[2] = hrtf->hrtf->SourcePosition.values[3 * nearest + 2]; + t[0] = lscfg.azi[i]; /* azimuth in deg */ + if ( t[0] < 0 ) + { + t[0] += 360.; + } + t[1] = lscfg.ele[i]; /* elevation in deg */ + t[2] = sofa_src_pos_val[2]; /* radius in m */ + // double *tmp = (double *) PyArray_DATA( dir_t ); + // tmp[0] = t[0]; + // tmp[1] = t[1]; + // tmp[2] = t[2]; + // fprintf( stderr, "Wanted Position: %lf, %lf, %lf\n", t[0], t[1], t[2] ); + // fprintf( stderr, "Wanted Position: %lf, %lf, %lf\n", tmp[0], tmp[1], tmp[2] ); + nearest = find_pos_spheric( sofa_src_pos_cart_val, sofa_M, t ); + if ( ( nearest >= 0 ) && ( nearest < sofa_M ) ) + { + a[0] = sofa_src_pos_val[nearest * 3] * 180. / M_PI; + if ( a[0] < 0 ) + { + a[0] += 360.; + } + a[1] = sofa_src_pos_val[nearest * 3 + 1] * 180. / M_PI; + a[2] = sofa_src_pos_val[nearest * 3 + 2]; + } + if ( fabs( t[0] - a[0] ) > MAX_DIFF_AZI ) { - mysofa_close( hrtf ); + mxDestroyArray( sofa ); fprintf( stderr, "Nearest position to far from target incomplete sofa file\n" ); free( sofa_file_path ); free( index_pos ); @@ -642,18 +1021,17 @@ int generate_crend_ivas_tables_from_sofa( const char *file_path, bool no_optim ) } if ( fabs( t[1] - a[1] ) > MAX_DIFF_ELE ) { - mysofa_close( hrtf ); + mxDestroyArray( sofa ); fprintf( stderr, "Nearest position to far from target incomplete sofa file\n" ); free( sofa_file_path ); return -1; } - mysofa_c2s( a ); - if ( a[0] > 180 ) - a[0] -= 360; - if ( a[0] < -180 ) - a[0] += 360; + if ( a[0] > 180. ) + a[0] -= 360.; + if ( a[0] < -180. ) + a[0] += 360.; fprintf( stderr, "Nearest Position: %f, %f, %f\n", a[0], a[1], a[2] ); - fprintf( stderr, "Nearest position found at: %d\n", nearest ); + fprintf( stderr, "Nearest position found at: %ld\n", nearest ); index_pos[i] = nearest; } else @@ -661,20 +1039,9 @@ int generate_crend_ivas_tables_from_sofa( const char *file_path, bool no_optim ) index_pos[i] = i; } /* get the HRIR for the position given in t */ - uint32_t size = (uint32_t) hrtf->hrtf->R; + uint32_t size = (uint32_t) sofa_R; uint32_t delL = 0, delR = 0; - if ( hrtf->hrtf->DataDelay.elements == ( hrtf->hrtf->M * hrtf->hrtf->R ) ) - { - size = hrtf->hrtf->R; - delL = (uint32_t) roundf( hrtf->hrtf->DataDelay.values[index_pos[i] * size] * DEFAULT_SAMPLERATE ); - if ( maxDel48kHz < delL ) - maxDel48kHz = delL; - delR = (uint32_t) roundf( hrtf->hrtf->DataDelay.values[index_pos[i] * size + 1] * DEFAULT_SAMPLERATE ); - if ( maxDel48kHz < delR ) - maxDel48kHz = delR; - } } - size_t len_ls_cfg_name = strlen( lscfg.name ); double latency_48k = 0; @@ -682,7 +1049,6 @@ int generate_crend_ivas_tables_from_sofa( const char *file_path, bool no_optim ) for ( indSR = 0; indSR < sizeof( sample_rates ) / sizeof( float ); indSR++ ) { - uint16_t frame_len = L_FRAME48k; int32_t maxDel = maxDel48kHz * DEFAULT_SAMPLERATE / sample_rates[indSR]; switch ( sample_rates[indSR] ) @@ -702,7 +1068,13 @@ int generate_crend_ivas_tables_from_sofa( const char *file_path, bool no_optim ) break; } if ( frame_len_ms == 5 ) + { frame_len = frame_len >> 2; + } + + data_IR_current = sofa_data_IR_val_48k; + sofa_N = sofa_N_48k; + if ( sample_rates[indSR] != DEFAULT_SAMPLERATE ) { @@ -731,25 +1103,25 @@ int generate_crend_ivas_tables_from_sofa( const char *file_path, bool no_optim ) if ( fp ) { fclose( fp ); - - mysofa_close( hrtf ); - hrtf = (struct MYSOFA_EASY *) malloc( sizeof( struct MYSOFA_EASY ) ); - if ( !hrtf ) - return 1234; - memset( hrtf, 0, sizeof( struct MYSOFA_EASY ) ); - hrtf->hrtf = mysofa_load( file_path, &err ); } else { - mysofa_close( hrtf ); - hrtf = (struct MYSOFA_EASY *) malloc( sizeof( struct MYSOFA_EASY ) ); - if ( !hrtf ) - return 1234; - memset( hrtf, 0, sizeof( struct MYSOFA_EASY ) ); - hrtf->hrtf = mysofa_load( sofa_file_path, &err ); - mysofa_resample( hrtf->hrtf, (float) sample_rates[indSR] ); + switch ( sample_rates[indSR] ) + { + case 32000: + data_IR_current = sofa_data_IR_val_32k; + sofa_N = (int32_t) ceil( 32000.f * sofa_N_48k / 48000.f ); + break; + case 16000: + data_IR_current = sofa_data_IR_val_16k; + sofa_N = (int32_t) ceil( 16000.f * sofa_N_48k / 48000.f ); + break; + default: + data_IR_current = sofa_data_IR_val_48k; + sofa_N = sofa_N_48k; + break; + } } - latency_s = mysofa_getVariable( hrtf->hrtf->variables, "latencys" ); if ( file_path ) free( file_path ); } @@ -757,41 +1129,36 @@ int generate_crend_ivas_tables_from_sofa( const char *file_path, bool no_optim ) struct ivas_hrtf_t *ivas_hrtf = NULL; ivas_hrtf = malloc( sizeof( ivas_hrtf_t ) ); memset( ivas_hrtf, 0, sizeof( ivas_hrtf_t ) ); - ivas_hrtf->I = hrtf->hrtf->I; ivas_hrtf->m = lscfg.nb_channel; - ivas_hrtf->N = hrtf->hrtf->N + maxDel; - ivas_hrtf->R = hrtf->hrtf->R; + ivas_hrtf->N = sofa_N + maxDel; + ivas_hrtf->R = sofa_R; ivas_hrtf->sampling_rate = sample_rates[indSR]; - int32_t ind_max_ir = hrtf->hrtf->N; + int32_t ind_max_ir = sofa_N; uint32_t delL = 0, delR = 0; - unsigned size = hrtf->hrtf->R; + unsigned size = sofa_R; double max_ir_l = 0; double max_ir_r = 0; - int32_t ind_max_l = hrtf->hrtf->N; - int32_t ind_max_r = hrtf->hrtf->N; + int32_t ind_max_l = sofa_N; + int32_t ind_max_r = sofa_N; double tmpf; - size = (uint32_t) hrtf->hrtf->N * hrtf->hrtf->R; + size = (uint32_t) sofa_N * sofa_R; for ( i = 0; i < lscfg.nb_channel; i++ ) { max_ir_l = 0; max_ir_r = 0; - ind_max_l = hrtf->hrtf->N; - ind_max_r = hrtf->hrtf->N; - - if ( hrtf->hrtf->DataDelay.elements == hrtf->hrtf->M * hrtf->hrtf->R ) - { - delL = (uint32_t) roundf( hrtf->hrtf->DataDelay.values[index_pos[i] * size] * DEFAULT_SAMPLERATE ); - delR = (uint32_t) roundf( hrtf->hrtf->DataDelay.values[index_pos[i] * size + 1] * DEFAULT_SAMPLERATE ); - } + ind_max_l = sofa_N; + ind_max_r = sofa_N; + delL = 0; + delR = 0; ivas_hrtf->data_ir[i][0] = (double *) malloc( sizeof( double ) * ( ivas_hrtf->N ) ); memset( ivas_hrtf->data_ir[i][0], 0, sizeof( double ) * ivas_hrtf->N ); - for ( unsigned n = 0; n < hrtf->hrtf->N; n++ ) + for ( int32_t n = 0; n < sofa_N; n++ ) { - ivas_hrtf->data_ir[i][0][n + delL] = hrtf->hrtf->DataIR.values[size * index_pos[i] + n]; - tmpf = fabs( hrtf->hrtf->DataIR.values[index_pos[i] * size + n] ); + ivas_hrtf->data_ir[i][0][n + delL] = data_IR_current[size * index_pos[i] + n]; + tmpf = fabs( data_IR_current[index_pos[i] * size + n] ); if ( tmpf > max_ir_l ) { max_ir_l = tmpf; @@ -800,10 +1167,10 @@ int generate_crend_ivas_tables_from_sofa( const char *file_path, bool no_optim ) } ivas_hrtf->data_ir[i][1] = (double *) malloc( sizeof( double ) * ( ivas_hrtf->N ) ); memset( ivas_hrtf->data_ir[i][1], 0, sizeof( double ) * ivas_hrtf->N ); - for ( unsigned n = 0; n < hrtf->hrtf->N; n++ ) + for ( int32_t n = 0; n < sofa_N; n++ ) { - ivas_hrtf->data_ir[i][1][n + delR] = hrtf->hrtf->DataIR.values[size * index_pos[i] + hrtf->hrtf->N + n]; - tmpf = fabs( hrtf->hrtf->DataIR.values[size * index_pos[i] + hrtf->hrtf->N + n] ); + ivas_hrtf->data_ir[i][1][n + delR] = data_IR_current[size * index_pos[i] + sofa_N + n]; + tmpf = fabs( data_IR_current[index_pos[i] * size + sofa_N + n] ); if ( tmpf > max_ir_r ) { max_ir_r = tmpf; @@ -825,17 +1192,17 @@ int generate_crend_ivas_tables_from_sofa( const char *file_path, bool no_optim ) latency_48k = (double) ind_max_ir / (double) sample_rates[indSR]; } ivas_hrtf->latency_s[0] = (double *) malloc( sizeof( double ) ); - if ( latency_s == NULL ) + if ( sofa_latencys == NULL ) { ivas_hrtf->latency_s[0][0] = latency_48k; } else { - if ( fabs( latency_s->values[0] - (float) latency_48k ) > 1e-6f ) + if ( fabs( sofa_latencys[0] - latency_48k ) > 1e-6f ) { - fprintf( stderr, "Warning : At sample rate %ld latency in sofa file and computed are different sofa = %f, computed = %lf\n", (long) sample_rates[indSR], latency_s->values[0], latency_48k ); + fprintf( stderr, "Warning : At sample rate %ld latency in sofa file and computed are different sofa = %f, computed = %lf\n", (long) sample_rates[indSR], sofa_latencys[0], latency_48k ); } - ivas_hrtf->latency_s[0][0] = latency_s->values[0]; + ivas_hrtf->latency_s[0][0] = (float) sofa_latencys[0]; } HRTFS_DATA hrtf_data = { 0 }; @@ -849,16 +1216,16 @@ int generate_crend_ivas_tables_from_sofa( const char *file_path, bool no_optim ) hrtf_data.latency_s = latency_48k_optim; } - if ( ( hrtf_data.num_iterations[0][0] > 2 ) && ( no_optim == false ) ) + if ( ( hrtf_data.num_iterations[0][0] > ( frame_len_ms == 5 ? NUM_ITERATIONS_TO_ALLOW_OPTIM_5_MS : NUM_ITERATIONS_TO_ALLOW_OPTIM_20_MS ) ) && ( cfgReader->optimize == 1 ) ) { - ivas_crend_binaural_filter_design_compute_filters_params( ivas_hrtf, frame_len, &hrtf_data, &index_start, &index_end, &max_ir_len ); - ivas_crend_binaural_filter_design_set_hrtf_fr( ivas_hrtf, frame_len, &hrtf_data, index_start, index_end, &max_ir_len ); + ivas_crend_binaural_filter_design_compute_filters_params( ivas_hrtf, frame_len, &hrtf_data, &index_start, &index_end, &max_ir_len, cfgReader ); + ivas_crend_binaural_filter_design_set_hrtf_fr( ivas_hrtf, frame_len, + &hrtf_data, index_start, index_end, &max_ir_len, cfgReader ); } else { ivas_set_hrtf_fr( &hrtf_data, ivas_hrtf, frame_len ); } - hrtf_data.latency_s += 0.000000001f; if ( ( hrtf_data.num_iterations[0][0] > 2 ) ) @@ -875,8 +1242,16 @@ int generate_crend_ivas_tables_from_sofa( const char *file_path, bool no_optim ) latency_48k_optim = hrtf_data.latency_s; } - update_h_file( &hrtf_data, lscfg, sample_rates[indSR], frame_len ); - update_c_file( &hrtf_data, lscfg, sample_rates[indSR], frame_len ); + if ( lib_rend_path != NULL ) + { + update_h_file( &hrtf_data, lscfg, sample_rates[indSR], frame_len ); + update_c_file( &hrtf_data, lscfg, sample_rates[indSR], frame_len ); + } + + if ( binary_file_path != NULL ) + { + write_binary_file( &hrtf_data, lscfg, sample_rates[indSR], frame_len ); + } if ( ivas_hrtf->latency_s[0] ) { @@ -899,8 +1274,9 @@ int generate_crend_ivas_tables_from_sofa( const char *file_path, bool no_optim ) free( ivas_hrtf ); ivas_hrtf_close( &hrtf_data ); } - /* close the file */ - mysofa_close( hrtf ); + + mxDestroyArray( sofa ); + if ( sofa_file_path ) free( sofa_file_path ); if ( index_pos ) @@ -909,6 +1285,7 @@ int generate_crend_ivas_tables_from_sofa( const char *file_path, bool no_optim ) return 0; } + /*---------------------------------------------------------------------* *write_array_float_to_file(); *---------------------------------------------------------------------*/ @@ -1013,13 +1390,15 @@ void write_array_uint16_to_file( FILE *fp, uint16_t *vec, int32_t size_vec, int3 fprintf( fp, "}" ); } - /*---------------------------------------------------------------------* *update_c_file(); *---------------------------------------------------------------------*/ void update_c_file( HRTFS_DATA *hrtf, struct ivas_layout_config lscfg, const int32_t samplerate, const int16_t frame_len ) { + if ( c_file_path == NULL ) + return; + FILE *fp = fopen( c_file_path, "a" ); int16_t i, j; uint32_t *pTotalNumFreqSampPerIterations[2], maxTotalNumFreqSampPerIterations; @@ -1037,8 +1416,7 @@ void update_c_file( HRTFS_DATA *hrtf, struct ivas_layout_config lscfg, const int { /* float latency_s; */ fprintf( fp, "\n\n/********************** %s_%s **********************/\n", DECLARATION_NAME, lscfg.name ); - fprintf( fp, "\n#ifdef FIX_BINAURAL_DELAY_PRECISION\nconst float %s_%s_latency_s = %10.9ff;\n#else", DECLARATION_NAME, lscfg.name, hrtf->latency_s ); - fprintf( fp, "\nconst float %s_%s_latency_s = %16.15ff;\n#endif", DECLARATION_NAME, lscfg.name, hrtf->latency_s - 0.000000001f ); + fprintf( fp, "\nconst float %s_%s_latency_s = %10.9ff;", DECLARATION_NAME, lscfg.name, hrtf->latency_s ); } fprintf( fp, "\n\n/* Sample Rate = %ld */\n", (long) samplerate ); @@ -1214,7 +1592,6 @@ void update_c_file( HRTFS_DATA *hrtf, struct ivas_layout_config lscfg, const int return; } - /*---------------------------------------------------------------------* *update_h_file(); *---------------------------------------------------------------------*/ @@ -1224,6 +1601,9 @@ void update_h_file( HRTFS_DATA *hrtf, struct ivas_layout_config lscfg, const int uint32_t *pTotalNumFreqSampPerIterations[2], maxTotalNumFreqSampPerIterations; uint32_t pTotalNumFreqSampPerIterationsDiffuse[2], maxTotalNumFreqSampPerIterationsDiffuse; + if ( h_file_path == NULL ) + return; + pTotalNumFreqSampPerIterations[0] = malloc( sizeof( float ) * hrtf->max_num_ir ); pTotalNumFreqSampPerIterations[1] = malloc( sizeof( float ) * hrtf->max_num_ir ); FILE *fp = fopen( h_file_path, "a" ); @@ -1301,7 +1681,6 @@ void update_h_file( HRTFS_DATA *hrtf, struct ivas_layout_config lscfg, const int /* float inv_diffuse_weight[MAX_INTERN_CHANNELS]; */ fprintf( fp, "\nextern float %s_%s_inv_diffuse_weight_%2dkHz[%u];", DECLARATION_NAME, lscfg.name, samplerate / 1000, hrtf->max_num_ir ); - /* uint16_t *pIndex_frequency_max_diffuse[BINAURAL_CHANNELS];*/ if ( hrtf->pIndex_frequency_max_diffuse[0] == NULL ) { @@ -1350,44 +1729,369 @@ void update_h_file( HRTFS_DATA *hrtf, struct ivas_layout_config lscfg, const int return; } +/*---------------------------------------------------------------------* + * get_tables_dimensions(); + *---------------------------------------------------------------------*/ +void get_binary_tables_dimensions( HRTFS_DATA *hrtf, crend_hrtf_tables_dimensions *hrtf_table_dims /*OUT*/ ) +{ + int16_t iIR, iIter, iChan; + uint16_t total_num_fsamp_per_iteration, total_num_fsamp_per_iteration_diff; + + memset( hrtf_table_dims, 0x00, sizeof( crend_hrtf_tables_dimensions ) ); + + hrtf_table_dims->max_num_ir = hrtf->max_num_ir; + hrtf_table_dims->max_num_iterations = hrtf->max_num_iterations; + + // hrtf_table_dims->max_num_iterations_diffuse = 0; + for ( iChan = 0; iChan < BINAURAL_CHANNELS; iChan++ ) + { + if ( hrtf_table_dims->max_num_iterations_diffuse < hrtf->num_iterations_diffuse[iChan] ) + { + hrtf_table_dims->max_num_iterations_diffuse = hrtf->num_iterations_diffuse[iChan]; + } + } + + // hrtf_table_dims->max_total_num_fsamp_per_iteration = 0; + for ( iIR = 0; iIR < hrtf->max_num_ir; iIR++ ) + { + for ( iChan = 0; iChan < BINAURAL_CHANNELS; iChan++ ) + { + total_num_fsamp_per_iteration = 0; + for ( iIter = 0; iIter < hrtf->num_iterations[iIR][iChan]; iIter++ ) + { + total_num_fsamp_per_iteration += hrtf->pIndex_frequency_max[iIR][iChan][iIter]; + } + if ( hrtf_table_dims->max_total_num_fsamp_per_iteration < total_num_fsamp_per_iteration ) + { + hrtf_table_dims->max_total_num_fsamp_per_iteration = total_num_fsamp_per_iteration; + } + } + } + + // hrtf_table_dims->max_total_num_fsamp_per_iteration_diff = 0; + for ( iChan = 0; iChan < BINAURAL_CHANNELS; iChan++ ) + { + total_num_fsamp_per_iteration_diff = 0; + + for ( iIter = 0; iIter < hrtf->num_iterations_diffuse[iChan]; iIter++ ) + { + total_num_fsamp_per_iteration_diff += hrtf->pIndex_frequency_max_diffuse[iChan][iIter]; + } + if ( hrtf_table_dims->max_total_num_fsamp_per_iteration_diff < total_num_fsamp_per_iteration_diff ) + { + hrtf_table_dims->max_total_num_fsamp_per_iteration_diff = total_num_fsamp_per_iteration_diff; + } + } +} + /*---------------------------------------------------------------------* - * to_upper() - * - * Capitalize all letters of a string. - * (normally to_upper() function would be used but it does not work in Unix) + * compute_binary_size(); *---------------------------------------------------------------------*/ -char *to_upper( - char *str ) +uint32_t compute_binary_size( HRTFS_DATA *hrtf, crend_hrtf_tables_dimensions *hrtf_table_dims ) { - int16_t i; - char *p = str; + int16_t iIR, iIter, iChan; + uint32_t hrtf_data_size; - i = 0; - while ( str[i] != 0 ) + hrtf_data_size = 0; + + hrtf_data_size += sizeof( float ); // latency_s + hrtf_data_size += sizeof( uint16_t ); // max_num_ir + hrtf_data_size += sizeof( uint16_t ); // BINAURAL_CHANNELS + hrtf_data_size += sizeof( int16_t ); // max_num_iterations + hrtf_data_size += hrtf->max_num_ir * BINAURAL_CHANNELS * sizeof( uint16_t ); // num_iterations + hrtf_data_size += hrtf->max_num_ir * BINAURAL_CHANNELS * hrtf->max_num_iterations * sizeof( uint16_t ); // pIndex_frequency_max + + hrtf_data_size += sizeof( int16_t ); // max_num_iterations_diffuse + + if ( hrtf_table_dims->max_num_iterations_diffuse != 0 ) { - if ( str[i] >= 'a' && str[i] <= 'z' ) + hrtf_data_size += BINAURAL_CHANNELS * sizeof( uint16_t ); // num_iterations_diffuse + // The size of pIndex_frequency_max_diffuse depends on num_iterations_diffuse + for ( iChan = 0; iChan < BINAURAL_CHANNELS; iChan++ ) { - str[i] -= 0x20; + hrtf_data_size += hrtf->num_iterations_diffuse[iChan] * sizeof( uint16_t ); } - i++; } - return p; + hrtf_data_size += sizeof( uint16_t ); // index_frequency_max_diffuse + hrtf_data_size += hrtf->max_num_ir * sizeof( float ); // inv_diffuse_weight + + hrtf_data_size += sizeof( uint16_t ); // max_total_num_fsamp_per_iteration + + // The sizes of coeff_re & coeff_im depend on pIndex_frequency_max + for ( iIR = 0; iIR < hrtf->max_num_ir; iIR++ ) + { + for ( iChan = 0; iChan < BINAURAL_CHANNELS; iChan++ ) + { + for ( iIter = 0; iIter < hrtf->num_iterations[iIR][iChan]; iIter++ ) + { + hrtf_data_size += 2 * hrtf->pIndex_frequency_max[iIR][iChan][iIter] * sizeof( float ); // 2* : re & im + } + } + } + + hrtf_data_size += sizeof( uint16_t ); // max_total_num_fsamp_per_iteration_diff + if ( hrtf_table_dims->max_total_num_fsamp_per_iteration_diff != 0 ) + { + // The sizes of coeff_diffuse_re & coeff_diffuse_im depend on pIndex_frequency_max + for ( iChan = 0; iChan < BINAURAL_CHANNELS; iChan++ ) + { + for ( iIter = 0; iIter < hrtf->num_iterations_diffuse[iChan]; iIter++ ) + { + hrtf_data_size += 2 * hrtf->pIndex_frequency_max_diffuse[iChan][iIter] * sizeof( float ); // 2* : re & im + } + } + } + + return hrtf_data_size; } + /*---------------------------------------------------------------------* - *get_ls_layout_config( IVAS_DEC_OUTPUT_CONFIG ls_layout_config, struct ivas_layout_config *ls_struct ) + * write_binary_file(); + *---------------------------------------------------------------------*/ +void write_binary_file( HRTFS_DATA *hrtf, struct ivas_layout_config lscfg, const int32_t samplerate, const int16_t frame_len ) +{ + FILE *output_binary_file; + + int16_t iIR, iIter, iChan, iTap; + uint32_t data_size_tmp; + float *coeff_rptr; + char tmpStr[64]; + + crend_hrtf_tables_dimensions hrtf_table_dims; + + uint32_t hrtf_data_size; + char *hrtf_bin = NULL, *hrtf_bin_wptr; + + char *binary_file_full_path = NULL; + + if ( hrtf == NULL ) + return; + + if ( binary_file_path == NULL ) + return; + + /* Binary file - block description : + + latency_s => float + + max_num_ir => uint16_t + BINAURAL_CHANNELS => uint16_t (BINAURAL_CHANNELS) + + max_num_iterations => int16_t + num_iterations => uint16_t[max_num_ir][BINAURAL_CHANNELS] + pIndex_frequency_max => uint16_t[max_num_ir][BINAURAL_CHANNELS][max_num_iterations] (Pointer) + + max_num_iterations_diffuse => int16_t + num_iterations_diffuse => uint16_t[BINAURAL_CHANNELS] + pIndex_frequency_max_diffuse => uint16_t[BINAURAL_CHANNELS][max_num_iterations_diffuse] (Pointer) + + index_frequency_max_diffuse => uint16_t + inv_diffuse_weight => float[max_num_ir] + + max_total_num_fsamp_per_iteration => uint16_t + coeff_re => float[max_num_ir][BINAURAL_CHANNELS][max_total_num_fsamp_per_iteration] (Pointer) + coeff_im => float[max_num_ir][BINAURAL_CHANNELS][max_total_num_fsamp_per_iteration] (Pointer) + + max_total_num_fsamp_per_iteration_diff => uint16_t + coeff_diffuse_re => float[BINAURAL_CHANNELS][max_total_num_fsamp_per_iteration] (Pointer) + coeff_diffuse_im => float[BINAURAL_CHANNELS][max_total_num_fsamp_per_iteration] (Pointer) + */ + + get_binary_tables_dimensions( hrtf, &hrtf_table_dims ); + + hrtf_data_size = compute_binary_size( hrtf, &hrtf_table_dims ); + + hrtf_bin = NULL; + hrtf_bin = (char *) malloc( hrtf_data_size ); + if ( hrtf_bin == NULL ) + return; + memset( hrtf_bin, 0x00, hrtf_data_size ); + hrtf_bin_wptr = hrtf_bin; + + // Write the HRTF raw data + + memcpy( hrtf_bin_wptr, &( hrtf->latency_s ), sizeof( float ) ); // latency_s + hrtf_bin_wptr += sizeof( float ); + + memcpy( hrtf_bin_wptr, &( hrtf->max_num_ir ), sizeof( uint16_t ) ); // max_num_ir + hrtf_bin_wptr += sizeof( uint16_t ); + + uint16_t nchan_bin = BINAURAL_CHANNELS; + memcpy( hrtf_bin_wptr, &nchan_bin, sizeof( uint16_t ) ); // BINAURAL_CHANNELS + hrtf_bin_wptr += sizeof( uint16_t ); + + memcpy( hrtf_bin_wptr, &( hrtf->max_num_iterations ), sizeof( int16_t ) ); // max_num_iterations + hrtf_bin_wptr += sizeof( int16_t ); + + data_size_tmp = hrtf->max_num_ir * BINAURAL_CHANNELS * sizeof( uint16_t ); + memcpy( hrtf_bin_wptr, hrtf->num_iterations, data_size_tmp ); // num_iterations + hrtf_bin_wptr += data_size_tmp; + + // pIndex_frequency_max + data_size_tmp = hrtf->max_num_iterations * sizeof( uint16_t ); + for ( int iIR = 0; iIR < hrtf->max_num_ir; iIR++ ) + { + for ( iChan = 0; iChan < BINAURAL_CHANNELS; iChan++ ) + { + memcpy( hrtf_bin_wptr, hrtf->pIndex_frequency_max[iIR][iChan], data_size_tmp ); + hrtf_bin_wptr += data_size_tmp; + } + } + + memcpy( hrtf_bin_wptr, &( hrtf_table_dims.max_num_iterations_diffuse ), sizeof( int16_t ) ); // max_num_iterations_diffuse + hrtf_bin_wptr += sizeof( int16_t ); + + if ( hrtf_table_dims.max_num_iterations_diffuse != 0 ) + { + data_size_tmp = BINAURAL_CHANNELS * sizeof( uint16_t ); + memcpy( hrtf_bin_wptr, hrtf->num_iterations_diffuse, data_size_tmp ); // num_iterations_diffuse + hrtf_bin_wptr += data_size_tmp; + + // pIndex_frequency_max_diffuse (the size depends on num_iterations_diffuse) + for ( iChan = 0; iChan < BINAURAL_CHANNELS; iChan++ ) + { + data_size_tmp = hrtf->num_iterations_diffuse[iChan] * sizeof( uint16_t ); + memcpy( hrtf_bin_wptr, hrtf->pIndex_frequency_max_diffuse[iChan], data_size_tmp ); + hrtf_bin_wptr += data_size_tmp; + } + } + + memcpy( hrtf_bin_wptr, &( hrtf->index_frequency_max_diffuse ), sizeof( uint16_t ) ); // index_frequency_max_diffuse + hrtf_bin_wptr += sizeof( uint16_t ); + + for ( iIR = 0; iIR < hrtf->max_num_ir; iIR++ ) + { + sprintf( tmpStr, FORMAT_FLOAT, hrtf->inv_diffuse_weight[iIR] ); + sscanf( tmpStr, "%f", &( (float *) hrtf_bin_wptr )[iIR] ); + } + data_size_tmp = hrtf->max_num_ir * sizeof( float ); + hrtf_bin_wptr += data_size_tmp; + + memcpy( hrtf_bin_wptr, &( hrtf_table_dims.max_total_num_fsamp_per_iteration ), sizeof( uint16_t ) ); // max_total_num_fsamp_per_iteration + hrtf_bin_wptr += sizeof( uint16_t ); + + // pOut_to_bin_re (The size depends on pIndex_frequency_max) + for ( iIR = 0; iIR < hrtf->max_num_ir; iIR++ ) + { + for ( iChan = 0; iChan < BINAURAL_CHANNELS; iChan++ ) + { + coeff_rptr = hrtf->pOut_to_bin_re[iIR][iChan]; + for ( iIter = 0; iIter < hrtf->num_iterations[iIR][iChan]; iIter++ ) + { + data_size_tmp = hrtf->pIndex_frequency_max[iIR][iChan][iIter] * sizeof( float ); + // memcpy( hrtf_bin_wptr, coeff_rptr, data_size_tmp ); + for ( iTap = 0; iTap < hrtf->pIndex_frequency_max[iIR][iChan][iIter]; iTap++ ) + { + //( (float *) hrtf_bin_wptr )[iTap] = coeff_rptr[iTap]; + sprintf( tmpStr, FORMAT_FLOAT, coeff_rptr[iTap] ); + sscanf( tmpStr, "%f", &( ( (float *) hrtf_bin_wptr )[iTap] ) ); + } + hrtf_bin_wptr += data_size_tmp; + coeff_rptr += hrtf->pIndex_frequency_max[iIR][iChan][iIter]; + } + } + } + + // pOut_to_bin_im (The size depends on pIndex_frequency_max) + for ( iIR = 0; iIR < hrtf->max_num_ir; iIR++ ) + { + for ( iChan = 0; iChan < BINAURAL_CHANNELS; iChan++ ) + { + coeff_rptr = hrtf->pOut_to_bin_im[iIR][iChan]; + for ( iIter = 0; iIter < hrtf->num_iterations[iIR][iChan]; iIter++ ) + { + data_size_tmp = hrtf->pIndex_frequency_max[iIR][iChan][iIter] * sizeof( float ); + // memcpy( hrtf_bin_wptr, coeff_rptr, data_size_tmp ); + for ( iTap = 0; iTap < hrtf->pIndex_frequency_max[iIR][iChan][iIter]; iTap++ ) + { + //( (float *) hrtf_bin_wptr )[iTap] = coeff_rptr[iTap]; + sprintf( tmpStr, FORMAT_FLOAT, coeff_rptr[iTap] ); + sscanf( tmpStr, "%f", &( ( (float *) hrtf_bin_wptr )[iTap] ) ); + } + hrtf_bin_wptr += data_size_tmp; + coeff_rptr += hrtf->pIndex_frequency_max[iIR][iChan][iIter]; + } + } + } + + memcpy( hrtf_bin_wptr, &( hrtf_table_dims.max_total_num_fsamp_per_iteration_diff ), sizeof( uint16_t ) ); // max_total_num_fsamp_per_iteration_diff + hrtf_bin_wptr += sizeof( uint16_t ); + + if ( hrtf_table_dims.max_total_num_fsamp_per_iteration_diff != 0 ) + { + // pOut_to_bin_diffuse_re : The size depends on pIndex_frequency_max_diffuse + for ( iChan = 0; iChan < BINAURAL_CHANNELS; iChan++ ) + { + coeff_rptr = hrtf->pOut_to_bin_diffuse_re[iChan]; + for ( iIter = 0; iIter < hrtf->num_iterations_diffuse[iChan]; iIter++ ) + { + data_size_tmp = hrtf->pIndex_frequency_max_diffuse[iChan][iIter] * sizeof( float ); + // memcpy( hrtf_bin_wptr, coeff_rptr, data_size_tmp ); + for ( iTap = 0; iTap < hrtf->pIndex_frequency_max_diffuse[iChan][iIter]; iTap++ ) + { + //( (float *) hrtf_bin_wptr )[iTap] = coeff_rptr[iTap]; + sprintf( tmpStr, FORMAT_FLOAT, coeff_rptr[iTap] ); + sscanf( tmpStr, "%f", &( ( (float *) hrtf_bin_wptr )[iTap] ) ); + } + hrtf_bin_wptr += data_size_tmp; + coeff_rptr += hrtf->pIndex_frequency_max_diffuse[iChan][iIter]; + } + } + + // pOut_to_bin_diffuse_im : The size depends on pIndex_frequency_max_diffuse + for ( iChan = 0; iChan < BINAURAL_CHANNELS; iChan++ ) + { + coeff_rptr = hrtf->pOut_to_bin_diffuse_im[iChan]; + for ( iIter = 0; iIter < hrtf->num_iterations_diffuse[iChan]; iIter++ ) + { + data_size_tmp = hrtf->pIndex_frequency_max_diffuse[iChan][iIter] * sizeof( float ); + // memcpy( hrtf_bin_wptr, coeff_rptr, data_size_tmp ); + for ( iTap = 0; iTap < hrtf->pIndex_frequency_max_diffuse[iChan][iIter]; iTap++ ) + { + //( (float *) hrtf_bin_wptr )[iTap] = coeff_rptr[iTap]; + sprintf( tmpStr, FORMAT_FLOAT, coeff_rptr[iTap] ); + sscanf( tmpStr, "%f", &( ( (float *) hrtf_bin_wptr )[iTap] ) ); + } + hrtf_bin_wptr += data_size_tmp; + coeff_rptr += hrtf->pIndex_frequency_max_diffuse[iChan][iIter]; + } + } + } + + binary_file_full_path = (char *) malloc( sizeof( char ) * ( strlen( binary_file_path ) + 1 + strlen( lscfg.name ) + 1 + 5 + 3 + 4 ) ); + sprintf( binary_file_full_path, "%s_%s_%ikHz.bin", binary_file_path, lscfg.name, samplerate / 1000 ); + fprintf( stdout, "Write Binary file %s:\n", binary_file_full_path ); + + output_binary_file = fopen( binary_file_full_path, "wb" ); + if ( output_binary_file == NULL ) + { + free( hrtf_bin ); + return; + } + fwrite( hrtf_bin, hrtf_data_size, 1, output_binary_file ); + fclose( output_binary_file ); + + free( hrtf_bin ); + free( binary_file_full_path ); +} + +/*---------------------------------------------------------------------* + *get_ls_layout_config( AUDIO_CONFIG_CONFIG ls_layout_config, struct ivas_layout_config *ls_struct ) * fill ls_struct with proper values depending on ls_layout_config *---------------------------------------------------------------------*/ -void get_ls_layout_config( IVAS_DEC_AUDIO_CONFIG ls_layout_config, struct ivas_layout_config *ls_struct ) +void get_ls_layout_config( AUDIO_CONFIG ls_layout_config, struct ivas_layout_config *ls_struct ) { memset( ls_struct, 0, sizeof( struct ivas_layout_config ) ); + ls_struct->audio_config = ls_layout_config; + switch ( ls_layout_config ) { - case IVAS_DEC_OUTPUT_FOA: + case IVAS_AUDIO_CONFIG_FOA: strcpy( ls_struct->name, "FOA" ); ls_struct->nb_channel = 4; ls_struct->isloudspeaker = 0; @@ -1395,7 +2099,7 @@ void get_ls_layout_config( IVAS_DEC_AUDIO_CONFIG ls_layout_config, struct ivas_l ls_struct->num_lfe = 0; memset( ls_struct->lfe_index, -1, sizeof( int16_t ) * 2 ); break; - case IVAS_DEC_OUTPUT_HOA2: + case IVAS_AUDIO_CONFIG_HOA2: strcpy( ls_struct->name, "HOA2" ); ls_struct->nb_channel = 9; ls_struct->isloudspeaker = 0; @@ -1403,7 +2107,7 @@ void get_ls_layout_config( IVAS_DEC_AUDIO_CONFIG ls_layout_config, struct ivas_l ls_struct->num_lfe = 0; memset( ls_struct->lfe_index, -1, sizeof( int16_t ) * 2 ); break; - case IVAS_DEC_OUTPUT_HOA3: + case IVAS_AUDIO_CONFIG_HOA3: strcpy( ls_struct->name, "HOA3" ); ls_struct->nb_channel = 16; ls_struct->isloudspeaker = 0; @@ -1411,7 +2115,7 @@ void get_ls_layout_config( IVAS_DEC_AUDIO_CONFIG ls_layout_config, struct ivas_l ls_struct->num_lfe = 0; memset( ls_struct->lfe_index, -1, sizeof( int16_t ) * 2 ); break; - case IVAS_DEC_OUTPUT_MONO: + case IVAS_AUDIO_CONFIG_MONO: strcpy( ls_struct->name, "MONO" ); ls_struct->nb_channel = 1; ls_struct->isloudspeaker = 1; @@ -1419,7 +2123,7 @@ void get_ls_layout_config( IVAS_DEC_AUDIO_CONFIG ls_layout_config, struct ivas_l ls_struct->num_lfe = 0; memset( ls_struct->lfe_index, -1, sizeof( int16_t ) * 2 ); break; - case IVAS_DEC_OUTPUT_STEREO: + case IVAS_AUDIO_CONFIG_STEREO: strcpy( ls_struct->name, "STEREO" ); ls_struct->nb_channel = 2; memcpy( ls_struct->azi, ls_azimuth_CICP2, sizeof( float ) * ls_struct->nb_channel ); @@ -1428,7 +2132,7 @@ void get_ls_layout_config( IVAS_DEC_AUDIO_CONFIG ls_layout_config, struct ivas_l ls_struct->num_lfe = 0; memset( ls_struct->lfe_index, -1, sizeof( int16_t ) * 2 ); break; - case IVAS_DEC_OUTPUT_5_1: + case IVAS_AUDIO_CONFIG_5_1: strcpy( ls_struct->name, "5_1" ); ls_struct->nb_channel = 5; ls_struct->isloudspeaker = 1; @@ -1439,7 +2143,7 @@ void get_ls_layout_config( IVAS_DEC_AUDIO_CONFIG ls_layout_config, struct ivas_l ls_struct->gain_lfe = GAIN_LFE; memcpy( ls_struct->azi, ls_azimuth_CICP6, sizeof( float ) * ls_struct->nb_channel ); break; - case IVAS_DEC_OUTPUT_7_1: + case IVAS_AUDIO_CONFIG_7_1: strcpy( ls_struct->name, "7_1" ); ls_struct->nb_channel = 7; ls_struct->isloudspeaker = 1; @@ -1450,7 +2154,7 @@ void get_ls_layout_config( IVAS_DEC_AUDIO_CONFIG ls_layout_config, struct ivas_l ls_struct->gain_lfe = GAIN_LFE; memcpy( ls_struct->azi, ls_azimuth_CICP12, sizeof( float ) * ls_struct->nb_channel ); break; - case IVAS_DEC_OUTPUT_5_1_2: + case IVAS_AUDIO_CONFIG_5_1_2: strcpy( ls_struct->name, "5_1_2" ); ls_struct->nb_channel = 7; ls_struct->isloudspeaker = 1; @@ -1460,7 +2164,7 @@ void get_ls_layout_config( IVAS_DEC_AUDIO_CONFIG ls_layout_config, struct ivas_l ls_struct->gain_lfe = GAIN_LFE; memcpy( ls_struct->azi, ls_azimuth_CICP14, sizeof( float ) * ls_struct->nb_channel ); break; - case IVAS_DEC_OUTPUT_5_1_4: + case IVAS_AUDIO_CONFIG_5_1_4: strcpy( ls_struct->name, "5_1_4" ); ls_struct->nb_channel = 9; ls_struct->isloudspeaker = 1; @@ -1471,7 +2175,7 @@ void get_ls_layout_config( IVAS_DEC_AUDIO_CONFIG ls_layout_config, struct ivas_l ls_struct->gain_lfe = GAIN_LFE; memcpy( ls_struct->azi, ls_azimuth_CICP16, sizeof( float ) * ls_struct->nb_channel ); break; - case IVAS_DEC_OUTPUT_7_1_4: + case IVAS_AUDIO_CONFIG_7_1_4: strcpy( ls_struct->name, "7_1_4" ); ls_struct->nb_channel = 11; ls_struct->isloudspeaker = 1; @@ -1482,7 +2186,7 @@ void get_ls_layout_config( IVAS_DEC_AUDIO_CONFIG ls_layout_config, struct ivas_l ls_struct->gain_lfe = GAIN_LFE; memcpy( ls_struct->azi, ls_azimuth_CICP19, sizeof( float ) * ls_struct->nb_channel ); break; - case IVAS_DEC_OUTPUT_EXT: + case IVAS_AUDIO_CONFIG_EXTERNAL: default: { const float tmp_azi[15] = { 30, -30, 0, 135, -135, 110, -110, 90, -90, 30, -30, 110, -110, 135, -135 }; diff --git a/scripts/binauralRenderer_interface/generate_ivas_binauralizer_tables_from_sofa.m b/scripts/binauralRenderer_interface/generate_ivas_binauralizer_tables_from_sofa.m new file mode 100644 index 0000000000000000000000000000000000000000..09fa7957c617d5ba90727664d8012e28697d0082 --- /dev/null +++ b/scripts/binauralRenderer_interface/generate_ivas_binauralizer_tables_from_sofa.m @@ -0,0 +1,225 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% (C) 2022-2023 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. +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +% +% Generate tables from given HRIRs and BRIRs for IVAS binaural renderers +% +clear all; +close all; +clc; + +%% Add path to routines needed scripts +addpath('./matlab_hrir_generation_scripts/'); +addpath('./param_bin/'); +addpath('./fastconv/'); +addpath(genpath('../td_object_renderer/modeling_tool/')); + +%% Set arguments +writeRomFileOutput = true; %% generation of rom files if true +writeBinaryOutput = false; %% generation of binary files if true. Always true for TD renderer +writeEachRendererBinaryOutput = true; %% generation of binary split files each containing binary data for individual renderer + +%% Set ivas root path +ivas_path = ['..' filesep '..' filesep]; + +%% Set input files +%hrir_file_name = 'D1_48K_24bit_256tap_FIR_SOFA.sofa'; +%hrir_file_name = 'HRIR_128_Meth5_IRC_51_Q10_symL_Itrp1_48000.sofa'; +hrir_file_name = 'HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000.sofa'; +brir_file_name = 'IIS_BRIR_officialMPEG_Combined.sofa'; +hrir_path = fullfile ('.','HRIRs_sofa'); +brir_path = fullfile ('.','BRIRs_sofa'); +%% Set output files +rom_path = [ivas_path 'lib_rend']; +binary_path = fullfile ('.','binaural_renderers_hrtf_data'); +binary_name = [erase(hrir_file_name,'.sofa') '+' erase(brir_file_name, '.sofa') ]; +output_bin_name = 'ivas_binaural'; +if ~(exist(binary_path, 'dir')) + mkdir(binary_path); +end + +hrir_file = fullfile( hrir_path, hrir_file_name); +brir_file = fullfile( brir_path, brir_file_name); + +%% generate td binauralizer rom or binary values + +dataSpec.dataBase = 'IVAS'; +dataSpec.subjId = 'custom'; +% specify HR filter directory +dataSpec.hrfInDir = hrir_file; +dataSpec.hrfOutDir = binary_path; +dataSpec.genRomFile = writeRomFileOutput; +dataSpec.romOutDir = rom_path; +Mod_Hrf_Itd_Main(dataSpec); + +%% generate crend rom or binary values +SOFA_save_to_mat(hrir_file); +SOFA_save_to_mat(brir_file); + +convert_SD2SHD_HRIRs(hrir_path,hrir_file_name,128); + +command = ['.' filesep() 'generate_crend_ivas_tables']; + +if writeRomFileOutput == true + command = [command ' -lib_rend_path ' rom_path]; +end +if writeBinaryOutput == true + command = [command ... + ' -binary_files_path ' binary_path ... + ' -binary_common_file_name ' binary_name ... + ]; +end + +command = [command ... + ' 5 ' ... + erase(hrir_file,'.sofa') '.mat ' ... + erase(hrir_file,'.sofa') '_FOA.mat ' ... + erase(hrir_file,'.sofa') '_HOA2.mat ' ... + erase(hrir_file,'.sofa') '_HOA3.mat ' ... + erase(brir_file,'.sofa') '.mat ' ]; + +%display(command); + +[status, cmdout] = system(command); +if status ~= 0 + error(cmdout) + return +end + +%% generate fastconv binauralizer rom or binary values + +fastconv_bin_file = ['fastconv_' erase(hrir_file_name, '.sofa') '_' erase(brir_file_name, '.sofa') '.bin']; +bin_file = fullfile('.',binary_path, fastconv_bin_file ); +rom_file = fullfile(rom_path, 'ivas_rom_binauralRenderer.c'); + +copyfile('ivas_license_header.template',rom_file,'f'); + +fp = fopen(rom_file,'at'); +fprintf(fp,"\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n\n%s\n\n%s\n\n%s\n%s\n%s\n\n%s\n%s\n%s\n", ... +'#include ', ... +'#include "options.h"', ... +'#ifdef DEBUGGING', ... +'#include "debug.h"', ... +'#endif', ... +'#include "cnst.h"', ... +'#include "ivas_cnst.h"', ... +'#include "wmc_auto.h"', ... +'/* clang-format off */', ... +'#define WMC_TOOL_SKIP', ... +'/*-------------------------------------------------------------------------', ... +' * Binaural rendering related ROM tables', ... +' *------------------------------------------------------------------------*/', ... +'/* Binaural rendering data set based on HRIRs */', ... +'/* Tables generated by the script at "scripts/binauralRenderer_interface/fastconv/generate_tables_for_fastconv.m */', ... +'/* Can be replaced by your own generated HRIR tables */'); + +fclose(fp); + +generate_tables_for_fastconv + +%% generate parametric binauralizer rom values + +param_bin_file = ['parambin_' erase(hrir_file_name, '.sofa') '_' erase(brir_file_name, '.sofa') '.bin']; +bin_file = fullfile('.',binary_path, param_bin_file ); +generate_tables_for_parametric_binauralizer + +rom_file = fullfile(rom_path, 'ivas_rom_binauralRenderer.c'); + +fp = fopen(rom_file,'at'); + +fprintf(fp,"\n%s\n\n%s\n", '#undef WMC_TOOL_SKIP', '/* clang-format on */'); + +fclose(fp); + +%% concatenate all previously generated binary files to binary file for IVAS decoder or renderer. One per sample rates + +if writeBinaryOutput == true + td_binary_file = ['td_' erase(hrir_file_name,'.sofa') '_model_v003']; + command = ['.' filesep() 'Table_Format_Converter' filesep() 'tables_format_converter']; + command = [command ... + ' -output_file_path ' binary_path ... + ' -output_file_name ' output_bin_name ... + ' -input_mixerconv_hrir_file_path ' binary_path ... + ' -input_mixerconv_hrir_file_name ' binary_name ... + ' -input_mixerconv_brir_file_path ' binary_path ... + ' -input_mixerconv_brir_file_name ' binary_name ... + ' -input_td_file_path ' fullfile(binary_path, 'IVAS_default') ... + ' -input_td_file_name ' td_binary_file ... + ' -input_param_file_path ' binary_path ... + ' -input_param_file_name ' param_bin_file ... + ' -input_fastconv_file_path ' binary_path ... + ' -input_fastconv_file_name ' fastconv_bin_file ... + ]; + + [status, cmdout] = system(command); + if status ~= 0 + error(cmdout) + return + end +end + +%% Foa all previously generated binary files, convert to binary files for IVAS decoder or renderer. One per sample rates and per renderers + +if writeBinaryOutput == true && writeEachRendererBinaryOutput == true + td_binary_file = ['td_' erase(hrir_file_name,'.sofa') '_model_v003']; + command = ['.' filesep() 'Table_Format_Converter' filesep() 'tables_format_converter']; + commandRendererList = [... + " -input_mixerconv_hrir_file_path " binary_path ... + " -input_mixerconv_hrir_file_name " binary_name , ... + " -input_mixerconv_brir_file_path " binary_path ... + " -input_mixerconv_brir_file_name " binary_name ,... + " -input_td_file_path " fullfile(binary_path, 'IVAS_default') ... + " -input_td_file_name " td_binary_file ,... + " -input_param_file_path " binary_path ... + " -input_param_file_name " param_bin_file , ... + " -input_fastconv_file_path " binary_path ... + " -input_fastconv_file_name " fastconv_bin_file ... + ]; + for indList = 3 : 4 : length(commandRendererList) + pos = strfind(commandRendererList{indList},"_"); + pos(2) = strfind(commandRendererList{indList},"_file_name"); + output_bin_name_list = [output_bin_name commandRendererList{indList}(pos(1):pos(2)-1) ]; + cmdl = [command ' -output_file_path ' binary_path ' -output_file_name ' output_bin_name_list]; + cmdl2 = [cmdl ... + commandRendererList{indList - 2} ... + commandRendererList{indList - 1} ... + commandRendererList{indList} ... + commandRendererList{indList + 1} ... + ]; + [status, cmdout] = system(cmdl2); + if status ~= 0 + error(cmdout) + return + end + end + end \ No newline at end of file diff --git a/scripts/binauralRenderer_interface/generate_ivas_binauralizer_tables_from_sofa_test_other_database.m b/scripts/binauralRenderer_interface/generate_ivas_binauralizer_tables_from_sofa_test_other_database.m new file mode 100644 index 0000000000000000000000000000000000000000..028e197f04f066e711e91a9f20eae0a135fad472 --- /dev/null +++ b/scripts/binauralRenderer_interface/generate_ivas_binauralizer_tables_from_sofa_test_other_database.m @@ -0,0 +1,241 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% (C) 2022-2023 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. +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +% +% Generate tables from given HRIRs and BRIRs for IVAS binaural renderers +% +clear all; +close all; +clc; + +%% Add path to routines needed scripts +addpath('./matlab_hrir_generation_scripts/'); +addpath('./param_bin/'); +addpath('./fastconv/'); +addpath(genpath('../td_object_renderer/modeling_tool/')); + + +%% Set arguments +writeRomFileOutput = false; %% generation of rom files if true +writeBinaryOutput = true; %% generation of binary files if true. Always true for TD renderer +writeEachRendererBinaryOutput = true; %% generation of binary split files each containing binary data for individual renderer + +%% Set ivas root path +ivas_path = ['..' filesep '..' filesep]; + +%% Set input files +%hrir_file_name = 'D1_48K_24bit_256tap_FIR_SOFA.sofa'; +%hrir_file_name = 'HRIR_128_Meth5_IRC_51_Q10_symL_Itrp1_48000.sofa'; +hrir_file_name = 'HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000.sofa'; +% hrir_file_name = 'IRC_1100_I_HRIR_48000.sofa'; +% hrir_file_name = 'IRC_1002_C_44100.sofa'; + +brir_file_name = 'IIS_BRIR_officialMPEG_Combined.sofa'; +hrir_path = fullfile ('.','HRIRs_sofa'); +brir_path = fullfile ('.','BRIRs_sofa'); +%% Set output files +rom_path = [ivas_path 'lib_rend']; +rom_path = './'; +binary_path = fullfile ('.','binaural_renderers_hrtf_data'); +binary_name = [erase(hrir_file_name,'.sofa') '+' erase(brir_file_name, '.sofa') ]; +output_bin_name = 'ivas_binaural_irc_1002'; +if(exist(binary_path, 'dir')==0) + mkdir(binary_path); +end + +hrir_file = fullfile( hrir_path, hrir_file_name); +brir_file = fullfile( brir_path, brir_file_name); + +%% generate td binauralizer rom or binary values + +dataSpec.dataBase = 'IVAS'; +dataSpec.subjId = 'custom'; +% specify HR filter directory +dataSpec.hrfInDir = hrir_file; +dataSpec.hrfOutDir = binary_path; +dataSpec.genRomFile = writeRomFileOutput; +dataSpec.romOutDir = rom_path; +Mod_Hrf_Itd_Main(dataSpec); + +%% generate crend rom or binary values +convert_SD2SHD_HRIRs(hrir_path,hrir_file_name,128); + +command = ['.' filesep() 'generate_crend_ivas_tables']; + +if writeRomFileOutput == true + command = [command ' -lib_rend_path ' rom_path]; +end +if writeBinaryOutput == true + command = [command ... + ' -binary_files_path ' binary_path ... + ' -binary_common_file_name ' binary_name ... + ]; +end + +command = [command ... + ' -compute_reverb_rom ' ... + hrir_file ' ' ... + ' 5 ' ... + hrir_file ' ' ... + erase(hrir_file,'.sofa') '_FOA.sofa ' ... + erase(hrir_file,'.sofa') '_HOA2.sofa ' ... + erase(hrir_file,'.sofa') '_HOA3.sofa ' ... + brir_file ]; + +%display(command); + +[status, cmdout] = system(command); +if status ~= 0 + error(cmdout) + return +end + +%% generate fastconv binauralizer rom or binary values + +fastconv_bin_file = ['fastconv_' erase(hrir_file_name, '.sofa') '_' erase(brir_file_name, '.sofa') '.bin']; +bin_file = fullfile('.',binary_path, fastconv_bin_file ); +rom_file = fullfile(rom_path, 'ivas_rom_binauralRenderer.c'); + +copyfile('ivas_license_header.template',rom_file,'f'); + +fp = fopen(rom_file,'at'); +fprintf(fp,"\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n\n%s\n\n%s\n\n%s\n%s\n%s\n\n%s\n%s\n%s\n", ... +'#include ', ... +'#include "options.h"', ... +'#ifdef DEBUGGING', ... +'#include "debug.h"', ... +'#endif', ... +'#include "cnst.h"', ... +'#include "ivas_cnst.h"', ... +'#include "wmc_auto.h"', ... +'/* clang-format off */', ... +'#define WMC_TOOL_SKIP', ... +'/*-------------------------------------------------------------------------', ... +' * Binaural rendering related ROM tables', ... +' *------------------------------------------------------------------------*/', ... +'/* Binaural rendering data set based on HRIRs */', ... +'/* Tables generated by the script at "scripts/binauralRenderer_interface/fastconv/generate_tables_for_fastconv.m */', ... +'/* Can be replaced by your own generated HRIR tables */'); + +fclose(fp); + +generate_tables_for_fastconv + +%% generate parametric binauralizer rom values + +param_bin_file = ['parambin_' erase(hrir_file_name, '.sofa') '_' erase(brir_file_name, '.sofa') '.bin']; +bin_file = fullfile('.',binary_path, param_bin_file ); +generate_tables_for_parametric_binauralizer + +rom_file = fullfile(rom_path, 'ivas_rom_binauralRenderer.c'); + +fp = fopen(rom_file,'at'); + +fprintf(fp,"\n%s\n\n%s\n", '#undef WMC_TOOL_SKIP', '/* clang-format on */'); + +fclose(fp); + +%% concatenate all previously generated binary files to binary file for IVAS decoder or renderer. One per sample rates + +if writeBinaryOutput == true + td_binary_file = ['td_' erase(hrir_file_name,'.sofa') '_model_v003']; + % sampleRates = ['48' ; '32' ; '16' ]; + % for ind = 1 : length(sampleRates) + % command = ['.' filesep() 'Table_Format_Converter' filesep() 'tables_format_converter' ' -' sampleRates(ind,:) ' ']; + command = ['.' filesep() 'Table_Format_Converter' filesep() 'tables_format_converter']; + command = [command ... + ' -output_file_path ' binary_path ... + ' -output_file_name ' output_bin_name ... + ' -input_mixerconv_hrir_file_path ' binary_path ... + ' -input_mixerconv_hrir_file_name ' binary_name ... + ' -input_mixerconv_brir_file_path ' binary_path ... + ' -input_mixerconv_brir_file_name ' binary_name ... + ' -input_reverb_file_path ' binary_path ... + ' -input_reverb_file_name ' binary_name ... + ' -input_td_file_path ' fullfile(binary_path, 'IVAS_default') ... + ' -input_td_file_name ' td_binary_file ... + ' -input_param_file_path ' binary_path ... + ' -input_param_file_name ' param_bin_file ... + ' -input_fastconv_file_path ' binary_path ... + ' -input_fastconv_file_name ' fastconv_bin_file ... + ]; + + [status, cmdout] = system(command); + if status ~= 0 + error(cmdout) + return + end +% end +end + +%% Foa all previously generated binary files, convert to binary files for IVAS decoder or renderer. One per sample rates and per renderers + +if writeBinaryOutput == true && writeEachRendererBinaryOutput == true + td_binary_file = ['td_' erase(hrir_file_name,'.sofa') '_model_v003']; +% sampleRates = ['48' ; '32' ; '16' ]; + command = ['.' filesep() 'Table_Format_Converter' filesep() 'tables_format_converter']; + commandRendererList = [... + " -input_mixerconv_hrir_file_path " binary_path ... + " -input_mixerconv_hrir_file_name " binary_name , ... + " -input_mixerconv_brir_file_path " binary_path ... + " -input_mixerconv_brir_file_name " binary_name ,... + " -input_reverb_file_path " binary_path ... + " -input_reverb_file_name " binary_name ,... + " -input_td_file_path " fullfile(binary_path, 'IVAS_default') ... + " -input_td_file_name " td_binary_file ,... + " -input_param_file_path " binary_path ... + " -input_param_file_name " param_bin_file , ... + " -input_fastconv_file_path " binary_path ... + " -input_fastconv_file_name " fastconv_bin_file ... + ]; + % for ind = 1 : length(sampleRates) + for indList = 3 : 4 : length(commandRendererList) + pos = strfind(commandRendererList{indList},"_"); + pos(2) = strfind(commandRendererList{indList},"_file_name"); + output_bin_name_list = [output_bin_name commandRendererList{indList}(pos(1):pos(2)-1) ]; +% cmdl = [command ' -output_file_path ' binary_path ' -output_file_name ' output_bin_name_list ' -' sampleRates(ind,:) ' ']; + cmdl = [command ' -output_file_path ' binary_path ' -output_file_name ' output_bin_name_list]; + cmdl2 = [cmdl ... + commandRendererList{indList - 2} ... + commandRendererList{indList - 1} ... + commandRendererList{indList} ... + commandRendererList{indList + 1} ... + ]; + [status, cmdout] = system(cmdl2); + if status ~= 0 + error(cmdout) + return + end + end +% end + end \ No newline at end of file diff --git a/scripts/binauralRenderer_interface/ivas_crend_binaural_filter_design.c b/scripts/binauralRenderer_interface/ivas_crend_binaural_filter_design.c index 73d19429e18f459d0ee48c2cf16da32fbbe76c94..99fdbdb7ec154126a4207fa696078bfafaeaf138 100644 --- a/scripts/binauralRenderer_interface/ivas_crend_binaural_filter_design.c +++ b/scripts/binauralRenderer_interface/ivas_crend_binaural_filter_design.c @@ -42,9 +42,9 @@ #ifdef DEBUG_BINAURAL_FILTER_DESIGN /*------------------------------ Debug utilities ---------------------------------------------- */ -static void printBuf_float32( float *buf, uint32_t size1 ) +static void printBuf_float32( float *buf, int32_t size1 ) { - uint32_t ii; + int32_t ii; for ( ii = 0; ii < size1; ++ii ) { printf( "%4.2f ", buf[ii] ); @@ -58,7 +58,7 @@ static void printBuf_uint16( uint16_t *buf, uint16_t size1 ) uint16_t ii; for ( ii = 0; ii < size1; ++ii ) { - printf( "%u ", (uint32_t) buf[ii] ); + printf( "%u ", (int32_t) buf[ii] ); } return; @@ -76,7 +76,7 @@ static void printBuf_int16( int16_t *buf, uint16_t size1 ) return; } -static void printBuf_uint32( uint32_t *buf, int32_t size1 ) +static void printBuf_int32_t( int32_t *buf, int32_t size1 ) { int32_t ii; for ( ii = 0; ii < size1; ++ii ) @@ -98,9 +98,9 @@ static void printBuf_int32( int32_t *buf, int32_t size1 ) return; } -static void printMatrix_float32(float** buf, uint32_t size1, uint32_t size2) +static void printMatrix_float32(float** buf, int32_t size1, int32_t size2) { - uint32_t ii, jj; + int32_t ii, jj; for (ii = 0; ii < size1; ++ii) { for (jj = 0; jj < size2; ++jj) @@ -111,9 +111,9 @@ static void printMatrix_float32(float** buf, uint32_t size1, uint32_t size2) } -static void printMatrix_uint32(uint32_t** buf, uint32_t size1, uint32_t size2) +static void printMatrix_int32_t(int32_t** buf, int32_t size1, int32_t size2) { - uint32_t ii, jj; + int32_t ii, jj; for (ii = 0; ii < size1; ++ii) { for (jj = 0; jj < size2; ++jj) @@ -127,8 +127,8 @@ static void printMatrix_uint32(uint32_t** buf, uint32_t size1, uint32_t size2) static void printfAudioBufferOutFilterParams( HRTFS_DATA *pParam, - uint32_t index_start, - uint32_t index_end ) + int32_t index_start, + int32_t index_end ) { printf( "\nFilter Params" ); printf( "\nNum Channels : %u", pParam->max_num_ir ); @@ -263,14 +263,15 @@ ivas_error ivas_crend_binaural_filter_design_compute_filters_params( HRTFS_DATA *pParam, int32_t *index_start, int32_t *index_end, - int32_t *max_ir_len ) + int32_t *max_ir_len, + ConfigReader *cfgReader ) { /* Parameters */ - float BeginEnergyThld = -50; - float EndEnergyThld = -120; + float BeginEnergyThld = -50; /* use to find beginning of HRIR/BRIR. ratio between HRIR/BRIR energy before begin sample and after begin sample is = BeginEnergyThld. Remove zero at the beginning of the HRIR */ + float EndEnergyThld = -120; /* use to find end of HRIR. ratio between HRIR energy after end sample and before end sample is = EndEnergyThld. Remove zero at the end of the HRIR */ - float DirectEnergyThld = -25; - float DiffuseEnergyThld = -25; + float DirectEnergyThld = -25; /* use to find the length direct and early part of HRIR/BRIR. ratio between HRIR/BRIR energy of diffuse part and complete HRIR/BRIR energy = BeginEnergyThld. Energy left in diffuse part */ + float DiffuseEnergyThld = -25; /* use to find the length diffuse part of HRIR/BRIR. Energy removed at the end of the diffuse part = DiffuseEnergyThld of total energy of whole diffuse part */ /* Vars for loop indices etc. */ int32_t i_ear, i_chan, i_tap; @@ -280,7 +281,14 @@ ivas_error ivas_crend_binaural_filter_design_compute_filters_params( float energy, energyL, energyR, energyMaxi, threshold, CSEinst, CSEinstInv; double valMax[IVAS_SOFA_MAX_VAL_M]; - // float mdft_scale_fact = ((float)L_FRAME48k) / framelen; + + if ( cfgReader != NULL ) + { + BeginEnergyThld = cfgReader->beginEnergyThreshold; + EndEnergyThld = cfgReader->endEnergyThreshold; + DirectEnergyThld = cfgReader->directEnergyThreshold; + DiffuseEnergyThld = cfgReader->diffuseEnergyThreshold; + } memset( indDirectMaxi, 0, sizeof( int32_t ) * MAX_INTERN_CHANNELS ); @@ -296,6 +304,7 @@ ivas_error ivas_crend_binaural_filter_design_compute_filters_params( i_tap = (int32_t) ( pParam->latency_s * pFirData->sampling_rate + 0.5f ); /* Find maximum energy */ + indBeginMini = (int32_t) pFirData->N - 1; energyMaxi = 0; for ( i_chan = 0; i_chan < pParam->max_num_ir; ++i_chan ) { @@ -321,19 +330,27 @@ ivas_error ivas_crend_binaural_filter_design_compute_filters_params( } energyR += (float) pFirData->data_ir[i_chan][1][i_tap] * (float) pFirData->data_ir[i_chan][1][i_tap]; } - if ( energyL > energyMaxi ) + if ( indBeginMini > indMax[i_chan] ) { - energyMaxi = energyL; + indBeginMini = indMax[i_chan]; } - if ( energyR > energyMaxi ) + if ( energyMaxi < (float) valMax[i_chan] ) { - energyMaxi = energyR; + energyMaxi = (float) valMax[i_chan]; } + // if ( energyL > energyMaxi ) + // { + // energyMaxi = energyL; + // } + // if ( energyR > energyMaxi ) + // { + // energyMaxi = energyR; + // } } /* Find minimum indBegin */ indBeginMini = (int32_t) pFirData->N - 1; - threshold = powf( 10.f, BeginEnergyThld * 0.1f ); + threshold = powf( 10.f, BeginEnergyThld * 0.1f ) * energyMaxi; for ( i_ear = 0; i_ear < 2; ++i_ear ) { for ( i_chan = 0; i_chan < pParam->max_num_ir; ++i_chan ) @@ -345,7 +362,7 @@ ivas_error ivas_crend_binaural_filter_design_compute_filters_params( { CSEinst += (float) pFirData->data_ir[i_chan][i_ear][indBegin] * (float) pFirData->data_ir[i_chan][i_ear][indBegin]; - if ( CSEinst / energyMaxi > threshold ) + if ( CSEinst > threshold ) { indBegin--; if ( indBegin < 0 ) @@ -377,13 +394,13 @@ ivas_error ivas_crend_binaural_filter_design_compute_filters_params( *index_start = indBeginMini = (int32_t) ( (float) indBeginMini / 3.f ) * 3; - i_tap = (uint32_t) ( pParam->latency_s * (double) pFirData->sampling_rate ) - indBeginMini; + i_tap = (int32_t) round( pParam->latency_s * (double) pFirData->sampling_rate ) - indBeginMini; pParam->latency_s = (float) i_tap / (float) pFirData->sampling_rate; } else { - indBeginMini = *index_start = (uint32_t) round( ( pFirData->latency_s[0][0] - (double) pParam->latency_s ) * (double) pFirData->sampling_rate ); + indBeginMini = *index_start = (int32_t) round( ( pFirData->latency_s[0][0] - (double) pParam->latency_s ) * (double) pFirData->sampling_rate ); } @@ -424,7 +441,7 @@ ivas_error ivas_crend_binaural_filter_design_compute_filters_params( { CSEinstInv += (float) pFirData->data_ir[i_chan][i_ear][indDirect] * (float) pFirData->data_ir[i_chan][i_ear][indDirect]; - if ( CSEinstInv >= threshold ) + if ( CSEinstInv / energy >= threshold ) { indDirect++; @@ -460,10 +477,6 @@ ivas_error ivas_crend_binaural_filter_design_compute_filters_params( } } - /* not used now because we use imdft thus set back value to initial value FOR test vector */ - *index_start = 0; - *index_end = pFirData->N - 1; - *max_ir_len = *index_end - *index_start + 1; pParam->max_num_iterations = 1; @@ -546,7 +559,6 @@ ivas_error ivas_crend_binaural_filter_design_compute_filters_params( pParam->num_iterations[i_chan][0]++; } pParam->num_iterations[i_chan][1] = pParam->num_iterations[i_chan][0]; - /* max MAX_LENGTH_DIRECT_FILTER */ if ( pParam->num_iterations[i_chan][0] > IVAS_MAX_NUM_DIRECT_BLOCKS ) { pParam->num_iterations[i_chan][0] = IVAS_MAX_NUM_DIRECT_BLOCKS; @@ -660,8 +672,13 @@ ivas_error ivas_crend_binaural_filter_design_compute_filters_params( /* Compute parameters for a given BRIR * * @param pFirData : source ptr to ivas_hrtf_t struct - * @param framelen : size of the blocks linked to sample rate and fft size + * @param framelen : size of the blocks linked to sample rate and fft size + * @param pParam : dest ptr to a HRTFS_DATA struct for storing computed params * @param pParam : dest ptr to a HRTFS_DATA struct for storing computed params + * @param index_start : index of first sample to use in IRs + * @param index_end : index of first sample to use in IRs + * @param *max_ir_len : return max if length + * @param *cfgReader : struct storing brir optimisation parameters * * @return 0 if no error, 1 otherwise */ @@ -671,10 +688,12 @@ ivas_error ivas_crend_binaural_filter_design_set_hrtf_fr( HRTFS_DATA *pParam, int32_t index_start, int32_t index_end, - int32_t *max_ir_len ) + int32_t *max_ir_len, + ConfigReader *cfgReader ) { /* Parameters */ - float DiffuseFcThld = -20; + float DiffuseFcThld = -20; /* thresold to determine the cut off frequency for each slice of the diffuse IR*/ + float DirectFcThld = -20; /* thresold to determine the cut off frequency for each slice of the Direct of IR*/ /* Vars FOR loop indices etc. */ int16_t i_ear, i_chan; @@ -683,19 +702,24 @@ ivas_error ivas_crend_binaural_filter_design_set_hrtf_fr( int16_t indFreq, indFreqMaxi; float energy, threshold, CSEinstInvFreq; - float DirectFcThld = -20; float pBlock[L_FRAME48k] = { 0 }; float pBlockSpectrum_r[L_FRAME48k]; float pBlockSpectrum_i[L_FRAME48k]; float pBlockSpectrum_Mag[L_FRAME48k] = { 0 }; - float *pDiffuseFilter; /* diffuse filter (containing all blocks) ( pDiffuseFilter[tap] ) */ - float **ppDiffuseFilterWMC; /* diffuse filters WMC (containing all blocks) ( ppDiffuseFilterWMC[ear][tap] ) */ + float *pDiffuseFilter; /* diffuse filter (containing all blocks) ( pDiffuseFilter[tap] ) */ + float **ppDiffuseFilterWMC; /* diffuse filters WMC (containing all blocks) ( ppDiffuseFilterWMC[ear][tap] ) */ float ppEnergyDiffuseFilter[MAX_INTERN_CHANNELS][BINAURAL_CHANNELS] = { { 0 } }; /* diffuse filter energies ( ppEnergyDiffuseFilter[ear][channel] ) */ float ppDiffuseWeight[MAX_INTERN_CHANNELS][BINAURAL_CHANNELS] = { { 0 } }; /* diffuse weights ( ppDiffuseWeight[ear][channel] ) */ float delayf; float mdft_scale_fact = ( (float) L_FRAME48k * 0.25f ) / frame_len; + if ( cfgReader != NULL ) + { + DiffuseFcThld = cfgReader->diffuseCutOffFreqThreshold; + DirectFcThld = cfgReader->directCutOffFreqThreshold; + } + if ( pFirData->N <= frame_len ) { *max_ir_len = ( index_end - index_start + 1 ); @@ -1238,7 +1262,7 @@ ivas_error ivas_crend_binaural_filter_design_set_hrtf_fr( } #ifdef DEBUG_BINAURAL_FILTER_DESIGN - printfAudioBufferOutFilterParams( pParam, (uint32_t) index_start, (uint32_t) index_end ); + printfAudioBufferOutFilterParams( pParam, (int32_t) index_start, (int32_t) index_end ); #endif return IVAS_ERR_OK; } @@ -1260,14 +1284,14 @@ ivas_error ivas_crend_binaural_filter_design_set_hrtf_fr( ivas_error ivas_set_hrtf_fr( HRTFS_DATA *crend_hrtf, ivas_hrtf_t *hrtf, - const int16_t output_frame ) + const int16_t output_frame +) { int32_t i, j, m, n; float data_ir_flt[L_FRAME48k] = { 0.0f }; int32_t tmp_ir_len, in_len, k; - float mdft_scale_fact; - mdft_scale_fact = ( (float) L_FRAME48k * 0.25f ) / output_frame; + float mdft_scale_fact = ( (float) L_FRAME48k * 0.25f ) / output_frame; crend_hrtf->max_num_ir = (int16_t) hrtf->m; diff --git a/scripts/binauralRenderer_interface/ivas_crend_binaural_filter_design.h b/scripts/binauralRenderer_interface/ivas_crend_binaural_filter_design.h index 6e58171ac01df968cd1126cda1cd21c48bed0c15..21e0bb37c0d7a32b50ceb5683ed4f89d5f0e4cd5 100644 --- a/scripts/binauralRenderer_interface/ivas_crend_binaural_filter_design.h +++ b/scripts/binauralRenderer_interface/ivas_crend_binaural_filter_design.h @@ -33,24 +33,22 @@ #ifndef IVAS_CREND_BIBAURAL_FILTER_DESIGN_H_ #define IVAS_CREND_BIBAURAL_FILTER_DESIGN_H_ -#include -#include #include "ivas_stat_dec.h" -#define IVAS_SOFA_MAX_VAL_M ( 30 ) -#define IVAS_SOFA_MAX_VAL_R ( 2 ) -#define IVAS_SOFA_MAX_VAL_N ( 48000 ) -#define IVAS_SOFA_MAX_VAL_I ( 1 ) -#define IVAS_MAX_NUM_DIRECT_BLOCKS ( 40 ) /* max number of direct blocks */ -#define IVAS_MAX_NUM_DIFFUSE_BLOCKS ( 40 ) /* max number of diffuse blocks */ -#define IVAS_MAX_HRTF_LATENCY_MS ( 0.1 ) /* max hrtf latency */ +#include "config_reader.h" +#define IVAS_SOFA_MAX_VAL_M ( 16 ) +#define IVAS_SOFA_MAX_VAL_R ( 2 ) +#define IVAS_SOFA_MAX_VAL_N ( 48000 ) +#define IVAS_SOFA_MAX_VAL_I ( 1 ) +#define IVAS_MAX_NUM_DIRECT_BLOCKS ( 40 ) /* max number of direct blocks */ +#define IVAS_MAX_NUM_DIFFUSE_BLOCKS ( 40 ) /* max number of diffuse blocks */ +#define IVAS_MAX_HRTF_LATENCY_MS ( 0.1 ) /* max hrtf latency */ typedef struct ivas_hrtf_t { double *latency_s[IVAS_SOFA_MAX_VAL_I]; double *data_ir[IVAS_SOFA_MAX_VAL_M][IVAS_SOFA_MAX_VAL_M]; int8_t *p_hrtf_data; - int32_t I; int32_t R; int32_t N; int32_t m; @@ -62,10 +60,16 @@ typedef struct ivas_hrtf_t *------------------------------------------------------------------------------------------*/ ivas_error ivas_get_hrtf_lens( ivas_hrtf_t *hrtf, HRTFS_DATA *crend_hrtf, const int16_t frame_len ); -ivas_error ivas_set_hrtf_fr( HRTFS_DATA *crend_hrtf, ivas_hrtf_t *hrtf, const int16_t frame_len ); +ivas_error ivas_set_hrtf_fr( HRTFS_DATA *crend_hrtf, ivas_hrtf_t *hrtf, const int16_t frame_len +); -ivas_error ivas_crend_binaural_filter_design_compute_filters_params( ivas_hrtf_t *pFirData, const int16_t framelen, HRTFS_DATA *pParam, int32_t *index_start, int32_t *index_end, int32_t *max_ir_len ); -ivas_error ivas_crend_binaural_filter_design_set_hrtf_fr( ivas_hrtf_t *pFirData, const int16_t frame_len, HRTFS_DATA *pParam, int32_t index_start, int32_t index_end, int32_t *max_ir_len ); +ivas_error ivas_crend_binaural_filter_design_compute_filters_params( ivas_hrtf_t *pFirData, const int16_t framelen, HRTFS_DATA *pParam, int32_t *index_start, int32_t *index_end, int32_t *max_ir_len, ConfigReader *cfgReader ); +ivas_error ivas_crend_binaural_filter_design_set_hrtf_fr( ivas_hrtf_t *pFirData, const int16_t frame_len, + HRTFS_DATA *pParam, + int32_t index_start, + int32_t index_end, + int32_t *max_ir_len, + ConfigReader *cfgReader ); ivas_error ivas_hrtf_close( HRTFS_HANDLE hHRTF ); diff --git a/scripts/binauralRenderer_interface/ivas_license_header.template b/scripts/binauralRenderer_interface/ivas_license_header.template new file mode 100644 index 0000000000000000000000000000000000000000..aa9c35e4f9786f3321942cacb1f56d7d91840e20 --- /dev/null +++ b/scripts/binauralRenderer_interface/ivas_license_header.template @@ -0,0 +1,31 @@ +/****************************************************************************************************** + + (C) 2022-2023 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. + +*******************************************************************************************************/ diff --git a/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/README.md b/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/README.md index f6eb2cfad6ea65309e27c337e672b3fe2945b238..dd19d2829961a05a77737c72af6e0af1fc6e2448 100644 --- a/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/README.md +++ b/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/README.md @@ -3,5 +3,3 @@ Entry point to convert SD HRIRs to SHD HRIRs is the convert_SD2SHD_HRIRs.m script. Entry point to convert SHD HRIRs to CLDFB domain HRIRs is SHD_2_ROM.m. -Python 3.9.x needs to be installed with the sofar python module. The convert_SD2SHD_HRIRs.m script needs the path to this python. -Matlab 2020 has seen some issues with using python, so use a newer version if possible. If you are unable to use a newer matlab version, try loading in the OS default python, as this works sometimes. diff --git a/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/SD_2_ROM.m b/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/SD_2_ROM.m new file mode 100644 index 0000000000000000000000000000000000000000..de1c6736da06906ed4cd4d1b46722ae03fe62a2b --- /dev/null +++ b/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/SD_2_ROM.m @@ -0,0 +1,73 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% (C) 2022-2023 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. +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function FastConv_SD_IR = SD_2_ROM(sofa_file) +% SD_2_ROM( rom_c_file, sofa_file, ambisonics_order, hrir_length ) +% +% Derived from SHD_2_ROM.m +% - loads sphere-sampled Head Related Impulse Responses (HRIRs) given in sofa_file +% - converts SD HRIRs to Complex Low Delay Filter Bank (CLDFB) domain using fir_to_cldfb_fir.m +[thispath,~,~] = fileparts(mfilename('fullpath')); +thispath = [thispath,filesep]; + +if ~exist('sofa_file','var') || isempty(sofa_file) + sofa_file = fullfile(thispath,'..','HRIRs_sofa','HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000.sofa'); +end +%% load SD HRIRs +H = hrtf_library_loader(); +H.readSOFA(char(sofa_file)); +ls_struct = get_ls_layout_config('Combined'); +IR_SD = H.XYZ_to_IR_SD([deg2rad(ls_struct.azi); deg2rad(ls_struct.ele)]); + +%% SD -> CLDFB via least squares error optimization +[~,num_ears,num_ch] = size(IR_SD); +num_cldfb_taps = 3; +IR_cldfb = zeros(60,num_cldfb_taps,num_ears,num_ch); % 60 frequency bands +eval_flag = 0; % optional, = 1 requires signal processing toolbox (fftfilt) +legacy_flag = 1; % = 1 used to indicate slightly too short buffers as used to generate tested coefficients +for pos = 1:num_ch + disp(['Channel ',num2str(pos),'/',num2str(num_ch)]) + for ear = 1:num_ears + IR_cldfb(:,:,ear,pos) = fir_to_cldfb_fir( IR_SD(:,ear,pos), num_cldfb_taps, eval_flag, legacy_flag ); + end +end + +%% CLDFB -> ROM +latency_s = 0.000666667; % No added latency from conversion method +max_band = 50; % Compute 60 bands, but only use 50 in ROM table + +IR_cldfb = permute(IR_cldfb, [3 1 4 2]); % after permute: [ears(2), bands(60), chans(15), taps(3)] +IR_cldfb = IR_cldfb(:,1:max_band,:,:); + +FastConv_SD_IR.IR = IR_cldfb; +FastConv_SD_IR.latency_s = latency_s; + +end \ No newline at end of file diff --git a/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/SHD_2_ROM.m b/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/SHD_2_ROM.m index c6c98ec46bb3f52533cd21093a35abab4b83b737..ff034649a2839c9e30815a53cddb7afe2afd7c56 100644 --- a/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/SHD_2_ROM.m +++ b/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/SHD_2_ROM.m @@ -29,8 +29,8 @@ % the United Nations Convention on Contracts on the International Sales of Goods. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -function IR_cldfb = SHD_2_ROM( rom_c_file, sofa_file, ambi_order, hrir_len ) -% SHD_2_ROM( rom_c_file, sofa_file, ambisonics_order, hrir_length ) +function FastConv_SHD_IR = SHD_2_ROM( sofa_file, ambi_order, hrir_len ) +% SHD_2_ROM( sofa_file, ambisonics_order, hrir_length ) % % - converts sphere-sampled Head Related Impulse Responses (HRIRs) given in sofa_file % to the Spherical Harmonics domain (SHD) using generate_HOA_HRIRs_MOD_lens.m @@ -39,7 +39,6 @@ function IR_cldfb = SHD_2_ROM( rom_c_file, sofa_file, ambi_order, hrir_len ) [thispath,~,~] = fileparts(mfilename('fullpath')); thispath = [thispath,filesep]; -%py_path = 'C:\Users\xxxx\AppData\Local\Programs\Python\Python39\python.exe'; % may look like this if ~exist('sofa_file','var') || isempty(sofa_file) sofa_file = fullfile(thispath,'..','HRIRs_sofa','HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000.sofa'); end @@ -50,11 +49,6 @@ if ~exist('hrir_len','var') hrir_len = 128; end %% convert sphere-sampled HRIRs to SHD HRIRs -% requires: -% python -m pip install sofar -% python -m pip install numpy - -% convert sphere-sampled HRIRs to SHD HRIRs [sofa_path,sofa_name, sofa_ext] = fileparts(sofa_file); IR = generate_HOA_HRIRs_MOD_lens(ambi_order, sofa_path, [sofa_name,sofa_ext], hrir_len); @@ -82,50 +76,8 @@ if ambi_order == 1 else order = ['HOA' int2str(ambi_order)]; end -if ~exist('rom_c_file','var') || isempty(rom_c_file) - rom_c_file = [thispath,'ivas_rom_binauralRenderer_',order,'.c']; % fullfile(thispath,'..','..','..','lib_rend',['ivas_rom_binauralRenderer_',order,'.c']); -end - -fid = fopen(rom_c_file,'wt'); - -fprintf(fid, ['const float FASTCONV_' order '_latency_s = %10.9ff;\n'], latency_s); -write_one_ear( fid, ['const float leftHRIRReal_' order '[BINAURAL_CONVBANDS][' order '_CHANNELS][BINAURAL_NTAPS_SBA]='], real(IR_cldfb_rom(1,:,:,:))); -write_one_ear( fid, ['const float leftHRIRImag_' order '[BINAURAL_CONVBANDS][' order '_CHANNELS][BINAURAL_NTAPS_SBA]='], imag(IR_cldfb_rom(1,:,:,:))); -write_one_ear( fid, ['const float rightHRIRReal_' order '[BINAURAL_CONVBANDS][' order '_CHANNELS][BINAURAL_NTAPS_SBA]='], real(IR_cldfb_rom(2,:,:,:))); -write_one_ear( fid, ['const float rightHRIRImag_' order '[BINAURAL_CONVBANDS][' order '_CHANNELS][BINAURAL_NTAPS_SBA]='], imag(IR_cldfb_rom(2,:,:,:))); - -fclose(fid); - -function write_one_ear( fid, first_line, IR_cldfb_rom) -IR_cldfb_rom = squeeze(IR_cldfb_rom); -[num_bands,num_chans, num_taps] = size(IR_cldfb_rom); -num_spaces = 4; -num_spaces_cur = 0; -fprintf(fid,[first_line,'\n{\n']); -num_spaces_cur = num_spaces_cur + num_spaces; -for band = 1:num_bands - fprintf(fid,[blanks(num_spaces_cur),'{\n']); - num_spaces_cur = num_spaces_cur + num_spaces; - for chan = 1:num_chans - fprintf(fid,[blanks(num_spaces_cur),'{']); - for tap = 1:num_taps - if tap == num_taps - fprintf(fid,'%+ff',IR_cldfb_rom(band,chan,tap)); - else - fprintf(fid,'%+ff, ',IR_cldfb_rom(band,chan,tap)); - end - end - if chan == num_chans - fprintf(fid,'}\n'); - else - fprintf(fid,'},\n'); - end - end - num_spaces_cur = num_spaces_cur - num_spaces; - if band == num_bands - fprintf(fid,[blanks(num_spaces_cur),'}\n']); - else - fprintf(fid,[blanks(num_spaces_cur),'},\n']); - end +FastConv_SHD_IR.IR = IR_cldfb_rom; +FastConv_SHD_IR.latency_s = latency_s; +FastConv_SHD_IR.order = order; + end -fprintf(fid,'};\n\n'); diff --git a/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/SOFA_save.m b/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/SOFA_save.m new file mode 100644 index 0000000000000000000000000000000000000000..80ddba8f0b04b0a883d9f5dd83ec82dde818c376 --- /dev/null +++ b/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/SOFA_save.m @@ -0,0 +1,125 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% (C) 2022-2023 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. +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function [outputArg1] = SOFA_save(IR,fs,latency_s, inputSofaTemplatePath,outputSofaPath) +%UNTITLED Summary of this function goes here +% Detailed explanation goes here +outputArg1 = false; +inputAsLatencys = false; + +if isfile(inputSofaTemplatePath) + if isfile(outputSofaPath) + delete(outputSofaPath); + end + sofa_data = ncinfo(inputSofaTemplatePath); + for indVar = 1:length(sofa_data.Variables) + sofa_data.Variables(indVar).FillValue = 0; + if (strcmp(sofa_data.Variables(indVar).Name, 'Data.IR')) + sofa_data.Variables(indVar).Size(1) = size(IR,1); + sofa_data.Variables(indVar).Size(2) = size(IR,2); + sofa_data.Variables(indVar).Size(3) = size(IR,3); + sofa_data.Variables(indVar).ChunkSize(1) = size(IR,1); + sofa_data.Variables(indVar).ChunkSize(2) = size(IR,2); + sofa_data.Variables(indVar).ChunkSize(3) = size(IR,3)/2; + sofa_data.Variables(indVar).Dimensions(1).Length = size(IR,1); + sofa_data.Variables(indVar).Dimensions(2).Length = size(IR,2); + sofa_data.Variables(indVar).Dimensions(3).Length = size(IR,3); + end + if (strcmp(sofa_data.Variables(indVar).Name, 'Data.Delay') && sofa_data.Variables(indVar).Size(2)>1) + sofa_data.Variables(indVar).Size(1) = size(IR,2); + sofa_data.Variables(indVar).Size(2) = size(IR,3); + sofa_data.Variables(indVar).ChunkSize(1) = size(IR,2); + sofa_data.Variables(indVar).ChunkSize(2) = size(IR,3); + sofa_data.Variables(indVar).Dimensions(1).Length = size(IR,2); + sofa_data.Variables(indVar).Dimensions(2).Length = size(IR,3); + end + if (strcmp(sofa_data.Variables(indVar).Name, 'SourcePosition')) + sofa_data.Variables(indVar).Size(2) = size(IR,3); + sofa_data.Variables(indVar).Dimensions(2).Length = size(IR,3); + sofa_data.Variables(indVar).ChunkSize(2) = size(IR,3); + end + if (strcmp(sofa_data.Variables(indVar).Name, 'latencys')) + inputAsLatencys = true; + end + end + for indDim = 1:length(sofa_data.Dimensions) + if (strcmp(sofa_data.Dimensions(indDim).Name, 'N')) + sofa_data.Dimensions(indDim).Length = size(IR,1); + end + if (strcmp(sofa_data.Dimensions(indDim).Name, 'R')) + sofa_data.Dimensions(indDim).Length = size(IR,2); + end + if (strcmp(sofa_data.Dimensions(indDim).Name, 'M')) + sofa_data.Dimensions(indDim).Length = size(IR,3); + end + end + + ncid_in = netcdf.open(inputSofaTemplatePath); + ncid = netcdf.create(outputSofaPath,'netcdf4'); + for inDim = 1 : length(sofa_data.Dimensions) + netcdf.defDim(ncid, sofa_data.Dimensions(inDim).Name, sofa_data.Dimensions(inDim).Length); + end + for indVar = 1 : length(sofa_data.Variables) + varId = netcdf.inqVarID(ncid_in,sofa_data.Variables(indVar).Name); + [name,xtype,dimids,natts] = netcdf.inqVar(ncid_in,varId); + netcdf.defVar(ncid, name , xtype, dimids); + data = zeros(sofa_data.Variables(indVar).Size); + netcdf.putVar(ncid, varId, data); + if (strcmp(name, 'Data.IR')) + netcdf.putVar(ncid, varId, IR); + end + for indAtt = 0 : natts - 1 + attName = netcdf.inqAttName(ncid_in, varId, indAtt); + attVal = netcdf.getAtt(ncid_in,varId,attName); + netcdf.putAtt(ncid,varId,attName,attVal) + end + end + if inputAsLatencys == false + netcdf.defVar(ncid, 'latencys' , 6, 0); + varId = netcdf.inqVarID(ncid, 'latencys'); + netcdf.putVar(ncid, varId, latency_s); + end + netcdf.close(ncid); + netcdf.close(ncid_in); + for inAtt = 1 : length(sofa_data.Attributes) + ncwriteatt(outputSofaPath, '/', sofa_data.Attributes(inAtt).Name, sofa_data.Attributes(inAtt).Value); + end + + license = ncreadatt(inputSofaTemplatePath,'/','License'); + ncwriteatt(outputSofaPath,'/','License', license); + ncwrite(outputSofaPath,'Data.SamplingRate', fs); + ncwriteatt(outputSofaPath,'/', 'ListenerShortName',ncreadatt(inputSofaTemplatePath,'/','ListenerShortName')); + ncwriteatt(outputSofaPath,'/', 'DatabaseName',ncreadatt(inputSofaTemplatePath,'/','DatabaseName')); + ncwriteatt(outputSofaPath,'/','Title' ,ncreadatt(inputSofaTemplatePath,'/','Title')); + ncwriteatt(outputSofaPath,'/', 'SOFAConventions', 'AmbisonicsBRIR'); + +end \ No newline at end of file diff --git a/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/SOFA_save_to_mat.m b/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/SOFA_save_to_mat.m new file mode 100644 index 0000000000000000000000000000000000000000..ac75bb8de29cbc4ee561133ea4e60c93c30961bb --- /dev/null +++ b/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/SOFA_save_to_mat.m @@ -0,0 +1,113 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% (C) 2022-2023 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. +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function SOFA_save_to_mat(Lib_Name,outputSofaPath,sampleRates) +%UNTITLED Summary of this function goes here +% Detailed explanation goes here + +if nargin == 1 + outputSofaPath = [erase(Lib_Name,'.sofa') '.mat']; + sampleRates = [48000 32000 16000]; +end +if nargin == 2 + sampleRates = [48000 32000 16000]; +end + +if isfile(Lib_Name) + if isfile(outputSofaPath) + delete(outputSofaPath); + end + + Sofa = struct('Sofa',struct()); + + sofa_data = ncinfo(Lib_Name); + for indVar = 1:length(sofa_data.Variables) + if (strcmp(sofa_data.Variables(indVar).Name, 'latencys')) + Sofa.latencys = ncread(Lib_Name,'latencys'); + end + end + + Sofa.Pos = ncread(Lib_Name, 'SourcePosition'); + Sofa.Units = strtrim(strsplit(ncreadatt(Lib_Name, 'SourcePosition', 'Units'), ',')); + + assert( any(strcmpi(Sofa.Units{1}, {'degree','radian'})), 'Unknown units'); + if strcmpi(Sofa.Units{1},'degree'), Sofa.Pos(1,:)=Sofa.Pos(1,:)*pi/180; end + assert( any(strcmpi(Sofa.Units{2}, {'degree','radian'})), 'Unknown units'); + if strcmpi(Sofa.Units{2},'degree'), Sofa.Pos(2,:)=Sofa.Pos(2,:)*pi/180; end + assert( any(strcmpi(Sofa.Units{3}, {'metre','meter','inch'})), 'Unknown units'); + if strcmpi(Sofa.Units{3},'inch' ), Sofa.Pos(3,:)=Sofa.Pos(3,:)*0.0254; end + Sofa.PosSpherical = Sofa.Pos; + Sofa.Pos = Sofa.Pos(3,:) .* ... + [cos(Sofa.Pos(2,:)).*[cos(Sofa.Pos(1,:));sin(Sofa.Pos(1,:))];sin(Sofa.Pos(2,:))]; + + Sofa.PosCartesian = make_unit_vectors(Sofa.Pos); + NumLoc = size(Sofa.PosCartesian,2); + + % Now, get the impulse repsonses: + Sofa.DataType = ncreadatt(Lib_Name, '/', 'DataType'); + Sofa.Data.IR = ncread(Lib_Name, 'Data.IR'); + Sofa.Data.SamplingRate = ncread(Lib_Name, 'Data.SamplingRate'); + Sofa.Data.SamplingRate_Units = ncreadatt(Lib_Name, 'Data.SamplingRate', 'Units'); + Sofa.Data.Delay = permute(ncread(Lib_Name, 'Data.Delay'), [2, 1]); + switch lower(Sofa.DataType) + case 'fir' + assert( size(Sofa.Data.IR,2)>=2, 'Expecting 2 receivers (ears)'); + if size(Sofa.Data.IR,2)>2 + Sofa.Data.IR = Sofa.Data.IR(:,1:2,:); + Sofa.Data.Delay = Sofa.Data.Delay(:,1:2); + end + assert( size(Sofa.Data.IR,3)==NumLoc, 'IR is incorrect size'); + assert( all(diff(Sofa.Data.Delay,1,2)==0), ... + 'Non-zero inter-aural delay offset not (yet) implemented'); + assert(strcmp(Sofa.Data.SamplingRate_Units,'hertz'), 'unknown samplerate units'); + otherwise + error(['unknown GLOBAL_DataType = ', hrtf.GLOBAL_DataType]); + end + + for ind = 1:length(sampleRates) + if sampleRates(ind) == Sofa.Data.SamplingRate + Sofa.DataResampled(ind).IR = Sofa.Data.IR; + else + Sofa.DataResampled(ind).IR = resample(Sofa.Data.IR, sampleRates(ind),Sofa.Data.SamplingRate, 'Dimension',1); + end + Sofa.DataResampled(ind).SamplingRate = sampleRates(ind); + end + + Sofa.License = ncreadatt(Lib_Name,'/','License'); + Sofa.ListenerShortName = ncreadatt(Lib_Name,'/','ListenerShortName'); + Sofa.DatabaseName = ncreadatt(Lib_Name,'/','DatabaseName'); + Sofa.Title = ncreadatt(Lib_Name,'/','Title'); + Sofa.SOFAConventions = ncreadatt(Lib_Name,'/','SOFAConventions'); + + save(outputSofaPath, 'Sofa'); + +end \ No newline at end of file diff --git a/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/compute_lr_energies_and_iac.m b/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/compute_lr_energies_and_iac.m new file mode 100644 index 0000000000000000000000000000000000000000..9c4f0a56c865a81756af2c0ae299a97a5612b07d --- /dev/null +++ b/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/compute_lr_energies_and_iac.m @@ -0,0 +1,101 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% (C) 2022-2023 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. +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function [left_avg_power, right_avg_power, ia_coherence] = compute_lr_energies_and_iac(HRTF_mdfts, in_freq_count, out_freq_count) + % Compute left/right and coherence of entire HRTF dataset + % + % HRTF_mdfts - HRTF dataset in frequency domain. + % in_freq_count - number of HRTF bins + % out_freq_count - number of bins in target for energies and coherence + % values + + hrtf_count = size(HRTF_mdfts,3); + + left_avg_power = zeros(1, out_freq_count); + right_avg_power = zeros(1, out_freq_count); + ia_coherence = zeros(1, out_freq_count); + + inp_freq_step = 0.5 / in_freq_count; + inp_freq_offset = 0.5 * inp_freq_step; + out_freq_step = 0.5 / (out_freq_count - 1); + + base_idx = 1; + relative_pos = 0; + + % loop over output frequency bins + for out_bin_idx=0:out_freq_count-1 + norm_freqs = out_freq_step * out_bin_idx; + tbl_index = ( norm_freqs - inp_freq_offset ) / inp_freq_step; + if (tbl_index <= 0.0) + base_idx = 0; + relative_pos = 0; + else + base_idx = int16(floor(tbl_index)); + relative_pos = tbl_index - double(base_idx); + % extrapolation (above last bin), choose nearest + if(base_idx > (in_freq_count-2)) + base_idx = in_freq_count-2; + relative_pos = 1; + end + end + + base_idx = base_idx +1; + IA_coherence = zeros(2,1); + avg_pwr_lr = zeros(2,2); + + for hrtf_idx=1:hrtf_count + lr_pair_0 = HRTF_mdfts(base_idx,:,hrtf_idx); + lr_pair_1 = HRTF_mdfts(base_idx + 1,:,hrtf_idx); + avg_pwr_lr(1,:) = avg_pwr_lr(1,:) + real(lr_pair_0).^2 + imag(lr_pair_0).^2; + avg_pwr_lr(2,:) = avg_pwr_lr(2,:) + real(lr_pair_1).^2 + imag(lr_pair_1).^2; + IA_coherence(1,1) = IA_coherence(1,1) + real(lr_pair_0(1)) * real(lr_pair_0(2)) + imag(lr_pair_0(1)) * imag(lr_pair_0(2)); + IA_coherence(2,1) = IA_coherence(2,1) + real(lr_pair_1(1)) * real(lr_pair_1(2)) + imag(lr_pair_1(1)) * imag(lr_pair_1(2)); + end + + % compute averages and IA coherence + avg_pwr_lr = avg_pwr_lr/hrtf_count; + IA_coherence = IA_coherence/hrtf_count; + IA_coherence(1,1) = IA_coherence(1,1) / sqrt((avg_pwr_lr(1,1) * avg_pwr_lr(1,2))); + IA_coherence(2,1) = IA_coherence(2,1) / sqrt((avg_pwr_lr(2,1) * avg_pwr_lr(2,2))); + + % Limiting to (0...1) range in case of small numerical errors or negative values + for i=1:2 + IA_coherence(i,1) = min(IA_coherence(i,1),1); + IA_coherence(i,1) = max(IA_coherence(i,1),0); + end + + % Computing weighted average of 2 nearest values (1 below + 1 above) for linear interpolation + weight_1st = 1 - relative_pos; + left_avg_power(out_bin_idx + 1) = weight_1st * avg_pwr_lr(1,1) + relative_pos * avg_pwr_lr(2,1); + right_avg_power(out_bin_idx + 1) = weight_1st * avg_pwr_lr(1,2) + relative_pos * avg_pwr_lr(2,2); + ia_coherence(out_bin_idx + 1) = weight_1st * IA_coherence(1,1) + relative_pos * IA_coherence(2,1); + end +end \ No newline at end of file diff --git a/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/convert_SD2SHD_HRIRs.m b/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/convert_SD2SHD_HRIRs.m index 0281f7d52f4fc6e51dc7686ae5ea795fd3026bee..51d4715aeac6bab0ee284984b410488200c1b19c 100644 --- a/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/convert_SD2SHD_HRIRs.m +++ b/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/convert_SD2SHD_HRIRs.m @@ -44,6 +44,8 @@ data_struct(1).n_HOA_ch = 4; data_struct(1).sr = sr; data_struct(1).sr_short = sr_short; data_struct(1).sr_dft_size = sr_dft_size; +SOFA_save(data_struct(1).IR_data, sr(1), 1/sr(1), [sofa_path filesep() sofa_file], [sofa_path filesep() erase(sofa_file, '.sofa') '_' data_struct(1).HOA_name '.sofa']); +SOFA_save_to_mat([sofa_path filesep() erase(sofa_file, '.sofa') '_' data_struct(1).HOA_name '.sofa']); % HOA2 data_struct(2).IR_data = generate_HOA_HRIRs_MOD_lens(2, sofa_path, sofa_file, IR_size); @@ -52,6 +54,8 @@ data_struct(2).n_HOA_ch = 9; data_struct(2).sr = sr; data_struct(2).sr_short = sr_short; data_struct(2).sr_dft_size = sr_dft_size; +SOFA_save(data_struct(2).IR_data, sr(1), 1/sr(1), [sofa_path filesep() sofa_file],[sofa_path filesep() erase(sofa_file, '.sofa') '_' data_struct(2).HOA_name '.sofa']); +SOFA_save_to_mat([sofa_path filesep() erase(sofa_file, '.sofa') '_' data_struct(2).HOA_name '.sofa']); % HOA3 data_struct(3).IR_data = generate_HOA_HRIRs_MOD_lens(3, sofa_path, sofa_file, IR_size); @@ -60,5 +64,6 @@ data_struct(3).n_HOA_ch = 16; data_struct(3).sr = sr; data_struct(3).sr_short = sr_short; data_struct(3).sr_dft_size = sr_dft_size; +SOFA_save(data_struct(3).IR_data, sr(1), 1/sr(1), [sofa_path filesep() sofa_file], [sofa_path filesep() erase(sofa_file, '.sofa') '_' data_struct(3).HOA_name '.sofa']); +SOFA_save_to_mat([sofa_path filesep() erase(sofa_file, '.sofa') '_' data_struct(3).HOA_name '.sofa']); -generate_rom_tables(data_struct) diff --git a/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/fir_to_cldfb_fir.m b/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/fir_to_cldfb_fir.m index 5043f4f2c7577e11b070a33c18ae8bcffb6bef5f..c4defd458823b23b73a26f8b8c997df07052b92a 100644 --- a/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/fir_to_cldfb_fir.m +++ b/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/fir_to_cldfb_fir.m @@ -169,136 +169,3 @@ set(gca,'xlim',[1,num_samples]) fprintf('SNR: %.1f dB \n', 10*log10(sum(y1.^2)/sum((y1-y2).^2))); legend('time domain','CLDFB domain','difference') title('Filtered noise') - -function [h, D, S, L] = get_cldfb_filter() -% const float LDQMF_60[] in \lib_com\rom_com.c, line 5219 -S = 60; % stride -L = 60; % frequency bands -D = 240 + S - 1; % system delay -h = [ - 0.0000953076, 0.0001230230, 0.0001279964, 0.0001260533, 0.0001211219 - 0.0001122123, 0.0001010860, 0.0000876540, 0.0000719883, 0.0000545472 - 0.0000352143, 0.0000145686, -0.0000074264, -0.0000303788, -0.0000539205 - -0.0000782743, -0.0001028838, -0.0001275374, -0.0001520015, -0.0001760167 - -0.0001997108, -0.0002226708, -0.0002446725, -0.0002655797, -0.0002852145 - -0.0003034996, -0.0003203036, -0.0003356283, -0.0003493345, -0.0003614030 - -0.0003719004, -0.0003807641, -0.0003881051, -0.0003939842, -0.0003985357 - -0.0004019095, -0.0004041938, -0.0004056677, -0.0004065430, -0.0004069925 - -0.0004072535, -0.0004075877, -0.0004083676, -0.0004098394, -0.0004122990 - -0.0004160839, -0.0004214063, -0.0004285777, -0.0004378651, -0.0004495422 - -0.0004637682, -0.0004806494, -0.0005003878, -0.0005231378, -0.0005489803 - -0.0005777747, -0.0006095612, -0.0006443121, -0.0006813223, -0.0007226231 - -0.0007722576, -0.0008268412, -0.0008839625, -0.0009417336, -0.0010004630 - -0.0010601623, -0.0011206097, -0.0011817788, -0.0012432419, -0.0013045983 - -0.0013656860, -0.0014260965, -0.0014855355, -0.0015435946, -0.0015999591 - -0.0016543545, -0.0017062968, -0.0017554691, -0.0018015467, -0.0018441341 - -0.0018829798, -0.0019177221, -0.0019480695, -0.0019736972, -0.0019943134 - -0.0020097434, -0.0020197174, -0.0020240925, -0.0020226294, -0.0020152442 - -0.0020017736, -0.0019820682, -0.0019561697, -0.0019240153, -0.0018855907 - -0.0018409232, -0.0017900462, -0.0017330211, -0.0016699535, -0.0016009507 - -0.0015261442, -0.0014456788, -0.0013597424, -0.0012685407, -0.0011722331 - -0.0010710671, -0.0009652392, -0.0008549765, -0.0007405236, -0.0006221444 - -0.0005001140, -0.0003745670, -0.0002458634, -0.0001142541, 0.0000199491 - 0.0001564174, 0.0002949402, 0.0004350246, 0.0005769439, 0.0007203126 - -0.0008803223, -0.0010328424, -0.0011841310, -0.0013346316, -0.0014848098 - -0.0016343417, -0.0017832819, -0.0019316213, -0.0020790498, -0.0022252349 - -0.0023701149, -0.0025136294, -0.0026556554, -0.0027960713, -0.0029348312 - -0.0030717771, -0.0032068293, -0.0033399195, -0.0034709862, -0.0035999804 - -0.0037267797, -0.0038513308, -0.0039736414, -0.0040935921, -0.0042111278 - -0.0043262239, -0.0044388464, -0.0045489701, -0.0046565188, -0.0047614835 - -0.0048637423, -0.0049632201, -0.0050599808, -0.0051539382, -0.0052450863 - -0.0053333500, -0.0054187514, -0.0055012843, -0.0055808770, -0.0056575472 - -0.0057313135, -0.0058021732, -0.0058701355, -0.0059352517, -0.0059975707 - -0.0060571772, -0.0061141332, -0.0061685541, -0.0062205540, -0.0062703062 - -0.0063179093, -0.0063635921, -0.0064075105, -0.0064498796, -0.0064908965 - -0.0065308069, -0.0065698619, -0.0066083665, -0.0066466411, -0.0066849431 - -0.0067233290, -0.0067621553, -0.0068021296, -0.0068436749, -0.0068870094 - -0.0069324085, -0.0069801519, -0.0070305937, -0.0070840055, -0.0071406048 - -0.0072006541, -0.0072644479, -0.0073321410, -0.0074039386, -0.0074799177 - -0.0075602704, -0.0076450342, -0.0077342330, -0.0078278277, -0.0079257628 - -0.0080279401, -0.0081341872, -0.0082442267, -0.0083577875, -0.0084744738 - -0.0085938899, -0.0087156557, -0.0088391500, -0.0089637861, -0.0090888245 - -0.0092134504, -0.0093367994, -0.0094579896, -0.0095760096, -0.0096898535 - -0.0097982995, -0.0099003557, -0.0099947909, -0.0100801717, -0.0101551116 - -0.0102182031, -0.0102678994, -0.0103026126, -0.0103207529, -0.0103206923 - -0.0103006857, -0.0102590285, -0.0101939747, -0.0101036867, -0.0099863587 - -0.0098401112, -0.0096632261, -0.0094537362, -0.0092098210, -0.0089295702 - -0.0086111929, -0.0082527259, -0.0078523541, -0.0074084769, -0.0069190590 - 0.0063841688, 0.0057985946, 0.0051621343, 0.0044734711, 0.0037309236 - 0.0029329660, 0.0020781513, 0.0011651339, 0.0001925042, -0.0008409545 - -0.0019364181, -0.0030950012, -0.0043176264, -0.0056051607, -0.0069584334 - -0.0083780792, -0.0098646237, -0.0114185056, -0.0130400723, -0.0147295250 - -0.0164868534, -0.0183120724, -0.0202049762, -0.0221651513, -0.0241921283 - -0.0262852497, -0.0284437388, -0.0306666382, -0.0329528190, -0.0353010744 - -0.0377098918, -0.0401776619, -0.0427025780, -0.0452826768, -0.0479161367 - -0.0506004691, -0.0533332452, -0.0561118126, -0.0589331910, -0.0617944039 - -0.0646922663, -0.0676232576, -0.0705836788, -0.0735698044, -0.0765774846 - -0.0796026587, -0.0826408863, -0.0856874809, -0.0887378305, -0.0917868018 - -0.0948293805, -0.0978601947, -0.1008738130, -0.1038645208, -0.1068264544 - -0.1097536832, -0.1126400903, -0.1154794544, -0.1182654947, -0.1209914312 - -0.1236500666, -0.1262341589, -0.1287376434, -0.1311538219, -0.1334753036 - -0.1356947273, -0.1378047168, -0.1397978216, -0.1416664869, -0.1434033662 - -0.1450008005, -0.1464512348, -0.1477471888, -0.1488809884, -0.1498452872 - -0.1506324410, -0.1512351334, -0.1516460329, -0.1518578976, -0.1518635303 - -0.1516559124, -0.1512281001, -0.1505732536, -0.1496847868, -0.1485562176 - -0.1471813470, -0.1455538720, -0.1436681300, -0.1415183097, -0.1390990764 - -0.1364052594, -0.1334318966, -0.1301742792, -0.1266280264, -0.1227891371 - -0.1186537445, -0.1142183766, -0.1094799563, -0.1044355705, -0.0990828425 - -0.0934195668, -0.0874440819, -0.0811550021, -0.0745511875, -0.0676321834 - -0.0603975877, -0.0528475679, -0.0449828543, -0.0368040986, -0.0283128861 - -0.0195108838, -0.0104003223, -0.0009837818, 0.0087356847, 0.0187546927 - 0.0290693250, 0.0396753438, 0.0505682528, 0.0617432520, 0.0731955394 - -0.0849232078, -0.0969054326, -0.1091460735, -0.1216373071, -0.1343720406 - -0.1473424733, -0.1605402082, -0.1739567965, -0.1875831038, -0.2014097124 - -0.2154271752, -0.2296251506, -0.2439934313, -0.2585212290, -0.2731975317 - -0.2880111337, -0.3029502928, -0.3180032372, -0.3331578076, -0.3484017253 - -0.3637222052, -0.3791064322, -0.3945416212, -0.4100143015, -0.4255111217 - -0.4410185516, -0.4565227628, -0.4720100164, -0.4874662757, -0.5028775334 - -0.5182296634, -0.5335084200, -0.5486994982, -0.5637886524, -0.5787616372 - -0.5936041474, -0.6083019376, -0.6228409410, -0.6372069120, -0.6513859630 - -0.6653640866, -0.6791275144, -0.6926627755, -0.7059561610, -0.7189947963 - -0.7317654490, -0.7442554235, -0.7564523220, -0.7683438063, -0.7799182534 - -0.7911639810, -0.8020697832, -0.8126249313, -0.8228194118, -0.8326428533 - -0.8420860767, -0.8511404991, -0.8597975969, -0.8680517077, -0.8758881092 - -0.8832823634, -0.8902196884, -0.8967157602, -0.9027729034, -0.9083824754 - -0.9135394692, -0.9182395935, -0.9224776030, -0.9262499809, -0.9295535684 - -0.9323854446, -0.9347436428, -0.9366261959, -0.9380323887, -0.9389615655 - -0.9394137263, -0.9393896461, -0.9388904572, -0.9379178882, -0.9364743829 - -0.9345626831, -0.9321863055, -0.9293491840, -0.9260557890, -0.9223110080 - -0.9181203246, -0.9134896994, -0.9084255695, -0.9029349089, -0.8970250487 - -0.8907034993, -0.8839784265, -0.8768582940, -0.8693521619, -0.8614694476 - -0.8532197475, -0.8446131349, -0.8356599212, -0.8263708353, -0.8167568445 - -0.8068289757, -0.7965991497, -0.7860788107, -0.7752800584, -0.7642148733 - -0.7528960109, -0.7413358092, -0.7295469642, -0.7175422311, -0.7053351402 - -0.6929380894, -0.6803644896, -0.6676273942, -0.6547405124, -0.6417166591 - -0.6285686493, -0.6153115034, -0.6019562483, -0.5885198116, -0.5750215650 - 0.5615197420, 0.5478612781, 0.5341838002, 0.5204906464, 0.5067980289 - 0.4931168854, 0.4794588387, 0.4658361673, 0.4522601366, 0.4387422502 - 0.4252935350, 0.4119254053, 0.3986486793, 0.3854739666, 0.3724119067 - 0.3594728410, 0.3466667533, 0.3340034485, 0.3214924335, 0.3091430366 - 0.2969639599, 0.2849639654, 0.2731511295, 0.2615332901, 0.2501178682 - 0.2389119864, 0.2279221565, 0.2171545923, 0.2066148520, 0.1963084787 - 0.1862401515, 0.1764142811, 0.1668347418, 0.1575049609, 0.1484276950 - 0.1396053135, 0.1310400218, 0.1227331311, 0.1146853194, 0.1068974212 - 0.0993694067, 0.0921007246, 0.0850901082, 0.0783365741, 0.0718384907 - 0.0655927584, 0.0595967993, 0.0538481586, 0.0483424664, 0.0430756323 - 0.0380428955, 0.0332404599, 0.0286619961, 0.0242999699, 0.0201510899 - 0.0162059069, 0.0124559226, 0.0088928537, 0.0054926532, 0.0023052765 - -0.0005515143, -0.0030201224, -0.0052712574, -0.0073737046, -0.0093160523 - -0.0111072771, -0.0127562135, -0.0142635731, -0.0156361461, -0.0168790054 - -0.0179969221, -0.0189934950, -0.0198726747, -0.0206398536, -0.0212980714 - -0.0218509119, -0.0223025978, -0.0226570386, -0.0229178313, -0.0230882075 - -0.0231725387, -0.0231746566, -0.0230979007, -0.0229462404, -0.0227237809 - -0.0224345829, -0.0220820960, -0.0216706358, -0.0212045144, -0.0206875466 - -0.0201238506, -0.0195175279, -0.0188730918, -0.0181944817, -0.0174855441 - -0.0167510118, -0.0159947462, -0.0152208358, -0.0144332750, -0.0136361914 - -0.0128338682, -0.0120294262, -0.0112272501, -0.0104311826, -0.0096443929 - -0.0088709844, -0.0081134979, -0.0073764324, -0.0066623385, -0.0059733889 - -0.0053142183, -0.0046856776, -0.0040914025, -0.0035321070, -0.0030089030 - -0.0025271603, -0.0020749648, -0.0016621647, -0.0012705614, -0.0008115423 -]; -h = h.'; -h = h(:); -h(1*120+(1:120)) = -h(1*120+(1:120)); -h(3*120+(1:120)) = -h(3*120+(1:120)); -h(:) = h(end:-1:1); \ No newline at end of file diff --git a/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/generate_HOA_HRIRs_MOD_lens.m b/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/generate_HOA_HRIRs_MOD_lens.m index 22a42dd1905059166cded0c4009222b4c7c96e35..0171e96bbb7a2b41a7e753235b236da70c31da58 100644 --- a/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/generate_HOA_HRIRs_MOD_lens.m +++ b/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/generate_HOA_HRIRs_MOD_lens.m @@ -55,8 +55,6 @@ Vs_hi_res = load("sphere_packing_2562.mat"); Vs_hi_res = Vs_hi_res.Vs_hi_res; N = 512; -% Fetch the HRTFs, and figure out the ITD for every direction -% name = ['HRIR_', num2str(ir_len), '_Meth5_IRC_53_Q10_symL_Itrp1_48000']; H = hrtf_library_loader(); H.readSOFA(char(fullfile(sofa_path, sofa_file_name))); @@ -116,7 +114,6 @@ IR_HOA = IR_HOA(:,1:ir_len,:) .* sin(interp1([0,150/192*ir_len,ir_len+1],[1,1,0] IR = permute(IR_HOA, [2, 1, 3]); HOAformat_str = ['HOA',num2str(order),'S']; -save(fullfile(erase(sofa_file_name, ".sofa") + "_converted_" + HOAformat_str + ".mat"), "IR") IR_data = IR; diff --git a/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/generate_lr_energies_and_iac.m b/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/generate_lr_energies_and_iac.m new file mode 100644 index 0000000000000000000000000000000000000000..f3e2cf244b39b2a09882694dc635e2291cb47bff --- /dev/null +++ b/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/generate_lr_energies_and_iac.m @@ -0,0 +1,111 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% (C) 2022-2023 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. +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function data_struct = generate_lr_energies_and_iac(sofa_path, sofa_file_name) + % Generate left and right energies and coherence for late reverb from + % HRIRs. + % + % sofa_path - path to the directory that contains the sofa files to be + % converted. + % sofa_file - file name of the HRTFs to be converted + % + % Typical usage: + % generate_lr_energies_and_iac('../HRIRs_sofa', 'HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000.sofa') + % + +audio_format.names(1:4) = {'510'; '710'; '512'; '714'}; + +audio_format.az(1,1:4) = {[30 330 0 110 250]; ... + [30 330 0 110 250 135 225]; ... + [30 330 0 110 250 90 270]; ... + [30 330 0 110 250 135 225 45 315 135 225];}; +audio_format.el(1,1:4) = {[0 0 0 0 0]; ... + [0 0 0 0 0 0 0]; ... + [0 0 0 0 0 45 45]; ... + [0 0 0 0 0 0 0 45 45 45 45];}; + + data_struct = struct.empty(1,0); + sr = [48000, 32000, 16000]; + sr_short = [48, 32, 16]; + sr_dft_size = [240, 160, 80]; + + H = hrtf_library_loader(); + H.readSOFA(char(fullfile(sofa_path, sofa_file_name))); + +Az = squeeze(H.PosSpherical(1,:)) * 180 / pi; +El = squeeze(H.PosSpherical(2,:)) * 180 / pi; + + +indexEl0 = find(El == 0); +indexEl45 = find(El == 42); + +indFmt= 1; + + azis = cell2mat(audio_format.az(indFmt)); + eles = cell2mat(audio_format.el(indFmt)); + +indexPos = []; + +for ind2 = 1 : length(azis) + if (eles(ind2) == 0) + index = find(abs(Az(indexEl0) - azis(ind2)) < 0.0001); + indexPos = [indexPos indexEl0(index)]; + else + index = find(abs(Az(indexEl45) - azis(ind2)) < 0.0001); + indexPos = [indexPos indexEl45(index)]; + end +end + +SourcePosition = [Az(indexPos); El(indexPos); ones(1,length(azis)) * 2 ]'; + + + % 48kHz + IRs_all = permute(H.get_Discrete_HRTFs(), [1,3,2]); + % IRs = IRs_all(:,:,indexPos) * H.Gain; + IRs = IRs_all * H.Gain; + HRTF_mdfts = m_dft(IRs, sr_dft_size(1)); + [left_avg_power, right_avg_power, ia_coherence] = compute_lr_energies_and_iac(HRTF_mdfts, sr_dft_size(1), 257); + + % 32 kHz + % TODO + + % 16 kHz + % TODO + + % + data_struct(1).lr_energies_iac_48kHz = [left_avg_power; right_avg_power; ia_coherence]; + data_struct(1).lr_energies_iac_32kHz = []; + data_struct(1).lr_energies_iac_16kHz = []; + data_struct(1).sr = sr; + data_struct(1).sr_short = sr_short; + data_struct(1).sr_dft_size = sr_dft_size; + +end \ No newline at end of file diff --git a/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/get_cldfb_filter.m b/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/get_cldfb_filter.m new file mode 100644 index 0000000000000000000000000000000000000000..f796dd9ee09ce2d98e18bca7151359f353a60aea --- /dev/null +++ b/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/get_cldfb_filter.m @@ -0,0 +1,163 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% (C) 2022-2023 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. +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function [h, D, S, L] = get_cldfb_filter() +% const float LDQMF_60[] in \lib_com\rom_com.c, line 5219 +S = 60; % stride +L = 60; % frequency bands +D = 240 + S - 1; % system delay +h = [ + 0.0000953076, 0.0001230230, 0.0001279964, 0.0001260533, 0.0001211219 + 0.0001122123, 0.0001010860, 0.0000876540, 0.0000719883, 0.0000545472 + 0.0000352143, 0.0000145686, -0.0000074264, -0.0000303788, -0.0000539205 + -0.0000782743, -0.0001028838, -0.0001275374, -0.0001520015, -0.0001760167 + -0.0001997108, -0.0002226708, -0.0002446725, -0.0002655797, -0.0002852145 + -0.0003034996, -0.0003203036, -0.0003356283, -0.0003493345, -0.0003614030 + -0.0003719004, -0.0003807641, -0.0003881051, -0.0003939842, -0.0003985357 + -0.0004019095, -0.0004041938, -0.0004056677, -0.0004065430, -0.0004069925 + -0.0004072535, -0.0004075877, -0.0004083676, -0.0004098394, -0.0004122990 + -0.0004160839, -0.0004214063, -0.0004285777, -0.0004378651, -0.0004495422 + -0.0004637682, -0.0004806494, -0.0005003878, -0.0005231378, -0.0005489803 + -0.0005777747, -0.0006095612, -0.0006443121, -0.0006813223, -0.0007226231 + -0.0007722576, -0.0008268412, -0.0008839625, -0.0009417336, -0.0010004630 + -0.0010601623, -0.0011206097, -0.0011817788, -0.0012432419, -0.0013045983 + -0.0013656860, -0.0014260965, -0.0014855355, -0.0015435946, -0.0015999591 + -0.0016543545, -0.0017062968, -0.0017554691, -0.0018015467, -0.0018441341 + -0.0018829798, -0.0019177221, -0.0019480695, -0.0019736972, -0.0019943134 + -0.0020097434, -0.0020197174, -0.0020240925, -0.0020226294, -0.0020152442 + -0.0020017736, -0.0019820682, -0.0019561697, -0.0019240153, -0.0018855907 + -0.0018409232, -0.0017900462, -0.0017330211, -0.0016699535, -0.0016009507 + -0.0015261442, -0.0014456788, -0.0013597424, -0.0012685407, -0.0011722331 + -0.0010710671, -0.0009652392, -0.0008549765, -0.0007405236, -0.0006221444 + -0.0005001140, -0.0003745670, -0.0002458634, -0.0001142541, 0.0000199491 + 0.0001564174, 0.0002949402, 0.0004350246, 0.0005769439, 0.0007203126 + -0.0008803223, -0.0010328424, -0.0011841310, -0.0013346316, -0.0014848098 + -0.0016343417, -0.0017832819, -0.0019316213, -0.0020790498, -0.0022252349 + -0.0023701149, -0.0025136294, -0.0026556554, -0.0027960713, -0.0029348312 + -0.0030717771, -0.0032068293, -0.0033399195, -0.0034709862, -0.0035999804 + -0.0037267797, -0.0038513308, -0.0039736414, -0.0040935921, -0.0042111278 + -0.0043262239, -0.0044388464, -0.0045489701, -0.0046565188, -0.0047614835 + -0.0048637423, -0.0049632201, -0.0050599808, -0.0051539382, -0.0052450863 + -0.0053333500, -0.0054187514, -0.0055012843, -0.0055808770, -0.0056575472 + -0.0057313135, -0.0058021732, -0.0058701355, -0.0059352517, -0.0059975707 + -0.0060571772, -0.0061141332, -0.0061685541, -0.0062205540, -0.0062703062 + -0.0063179093, -0.0063635921, -0.0064075105, -0.0064498796, -0.0064908965 + -0.0065308069, -0.0065698619, -0.0066083665, -0.0066466411, -0.0066849431 + -0.0067233290, -0.0067621553, -0.0068021296, -0.0068436749, -0.0068870094 + -0.0069324085, -0.0069801519, -0.0070305937, -0.0070840055, -0.0071406048 + -0.0072006541, -0.0072644479, -0.0073321410, -0.0074039386, -0.0074799177 + -0.0075602704, -0.0076450342, -0.0077342330, -0.0078278277, -0.0079257628 + -0.0080279401, -0.0081341872, -0.0082442267, -0.0083577875, -0.0084744738 + -0.0085938899, -0.0087156557, -0.0088391500, -0.0089637861, -0.0090888245 + -0.0092134504, -0.0093367994, -0.0094579896, -0.0095760096, -0.0096898535 + -0.0097982995, -0.0099003557, -0.0099947909, -0.0100801717, -0.0101551116 + -0.0102182031, -0.0102678994, -0.0103026126, -0.0103207529, -0.0103206923 + -0.0103006857, -0.0102590285, -0.0101939747, -0.0101036867, -0.0099863587 + -0.0098401112, -0.0096632261, -0.0094537362, -0.0092098210, -0.0089295702 + -0.0086111929, -0.0082527259, -0.0078523541, -0.0074084769, -0.0069190590 + 0.0063841688, 0.0057985946, 0.0051621343, 0.0044734711, 0.0037309236 + 0.0029329660, 0.0020781513, 0.0011651339, 0.0001925042, -0.0008409545 + -0.0019364181, -0.0030950012, -0.0043176264, -0.0056051607, -0.0069584334 + -0.0083780792, -0.0098646237, -0.0114185056, -0.0130400723, -0.0147295250 + -0.0164868534, -0.0183120724, -0.0202049762, -0.0221651513, -0.0241921283 + -0.0262852497, -0.0284437388, -0.0306666382, -0.0329528190, -0.0353010744 + -0.0377098918, -0.0401776619, -0.0427025780, -0.0452826768, -0.0479161367 + -0.0506004691, -0.0533332452, -0.0561118126, -0.0589331910, -0.0617944039 + -0.0646922663, -0.0676232576, -0.0705836788, -0.0735698044, -0.0765774846 + -0.0796026587, -0.0826408863, -0.0856874809, -0.0887378305, -0.0917868018 + -0.0948293805, -0.0978601947, -0.1008738130, -0.1038645208, -0.1068264544 + -0.1097536832, -0.1126400903, -0.1154794544, -0.1182654947, -0.1209914312 + -0.1236500666, -0.1262341589, -0.1287376434, -0.1311538219, -0.1334753036 + -0.1356947273, -0.1378047168, -0.1397978216, -0.1416664869, -0.1434033662 + -0.1450008005, -0.1464512348, -0.1477471888, -0.1488809884, -0.1498452872 + -0.1506324410, -0.1512351334, -0.1516460329, -0.1518578976, -0.1518635303 + -0.1516559124, -0.1512281001, -0.1505732536, -0.1496847868, -0.1485562176 + -0.1471813470, -0.1455538720, -0.1436681300, -0.1415183097, -0.1390990764 + -0.1364052594, -0.1334318966, -0.1301742792, -0.1266280264, -0.1227891371 + -0.1186537445, -0.1142183766, -0.1094799563, -0.1044355705, -0.0990828425 + -0.0934195668, -0.0874440819, -0.0811550021, -0.0745511875, -0.0676321834 + -0.0603975877, -0.0528475679, -0.0449828543, -0.0368040986, -0.0283128861 + -0.0195108838, -0.0104003223, -0.0009837818, 0.0087356847, 0.0187546927 + 0.0290693250, 0.0396753438, 0.0505682528, 0.0617432520, 0.0731955394 + -0.0849232078, -0.0969054326, -0.1091460735, -0.1216373071, -0.1343720406 + -0.1473424733, -0.1605402082, -0.1739567965, -0.1875831038, -0.2014097124 + -0.2154271752, -0.2296251506, -0.2439934313, -0.2585212290, -0.2731975317 + -0.2880111337, -0.3029502928, -0.3180032372, -0.3331578076, -0.3484017253 + -0.3637222052, -0.3791064322, -0.3945416212, -0.4100143015, -0.4255111217 + -0.4410185516, -0.4565227628, -0.4720100164, -0.4874662757, -0.5028775334 + -0.5182296634, -0.5335084200, -0.5486994982, -0.5637886524, -0.5787616372 + -0.5936041474, -0.6083019376, -0.6228409410, -0.6372069120, -0.6513859630 + -0.6653640866, -0.6791275144, -0.6926627755, -0.7059561610, -0.7189947963 + -0.7317654490, -0.7442554235, -0.7564523220, -0.7683438063, -0.7799182534 + -0.7911639810, -0.8020697832, -0.8126249313, -0.8228194118, -0.8326428533 + -0.8420860767, -0.8511404991, -0.8597975969, -0.8680517077, -0.8758881092 + -0.8832823634, -0.8902196884, -0.8967157602, -0.9027729034, -0.9083824754 + -0.9135394692, -0.9182395935, -0.9224776030, -0.9262499809, -0.9295535684 + -0.9323854446, -0.9347436428, -0.9366261959, -0.9380323887, -0.9389615655 + -0.9394137263, -0.9393896461, -0.9388904572, -0.9379178882, -0.9364743829 + -0.9345626831, -0.9321863055, -0.9293491840, -0.9260557890, -0.9223110080 + -0.9181203246, -0.9134896994, -0.9084255695, -0.9029349089, -0.8970250487 + -0.8907034993, -0.8839784265, -0.8768582940, -0.8693521619, -0.8614694476 + -0.8532197475, -0.8446131349, -0.8356599212, -0.8263708353, -0.8167568445 + -0.8068289757, -0.7965991497, -0.7860788107, -0.7752800584, -0.7642148733 + -0.7528960109, -0.7413358092, -0.7295469642, -0.7175422311, -0.7053351402 + -0.6929380894, -0.6803644896, -0.6676273942, -0.6547405124, -0.6417166591 + -0.6285686493, -0.6153115034, -0.6019562483, -0.5885198116, -0.5750215650 + 0.5615197420, 0.5478612781, 0.5341838002, 0.5204906464, 0.5067980289 + 0.4931168854, 0.4794588387, 0.4658361673, 0.4522601366, 0.4387422502 + 0.4252935350, 0.4119254053, 0.3986486793, 0.3854739666, 0.3724119067 + 0.3594728410, 0.3466667533, 0.3340034485, 0.3214924335, 0.3091430366 + 0.2969639599, 0.2849639654, 0.2731511295, 0.2615332901, 0.2501178682 + 0.2389119864, 0.2279221565, 0.2171545923, 0.2066148520, 0.1963084787 + 0.1862401515, 0.1764142811, 0.1668347418, 0.1575049609, 0.1484276950 + 0.1396053135, 0.1310400218, 0.1227331311, 0.1146853194, 0.1068974212 + 0.0993694067, 0.0921007246, 0.0850901082, 0.0783365741, 0.0718384907 + 0.0655927584, 0.0595967993, 0.0538481586, 0.0483424664, 0.0430756323 + 0.0380428955, 0.0332404599, 0.0286619961, 0.0242999699, 0.0201510899 + 0.0162059069, 0.0124559226, 0.0088928537, 0.0054926532, 0.0023052765 + -0.0005515143, -0.0030201224, -0.0052712574, -0.0073737046, -0.0093160523 + -0.0111072771, -0.0127562135, -0.0142635731, -0.0156361461, -0.0168790054 + -0.0179969221, -0.0189934950, -0.0198726747, -0.0206398536, -0.0212980714 + -0.0218509119, -0.0223025978, -0.0226570386, -0.0229178313, -0.0230882075 + -0.0231725387, -0.0231746566, -0.0230979007, -0.0229462404, -0.0227237809 + -0.0224345829, -0.0220820960, -0.0216706358, -0.0212045144, -0.0206875466 + -0.0201238506, -0.0195175279, -0.0188730918, -0.0181944817, -0.0174855441 + -0.0167510118, -0.0159947462, -0.0152208358, -0.0144332750, -0.0136361914 + -0.0128338682, -0.0120294262, -0.0112272501, -0.0104311826, -0.0096443929 + -0.0088709844, -0.0081134979, -0.0073764324, -0.0066623385, -0.0059733889 + -0.0053142183, -0.0046856776, -0.0040914025, -0.0035321070, -0.0030089030 + -0.0025271603, -0.0020749648, -0.0016621647, -0.0012705614, -0.0008115423 +]; +h = h.'; +h = h(:); +h(1*120+(1:120)) = -h(1*120+(1:120)); +h(3*120+(1:120)) = -h(3*120+(1:120)); +h(:) = h(end:-1:1); diff --git a/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/get_ls_layout_config.m b/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/get_ls_layout_config.m new file mode 100644 index 0000000000000000000000000000000000000000..2b57aadfcb9b76b02b79dc5fedcd3fee7dc1adb5 --- /dev/null +++ b/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/get_ls_layout_config.m @@ -0,0 +1,167 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% (C) 2022-2023 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. +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function ls_struct = get_ls_layout_config(ls_layout_config) + +ls_struct = struct; +switch ls_layout_config + case 'FOA' + ls_struct.name = 'FOA'; + ls_struct.nb_channel = 4; + ls_struct.azi = [0 0 0 0]; + ls_struct.ele = [0 0 0 0]; + ls_struct.isloudspeaker = 0; + ls_struct.sba_order = 1; + ls_struct.num_lfe = 0; + ls_struct.lfe_index = zeros(0,0); + case 'HOA2' + ls_struct.name = 'HOA2'; + ls_struct.nb_channel = 9; + ls_struct.azi = [0 0 0 0 0 0 0 0 0]; + ls_struct.ele = [0 0 0 0 0 0 0 0 0]; + ls_struct.isloudspeaker = 0; + ls_struct.sba_order = 2; + ls_struct.num_lfe = 0; + ls_struct.lfe_index = zeros(0,0); + case 'HOA3' + ls_struct.name = 'HOA3'; + ls_struct.nb_channel = 16; + ls_struct.azi = [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]; + ls_struct.ele = [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]; + ls_struct.isloudspeaker = 0; + ls_struct.sba_order = 3; + ls_struct.num_lfe = 0; + ls_struct.lfe_index = zeros(0,0); + case {'CICP2', '2d0'} + ls_struct.name = 'CICP2'; + ls_struct.nb_channel = 2; + ls_struct.azi = [30 -30]; + ls_struct.ele = [0 0]; + ls_struct.isloudspeaker = 1; + ls_struct.sba_order = -1; + ls_struct.num_lfe = 0; + ls_struct.lfe_index = zeros(0,0); + case {'CICP6', 'cicp6', '5d1'} + ls_struct.name = 'CICP6'; + ls_struct.nb_channel = 6; + ls_struct.azi = [30 -30 0 0 110 -110]; + ls_struct.ele = [0 0 0 0 0 0]; + ls_struct.isloudspeaker = 1; + ls_struct.sba_order = -1; + ls_struct.num_lfe = 1; + ls_struct.lfe_index = [4]; + case {'CICP12', 'cicp12', '7d1'} % 3 front, 4 surround + 1LFE + ls_struct.name = 'CICP12'; + ls_struct.nb_channel = 8; + ls_struct.azi = [30 -30 0 0 110 -110 135 -135]; + ls_struct.ele = [0 0 0 0 0 0 0 0]; + ls_struct.isloudspeaker = 1; + ls_struct.sba_order = -1; + ls_struct.num_lfe = 1; + ls_struct.lfe_index = [4]; + case {'CICP16', 'cicp16', '5d1p4'} + ls_struct.name = 'CICP16'; + ls_struct.nb_channel = 10; + ls_struct.azi = [30 -30 0 0 110 -110 30 -30 110 -110]; + ls_struct.ele = [0 0 0 0 0 0 35 35 35 35]; + ls_struct.isloudspeaker = 1; + ls_struct.sba_order = -1; + ls_struct.num_lfe = 1; + ls_struct.lfe_index = [4]; + case {'CICP13', 'cicp13','22d2'} + ls_struct.name = 'CICP13'; + ls_struct.nb_channel = 24; + ls_struct.azi = [60 -60 0 0 135 -135 30 -30 180 0 90 -90 45 -45 0 0 135 -135 90 -90 180 0 45 -45]; + ls_struct.ele = [0 0 0 0 0 0 0 0 0 0 0 0 35 35 35 90 35 35 35 35 35 -15 -15 -15]; + ls_struct.isloudspeaker = 1; + ls_struct.sba_order = -1; + ls_struct.num_lfe = 2; + ls_struct.lfe_index = [4 10]; + case {'CICP19', 'cicp19','7d1p4'} + ls_struct.name = 'CICP19'; + ls_struct.nb_channel = 12; + ls_struct.azi = [30 -30 0 0 135 -135 90 -90 30 -30 135 -135]; + ls_struct.ele = [0 0 0 0 0 0 0 0 35 35 35 35]; + ls_struct.isloudspeaker = 1; + ls_struct.sba_order = -1; + ls_struct.num_lfe = 1; + ls_struct.lfe_index = [4]; + case {'Combined'} + ls_struct.name = 'Combined'; + ls_struct.nb_channel = 15; + ls_struct.azi = [30 -30 0 135 -135 110 -110 90 -90 30 -30 110 -110 135 -135]; + ls_struct.ele = [0 0 0 0 0 0 0 0 0 35 35 35 35 35 35]; + ls_struct.isloudspeaker = 1; + ls_struct.sba_order = -1; + ls_struct.num_lfe = 0; + case {'Lebedev_26'} + ls_struct.name = 'Leb26'; + ls_struct.nb_channel = 26; + ls_struct.azi = [0 180.0 90.0 270.0 0 0 90.0 90.0 270.0 270.0 0 0 180.0 180.0 45.0 315.0 135.0 225.0 45.0 45.0 315.0 315.0 135.0 135.0 225.0 225.0]; + ls_struct.ele = [0 0 0 0 90.0 -90.0 45.0 -45.0 45.0 -45.0 45.0 -45.0 45.0 -45.0 0 0 0 0 35.3 -35.3 35.3 -35.3 35.3 -35.3 35.3 -35.3]; + ls_struct.isloudspeaker = 1; + ls_struct.sba_order = -1; + ls_struct.num_lfe = 0; + case {'cube_8'} + ls_struct.name = 'Cub8'; + ls_struct.nb_channel = 8; + ls_struct.azi = [45 45 135 135 225 225 315 315]; + ls_struct.ele = [35.3 -35.3 35.3 -35.3 35.3 -35.3 35.3 -35.3]; + ls_struct.isloudspeaker = 1; + ls_struct.sba_order = -1; + ls_struct.num_lfe = 0; + case {'BINAURAL', 'BINAURAL_ROOM'} + ls_struct.name = 'BINAURAL'; + ls_struct.nb_channel = 2; + ls_struct.azi = [90 -90]; + ls_struct.ele = [0 0]; + ls_struct.isloudspeaker = 2; + ls_struct.sba_order = -1; + ls_struct.num_lfe = 0; + case {'STEREO'} + ls_struct.name = 'STEREO'; + ls_struct.nb_channel = 2; + ls_struct.azi = [90 -90]; + ls_struct.ele = [0 0]; + ls_struct.isloudspeaker = 2; + ls_struct.sba_order = -1; + ls_struct.num_lfe = 0; + case {'MONO'} + ls_struct.name = 'MONO'; + ls_struct.nb_channel = 1; + ls_struct.azi = [0]; + ls_struct.ele = [0]; + ls_struct.isloudspeaker = 1; + ls_struct.sba_order = -1; + ls_struct.num_lfe = 0; + otherwise + error('Loudspeaker layout not supported!'); +end diff --git a/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/hrtf_library_loader.m b/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/hrtf_library_loader.m index c8d41d7e06b244bd7b283ee9203a5557b5742a20..2562b6de4801e1bfcc3ab7a204f171ba81f48f05 100644 --- a/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/hrtf_library_loader.m +++ b/scripts/binauralRenderer_interface/matlab_hrir_generation_scripts/hrtf_library_loader.m @@ -46,6 +46,10 @@ classdef hrtf_library_loader < handle SourceRadius = []; % The source distance for HRTFs in this library PlaybackRadius = []; % The radius for HRTFs during playback Info = {''}; % A cell array of strings with info about this library + PosSpherical = []; % source positiona in spherical representation (rads, meters) + Data = []; + % Remember Global Gain + Gain = 1.0; end properties (Access=protected) % Define the set of uni-vectors for the HRTF directions in a discrete Library @@ -100,6 +104,7 @@ classdef hrtf_library_loader < handle if strcmpi(Units{2},'degree'), Pos(2,:)=Pos(2,:)*pi/180; end assert( any(strcmpi(Units{3}, {'metre','meter','inch'})), 'Unknown units'); if strcmpi(Units{3},'inch' ), Pos(3,:)=Pos(3,:)*0.0254; end + PosSpherical = Pos; Pos = Pos(3,:) .* ... [cos(Pos(2,:)).*[cos(Pos(1,:));sin(Pos(1,:))];sin(Pos(2,:))]; @@ -131,6 +136,12 @@ classdef hrtf_library_loader < handle otherwise error(['unknown GLOBAL_DataType = ', hrtf.GLOBAL_DataType]); end + + if (Data.SamplingRate ~= 48000) + HRTF_L = resample(HRTF_L, 48000,Data.SamplingRate); + HRTF_R = resample(HRTF_R, 48000,Data.SamplingRate); + Data.SamplingRate = 48000; + end % Normalise for unity gain around 1kHz FFTLen=1024; @@ -146,6 +157,7 @@ classdef hrtf_library_loader < handle H.UnitVectors = XYZ; H.HRTF_L = HRTF_L; H.HRTF_R = HRTF_R; + H.PosSpherical = PosSpherical; [~,NameRoot,~] = fileparts(Lib_Name); H.Info.Name = NameRoot; @@ -154,12 +166,24 @@ classdef hrtf_library_loader < handle H.Info.FilterSize = sprintf('%d-tap FIR',IRLen); H.Info.Scaling = 'Normalised to unity gain at 1kHz'; + H.Data = Data; + obj.Gain = MeanG; + obj.process_lib(H, Data.SamplingRate); end function IR = XYZ_to_IR( this, XYZ ) IR = permute(cat(3,this.getHRTF_L(XYZ),this.getHRTF_R(XYZ)),[1,3,2]); end + + function IR = XYZ_to_IR_SD( this, XYZ ) + [HRTF_L, HRTF_R] = this.getHRTF_SD(XYZ); + IR = permute(cat(3,HRTF_L,HRTF_R),[1,3,2]); + end + + function discrete_HRTFs = get_Discrete_HRTFs(this) + discrete_HRTFs = this.Discrete_HRTFs; + end end % methods @@ -212,6 +236,8 @@ classdef hrtf_library_loader < handle obj.buildGDMag(); obj.Last_UV=[]; obj.setLen(512); + obj.PosSpherical = hrtf_lib.PosSpherical; + obj.Data = hrtf_lib.Data; end function setLen(obj,Len) @@ -224,6 +250,19 @@ classdef hrtf_library_loader < handle obj.Last_UV=[]; end + function [HRTFs_L, HRTFs_R] = getHRTF_SD(obj, varargin) + % GETHRTF_SD Get the SD HRTFs for both ears from the library + % Given [N] direction-of-arrival vectors, returns an array + % of size [Len]x[N], containing the N HRTFs. + % Examples: + % HRTFs = H.getHRTF_SD(Az,El) % Az and El are both Nx1 or 1xN vectors (in radians) + % HRTFs = H.getHRTF_SD( Angles ) % Angles is a 2xN array of Az,El column pairs (in radians) + % HRTFs = H.getHRTF_SD(X, Y, Z) % X,Y,Z are all 1xN or Nx1 vectors + % HRTFs = H.getHRTF_SD(Vects) % Vects is a 3xN array of X,Y,Z column vectors + UnitVecs = make_unit_vectors(varargin{:}); + [HRTFs_L, HRTFs_R] = obj.Fetch_Discrete_HRTFs(UnitVecs); + end + function HRTFs = getHRTF_L(obj,varargin) % GETHRTF_L Get one or more Left-ear HRTFs from the library % Given [N] direction-of-arrival vectors, returns an array @@ -343,6 +382,29 @@ classdef hrtf_library_loader < handle end end + function [TempL,TempR]=Fetch_Discrete_HRTFs(obj, UnitVecs) + % We have set of unit-vectors, so we need to fetch the Left/Right + % HRTFs at these (interpolated) angle positions + NoVecs=size(UnitVecs,2); + TempL=zeros(size(obj.Discrete_HRTFs,1),NoVecs); + TempR=zeros(size(obj.Discrete_HRTFs,1),NoVecs); + for k=1:NoVecs + % For each direction (specified by a column of UnitVecs), we need + % to figure out which HRTF Direction Vectors match the + % given position + IndSubset=1:size(obj.Discrete_UnitVectors,2); + Dists=sum( (obj.Discrete_UnitVectors - repmat(UnitVecs(:,k),[1 size(obj.Discrete_UnitVectors,2)])).^2); + [minDist, Dir] = min(Dists(IndSubset)); + % 10e-e4 is roughly the error for 1deg offset on the sphere + if abs(minDist) > 0.015 % 10e-3 + error("Could not find an IR exactly matching this position, please check HRTF set!"); + end + + TempL(:,k)=obj.Discrete_HRTFs(:,Dir,1); + TempR(:,k)=obj.Discrete_HRTFs(:,Dir,2); + end + end + function [TempL,TempR]=Interpolate_Discrete_HRTFs(obj,UnitVecs) % We have set of unit-vectors, so we need to buld the Left/Right diff --git a/scripts/binauralRenderer_interface/mixer_conv_sofa_to_rom_table_converter_readme.txt b/scripts/binauralRenderer_interface/mixer_conv_sofa_to_rom_table_converter_readme.txt index 73314c5cd5188ed690ecc00d4d4b5fd30737db40..ea3e72bc5cbb8678d727644d290d1e4c56b6c706 100644 --- a/scripts/binauralRenderer_interface/mixer_conv_sofa_to_rom_table_converter_readme.txt +++ b/scripts/binauralRenderer_interface/mixer_conv_sofa_to_rom_table_converter_readme.txt @@ -30,13 +30,27 @@ *******************************************************************************************************/ -Mixer conv sofa to rom table converter program +Mixer conv sofa to rom table or binary files converter program ------------------------------ -The sofa to rom format converter is used to generate the c files (*.h,*.c) containing the binary representation of the binaural +The sofa to rom format or binary files converter is used to generate the c files (*.h,*.c) or binary files containing the binary representation of the binaural filters for renderer MIXER_CONV and MIXER_CONV_ROOM -First, build the converter under scripts/binauralRenderer_interface in VSCode (using CMakeList). +First, build the converter under scripts/binauralRenderer_interface in VSCode (using CMakeList) or using the following command lines : + - mkdir build + - cd build + - cmake .. + - cmake --build . (option --config=release) + - cd .. + - Test : + - run py run.py (require matplotlib) -> no error and a figure with impulse response shall appear + +Requirements: +------------ + - Python version 3.9.* with pip + - numpy (pip install numpy) + - netCDF4 (pip install netCDF4) + - SofaReader.py file must be in the same folder as the executable generate_crend_ivas_tables Usage: ------ @@ -44,13 +58,25 @@ generate_crend_ivas_tables [Options] Mandatory parameters : - Frame size in ms (5 or 20) - - list of sofa files (one with HRIR that directions of IVAS combined speakers configuration or more, one with HOA to binaura filters at least order 3, one with BRIR filters that directions of IVAS combined speakers configuration or more) + - list of sofa files at least one. For rom files generation it is needed : + - one with HRIR with directions of IVAS combined speakers configuration or more + - one with FOA to binaural filters, can be obtain from HRIR using ./matlab_hrir_generation_scripts/convert_SD2SHD_HRIRs.m matlab script + - one with HOA order 2 to binaural filters, can be obtain from HRIR using ./matlab_hrir_generation_scripts/convert_SD2SHD_HRIRs.m matlab script + - one with HOA order 3 to binaural filters, can be obtain from HRIR using ./matlab_hrir_generation_scripts/convert_SD2SHD_HRIRs.m matlab script + - one with BRIR filters that directions of IVAS combined speakers configuration or more Options : - -lib_rend_path : Path where output file will be created (with separator, default = './'). - -no_optim : if present the BRIR filters are not optimised the renderer will perform perfect convolution with the complete size of the BRIR (high files size and high complexity). It is useful for debug purpose + -lib_rend_path : path where header and c files will be created (if missing rom files not generated). + -binary_files_path : path where binary files will be created (if missing binary files not generated)\n + -binary_common_file_name : common name for binary files that will be created (crend_hrir-53_brir-Fhg for example + -compute_reverb_rom sofa_file_path : if present reverb rom tables and binary files are computed using sofa_file_path as input HRIRs + -brir_optim_config_path config_file_path : if present brir optimisation process uses parameters stored in config_file_path + Configuration example files are provided in folder : + -brir_no_optim.cfg : for exact convolution of the BRIR by IVAS decoder or renderer + -brir_default_optim.cfg : default values BRIR optimisation used by IVAS decoder or renderer + -brir_low_complexity_optim.cfg : values for BRIR optimisation reducing IVAS decoder or renderer complexity For example : - -./build/generate_crend_ivas_tables.exe -lib_rend_path ../../lib_rend 5 ./HRIRs_sofa/HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000.sofa ./HRIRs_sofa/ORANGE_HRIR_53_HOA3S_48000.sofa ./BRIRs_sofa/IIS_BRIR_officialMPEG_Combined.sofa -./build/generate_crend_ivas_tables -lib_rend_path ../../lib_rend 5 ./HRIRs_sofa/HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000.sofa ./HRIRs_sofa/ORANGE_HRIR_53_HOA3S_48000.sofa ./BRIRs_sofa/IIS_BRIR_officialMPEG_Combined.sofa \ No newline at end of file + +.\\generate_crend_ivas_tables.exe -lib_rend_path ../../lib_rend 5 ./HRIRs_sofa/HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000.sofa ./HRIRs_sofa/HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000_FOA.sofa ./HRIRs_sofa/HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000_HOA2.sofa ./HRIRs_sofa/HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000_HOA3.sofa ./BRIRs_sofa/IIS_BRIR_officialMPEG_Combined.sofa +./generate_crend_ivas_tables -lib_rend_path ../../lib_rend 5 ./HRIRs_sofa/HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000.sofa ./HRIRs_sofa/HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000_FOA.sofa ./HRIRs_sofa/HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000_HAO2.sofa ./HRIRs_sofa/HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000_HOA3.sofa ./BRIRs_sofa/IIS_BRIR_officialMPEG_Combined.sofa diff --git a/scripts/binauralRenderer_interface/param_bin/SH_GainComputation.m b/scripts/binauralRenderer_interface/param_bin/SH_GainComputation.m new file mode 100644 index 0000000000000000000000000000000000000000..2128779acfe2bb037a3c4071132a1f06c370f5b2 --- /dev/null +++ b/scripts/binauralRenderer_interface/param_bin/SH_GainComputation.m @@ -0,0 +1,71 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% (C) 2022-2023 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. +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function sh_gains = SH_GainComputation(dirs_deg, max_order) +% Computation of real-valued spherical harmonic coefficients in ACN/orthonormal +% normalization format + +num_sh = (max_order+1)^2; +az_rad = dirs_deg(:,1)*pi/180; +coel_rad = pi/2-dirs_deg(:,2)*pi/180; +num_el = length(coel_rad); + +% Compute real-valued spherical harmonic coefficients +sh_gains = zeros(num_sh,num_el); +indx = 0; +% l: SH-level (SH-order) +for l = 0:max_order + P = legendre(l,cos(coel_rad)).'; + + % m: SH-mode + for m = -l:l + indx = indx + 1; + % N3D normalization term + norm_term = sqrt((2*l+1)*factorial(l-abs(m))/(4*pi*factorial(l+abs(m)))); + + % trigonometric term + if m > 0 + trg_term = sqrt(2)*cos(m*az_rad); + elseif m == 0 + trg_term = 1; + else + trg_term = -sqrt(2)*sin(m*az_rad); + end + + % associate Legendre function (with compensation of the Condon-Shortley phase term) + Pnm = P(:,abs(m)+1)*(-1)^m; + + % final direct gain + sh_gains(indx,:) = norm_term.*Pnm.*trg_term; + end +end + +end \ No newline at end of file diff --git a/scripts/binauralRenderer_interface/param_bin/equalDistributionUnitVectors.mat b/scripts/binauralRenderer_interface/param_bin/equalDistributionUnitVectors.mat new file mode 100644 index 0000000000000000000000000000000000000000..b242a66423323324236637a8bece44527a5d3fbf --- /dev/null +++ b/scripts/binauralRenderer_interface/param_bin/equalDistributionUnitVectors.mat @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f47ff2387079ac315e2ea4bdf9f6f9c67d47173d9740eef86eec3a7d409f24d7 +size 3844 diff --git a/scripts/binauralRenderer_interface/param_bin/generate_BRIR_in_SHD_CLDFB_PARAMETRIC.m b/scripts/binauralRenderer_interface/param_bin/generate_BRIR_in_SHD_CLDFB_PARAMETRIC.m new file mode 100644 index 0000000000000000000000000000000000000000..5a30bcbf8da4803a49f12787b31817154085f291 --- /dev/null +++ b/scripts/binauralRenderer_interface/param_bin/generate_BRIR_in_SHD_CLDFB_PARAMETRIC.m @@ -0,0 +1,195 @@ +% +% (C) 2022-2023 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. +% + +function [T60, lateEnes, earlyEnes] = generate_BRIR_in_SHD_CLDFB_PARAMETRIC(brir_inputfile, SHhrtf) +% +% [T60, lateEnes, earlyEnes] = generate_BRIR_in_SHD_CLDFB_PARAMETRIC(brir_inputfile, SHhrtf) +% +% First parameter is the name with path to BRIR file in SOFA format +% Second parameter is the HRIR set in SHD created before. +% Return value contains the tables derived from BRIR set. + +%% Load BRIR input file +sofaData = hrtf_library_loader(); +sofaData.readSOFA(brir_inputfile); + +%% Get data and format it for us +% Input VRIR data from SOFA. After permuation, in order (response, ear, dirIndex) +brirs = permute(sofaData.Data.IR(:, :, :), [3 2 1]); + +% Sampling rate of the BRIR set. Currently only checked. +brirFS = sofaData.Data.SamplingRate; +if brirFS ~= 48000 + error('Only 48 kHz sampling rate BRIR is supported for now.') +end + +% Measurement directions for responses. We discard the distance but there should +% be solution that uses only measurements from same distance. +brirAziRad = sofaData.PosSpherical(1, :).'; +brirEleRad = sofaData.PosSpherical(2, :).'; + +% Determine nearest subset corresponding to 5.0 layout. +% All BRIR related parameters are determined based on them + +refAnglesRad = [30 0 -30 110 -110]' * pi/180; +refVectors = [cos(refAnglesRad) sin(refAnglesRad) zeros(size(refAnglesRad))]; +sofaVectors = [cos(brirAziRad).*cos(brirEleRad) sin(brirAziRad).*cos(brirEleRad) sin(brirEleRad)]; +for ch = 1:length(refAnglesRad) + [~, maxIndex] = max(sofaVectors*refVectors(ch,:)'); + chSelect(ch) = maxIndex; +end +brirs = brirs(:, :, chSelect); + +% Remove low frequencies which would cause T60 estimation errors +[B,A] = butter(5, 80/24000, 'high'); +brirs = filter(B, A, brirs); + +% Determine energies for the 5 BRIR pairs in 60 CLDFB frequency bins +nFFT = 120; % 60 frequency bins +window = hanning(nFFT); +freqShiftWindow = window.*exp(-1i*[1:nFFT]'*pi/nFFT); % half bin offset as in CLDFB +enes = []; +for ch = 1:length(refAnglesRad) + % Make low-pass energy enevelope and find its maximum energy position, + % for each BRIR pair separately since the measurements may be not in sync + brirEne = sum(abs(brirs(:, :, ch)).^2,2); + maxEneSearchEnvelope = fftfilt(window, brirEne); + [~, maxEnePos] = max(maxEneSearchEnvelope); + + % Set the first frame to match the maximum energy (i.e., catch the the direct component) + timeIndices = maxEnePos - nFFT + [1:nFFT]'; + + % Determine the energy from that position onwards in 60 sample hops + frameIndex = 1; + while timeIndices(end) < length(brirs) + brirFrame = brirs(timeIndices, :, ch).*repmat(freqShiftWindow, [1 2]); + frameF = fft(brirFrame); + enes(:, frameIndex, ch) = sum(abs(frameF(1:nFFT/2, :)).^2,2); + frameIndex = frameIndex + 1; + timeIndices = timeIndices + nFFT/2; + end +end +% Combine energies across all directions +enes = sum(enes, 3); + +% Determine search range for the T60 determination. In other words, find +% where noise floor starts at each band +for band = 1:nFFT/2 + % This position is a maximum value after the early part + [~, lateStart] = max(enes(band, 5:15)); + + % Ene envelope in dB for the band + eneDb = 10*log10(enes(band, :)); + index = 1; + + % Estimate a linear fit to the energy decay and determine RMSE:s with + % respect to the actual energt decay + for p = lateStart+5:length(eneDb) + indices = [lateStart:p]'; + P = polyfit(indices, eneDb(indices).', 1); + est = polyval(P, indices); + RMSE(index) = rms(est'-eneDb(indices)); + index = index+1; + end + % Find minimum RMSE, but then find the longest sequence that has + % smaller than 1dB larger RMSE + rmseIndicesInRange = (RMSE < (min(RMSE) + 1)); + maxIndexInRange(band) = 1; + for index = 1:length(RMSE) + if rmseIndicesInRange(index) + maxIndexInRange(band) = index; + end + end + % Truncate a little bit from the end, otherwise the start of the noise + % floor slightly appears at the tail + maxIndexInRange(band) = round(maxIndexInRange(band)*0.9); +end + +% Smooth the length of the responses (starts of the noise floor) across +% frequency. This clears any occasional errors at the estimates +maxIndexInRangeSmooth = zeros(nFFT/2, 1); +for band = 1:nFFT/2 + range = band + [-2:2]; + range=range(range > 0); + range=range(range <= nFFT/2); + maxIndexInRangeSmooth(band) = round(median(maxIndexInRange(range))); +end + +% Determine T60, early energies, and late energies +T60 = zeros(nFFT/2,1); +for band = 1:nFFT/2 + [~, lateStart] = max(enes(band, 5:15)); + eneDb = 10*log10(enes(band, :)); + indices = [lateStart:maxIndexInRangeSmooth(band)]; + + % Linear fitting a line, determining T60 based on it + P = polyfit(indices, eneDb(indices), 1); + dbDropPerFrame = P(1); + frames60dBdropped = -60 / dbDropPerFrame; + T60(band) = frames60dBdropped / 48000 * nFFT /2; + + % Formulate early and late part enes + earlyEnes(band) = sum(enes(band, 1:25)); + lateEnes(band) = sum(enes(band, 26:maxIndexInRangeSmooth(band))); +end + +% Compensate earlyEnes with HRIR energy as it is used together with the +% BRIR set in rendering. +order = 3; +SH = SH_GainComputation([refAnglesRad*180/pi zeros(size(refAnglesRad))], order)/0.2821; +SH(2:4, :) = SH(2:4, :) / sqrt(3); +SH(5:9, :) = SH(5:9, :) / sqrt(5); +SH(10:16, :) = SH(10:16,: ) / sqrt(7); +refHrtfEnes = zeros(60, 1); +for band = 1:60 + for ch = 1:length(refAnglesRad) + hrtf = SHhrtf(:, :, band) * SH(:, ch); + refHrtfEnes(band) = refHrtfEnes(band) + mean(abs(hrtf).^2); + end +end +refHrtfEnes = refHrtfEnes / length(refAnglesRad); + +% Limit reference energies such that close to zero or zero HRTF energy would not generate high compensation +% factors for earlyEnes. +refHrtfEnes = max(0.2*median(refHrtfEnes), refHrtfEnes); + +earlyEnes = earlyEnes./refHrtfEnes'; +earlyEnes(1) = earlyEnes(1)*10^(1/10); % 1dB LF boost at first bin to compensate for the high-pass filter + +% Smoothing of the high frequency T60s. Highest range near Nyquist are +% prone for T60 estimation errors. Linearly expand from lower frequencies. +indices = [30:50]'; +P = polyfit(indices, T60(indices), 1); +interp = min(1, [0:30]'/20); +T60(30:60) = T60(30:60).*(1-interp) + polyval(P, [30:60]').*interp; + +% Late part energies are multiplied by sqrt(2), since parametric +% expects such normalization. +lateEnes = lateEnes * sqrt(2); diff --git a/scripts/binauralRenderer_interface/param_bin/generate_HRIR_in_SHD_CLDFB_PARAMETRIC.m b/scripts/binauralRenderer_interface/param_bin/generate_HRIR_in_SHD_CLDFB_PARAMETRIC.m new file mode 100644 index 0000000000000000000000000000000000000000..ff7d6c0146169862ab1e79fd7f1198bbeab919e5 --- /dev/null +++ b/scripts/binauralRenderer_interface/param_bin/generate_HRIR_in_SHD_CLDFB_PARAMETRIC.m @@ -0,0 +1,166 @@ +% +% (C) 2022-2023 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. +% + +function SHhrtf = generate_HRIR_in_SHD_CLDFB_PARAMETRIC(hrir_inputfile) +% +% SHhrtf = generate_HRIR_in_SHD_CLDFB_PARAMETRIC(hrir_inputfile) +% +% Parameter is the input HRIR file in sofa-format. +% Formulated HRTF in SHD CLDFB domain is given as return value. + +%% Load HRIR input file +sofaData = hrtf_library_loader(); +sofaData.readSOFA(hrir_inputfile); + +%% Get data and format it for us +% Input HRIR data from SOFA. After permuation, in order (ear, dirIndex, response) +hrirRaw = permute(sofaData.Data.IR(:, :, :), [2 1 3]); +hrirl = squeeze(hrirRaw(1, :, :)); +hrirr = squeeze(hrirRaw(2, :, :)); + +% Sampling rate of the HRIR set. Currently only checked. +hrirFS = sofaData.Data.SamplingRate; +if hrirFS ~= 48000 + error('Only 48 kHz sampling rate HRIR is supported for now.') +end + +% Measurement directions for responses. We discard the distance but there should +% be solution that uses only measurements from same distance. +HRTFanglesRad = sofaData.PosSpherical(1:2, :).'; + +% Conversion code starts +nBins = 60; +binCenterF = ([0:59]+0.5)/60*24000; +IRlen = 1200; + +nDirs = length(HRTFanglesRad); +groupDelays = zeros(nDirs, 1); +HRIR = zeros(IRlen, 2, nDirs); +HRTFvectors = zeros(nDirs, 3); + +for dirIndex=1:nDirs + azi = HRTFanglesRad(dirIndex, 1); + ele = HRTFanglesRad(dirIndex, 2); + + %% transform coordinates to XYZ vectors + HRTFvectors(dirIndex, 1) = cos(azi)*cos(ele); + HRTFvectors(dirIndex, 2) = sin(azi)*cos(ele); + HRTFvectors(dirIndex, 3) = sin(ele); + + HRIRthis = double([hrirl(dirIndex,: )' hrirr(dirIndex, :)']); + + HRIR(1:length(HRIRthis), :, dirIndex) = HRIRthis; + groupDelays(dirIndex) = median([grpdelay(HRIR(1:512, 1, dirIndex)); grpdelay(HRIR(1:512, 2, dirIndex))]); +end + +HRTF = fft(HRIR, 1200); +HRTF = HRTF(1:end/2, :, :); + +%% Reference impulse for estimating the steering vectors (transfer functions) +refImpulse = zeros(IRlen, 1); +refImpulse(round(median(groupDelays))) = 1; + +ref = CLDFB(refImpulse); +refEne = repmat(sum(abs(ref).^2,2), [1 2]); + +%% IVAS filter-bank assumed +HRTFs = zeros(nBins, 2, nDirs); + +%% HRIR -> HRTF +for dirIndex = 1:nDirs + HRTFs_this = CLDFB(HRIR(:, :, dirIndex)); + phase = angle(squeeze(sum(HRTFs_this.*conj(repmat(ref, [1 1 2])), 2))); + energy = squeeze(sum(abs(HRTFs_this).^2, 2))./refEne; + HRTFs(:, :, dirIndex) = sqrt(energy).*exp(1i*phase); +end + +%% Diffuse field equalization and formulation of the diffuse field response +load equalDistributionUnitVectors +srcVec = equalDistributionUnitVectors; +diffEne = zeros(nBins,1); + +for k = 1:length(srcVec) + dirVec = srcVec(k, :); + [~, maxIndex] = max(HRTFvectors * dirVec'); + HRTF_this = HRTFs(:, :, maxIndex); + diffEne = diffEne + sum(abs(HRTF_this).^2, 2); +end + +%% +diffEne = diffEne/length(srcVec)/2; +EQ = sqrt(1./diffEne); +EQ = min(EQ, median(EQ)*5); % Avoid multiply non-existent data with large values (e.g. HF is missing in data) +HRTFs = HRTFs.*repmat(EQ, [1 2 nDirs]); + +order = 3; +SH = SH_GainComputation(HRTFanglesRad / pi * 180, order)/0.2821; +SH(2:4, :) = SH(2:4, :) / sqrt(3); +SH(5:9, :) = SH(5:9, :) / sqrt(5); +SH(10:16, :) = SH(10:16, :) / sqrt(7); +SH = SH'; +SHhrtf = zeros(size(SH,2), 2, 60); +SHpinv = pinv(SH); +for bin = 1:nBins + hrtfThis = permute(HRTFs(bin, :, :), [3 2 1]); + if binCenterF(bin) > 2000 % Hz + hrtfThis = abs(hrtfThis); + end + SHhrtf(:, :, bin) = (SHpinv*hrtfThis); +end + +SHhrtf = permute(SHhrtf, [2 1 3]); + +end % function + + +function FD = CLDFB(sig) + % retrieve filter prototype + [h, D, S, L] = get_cldfb_filter(); + proto = h(end:-1:1); + + % Modulate prototype by half bin, and scale to match C implementation + proto = proto.*exp(-1j*[0.5:1:600]'/120*pi) / 0.75; + numCh = size(sig, 2); + sig = sig(1:end-mod(size(sig),60), :); + FD = zeros(60, size(sig,1)/60, numCh); + sig = [zeros(540, numCh); sig]; + indices = [1:600]'; + FDindex = 1; + while indices(end) <= length(sig) + frame = sig(indices, :).*repmat(proto, [1 numCh]); + frameWrap = frame(1:120, :) + frame(121:240, :) + frame(241:360, :) + frame(361:480, :) + frame(481:600, :); + frameWrap = circshift(frameWrap, [60 0]); + FDsig = fft(frameWrap); + phase = [0:59]'/60*pi/2 + pi/2; + FD(:, FDindex, :) = FDsig(1:60, :).*repmat(exp(-1i*phase), [1 numCh]); + FDindex = FDindex + 1; + indices = indices + 60; + end +end diff --git a/scripts/binauralRenderer_interface/param_bin/generate_tables_for_parametric_binauralizer.m b/scripts/binauralRenderer_interface/param_bin/generate_tables_for_parametric_binauralizer.m new file mode 100644 index 0000000000000000000000000000000000000000..788c05fb60a5c999bd05a93ab73d3fd6ac9f011a --- /dev/null +++ b/scripts/binauralRenderer_interface/param_bin/generate_tables_for_parametric_binauralizer.m @@ -0,0 +1,158 @@ +% +% (C) 2022-2023 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. +% + +% +% Generate tables from given HRIRs and BRIRs for IVAS binaural renderers PARAMETRIC and FASTCONV +% +if exist('clearButKeepNeededVariables') + clearButKeepNeededVariables; +else + clear all; +end +close all; +clc; + +%% Add path to routines get_cldfb_filter.m and hrtf_library_loader.m +if isfolder(['..' filesep() 'matlab_hrir_generation_scripts/']) + addpath(['..' filesep() 'matlab_hrir_generation_scripts/']); +end + +%% Set arguments +if ~exist("writeRomFileOutput",'var') + writeRomFileOutput = true; +end +if ~exist("writeBinaryOutput",'var') + writeBinaryOutput = true; +end +if ~exist("rom_file",'var') + rom_file = fullfile('.', 'ivas_rom_binauralRenderer.c'); +end +if ~exist("bin_file",'var') + bin_file = fullfile('.', 'parambin_binary_rom.bin'); +end +%% Set input files +if ~exist("hrir_file",'var') + hrir_file = fullfile('..', 'HRIRs_sofa', 'HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000.sofa'); +end +if ~exist("brir_file",'var') + brir_file = fullfile('..', 'BRIRs_sofa', 'IIS_BRIR_officialMPEG_Combined.sofa'); +end + +if writeRomFileOutput + %% Open file and write header + if ismac + username = getenv('USER'); + else + username = getenv('username'); + end + fid = fopen(fullfile('.', rom_file), 'at'); + fprintf(fid, '/*\n'); + fprintf(fid, ' * Generated on %s with Matlab version %s by %s on %s\n', datetime("today"), version, username, computer); + fprintf(fid, ' * Binaural rendering data set based on BRIRs \n Tables derived from Mozart IIS BRIRs.*/'); + fprintf(fid, '\n\n\n'); +end + + +%% Generate C-code tables for RENDERER_BINAURAL_PARAMETRIC (SHD) +disp('Processing HRIR for parametric renderer...'); +SHhrtf = generate_HRIR_in_SHD_CLDFB_PARAMETRIC(hrir_file); + +if writeRomFileOutput + writeData3L(fid, 'const float hrtfShCoeffsRe[BINAURAL_CHANNELS][HRTF_SH_CHANNELS][HRTF_NUM_BINS]', real(SHhrtf)); + writeData3L(fid, 'const float hrtfShCoeffsIm[BINAURAL_CHANNELS][HRTF_SH_CHANNELS][HRTF_NUM_BINS]', imag(SHhrtf)); +end + +%% Generate C-code tables for RENDERER_BINAURAL_PARAMETRIC_ROOM (SHD) +disp('Processing BRIR for parametric renderer...'); +[T60, lateEnes, earlyEnes] = generate_BRIR_in_SHD_CLDFB_PARAMETRIC(brir_file, SHhrtf); + +if writeRomFileOutput + % Write BRIR parameters to file + fprintf(fid, 'const float parametricReverberationTimes[CLDFB_NO_CHANNELS_MAX] = {\n'); + for k = 1:60 + if mod(k-1, 10)==0 + fprintf(fid, ' '); + end + if k < 60 + fprintf(fid, '%ff,', T60(k)); + else + fprintf(fid, '%ff\n};', T60(k)); + end + if k>1 && mod(k, 10)==0 + fprintf(fid, '\n'); + else + fprintf(fid, ' '); + end + end + + fprintf(fid, '\n\nconst float parametricReverberationEneCorrections[CLDFB_NO_CHANNELS_MAX] = {\n'); + for k = 1:60 + if mod(k-1, 10)==0 + fprintf(fid,' '); + end + if k < 60 + fprintf(fid, '%ff,', lateEnes(k)); + else + fprintf(fid, '%ff\n};', lateEnes(k)); + end + if k>1 && mod(k, 10)==0 + fprintf(fid, '\n'); + else + fprintf(fid, ' '); + end + end + + fprintf(fid, '\n\nconst float parametricEarlyPartEneCorrection[CLDFB_NO_CHANNELS_MAX] = {\n'); + for k = 1:60 + if mod(k-1, 10)==0 + fprintf(fid, ' '); + end + if k < 60 + fprintf(fid, '%ff,', earlyEnes(k)); + else + fprintf(fid, '%ff\n};', earlyEnes(k)); + end + if k>1 && mod(k, 10)==0 + fprintf(fid, '\n'); + else + fprintf(fid, ' '); + end + end +end + +if writeRomFileOutput + fclose(fid); +end + +%% +if writeBinaryOutput + write_parametric_binauralizer_binary_data(bin_file, SHhrtf, T60, lateEnes, earlyEnes); + %save('parambin_binary_rom.mat', 'SHhrtf', 'T60', 'lateEnes', 'earlyEnes'); % debug saving +end diff --git a/scripts/binauralRenderer_interface/param_bin/write_parametric_binauralizer_binary_data.m b/scripts/binauralRenderer_interface/param_bin/write_parametric_binauralizer_binary_data.m new file mode 100644 index 0000000000000000000000000000000000000000..5fd8c79b02f43064846ca1447b7b420b16f7bf8c --- /dev/null +++ b/scripts/binauralRenderer_interface/param_bin/write_parametric_binauralizer_binary_data.m @@ -0,0 +1,96 @@ +% +% (C) 2022-2023 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. +% + +function write_parametric_binauralizer_binary_data(filename, SHhrtf, T60, late_enes, early_enes) +% +% Writes HRIR & BRIR based data for parametric binauralizer into a binary file. +% +% write_parametric_binauralizer_binary_data(filename, SHhrtf, T60, late_enes, early_enes) +% +% filename : string +% name of the file to be written +% SHhrtf : array of shape (2, 16, 60) i.e., (BINAURAL_CHANNELS, HRTF_SH_CHANNELS, HRTF_NUM_BINS), complex-valued +% HRTF coefficients +% T60 : array of shape (60, 1), i.e., (CLDFB_NO_CHANNELS_MAX, 1), double +% late_enes : array of shape (1, 60), i.e., (1, CLDFB_NO_CHANNELS_MAX), double +% early_enes : array of shape (1, 60), i.e., (1, CLDFB_NO_CHANNELS_MAX), double +% +% +% Output file format: +% HRTFs +% HRTF_SH_CHANNELS => uint16_t +% HRTF_NUM_BINS => uint16_t +% hrtfShCoeffsRe => float[BINAURAL_CHANNELS][HRTF_SH_CHANNELS][HRTF_NUM_BINS]; +% hrtfShCoeffsIm => float[BINAURAL_CHANNELS][HRTF_SH_CHANNELS][HRTF_NUM_BINS]; +% +% BRIR-based reverb +% CLDFB_NO_CHANNELS_MAX => uint16_t +% parametricReverberationTimes => float[CLDFB_NO_CHANNELS_MAX]; +% parametricReverberationEneCorrections => float[CLDFB_NO_CHANNELS_MAX]; +% parametricEarlyPartEneCorrection => float[CLDFB_NO_CHANNELS_MAX]; +% + +[f_id, err_msg] = fopen(filename, 'wb'); + +if f_id == -1 + error('Could not open file %s for writing. Error message:\n%s', filename, err_msg); +end + +% HRTFs +n_chnls_bin = 2; +hrtf_sh_channels = size(SHhrtf, 2); +hrtf_num_bins = size(SHhrtf, 3); + +fwrite(f_id, hrtf_sh_channels, 'uint16'); +fwrite(f_id, hrtf_num_bins, 'uint16'); + +% hrtfShCoeffsRe +for bin_chnl_idx = 1:n_chnls_bin + for hrtf_chnl_idx = 1:hrtf_sh_channels + fwrite(f_id, real(SHhrtf(bin_chnl_idx, hrtf_chnl_idx, :)), 'float32'); % HRTF_NUM_BINS elements + end +end + +% hrtfShCoeffsIm +for bin_chnl_idx = 1:n_chnls_bin + for hrtf_chnl_idx = 1:hrtf_sh_channels + fwrite(f_id, imag(SHhrtf(bin_chnl_idx, hrtf_chnl_idx, :)), 'float32'); % HRTF_NUM_BINS elements + end +end + +% BRIR-based reverb +cldfb_no_channels_max = size(T60, 1); + +fwrite(f_id, cldfb_no_channels_max, 'uint16'); +fwrite(f_id, T60, 'float32'); % parametricReverberationTimes +fwrite(f_id, late_enes, 'float32'); % parametricReverberationEneCorrections +fwrite(f_id, early_enes, 'float32'); % parametricEarlyPartEneCorrection + +fclose(f_id); diff --git a/scripts/binauralRenderer_interface/resolve_build_dep.py b/scripts/binauralRenderer_interface/resolve_build_dep.py deleted file mode 100644 index 4489770a2ae5cfdc8fe01800787bde3a456ad38e..0000000000000000000000000000000000000000 --- a/scripts/binauralRenderer_interface/resolve_build_dep.py +++ /dev/null @@ -1,134 +0,0 @@ -""" - (C) 2022-2023 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. -""" - -import os -import sys -import subprocess -import urllib.request -import shutil -import zipfile -import errno -import fileinput - - -def main(): - zlib_src_dir = './Externals/zlib' - extracted_zlib_dir = get_zlib(zlib_src_dir) - #extracted_zlib_dir = 'zlib_dir/zlib-1.2.12' - # delete_files(zlib_src_dir) - print(extracted_zlib_dir) - return extracted_zlib_dir - - -def check_rm_and_makedir(dir_path): - if not os.path.exists(dir_path): - try: - os.makedirs(dir_path) - except OSError as e: - if e.errno != errno.EEXIST: - raise # raises the error again - else: - shutil.rmtree(dir_path, ignore_errors=True) - check_rm_and_makedir(dir_path) - - -def extract_files(file_name, extract_path): - check_rm_and_makedir(extract_path) - with zipfile.ZipFile(file_name, 'r') as zip_ref: - zip_ref.extractall(extract_path) - - -def get_zlib(zlib_dir): - url = 'https://github.com/madler/zlib/archive/refs/tags/v1.2.12.zip' - file_name = 'zlib1212.zip' - if os.path.isfile(file_name): - os.remove(file_name) - # Download the file from `url` and save it locally under `file_name`: - with urllib.request.urlopen(url) as response, open(file_name, 'wb') as out_file: - shutil.copyfileobj(response, out_file) - - if os.path.isfile(file_name): - extract_files(file_name, zlib_dir) - extracted_zlib_dir = zlib_dir + '/zlib-1.2.12' - os.remove(file_name) - else: - extracted_zlib_dir = '' - assert False - - return extracted_zlib_dir - - -def find_config(file, search_text): - f = open(file, 'r') - empty_line = '' - for line in f: - if search_text in line: - return line - return empty_line - - -def add_config(file, tag, prop): - for line in fileinput.FileInput(file, inplace=1): - if tag in line: - line = line.replace(line, line+prop) - sys.stdout.write(line) - - -def replace_config(file, search_text, replace_text): - for line in fileinput.input(file, inplace=1): - if search_text in line: - line = line.replace(search_text, replace_text) - sys.stdout.write(line) - - -def scr_fun(tag, src_file, dest_file): - new_config = find_config(src_file, tag) - if len(new_config) == 0: - print('property not found in IVAS project file, update IVAS project file first') - assert False - old_config = find_config(dest_file, tag) - replace_config(dest_file, old_config, new_config) - - -def scr_fun2(tag, src_file, dest_file, tag2): - new_config = find_config(src_file, tag) - if len(new_config) == 0: - print('property not found in IVAS project file, update IVAS project file first') - assert False - add_config(dest_file, tag2, new_config) - - -def delete_files(extracted_zlib_dir): - if os.path.exists(extracted_zlib_dir): - shutil.rmtree(extracted_zlib_dir, ignore_errors=True) - - -if __name__ == "__main__": - main() diff --git a/scripts/td_object_renderer/modeling_tool/Gen_Hrf_IVAS_Binary.m b/scripts/td_object_renderer/modeling_tool/Gen_Hrf_IVAS_Binary.m index 6d2cdb0e615877bc3dcf16b3c76bc0287a0c63e5..9e1b4cb674288b20dd5e58f29e5d2fc41d5f65a7 100644 --- a/scripts/td_object_renderer/modeling_tool/Gen_Hrf_IVAS_Binary.m +++ b/scripts/td_object_renderer/modeling_tool/Gen_Hrf_IVAS_Binary.m @@ -26,7 +26,7 @@ % 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. -function Gen_Hrf_IVAS_Binary(dataSpec, modSpec) +function Gen_Hrf_IVAS_Binary(dataSpec, modSpec, info) %% Config filePath = modSpec.folderMod; % Path for outputs @@ -47,10 +47,152 @@ load(fn,'mod'); mod_hrf_org = mod.mod.interp.hrf; mod_itd_org = mod.mod.interp.itd; fs_orig = 48000; +fs_last = 16000; + +if dataSpec.genRomFile + h_file_name = fullfile(dataSpec.romOutDir,'ivas_rom_TdBinauralRenderer.h'); + c_file_name = fullfile(dataSpec.romOutDir,'ivas_rom_TdBinauralRenderer.c'); + + copyright_str = string(join({ + '/******************************************************************************************************' + '' + ' (C) 2022-2023 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.' + '' + '*******************************************************************************************************/' + '' + }, newline)); + + %% Write out the header + fileID_h = fopen(h_file_name,'wt'); + fprintf(fileID_h,'%s', copyright_str); + + h_file_content = string(join({ + '' + '' + '#ifndef _IVAS_ROM_TDBINAURALRENDERER_' + '#define _IVAS_ROM_TDBINAURALRENDERER_' + '' + '#include ' + '#include "options.h"' + '#ifdef DEBUGGING' + '#include "debug.h"' + '#endif' + '#include "cnst.h"' + '#include "ivas_cnst.h"' + '' + '/*-------------------------------------------------------------------------' + ' * TD Binaural rendering related ROM tables' + ' *------------------------------------------------------------------------*/' + '/* TD renderer default HRIR model */' + 'extern const float defaultHRIR_rom_latency_s;' + ['extern const int16_t defaultHRIR_rom_azimDim2[' int2str(size(mod_hrf_org.elevBf{1}, 3)) '];'] + ['extern const int16_t defaultHRIR_rom_azimDim3[' int2str(size(mod_hrf_org.elevBf{1}, 3)) '];'] + ['extern const int16_t defaultHRIR_rom_azim_start_idx[' int2str(size(mod_hrf_org.elevBf{1}, 3)) '];'] + 'extern const int16_t defaultHRIR_rom_azimSegSamples[1];' + ['extern const int16_t defaultHRIR_rom_azimShapeIdx[' int2str(size(mod_hrf_org.elevBf{1}, 3)) '];'] + ['extern const int16_t defaultHRIR_rom_azimShapeSampFactor[' int2str(size(mod_hrf_org.elevBf{1}, 3)) '];'] + ['extern const float defaultHRIR_rom_elevKSeq[' int2str(length(mod_hrf_org.elevKSeq{1})) '];'] + ['extern const uint32_t defaultHRIR_rom_AlphaL48[' int2str(size(mod_hrf_org.WL{1}, 1)) ' * ' int2str(size(mod_hrf_org.WL{1}, 2)) '];'] + ['extern const uint32_t defaultHRIR_rom_AlphaR48[' int2str(size(mod_hrf_org.WR{1}, 1)) ' * ' int2str(size(mod_hrf_org.WR{1}, 2)) '];'] + ['extern const uint32_t defaultHRIR_rom_AlphaL32[' int2str(size(mod_hrf_org.WL{1}, 1)) ' * ' int2str(ceil(32*size(mod_hrf_org.WL{1}, 2)/48)) '];'] + ['extern const uint32_t defaultHRIR_rom_AlphaR32[' int2str(size(mod_hrf_org.WR{1}, 1)) ' * ' int2str(ceil(32*size(mod_hrf_org.WR{1}, 2)/48)) '];'] + ['extern const uint32_t defaultHRIR_rom_AlphaL16[' int2str(size(mod_hrf_org.WL{1}, 1)) ' * ' int2str(ceil(16*size(mod_hrf_org.WL{1}, 2)/48)) '];'] + ['extern const uint32_t defaultHRIR_rom_AlphaR16[' int2str(size(mod_hrf_org.WR{1}, 1)) ' * ' int2str(ceil(16*size(mod_hrf_org.WR{1}, 2)/48)) '];'] + ['extern const uint32_t defaultHRIR_rom_EL48[HRTF_MODEL_N_SECTIONS * ' int2str(size(mod_hrf_org.WL{1}, 1)) '];'] + ['extern const uint32_t defaultHRIR_rom_ER48[HRTF_MODEL_N_SECTIONS * ' int2str(size(mod_hrf_org.WR{1}, 1)) '];'] + ['extern const uint32_t defaultHRIR_rom_EL32[HRTF_MODEL_N_SECTIONS * ' int2str(size(mod_hrf_org.WL{1}, 1)) '];'] + ['extern const uint32_t defaultHRIR_rom_ER32[HRTF_MODEL_N_SECTIONS * ' int2str(size(mod_hrf_org.WR{1}, 1)) '];'] + ['extern const uint32_t defaultHRIR_rom_EL16[HRTF_MODEL_N_SECTIONS * ' int2str(size(mod_hrf_org.WL{1}, 1)) '];'] + ['extern const uint32_t defaultHRIR_rom_ER16[HRTF_MODEL_N_SECTIONS * ' int2str(size(mod_hrf_org.WR{1}, 1)) '];'] + }, newline)); + fprintf(fileID_h,'%s', h_file_content); + + fclose(fileID_h); + + %% Write out the header + fileID_c = fopen(c_file_name,'wt'); + fprintf(fileID_c,'%s', copyright_str); + + if ismac + username = getenv('USER'); + else + username = getenv('username'); + end + + fprintf(fileID_c, '/*\n'); + fprintf(fileID_c, ' * Generated on %s with Matlab version %s by %s on %s\n', datetime("today"), version, username, computer); + fprintf(fileID_c, [' * Binaural rendering data set based on BRIRs\n']); + fprintf(fileID_c, [' * Tables derived from Mozart IIS BRIRs.*/']); + fprintf(fileID_c, '\n\n'); + + c_file_content = string(join({ + '' + '/* clang-format off */' + '' + '#include ' + '#include "options.h"' + '#ifdef DEBUGGING' + '#include "debug.h"' + '#endif' + '#include "cnst.h"' + '#include "ivas_cnst.h"' + '#include "wmc_auto.h"' + '' + '#define WMC_TOOL_SKIP' + '' + '/*-------------------------------------------------------------------------' + ' * TD Binaural rendering related ROM tables' + ' *------------------------------------------------------------------------*/' + '/* TD renderer default HRIR model */' + '' + }, newline)); + fprintf(fileID_c,'%s', c_file_content); + + fclose(fileID_c); + + fileID_c = fopen(c_file_name,'at'); + + c_file_content = string(join({ + ['const float defaultHRIR_rom_latency_s = ' num2str(mod.dat.hrf.hrf_latency,'%.9f') 'f;'] + '' + }, newline)); + fprintf(fileID_c,'%s', c_file_content); + + fclose(fileID_c); + +end + %% Generate paramters for model for fs = [48000 32000 16000] fs_khz = fs/1000; - outputBinaryFileName = sprintf('hrfilter_model_v%03d_%dkHz.bin',modelVersion,fs_khz); +% outputBinaryFileName = sprintf('hrfilter_model_v%03d_%dkHz.bin',modelVersion,fs_khz); + outputBinaryFileName = sprintf(['td_' erase(info.fileNameHrf,'.sofa') '_model_v%03d_%dkHz.bin'],modelVersion,fs_khz); % HR filters, sample basis functions mod_hrf = mod_hrf_org; @@ -243,15 +385,90 @@ for fs = [48000 32000 16000] fwrite(fileID, mod_hrf.elevKSeq{1}, 'float'); % length = elevDim3-2 % Azimuth model structure azim_start_idx = 0; + + c_file_content_dim2 = { + ['const int16_t defaultHRIR_rom_azimDim2[' num2str(elevDim3) '] = {'] + }; + c_file_content_dim3 = { + ['const int16_t defaultHRIR_rom_azimDim3[' num2str(elevDim3) '] = {'] + }; + c_file_content_start_idx = { + ['const int16_t defaultHRIR_rom_azim_start_idx[' num2str(elevDim3) '] = {'] + }; + + content_dim2 = ''; + content_dim3 = ''; + content_start_idx = ''; for i = 1:elevDim3 azimDim2 = size(mod_hrf.azimBf{i}, 2); azimDim3 = size(mod_hrf.azimBf{i}, 3); fwrite(fileID, azimDim2, 'short'); % azimDim2 + content_dim2 = [content_dim2 int2str(azimDim2) ', ']; fwrite(fileID, azimDim3, 'short'); % azimDim3 = Q + content_dim3 = [content_dim3 int2str(azimDim3) ', ']; fwrite(fileID, azim_start_idx, 'short'); % start azim index per elevation + content_start_idx = [content_start_idx int2str(azim_start_idx) ', ']; azim_start_idx = azim_start_idx + azimDim3; fwrite(fileID, mod_hrf.azimKSeq{i}, 'float'); % length = azimDim3+1 end + if fs == fs_orig && dataSpec.genRomFile + fileID_c = fopen(c_file_name,'at'); + c_file_content_dim2{size(c_file_content_dim2,2)+1} = content_dim2; + c_file_content_dim2{size(c_file_content_dim2,2)+1} = '};'; + c_file_content_dim2{size(c_file_content_dim2,2)+1} = ''; + c_file_content_dim3{size(c_file_content_dim3,2)+1} = content_dim3; + c_file_content_dim3{size(c_file_content_dim3,2)+1} = '};'; + c_file_content_dim3{size(c_file_content_dim3,2)+1} = ''; + c_file_content_start_idx{size(c_file_content_start_idx,2)+1} = content_start_idx; + c_file_content_start_idx{size(c_file_content_start_idx,2)+1} = '};'; + c_file_content_start_idx{size(c_file_content_start_idx,2)+1} = ''; + + c_file_content = string(join(c_file_content_dim2,newline)); + fprintf(fileID_c,'%s', c_file_content); + c_file_content = string(join(c_file_content_dim3,newline)); + fprintf(fileID_c,'%s', c_file_content); + c_file_content = string(join(c_file_content_start_idx,newline)); + fprintf(fileID_c,'%s', c_file_content); + + c_file_content = ['const int16_t defaultHRIR_rom_azimSegSamples[1] = {' newline num2str(mod_hrf_org.azimKmSeq{1,2}(2)) ',' newline '};' newline]; + fprintf(fileID_c,'%s', c_file_content); + + arr_str = mat2str(azimShapeIdx); + arr_str = arr_str(2:end); + arr_str(end) = ';'; + arr_str = replace(arr_str,';', ', '); + c_file_content = ... + ['const int16_t defaultHRIR_rom_azimShapeIdx[' num2str(length(azimShapeIdx)) '] = {' newline ... + arr_str ... + newline '};' newline ... + ]; + fprintf(fileID_c,'%s', c_file_content); + + arr_str = mat2str(azimShapeSampFactor); + arr_str = arr_str(2:end); + arr_str(end) = ';'; + arr_str = replace(arr_str,';', ', '); + c_file_content = ... + ['const int16_t defaultHRIR_rom_azimShapeSampFactor[' num2str(length(azimShapeSampFactor)) '] = {' newline ... + arr_str ... + newline '};' newline ... + ]; + fprintf(fileID_c,'%s', c_file_content); + + arr_str = mat2str(mod_hrf_org.elevKSeq{1}); + arr_str = arr_str(2:end); + arr_str(end) = ' '; + arr_str = replace(arr_str,' ', '.000000f, '); + c_file_content = ... + ['const float defaultHRIR_rom_elevKSeq[' num2str(length(mod_hrf_org.elevKSeq{1})) '] = {' newline ... + arr_str ... + newline '};' newline ... + ]; + fprintf(fileID_c,'%s', c_file_content); + fclose(fileID_c); + + end + % Weights fwrite(fileID, size(mod_hrf.WL{1},1), 'short'); % (P*Q) fwrite(fileID, mod_hrf.WL{1}, 'float'); % (P*Q) by K @@ -274,6 +491,177 @@ for fs = [48000 32000 16000] fwrite(fileID, elevSplineShape_all, 'float'); % elevation shapes fwrite(fileID, e_num_points, 'short'); % samples between knot points + if fs == fs_orig && dataSpec.genRomFile + + fileID_c = fopen(c_file_name,'at'); + + arr_str = join(mat2str(num2hex(single(elevSplineShape_all)))); + arr_str = arr_str(2:end); + arr_str(end) = ';'; + arr_str = replace(arr_str, "';",','); + arr_str = replace(arr_str, "'",'0x'); + c_file_content = ... + ['const uint32_t defaultHRIR_rom_elevBsShape[' num2str(length(elevSplineShape_all)) '] = {' newline ... + arr_str ... + newline '};' newline ... + ]; + fprintf(fileID_c,'%s', c_file_content); + + arr_str = join(mat2str(num2hex(single(azimSplineShape{n})))); + arr_str = arr_str(2:end); + arr_str(end) = ';'; + arr_str = replace(arr_str, "';",','); + arr_str = replace(arr_str, "'",'0x'); + c_file_content = ... + ['const uint32_t defaultHRIR_rom_azimBsShape[' num2str(length(azimSplineShape{n})) '] = {' newline ... + arr_str ... + newline '};' newline newline ... + ]; + fprintf(fileID_c,'%s', c_file_content); + fclose(fileID_c); + + end + + if dataSpec.genRomFile + + fileID_c = fopen(c_file_name,'at'); + + arr_str_all = num2hex(single(mod_hrf.WL{1})); + numCol = 25; + numIter = floor(size(mod_hrf.WL{1},1)*size(mod_hrf.WL{1},2)/numCol); + numRemain = size(mod_hrf.WL{1},1)*size(mod_hrf.WL{1},2) - numCol * numIter; + c_file_content = ... + ['const uint32_t defaultHRIR_rom_AlphaL' num2str(fs/1000) '[' int2str(size(mod_hrf.WL{1}, 1)) ' * ' int2str(size(mod_hrf.WL{1}, 2)) '] = {' newline ]; + fprintf(fileID_c,'%s', c_file_content); + for ind = 1: numIter + arr_str = join(mat2str(arr_str_all((ind-1) * numCol + 1 :ind * numCol, : ))); + arr_str = arr_str(2:end); + arr_str(end) = ';'; + arr_str = replace(arr_str, "';",','); + arr_str = replace(arr_str, "'",'0x'); + c_file_content = [ arr_str newline]; + fprintf(fileID_c,'%s', c_file_content); + end + arr_str = join(mat2str(arr_str_all(ind * numCol + 1 :ind * numCol + numRemain, : ))); + arr_str = arr_str(2:end); + arr_str(end) = ';'; + arr_str = replace(arr_str, "';",','); + arr_str = replace(arr_str, "'",'0x'); + c_file_content = [ arr_str newline '};' newline]; + fprintf(fileID_c,'%s', c_file_content); + + arr_str_all = num2hex(single(mod_hrf.WR{1})); + numCol = 25; + numIter = floor(size(mod_hrf.WR{1},1)*size(mod_hrf.WR{1},2)/numCol); + numRemain = size(mod_hrf.WR{1},1)*size(mod_hrf.WR{1},2) - numCol * numIter; + c_file_content = ... + ['const uint32_t defaultHRIR_rom_AlphaR' num2str(fs/1000) '[' int2str(size(mod_hrf.WR{1}, 1)) ' * ' int2str(size(mod_hrf.WR{1}, 2)) '] = {' newline ]; + fprintf(fileID_c,'%s', c_file_content); + for ind = 1: numIter + arr_str = join(mat2str(arr_str_all((ind-1) * numCol + 1 :ind * numCol, : ))); + arr_str = arr_str(2:end); + arr_str(end) = ';'; + arr_str = replace(arr_str, "';",','); + arr_str = replace(arr_str, "'",'0x'); + c_file_content = [ arr_str newline]; + fprintf(fileID_c,'%s', c_file_content); + end + arr_str = join(mat2str(arr_str_all(ind * numCol + 1 :ind * numCol + numRemain, : ))); + arr_str = arr_str(2:end); + arr_str(end) = ';'; + arr_str = replace(arr_str, "';",','); + arr_str = replace(arr_str, "'",'0x'); + c_file_content = [ arr_str newline '};' newline]; + fprintf(fileID_c,'%s', c_file_content); + + + HRTF_MODEL_N_SECTIONS = 3; + AlphaN = size(mod_hrf.WL{1}, 1); + K = size(mod_hrf.WL{1}, 2); + sec_length = int32(floor(K / HRTF_MODEL_N_SECTIONS)); + + iSecFirst = zeros(HRTF_MODEL_N_SECTIONS,1,"int32"); + iSecLast = zeros(HRTF_MODEL_N_SECTIONS,1,"int32"); + for i = 1:HRTF_MODEL_N_SECTIONS + iSecFirst(i) = (i -1) * sec_length; + end + for i = 1:HRTF_MODEL_N_SECTIONS - 1 + iSecLast(i) = i * sec_length - 1; + end + iSecLast(HRTF_MODEL_N_SECTIONS) = K - 1; + + EL = zeros( HRTF_MODEL_N_SECTIONS * AlphaN, 1, "single"); + ER = zeros( HRTF_MODEL_N_SECTIONS * AlphaN, 1, "single"); + ind = 1; + for i = 1:HRTF_MODEL_N_SECTIONS + for j = 1:AlphaN + indAlpha = iSecFirst(i) * AlphaN + j; + indK = 0; + EL(ind) = 0; + ER(ind) = 0; + for k = iSecFirst(i) : iSecLast(i) -1 + tmp = single(mod_hrf.WL{1}(indAlpha + indK)); + EL(ind) = EL(ind) + tmp^2; + tmp = single(mod_hrf.WR{1}(indAlpha + indK)); + ER(ind) = ER(ind) + tmp^2; + indK = indK +AlphaN; + end + ind = ind + 1; + end + end + + arr_str_all = num2hex(single(EL)); + numCol = 25; + numIter = floor(HRTF_MODEL_N_SECTIONS*size(mod_hrf.WL{1},1)/numCol); + numRemain = HRTF_MODEL_N_SECTIONS*size(mod_hrf.WL{1},1) - numCol * numIter; + c_file_content = ... + ['const uint32_t defaultHRIR_rom_EL' num2str(fs/1000) '[HRTF_MODEL_N_SECTIONS * ' int2str(size(mod_hrf.WL{1}, 1)) '] = {' newline ]; + fprintf(fileID_c,'%s', c_file_content); + for ind = 1: numIter + arr_str = join(mat2str(arr_str_all((ind-1) * numCol + 1 :ind * numCol, : ))); + arr_str = arr_str(2:end); + arr_str(end) = ';'; + arr_str = replace(arr_str, "';",','); + arr_str = replace(arr_str, "'",'0x'); + c_file_content = [ arr_str newline]; + fprintf(fileID_c,'%s', c_file_content); + end + arr_str = join(mat2str(arr_str_all(ind * numCol + 1 :ind * numCol + numRemain, : ))); + arr_str = arr_str(2:end); + arr_str(end) = ';'; + arr_str = replace(arr_str, "';",','); + arr_str = replace(arr_str, "'",'0x'); + c_file_content = [ arr_str newline '};' newline]; + fprintf(fileID_c,'%s', c_file_content); + + arr_str_all = num2hex(single(ER)); + numCol = 25; + numIter = floor(HRTF_MODEL_N_SECTIONS*size(mod_hrf.WL{1},1)/numCol); + numRemain = HRTF_MODEL_N_SECTIONS*size(mod_hrf.WL{1},1) - numCol * numIter; + c_file_content = ... + ['const uint32_t defaultHRIR_rom_ER' num2str(fs/1000) '[HRTF_MODEL_N_SECTIONS * ' int2str(size(mod_hrf.WL{1}, 1)) '] = {' newline ]; + fprintf(fileID_c,'%s', c_file_content); + for ind = 1: numIter + arr_str = join(mat2str(arr_str_all((ind-1) * numCol + 1 :ind * numCol, : ))); + arr_str = arr_str(2:end); + arr_str(end) = ';'; + arr_str = replace(arr_str, "';",','); + arr_str = replace(arr_str, "'",'0x'); + c_file_content = [ arr_str newline]; + fprintf(fileID_c,'%s', c_file_content); + end + arr_str = join(mat2str(arr_str_all(ind * numCol + 1 :ind * numCol + numRemain, : ))); + arr_str = arr_str(2:end); + arr_str(end) = ';'; + arr_str = replace(arr_str, "';",','); + arr_str = replace(arr_str, "'",'0x'); + c_file_content = [ arr_str newline '};' newline]; + fprintf(fileID_c,'%s', c_file_content); + + fclose(fileID_c); + + end + % If ITD model is used, parameters are stored in 2nd part of the same file if useITD % General @@ -311,6 +699,110 @@ for fs = [48000 32000 16000] fwrite(fileID, length(elevSplineShapeITD_all), 'short'); % total length elevation shapes fwrite(fileID, elevSplineShapeITD_all, 'float'); % elevation shapes fwrite(fileID, e_num_points_ITD, 'short'); % samples between knot points + + if fs == fs_last && dataSpec.genRomFile + + fileID_c = fopen(c_file_name,'at'); + + arr_str_all = num2hex(single(mod_itd.W)); + numCol = 25; + numIter = floor(length(mod_itd.W)/numCol); + numRemain = length(mod_itd.W) - numCol * numIter; + c_file_content = ... + ['const uint32_t defaultHRIR_rom_ITD_W[' num2str(length(mod_itd.W)) '] = {' newline ]; + fprintf(fileID_c,'%s', c_file_content); + for ind = 1: numIter + arr_str = join(mat2str(arr_str_all((ind-1) * numCol + 1 :ind * numCol, : ))); + arr_str = arr_str(2:end); + arr_str(end) = ';'; + arr_str = replace(arr_str, "';",','); + arr_str = replace(arr_str, "'",'0x'); + c_file_content = [ arr_str newline]; + fprintf(fileID_c,'%s', c_file_content); + end + arr_str = join(mat2str(arr_str_all(ind * numCol + 1 :ind * numCol + numRemain, : ))); + arr_str = arr_str(2:end); + arr_str(end) = ';'; + arr_str = replace(arr_str, "';",','); + arr_str = replace(arr_str, "'",'0x'); + c_file_content = [ arr_str newline '};' newline]; + fprintf(fileID_c,'%s', c_file_content); + + arr_str_all = num2hex(single(azimSplineShapeITD_all)); + numCol = 25; + numIter = floor(length(azimSplineShapeITD_all)/numCol); + numRemain = length(azimSplineShapeITD_all) - numCol * numIter; + c_file_content = ... + ['const uint32_t defaultHRIR_rom_ITD_azimBsShape[' num2str(length(azimSplineShapeITD_all)) '] = {' newline ]; + fprintf(fileID_c,'%s', c_file_content); + for ind = 1: numIter + arr_str = join(mat2str(arr_str_all((ind-1) * numCol + 1 :ind * numCol, : ))); + arr_str = arr_str(2:end); + arr_str(end) = ';'; + arr_str = replace(arr_str, "';",','); + arr_str = replace(arr_str, "'",'0x'); + c_file_content = [ arr_str newline]; + fprintf(fileID_c,'%s', c_file_content); + end + arr_str = join(mat2str(arr_str_all(ind * numCol + 1 :ind * numCol + numRemain, : ))); + arr_str = arr_str(2:end); + arr_str(end) = ';'; + arr_str = replace(arr_str, "';",','); + arr_str = replace(arr_str, "'",'0x'); + c_file_content = [ arr_str newline '};' newline]; + fprintf(fileID_c,'%s', c_file_content); + + arr_str = mat2str(mod_itd.azimKSeq{2}); + arr_str = arr_str(2:end); + arr_str(end) = ' '; + arr_str = replace(arr_str,' ', '.000000f, '); + c_file_content = ... + ['const float defaultHRIR_rom_ITD_azimKSeq[' num2str(length(mod_itd.azimKSeq{2})) '] = {' newline ... + arr_str ... + newline '};' newline ... + ]; + fprintf(fileID_c,'%s', c_file_content); + + arr_str_all = num2hex(single(elevSplineShapeITD_all)); + numCol = 25; + numIter = floor(length(elevSplineShapeITD_all)/numCol); + numRemain = length(elevSplineShapeITD_all) - numCol * numIter; + c_file_content = ... + ['const uint32_t defaultHRIR_rom_ITD_elevBsShape[' num2str(length(elevSplineShapeITD_all)) '] = {' newline ]; + fprintf(fileID_c,'%s', c_file_content); + for ind = 1: numIter + arr_str = join(mat2str(arr_str_all((ind-1) * numCol + 1 :ind * numCol, : ))); + arr_str = arr_str(2:end); + arr_str(end) = ';'; + arr_str = replace(arr_str, "';",','); + arr_str = replace(arr_str, "'",'0x'); + c_file_content = [ arr_str newline]; + fprintf(fileID_c,'%s', c_file_content); + end + arr_str = join(mat2str(arr_str_all(ind * numCol + 1 :ind * numCol + numRemain, : ))); + arr_str = arr_str(2:end); + arr_str(end) = ';'; + arr_str = replace(arr_str, "';",','); + arr_str = replace(arr_str, "'",'0x'); + c_file_content = [ arr_str newline '};' newline]; + fprintf(fileID_c,'%s', c_file_content); + + arr_str = mat2str(mod_itd.elevKSeq); + arr_str = arr_str(2:end); + arr_str(end) = ' '; + arr_str = replace(arr_str,' ', '.000000f, '); + c_file_content = ... + ['const float defaultHRIR_rom_ITD_elevKSeq[' num2str(length(mod_itd.elevKSeq)) '] = {' newline ... + arr_str ... + newline '};' newline ... + ]; + fprintf(fileID_c,'%s', c_file_content); + + + fclose(fileID_c); + + end + end % Close file fclose(fileID); @@ -318,4 +810,39 @@ for fs = [48000 32000 16000] fprintf("Wrote model parameters to: %s\n",fullfile(filePath,outputBinaryFileName)); end % fs loop +if dataSpec.genRomFile + h_file_content = string(join({'' + ['extern const uint32_t defaultHRIR_rom_elevBsShape[' int2str(length(elevSplineShape_all)) '];'] + ['extern const uint32_t defaultHRIR_rom_azimBsShape[' int2str(length(azimSplineShape{1})) '];'] + ['extern const uint32_t defaultHRIR_rom_ITD_W[' int2str(mod_itd.angleBfNum) '];'] + ['extern const uint32_t defaultHRIR_rom_ITD_azimBsShape[' int2str(length(azimSplineShapeITD_all)) '];'] + ['extern const float defaultHRIR_rom_ITD_azimKSeq[19];'] + ['extern const uint32_t defaultHRIR_rom_ITD_elevBsShape[' int2str(length(elevSplineShapeITD_all)) '];'] + ['extern const float defaultHRIR_rom_ITD_elevKSeq[16];'] + '#endif' + '' + }, newline)); + + + fileID_h = fopen(h_file_name,'at'); + + fprintf(fileID_h,'%s', h_file_content); + + fclose(fileID_h); + + c_file_content = string(join({'' ... + '#undef WMC_TOOL_SKIP' ... + '' ... + '/* clang-format on */',... + '' + }, newline)); + + + fileID_c = fopen(c_file_name,'at'); + + fprintf(fileID_c,'%s', c_file_content); + + fclose(fileID_c); +end + end % function \ No newline at end of file diff --git a/scripts/td_object_renderer/modeling_tool/HrfModBsp_InitPath.m b/scripts/td_object_renderer/modeling_tool/HrfModBsp_InitPath.m index 275dd7a4d0fc8e6a3633b1b847a45b35740a29e1..70ddc653ca017f7639a751dbefc032fd0ac3a8a5 100644 --- a/scripts/td_object_renderer/modeling_tool/HrfModBsp_InitPath.m +++ b/scripts/td_object_renderer/modeling_tool/HrfModBsp_InitPath.m @@ -29,24 +29,37 @@ function HrfModBsp_InitPath(dataSpec) % Initialize Matlab paths mypath = fullfile(pwd, 'preprocessing'); - addpath(mypath); + if isfolder(mypath) + addpath(mypath); + end mypath = fullfile(pwd, 'modeling'); - addpath(mypath); + if isfolder(mypath) + addpath(mypath); + end mypath = fullfile(pwd, 'evaluation'); - addpath(mypath); + if isfolder(mypath) + addpath(mypath); + end mypath = fullfile(pwd, 'spat_area'); - addpath(mypath); + if isfolder(mypath) + addpath(mypath); + end mypath = dataSpec.hrfOutDir; + if ~isfolder(mypath) + mkdir(mypath) + end addpath(mypath); switch dataSpec.dataBase case 'IVAS' mypath = fullfile(mypath, 'IVAS_default'); + if ~isfolder(mypath) + mkdir(mypath) + end addpath(mypath); - mypath1 = fullfile(mypath, 'OnsetDelay'); if ~isfolder(mypath1) mkdir(mypath1) diff --git a/scripts/td_object_renderer/modeling_tool/Mod_Hrf_Itd_Main.m b/scripts/td_object_renderer/modeling_tool/Mod_Hrf_Itd_Main.m index fa4333a7523e7450460486b5b4535a2b2c2b4e28..95746b692940b1b4a150e0b968b2d5b9a57d7a19 100644 --- a/scripts/td_object_renderer/modeling_tool/Mod_Hrf_Itd_Main.m +++ b/scripts/td_object_renderer/modeling_tool/Mod_Hrf_Itd_Main.m @@ -37,9 +37,12 @@ clc % specify HR filter directory dataSpec.hrfInDir = fullfile(pwd, '..','..','binauralRenderer_interface','HRIRs_sofa'); dataSpec.hrfOutDir = fullfile(pwd, '..', 'hrtf_data'); + dataSpec.genRomFile = false; + dataSpec.romOutDir = fullfile(pwd, '..','..','..','lib_rend'); elseif nargin == 1 - dataSpec.dataBase = varargin{1}.dataBase; - dataSpec.subjId = varargin{1}.subjId; +% dataSpec.dataBase = varargin{1}.dataBase; +% dataSpec.subjId = varargin{1}.subjId; + dataSpec = varargin{1}; elseif nargin > 1 error('Too many inputs!') end @@ -51,8 +54,8 @@ clc HrfModBsp_InitPath(dataSpec); %% modeling and evaluation - Mod_Hrf_Itd(dataSpec, modSpec); + [~,~,info] = Mod_Hrf_Itd(dataSpec, modSpec); %% load model and generate parameters for IVAS - Gen_Hrf_IVAS_Binary(dataSpec, modSpec); + Gen_Hrf_IVAS_Binary(dataSpec, modSpec, info); end diff --git a/scripts/td_object_renderer/modeling_tool/modeling/Mod_Hrf_Itd.m b/scripts/td_object_renderer/modeling_tool/modeling/Mod_Hrf_Itd.m index a5ca5186c915ff58047572db87c93a314cdf87e1..7c160506f9ec2a0b6300a123d26133d5166cdc47 100644 --- a/scripts/td_object_renderer/modeling_tool/modeling/Mod_Hrf_Itd.m +++ b/scripts/td_object_renderer/modeling_tool/modeling/Mod_Hrf_Itd.m @@ -26,13 +26,14 @@ % 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. -function [mod, evalHrf] = Mod_Hrf_Itd(dataSpec, modSpec) +function [mod, evalHrf, info] = Mod_Hrf_Itd(dataSpec, modSpec) %% Prepare data for modeling % All data for modeling is ready in data. dat = data_SOFA(dataSpec, modSpec); dat.get_hrf_itd; + info = dat.info; %% modeling for the purpose of delay correction if dat.flag.delayCorr diff --git a/scripts/td_object_renderer/modeling_tool/preprocessing/data_SOFA.m b/scripts/td_object_renderer/modeling_tool/preprocessing/data_SOFA.m index 4f8bc77908aa7097c66c58ca5bcd98b834820eb7..4af92b4e1ace12be89372461b1f2ed2a27231611 100644 --- a/scripts/td_object_renderer/modeling_tool/preprocessing/data_SOFA.m +++ b/scripts/td_object_renderer/modeling_tool/preprocessing/data_SOFA.m @@ -69,8 +69,15 @@ classdef data_SOFA < handle case 'IVAS' if sum(strcmp(obj.info.subjId, 'default')) > eps obj.info.fileNameHrf = 'HRIR_128_Meth5_IRC_53_Q10_symL_Itrp1_48000.sofa'; + dataSpec.fileNameHrf = obj.info.fileNameHrf; else - error( 'Error! Invalid HR filter set specified' ) + if isfile(obj.info.hrfInDir) + [obj.info.hrfInDir,obj.info.fileNameHrf,ext] = fileparts(obj.info.hrfInDir); + obj.info.fileNameHrf = [obj.info.fileNameHrf ext]; + dataSpec.fileNameHrf = obj.info.fileNameHrf; + else + error( 'Error! Invalid HR filter set specified' ) + end end end % name of the onset delay file @@ -104,9 +111,13 @@ classdef data_SOFA < handle left_orig = squeeze(meas.Data.IR(:, 1, :))'; right_orig = squeeze(meas.Data.IR(:, 2, :))'; - left = left_orig; - right = right_orig; - + if (meas.Data.SamplingRate ~= 48000) + left = resample(left_orig, 48000, meas.Data.SamplingRate, 'Dimension',2); + right = resample(right_orig, 48000, meas.Data.SamplingRate, 'Dimension',2); + else + left = left_orig; + right = right_orig; + end % set range, length and truncation hrfLength = size(left, 2); range{1} = 1:hrfLength;