diff --git a/apps/decoder.c b/apps/decoder.c index ea8a58f8db805cb44aaed016ab1af47b45799441..f726ab6d2ae1850be4d04a01518dd20a941dcd89 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -157,6 +157,13 @@ typedef struct #endif #endif +#ifdef CONTROL_METADATA_REVERB + uint16_t acousticEnvironmentId; +#ifdef CONTROL_METADATA_DIRECTIVITY + uint16_t directivityPatternId[IVAS_MAX_NUM_OBJECTS]; +#endif +#endif + } DecArguments; @@ -602,12 +609,42 @@ int main( goto cleanup; } +#ifdef CONTROL_METADATA_REVERB + if ( RenderConfigReader_read( renderConfigReader, arg.renderConfigFilename, &renderConfig ) != IVAS_ERR_OK ) +#else if ( RenderConfigReader_read( renderConfigReader, &renderConfig ) != IVAS_ERR_OK ) +#endif { fprintf( stderr, "Failed to read renderer configuration from file %s\n\n", arg.renderConfigFilename ); goto cleanup; } +#ifdef CONTROL_METADATA_DIRECTIVITY + if ( ( error = RenderConfigReader_getDirectivity( renderConfigReader, arg.directivityPatternId, renderConfig.directivity ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "Failed to get directivity for objects: %d %d %d %d\n\n", arg.directivityPatternId[0], arg.directivityPatternId[1], arg.directivityPatternId[2], arg.directivityPatternId[3] ); + goto cleanup; + } +#endif +#ifdef CONTROL_METADATA_REVERB + if ( arg.outputFormat == IVAS_DEC_OUTPUT_BINAURAL_ROOM_REVERB ) + { + if ( ( error = RenderConfigReader_getAcousticEnvironment( renderConfigReader, arg.acousticEnvironmentId, &renderConfig.room_acoustics ) ) == IVAS_ERR_OK ) + { + if ( RenderConfigReader_checkValues( &renderConfig ) != IVAS_ERR_OK ) + { + fprintf( stderr, "Invalid reverberation configuration parameters\n\n" ); + goto cleanup; + } + } + else if ( error != IVAS_ERR_ACOUSTIC_ENVIRONMENT_MISSING ) + { + fprintf( stderr, "Failed to get acoustic environment with ID: %d\n\n", arg.acousticEnvironmentId ); + goto cleanup; + } + renderConfig.room_acoustics.override = true; + } +#endif if ( ( error = IVAS_DEC_FeedRenderConfig( hIvasDec, renderConfig ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nIVAS_DEC_FeedRenderConfig failed: %s\n\n", IVAS_DEC_GetErrorMessage( error ) ); @@ -965,7 +1002,15 @@ static bool parseCmdlIVAS_dec( #endif #endif - +#ifdef CONTROL_METADATA_REVERB + arg->acousticEnvironmentId = 0; +#ifdef CONTROL_METADATA_DIRECTIVITY + for ( i = 0; i < IVAS_MAX_NUM_OBJECTS; ++i ) + { + arg->directivityPatternId[i] = 0; + } +#endif +#endif /*-----------------------------------------------------------------* * Initialization *-----------------------------------------------------------------*/ @@ -1326,8 +1371,27 @@ static bool parseCmdlIVAS_dec( fprintf( stdout, "Complexity levels 1 and 2 will be defined after characterisation - default to level 3 (full functionality).\n" ); } } - - +#ifdef CONTROL_METADATA_REVERB + else if ( strcmp( argv_to_upper, "-AEID" ) == 0 ) + { + ++i; + arg->acousticEnvironmentId = (int16_t) atoi( argv[i++] ); + } +#ifdef CONTROL_METADATA_DIRECTIVITY + else if ( strcmp( argv_to_upper, "-DPID" ) == 0 ) + { + ++i; + int16_t tmp; + tmp = 0; + while ( is_number( argv[i + tmp] ) && tmp < IVAS_MAX_NUM_OBJECTS ) + { + arg->directivityPatternId[tmp] = (int16_t) atoi( argv[i + tmp] ); + ++tmp; + } + i += tmp; + } +#endif +#endif /*-----------------------------------------------------------------* * Option not recognized *-----------------------------------------------------------------*/ @@ -1512,6 +1576,12 @@ static void usage_dec( void ) fprintf( stdout, " Currently, all values default to level 3 (full functionality).\n" ); #endif fprintf( stdout, "-exof File : External orientation file for external orientation trajectory\n" ); +#ifdef CONTROL_METADATA_DIRECTIVITY + fprintf( stdout, "-dpid ID : Directivity pattern ID(s) (space-separated list of up to 4 numbers can be specified) for binaural output configuration\n" ); +#endif +#ifdef CONTROL_METADATA_REVERB + fprintf( stdout, "-aeid ID : Acoustic environment ID (number >= 0) for BINAURAL_ROOM_REVERB output configuration\n" ); +#endif #ifdef DEBUG_MODE_INFO #ifdef DEBUG_MODE_INFO_TWEAK fprintf( stdout, "-info : specify subfolder name for debug output\n" ); diff --git a/apps/renderer.c b/apps/renderer.c index 817b423383bbd80a4a89b65ad75ea112fd93a22c..0a7a5698a6616376a217029aa255d2a743737491 100644 --- a/apps/renderer.c +++ b/apps/renderer.c @@ -178,6 +178,12 @@ typedef struct #ifdef FIX_488_SYNC_DELAY float syncMdDelay; #endif +#ifdef CONTROL_METADATA_DIRECTIVITY + uint16_t directivityPatternId[RENDERER_MAX_ISM_INPUTS]; +#endif +#ifdef CONTROL_METADATA_REVERB + uint16_t acousticEnvironmentId; +#endif } CmdlnArgs; typedef enum @@ -209,6 +215,12 @@ typedef enum #ifdef FIX_488_SYNC_DELAY CmdLnOptionId_syncMdDelay, #endif +#ifdef CONTROL_METADATA_DIRECTIVITY + CmdLnOptionId_directivityPatternId, +#endif +#ifdef CONTROL_METADATA_REVERB + CmdLnOptionId_acousticEnvironmentId +#endif } CmdLnOptionId; static const CmdLnParser_Option cliOptions[] = { @@ -356,6 +368,22 @@ static const CmdLnParser_Option cliOptions[] = { .description = "Metadata Synchronization Delay in ms, Default is 0. Quantized by 5ms subframes for TDRenderer (13ms -> 10ms -> 2subframes)", }, #endif +#ifdef CONTROL_METADATA_DIRECTIVITY + { + .id = CmdLnOptionId_directivityPatternId, + .match = "ism_directivity_pattern_id", + .matchShort = "dpid", + .description = "Directivity pattern ID(s) (space-separated list of up to 4 numbers can be specified) for binaural output configuration", + }, +#endif +#ifdef CONTROL_METADATA_REVERB + { + .id = CmdLnOptionId_acousticEnvironmentId, + .match = "acoustic_environment_id", + .matchShort = "aeid", + .description = "Acoustic environment ID (number >= 0) for BINAURAL_ROOM_REVERB output configuration", + }, +#endif }; @@ -1069,7 +1097,11 @@ int main( exit( -1 ); } +#ifdef CONTROL_METADATA_REVERB + if ( RenderConfigReader_read( renderConfigReader, args.renderConfigFilePath, &renderConfig ) != IVAS_ERR_OK ) +#else if ( RenderConfigReader_read( renderConfigReader, &renderConfig ) != IVAS_ERR_OK ) +#endif { fprintf( stderr, "Failed to read renderer configuration from file %s\n", args.renderConfigFilePath ); exit( -1 ); @@ -1077,6 +1109,21 @@ int main( if ( args.outConfig.audioConfig == IVAS_REND_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) { +#ifdef CONTROL_METADATA_REVERB + if ( ( error = RenderConfigReader_getAcousticEnvironment( renderConfigReader, args.acousticEnvironmentId, &renderConfig.room_acoustics ) ) == IVAS_ERR_OK ) + { + if ( RenderConfigReader_checkValues( &renderConfig ) != IVAS_ERR_OK ) + { + fprintf( stderr, "Invalid room acoustics configuration parameters\n\n" ); + exit( -1 ); + } + } + else + { + fprintf( stderr, "Failed to get acoustic environment with ID: %d\n\n", args.acousticEnvironmentId ); + exit( -1 ); + } +#endif renderConfig.room_acoustics.override = TRUE; } @@ -2513,6 +2560,17 @@ static CmdlnArgs defaultArgs( #ifdef FIX_488_SYNC_DELAY args.syncMdDelay = 0; #endif + +#ifdef CONTROL_METADATA_DIRECTIVITY + for ( int32_t i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i ) + { + args.directivityPatternId[i] = 0; + } +#endif + +#ifdef CONTROL_METADATA_REVERB + args.acousticEnvironmentId = 0; +#endif return args; } @@ -2652,6 +2710,23 @@ static void parseOption( exit( -1 ); } break; + +#ifdef CONTROL_METADATA_DIRECTIVITY + case CmdLnOptionId_directivityPatternId: + assert( numOptionValues <= RENDERER_MAX_ISM_INPUTS ); + for ( int16_t i = 0; i < numOptionValues; ++i ) + { + args->directivityPatternId[i] = (int16_t) strtol( optionValues[i], NULL, 10 ); + } + break; +#endif + +#ifdef CONTROL_METADATA_REVERB + case CmdLnOptionId_acousticEnvironmentId: + assert( numOptionValues == 1 ); + args->acousticEnvironmentId = (int16_t) strtol( optionValues[0], NULL, 10 ); + break; +#endif #ifdef FIX_488_SYNC_DELAY case CmdLnOptionId_syncMdDelay: assert( numOptionValues == 1 ); diff --git a/lib_com/common_api_types.h b/lib_com/common_api_types.h index 79bda1eaa684ef220e80cae84ecaa5a800239894..1a2d7d77c3b397d939a67782ef4611ab0a6593a0 100644 --- a/lib_com/common_api_types.h +++ b/lib_com/common_api_types.h @@ -215,7 +215,11 @@ typedef struct _IVAS_RENDER_CONFIG #ifdef SPLIT_REND_WITH_HEAD_ROT IVAS_SPLIT_REND_CONFIG_DATA split_rend_config; #endif +#ifdef CONTROL_METADATA_DIRECTIVITY + float directivity[IVAS_MAX_NUM_OBJECTS * 3]; +#else float directivity[3]; +#endif } IVAS_RENDER_CONFIG_DATA, *IVAS_RENDER_CONFIG_HANDLE; typedef struct _IVAS_LS_CUSTOM_LAYOUT diff --git a/lib_com/ivas_error.h b/lib_com/ivas_error.h index e04b40468057c513aa017f8c8ca1a1bf719d9870..22dbfe69816739f816da2664fdcbb66e580353a0 100644 --- a/lib_com/ivas_error.h +++ b/lib_com/ivas_error.h @@ -135,6 +135,13 @@ typedef enum IVAS_ERR_INVALID_INPUT_ID, IVAS_ERR_WRONG_NUM_CHANNELS, IVAS_ERR_INVALID_BUFFER_SIZE, +#ifdef CONTROL_METADATA_REVERB + IVAS_ERR_INVALID_RENDER_CONFIG, + IVAS_ERR_ACOUSTIC_ENVIRONMENT_MISSING, +#ifdef CONTROL_METADATA_DIRECTIVITY + IVAS_ERR_DIRECTIVITY_PATTERN_ID_MISSING, +#endif +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT IVAS_ERR_LC3PLUS_INVALID_BITRATE, IVAS_ERR_INVALID_SPLIT_REND_CONFIG, diff --git a/lib_com/options.h b/lib_com/options.h index 7233fe37534cf9035574466ea5b1f218a930c688..e8eda32065d915b0a5c16861307a23f308943321 100755 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -149,7 +149,11 @@ /* only BE switches wrt operation points tested in selection */ /*#define FIX_I4_OL_PITCH*/ /* fix open-loop pitch used for EVS core switching */ - +#define CONTROL_METADATA_REVERB /* Philips: reverb configuration change to binary format */ +#ifdef CONTROL_METADATA_REVERB +#define EARLY_REFLECTIONS /* Philips/Qualcomm: early reflections extension to reverb configuration */ +#define CONTROL_METADATA_DIRECTIVITY /* Ericsson: Directivity renderer configuration */ +#endif #define VLBR_20MS_MD /* Dlb: SBA VLBR 20ms Optimization*/ #define SBA_MODE_CLEANUP_2 /* Dlb : changes part of fix issue #523 for unused signaling bit in SBA SID*/ #define FIX_137_SID_MD_BITS /* Dlb: Fix issue #137 , SID bitrate mismatch correction */ diff --git a/lib_dec/ivas_ism_metadata_dec.c b/lib_dec/ivas_ism_metadata_dec.c index 4cc8bbb858a5199a505a6b5de170153a82cc6df1..56a52f2be9944bc27587624bb71ad92cd52734d0 100644 --- a/lib_dec/ivas_ism_metadata_dec.c +++ b/lib_dec/ivas_ism_metadata_dec.c @@ -944,7 +944,6 @@ static int16_t decode_radius( return idx_radius; } - /*-------------------------------------------------------------------* * ivas_ism_metadata_sid_dec() * diff --git a/lib_dec/lib_dec.c b/lib_dec/lib_dec.c index ee50dea27ec2b5d4a0878a7fb1da5a135f837c45..e88e6edd1b3c49df23b8ff2e705dc7af067eb7fd 100644 --- a/lib_dec/lib_dec.c +++ b/lib_dec/lib_dec.c @@ -1621,7 +1621,11 @@ ivas_error IVAS_DEC_GetRenderConfig( mvr2r( hRCin->roomAcoustics.pFc_input, hRCout->room_acoustics.pFc_input, CLDFB_NO_CHANNELS_MAX ); mvr2r( hRCin->roomAcoustics.pAcoustic_rt60, hRCout->room_acoustics.pAcoustic_rt60, CLDFB_NO_CHANNELS_MAX ); mvr2r( hRCin->roomAcoustics.pAcoustic_dsr, hRCout->room_acoustics.pAcoustic_dsr, CLDFB_NO_CHANNELS_MAX ); +#ifdef CONTROL_METADATA_DIRECTIVITY + mvr2r( hRCin->directivity, hRCout->directivity, 3 * MAX_NUM_OBJECTS ); +#else mvr2r( hRCin->directivity, hRCout->directivity, 3 ); +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT hRCout->split_rend_config.splitRendBitRate = SPLIT_REND_768k; @@ -1677,7 +1681,12 @@ ivas_error IVAS_DEC_FeedRenderConfig( mvr2r( renderConfig.room_acoustics.pFc_input, hRenderConfig->roomAcoustics.pFc_input, CLDFB_NO_CHANNELS_MAX ); mvr2r( renderConfig.room_acoustics.pAcoustic_rt60, hRenderConfig->roomAcoustics.pAcoustic_rt60, CLDFB_NO_CHANNELS_MAX ); mvr2r( renderConfig.room_acoustics.pAcoustic_dsr, hRenderConfig->roomAcoustics.pAcoustic_dsr, CLDFB_NO_CHANNELS_MAX ); + +#ifdef CONTROL_METADATA_DIRECTIVITY + mvr2r( renderConfig.directivity, hRenderConfig->directivity, 3 * MAX_NUM_OBJECTS ); +#else mvr2r( renderConfig.directivity, hRenderConfig->directivity, 3 ); +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT hRenderConfig->split_rend_config = renderConfig.split_rend_config; diff --git a/lib_rend/ivas_objectRenderer.c b/lib_rend/ivas_objectRenderer.c index 3aa9e6d80b69a8f9241a27900def39a0c8d0fc02..f6abe725d107bf3ec787c1b5a551b15f5658d8f5 100644 --- a/lib_rend/ivas_objectRenderer.c +++ b/lib_rend/ivas_objectRenderer.c @@ -201,6 +201,7 @@ ivas_error ivas_td_binaural_open_unwrap( #endif { DirAtten_p = pBinRendTd->DirAtten_p; +#ifndef CONTROL_METADATA_DIRECTIVITY if ( NULL == directivity ) { DirAtten_p->ConeInnerAngle = 360.0f; /* Front cone */ @@ -213,9 +214,24 @@ ivas_error ivas_td_binaural_open_unwrap( DirAtten_p->ConeOuterAngle = directivity[1]; DirAtten_p->ConeOuterGain = directivity[2]; } +#endif for ( nS = 0; nS < nchan_rend; nS++ ) { +#ifdef CONTROL_METADATA_DIRECTIVITY + if ( NULL == directivity ) + { + DirAtten_p->ConeInnerAngle = 360.0f; /* Front cone */ + DirAtten_p->ConeOuterAngle = 360.0f; /* Back cone */ + DirAtten_p->ConeOuterGain = 1.0f; /* Back attenuation */ + } + else + { + DirAtten_p->ConeInnerAngle = directivity[nS * 3]; + DirAtten_p->ConeOuterAngle = directivity[nS * 3 + 1]; + DirAtten_p->ConeOuterGain = directivity[nS * 3 + 2]; + } +#endif TDREND_MIX_SRC_SetDirAtten( pBinRendTd, nS, DirAtten_p ); } } @@ -643,6 +659,7 @@ ivas_error ivas_td_binaural_open_ext( IVAS_FORMAT ivas_format; IVAS_OUTPUT_SETUP hTransSetup; ivas_error error; + float *directivity = NULL; if ( inConfig != IVAS_REND_AUDIO_CONFIG_LS_CUSTOM ) diff --git a/lib_rend/ivas_render_config.c b/lib_rend/ivas_render_config.c index e4a62d217f9d89b368232c3b8b0208edaca597c7..2972b57f847e16140fc142dced8c92af88c56c17 100644 --- a/lib_rend/ivas_render_config.c +++ b/lib_rend/ivas_render_config.c @@ -102,6 +102,9 @@ ivas_error ivas_render_config_init_from_rom( RENDER_CONFIG_HANDLE *hRenderConfig /* i/o: Renderer config handle */ ) { +#ifdef CONTROL_METADATA_DIRECTIVITY + int16_t i; +#endif if ( hRenderConfig == NULL || *hRenderConfig == NULL ) { return IVAS_ERROR( IVAS_ERR_UNEXPECTED_NULL_POINTER, "Unexpected null pointer while attempting to fill renderer configuration from ROM" ); @@ -121,9 +124,18 @@ ivas_error ivas_render_config_init_from_rom( mvr2r( ivas_reverb_default_RT60, ( *hRenderConfig )->roomAcoustics.pAcoustic_rt60, IVAS_REVERB_DEFAULT_N_BANDS ); mvr2r( ivas_reverb_default_DSR, ( *hRenderConfig )->roomAcoustics.pAcoustic_dsr, IVAS_REVERB_DEFAULT_N_BANDS ); +#ifdef CONTROL_METADATA_DIRECTIVITY + for ( i = 0; i < MAX_NUM_OBJECTS; i++ ) + { + ( *hRenderConfig )->directivity[i * 3] = 360.0f; /* Front cone */ + ( *hRenderConfig )->directivity[i * 3 + 1] = 360.0f; /* Back cone */ + ( *hRenderConfig )->directivity[i * 3 + 2] = 1.0f; /* Back attenuation */ + } +#else ( *hRenderConfig )->directivity[0] = 360.0f; /* Front cone */ ( *hRenderConfig )->directivity[1] = 360.0f; /* Back cone */ ( *hRenderConfig )->directivity[2] = 1.0f; /* Back attenuation */ +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT ( *hRenderConfig )->split_rend_config.splitRendBitRate = SPLIT_REND_768k; ( *hRenderConfig )->split_rend_config.dof = 3; diff --git a/lib_rend/ivas_stat_rend.h b/lib_rend/ivas_stat_rend.h index 4a034eecb4ade6f5ebd80a88329e5b800f77b474..e0818b20ae4a19e9544a1721a2e02948bcdfd6d9 100644 --- a/lib_rend/ivas_stat_rend.h +++ b/lib_rend/ivas_stat_rend.h @@ -933,7 +933,11 @@ typedef struct ivas_render_config_t ivas_renderTypeOverride renderer_type_override; #endif ivas_roomAcoustics_t roomAcoustics; +#ifdef CONTROL_METADATA_DIRECTIVITY + float directivity[MAX_NUM_OBJECTS * 3]; +#else float directivity[3]; +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT IVAS_SPLIT_REND_CONFIG_DATA split_rend_config; #endif diff --git a/lib_rend/lib_rend.c b/lib_rend/lib_rend.c index 147c5e2127db9ac05bbca182ed0fedb287e86a11..cbf6143e5e938f73924c4832fcb168351a414f94 100644 --- a/lib_rend/lib_rend.c +++ b/lib_rend/lib_rend.c @@ -4983,7 +4983,11 @@ int16_t IVAS_REND_GetRenderConfig( hRCout->room_acoustics.nBands = hRCin->roomAcoustics.nBands; hRCout->room_acoustics.acousticPreDelay = hRCin->roomAcoustics.acousticPreDelay; hRCout->room_acoustics.inputPreDelay = hRCin->roomAcoustics.inputPreDelay; +#ifdef CONTROL_METADATA_DIRECTIVITY + mvr2r( hRCin->directivity, hRCout->directivity, 3 * MAX_NUM_OBJECTS ); +#else mvr2r( hRCin->directivity, hRCout->directivity, 3 ); +#endif mvr2r( hRCin->roomAcoustics.pFc_input, hRCout->room_acoustics.pFc_input, CLDFB_NO_CHANNELS_MAX ); mvr2r( hRCin->roomAcoustics.pAcoustic_rt60, hRCout->room_acoustics.pAcoustic_rt60, CLDFB_NO_CHANNELS_MAX ); @@ -5043,7 +5047,11 @@ int16_t IVAS_REND_FeedRenderConfig( mvr2r( renderConfig.room_acoustics.pFc_input, hRenderConfig->roomAcoustics.pFc_input, CLDFB_NO_CHANNELS_MAX ); mvr2r( renderConfig.room_acoustics.pAcoustic_rt60, hRenderConfig->roomAcoustics.pAcoustic_rt60, CLDFB_NO_CHANNELS_MAX ); mvr2r( renderConfig.room_acoustics.pAcoustic_dsr, hRenderConfig->roomAcoustics.pAcoustic_dsr, CLDFB_NO_CHANNELS_MAX ); +#ifdef CONTROL_METADATA_DIRECTIVITY + mvr2r( renderConfig.directivity, hRenderConfig->directivity, 3 * MAX_NUM_OBJECTS ); +#else mvr2r( renderConfig.directivity, hRenderConfig->directivity, 3 ); +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT hRenderConfig->split_rend_config = renderConfig.split_rend_config; diff --git a/lib_util/render_config_reader.c b/lib_util/render_config_reader.c index e93baa3c3ffa90738a2a2cb8e8bed9faf913d1e1..d83875466a05d98b81a7f0bbed4bbd8b80d65800 100644 --- a/lib_util/render_config_reader.c +++ b/lib_util/render_config_reader.c @@ -33,6 +33,9 @@ #include "render_config_reader.h" #include #include +#ifdef CONTROL_METADATA_REVERB +#include +#endif #include #include #include "cmdl_tools.h" @@ -43,9 +46,15 @@ * PreProc Local Macros *------------------------------------------------------------------------------------------*/ -#define MAX_LINE_LENGTH ( 1024 ) -#define MAX_ITEM_LENGTH ( 64 ) +#ifndef CONTROL_METADATA_REVERB +#define MAX_LINE_LENGTH ( 1024 ) +#endif +#define MAX_ITEM_LENGTH ( 64 ) +#ifdef CONTROL_METADATA_REVERB +#define N_ABS_COEFFS ( 6 ) +#else #define N_REVERB_VECTORS ( 3 ) +#endif #define SHORTEST_REV_DEL_LINE ( 0.015f ) #define N_BANDS_MIN ( 2 ) @@ -68,358 +77,2492 @@ * Local Type definitions *------------------------------------------------------------------------------------------*/ +typedef struct +{ + uint32_t nrBands; /* Number of frequency bands */ + float *pFc; /* Center frequencies */ +} FrequencyGrid; + +#ifdef CONTROL_METADATA_REVERB +typedef enum _FREQ_GRID_MODE +{ + FREQ_GRID_MODE_UNKNOWN = -1, + FREQ_GRID_MODE_INDIVIDUAL_FREQUENCIES = 0, + FREQ_GRID_MODE_START_HOP_AMOUNT = 1, + FREQ_GRID_MODE_DEFAULT_BANDING = 2 +} FREQ_GRID_MODE; +#endif + +#ifdef EARLY_REFLECTIONS +typedef struct +{ + IVAS_VECTOR3 dimensions; /* Room dimensions [m] */ + float pAbsCoeff[N_ABS_COEFFS]; /* Absorption coeffs table */ + IVAS_VECTOR3 *pListenerOrigin; /* Listener origin */ + uint32_t lowComplexity; /* Low complexity mode flag */ +} EarlyReflectionsConfig; +#endif + +typedef struct +{ + uint32_t id; /* Acoustic environment ID */ + FrequencyGrid *pFG; /* Pointer into Frequency grids table for late reverb coeffs */ + float *pRT60; /* RT60 table */ + float *pDSR; /* DSR table */ + float preDelay; /* Pre-delay */ +#ifdef EARLY_REFLECTIONS + EarlyReflectionsConfig *pEarlyReflections; /* Early reflections configuration */ +#endif +} AcousticEnv; + +#ifdef CONTROL_METADATA_DIRECTIVITY +typedef struct +{ + uint32_t id; /* Pattern ID */ + float *pDirectivity; /* Source directivity */ +} DirectrivityPat; +#endif + struct RenderConfigReader { FILE *pConfigFile; +#ifdef CONTROL_METADATA_REVERB + uint8_t *pBitstream; /* Renderer config bitstream */ + size_t length; /* Bitstream length */ + size_t readOffset; /* Bitstream read offset */ + uint32_t nFG; /* Number of frequency grids */ + FrequencyGrid *pFG; /* Frequency grids */ + uint32_t nAE; /* Number of acoustic environments */ + AcousticEnv *pAE; /* Acoustic environments */ +#ifdef CONTROL_METADATA_DIRECTIVITY + uint32_t nDP; /* Number of directivity patterns */ + DirectrivityPat *pDP; /* Directivity Pattern */ +#endif +#endif +}; + +#ifdef CONTROL_METADATA_REVERB + +typedef enum _RC_LUT +{ + RC_LUT_INVALID = 0x00, + RC_LUT_COUNT_IDX_LO, + RC_LUT_COUNT_IDX_HI, + RC_LUT_DECI_SEC, + RC_LUT_SEC, + RC_LUT_MILLI_SEC, + RC_LUT_MICRO_SEC, + RC_LUT_FREQ, + RC_LUT_FREQ_HOP, + RC_LUT_DSR, + RC_LUT_METERS, + RC_LUT_HECTOMETERS, + RC_LUT_KILOMETERS, + RC_LUT_CENTIMETERS, + RC_LUT_ABSORPTION +} RC_LUT; + +/*------------------------------------------------------------------------------------------* + * Lookup tables + *------------------------------------------------------------------------------------------*/ + +const float lutCountIdxLo_Value[] = { + 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, + 16.0f, 17.0f, 18.0f, 19.0f, 20.0f, 21.0f, 22.0f, 23.0f, 24.0f, 25.0f, 26.0f, 27.0f, 28.0f, 29.0f, 30.0f, 31.0f, + 32.0f, 33.0f, 34.0f, 35.0f, 36.0f, 37.0f, 38.0f, 39.0f, 40.0f, 41.0f, 42.0f, 43.0f, 44.0f, 45.0f, 46.0f, 47.0f, + 48.0f, 49.0f, 50.0f, 51.0f, 52.0f, 53.0f, 54.0f, 55.0f, 56.0f, 57.0f, 58.0f, 59.0f, 60.0f, 61.0f, 62.0f, 63.0f +}; +const uint16_t lutCountIdxLo_Code[] = { + 7, 4, 12, 13, 10, 11, 8, 9, 15, 14, 13, 12, 11, 10, 9, 8, + 7, 6, 5, 4, 3, 2, 1, 0, 63, 62, 61, 60, 59, 58, 57, 56, + 111, 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, 99, 98, 97, 96, + 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80 +}; +const uint8_t lutCountIdxLo_Len[] = { + 4, 3, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +}; + +const float lutCountIdxHi_Value[] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f }; +const uint16_t lutCountIdxHi_Code[] = { 1, 0, 6, 5, 4, 7, 5, 15, 14, 13, 9, 8, 25, 49, 48 }; +const uint8_t lutCountIdxHi_Len[] = { 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 7, 7 }; + +const float lutDeciSec_Value[] = { 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f }; +const uint16_t lutDeciSec_Code[] = { 6, 4, 5, 6, 7, 7, 4, 5, 2, 3, 0 }; +const uint8_t lutDeciSec_Len[] = { 3, 3, 3, 4, 4, 3, 4, 4, 4, 4, 3 }; + +const float lutSec_Value[] = { + 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, + 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f, 20.0f, + 21.0f, 22.0f, 23.0f, 24.0f, 25.0f, 26.0f, 27.0f, 28.0f, 29.0f, 30.0f +}; +const uint16_t lutSec_Code[] = { 3, 1, 0, 15, 13, 12, 11, 9, 8, 14, 13, 12, 11, 9, 8, 5, 29, 28, 21, 31, 30, 21, 9, 8, 41, 41, 40, 81, 161, 160 }; +const uint8_t lutSec_Len[] = { 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 8, 8 }; + +const float lutMilliSec_Value[] = { + 0.00f, 0.001f, 0.002f, 0.003f, 0.004f, 0.005f, 0.006f, 0.007f, 0.008f, 0.009f, + 0.01f, 0.011f, 0.012f, 0.013f, 0.014f, 0.015f, 0.016f, 0.017f, 0.018f, 0.019f, + 0.02f, 0.021f, 0.022f, 0.023f, 0.024f, 0.025f, 0.026f, 0.027f, 0.028f, 0.029f, + 0.03f, 0.031f, 0.032f, 0.033f, 0.034f, 0.035f, 0.036f, 0.037f, 0.038f, 0.039f, + 0.04f, 0.041f, 0.042f, 0.043f, 0.044f, 0.045f, 0.046f, 0.047f, 0.048f, 0.049f, + 0.05f, 0.051f, 0.052f, 0.053f, 0.054f, 0.055f, 0.056f, 0.057f, 0.058f, 0.059f, + 0.06f, 0.061f, 0.062f, 0.063f, 0.064f, 0.065f, 0.066f, 0.067f, 0.068f, 0.069f, + 0.07f, 0.071f, 0.072f, 0.073f, 0.074f, 0.075f, 0.076f, 0.077f, 0.078f, 0.079f, + 0.08f, 0.081f, 0.082f, 0.083f, 0.084f, 0.085f, 0.086f, 0.087f, 0.088f, 0.089f, + 0.09f, 0.091f, 0.092f, 0.093f, 0.094f, 0.095f, 0.096f, 0.097f, 0.098f, 0.099f +}; +const uint16_t lutMilliSec_Code[] = { + 122, 123, 120, 121, 126, 127, 124, 125, 114, 115, 25, 112, 113, 118, 119, 116, 117, 42, 43, 40, + 18, 41, 46, 47, 44, 45, 34, 35, 32, 33, 19, 38, 39, 36, 37, 58, 59, 56, 57, 62, + 16, 63, 60, 61, 50, 51, 48, 49, 54, 55, 17, 52, 53, 10, 11, 8, 9, 14, 15, 12, + 22, 13, 2, 3, 0, 1, 6, 7, 4, 5, 23, 26, 27, 24, 25, 30, 31, 28, 29, 18, + 20, 19, 16, 17, 22, 23, 20, 21, 106, 107, 21, 104, 105, 110, 111, 108, 109, 98, 99, 48 +}; +const uint8_t lutMilliSec_Len[] = { + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, 7, 7, 7, 7, 7, 7, 7, 7, 6 +}; + +const float lutMicroSec_Value[] = { + 0.00001f, 0.00002f, 0.00003f, 0.00004f, 0.00005f, 0.00006f, 0.00007f, 0.00008f, 0.00009f, 0.0001f, + 0.00011f, 0.00012f, 0.00013f, 0.00014f, 0.00015f, 0.00016f, 0.00017f, 0.00018f, 0.00019f, 0.0002f, + 0.00021f, 0.00022f, 0.00023f, 0.00024f, 0.00025f, 0.00026f, 0.00027f, 0.00028f, 0.00029f, 0.0003f, + 0.00031f, 0.00032f, 0.00033f, 0.00034f, 0.00035f, 0.00036f, 0.00037f, 0.00038f, 0.00039f, 0.0004f, + 0.00041f, 0.00042f, 0.00043f, 0.00044f, 0.00045f, 0.00046f, 0.00047f, 0.00048f, 0.00049f, 0.0005f, + 0.00051f, 0.00052f, 0.00053f, 0.00054f, 0.00055f, 0.00056f, 0.00057f, 0.00058f, 0.00059f, 0.0006f, + 0.00061f, 0.00062f, 0.00063f, 0.00064f, 0.00065f, 0.00066f, 0.00067f, 0.00068f, 0.00069f, 0.0007f, + 0.00071f, 0.00072f, 0.00073f, 0.00074f, 0.00075f, 0.00076f, 0.00077f, 0.00078f, 0.00079f, 0.0008f, + 0.00081f, 0.00082f, 0.00083f, 0.00084f, 0.00085f, 0.00086f, 0.00087f, 0.00088f, 0.00089f, 0.0009f, + 0.00091f, 0.00092f, 0.00093f, 0.00094f, 0.00095f, 0.00096f, 0.00097f, 0.00098f, 0.00099f +}; +const uint16_t lutMicroSec_Code[] = { + 444, 18, 445, 19, 894, 16, 895, 17, 892, 22, 893, 23, 434, 20, 435, 21, 432, 10, 433, 11, + 438, 8, 439, 9, 436, 14, 437, 15, 410, 12, 411, 13, 408, 2, 409, 3, 414, 0, 415, 1, + 412, 6, 413, 7, 402, 4, 403, 5, 400, 26, 401, 27, 406, 24, 407, 25, 404, 30, 405, 31, + 426, 28, 427, 29, 424, 18, 425, 19, 430, 16, 431, 17, 428, 22, 429, 23, 418, 20, 419, 21, + 416, 58, 417, 59, 422, 56, 423, 57, 420, 62, 421, 63, 442, 60, 443, 61, 440, 24, 441 +}; +const uint8_t lutMicroSec_Len[] = { + 9, 5, 9, 5, 10, 5, 10, 5, 10, 5, 10, 5, 9, 5, 9, 5, 9, 6, 9, 6, + 9, 6, 9, 6, 9, 6, 9, 6, 9, 6, 9, 6, 9, 6, 9, 6, 9, 6, 9, 6, + 9, 6, 9, 6, 9, 6, 9, 6, 9, 6, 9, 6, 9, 6, 9, 6, 9, 6, 9, 6, + 9, 6, 9, 6, 9, 6, 9, 6, 9, 6, 9, 6, 9, 6, 9, 6, 9, 6, 9, 6, + 9, 6, 9, 6, 9, 6, 9, 6, 9, 6, 9, 6, 9, 6, 9, 6, 9, 5, 9 +}; + +const float lutFreq_Value[] = { + 16.0f, 20.0f, 25.0f, 31.5f, 40.0f, 50.0f, 63.0f, 80.0f, 100.0f, 125.0f, + 160.0f, 200.0f, 250.0f, 315.0f, 400.0f, 500.0f, 630.0f, 800.0f, 1000.0f, 1250.0f, + 1600.0f, 2000.0f, 2500.0f, 3150.0f, 4000.0f, 5000.0f, 6300.0f, 8000.0f, 10000.0f, 12500.0f, + 16000.0f, 20000.0f, 25000.0f, 31500.0f, 40000.0f +}; +const uint16_t lutFreq_Code[] = { 35, 14, 15, 9, 12, 13, 0, 26, 27, 1, 24, 25, 14, 30, 31, 15, 28, 29, 12, 18, 19, 13, 16, 17, 10, 22, 23, 11, 20, 21, 2, 16, 138, 139, 68 }; +const uint8_t lutFreq_Len[] = { 6, 6, 6, 4, 6, 6, 4, 6, 6, 4, 6, 6, 4, 6, 6, 4, 6, 6, 4, 6, 6, 4, 6, 6, 4, 6, 6, 4, 6, 6, 4, 5, 8, 8, 7 }; + +const float lutFreqHop_Value[] = { 1.059463094f, 1.122462048f, 1.189207115f, 1.259921050f, 1.414213562f, 2.0f, 4.0f }; +const uint16_t lutFreqHop_Code[] = { 2, 3, 0, 1, 1, 3, 2 }; +const uint8_t lutFreqHop_Len[] = { 4, 4, 4, 2, 4, 2, 2 }; + +const float lutDsr_Value[] = { + -150.0f, -149.0f, -148.0f, -147.0f, -146.0f, -145.0f, -144.0f, -143.0f, -142.0f, -141.0f, + -140.0f, -139.0f, -138.0f, -137.0f, -136.0f, -135.0f, -134.0f, -133.0f, -132.0f, -131.0f, + -130.0f, -129.0f, -128.0f, -127.0f, -126.0f, -125.0f, -124.0f, -123.0f, -122.0f, -121.0f, + -120.0f, -119.0f, -118.0f, -117.0f, -116.0f, -115.0f, -114.0f, -113.0f, -112.0f, -111.0f, + -110.0f, -109.0f, -108.0f, -107.0f, -106.0f, -105.0f, -104.0f, -103.0f, -102.0f, -101.0f, + -100.0f, -99.0f, -98.0f, -97.0f, -96.0f, -95.0f, -94.0f, -93.0f, -92.0f, -91.0f, + -90.0f, -89.0f, -88.0f, -87.0f, -86.0f, -85.0f, -84.0f, -83.0f, -82.0f, -81.0f, + -80.0f, -79.0f, -78.0f, -77.0f, -76.0f, -75.0f, -74.0f, -73.0f, -72.0f, -71.0f, + -70.0f, -69.0f, -68.0f, -67.0f, -66.0f, -65.0f, -64.0f, -63.0f, -62.0f, -61.0f, + -60.0f, -59.0f, -58.0f, -57.0f, -56.0f, -55.0f, -54.0f, -53.0f, -52.0f, -51.0f, + -50.0f, -49.0f, -48.0f, -47.0f, -46.0f, -45.0f, -44.0f, -43.0f, -42.0f, -41.0f, + -40.0f, -39.0f, -38.0f, -37.0f, -36.0f, -35.0f, -34.0f, -33.0f, -32.0f, -31.0f, + -30.0f, -29.0f, -28.0f, -27.0f, -26.0f, -25.0f, -24.0f, -23.0f, -22.0f, -21.0f, + -20.0f, -19.0f, -18.0f, -17.0f, -16.0f, -15.0f, -14.0f, -13.0f, -12.0f, -11.0f, + -10.0f +}; +const uint16_t lutDsr_Code[] = { + 140, 141, 286, 287, 284, 285, 130, 131, 128, 129, 134, 135, 132, 133, 234, 235, 232, 233, 238, 239, + 236, 237, 226, 227, 224, 225, 230, 231, 228, 229, 250, 251, 248, 249, 254, 255, 252, 253, 242, 243, + 240, 241, 246, 247, 244, 245, 202, 203, 200, 201, 206, 207, 204, 205, 194, 195, 192, 193, 198, 199, + 196, 197, 218, 219, 216, 217, 222, 223, 220, 221, 20, 21, 38, 39, 36, 37, 58, 59, 56, 57, + 62, 63, 60, 61, 50, 51, 48, 49, 54, 55, 52, 53, 10, 11, 8, 9, 14, 15, 12, 13, + 2, 3, 0, 1, 6, 7, 4, 5, 42, 43, 40, 41, 46, 47, 44, 45, 18, 19, 16, 17, + 22, 210, 211, 208, 209, 214, 215, 212, 213, 186, 187, 184, 185, 190, 191, 188, 189, 138, 139, 136, + 137 +}; +const uint8_t lutDsr_Len[] = { + 8, 8, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, + 8 +}; + +const float lutMeters_Value[] = { + 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, + 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f, + 20.0f, 21.0f, 22.0f, 23.0f, 24.0f, 25.0f, 26.0f, 27.0f, 28.0f, 29.0f, + 30.0f, 31.0f, 32.0f, 33.0f, 34.0f, 35.0f, 36.0f, 37.0f, 38.0f, 39.0f, + 40.0f, 41.0f, 42.0f, 43.0f, 44.0f, 45.0f, 46.0f, 47.0f, 48.0f, 49.0f, + 50.0f, 51.0f, 52.0f, 53.0f, 54.0f, 55.0f, 56.0f, 57.0f, 58.0f, 59.0f, + 60.0f, 61.0f, 62.0f, 63.0f, 64.0f, 65.0f, 66.0f, 67.0f, 68.0f, 69.0f, + 70.0f, 71.0f, 72.0f, 73.0f, 74.0f, 75.0f, 76.0f, 77.0f, 78.0f, 79.0f, + 80.0f, 81.0f, 82.0f, 83.0f, 84.0f, 85.0f, 86.0f, 87.0f, 88.0f, 89.0f, + 90.0f, 91.0f, 92.0f, 93.0f, 94.0f, 95.0f, 96.0f, 97.0f, 98.0f, 99.0f }; +const uint16_t lutMeters_Code[] = { + 61, 50, 51, 48, 49, 54, 55, 52, 53, 10, + 11, 8, 9, 14, 15, 12, 13, 2, 3, 0, + 1, 6, 7, 4, 5, 26, 27, 24, 25, 30, + 31, 28, 29, 18, 19, 16, 17, 22, 23, 20, + 21, 42, 43, 40, 41, 46, 47, 44, 45, 16, + 68, 69, 142, 143, 140, 141, 154, 155, 152, 153, + 158, 159, 156, 157, 146, 147, 144, 145, 150, 151, + 148, 149, 234, 235, 232, 233, 238, 239, 236, 237, + 226, 227, 224, 225, 230, 231, 228, 229, 250, 251, + 248, 249, 254, 255, 252, 253, 242, 243, 240, 241 +}; + +const uint8_t lutMeters_Len[] = { + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, + 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 +}; + +const float lutHectometers_Value[] = { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f }; +const uint16_t lutHectometers_Code[] = { 0, 1, 6, 7, 4, 5, 6, 7, 4, 5 }; +const uint8_t lutHectometers_Len[] = { 3, 3, 3, 3, 3, 3, 4, 4, 4, 4 }; + +const float lutKilometers_Value[] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f }; +const uint16_t lutKilometers_Code[] = { 2, 3, 1, 0, 7, 5, 4, 13, 25, 24 }; +const uint8_t lutKilometers_Len[] = { 2, 3, 3, 3, 3, 4, 4, 4, 5, 5 }; + +const float lutCentimeters_Value[] = { + 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, + 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f, + 20.0f, 21.0f, 22.0f, 23.0f, 24.0f, 25.0f, 26.0f, 27.0f, 28.0f, 29.0f, + 30.0f, 31.0f, 32.0f, 33.0f, 34.0f, 35.0f, 36.0f, 37.0f, 38.0f, 39.0f, + 40.0f, 41.0f, 42.0f, 43.0f, 44.0f, 45.0f, 46.0f, 47.0f, 48.0f, 49.0f, + 50.0f, 51.0f, 52.0f, 53.0f, 54.0f, 55.0f, 56.0f, 57.0f, 58.0f, 59.0f, + 60.0f, 61.0f, 62.0f, 63.0f, 64.0f, 65.0f, 66.0f, 67.0f, 68.0f, 69.0f, + 70.0f, 71.0f, 72.0f, 73.0f, 74.0f, 75.0f, 76.0f, 77.0f, 78.0f, 79.0f, + 80.0f, 81.0f, 82.0f, 83.0f, 84.0f, 85.0f, 86.0f, 87.0f, 88.0f, 89.0f, + 90.0f, 91.0f, 92.0f, 93.0f, 94.0f, 95.0f, 96.0f, 97.0f, 98.0f, 99.0f +}; + +const uint16_t lutCentimeters_Code[] = { + 50, 51, 48, 49, 54, 55, 52, 53, 42, 43, + 40, 41, 46, 47, 44, 45, 34, 35, 32, 33, + 38, 39, 36, 37, 58, 59, 56, 57, 62, 63, + 60, 61, 50, 51, 48, 49, 54, 55, 52, 53, + 10, 11, 8, 9, 14, 15, 12, 13, 2, 3, + 0, 1, 6, 7, 4, 5, 26, 27, 24, 25, + 30, 31, 28, 29, 18, 19, 16, 17, 22, 23, + 20, 21, 42, 43, 40, 41, 46, 47, 44, 45, + 34, 35, 32, 33, 38, 39, 36, 37, 122, 123, + 120, 121, 126, 127, 124, 125, 58, 59, 56, 57 +}; + +const uint8_t lutCentimeters_Len[] = { + 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, + 7, 7, 7, 7, 7, 7, 6, 6, 6, 6 +}; + +const float lutAbsorption_Value[] = { 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f }; +const uint16_t lutAbsorption_Code[] = { 6, 4, 5, 6, 7, 7, 4, 5, 2, 3, 0 }; +const uint8_t lutAbsorption_Len[] = { 3, 3, 3, 4, 4, 3, 4, 4, 4, 4, 3 }; + +/*------------------------------------------------------------------------------------------* + * Default frequency grids + *------------------------------------------------------------------------------------------*/ + +const float defaultFrequencyGrid_0[] = { 31.5f, 63.0f, 125.0f, 250.0f, 500.0f, 1000.0f, 2000.0f, 4000.0f, 8000.0f, 16000.0f }; +const float defaultFrequencyGrid_1[] = { 25.0f, 50.0f, 100.0f, 200.0f, 400.0f, 800.0f, 1600.0f, 3150.0f, 6300.0f, 12500.0f }; +const float defaultFrequencyGrid_2[] = { + 20.0f, 25.0f, 31.5f, 40.0f, 50.0f, 63.0f, 80.0f, 100.0f, 125.0f, 160.0f, + 200.0f, 250.0f, 315.0f, 400.0f, 500.0f, 630.0f, 800.0f, 1000.0f, 1250.0f, 1600.0f, + 2000.0f, 2500.0f, 3150.0f, 4000.0f, 5000.0f, 6300.0f, 8000.0f, 10000.0f, 12500.0f, 16000.0f, 20000.0f +}; +const float defaultFrequencyGrid_3[] = { 25.0f, 100.0f, 400.0f, 1600.0f, 6300.0f }; +const float defaultFrequencyGrid_4[] = { 125.0f, 250.0f, 500.0f, 1000.0f, 2000.0f, 4000.0f }; +const float defaultFrequencyGrid_5[] = { 25.0f, 250.0f, 2500.0f }; +const float defaultFrequencyGrid_6[] = { + 27.0f, 56.0f, 89.0f, 126.0f, 168.0f, 214.0f, 265.0f, 323.0f, 387.0f, 459.0f, + 539.0f, 628.0f, 727.0f, 839.0f, 963.0f, 1101.0f, 1256.0f, 1429.0f, 1621.0f, 1836.0f, + 2077.0f, 2345.0f, 2644.0f, 2978.0f, 3351.0f, 3767.0f, 4232.0f, 4750.0f, 5329.0f, 5975.0f, + 6697.0f, 7502.0f, 8401.0f, 9405.0f, 10525.0f, 11775.0f, 13171.0f, 14729.0f, 16468.0f, 18410.0f, 20577.0f +}; +const float defaultFrequencyGrid_7[] = { + 27.0f, 89.0f, 168.0f, 265.0f, 387.0f, 539.0f, 727.0f, 963.0f, 1256.0f, 1621.0f, + 2077.0f, 2644.0f, 3351.0f, 4232.0f, 5329.0f, 6697.0f, 8401.0f, 10525.0f, 13171.0f, 16468.0f, 20577.0f +}; +const float defaultFrequencyGrid_8[] = { + 50.0f, 150.0f, 250.0f, 350.0f, 450.0f, 570.0f, 700.0f, 840.0f, 1000.0f, 1170.0f, + 1370.0f, 1600.0f, 1850.0f, 2150.0f, 2150.0f, 2500.0f, 2900.0f, 3400.0f, 4000.0f, 4800.0f, + 5800.0f, 7000.0f, 8500.0f, 10500.0f, 13500.0f +}; /*-----------------------------------------------------------------------------------------* - * Function read_bool() - * - * Reads a boolean value from a line + * Function read_bin_bits() + * Reads a given number of bits from the bitstream *-----------------------------------------------------------------------------------------*/ - -/*! r: false on success, true on failure */ -static int16_t read_bool( - const char *pLine, /* i : String to read from */ - int16_t *pTarget /* o : Output pointer (int16_t type used instead of bool because of coding rules/specs) */ +static ivas_error read_bin_bits( + RenderConfigReader *this, /* i/o : Renderer config reader handle */ + uint32_t *pTarget, /* o : Target read data pointer */ + const size_t nBits /* i : Number of bits to read */ ) { - char value[8]; + uint8_t n; + uint32_t nByte; + uint8_t bit; - if ( sscanf( pLine, "%s", (char *) &value ) != 1 ) + if ( this == NULL || this->pBitstream == NULL || pTarget == NULL ) { - return TRUE; + return IVAS_ERR_UNEXPECTED_NULL_POINTER; } - if ( strcmp( value, "TRUE" ) == 0 ) + + if ( this->readOffset + nBits > this->length * 8 ) { - *pTarget = TRUE; - return FALSE; + return IVAS_ERR_INVALID_RENDER_CONFIG; } - if ( strcmp( value, "FALSE" ) == 0 ) + + *pTarget = 0; + for ( n = 0; n < nBits; n++ ) { - *pTarget = FALSE; - return FALSE; + nByte = ( this->readOffset + n ) >> 3; + bit = this->pBitstream[nByte] >> ( 7 - ( ( this->readOffset + n ) % 8 ) ) & 1; + *pTarget = ( *pTarget << 1 ) + bit; } - return true; -} + this->readOffset += nBits; + return IVAS_ERR_OK; +} /*-----------------------------------------------------------------------------------------* - * Function read_vector() - * - * Reads a vector value from a line + * Function read_bin_bool() + * Reads a boolean value from a bitstream *-----------------------------------------------------------------------------------------*/ - -static int16_t read_vector( - char *pLine, /* i : String to read from */ - const int16_t length, /* i : Number of expected vector elements */ - float *pTarget /* o : Output vector pointer */ +static ivas_error read_bin_bool( + RenderConfigReader *this, /* i/o : Renderer config reader handle */ + uint32_t *pResult /* o : Target read data pointer */ ) { - char *tmp; - int16_t n; - int16_t count; - - n = (int16_t) sscanf( pLine, "[%s", pLine ); - if ( n == 0 ) - { - return true; - } - - /* 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++ ) - ; + return read_bin_bits( this, pResult, 1 ); +} - count = n; +/*-----------------------------------------------------------------------------------------* + * Function get_bin_id() + * Reads an ID from a bitstream + *-----------------------------------------------------------------------------------------*/ +static ivas_error get_bin_id( + RenderConfigReader *this, /* i/o : Renderer config reader handle */ + uint32_t *pResult /* o : Target read data pointer */ +) +{ + ivas_error error; + uint32_t id; + uint32_t cont; - tmp = pLine; + *pResult = 0; + id = 0; + cont = true; - /* Check for maximum vector length */ - if ( n != length ) + if ( pResult == NULL ) { - return true; + return IVAS_ERR_UNEXPECTED_NULL_POINTER; } - for ( n = 0; n < count; n++ ) + while ( cont ) { - if ( (int16_t) sscanf( tmp, "%f,", &pTarget[n] ) != 1 ) + if ( ( error = read_bin_bits( this, &id, 7 ) ) != IVAS_ERR_OK ) { - return true; + return error; } + *pResult = ( *pResult << 7 ) | id; - tmp = strchr( tmp, ',' ) + 1; + if ( ( error = read_bin_bool( this, &cont ) ) != IVAS_ERR_OK ) + { + return error; + } } - return false; + return IVAS_ERR_OK; } - /*-----------------------------------------------------------------------------------------* - * Function strip_spaces_upper() - * - * Strips the spaces from a buffer and uppercases it + * Function read_bin_code_word() + * Reads a code word from a LUT *-----------------------------------------------------------------------------------------*/ - -static void strip_spaces_upper( - char *pStr /* i : String to read from */ +static ivas_error read_bin_code_word( + RenderConfigReader *this, /* i/o : Renderer config reader handle */ + const RC_LUT table, /* i : Table enum */ + float *pResult /* o : Code value */ ) { - int32_t read_idx = 0, write_idx = 0; + ivas_error error; + const float *pValues; + const uint16_t *pCodes; + const uint8_t *pLengths; + uint8_t minLen; + uint8_t maxLen; + uint8_t size; + uint8_t n; + uint32_t code; + uint32_t bits; + uint32_t nr_bits; + uint8_t len; + + minLen = 255; + maxLen = 0; + bits = 0; + nr_bits = 0; + code = 0; + + if ( pResult == NULL ) + { + return IVAS_ERR_UNEXPECTED_NULL_POINTER; + } - while ( pStr[read_idx] ) + /* Select the right tables */ + switch ( table ) { -#ifdef SPLIT_REND_WITH_HEAD_ROT - if ( !isspace( (int32_t) pStr[read_idx] ) && !iscntrl( (int32_t) pStr[read_idx] ) ) -#else - if ( !isspace( pStr[read_idx] ) && !iscntrl( pStr[read_idx] ) ) -#endif + case RC_LUT_COUNT_IDX_LO: + pValues = lutCountIdxLo_Value; + pCodes = lutCountIdxLo_Code; + pLengths = lutCountIdxLo_Len; + size = sizeof lutCountIdxLo_Len / sizeof( uint8_t ); + break; + case RC_LUT_COUNT_IDX_HI: + pValues = lutCountIdxHi_Value; + pCodes = lutCountIdxHi_Code; + pLengths = lutCountIdxHi_Len; + size = sizeof lutCountIdxHi_Len / sizeof( uint8_t ); + break; + case RC_LUT_DECI_SEC: + pValues = lutDeciSec_Value; + pCodes = lutDeciSec_Code; + pLengths = lutDeciSec_Len; + size = sizeof lutDeciSec_Len / sizeof( uint8_t ); + break; + case RC_LUT_SEC: + pValues = lutSec_Value; + pCodes = lutSec_Code; + pLengths = lutSec_Len; + size = sizeof lutSec_Len / sizeof( uint8_t ); + break; + case RC_LUT_MILLI_SEC: + pValues = lutMilliSec_Value; + pCodes = lutMilliSec_Code; + pLengths = lutMilliSec_Len; + size = sizeof lutMilliSec_Len / sizeof( uint8_t ); + break; + case RC_LUT_MICRO_SEC: + pValues = lutMicroSec_Value; + pCodes = lutMicroSec_Code; + pLengths = lutMicroSec_Len; + size = sizeof lutMicroSec_Len / sizeof( uint8_t ); + break; + case RC_LUT_FREQ: + pValues = lutFreq_Value; + pCodes = lutFreq_Code; + pLengths = lutFreq_Len; + size = sizeof lutFreq_Len / sizeof( uint8_t ); + break; + case RC_LUT_FREQ_HOP: + pValues = lutFreqHop_Value; + pCodes = lutFreqHop_Code; + pLengths = lutFreqHop_Len; + size = sizeof lutFreqHop_Len / sizeof( uint8_t ); + break; + case RC_LUT_DSR: + pValues = lutDsr_Value; + pCodes = lutDsr_Code; + pLengths = lutDsr_Len; + size = sizeof lutDsr_Len / sizeof( uint8_t ); + break; + case RC_LUT_METERS: + pValues = lutMeters_Value; + pCodes = lutMeters_Code; + pLengths = lutMeters_Len; + size = sizeof lutMeters_Len / sizeof( uint8_t ); + break; + case RC_LUT_HECTOMETERS: + pValues = lutHectometers_Value; + pCodes = lutHectometers_Code; + pLengths = lutHectometers_Len; + size = sizeof lutHectometers_Len / sizeof( uint8_t ); + break; + case RC_LUT_KILOMETERS: + pValues = lutKilometers_Value; + pCodes = lutKilometers_Code; + pLengths = lutKilometers_Len; + size = sizeof lutKilometers_Len / sizeof( uint8_t ); + break; + case RC_LUT_CENTIMETERS: + pValues = lutCentimeters_Value; + pCodes = lutCentimeters_Code; + pLengths = lutCentimeters_Len; + size = sizeof lutCentimeters_Len / sizeof( uint8_t ); + break; + case RC_LUT_ABSORPTION: + pValues = lutAbsorption_Value; + pCodes = lutAbsorption_Code; + pLengths = lutAbsorption_Len; + size = sizeof lutAbsorption_Len / sizeof( uint8_t ); + break; + case RC_LUT_INVALID: + default: + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + + /* First read minLen bits, then add one bit per iteration to find the correct value */ + for ( n = 0; n < size; n++ ) + { + minLen = min( minLen, pLengths[n] ); + maxLen = max( maxLen, pLengths[n] ); + } + for ( len = minLen; len <= maxLen; len++ ) + { + nr_bits = ( len == minLen ) ? minLen : 1; + if ( ( error = read_bin_bits( this, &bits, nr_bits ) ) != IVAS_ERR_OK ) { - pStr[write_idx++] = pStr[read_idx]; + return error; + } + code = ( code << nr_bits ) | bits; + for ( n = 0; n < size; n++ ) + { + if ( code == pCodes[n] && len == pLengths[n] ) + { + *pResult = pValues[n]; + return IVAS_ERR_OK; + } } - read_idx++; } - pStr[write_idx] = '\0'; - to_upper( pStr ); - - return; + return IVAS_ERR_INVALID_RENDER_CONFIG; } - /*-----------------------------------------------------------------------------------------* - * Function errorHandler() - * - * Prints error message and exits + * Function get_bin_count_or_index() + * Gets a count or index *-----------------------------------------------------------------------------------------*/ - -/*! r: error accumulation */ -static int32_t errorHandler( - const char *badStr, /* i : String to complain about */ - const ERROR_CODES_t error ) +static ivas_error get_bin_count_or_index( + RenderConfigReader *this, /* i/o : Renderer config reader handle */ + uint32_t *pResult /* o : Count or index value */ +) { - static int32_t numErrors = 0; + ivas_error error; + float value; + uint32_t isLarge; - switch ( error ) + if ( pResult == NULL ) { - 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 IVAS_ERR_UNEXPECTED_NULL_POINTER; } - return numErrors; -} + if ( ( error = read_bin_code_word( this, RC_LUT_COUNT_IDX_LO, &value ) ) != IVAS_ERR_OK ) + { + return error; + } + *pResult = (uint32_t) value; -/*------------------------------------------------------------------------------------------* - * RenderConfigReader_checkValues() - * - * Verifies if the configuration parameters lie within acceptable limits - *------------------------------------------------------------------------------------------*/ + if ( ( error = read_bin_bool( this, &isLarge ) ) != IVAS_ERR_OK ) + { + return error; + } -static ivas_error RenderConfigReader_checkValues( - IVAS_RENDER_CONFIG_HANDLE hRenderConfig /* o : Renderer configuration handle */ + if ( isLarge ) + { + if ( ( error = read_bin_code_word( this, RC_LUT_COUNT_IDX_HI, &value ) ) != IVAS_ERR_OK ) + { + return error; + } + *pResult += (uint32_t) value << 6; + } + + return IVAS_ERR_OK; +} + +/*-----------------------------------------------------------------------------------------* + * Function get_bin_duration() + * Gets a duration value + *-----------------------------------------------------------------------------------------*/ +static ivas_error get_bin_duration( + RenderConfigReader *this, /* i/o : Renderer config reader handle */ + float *pResult /* o : Duration value */ ) { - int16_t band_idx, tab_value_err_count; - IVAS_ROOM_ACOUSTICS_CONFIG_DATA *pRoom_acoustics; - pRoom_acoustics = &hRenderConfig->room_acoustics; - tab_value_err_count = 0; + ivas_error error; + float value; + uint32_t addFlag; - /* Verify the number of frequency bands in the config input data */ - if ( ( pRoom_acoustics->nBands > N_BANDS_MAX ) || ( pRoom_acoustics->nBands < N_BANDS_MIN ) ) + /* Deciseconds */ + if ( ( error = read_bin_code_word( this, RC_LUT_DECI_SEC, &value ) ) != IVAS_ERR_OK ) { - return IVAS_ERR_WRONG_PARAMS; + return error; } + *pResult = value; - /* Verify input pre-delay value */ - if ( ( pRoom_acoustics->inputPreDelay > INPUTPREDELAY_MAX ) || ( pRoom_acoustics->inputPreDelay < INPUTPREDELAY_MIN ) ) + /* Milliseconds */ + if ( ( error = read_bin_bool( this, &addFlag ) ) != IVAS_ERR_OK ) { - return IVAS_ERR_WRONG_PARAMS; + return error; } - /* Verify data per band in the acoustic properties table */ - for ( band_idx = 0; band_idx < pRoom_acoustics->nBands; band_idx++ ) + if ( addFlag ) { - /* Verify if the frequencies are in the ascending order (required for interpolation) */ - if ( band_idx != 0 ) + if ( ( error = read_bin_code_word( this, RC_LUT_MILLI_SEC, &value ) ) != IVAS_ERR_OK ) { - if ( pRoom_acoustics->pFc_input[band_idx] <= pRoom_acoustics->pFc_input[band_idx - 1] ) - { - tab_value_err_count++; - } + return error; } + *pResult += value; - /* Check the input frequencies */ - if ( ( pRoom_acoustics->pFc_input[band_idx] > FC_INPUT_MAX ) || ( pRoom_acoustics->pFc_input[band_idx] < FC_INPUT_MIN ) ) + /* Microseconds */ + if ( ( error = read_bin_bool( this, &addFlag ) ) != IVAS_ERR_OK ) { - tab_value_err_count++; + return error; } - /* Check the input RT60 values */ - if ( ( pRoom_acoustics->pAcoustic_rt60[band_idx] > ACOUSTIC_RT60_MAX ) || ( pRoom_acoustics->pAcoustic_rt60[band_idx] < ACOUSTIC_RT60_MIN ) ) + if ( addFlag ) { - tab_value_err_count++; + if ( ( error = read_bin_code_word( this, RC_LUT_MICRO_SEC, &value ) ) != IVAS_ERR_OK ) + { + return error; + } + *pResult += value; } + } - /* Check the input DSR values */ - if ( ( pRoom_acoustics->pAcoustic_dsr[band_idx] > ACOUSTIC_DSR_MAX ) || ( pRoom_acoustics->pAcoustic_dsr[band_idx] < ACOUSTIC_DSR_MIN ) ) - { - tab_value_err_count++; + /* Seconds */ + if ( ( error = read_bin_bool( this, &addFlag ) ) != IVAS_ERR_OK ) + { + return error; + } + + if ( addFlag ) + { + if ( ( error = read_bin_code_word( this, RC_LUT_SEC, &value ) ) != IVAS_ERR_OK ) + { + return error; } + *pResult += value; + } - /* Replace zero DSR values with very small positive values, to avoid issues with coloration filter design */ - if ( pRoom_acoustics->pAcoustic_dsr[band_idx] <= 0.0f ) + /* Correct rounding errors due to multiple additions: */ + *pResult = roundf( *pResult * 100000.0f ) / 100000.0f; + + return IVAS_ERR_OK; +} + +/*-----------------------------------------------------------------------------------------* + * Function get_bin_frequency() + * Gets a frequency value + *-----------------------------------------------------------------------------------------*/ +static ivas_error get_bin_frequency( + RenderConfigReader *this, /* i/o : Renderer config reader handle */ + float *pResult /* o : Frequency value */ +) +{ + ivas_error error; + uint32_t hiRes; + uint32_t refine; + + hiRes = 0; + refine = 0; + + if ( ( error = read_bin_code_word( this, RC_LUT_FREQ, pResult ) ) != IVAS_ERR_OK ) + { + return error; + } + + if ( ( error = read_bin_bool( this, &hiRes ) ) != IVAS_ERR_OK ) + { + return error; + } + + if ( hiRes ) + { + if ( ( error = read_bin_bits( this, &refine, 4 ) ) != IVAS_ERR_OK ) { - pRoom_acoustics->pAcoustic_dsr[band_idx] = ACOUSTIC_DSR_EPSILON; + return error; } + + *pResult *= powf( 2.0f, ( (float) refine + 1.0f ) / 51.0f ); } + return IVAS_ERR_OK; +} - if ( tab_value_err_count != 0 ) +/*-----------------------------------------------------------------------------------------* + * Function get_bin_dsr() + * Gets a DSR value + *-----------------------------------------------------------------------------------------*/ +static ivas_error get_bin_dsr( + RenderConfigReader *this, /* i/o : Renderer config reader handle */ + float *pResult /* o : DSR value */ +) +{ + ivas_error error; + float value; + + if ( ( error = read_bin_code_word( this, RC_LUT_DSR, &value ) ) != IVAS_ERR_OK ) { - return IVAS_ERR_WRONG_PARAMS; + return error; } + *pResult = powf( 10.0f, value / 10.0f ); -#ifdef DEBUGGING - /* Specific limits for Jot reverb */ - if ( hRenderConfig->renderer_type_override == IVAS_RENDER_TYPE_OVERRIDE_CREND ) + return IVAS_ERR_OK; +} + +/*-----------------------------------------------------------------------------------------* + * Function get_bin_distance() + * Gets a distance value (in meters) + *-----------------------------------------------------------------------------------------*/ + +static ivas_error get_bin_distance( + RenderConfigReader *this, /* i/o : Render config reader handle */ + uint16_t isSmall, /* i : Flag indicating a small distance */ + float *pResult /* o : Distance value */ +) +{ + ivas_error error; + float value; + uint32_t flag; + + if ( ( error = read_bin_code_word( this, RC_LUT_METERS, pResult ) ) != IVAS_ERR_OK ) { - if ( ( pRoom_acoustics->acousticPreDelay > ACOUSTICPREDELAY_JOTREV_MAX ) || ( pRoom_acoustics->acousticPreDelay < ACOUSTICPREDELAY_JOTREV_MIN ) ) + return error; + } + + if ( isSmall == false ) + { + /* addHectometers flag */ + if ( ( error = read_bin_bool( this, &flag ) ) != IVAS_ERR_OK ) { - return IVAS_ERR_WRONG_PARAMS; + return error; + } + + if ( flag == true ) + { + /* Hectometers */ + if ( ( error = read_bin_code_word( this, RC_LUT_HECTOMETERS, &value ) ) != IVAS_ERR_OK ) + { + return error; + } + *pResult += value * 100.0f; + + /* addKilometers flag */ + if ( ( error = read_bin_bool( this, &flag ) ) != IVAS_ERR_OK ) + { + return error; + } + + while ( flag == true ) + { + /* Kilometers */ + if ( ( error = read_bin_code_word( this, RC_LUT_KILOMETERS, &value ) ) != IVAS_ERR_OK ) + { + return error; + } + *pResult += value * 1000.0f; + + /* addKilometers flag */ + if ( ( error = read_bin_bool( this, &flag ) ) != IVAS_ERR_OK ) + { + return error; + } + } } } - /* Specific limits for frequency-domain reverb */ - if ( hRenderConfig->renderer_type_override == IVAS_RENDER_TYPE_OVERRIDE_FASTCONV ) + /* addCentimeters flag */ + if ( ( error = read_bin_bool( this, &flag ) ) != IVAS_ERR_OK ) { - if ( ( pRoom_acoustics->acousticPreDelay > ACOUSTICPREDELAY_FDREV_MAX ) || ( pRoom_acoustics->acousticPreDelay < ACOUSTICPREDELAY_FDREV_MIN ) ) + return error; + } + if ( flag == true ) + { + /* Centimeters */ + if ( ( error = read_bin_code_word( this, RC_LUT_CENTIMETERS, &value ) ) != IVAS_ERR_OK ) { - return IVAS_ERR_WRONG_PARAMS; + return error; } + *pResult += value * 0.01f; } -#endif /* DEBUGGING */ return IVAS_ERR_OK; } +/*-----------------------------------------------------------------------------------------* + * Function get_bin_absorption() + * Gets an absorption value + *-----------------------------------------------------------------------------------------*/ -/*------------------------------------------------------------------------------------------* - * RenderConfigReader_open() - * - * Allocates and initializes a renderer configuration reader instance - *------------------------------------------------------------------------------------------*/ +static ivas_error get_bin_absorption( + RenderConfigReader *this, /* i/o : Render config reader handle */ + float *pResult /* o : Absorption value */ +) +{ + ivas_error error; -ivas_error RenderConfigReader_open( - char *pConfigPath, /* i : renderer configuration file path */ - RenderConfigReader **ppRenderConfigReader /* o : RenderConfigReader handle */ + if ( ( error = read_bin_code_word( this, RC_LUT_ABSORPTION, pResult ) ) != IVAS_ERR_OK ) + { + return error; + } + + return IVAS_ERR_OK; +} + +/*-----------------------------------------------------------------------------------------* + * 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 */ + uint32_t *pTarget /* o : Output pointer */ ) { - RenderConfigReader *pSelf; - FILE *pConfigFile; + char value[8 + 1]; - /* Open the configuration file */ - if ( strlen( pConfigPath ) < 1 ) + if ( sscanf( pLine, "%8s", (char *) &value ) != 1 ) { - return IVAS_ERR_FAILED_FILE_OPEN; + return IVAS_ERR_INVALID_RENDER_CONFIG; } - pConfigFile = fopen( pConfigPath, "r" ); + 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; +} +#ifdef CONTROL_METADATA_DIRECTIVITY +/*-----------------------------------------------------------------------------------------* + * Function get_bin_angle() + * Gets an angle value in degrees [0,360] + *-----------------------------------------------------------------------------------------*/ - if ( !pConfigFile ) +static ivas_error get_bin_angle( + RenderConfigReader *this, /* i/o : Render config reader handle */ + float *pResult /* o : Angle value */ +) +{ + ivas_error error; + uint32_t value; + + if ( ( error = read_bin_bits( this, &value, 5 ) ) != IVAS_ERR_OK ) { - return IVAS_ERR_FAILED_FILE_OPEN; + return error; } - pSelf = calloc( sizeof( RenderConfigReader ), 1 ); - pSelf->pConfigFile = pConfigFile; + *pResult = usdequant( (int16_t) value, 0.0f, 20.0f ); - *ppRenderConfigReader = pSelf; return IVAS_ERR_OK; } +/*-----------------------------------------------------------------------------------------* + * Function get_bin_outer_attenuation () + * Gets an outer attenuation value [3.1623e-05,1.0], or in dB: [-90,0] + *-----------------------------------------------------------------------------------------*/ -/*------------------------------------------------------------------------------------------* - * RenderConfigReader_read() +static ivas_error get_bin_outer_attenuation( + RenderConfigReader *this, /* i/o : Render config reader handle */ + float *pResult /* o : Attenuation value */ +) +{ + ivas_error error; + uint32_t value; + float logval, att; + + if ( ( error = read_bin_bits( this, &value, 5 ) ) != IVAS_ERR_OK ) + { + return error; + } + + logval = usdequant( (int16_t) value, -90.0f, 3.0f ); + att = powf( 10, logval / 20.0f ); + + *pResult = att; + + return IVAS_ERR_OK; +} + +#endif + +#else +/*-----------------------------------------------------------------------------------------* + * Function read_bool() * - * Reads the configuration from a file - *------------------------------------------------------------------------------------------*/ + * Reads a boolean value from a line + *-----------------------------------------------------------------------------------------*/ -ivas_error RenderConfigReader_read( - RenderConfigReader *pRenderConfigReader, /* i : RenderConfigReader handle */ - IVAS_RENDER_CONFIG_HANDLE hRenderConfig /* o : Renderer configuration handle */ +/*! r: false on success, true on failure */ +static int16_t read_bool( + const char *pLine, /* i : String to read from */ + int16_t *pTarget /* o : Output pointer (int16_t type used instead of bool because of coding rules/specs) */ ) { - 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; - int16_t nBandsInput; - int16_t nVectorsMissing; -#ifdef SPLIT_REND_WITH_HEAD_ROT - bool dofProvided = false; - bool poseCorrProvided = false; + char value[8]; + + if ( sscanf( pLine, "%s", (char *) &value ) != 1 ) + { + return TRUE; + } + if ( strcmp( value, "TRUE" ) == 0 ) + { + *pTarget = TRUE; + return FALSE; + } + if ( strcmp( value, "FALSE" ) == 0 ) + { + *pTarget = FALSE; + return FALSE; + } + + return true; +} +#endif + +#ifdef CONTROL_METADATA_REVERB +/*-----------------------------------------------------------------------------------------* + * Function read_txt_vector() + * + * Reads a vector value from a line + *-----------------------------------------------------------------------------------------*/ + +static int16_t 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 true; + } + + /* 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 true; + } + + for ( n = 0; n < count; n++ ) + { + if ( (int16_t) sscanf( tmp, "%f,", &pTarget[n] ) != 1 ) + { + return true; + } + + tmp = strchr( tmp, ',' ) + 1; + } + + return false; +} +#else +/*-----------------------------------------------------------------------------------------* + * Function read_vector() + * + * Reads a vector value from a line + *-----------------------------------------------------------------------------------------*/ + +static int16_t read_vector( + char *pLine, /* i : String to read from */ + const int16_t length, /* i : Number of expected vector elements */ + float *pTarget /* o : Output vector pointer */ +) +{ + char *tmp; + int16_t n; + int16_t count; + + n = (int16_t) sscanf( pLine, "[%s", pLine ); + if ( n == 0 ) + { + return true; + } + + /* 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 true; + } + + for ( n = 0; n < count; n++ ) + { + if ( (int16_t) sscanf( tmp, "%f,", &pTarget[n] ) != 1 ) + { + return true; + } + + tmp = strchr( tmp, ',' ) + 1; + } + + return false; +} +#endif + +#ifdef CONTROL_METADATA_REVERB +/*-----------------------------------------------------------------------------------------* + * Function strip_spaces() + * + * Strips the spaces from a buffer + *-----------------------------------------------------------------------------------------*/ + +static void strip_spaces( +#else +/*-----------------------------------------------------------------------------------------* + * Function strip_spaces_upper() + * + * Strips the spaces from a buffer and uppercases it + *-----------------------------------------------------------------------------------------*/ + +static void strip_spaces_upper( +#endif + char *pStr /* i : String to read from */ +) +{ + int32_t read_idx = 0, write_idx = 0; + + while ( pStr[read_idx] ) + { +#ifdef SPLIT_REND_WITH_HEAD_ROT + if ( !isspace( (int32_t) pStr[read_idx] ) && !iscntrl( (int32_t) pStr[read_idx] ) ) +#else + if ( !isspace( pStr[read_idx] ) && !iscntrl( pStr[read_idx] ) ) +#endif + { + pStr[write_idx++] = pStr[read_idx]; + } + read_idx++; + } + pStr[write_idx] = '\0'; +#ifndef CONTROL_METADATA_REVERB + to_upper( pStr ); +#endif + + 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 + *------------------------------------------------------------------------------------------*/ + +#ifdef CONTROL_METADATA_REVERB +ivas_error RenderConfigReader_checkValues( +#else +static ivas_error RenderConfigReader_checkValues( +#endif + IVAS_RENDER_CONFIG_HANDLE hRenderConfig /* o : Renderer configuration handle */ +) +{ + int16_t band_idx, tab_value_err_count; + IVAS_ROOM_ACOUSTICS_CONFIG_DATA *pRoom_acoustics; + pRoom_acoustics = &hRenderConfig->room_acoustics; + tab_value_err_count = 0; + + /* Verify the number of frequency bands in the config input data */ + if ( ( pRoom_acoustics->nBands > N_BANDS_MAX ) || ( pRoom_acoustics->nBands < N_BANDS_MIN ) ) + { + return IVAS_ERR_WRONG_PARAMS; + } + + /* Verify input pre-delay value */ + if ( ( pRoom_acoustics->inputPreDelay > INPUTPREDELAY_MAX ) || ( pRoom_acoustics->inputPreDelay < INPUTPREDELAY_MIN ) ) + { + return IVAS_ERR_WRONG_PARAMS; + } + + /* Verify data per band in the acoustic properties table */ + for ( band_idx = 0; band_idx < pRoom_acoustics->nBands; band_idx++ ) + { + /* Verify if the frequencies are in the ascending order (required for interpolation) */ + if ( band_idx != 0 ) + { + if ( pRoom_acoustics->pFc_input[band_idx] <= pRoom_acoustics->pFc_input[band_idx - 1] ) + { + tab_value_err_count++; + } + } + + /* Check the input frequencies */ + if ( ( pRoom_acoustics->pFc_input[band_idx] > FC_INPUT_MAX ) || ( pRoom_acoustics->pFc_input[band_idx] < FC_INPUT_MIN ) ) + { + tab_value_err_count++; + } + + /* Check the input RT60 values */ + if ( ( pRoom_acoustics->pAcoustic_rt60[band_idx] > ACOUSTIC_RT60_MAX ) || ( pRoom_acoustics->pAcoustic_rt60[band_idx] < ACOUSTIC_RT60_MIN ) ) + { + tab_value_err_count++; + } + + /* Check the input DSR values */ + if ( ( pRoom_acoustics->pAcoustic_dsr[band_idx] > ACOUSTIC_DSR_MAX ) || ( pRoom_acoustics->pAcoustic_dsr[band_idx] < ACOUSTIC_DSR_MIN ) ) + { + tab_value_err_count++; + } + + /* Replace zero DSR values with very small positive values, to avoid issues with coloration filter design */ + if ( pRoom_acoustics->pAcoustic_dsr[band_idx] <= 0.0f ) + { + pRoom_acoustics->pAcoustic_dsr[band_idx] = ACOUSTIC_DSR_EPSILON; + } + } + + if ( tab_value_err_count != 0 ) + { + return IVAS_ERR_WRONG_PARAMS; + } + +#ifdef DEBUGGING + /* Specific limits for Jot reverb */ + if ( hRenderConfig->renderer_type_override == IVAS_RENDER_TYPE_OVERRIDE_CREND ) + { + if ( ( pRoom_acoustics->acousticPreDelay > ACOUSTICPREDELAY_JOTREV_MAX ) || ( pRoom_acoustics->acousticPreDelay < ACOUSTICPREDELAY_JOTREV_MIN ) ) + { + return IVAS_ERR_WRONG_PARAMS; + } + } + + /* Specific limits for frequency-domain reverb */ + if ( hRenderConfig->renderer_type_override == IVAS_RENDER_TYPE_OVERRIDE_FASTCONV ) + { + if ( ( pRoom_acoustics->acousticPreDelay > ACOUSTICPREDELAY_FDREV_MAX ) || ( pRoom_acoustics->acousticPreDelay < ACOUSTICPREDELAY_FDREV_MIN ) ) + { + return IVAS_ERR_WRONG_PARAMS; + } + } +#endif /* DEBUGGING */ + + return IVAS_ERR_OK; +} + + +/*------------------------------------------------------------------------------------------* + * RenderConfigReader_open() + * + * Allocates and initializes a renderer configuration reader instance + *------------------------------------------------------------------------------------------*/ + +ivas_error RenderConfigReader_open( + char *pConfigPath, /* i : renderer configuration file path */ + RenderConfigReader **ppRenderConfigReader /* o : RenderConfigReader handle */ +) +{ + RenderConfigReader *pSelf; + 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; + } + + pSelf = calloc( sizeof( RenderConfigReader ), 1 ); + pSelf->pConfigFile = pConfigFile; +#ifdef CONTROL_METADATA_REVERB + pSelf->nFG = 0; + pSelf->pFG = NULL; + pSelf->nAE = 0; + pSelf->pAE = NULL; +#endif +#ifdef CONTROL_METADATA_DIRECTIVITY + pSelf->nDP = 0; + pSelf->pDP = NULL; +#endif + + *ppRenderConfigReader = pSelf; + return IVAS_ERR_OK; +} + + +/*------------------------------------------------------------------------------------------* + * RenderConfigReader_readBinary() + * + * Reads the binary configuration from a file + *------------------------------------------------------------------------------------------*/ + +#ifdef CONTROL_METADATA_REVERB +static ivas_error RenderConfigReader_readBinary( + const char *pReverbConfigPath, /* i : Configuration file path */ + RenderConfigReader *pRenderConfigReader /* i/o : RenderConfigReader handle */ +) +{ + uint32_t file_size; + uint32_t value; +#ifdef EARLY_REFLECTIONS + uint32_t signx, signy, k; +#endif + uint32_t i, m, n; + uint32_t nFG, nAE; +#ifdef CONTROL_METADATA_DIRECTIVITY + uint32_t nDP; +#endif + ivas_error error; + float freqHop; + uint32_t gridLen; + uint32_t subGridLen; + const float *pGrid; + FILE *pReverbConfigFile; + + /* Open the configuration file */ + pReverbConfigFile = fopen( pReverbConfigPath, "rb" ); + + if ( !pReverbConfigFile ) + { + return IVAS_ERR_FAILED_FILE_OPEN; + } + + /* Read the bitstream */ + fseek( pReverbConfigFile, 0, SEEK_END ); + file_size = ftell( pReverbConfigFile ); + rewind( pReverbConfigFile ); + + pRenderConfigReader->pBitstream = (uint8_t *) malloc( file_size * sizeof( uint8_t ) ); + if ( pRenderConfigReader->pBitstream == NULL ) + { + return IVAS_ERR_FAILED_ALLOC; + } + + fread( pRenderConfigReader->pBitstream, sizeof( uint8_t ), file_size, pReverbConfigFile ); + pRenderConfigReader->length = file_size; + + /****************************/ + /* Read the presence flag */ + /****************************/ + if ( ( error = read_bin_bool( pRenderConfigReader, &value ) ) != IVAS_ERR_OK ) + { + return error; + } +#ifndef CONTROL_METADATA_DIRECTIVITY + /* Just return in case no acoustic environment data available */ + if ( value == false ) + { + return IVAS_ERR_OK; + } +#endif +#ifdef CONTROL_METADATA_DIRECTIVITY + /* acoustic environment data available */ + if ( value == true ) + { +#endif + /****************************/ + /* Read the frequency grids */ + /****************************/ + + /* Number of frequency grids */ + if ( ( error = get_bin_count_or_index( pRenderConfigReader, &nFG ) ) != IVAS_ERR_OK ) + { + return error; + } + + /* Allocate memory for the frequency grids */ + if ( nFG > 0 ) + { + if ( pRenderConfigReader->nFG > 0 ) + { + for ( n = 0; n < pRenderConfigReader->nFG; n++ ) + { + free( pRenderConfigReader->pFG[n].pFc ); + } + free( pRenderConfigReader->pFG ); + } + pRenderConfigReader->nFG = nFG; + if ( ( pRenderConfigReader->pFG = (FrequencyGrid *) malloc( pRenderConfigReader->nFG * sizeof( FrequencyGrid ) ) ) == NULL ) + { + return IVAS_ERR_FAILED_ALLOC; + } + for ( n = 0; n < nFG; n++ ) + { + /* Initialize memory pointers to allow safe freeing ico errors */ + pRenderConfigReader->pFG[n].pFc = NULL; + } + } + + /* Loop through the frequency grids read from the binary stream */ + for ( n = 0; n < nFG; n++ ) + { + /* Read the representation method */ + value = 0; + if ( ( error = read_bin_bits( pRenderConfigReader, &value, 2 ) ) != IVAS_ERR_OK ) + { + return error; + } + + /* Process depending on the representation method */ + switch ( value ) + { + case FREQ_GRID_MODE_INDIVIDUAL_FREQUENCIES: + if ( ( error = get_bin_count_or_index( pRenderConfigReader, &pRenderConfigReader->pFG[n].nrBands ) ) != IVAS_ERR_OK ) + { + return error; + } + /* Allocate memory for the center frequency array */ + if ( ( pRenderConfigReader->pFG[n].pFc = (float *) malloc( pRenderConfigReader->pFG[n].nrBands * sizeof( float ) ) ) == NULL ) + { + return IVAS_ERR_FAILED_ALLOC; + } + /* Read the individual frequencies */ + for ( m = 0; m < pRenderConfigReader->pFG[n].nrBands; m++ ) + { + if ( ( error = get_bin_frequency( pRenderConfigReader, &pRenderConfigReader->pFG[n].pFc[m] ) ) != IVAS_ERR_OK ) + { + return error; + } + } + break; + case FREQ_GRID_MODE_START_HOP_AMOUNT: + if ( ( error = get_bin_count_or_index( pRenderConfigReader, &pRenderConfigReader->pFG[n].nrBands ) ) != IVAS_ERR_OK ) + { + return error; + } + /* Allocate memory for the center frequency array */ + if ( ( pRenderConfigReader->pFG[n].pFc = (float *) malloc( pRenderConfigReader->pFG[n].nrBands * sizeof( float ) ) ) == NULL ) + { + return IVAS_ERR_FAILED_ALLOC; + } + /* Read the first frequency */ + if ( ( error = get_bin_frequency( pRenderConfigReader, &pRenderConfigReader->pFG[n].pFc[0] ) ) != IVAS_ERR_OK ) + { + return error; + } + /* Read frequency hop from LUT */ + if ( ( error = read_bin_code_word( pRenderConfigReader, RC_LUT_FREQ_HOP, &freqHop ) ) != IVAS_ERR_OK ) + { + return error; + } + /* Fill up the center frequency array */ + for ( m = 1; m < pRenderConfigReader->pFG[n].nrBands; m++ ) + { + pRenderConfigReader->pFG[n].pFc[m] = pRenderConfigReader->pFG[n].pFc[m - 1] * freqHop; + } + break; + case FREQ_GRID_MODE_DEFAULT_BANDING: + /* Read the default grid ID */ + value = 0; + if ( ( error = read_bin_bits( pRenderConfigReader, &value, 4 ) ) != IVAS_ERR_OK ) + { + return error; + } + switch ( value ) + { + case 0: + gridLen = sizeof( defaultFrequencyGrid_0 ) / sizeof( defaultFrequencyGrid_0[0] ); + pGrid = defaultFrequencyGrid_0; + break; + case 1: + gridLen = sizeof( defaultFrequencyGrid_1 ) / sizeof( defaultFrequencyGrid_1[0] ); + pGrid = defaultFrequencyGrid_1; + break; + case 2: + gridLen = sizeof( defaultFrequencyGrid_2 ) / sizeof( defaultFrequencyGrid_2[0] ); + pGrid = defaultFrequencyGrid_2; + break; + case 3: + gridLen = sizeof( defaultFrequencyGrid_3 ) / sizeof( defaultFrequencyGrid_3[0] ); + pGrid = defaultFrequencyGrid_3; + break; + case 4: + gridLen = sizeof( defaultFrequencyGrid_4 ) / sizeof( defaultFrequencyGrid_4[0] ); + pGrid = defaultFrequencyGrid_4; + break; + case 5: + gridLen = sizeof( defaultFrequencyGrid_5 ) / sizeof( defaultFrequencyGrid_5[0] ); + pGrid = defaultFrequencyGrid_5; + break; + case 6: + gridLen = sizeof( defaultFrequencyGrid_6 ) / sizeof( defaultFrequencyGrid_6[0] ); + pGrid = defaultFrequencyGrid_6; + break; + case 7: + gridLen = sizeof( defaultFrequencyGrid_7 ) / sizeof( defaultFrequencyGrid_7[0] ); + pGrid = defaultFrequencyGrid_7; + break; + case 8: + gridLen = sizeof( defaultFrequencyGrid_8 ) / sizeof( defaultFrequencyGrid_8[0] ); + pGrid = defaultFrequencyGrid_8; + break; + default: + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + + m = 0; + /* Read sub-grid flag */ + if ( ( error = read_bin_bool( pRenderConfigReader, &value ) ) != IVAS_ERR_OK ) + { + return error; + } + if ( value != false ) + { + /* Read the sub-grid offset */ + if ( ( error = read_bin_bits( pRenderConfigReader, &m, 3 ) ) != IVAS_ERR_OK ) + { + return error; + } + + /* Read the sub-grid length */ + subGridLen = 0; + if ( ( error = read_bin_bits( pRenderConfigReader, &subGridLen, 6 ) ) != IVAS_ERR_OK ) + { + return error; + } + if ( m + subGridLen > gridLen ) + { + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + gridLen = subGridLen; + } + pRenderConfigReader->pFG[n].nrBands = gridLen; + /* Allocate memory for the center frequency array */ + if ( ( pRenderConfigReader->pFG[n].pFc = (float *) malloc( gridLen * sizeof( float ) ) ) == NULL ) + { + return IVAS_ERR_FAILED_ALLOC; + } + + /* Copy the ROM content to the frequency grid*/ + for ( i = 0; i < gridLen; i++ ) + { + pRenderConfigReader->pFG[n].pFc[i] = pGrid[m + i]; + } + + break; + default: + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + /* Initialize memory pointers to allow safe freeing ico errors */ + pRenderConfigReader->pFG[n].pFc = NULL; + } + + /**********************************/ + /* Read the acoustic environments */ + /**********************************/ + + /* Number of acoustic environments */ + if ( ( error = get_bin_count_or_index( pRenderConfigReader, &nAE ) ) != IVAS_ERR_OK ) + { + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + + /* Allocate memory for the acoustic environments array */ + if ( nAE > 0 ) + { + if ( pRenderConfigReader->nAE > 0 ) + { + for ( n = 0; n < pRenderConfigReader->nAE; n++ ) + { + free( pRenderConfigReader->pAE[n].pRT60 ); + free( pRenderConfigReader->pAE[n].pDSR ); +#ifdef EARLY_REFLECTIONS + if ( pRenderConfigReader->pAE[n].pEarlyReflections != NULL ) + { + free( pRenderConfigReader->pAE[n].pEarlyReflections->pListenerOrigin ); + free( pRenderConfigReader->pAE[n].pEarlyReflections ); + } +#endif + } + free( pRenderConfigReader->pAE ); + } + pRenderConfigReader->nAE = nAE; + + if ( ( pRenderConfigReader->pAE = (AcousticEnv *) malloc( pRenderConfigReader->nAE * sizeof( AcousticEnv ) ) ) == NULL ) + { + return IVAS_ERR_FAILED_ALLOC; + } + /* Initialize memory pointers to allow safe freeing ico errors */ + for ( n = 0; n < nAE; n++ ) + { + pRenderConfigReader->pAE[n].pRT60 = NULL; + pRenderConfigReader->pAE[n].pDSR = NULL; +#ifdef EARLY_REFLECTIONS + pRenderConfigReader->pAE[n].pEarlyReflections = NULL; +#endif + } + } + + /* Loop through the acoustic environments from the binary stream */ + for ( n = 0; n < nAE; n++ ) + { + /* Read the AE ID */ + if ( ( error = get_bin_id( pRenderConfigReader, &pRenderConfigReader->pAE[n].id ) ) != IVAS_ERR_OK ) + { + return error; + } + + /* Read the frequency grid ID */ + if ( ( error = get_bin_count_or_index( pRenderConfigReader, &value ) ) != IVAS_ERR_OK ) + { + return error; + } + + /* Associate the frequency grid */ + if ( value >= pRenderConfigReader->nFG ) + { + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + + pRenderConfigReader->pAE[n].pFG = &( pRenderConfigReader->pFG[value] ); + + /* Allocate memory for RT60 and DSR arrays */ + if ( ( pRenderConfigReader->pAE[n].pRT60 = (float *) malloc( pRenderConfigReader->pAE[n].pFG->nrBands * sizeof( float ) ) ) == NULL ) + { + return IVAS_ERR_FAILED_ALLOC; + } + + if ( ( pRenderConfigReader->pAE[n].pDSR = (float *) malloc( pRenderConfigReader->pAE[n].pFG->nrBands * sizeof( float ) ) ) == NULL ) + { + return IVAS_ERR_FAILED_ALLOC; + } + + /* Read the values */ + if ( ( error = get_bin_duration( pRenderConfigReader, &pRenderConfigReader->pAE[n].preDelay ) ) != IVAS_ERR_OK ) + { + return error; + } + + for ( m = 0; m < pRenderConfigReader->pAE[n].pFG->nrBands; m++ ) + { + if ( ( error = get_bin_duration( pRenderConfigReader, &pRenderConfigReader->pAE[n].pRT60[m] ) ) != IVAS_ERR_OK ) + { + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + } + for ( m = 0; m < pRenderConfigReader->pAE[n].pFG->nrBands; m++ ) + { + if ( ( error = get_bin_dsr( pRenderConfigReader, &pRenderConfigReader->pAE[n].pDSR[m] ) ) != IVAS_ERR_OK ) + { + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + } + +#ifdef EARLY_REFLECTIONS + /* Has early reflections */ + if ( ( error = read_bin_bool( pRenderConfigReader, &value ) ) != IVAS_ERR_OK ) + { + return error; + } + if ( value == true ) + { + if ( ( pRenderConfigReader->pAE[n].pEarlyReflections = (EarlyReflectionsConfig *) malloc( sizeof( EarlyReflectionsConfig ) ) ) == NULL ) + { + return IVAS_ERR_FAILED_ALLOC; + } + /* Initialize memory pointers to allow safe freeing ico eg errors */ + pRenderConfigReader->pAE[n].pEarlyReflections->pListenerOrigin = NULL; + + /* Room sizes */ + if ( ( error = get_bin_distance( pRenderConfigReader, true, &pRenderConfigReader->pAE[n].pEarlyReflections->dimensions.x ) ) != IVAS_ERR_OK ) + { + return error; + } + if ( ( error = get_bin_distance( pRenderConfigReader, true, &pRenderConfigReader->pAE[n].pEarlyReflections->dimensions.y ) ) != IVAS_ERR_OK ) + { + return error; + } + if ( ( error = get_bin_distance( pRenderConfigReader, true, &pRenderConfigReader->pAE[n].pEarlyReflections->dimensions.z ) ) != IVAS_ERR_OK ) + { + return error; + } + + for ( k = 0; k < N_ABS_COEFFS; k++ ) + { + if ( ( error = get_bin_absorption( pRenderConfigReader, &pRenderConfigReader->pAE[n].pEarlyReflections->pAbsCoeff[k] ) ) != IVAS_ERR_OK ) + { + return error; + } + } + + /* Has listener origin */ + if ( ( error = read_bin_bool( pRenderConfigReader, &value ) ) != IVAS_ERR_OK ) + { + return error; + } + + if ( value == true ) + { + if ( ( pRenderConfigReader->pAE[n].pEarlyReflections->pListenerOrigin = malloc( sizeof( IVAS_VECTOR3 ) ) ) == NULL ) + { + return IVAS_ERR_FAILED_ALLOC; + } + + if ( ( error = read_bin_bits( pRenderConfigReader, &signx, 1 ) ) != IVAS_ERR_OK ) + { + return error; + } + if ( ( error = read_bin_bits( pRenderConfigReader, &signy, 1 ) ) != IVAS_ERR_OK ) + { + return error; + } + if ( ( error = get_bin_distance( pRenderConfigReader, true, &pRenderConfigReader->pAE[n].pEarlyReflections->pListenerOrigin->x ) ) != IVAS_ERR_OK ) + { + return error; + } + if ( signx == 0 ) + { + pRenderConfigReader->pAE[n].pEarlyReflections->pListenerOrigin->x *= -1.0f; + } + if ( ( error = get_bin_distance( pRenderConfigReader, true, &pRenderConfigReader->pAE[n].pEarlyReflections->pListenerOrigin->y ) ) != IVAS_ERR_OK ) + { + return error; + } + if ( signy == 0 ) + { + pRenderConfigReader->pAE[n].pEarlyReflections->pListenerOrigin->y *= -1.0f; + } + if ( ( error = get_bin_distance( pRenderConfigReader, true, &pRenderConfigReader->pAE[n].pEarlyReflections->pListenerOrigin->z ) ) != IVAS_ERR_OK ) + { + return error; + } + } + + /* Low complexity mode */ + if ( ( error = read_bin_bool( pRenderConfigReader, &pRenderConfigReader->pAE[n].pEarlyReflections->lowComplexity ) ) != IVAS_ERR_OK ) + { + return error; + } + } +#endif + } +#ifdef CONTROL_METADATA_DIRECTIVITY + } + /**********************************/ + /* Read the directivity patterns */ + /**********************************/ + + /* Has source directivity */ + if ( ( error = read_bin_bool( pRenderConfigReader, &value ) ) != IVAS_ERR_OK ) + { + return error; + } + if ( value == true ) + { + + /* Number of directivity patterns */ + if ( ( error = get_bin_id( pRenderConfigReader, &nDP ) ) != IVAS_ERR_OK ) + { + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + + if ( nDP > 0 ) + { + if ( pRenderConfigReader->nDP > 0 ) + { + for ( n = 0; n < pRenderConfigReader->nDP; n++ ) + { + free( pRenderConfigReader->pDP[n].pDirectivity ); + } + free( pRenderConfigReader->pDP ); + } + + pRenderConfigReader->nDP = nDP; + + if ( ( pRenderConfigReader->pDP = (DirectrivityPat *) malloc( pRenderConfigReader->nDP * sizeof( DirectrivityPat ) ) ) == NULL ) + { + return IVAS_ERR_FAILED_ALLOC; + } + + for ( n = 0; n < nDP; n++ ) + { + /* Allocate memory for directivity arrays*/ + if ( ( pRenderConfigReader->pDP[n].pDirectivity = (float *) malloc( 3 * sizeof( float ) ) ) == NULL ) + { + return IVAS_ERR_FAILED_ALLOC; + } + } + } + /* Loop through the directivity patterns from the binary stream */ + for ( n = 0; n < nDP; n++ ) + { + + /* Read the Directivity ID */ + if ( ( error = get_bin_id( pRenderConfigReader, &pRenderConfigReader->pDP[n].id ) ) != IVAS_ERR_OK ) + { + return error; + } + if ( ( error = get_bin_angle( pRenderConfigReader, &pRenderConfigReader->pDP[n].pDirectivity[0] ) ) != IVAS_ERR_OK ) + { + return error; + } + if ( ( error = get_bin_angle( pRenderConfigReader, &pRenderConfigReader->pDP[n].pDirectivity[1] ) ) != IVAS_ERR_OK ) + { + return error; + } + if ( ( error = get_bin_outer_attenuation( pRenderConfigReader, &pRenderConfigReader->pDP[n].pDirectivity[2] ) ) != IVAS_ERR_OK ) + { + return error; + } + } + } +#endif + + /* Cleanup */ + free( pRenderConfigReader->pBitstream ); + + return IVAS_ERR_OK; +} + +#endif + +ivas_error RenderConfigReader_read( +#ifdef CONTROL_METADATA_REVERB + RenderConfigReader *pRenderConfigReader, /* i : RenderConfigReader handle */ + const char *pRenderConfigPath, /* i : Renderer configuration file path */ + IVAS_RENDER_CONFIG_HANDLE hRenderConfig /* o : Renderer configuration handle */ +#else + RenderConfigReader *pRenderConfigReader, /* i : RenderConfigReader handle */ + IVAS_RENDER_CONFIG_HANDLE hRenderConfig /* o : Renderer configuration handle */ +#endif +) +{ + 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; +#ifdef CONTROL_METADATA_REVERB + ivas_error error; + int32_t params_length; + int32_t length; + uint32_t i, idx; + uint32_t nFG, nAE; + char *pToken; + FREQ_GRID_MODE fgMode; + float freqHop; + uint32_t acIdx; + uint32_t defGridId, defGridLen, defGridOffset, defGridNrBands; + const float *pDefGrid; + float erTemp[N_ABS_COEFFS]; + uint32_t roomAcHasFgCount, roomAcHasAcEnvCount; + uint32_t fgHasMethod, fgHasNBands, fgHasFreqs, fgHasDefaultGrid, fgHasStartFreq, fgHasFreqHop; + uint32_t aeHasFgIdx, aeHasPredelay, aeHasRt60, aeHasDsr; +#ifdef EARLY_REFLECTIONS + uint32_t aeHasERsize, aeHasERabs; +#endif +#else + int16_t nBandsInput; + int16_t nVectorsMissing; +#endif +#ifdef SPLIT_REND_WITH_HEAD_ROT + bool dofProvided = false; + bool poseCorrProvided = false; +#endif + +#ifdef CONTROL_METADATA_DIRECTIVITY + uint32_t nDP; + uint32_t accDPIdx; + accDPIdx = 0; +#endif + + fseek( pRenderConfigReader->pConfigFile, 0, SEEK_END ); + file_size = ftell( pRenderConfigReader->pConfigFile ); + rewind( pRenderConfigReader->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 ) ); +#ifdef CONTROL_METADATA_REVERB + acIdx = 0; + roomAcHasFgCount = roomAcHasAcEnvCount = FALSE; +#else + nBandsInput = hRenderConfig->room_acoustics.nBands; + nVectorsMissing = N_REVERB_VECTORS; +#endif + + /* read file line by line */ + while ( fgets( pConfig_str, file_size, pRenderConfigReader->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( pRenderConfigReader->pConfigFile ); + if ( fgets( pTemp, file_size, pRenderConfigReader->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( pRenderConfigReader->pConfigFile, read_idx, SEEK_SET ); + +#ifdef CONTROL_METADATA_REVERB + strip_spaces( pParams ); + strcpy( pTemp, pParams ); + to_upper( pParams ); +#else + strip_spaces_upper( pParams ); +#endif + to_upper( chapter ); + + /* interpret params */ +#ifdef CONTROL_METADATA_REVERB + pToken = strtok( chapter, ":" ); + if ( strcmp( chapter, "ROOMACOUSTICS" ) == 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, "FREQUENCYGRIDCOUNT" ) == 0 ) + { + /* Read the number of frequency grids */ + if ( !sscanf( pValue, "%u", &nFG ) ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + if ( nFG > 0 ) + { + for ( idx = 0; idx < pRenderConfigReader->nFG; idx++ ) + { + free( pRenderConfigReader->pFG[idx].pFc ); + } + free( pRenderConfigReader->pFG ); + + pRenderConfigReader->nFG = nFG; + + /* Allocate memory for the frequency grids */ + if ( ( pRenderConfigReader->pFG = (FrequencyGrid *) malloc( pRenderConfigReader->nFG * sizeof( FrequencyGrid ) ) ) == NULL ) + { + return IVAS_ERR_FAILED_ALLOC; + } + for ( idx = 0; idx < nFG; idx++ ) + { + pRenderConfigReader->pFG[idx].nrBands = 0; + pRenderConfigReader->pFG[idx].pFc = NULL; + } + } + roomAcHasFgCount = TRUE; + } + else if ( strcmp( item, "ACOUSTICENVIRONMENTCOUNT" ) == 0 ) + { + /* Read the number of acoustic environments */ + if ( !sscanf( pValue, "%u", &nAE ) ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + if ( nAE > 0 ) + { + for ( idx = 0; idx < pRenderConfigReader->nAE; idx++ ) + { + free( pRenderConfigReader->pAE[idx].pRT60 ); + free( pRenderConfigReader->pAE[idx].pDSR ); +#ifdef EARLY_REFLECTIONS + if ( pRenderConfigReader->pAE[idx].pEarlyReflections != NULL ) + { + free( pRenderConfigReader->pAE[idx].pEarlyReflections->pListenerOrigin ); + free( pRenderConfigReader->pAE[idx].pEarlyReflections ); + } +#endif + } + free( pRenderConfigReader->pAE ); + + pRenderConfigReader->nAE = nAE; + + /* Allocate memory for the acoustic environments array */ + if ( ( pRenderConfigReader->pAE = (AcousticEnv *) malloc( pRenderConfigReader->nAE * sizeof( AcousticEnv ) ) ) == NULL ) + { + return IVAS_ERR_FAILED_ALLOC; + } + /* Initialize memory pointers to allow for safe freeing */ + for ( acIdx = 0; acIdx < pRenderConfigReader->nAE; acIdx++ ) + { + pRenderConfigReader->pAE[acIdx].pRT60 = NULL; + pRenderConfigReader->pAE[acIdx].pDSR = NULL; +#ifdef EARLY_REFLECTIONS + pRenderConfigReader->pAE[acIdx].pEarlyReflections = NULL; +#endif + } + } + acIdx = 0; + roomAcHasAcEnvCount = TRUE; + } +#ifdef DEBUGGING + else + { + fprintf( stderr, "Rendering configuration: unsupported property %s\n", item ); + } +#endif + } +#ifdef DEBUGGING + if ( roomAcHasFgCount == FALSE ) + { + fprintf( stderr, "Renderer configuration: frequencyGridCount missing from 'roomAcoustics' chapter.\n\n" ); + } + if ( roomAcHasAcEnvCount == FALSE ) + { + fprintf( stderr, "Renderer configuration: acousticEnvironmentCount missing from 'roomAcoustics' chapter.\n\n" ); + } +#endif + if ( roomAcHasFgCount == FALSE || roomAcHasAcEnvCount == FALSE ) + { + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + free( pValue ); + } + else if ( strcmp( pToken, "FREQUENCYGRID" ) == 0 ) + { + if ( pRenderConfigReader->pFG == NULL ) + { + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + + idx = strtol( strtok( NULL, ":" ), NULL, 0 ); + if ( idx >= pRenderConfigReader->nFG ) + { +#ifdef DEBUGGING + fprintf( stderr, "Rendering configuration: frequency grid with index %d does not fit into the frequency grid array of %d elements.\n", idx, pRenderConfigReader->nFG ); +#endif + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + + fgHasMethod = fgHasNBands = fgHasFreqs = fgHasDefaultGrid = fgHasStartFreq = fgHasFreqHop = FALSE; + fgMode = FREQ_GRID_MODE_UNKNOWN; + 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, "METHOD" ) == 0 ) + { + if ( strcmp( pValue, "INDIVIDUALFREQUENCIES" ) == 0 ) + { + fgMode = FREQ_GRID_MODE_INDIVIDUAL_FREQUENCIES; + } + else if ( strcmp( pValue, "STARTHOPAMOUNT" ) == 0 ) + { + fgMode = FREQ_GRID_MODE_START_HOP_AMOUNT; + } + else if ( strcmp( pValue, "DEFAULTBANDING" ) == 0 ) + { + fgMode = FREQ_GRID_MODE_DEFAULT_BANDING; + } + fgHasMethod = TRUE; + } + /* Read number of bands for individual frequency, start-hop-amount mode */ + else if ( strcmp( item, "NRBANDS" ) == 0 ) + { + if ( fgMode != FREQ_GRID_MODE_INDIVIDUAL_FREQUENCIES && fgMode != FREQ_GRID_MODE_START_HOP_AMOUNT ) + { + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + if ( !sscanf( pValue, "%u", &pRenderConfigReader->pFG[idx].nrBands ) ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + /* Allocate memory for the center frequency array */ + if ( ( pRenderConfigReader->pFG[idx].pFc = (float *) malloc( pRenderConfigReader->pFG[idx].nrBands * sizeof( float ) ) ) == NULL ) + { + return IVAS_ERR_FAILED_ALLOC; + } + fgHasNBands = TRUE; + } + else if ( strcmp( item, "FREQUENCIES" ) == 0 ) + { + if ( fgMode != FREQ_GRID_MODE_INDIVIDUAL_FREQUENCIES || pRenderConfigReader->pFG[idx].nrBands == 0 || pRenderConfigReader->pFG[idx].pFc == NULL ) + { + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + /* Read the individual frequencies */ + if ( read_txt_vector( pValue, pRenderConfigReader->pFG[idx].nrBands, pRenderConfigReader->pFG[idx].pFc ) ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + fgHasFreqs = TRUE; + } + else if ( strcmp( item, "STARTFREQUENCY" ) == 0 ) + { + if ( fgMode != FREQ_GRID_MODE_START_HOP_AMOUNT || pRenderConfigReader->pFG[idx].nrBands == 0 || pRenderConfigReader->pFG[idx].pFc == NULL ) + { + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + if ( !sscanf( pValue, "%f", &pRenderConfigReader->pFG[idx].pFc[0] ) ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + fgHasStartFreq = TRUE; + } + else if ( strcmp( item, "FREQUENCYHOP" ) == 0 ) + { + if ( fgMode != FREQ_GRID_MODE_START_HOP_AMOUNT || pRenderConfigReader->pFG[idx].nrBands == 0 || pRenderConfigReader->pFG[idx].pFc == NULL || pRenderConfigReader->pFG[idx].pFc[0] == 0.0f ) + { + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + if ( !sscanf( pValue, "%f", &freqHop ) ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + /* Fill up the center frequency array */ + for ( i = 1; i < pRenderConfigReader->pFG[idx].nrBands; i++ ) + { + pRenderConfigReader->pFG[idx].pFc[i] = pRenderConfigReader->pFG[idx].pFc[i - 1] * freqHop; + } + fgHasFreqHop = TRUE; + } + /* Handle default grids, with optional sub-grids */ + else if ( strcmp( item, "DEFAULTGRID" ) == 0 ) + { + if ( !sscanf( pValue, "%u", &defGridId ) ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + + switch ( defGridId ) + { + case 0: + defGridLen = sizeof( defaultFrequencyGrid_0 ) / sizeof( defaultFrequencyGrid_0[0] ); + pDefGrid = defaultFrequencyGrid_0; + break; + case 1: + defGridLen = sizeof( defaultFrequencyGrid_1 ) / sizeof( defaultFrequencyGrid_1[0] ); + pDefGrid = defaultFrequencyGrid_1; + break; + case 2: + defGridLen = sizeof( defaultFrequencyGrid_2 ) / sizeof( defaultFrequencyGrid_2[0] ); + pDefGrid = defaultFrequencyGrid_2; + break; + case 3: + defGridLen = sizeof( defaultFrequencyGrid_3 ) / sizeof( defaultFrequencyGrid_3[0] ); + pDefGrid = defaultFrequencyGrid_3; + break; + case 4: + defGridLen = sizeof( defaultFrequencyGrid_4 ) / sizeof( defaultFrequencyGrid_4[0] ); + pDefGrid = defaultFrequencyGrid_4; + break; + case 5: + defGridLen = sizeof( defaultFrequencyGrid_5 ) / sizeof( defaultFrequencyGrid_5[0] ); + pDefGrid = defaultFrequencyGrid_5; + break; + case 6: + defGridLen = sizeof( defaultFrequencyGrid_6 ) / sizeof( defaultFrequencyGrid_6[0] ); + pDefGrid = defaultFrequencyGrid_6; + break; + case 7: + defGridLen = sizeof( defaultFrequencyGrid_7 ) / sizeof( defaultFrequencyGrid_7[0] ); + pDefGrid = defaultFrequencyGrid_7; + break; + case 8: + defGridLen = sizeof( defaultFrequencyGrid_8 ) / sizeof( defaultFrequencyGrid_8[0] ); + pDefGrid = defaultFrequencyGrid_8; + break; + default: + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + fgHasDefaultGrid = TRUE; + + /* Handle sub-grids */ + defGridOffset = 0; + defGridNrBands = defGridLen; + + while ( sscanf( pParams + params_idx, "%64[^=]=%[^;];", item, pValue ) == 2 ) + { + if ( strcmp( item, "DEFAULTGRIDOFFSET" ) == 0 ) + { + if ( !sscanf( pValue, "%u", &defGridOffset ) ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + } + else if ( strcmp( item, "DEFAULTGRIDNRBANDS" ) == 0 ) + { + if ( !sscanf( pValue, "%u", &defGridNrBands ) ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + } + else + { +#ifdef DEBUGGING + fprintf( stderr, "Rendering configuration: unsupported property %s\n", item ); +#endif + break; + } + params_idx += (int32_t) ( strlen( item ) + strlen( pValue ) + 2 ); + } + + if ( defGridOffset + defGridNrBands > defGridLen ) + { +#ifdef DEBUGGING + fprintf( stderr, "Rendering configuration: invalid default banding selection.\n\n" ); +#endif + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + pRenderConfigReader->pFG[idx].nrBands = defGridNrBands; + + /* Allocate memory for the center frequency array */ + if ( ( pRenderConfigReader->pFG[idx].pFc = (float *) malloc( defGridNrBands * sizeof( float ) ) ) == NULL ) + { + return IVAS_ERR_FAILED_ALLOC; + } + + /* Copy the ROM content to the frequency grid*/ + for ( i = 0; i < defGridNrBands; i++ ) + { + pRenderConfigReader->pFG[idx].pFc[i] = pDefGrid[defGridOffset + i]; + } + } +#ifdef DEBUGGING + else + { + fprintf( stderr, "Rendering configuration: unsupported configuration property %s\n", item ); + } +#endif + } + if ( fgHasMethod == FALSE || + ( fgMode == FREQ_GRID_MODE_INDIVIDUAL_FREQUENCIES && ( fgHasFreqs == FALSE || fgHasNBands == FALSE ) ) || + ( fgMode == FREQ_GRID_MODE_DEFAULT_BANDING && fgHasDefaultGrid == FALSE ) || + ( fgMode == FREQ_GRID_MODE_START_HOP_AMOUNT && ( fgHasStartFreq == FALSE || fgHasFreqHop == FALSE || fgHasNBands == FALSE ) ) ) + { +#ifdef DEBUGGING + fprintf( stderr, "Rendering configuration: inconsistent default frequency band configuration.\n\n" ); +#endif + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + free( pValue ); + } + /* Handle multiple acoustic environments */ + else if ( strcmp( pToken, "ACOUSTICENVIRONMENT" ) == 0 ) + { + if ( pRenderConfigReader->pAE == NULL || acIdx >= pRenderConfigReader->nAE ) + { + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + idx = strtol( strtok( NULL, ":" ), NULL, 0 ); + pRenderConfigReader->pAE->id = idx; + + aeHasFgIdx = aeHasPredelay = aeHasRt60 = aeHasDsr = FALSE; +#ifdef EARLY_REFLECTIONS + aeHasERsize = aeHasERabs = FALSE; +#endif + 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 + /* Frequency grid index */ + if ( strcmp( item, "FREQUENCYGRIDINDEX" ) == 0 ) + { + if ( !sscanf( pValue, "%u", &i ) ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + if ( i > pRenderConfigReader->nFG || &pRenderConfigReader->pFG[i] == NULL ) + { + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + pRenderConfigReader->pAE[acIdx].pFG = &pRenderConfigReader->pFG[i]; + + /* Allocate memory for RT60 and DSR arrays */ + if ( ( pRenderConfigReader->pAE[acIdx].pRT60 = (float *) malloc( pRenderConfigReader->pAE[acIdx].pFG->nrBands * sizeof( float ) ) ) == NULL ) + { + return IVAS_ERR_FAILED_ALLOC; + } + + if ( ( pRenderConfigReader->pAE[acIdx].pDSR = (float *) malloc( pRenderConfigReader->pAE[acIdx].pFG->nrBands * sizeof( float ) ) ) == NULL ) + { + return IVAS_ERR_FAILED_ALLOC; + } + aeHasFgIdx = TRUE; + } + + /* Acoustic pre-delay */ + else if ( strcmp( item, "ACOUSTICPREDELAY" ) == 0 ) + { + if ( !sscanf( pValue, "%f", &hRenderConfig->room_acoustics.acousticPreDelay ) ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + } + } + /* Pre-delay */ + else if ( strcmp( item, "PREDELAY" ) == 0 ) + { + if ( !sscanf( pValue, "%f", &pRenderConfigReader->pAE[acIdx].preDelay ) ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + aeHasPredelay = TRUE; + } + /* RT60 */ + else if ( strcmp( item, "RT60" ) == 0 ) + { + if ( read_txt_vector( pValue, pRenderConfigReader->pFG[idx].nrBands, pRenderConfigReader->pAE[acIdx].pRT60 ) ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + aeHasRt60 = TRUE; + } + /* DSR */ + else if ( strcmp( item, "DSR" ) == 0 ) + { + if ( read_txt_vector( pValue, pRenderConfigReader->pFG[idx].nrBands, pRenderConfigReader->pAE[acIdx].pDSR ) ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + aeHasDsr = TRUE; + } +#ifdef EARLY_REFLECTIONS + else if ( strcmp( item, "EARLYREFLECTIONSSIZE" ) == 0 ) + { + if ( pRenderConfigReader->pAE[acIdx].pEarlyReflections == NULL ) + { + if ( ( pRenderConfigReader->pAE[acIdx].pEarlyReflections = (EarlyReflectionsConfig *) malloc( sizeof( EarlyReflectionsConfig ) ) ) == NULL ) + { + return IVAS_ERR_FAILED_ALLOC; + } + pRenderConfigReader->pAE[acIdx].pEarlyReflections->pListenerOrigin = NULL; + pRenderConfigReader->pAE[acIdx].pEarlyReflections->lowComplexity = FALSE; + } + if ( strcmp( item, "EARLYREFLECTIONSSIZE" ) == 0 ) + { + if ( read_txt_vector( pValue, 3, erTemp ) ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + pRenderConfigReader->pAE[acIdx].pEarlyReflections->dimensions.x = erTemp[0]; + pRenderConfigReader->pAE[acIdx].pEarlyReflections->dimensions.y = erTemp[1]; + pRenderConfigReader->pAE[acIdx].pEarlyReflections->dimensions.z = erTemp[2]; + aeHasERsize = TRUE; + } + } + else if ( strcmp( item, "ABSORPTIONCOEFFS" ) == 0 ) + { + if ( pRenderConfigReader->pAE[acIdx].pEarlyReflections == NULL ) + { +#ifdef DEBUGGING + fprintf( stderr, "Rendering configuration: early reflections absorption coefficients specified without room size preceding.\n\n" ); #endif - - fseek( pRenderConfigReader->pConfigFile, 0, SEEK_END ); - file_size = ftell( pRenderConfigReader->pConfigFile ); - rewind( pRenderConfigReader->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 ) ); - nBandsInput = hRenderConfig->room_acoustics.nBands; - nVectorsMissing = N_REVERB_VECTORS; - - /* read file line by line */ - while ( fgets( pConfig_str, file_size, pRenderConfigReader->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( pRenderConfigReader->pConfigFile ); - if ( fgets( pTemp, file_size, pRenderConfigReader->pConfigFile ) == NULL ) + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + if ( read_txt_vector( pValue, N_ABS_COEFFS, erTemp ) ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + for ( i = 0; i < N_ABS_COEFFS; i++ ) + { + pRenderConfigReader->pAE[acIdx].pEarlyReflections->pAbsCoeff[i] = erTemp[i]; + } + aeHasERabs = TRUE; + } + else if ( strcmp( item, "LISTENERORIGIN" ) == 0 ) + { + if ( pRenderConfigReader->pAE[acIdx].pEarlyReflections == NULL ) + { +#ifdef DEBUGGING + fprintf( stderr, "Rendering configuration: early reflections listener origin specified without room size preceding.\n\n" ); +#endif + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + if ( read_txt_vector( pValue, 3, erTemp ) ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + if ( ( pRenderConfigReader->pAE[acIdx].pEarlyReflections->pListenerOrigin = malloc( sizeof( IVAS_VECTOR3 ) ) ) == NULL ) + { + return IVAS_ERR_FAILED_ALLOC; + } + pRenderConfigReader->pAE[acIdx].pEarlyReflections->pListenerOrigin->x = erTemp[0]; + pRenderConfigReader->pAE[acIdx].pEarlyReflections->pListenerOrigin->y = erTemp[1]; + pRenderConfigReader->pAE[acIdx].pEarlyReflections->pListenerOrigin->z = erTemp[2]; + } + else if ( strcmp( item, "LOWCOMPLEXITY" ) == 0 ) + { + if ( pRenderConfigReader->pAE[acIdx].pEarlyReflections == NULL ) + { +#ifdef DEBUGGING + fprintf( stderr, "Rendering configuration: early reflections low complexity flag specified without room size preceding.\n\n" ); +#endif + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + if ( read_txt_bool( pValue, &pRenderConfigReader->pAE[acIdx].pEarlyReflections->lowComplexity ) ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + } +#endif +#ifdef DEBUGGING + else + { + fprintf( stderr, "Rendering configuration: unsupported configuration property %s\n", item ); + } +#endif + } +#ifdef DEBUGGING + if ( aeHasFgIdx == FALSE ) { - break; + fprintf( stderr, "Renderer configuration: frequencyGridIndex missing from 'acousticEnvironment' %d.\n\n", acIdx ); } - - if ( ( pTemp[0] != '#' ) && ( sscanf( pTemp, "[%64[^]]]", item ) != 1 ) ) + if ( aeHasPredelay == FALSE ) { - /* ignore inline comments */ - sscanf( pTemp, "%[^#]", pTemp ); - strcat( pParams, pTemp ); + fprintf( stderr, "Renderer configuration: predelay missing from 'acousticEnvironment' %d.\n\n", acIdx ); } - } while ( sscanf( pTemp, "[%64[^]]]", item ) != 1 ); - - /* go back one line */ - fseek( pRenderConfigReader->pConfigFile, read_idx, SEEK_SET ); - - strip_spaces_upper( pParams ); - to_upper( chapter ); + if ( aeHasRt60 == FALSE ) + { + fprintf( stderr, "Renderer configuration: RT60 missing from 'acousticEnvironment' %d.\n\n", acIdx ); + } + if ( aeHasDsr == FALSE ) + { + fprintf( stderr, "Renderer configuration: DSR missing from 'acousticEnvironment' %d.\n\n", acIdx ); + } +#ifdef EARLY_REFLECTIONS + if ( aeHasERsize == TRUE && aeHasERabs == FALSE ) + { + fprintf( stderr, "Renderer configuration: early reflections absorption coefficients missing from 'acousticEnvironment' %d.\n\n", acIdx ); + } +#endif +#endif + if ( aeHasFgIdx == FALSE || aeHasPredelay == FALSE || aeHasRt60 == FALSE || aeHasDsr == FALSE ) + { + return IVAS_ERR_INVALID_RENDER_CONFIG; + } +#ifdef EARLY_REFLECTIONS + if ( aeHasERsize == TRUE && aeHasERabs == FALSE ) + { + return IVAS_ERR_INVALID_RENDER_CONFIG; + } +#endif - /* interpret params */ + free( pValue ); + acIdx++; + } +#else if ( strcmp( chapter, "ROOMACOUSTICS" ) == 0 ) { params_idx = 0; @@ -493,6 +2636,7 @@ ivas_error RenderConfigReader_read( fprintf( stderr, "Reverb config: number of bands changed but configuration vectors missing\n" ); } } +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT else if ( strcmp( chapter, "SPLITREND" ) == 0 && strlen( pParams ) != 0 ) { @@ -604,17 +2748,142 @@ ivas_error RenderConfigReader_read( } free( pValue ); } -#endif /* SPLIT_REND_WITH_HEAD_ROT */ +#endif + +#ifdef CONTROL_METADATA_DIRECTIVITY + else if ( strcmp( chapter, "DIRECTIVITYSETTING" ) == 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, "DIRECTIVITYCOUNT" ) == 0 ) + { + /* Read the number of directivity chapters */ + if ( !sscanf( pValue, "%u", &nDP ) ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + if ( nDP > 0 ) + { + for ( idx = 0; idx < pRenderConfigReader->nDP; idx++ ) + { + free( pRenderConfigReader->pDP[idx].pDirectivity ); + } + + free( pRenderConfigReader->pDP ); + pRenderConfigReader->nDP = nDP; + + /* Allocate memory for the directivity pattern*/ + if ( ( pRenderConfigReader->pDP = (DirectrivityPat *) malloc( pRenderConfigReader->nDP * sizeof( DirectrivityPat ) ) ) == NULL ) + { + return IVAS_ERR_FAILED_ALLOC; + } + + for ( idx = 0; idx < nDP; idx++ ) + { + pRenderConfigReader->pDP[idx].pDirectivity = NULL; + } + } + accDPIdx = 0; + } + } + free( pValue ); + } + else if ( strcmp( pToken, "DIRECTIVITYPATTERN" ) == 0 ) + { + if ( pRenderConfigReader->pDP == NULL || accDPIdx >= pRenderConfigReader->nDP ) + { + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + idx = strtol( strtok( NULL, ":" ), NULL, 0 ); + pRenderConfigReader->pDP->id = idx; + + 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 + /* Allocate memory for directivity arrays*/ + if ( ( pRenderConfigReader->pDP[accDPIdx].pDirectivity = (float *) malloc( 3 * sizeof( float ) ) ) == NULL ) + { + return IVAS_ERR_FAILED_ALLOC; + } + if ( strcmp( item, "DIRECTIVITY" ) == 0 ) + { + if ( read_txt_vector( pValue, 3, pRenderConfigReader->pDP[accDPIdx].pDirectivity ) ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + } + } + free( pValue ); + accDPIdx++; + } +#endif +#if ( defined DEBUGGING ) || ( defined CONTROL_METADATA_REVERB ) else if ( strcmp( chapter, "GENERAL" ) == 0 && strlen( pParams ) != 0 ) +#else + if ( strcmp( chapter, "GENERAL" ) == 0 && strlen( pParams ) != 0 ) +#endif { params_idx = 0; pValue = (char *) calloc( strlen( pParams ), sizeof( char ) ); while ( sscanf( pParams + params_idx, "%64[^=]=%[^;];", item, pValue ) == 2 ) { +#ifdef CONTROL_METADATA_REVERB + params_length = (int32_t) ( strlen( item ) + strlen( pValue ) + 2 ); +#else params_idx += (int32_t) ( strlen( item ) + strlen( pValue ) + 2 ); +#endif +#ifdef DEBUGGING fprintf( stderr, " PARAM: %s -> %s\n", item, pValue ); - if ( strcmp( item, "RENDERER" ) == 0 ) +#endif +#ifdef CONTROL_METADATA_REVERB + if ( strcmp( item, "BINARYCONFIG" ) == 0 ) + { + /* get correct case reverb configuration file path */ + sscanf( pTemp + params_idx, "%*[^=] = %[^;];", pValue ); + + /* make reverb configuration file path relative to render configuration file path */ + for ( length = (int32_t) strlen( pRenderConfigPath ) - 1; length >= 0; length-- ) + { + if ( pRenderConfigPath[length] == '\\' || pRenderConfigPath[length] == '/' ) + { + length++; + break; + } + } + if ( length < 0 ) + { + /* no slash found */ + length = 0; + } + char *pCombinedName = calloc( length + (int32_t) strlen( pValue ) + 1, sizeof( char ) ); + strncpy( pCombinedName, pRenderConfigPath, length ); + strcpy( pCombinedName + length, pValue ); + + if ( ( error = RenderConfigReader_readBinary( pCombinedName, pRenderConfigReader ) ) != IVAS_ERR_OK ) + { + errorHandler( item, ERROR_VALUE_INVALID ); + return IVAS_ERR_INVALID_RENDER_CONFIG; + } + free( pCombinedName ); + } + else +#endif +#ifdef DEBUGGING + if ( strcmp( item, "RENDERER" ) == 0 ) { if ( strcmp( pValue, "CREND" ) == 0 ) { @@ -627,11 +2896,20 @@ ivas_error RenderConfigReader_read( else { errorHandler( pValue, ERROR_VALUE_INVALID ); +#ifdef CONTROL_METADATA_REVERB + return IVAS_ERR_INVALID_RENDER_CONFIG; +#endif } } - else if ( strcmp( item, "DIRECTIVITY" ) == 0 ) + else +#endif + if ( strcmp( item, "DIRECTIVITY" ) == 0 ) { +#ifdef CONTROL_METADATA_REVERB + if ( read_txt_vector( pValue, 3, hRenderConfig->directivity ) ) +#else if ( read_vector( pValue, 3, hRenderConfig->directivity ) ) +#endif { errorHandler( item, ERROR_VALUE_INVALID ); } @@ -641,11 +2919,13 @@ ivas_error RenderConfigReader_read( { fprintf( stderr, "Unsupported configuration property %s\n", item ); } +#endif +#ifdef CONTROL_METADATA_REVERB + params_idx += params_length; #endif } free( pValue ); } -#endif else { fprintf( stderr, "Unknown chapter: %s\n", chapter ); @@ -672,10 +2952,108 @@ ivas_error RenderConfigReader_read( fprintf( stderr, "Errors occurred\n" ); return IVAS_ERR_FAILED_FILE_PARSE; } - +#ifdef CONTROL_METADATA_REVERB + return IVAS_ERR_OK; +#else return RenderConfigReader_checkValues( hRenderConfig ); +#endif } +#ifdef CONTROL_METADATA_REVERB +/*------------------------------------------------------------------------------------------* + * RenderConfigReader_getEnvironment() + * + * Gets Acoustic environment with a given ID + *------------------------------------------------------------------------------------------*/ + +ivas_error RenderConfigReader_getAcousticEnvironment( + RenderConfigReader *pRenderConfigReader, /* i : RenderConfigReader handle */ + uint16_t id, /* i : Acoustic environment ID */ + IVAS_ROOM_ACOUSTICS_CONFIG_DATA *pAcEnv /* o : Target acoustic environment pointer */ +) +{ + uint16_t n, m; + + if ( pRenderConfigReader == NULL || pAcEnv == NULL ) + { + return IVAS_ERR_UNEXPECTED_NULL_POINTER; + } + + for ( n = 0; n < pRenderConfigReader->nAE; n++ ) + { + if ( id == pRenderConfigReader->pAE[n].id ) + { + pAcEnv->nBands = (int16_t) pRenderConfigReader->pAE[n].pFG->nrBands; + pAcEnv->inputPreDelay = pRenderConfigReader->pAE[n].preDelay; + + for ( m = 0; m < pAcEnv->nBands; m++ ) + { + pAcEnv->pFc_input[m] = pRenderConfigReader->pAE[n].pFG->pFc[m]; + pAcEnv->pAcoustic_rt60[m] = pRenderConfigReader->pAE[n].pRT60[m]; + pAcEnv->pAcoustic_dsr[m] = pRenderConfigReader->pAE[n].pDSR[m]; + } + return IVAS_ERR_OK; + } + } + return IVAS_ERR_ACOUSTIC_ENVIRONMENT_MISSING; +} + +#endif + +#ifdef CONTROL_METADATA_DIRECTIVITY +/*------------------------------------------------------------------------------------------* + * RenderConfigReader_getDirectivity() + * + * Gets Directivity DirectrivityPatern with a given ID + *------------------------------------------------------------------------------------------*/ + +ivas_error RenderConfigReader_getDirectivity( + RenderConfigReader *pRenderConfigReader, /* i : RenderConfigReader handle */ + uint16_t *id, /* i : Directivity pattern ID */ + float *directivity /* o : Target directivity */ +) +{ + uint16_t n, m; + bool idExists; + + + if ( pRenderConfigReader == NULL ) + { + return IVAS_ERR_UNEXPECTED_NULL_POINTER; + } + if ( pRenderConfigReader->pDP == NULL ) + { + for ( n = 0; n < MAX_NUM_OBJECTS; n++ ) + { + directivity[n * 3] = 360.0f; + directivity[n * 3 + 1] = 360.0f; + directivity[n * 3 + 2] = 1.0f; + } + } + else + { + for ( n = 0; n < MAX_NUM_OBJECTS; n++ ) + { + idExists = false; + for ( m = 0; m < pRenderConfigReader->nDP; m++ ) + { + if ( id[n] == pRenderConfigReader->pDP[m].id ) + { + idExists = true; + mvr2r( pRenderConfigReader->pDP[id[n]].pDirectivity, directivity + ( n * 3 ), 3 ); + break; + } + } + if ( !idExists ) + { + return IVAS_ERR_DIRECTIVITY_PATTERN_ID_MISSING; + } + } + } + return IVAS_ERR_OK; +} + +#endif /*------------------------------------------------------------------------------------------* * RenderConfigReader_close() @@ -687,11 +3065,46 @@ void RenderConfigReader_close( RenderConfigReader **ppRenderConfigReader /* i : RenderConfigReader handle */ ) { +#ifdef CONTROL_METADATA_REVERB + uint32_t n; +#endif + if ( ppRenderConfigReader == NULL || *ppRenderConfigReader == NULL ) { return; } +#ifdef CONTROL_METADATA_REVERB + /* Free the acoustic environments */ + for ( n = 0; n < ( *ppRenderConfigReader )->nAE; n++ ) + { +#ifdef EARLY_REFLECTIONS + if ( ( *ppRenderConfigReader )->pAE[n].pEarlyReflections != NULL ) + { + free( ( *ppRenderConfigReader )->pAE[n].pEarlyReflections->pListenerOrigin ); + free( ( *ppRenderConfigReader )->pAE[n].pEarlyReflections ); + } +#endif + free( ( *ppRenderConfigReader )->pAE[n].pRT60 ); + free( ( *ppRenderConfigReader )->pAE[n].pDSR ); + } + free( ( *ppRenderConfigReader )->pAE ); + + /* Free the frequency grids */ + for ( n = 0; n < ( *ppRenderConfigReader )->nFG; n++ ) + { + free( ( *ppRenderConfigReader )->pFG[n].pFc ); + } + free( ( *ppRenderConfigReader )->pFG ); +#endif +#ifdef CONTROL_METADATA_DIRECTIVITY + /* Free the directivity patterns */ + for ( n = 0; n < ( *ppRenderConfigReader )->nDP; n++ ) + { + free( ( *ppRenderConfigReader )->pDP[n].pDirectivity ); + } + free( ( *ppRenderConfigReader )->pDP ); +#endif fclose( ( *ppRenderConfigReader )->pConfigFile ); free( *ppRenderConfigReader ); diff --git a/lib_util/render_config_reader.h b/lib_util/render_config_reader.h index c2afb92e8bb11cd1b8706fbb573961dd69a1b36c..f9491a0488124d6f87eed4c501ef5bc5dd6f5f50 100644 --- a/lib_util/render_config_reader.h +++ b/lib_util/render_config_reader.h @@ -51,10 +51,39 @@ ivas_error RenderConfigReader_open( RenderConfigReader **ppRenderConfigReader /* o : RenderConfigReader handle */ ); +#ifdef CONTROL_METADATA_REVERB +/* Get an acoustic environment */ +ivas_error RenderConfigReader_getAcousticEnvironment( + RenderConfigReader *pRenderConfigReader, /* i : RenderConfigReader handle */ + uint16_t id, /* i : Acoustic environment ID */ + IVAS_ROOM_ACOUSTICS_CONFIG_DATA *pAcEnv /* o : Target acoustic environment pointer */ +); +#ifdef CONTROL_METADATA_DIRECTIVITY +ivas_error RenderConfigReader_getDirectivity( + RenderConfigReader *pRenderConfigReader, /* i : RenderConfigReader handle */ + uint16_t *pId, /* i : Directivity pattern ID */ + float *directivity /* o : Target directivity */ +); +#endif +/* Verifies configuration parameters */ +ivas_error RenderConfigReader_checkValues( + IVAS_RENDER_CONFIG_HANDLE hRenderConfig /* o : Renderer configuration handle */ +); +#endif + /* Reads a configuration */ ivas_error RenderConfigReader_read( +#ifdef CONTROL_METADATA_REVERB + RenderConfigReader *pRenderConfigReader, /* i : RenderConfigReader handle */ + const char *pRenderConfigPath /* i : Renderer configuration file path */ +#if ( defined SPLIT_REND_WITH_HEAD_ROT ) || ( defined DEBUGGING ) + , + IVAS_RENDER_CONFIG_HANDLE hRenderConfig /* o : Renderer configuration handle */ +#endif +#else RenderConfigReader *pRenderConfigReader, /* i : RenderConfigReader handle */ IVAS_RENDER_CONFIG_HANDLE hRenderConfig /* o : Renderer configuration handle */ +#endif ); /* Closes the renderer configuration reader and deallocates memory */ diff --git a/scripts/reverb/acoustic_environment_hospital_patientroom.cfg b/scripts/reverb/acoustic_environment_hospital_patientroom.cfg new file mode 100644 index 0000000000000000000000000000000000000000..cc7747cd1baabb7ac5cd1877d5da22eb2b458b04 --- /dev/null +++ b/scripts/reverb/acoustic_environment_hospital_patientroom.cfg @@ -0,0 +1,32 @@ +[roomAcoustics] +frequencyGridCount = 1; +acousticEnvironmentCount = 1; + +[frequencyGrid:0] +method = individualFrequencies; +frequencies = [ + 20.0, 25.0, 31.5, 40.0, + 50.0, 63.0, 80.0, 100.0, + 125.0, 160.0, 200.0, 250.0, + 315.0, 400.0, 500.0, 630.0, + 800.0, 1000.0, 1250.0, 1600.0, + 2000.0, 2500.0, 3150.0, 4000.0, + 5000.0, 6300.0, 8000.0, 10000.0, + 12500.0, 16000.0, 20000.0]; + +[acousticEnvironment:0] +id = 0; +frequencyGridIndex = 0; +predelay = 0.08163; +rt60 = [ + 0.81275, 0.61888, 0.45111, 0.34672, 0.46683, 0.53987, 0.61874, 0.70291, 0.66657, 0.73037, + 0.75090, 0.72470, 0.75486, 0.75857, 0.76844, 0.74999, 0.77622, 0.78227, 0.77441, 0.74688, + 0.73521, 0.73782, 0.71928, 0.71708, 0.71465, 0.60592, 0.52031, 0.51768, 0.52102, 0.37956, + 0.30786]; + +dsr = [ + 0.00019952621, 0.00019952621, 7.9432844e-05, 5.0118702e-05, 7.943284e-06, 6.3095763e-06, 6.3095763e-06, 7.943284e-06, 1e-05, 1e-05, + 7.943284e-06, 1e-05, 1e-05, 1e-05, 7.943284e-06, 1e-05, 1e-05, 7.943284e-06, 7.943284e-06, 6.3095763e-06, + 6.3095763e-06, 6.3095763e-06, 6.3095763e-06, 6.3095763e-06, 6.3095763e-06, 3.1622776e-06, 3.1622776e-06, 3.1622776e-06, 6.3095763e-07, 3.1622776e-07, + 3.1622776e-07]; + diff --git a/scripts/reverb/acoustic_environment_recreation.cfg b/scripts/reverb/acoustic_environment_recreation.cfg new file mode 100644 index 0000000000000000000000000000000000000000..ec1ee14b7ac1953554724e1c10665c62de963645 --- /dev/null +++ b/scripts/reverb/acoustic_environment_recreation.cfg @@ -0,0 +1,32 @@ +[roomAcoustics] +frequencyGridCount = 1; +acousticEnvironmentCount = 1; + +[frequencyGrid:0] +nBands = 31; +method = individualFrequencies; +frequencies = [ + 20.0, 25.0, 31.5, 40.0, + 50.0, 63.0, 80.0, 100.0, + 125.0, 160.0, 200.0, 250.0, + 315.0, 400.0, 500.0, 630.0, + 800.0, 1000.0, 1250.0, 1600.0, + 2000.0, 2500.0, 3150.0, 4000.0, + 5000.0, 6300.0, 8000.0, 10000.0, + 12500.0, 16000.0, 20000.0]; + +[acousticEnvironment:0] +id = 0; +frequencyGridIndex = 0; +predelay = 0.43031; +rt60 = [ + 4.51916, 4.89553, 4.83276, 5.00198, 5.34468, 5.76026, 6.36818, 6.95503, 7.27557, 7.62559, + 8.08892, 8.16002, 8.13900, 8.17919, 8.16280, 8.46226, 9.61806, 9.93048, 9.81353, 8.59340, + 8.38885, 8.36823, 6.51845, 3.76089, 3.75374, 3.57451, 1.28724, 1.22174, 1.22448, 1.71631, + 2.14343]; + +dsr = [ + 1e-06, 7.943284e-07, 1e-06, 1e-06, 1.5848925e-06, 1.9952631e-06, 3.1622776e-06, 3.9810707e-06, 6.3095763e-06, 7.943284e-06, + 1e-05, 7.943284e-06, 7.943284e-06, 7.943284e-06, 7.943284e-06, 7.943284e-06, 5.01187e-06, 5.01187e-06, 3.9810707e-06, 3.1622776e-06, + 3.1622776e-06, 2.511887e-06, 7.943284e-07, 6.3095763e-07, 6.3095763e-07, 5.01187e-08, 1.2589251e-08, 1.2589251e-08, 1.2589265e-09, 1.2589266e-11, + 3.981075e-12]; diff --git a/scripts/reverb/acoustic_environment_renderer.cfg b/scripts/reverb/acoustic_environment_renderer.cfg new file mode 100644 index 0000000000000000000000000000000000000000..fffa8d0f2642ddb561d2d056040ecfa8718c27d7 --- /dev/null +++ b/scripts/reverb/acoustic_environment_renderer.cfg @@ -0,0 +1,37 @@ +[roomAcoustics] +frequencyGridCount = 1; +acousticEnvironmentCount = 1; + +[frequencyGrid:0] +method = individualFrequencies; +frequencies = [ + 20.0, 25.0, 31.5, 40.0, + 50.0, 63.0, 80.0, 100.0, + 125.0, 160.0, 200.0, 250.0, + 315.0, 400.0, 500.0, 630.0, + 800.0, 1000.0, 1250.0, 1600.0, + 2000.0, 2500.0, 3150.0, 4000.0, + 5000.0, 6300.0, 8000.0, 10000.0, + 12500.0, 16000.0, 20000.0]; + +[acousticEnvironment:0] +id = 0; +frequencyGridIndex = 0; +predelay = 0.1; +rt60 = [ + 1.3622, 1.4486, 1.3168, 1.5787, + 1.4766, 1.3954, 1.2889, 1.3462, + 1.0759, 1.0401, 1.0970, 1.0850, + 1.0910, 1.0404, 1.0499, 1.0699, + 1.1028, 1.1714, 1.1027, 1.0666, + 1.0550, 1.0553, 1.0521, 1.0569, + 1.0421, 0.97822, 0.80487, 0.75944, + 0.71945, 0.61682, 0.60031]; + +dsr = [ + 1.9952632e-08, 1.9952632e-08, 1.2589251e-08, 1.5848926e-08, 1.2589251e-08, 1.9952632e-08, 2.511887e-08, 3.9810708e-08, 1e-07, 1.9952633e-07, + 3.981071e-07, 6.3095763e-07, 7.943284e-07, 6.3095763e-07, 5.01187e-07, 5.01187e-07, 6.3095763e-07, 6.3095763e-07, 7.943284e-07, 6.3095763e-07, + 5.01187e-07, 6.3095763e-07, 6.3095763e-07, 6.3095763e-07, 5.01187e-07, 2.511887e-07, 1.2589251e-07, 1e-07, 6.309576e-08, 3.1622776e-08, + 2.511887e-08]; + + diff --git a/scripts/reverb/acoustic_environment_renderer_directivity.cfg b/scripts/reverb/acoustic_environment_renderer_directivity.cfg new file mode 100644 index 0000000000000000000000000000000000000000..1c9db1e9e4316d7bb46dca327a01370ef1716f74 --- /dev/null +++ b/scripts/reverb/acoustic_environment_renderer_directivity.cfg @@ -0,0 +1,41 @@ +[roomAcoustics] +frequencyGridCount = 1; +acousticEnvironmentCount = 1; + +[frequencyGrid:0] +method = individualFrequencies; +frequencies = [ + 20.0, 25.0, 31.5, 40.0, + 50.0, 63.0, 80.0, 100.0, + 125.0, 160.0, 200.0, 250.0, + 315.0, 400.0, 500.0, 630.0, + 800.0, 1000.0, 1250.0, 1600.0, + 2000.0, 2500.0, 3150.0, 4000.0, + 5000.0, 6300.0, 8000.0, 10000.0, + 12500.0, 16000.0, 20000.0]; + +[acousticEnvironment:0] +id = 0; +frequencyGridIndex = 0; +predelay = 0.1; +rt60 = [ + 1.3622, 1.4486, 1.3168, 1.5787, + 1.4766, 1.3954, 1.2889, 1.3462, + 1.0759, 1.0401, 1.0970, 1.0850, + 1.0910, 1.0404, 1.0499, 1.0699, + 1.1028, 1.1714, 1.1027, 1.0666, + 1.0550, 1.0553, 1.0521, 1.0569, + 1.0421, 0.97822, 0.80487, 0.75944, + 0.71945, 0.61682, 0.60031]; + +dsr = [ + 1.9952632e-08, 1.9952632e-08, 1.2589251e-08, 1.5848926e-08, 1.2589251e-08, 1.9952632e-08, 2.511887e-08, 3.9810708e-08, 1e-07, 1.9952633e-07, + 3.981071e-07, 6.3095763e-07, 7.943284e-07, 6.3095763e-07, 5.01187e-07, 5.01187e-07, 6.3095763e-07, 6.3095763e-07, 7.943284e-07, 6.3095763e-07, + 5.01187e-07, 6.3095763e-07, 6.3095763e-07, 6.3095763e-07, 5.01187e-07, 2.511887e-07, 1.2589251e-07, 1e-07, 6.309576e-08, 3.1622776e-08, + 2.511887e-08]; + +[directivitySetting] +directivityCount = 1; + +[directivityPattern:0] +directivity = [0.0, 360.0, 0.2512] diff --git a/scripts/reverb/generate_acoustic_environments_metadata.py b/scripts/reverb/generate_acoustic_environments_metadata.py new file mode 100644 index 0000000000000000000000000000000000000000..6c771319958276cadc67e132306689a87ddcf82e --- /dev/null +++ b/scripts/reverb/generate_acoustic_environments_metadata.py @@ -0,0 +1,736 @@ +#!/usr/bin/env python3 + +""" + (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 binary render configuration output files for testing purposes. +# The binary code generation is based on the MPEG-I audio standard, +# which defines functions to decode raw bitstream into internal parameters. +# + + +from bitarray import bitarray +import math +from enum import Enum +import numpy as np + + +# Set to True to print quantized values +print_quantized = False + + +max_quantization_error = { + 'duration' : 0, + 'frequency' : 0, + 'dsr' : 0, + 'distance' : 0, + 'absorption' : 0 +} + + +def update_quantization_error(name, quantized_value, value): + if value == 0: + if quantized_value != 0: + print(' {}: value = 0, quantized value = {}'.format(name, quantized_value)) + else: + max_quantization_error[name] = max(abs(quantized_value - value) / value, max_quantization_error[name]) + if print_quantized: + print(' {}: {}'.format(name, quantized_value)) + + +def get_id_code(id): + code = format(id % 128, '07b') + '0' + id //= 128 + while id > 0: + code = format(id % 128, '07b') + '1' + code + id = id // 128 + return code + + +def get_count_or_index_code(n): + # 0, 1, ... 63 + countOrIndexLoCodes = [ + '0111', '100', '01100', '01101', '01010', '01011', '01000', '01001', '001111', '001110', + '001101', '001100', '001011', '001010', '001001', '001000', '000111', '000110', '000101', '000100', + '000011', '000010', '000001', '000000', '111111', '111110', '111101', '111100', '111011', '111010', + '111001', '111000', '1101111', '1101110', '1101101', '1101100', '1101011', '1101010', '1101001', '1101000', + '1100111', '1100110', '1100101', '1100100', '1100011', '1100010', '1100001', '1100000', '1011111', '1011110', + '1011101', '1011100', '1011011', '1011010', '1011001', '1011000', '1010111', '1010110', '1010101', '1010100', + '1010011', '1010010', '1010001', '1010000'] + + # 1, 2, ... 15 + countOrIndexHiCode = [ + '001', '000', '110', '101', '100', '0111', '0101', '1111', '1110', '01101', + '01001', '01000', '011001', '0110001', '0110000'] + + assert 0 <= n < 16 * 64 + code = countOrIndexLoCodes[n % 64] + if n < 64: + code += '0' + else: + code += '1' + countOrIndexHiCode[n // 64 - 1] + return code + + +def get_duration_code(duration): + # 1, 2, ... 30 + secondsCode = [ + '0011', '0001', '0000', '1111', '1101', '1100', '1011', '1001', '1000', '01110', + '01101', '01100', '01011', '01001', '01000', '00101', '11101', '11100', '10101', '011111', + '011110', '010101', '001001', '001000', '101001', '0101001', '0101000', '1010001', '10100001', '10100000' ] + + # 0, 0.1, ... 1.0 + deciSecondsCode = [ + '110', '100', '101', '0110', '0111', '111', '0100', '0101', '0010', '0011', '000' ] + + # 0, 1, ..., 99 + millisecondsCode = [ + '1111010', '1111011', '1111000', '1111001', '1111110', '1111111', '1111100', '1111101', '1110010', '1110011', + '11001', '1110000', '1110001', '1110110', '1110111', '1110100', '1110101', '0101010', '0101011', '0101000', + '10010', '0101001', '0101110', '0101111', '0101100', '0101101', '0100010', '0100011', '0100000', '0100001', + '10011', '0100110', '0100111', '0100100', '0100101', '0111010', '0111011', '0111000', '0111001', '0111110', + '10000', '0111111', '0111100', '0111101', '0110010', '0110011', '0110000', '0110001', '0110110', '0110111', + '10001', '0110100', '0110101', '0001010', '0001011', '0001000', '0001001', '0001110', '0001111', '0001100', + '10110', '0001101', '0000010', '0000011', '0000000', '0000001', '0000110', '0000111', '0000100', '0000101', + '10111', '0011010', '0011011', '0011000', '0011001', '0011110', '0011111', '0011100', '0011101', '0010010', + '10100', '0010011', '0010000', '0010001', '0010110', '0010111', '0010100', '0010101', '1101010', '1101011', + '10101', '1101000', '1101001', '1101110', '1101111', '1101100', '1101101', '1100010', '1100011', '110000' ] + + # 10, 20, ... 990 + microsecondsCode = [ + '110111100', '10010', '110111101', '10011', '1101111110', '10000', '1101111111', '10001', '1101111100', '10110', + '1101111101', '10111', '110110010', '10100', '110110011', '10101', '110110000', '001010', '110110001', '001011', + '110110110', '001000', '110110111', '001001', '110110100', '001110', '110110101', '001111', '110011010', '001100', + '110011011', '001101', '110011000', '000010', '110011001', '000011', '110011110', '000000', '110011111', '000001', + '110011100', '000110', '110011101', '000111', '110010010', '000100', '110010011', '000101', '110010000', '011010', + '110010001', '011011', '110010110', '011000', '110010111', '011001', '110010100', '011110', '110010101', '011111', + '110101010', '011100', '110101011', '011101', '110101000', '010010', '110101001', '010011', '110101110', '010000', + '110101111', '010001', '110101100', '010110', '110101101', '010111', '110100010', '010100', '110100011', '010101', + '110100000', '111010', '110100001', '111011', '110100110', '111000', '110100111', '111001', '110100100', '111110', + '110100101', '111111', '110111010', '111100', '110111011', '111101', '110111000', '11000', '110111001' ] + + duration_dus = round(np.float32(duration) * np.float32(100000)) # [deca us] + + quantized_duration = round(np.float32(duration), 5) + update_quantization_error('duration', quantized_duration, duration) + + dus = duration_dus # [deca us] + s = dus // 100000 # 0, 1, ... 30 [s] + ms = (dus % 100000) // 100 # 0, 1, ... 999 [ms] + dus = (dus % 100) # 0, 1, ... 99 [deca us] + ds = ms // 100 # 0, 1, ... 9 [deci s] + ms = ms % 100 # 0, 1, ... 99 [ms] + if s >= 1 and ds == 0: + s -= 1 + ds = 10 # 0, 1, ... 10 [deci s] + + assert 0 <= s <= 30 + assert 0 <= ds <= 10 + assert 0 <= ms <= 99 + assert 0 <= dus <= 99 + assert duration_dus == s * 100000 + ds * 10000 + ms * 100 + dus + + code = deciSecondsCode[ds] + if ms > 0 or dus > 0: + code += '1' + millisecondsCode[ms] + if dus > 0: + code += '1' + microsecondsCode[dus - 1] + else: + code += '0' + else: + code += '0' + if s > 0: + # long range mode not implemented + code += '1' + secondsCode[s - 1] + else: + code += '0' + + return code + + +def get_frequency_code(frequency): + frequencyCode = { + 16.0 : '100011', 20.0 : '001110', 25.0 : '001111', 31.5 : '1001', 40.0 : '001100', + 50.0 : '001101', 63.0 : '0000', 80.0 : '011010', 100.0 : '011011', 125.0 : '0001', + 160.0 : '011000', 200.0 : '011001', 250.0 : '1110', 315.0 : '011110', 400.0 : '011111', + 500.0 : '1111', 630.0 : '011100', 800.0 : '011101', 1000.0 : '1100', 1250.0 : '010010', + 1600.0 : '010011', 2000.0 : '1101', 2500.0 : '010000', 3150.0 : '010001', 4000.0 : '1010', + 5000.0 : '010110', 6300.0 : '010111', 8000.0 : '1011', 10000.0: '010100', 12500.0: '010101', + 16000.0: '0010', 20000.0: '10000', 25000.0: '10001010', 31500.0: '10001011', 40000.0: '1000100', } + + assert 16 <= frequency <= 40000 + if frequency in frequencyCode.keys(): + quantized_frequency = frequency + code = frequencyCode[quantized_frequency] + '0' + else: + # exact frequency not found, use frequency refinement to approximate + f_low = max([k for k in frequencyCode.keys() if k < frequency]) + refinement = round(51 * math.log(frequency / f_low, 2)) - 1 + if 0 <= refinement <= 15: + quantized_frequency = f_low * 2 ** ((refinement + 1) / 51) + code = frequencyCode[f_low] + '1' + format(refinement, '04b') + else: + # choose next lower / higher frequency + f_high = min([k for k in frequencyCode.keys() if k > frequency]) + quantized_frequency = f_low if refinement < 0 else f_high + code = frequencyCode[quantized_frequency] + '0' + + update_quantization_error('frequency', quantized_frequency, frequency) + + return code + + +def get_frequency_hop_code(value): + index = -1 + tolerance = 1e-5 + hop_sizes = [2 ** (1/12), 2 ** (1/6), 2 ** (1/4), 2 ** (1/3), 2 ** (1/2), 2 ** (1), 2 ** (2)] + for idx, hop in enumerate(hop_sizes): + if math.isclose(value, hop, rel_tol = tolerance): + index = idx + break + assert 0 <= index <= 6 + return [ + '0010', # 2^(1/12) + '0011', # 2^(1/6) + '0000', # 2^(1/4) + '01', # 2^(1/3) + '0001', # 2^(1/2) + '11', # 2^1 + '10'][index] # 2^2 + + +def get_dsr_code(dsr): + # -150.0, -149.0, ... -10.0 + dsrCode = [ + '10001100', '10001101', '100011110', '100011111', '100011100', '100011101', '10000010', '10000011', '10000000', '10000001', + '10000110', '10000111', '10000100', '10000101', '011101010', '011101011', '011101000', '011101001', '011101110', '011101111', + '011101100', '011101101', '011100010', '011100011', '011100000', '011100001', '011100110', '011100111', '011100100', '011100101', + '011111010', '011111011', '011111000', '011111001', '011111110', '011111111', '011111100', '011111101', '011110010', '011110011', + '011110000', '011110001', '011110110', '011110111', '011110100', '011110101', '011001010', '011001011', '011001000', '011001001', + '011001110', '011001111', '011001100', '011001101', '011000010', '011000011', '011000000', '011000001', '011000110', '011000111', + '011000100', '011000101', '011011010', '011011011', '011011000', '011011001', '011011110', '011011111', '011011100', '011011101', + '010100', '010101', '100110', '100111', '100100', '100101', '111010', '111011', '111000', '111001', + '111110', '111111', '111100', '111101', '110010', '110011', '110000', '110001', '110110', '110111', + '110100', '110101', '001010', '001011', '001000', '001001', '001110', '001111', '001100', '001101', + '000010', '000011', '000000', '000001', '000110', '000111', '000100', '000101', '101010', '101011', + '101000', '101001', '101110', '101111', '101100', '101101', '010010', '010011', '010000', '010001', + '010110', '011010010', '011010011', '011010000', '011010001', '011010110', '011010111', '011010100', '011010101', '010111010', + '010111011', '010111000', '010111001', '010111110', '010111111', '010111100', '010111101', '10001010', '10001011', '10001000', + '10001001' ] + + d = math.log10(dsr) * 10 + d = round(d + 150) + assert 0 <= d <= 140 + + quantized_dsr = np.float32(np.power(np.float32(10), np.float32(d - 150) / np.float32(10))) # C decoder uses float precision math + update_quantization_error('dsr', quantized_dsr, dsr) + + return dsrCode[d] + +def usquant(x,qlow,delta,cbsize): + nbits = math.ceil(math.log2(cbsize)) # nextpow2 + index = max(0,min(cbsize-1, round( ( x - qlow ) / delta ))) + return format(index,'0'+ str(nbits) + 'b') + +def get_angle_code(angle): + assert 0 <= angle <= 360 + return usquant(angle, 0, 20, 19) + +def get_outer_attenuation_code(att): + assert 0 <= att <= 1 + return usquant(20 * math.log10(att), -90, 3, 31) + +class fgdMethod(Enum): + Individual_Frequencies = '00' + Start_Hop_Amount = '01' + Default_Banding = '10' + + +def get_default_grid_nr_bands(code): + assert 0 <= code <= 8 + return [10, 10, 31, 5, 6, 3, 41, 21, 25][code] + + +def get_distance_code(distance, isSmallScene): + # 0, 1, ... 99 + metersCode = [ + '111101', '110010', '110011', '110000', '110001', '110110', '110111', '110100', '110101', '001010', + '001011', '001000', '001001', '001110', '001111', '001100', '001101', '000010', '000011', '000000', + '000001', '000110', '000111', '000100', '000101', '011010', '011011', '011000', '011001', '011110', + '011111', '011100', '011101', '010010', '010011', '010000', '010001', '010110', '010111', '010100', + '010101', '101010', '101011', '101000', '101001', '101110', '101111', '101100', '101101', '10000', + '1000100', '1000101', '10001110', '10001111', '10001100', '10001101', '10011010', '10011011', '10011000', '10011001', + '10011110', '10011111', '10011100', '10011101', '10010010', '10010011', '10010000', '10010001', '10010110', '10010111', + '10010100', '10010101', '11101010', '11101011', '11101000', '11101001', '11101110', '11101111', '11101100', '11101101', + '11100010', '11100011', '11100000', '11100001', '11100110', '11100111', '11100100', '11100101', '11111010', '11111011', + '11111000', '11111001', '11111110', '11111111', '11111100', '11111101', '11110010', '11110011', '11110000', '11110001' ] + + # 0, 1, ... 9 + hectometersCode = [ + '000', '001', '110', '111', '100', '101', '0110', '0111', '0100', '0101' ] + + # 1, 2, ... 10 + kilometersCode = [ + '10', '011', '001', '000', '111', '0101', '0100', '1101', '11001', '11000' ] + + # 0, 1, ... 99 + centimetersCode = [ + '110010', '110011', '110000', '110001', '110110', '110111', '110100', '110101', '0101010', '0101011', + '0101000', '0101001', '0101110', '0101111', '0101100', '0101101', '0100010', '0100011', '0100000', '0100001', + '0100110', '0100111', '0100100', '0100101', '0111010', '0111011', '0111000', '0111001', '0111110', '0111111', + '0111100', '0111101', '0110010', '0110011', '0110000', '0110001', '0110110', '0110111', '0110100', '0110101', + '0001010', '0001011', '0001000', '0001001', '0001110', '0001111', '0001100', '0001101', '0000010', '0000011', + '0000000', '0000001', '0000110', '0000111', '0000100', '0000101', '0011010', '0011011', '0011000', '0011001', + '0011110', '0011111', '0011100', '0011101', '0010010', '0010011', '0010000', '0010001', '0010110', '0010111', + '0010100', '0010101', '101010', '101011', '101000', '101001', '101110', '101111', '101100', '101101', + '100010', '100011', '100000', '100001', '100110', '100111', '100100', '100101', '1111010', '1111011', + '1111000', '1111001', '1111110', '1111111', '1111100', '1111101', '111010', '111011', '111000', '111001' ] + + distance_cm = round(np.float32(distance) * np.float32(100)) # distance in cm + + quantized_distance = round(np.float32(distance), 2) + update_quantization_error('distance', quantized_distance, distance) + + cm = distance_cm # [cm] + m = cm // 100 # [m] + hm = m // 100 # [hm] + km = hm // 10 # [km] + + cm = (cm % 100) # 0, 1, ... 99 [cm] + m = (m % 100) # 0, 1, ... 99 [m] + hm = (hm % 10) # 0, 1, ... 9 [hm] + + assert 0 <= cm <= 99 + assert 0 <= m <= 99 + assert 0 <= hm <= 9 + assert distance_cm == km * 100000 + hm * 10000 + m * 100 + cm + + code = metersCode[m] + + if isSmallScene: + assert(hm == km == 0) + else: + # large scenes + if hm > 0 or km > 0: + # hectometers + code += '1' + hectometersCode[hm] + while km > 0: + # kilometers + code += '1' + kilometersCode[min(km, 10) - 1] + km = km - 10 + code += '0' + else: + code += '0' + + # centimeters + if cm > 0: + code += '1' + centimetersCode[cm] + else: + code += '0' + + return code + + +def get_absorption_code(absorption): + assert 0.0 <= absorption <= 1.0 + + index = round(absorption * 10.0) + + quantized_absorption = round(np.float32(absorption), 1) + update_quantization_error('absorption', quantized_absorption, absorption) + + return ['110', '100', '101', '0110', '0111', '111', '0100', '0101', '0010', '0011', '000' ][index] + + +# apply function to elements of list and concatenate the resulting strings +def concatenate(function, data): + return ''.join([function(d) for d in data]) + + +def test(): + # exercise encoding functions over their supported ranges + # save binary output to file so it can be compared against Matlab / C implementations + string = '' + + # count or index encoding + string += concatenate(get_count_or_index_code, [n for n in range(16 * 64)]) + + # duration encoding + string += concatenate(get_duration_code, [d / 1000 for d in range(30 * 1000)]) + string += concatenate(get_duration_code, [d / 10000 for d in range(30 * 1000)]) + string += concatenate(get_duration_code, [d / 100000 for d in range(30 * 1000)]) + + # frequency encoding + string += concatenate(get_frequency_code, + [16 , 20 , 25 , 31.5 , 40 , 50 , 63 , 80 , 100 , 125 , + 160 , 200 , 250 , 315 , 400 , 500 , 630 , 800 , 1000 , 1250 , + 1600 , 2000 , 2500 , 3150 , 4000 , 5000 , 6300 , 8000, 10000, 12500, + 16000, 20000, 25000, 31500, 40000]) + + # frequency hop encoding + string += concatenate(get_frequency_hop_code, [index for index in range(7)]) + + # DSR encoding + string += concatenate(get_dsr_code, [math.pow(10, dsr / 10) for dsr in range(-150, -10 + 1)]) + + # distance encoding + string += concatenate(lambda d : get_distance_code(d, False), [d for d in range(20 * 1000)]) + string += concatenate(lambda d : get_distance_code(d, False), [d / 10 for d in range(20 * 1000)]) + string += concatenate(lambda d : get_distance_code(d, False), [d / 100 for d in range(20 * 1000)]) + string += concatenate(lambda d : get_distance_code(d, True), [d / 100 for d in range(10 * 1000)]) + + # absorption encoding + string += concatenate(get_absorption_code, [a / 100 for a in range(100 + 1)]) + + data = bitarray(string, endian='big') + + file = open('test_python.dat', 'wb') + data.tofile(file) + file.close() + + +def generate_reverb_payload_equivalent_to_rend_config_renderer_cfg(): + # based on config_renderer.cfg + # note that because of encoding, resolution is lost and behaviour may not be bit-exact compared to .cfg file based values + data = bitarray( + '1' # hasAcEnv (see IVAS acoustic environment payload syntax document) + + get_count_or_index_code(1) # fgdNrGrids + + fgdMethod.Individual_Frequencies.value # fgdMethod + + get_count_or_index_code(31) # fgdNrBands + + + concatenate(get_frequency_code, # fgdCenterFreq + [ 20.0, 25.0, 31.5, 40.0, 50.0, 63.0, 80.0, 100.0, 125.0, 160.0, + 200.0, 250.0, 315.0, 400.0, 500.0, 630.0, 800.0, 1000.0, 1250.0, 1600.0, + 2000.0, 2500.0, 3150.0, 4000.0, 5000.0, 6300.0, 8000.0, 10000.0, 12500.0, 16000.0, + 20000.0 ]) + + + get_count_or_index_code(1) # AcousticEnvCount + + get_id_code(0) # ID + + get_count_or_index_code(0) # FreqGridID + + get_duration_code(0.1) # (input)Predelay + + + concatenate(get_duration_code, # RT60 + [ 1.3622, 1.4486, 1.3168, 1.5787, 1.4766, 1.3954, 1.2889, 1.3462, 1.0759, 1.0401, + 1.0970, 1.0850, 1.0910, 1.0404, 1.0499, 1.0699, 1.1028, 1.1714, 1.1027, 1.0666, + 1.0550, 1.0553, 1.0521, 1.0569, 1.0421, 0.97822, 0.80487, 0.75944, 0.71945, 0.61682, + 0.60031 ]) + + + concatenate(get_dsr_code, # DSR + [ 1.9952632e-08, 1.9952632e-08, 1.2589251e-08, 1.5848926e-08, 1.2589251e-08, 1.9952632e-08, 2.511887e-08, 3.9810708e-08, 1e-07, 1.9952633e-07, + 3.981071e-07, 6.3095763e-07, 7.943284e-07, 6.3095763e-07, 5.01187e-07, 5.01187e-07, 6.3095763e-07, 6.3095763e-07, 7.943284e-07, 6.3095763e-07, + 5.01187e-07, 6.3095763e-07, 6.3095763e-07, 6.3095763e-07, 5.01187e-07, 2.511887e-07, 1.2589251e-07, 1e-07, 6.309576e-08, 3.1622776e-08, + 2.511887e-08 ]) + + '0' # hasEarlyReflections + + '0' # hasDirectivity + , endian='big') + + file = open('rend_config_renderer.dat', 'wb') + data.tofile(file) + file.close() + +def generate_reverb_payload_equivalent_to_rend_config_renderer_cfg_plus_early_reflections_no_listener_origin(): + # based on config_renderer.cfg + # note that because of encoding, resolution is lost and behaviour may not be bit-exact compared to .cfg file based values + data = bitarray( + '1' # hasAcEnv + + get_count_or_index_code(2) # fgdNrGrids + # frequency grid #1 + + fgdMethod.Individual_Frequencies.value # fgdMethod + + get_count_or_index_code(1) # fgdNrBands + + + concatenate(get_frequency_code, # fgdCenterFreq + [ 10000.0 ]) + + # frequency grid #2 + + fgdMethod.Individual_Frequencies.value # fgdMethod + + get_count_or_index_code(31) # fgdNrBands + + + concatenate(get_frequency_code, # fgdCenterFreq + [ 20.0, 25.0, 31.5, 40.0, 50.0, 63.0, 80.0, 100.0, 125.0, 160.0, + 200.0, 250.0, 315.0, 400.0, 500.0, 630.0, 800.0, 1000.0, 1250.0, 1600.0, + 2000.0, 2500.0, 3150.0, 4000.0, 5000.0, 6300.0, 8000.0, 10000.0, 12500.0, 16000.0, + 20000.0 ]) + + + get_count_or_index_code(1) # AcousticEnvCount + + get_id_code(0) # ID + + get_count_or_index_code(0) # FreqGridID + + get_duration_code(0.1) # (input)Predelay + + + concatenate(get_duration_code, # RT60 + [ 1.3622, 1.4486, 1.3168, 1.5787, 1.4766, 1.3954, 1.2889, 1.3462, 1.0759, 1.0401, + 1.0970, 1.0850, 1.0910, 1.0404, 1.0499, 1.0699, 1.1028, 1.1714, 1.1027, 1.0666, + 1.0550, 1.0553, 1.0521, 1.0569, 1.0421, 0.97822, 0.80487, 0.75944, 0.71945, 0.61682, + 0.60031 ]) + + + concatenate(get_dsr_code, # DSR + [ 1.9952632e-08, 1.9952632e-08, 1.2589251e-08, 1.5848926e-08, 1.2589251e-08, 1.9952632e-08, 2.511887e-08, 3.9810708e-08, 1e-07, 1.9952633e-07, + 3.981071e-07, 6.3095763e-07, 7.943284e-07, 6.3095763e-07, 5.01187e-07, 5.01187e-07, 6.3095763e-07, 6.3095763e-07, 7.943284e-07, 6.3095763e-07, + 5.01187e-07, 6.3095763e-07, 6.3095763e-07, 6.3095763e-07, 5.01187e-07, 2.511887e-07, 1.2589251e-07, 1e-07, 6.309576e-08, 3.1622776e-08, + 2.511887e-08 ]) + + + '1' # hasEarlyReflections + + concatenate(lambda d : get_distance_code(d, True), + [ 3.0, 4.0, 2.5 ]) # erSize (room dimensions) + + + get_count_or_index_code(0) # erFreqGridIdx + + concatenate(get_absorption_code, # erAbsCoeff + [ 0.8, 0.8, 0.8, 0.8, 0.2, 0.6 ]) + + + '0' # hasListenerOrigin + + '0' # lowComplexity + + '0' # hasDirectivity + , endian='big') + + file = open('rend_config_renderer_cfg_plus_early_reflections_no_listener_origin.dat', 'wb') + data.tofile(file) + file.close() + + +def generate_reverb_payload_equivalent_to_rend_config_renderer_cfg_plus_early_reflections_listener_origin(): + # based on config_renderer.cfg + # note that because of encoding, resolution is lost and behaviour may not be bit-exact compared to .cfg file based values + data = bitarray( + '1' # hasAcEnv + + get_count_or_index_code(2) # fgdNrGrids + # frequency grid #1 + + fgdMethod.Individual_Frequencies.value # fgdMethod + + get_count_or_index_code(1) # fgdNrBands + + + concatenate(get_frequency_code, # fgdCenterFreq + [ 10000.0 ]) + + # frequency grid #2 + + fgdMethod.Individual_Frequencies.value # fgdMethod + + get_count_or_index_code(31) # fgdNrBands + + + concatenate(get_frequency_code, # fgdCenterFreq + [ 20.0, 25.0, 31.5, 40.0, 50.0, 63.0, 80.0, 100.0, 125.0, 160.0, + 200.0, 250.0, 315.0, 400.0, 500.0, 630.0, 800.0, 1000.0, 1250.0, 1600.0, + 2000.0, 2500.0, 3150.0, 4000.0, 5000.0, 6300.0, 8000.0, 10000.0, 12500.0, 16000.0, + 20000.0 ]) + + + get_count_or_index_code(1) # AcousticEnvCount + + get_id_code(0) # ID + + get_count_or_index_code(0) # FreqGridID + + get_duration_code(0.1) # (input)Predelay + + + concatenate(get_duration_code, # RT60 + [ 1.3622, 1.4486, 1.3168, 1.5787, 1.4766, 1.3954, 1.2889, 1.3462, 1.0759, 1.0401, + 1.0970, 1.0850, 1.0910, 1.0404, 1.0499, 1.0699, 1.1028, 1.1714, 1.1027, 1.0666, + 1.0550, 1.0553, 1.0521, 1.0569, 1.0421, 0.97822, 0.80487, 0.75944, 0.71945, 0.61682, + 0.60031 ]) + + + concatenate(get_dsr_code, # DSR + [ 1.9952632e-08, 1.9952632e-08, 1.2589251e-08, 1.5848926e-08, 1.2589251e-08, 1.9952632e-08, 2.511887e-08, 3.9810708e-08, 1e-07, 1.9952633e-07, + 3.981071e-07, 6.3095763e-07, 7.943284e-07, 6.3095763e-07, 5.01187e-07, 5.01187e-07, 6.3095763e-07, 6.3095763e-07, 7.943284e-07, 6.3095763e-07, + 5.01187e-07, 6.3095763e-07, 6.3095763e-07, 6.3095763e-07, 5.01187e-07, 2.511887e-07, 1.2589251e-07, 1e-07, 6.309576e-08, 3.1622776e-08, + 2.511887e-08 ]) + + + '1' # hasEarlyReflections + + concatenate(lambda code : get_distance_code(code, True), + [ 3.0, 4.0, 2.5 ]) # erSize (room dimensions) + + + get_count_or_index_code(0) # erFreqGridIdx + + concatenate(get_absorption_code, # erAbsCoeff + [ 0.8, 0.8, 0.8, 0.8, 0.2, 0.6 ]) + + + '1' # hasListenerOrigin + + '1' # isPositiveX + + '0' # isPositiveY + + concatenate(lambda d : get_distance_code(d, True), + [ 0.5, 0.5, 1.5 ]) # erListenerOrigin (x, y, z) + + '1' # lowComplexity + + '0' # hasDirectivity + , endian='big') + + file = open('rend_config_renderer_cfg_plus_early_reflections_listener_origin.dat', 'wb') + data.tofile(file) + file.close() + +def generate_reverb_payload_equivalent_to_rend_config_renderer_directivity_cfg(): + # based on rend_config_renderer_directivity.cfg + # note that because of encoding, resolution is lost and behaviour may not be bit-exact compared to .cfg file based values + data = bitarray( + '1' # hasAcEnv + + get_count_or_index_code(1) # fgdNrGrids + + fgdMethod.Individual_Frequencies.value # fgdMethod + + get_count_or_index_code(31) # fgdNrBands + + + concatenate(get_frequency_code, # fgdCenterFreq + [ 20.0, 25.0, 31.5, 40.0, 50.0, 63.0, 80.0, 100.0, 125.0, 160.0, + 200.0, 250.0, 315.0, 400.0, 500.0, 630.0, 800.0, 1000.0, 1250.0, 1600.0, + 2000.0, 2500.0, 3150.0, 4000.0, 5000.0, 6300.0, 8000.0, 10000.0, 12500.0, 16000.0, + 20000.0 ]) + + + get_count_or_index_code(1) # AcousticEnvCount + + get_id_code(0) # ID + + get_count_or_index_code(0) # FreqGridID + + get_duration_code(0.1) # (input)Predelay + + + concatenate(get_duration_code, # RT60 + [ 1.3622, 1.4486, 1.3168, 1.5787, + 1.4766, 1.3954, 1.2889, 1.3462, + 1.0759, 1.0401, 1.0970, 1.0850, + 1.0910, 1.0404, 1.0499, 1.0699, + 1.1028, 1.1714, 1.1027, 1.0666, + 1.0550, 1.0553, 1.0521, 1.0569, + 1.0421, 0.97822, 0.80487, 0.75944, + 0.71945, 0.61682, 0.60031 ]) + + + concatenate(get_dsr_code, # DSR + [ 1.9952632e-08, 1.9952632e-08, 1.2589251e-08, 1.5848926e-08, 1.2589251e-08, 1.9952632e-08, 2.511887e-08, 3.9810708e-08, 1e-07, 1.9952633e-07, + 3.981071e-07, 6.3095763e-07, 7.943284e-07, 6.3095763e-07, 5.01187e-07, 5.01187e-07, 6.3095763e-07, 6.3095763e-07, 7.943284e-07, 6.3095763e-07, + 5.01187e-07, 6.3095763e-07, 6.3095763e-07, 6.3095763e-07, 5.01187e-07, 2.511887e-07, 1.2589251e-07, 1e-07, 6.309576e-08, 3.1622776e-08, + 2.511887e-08 ]) + + + '0' # hasEarlyReflections + + '1' # hasDirectivity + + get_id_code(1) # Number of directivity patterns + + get_id_code(0) # directivity ID + + get_angle_code(0.0) + + get_angle_code(360.0) + + get_outer_attenuation_code(0.2512) + , endian='big') + + file = open('rend_config_renderer_directivity.dat', 'wb') + data.tofile(file) + file.close() + +def generate_reverb_payload_equivalent_to_config_directivity_cfg(): + # based on config_directivity_cfg.cfg + # note that because of encoding, resolution is lost and behaviour may not be bit-exact compared to .cfg file based values + data = bitarray( + '0' # hasAcEnv + + '1' # hasDirectivity + + get_id_code(1) # Number of directivity patterns + + get_id_code(0) # directivity ID + + get_angle_code(0.0) + + get_angle_code(360.0) + + get_outer_attenuation_code(0.2512) + , endian='big') + + file = open('config_directivity.dat', 'wb') + data.tofile(file) + file.close() + +def generate_reverb_payload_equivalent_to_rend_config_hospital_patientroom_cfg(): + # based on config_hospital_patientroom.cfg + # note that because of encoding, resolution is lost and behaviour may not be bit-exact compared to .cfg file based values + data = bitarray( + '1' # hasAcEnv + + get_count_or_index_code(1) # fgdNrGrids + + fgdMethod.Individual_Frequencies.value # fgdMethod + + get_count_or_index_code(31) # fgdNrBands + + + + concatenate(get_frequency_code, # fgdCenterFreq + [ 20.0, 25.0, 31.5, 40.0, 50.0, 63.0, 80.0, 100.0, 125.0, 160.0, + 200.0, 250.0, 315.0, 400.0, 500.0, 630.0, 800.0, 1000.0, 1250.0, 1600.0, + 2000.0, 2500.0, 3150.0, 4000.0, 5000.0, 6300.0, 8000.0, 10000.0, 12500.0, 16000.0, + 20000.0 ]) + + + get_count_or_index_code(1) # AcousticEnvCount + + get_id_code(0) # ID + + get_count_or_index_code(0) # FreqGridID + + get_duration_code(0.08163) # (input)Predelay + + + concatenate(get_duration_code, # RT60 + [ 0.81275, 0.61888, 0.45111, 0.34672, 0.46683, 0.53987, 0.61874, 0.70291, 0.66657, 0.73037, + 0.75090, 0.72470, 0.75486, 0.75857, 0.76844, 0.74999, 0.77622, 0.78227, 0.77441, 0.74688, + 0.73521, 0.73782, 0.71928, 0.71708, 0.71465, 0.60592, 0.52031, 0.51768, 0.52102, 0.37956, + 0.30786 ]) + + + concatenate(get_dsr_code, # DSR + [ 0.00019952621, 0.00019952621, 7.9432844e-05, 5.0118702e-05, 7.943284e-06, 6.3095763e-06, 6.3095763e-06, 7.943284e-06, 1e-05, 1e-05, + 7.943284e-06, 1e-05, 1e-05, 1e-05, 7.943284e-06, 1e-05, 1e-05, 7.943284e-06, 7.943284e-06, 6.3095763e-06, + 6.3095763e-06, 6.3095763e-06, 6.3095763e-06, 6.3095763e-06, 6.3095763e-06, 3.1622776e-06, 3.1622776e-06, 3.1622776e-06, 6.3095763e-07, 3.1622776e-07, + 3.1622776e-07 ]) + + '0' # hasEarlyReflections + + '0' # hasDirectivity + , endian='big') + + file = open('rend_config_hospital_patientroom.dat', 'wb') + data.tofile(file) + file.close() + + +def generate_reverb_payload_equivalent_to_rend_config_recreation_cfg(): + # based on config_recreation.cfg + # note that because of encoding, resolution is lost and behaviour may not be bit-exact compared to .cfg file based values + data = bitarray( + '1' # hasAcEnv + + get_count_or_index_code(1) # fgdNrGrids + + fgdMethod.Individual_Frequencies.value # fgdMethod + + get_count_or_index_code(31) # fgdNrBands + + + + concatenate(get_frequency_code, # fgdCenterFreq + [ 20.0, 25.0, 31.5, 40.0, 50.0, 63.0, 80.0, 100.0, 125.0, 160.0, + 200.0, 250.0, 315.0, 400.0, 500.0, 630.0, 800.0, 1000.0, 1250.0, 1600.0, + 2000.0, 2500.0, 3150.0, 4000.0, 5000.0, 6300.0, 8000.0, 10000.0, 12500.0, 16000.0, + 20000.0 ]) + + + get_count_or_index_code(1) # AcousticEnvCount + + get_id_code(0) # ID + + get_count_or_index_code(0) # FreqGridID + + get_duration_code(0.43031) # (input)Predelay + + + concatenate(get_duration_code, # RT60 + [ 4.51916, 4.89553, 4.83276, 5.00198, 5.34468, 5.76026, 6.36818, 6.95503, 7.27557, 7.62559, + 8.08892, 8.16002, 8.13900, 8.17919, 8.16280, 8.46226, 9.61806, 9.93048, 9.81353, 8.59340, + 8.38885, 8.36823, 6.51845, 3.76089, 3.75374, 3.57451, 1.28724, 1.22174, 1.22448, 1.71631, + 2.14343 ]) + + + concatenate(get_dsr_code, # DSR + [ 1e-06, 7.943284e-07, 1e-06, 1e-06, 1.5848925e-06, 1.9952631e-06, 3.1622776e-06, 3.9810707e-06, 6.3095763e-06, 7.943284e-06, + 1e-05, 7.943284e-06, 7.943284e-06, 7.943284e-06, 7.943284e-06, 7.943284e-06, 5.01187e-06, 5.01187e-06, 3.9810707e-06, 3.1622776e-06, + 3.1622776e-06, 2.511887e-06, 7.943284e-07, 6.3095763e-07, 6.3095763e-07, 5.01187e-08, 1.2589251e-08, 1.2589251e-08, 1.2589265e-09, 1.2589266e-11, + 3.981075e-12 ]) + + '0' # hasEarlyReflections + + '0' # hasDirectivity + , endian='big') + + file = open('rend_config_recreation.dat', 'wb') + data.tofile(file) + file.close() + + +if __name__ == "__main__": + #test() + generate_reverb_payload_equivalent_to_rend_config_renderer_cfg() + generate_reverb_payload_equivalent_to_rend_config_hospital_patientroom_cfg() + generate_reverb_payload_equivalent_to_rend_config_recreation_cfg() + generate_reverb_payload_equivalent_to_rend_config_renderer_directivity_cfg() + generate_reverb_payload_equivalent_to_config_directivity_cfg() + + + #generate_reverb_payload_equivalent_to_rend_config_renderer_cfg_plus_early_reflections_no_listener_origin() + #generate_reverb_payload_equivalent_to_rend_config_renderer_cfg_plus_early_reflections_listener_origin() diff --git a/scripts/reverb/generate_scene_metadata.py b/scripts/reverb/generate_scene_metadata.py deleted file mode 100644 index 5e1df7334b0f2b82422eb7c6d338fb7cb9133987..0000000000000000000000000000000000000000 --- a/scripts/reverb/generate_scene_metadata.py +++ /dev/null @@ -1,399 +0,0 @@ -#!/usr/bin/env python3 - -""" - (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 binary render configuration output files for testing purposes -# The binary code generation is based on the MPEG-I audio standard -# which defines functions to decode raw bitstream into internal parameters -# - - -from bitarray import bitarray, test as bitarray_test -import math -from enum import Enum -import numpy as np - - -# Set to True to print values suitable for inclusion into .cfg configuration files -print_cfg = False - -def get_id_code(id): - code = format(id % 128, '07b') + '0' - id //= 128 - while id > 0: - code = format(id % 128, '07b') + '1' + code - id = id // 128 - return code - - -def get_count_or_index_code(n): - # 0, 1, ... 63 - countOrIndexLoCodes = [ - '0111', '100', '01100', '01101', '01010', '01011', '01000', '01001', '001111', '001110', - '001101', '001100', '001011', '001010', '001001', '001000', '000111', '000110', '000101', '000100', - '000011', '000010', '000001', '000000', '111111', '111110', '111101', '111100', '111011', '111010', - '111001', '111000', '1101111', '1101110', '1101101', '1101100', '1101011', '1101010', '1101001', '1101000', - '1100111', '1100110', '1100101', '1100100', '1100011', '1100010', '1100001', '1100000', '1011111', '1011110', - '1011101', '1011100', '1011011', '1011010', '1011001', '1011000', '1010111', '1010110', '1010101', '1010100', - '1010011', '1010010', '1010001', '1010000'] - - # 1, 2, ... 15 - countOrIndexHiCode = [ - '001', '000', '110', '101', '100', '0111', '0101', '1111', '1110', '01101', - '01001', '01000', '011001', '0110001', '0110000'] - - assert 0 <= n < 16 * 64 - code = countOrIndexLoCodes[n % 64] - if n < 64: - code += '0' - else: - code += '1' + countOrIndexHiCode[n // 64 - 1] - return code - - -def get_duration_code(duration): - # 1, 2, ... 30 - secondsCode = [ - '0011', '0001', '0000', '1111', '1101', '1100', '1011', '1001', '1000', '01110', - '01101', '01100', '01011', '01001', '01000', '00101', '11101', '11100', '10101', '011111', - '011110', '010101', '001001', '001000', '101001', '0101001', '0101000', '1010001', '10100001', '10100000' ] - - # 0, 0.1, ... 1.0 - deciSecondsCode = [ - '110', '100', '101', '0110', '0111', '111', '0100', '0101', '0010', '0011', '000' ] - - # 0, 1, ..., 99 - millisecondsCode = [ - '1111010', '1111011', '1111000', '1111001', '1111110', '1111111', '1111100', '1111101', '1110010', '1110011', - '11001', '1110000', '1110001', '1110110', '1110111', '1110100', '1110101', '0101010', '0101011', '0101000', - '10010', '0101001', '0101110', '0101111', '0101100', '0101101', '0100010', '0100011', '0100000', '0100001', - '10011', '0100110', '0100111', '0100100', '0100101', '0111010', '0111011', '0111000', '0111001', '0111110', - '10000', '0111111', '0111100', '0111101', '0110010', '0110011', '0110000', '0110001', '0110110', '0110111', - '10001', '0110100', '0110101', '0001010', '0001011', '0001000', '0001001', '0001110', '0001111', '0001100', - '10110', '0001101', '0000010', '0000011', '0000000', '0000001', '0000110', '0000111', '0000100', '0000101', - '10111', '0011010', '0011011', '0011000', '0011001', '0011110', '0011111', '0011100', '0011101', '0010010', - '10100', '0010011', '0010000', '0010001', '0010110', '0010111', '0010100', '0010101', '1101010', '1101011', - '10101', '1101000', '1101001', '1101110', '1101111', '1101100', '1101101', '1100010', '1100011', '110000' ] - - # 10, 20, ... 990 - microsecondsCode = [ - '110111100', '10010', '110111101', '10011', '1101111110', '10000', '1101111111', '10001', '1101111100', '10110', - '1101111101', '10111', '110110010', '10100', '110110011', '10101', '110110000', '001010', '110110001', '001011', - '110110110', '001000', '110110111', '001001', '110110100', '001110', '110110101', '001111', '110011010', '001100', - '110011011', '001101', '110011000', '000010', '110011001', '000011', '110011110', '000000', '110011111', '000001', - '110011100', '000110', '110011101', '000111', '110010010', '000100', '110010011', '000101', '110010000', '011010', - '110010001', '011011', '110010110', '011000', '110010111', '011001', '110010100', '011110', '110010101', '011111', - '110101010', '011100', '110101011', '011101', '110101000', '010010', '110101001', '010011', '110101110', '010000', - '110101111', '010001', '110101100', '010110', '110101101', '010111', '110100010', '010100', '110100011', '010101', - '110100000', '111010', '110100001', '111011', '110100110', '111000', '110100111', '111001', '110100100', '111110', - '110100101', '111111', '110111010', '111100', '110111011', '111101', '110111000', '11000', '110111001' ] - - duration_dus = int(round(np.float32(duration) * np.float32(100000))) # [deca us] - if print_cfg: - print('duration: ', duration_dus) - - dus = duration_dus # [deca us] - s = dus // 100000 # 0, 1, ... 30 [s] - ms = (dus % 100000) // 100 # 0, 1, ... 999 [ms] - dus = (dus % 100) # 0, 1, ... 99 [deca us] - ds = ms // 100 # 0, 1, ... 9 [deci s] - ms = ms % 100 # 0, 1, ... 99 [ms] - if s >= 1 and ds == 0: - s -= 1 - ds = 10 # 0, 1, ... 10 [deci s] - - assert 0 <= s <= 30 - assert 0 <= ds <= 10 - assert 0 <= ms <= 99 - assert 0 <= dus <= 99 - assert duration_dus == s * 100000 + ds * 10000 + ms * 100 + dus - - code = deciSecondsCode[ds] - if ms > 0 or dus > 0: - code += '1' + millisecondsCode[ms] - if dus > 0: - code += '1' + microsecondsCode[dus - 1] - else: - code += '0' - else: - code += '0' - if s > 0: - # long range mode not implemented - code += '1' + secondsCode[s - 1] - else: - code += '0' - - return code - - -def get_frequency_code(f): - frequencyCode = { - 16 : '100011', 20 : '001110', 25 : '001111', 31.5 : '1001', 40 : '001100', - 50 : '001101', 63 : '0000', 80 : '011010', 100 : '011011', 125 : '0001', - 160 : '011000', 200 : '011001', 250 : '1110', 315 : '011110', 400 : '011111', - 500 : '1111', 630 : '011100', 800 : '011101', 1000 : '1100', 1250 : '010010', - 1600 : '010011', 2000 : '1101', 2500 : '010000', 3150 : '010001', 4000 : '1010', - 5000 : '010110', 6300 : '010111', 8000 : '1011', 10000: '010100', 12500: '010101', - 16000: '0010', 20000: '10000', 25000: '10001010', 31500: '10001011', 40000: '1000100', } - - assert 16 <= f <= 40000 - if f in frequencyCode.keys(): - if print_cfg: - print('frequency:', f) - return frequencyCode[f] + '0' - else: - # exact frequency not found, use frequency refinement to aproximate - # (largest relative deviation seen for range(16, 40000) was 0.006818) - # find frequencies enveloping f - f_low = 16 - f_high = 40000 - for key in frequencyCode.keys(): - if key < f: - f_low = max(f_low, key) - else: - f_high = min(f_high, key) - refinement = round(51 * math.log(f / f_low, 2)) - 1 - if refinement >= 16: - # choose next higer frequency - if print_cfg: - print('frequency:', list(frequencyCode)[f_high]) - return frequencyCode[f_high] + '0' - else: - if print_cfg: - print('frequency:', list(frequencyCode)[f_low], ', refined: ', f_low * 2 ** ((refinement + 1) / 51)) - return frequencyCode[f_low] + '1' + format(refinement, '04b') - - -def get_frequency_hop_code(index): - assert 0 <= index < 9 - return [ - '1100', # 2^(1/8) - '1101', # 2^(1/7) - '0010', # 2^(1/6) - '0011', # 2^(1/5) - '0000', # 2^(1/4) - '01', # 2^(1/3) - '0001', # 2^(1/2) - '10', # 2^1 - '111'][index] # 2^2 - - -def get_dsr_code(dsr): - # -150.0, -149.0, ... -10.0 - dsrCode = [ - '10001100', '10001101', '100011110', '100011111', '100011100', '100011101', '10000010', '10000011', '10000000', '10000001', - '10000110', '10000111', '10000100', '10000101', '011101010', '011101011', '011101000', '011101001', '011101110', '011101111', - '011101100', '011101101', '011100010', '011100011', '011100000', '011100001', '011100110', '011100111', '011100100', '011100101', - '011111010', '011111011', '011111000', '011111001', '011111110', '011111111', '011111100', '011111101', '011110010', '011110011', - '011110000', '011110001', '011110110', '011110111', '011110100', '011110101', '011001010', '011001011', '011001000', '011001001', - '011001110', '011001111', '011001100', '011001101', '011000010', '011000011', '011000000', '011000001', '011000110', '011000111', - '011000100', '011000101', '011011010', '011011011', '011011000', '011011001', '011011110', '011011111', '011011100', '011011101', - '010100', '010101', '100110', '100111', '100100', '100101', '111010', '111011', '111000', '111001', - '111110', '111111', '111100', '111101', '110010', '110011', '110000', '110001', '110110', '110111', - '110100', '110101', '001010', '001011', '001000', '001001', '001110', '001111', '001100', '001101', - '000010', '000011', '000000', '000001', '000110', '000111', '000100', '000101', '101010', '101011', - '101000', '101001', '101110', '101111', '101100', '101101', '010010', '010011', '010000', '010001', - '010110', '011010010', '011010011', '011010000', '011010001', '011010110', '011010111', '011010100', '011010101', '010111010', - '010111011', '010111000', '010111001', '010111110', '010111111', '010111100', '010111101', '10001010', '10001011', '10001000', - '10001001' ] - - d = math.log10(dsr) * 10 - d = round(d + 150) - assert 0 <= d <= 140 - if print_cfg: - print('dsr:', np.float32(np.power(np.float32(10), np.float32(d - 150) / np.float32(10)))) # C decoder uses float precision math - return dsrCode[d] - - -class fgdMethod(Enum): - Individual_Frequencies = '00' - Start_Hop_Amount = '01' - Default_Banding = '10' - - -# apply function to elements of list and concatenate the resulting strings -def concatenate(function, data): - return ''.join([function(d) for d in data]) - - -def test(): - # generate binary output which can be compared with the Matlab implementation output - string = '' - - # count or index encoding - string += concatenate(get_count_or_index_code, [n for n in range(0, 16 * 64)]) - - # duration encoding - string += concatenate(get_duration_code, [d / 1000 for d in range(0, 30 * 1000)]) - string += concatenate(get_duration_code, [d / 10000 for d in range(0, 30 * 1000)]) - string += concatenate(get_duration_code, [d / 100000 for d in range(0, 30 * 1000)]) - - # frequency encoding - string += concatenate(get_frequency_code, - [16 , 20 , 25 , 31.5 , 40 , 50 , 63 , 80 , 100 , 125 , - 160 , 200 , 250 , 315 , 400 , 500 , 630 , 800 , 1000 , 1250 , - 1600 , 2000 , 2500 , 3150 , 4000 , 5000 , 6300 , 8000, 10000, 12500, - 16000, 20000, 25000, 31500, 40000]) - - # frequency hop encoding - string += concatenate(get_frequency_hop_code, [index for index in range(0, 9)]) - - # DSR encoding - string += concatenate(get_dsr_code, [math.pow(10, dsr / 10) for dsr in range(-150, -10 + 1)]) - - data = bitarray(string, endian='big') - - file = open('test_python.dat', 'wb') - data.tofile(file) - file.close() - - -def generate_reverb_payload_equivalent_to_rend_config_renderer_cfg(): - # based on config_renderer.cfg - # note that because of encoding, resolution is lost and behaviour may not be bit-exact compared to .cfg file based values - data = bitarray( - get_count_or_index_code(1) # fgdNrGrids - + fgdMethod.Individual_Frequencies.value # fgdMethod - + get_count_or_index_code(31) # fgdNrBands - - + concatenate(get_frequency_code, # fgdCenterFreq - [ 20.0, 25.0, 31.5, 40.0, 50.0, 63.0, 80.0, 100.0, 125.0, 160.0, - 200.0, 250.0, 315.0, 400.0, 500.0, 630.0, 800.0, 1000.0, 1250.0, 1600.0, - 2000.0, 2500.0, 3150.0, 4000.0, 5000.0, 6300.0, 8000.0, 10000.0, 12500.0, 16000.0, - 20000.0 ]) - - + get_count_or_index_code(1) # AcousticEnvCount - + get_id_code(0) # ID - + get_count_or_index_code(0) # FreqGridID - + get_duration_code(0.1) # (input)Predelay - - + concatenate(get_duration_code, # RT60 - [ 1.3622, 1.4486, 1.3168, 1.5787, 1.4766, 1.3954, 1.2889, 1.3462, 1.0759, 1.0401, - 1.0970, 1.0850, 1.0910, 1.0404, 1.0499, 1.0699, 1.1028, 1.1714, 1.1027, 1.0666, - 1.0550, 1.0553, 1.0521, 1.0569, 1.0421, 0.97822, 0.80487, 0.75944, 0.71945, 0.61682, - 0.60031 ]) - - + concatenate(get_dsr_code, # DSR - [ 1.8811e-08, 2.1428e-08, 1.3972e-08, 1.51e-08, 1.287e-08, 1.8747e-08, 2.413e-08, 3.9927e-08, 8.9719e-08, 1.902e-07, - 3.702e-07, 6.1341e-07, 7.1432e-07, 6.5331e-07, 4.6094e-07, 5.4683e-07, 7.0134e-07, 6.856e-07, 7.114e-07, 6.9604e-07, - 5.2939e-07, 5.699e-07, 6.1773e-07, 5.7488e-07, 4.7748e-07, 2.7213e-07, 1.3681e-07, 1.0941e-07, 6.2001e-08, 2.8483e-08, - 2.6267e-08 ]) - - , endian='big') - - file = open('rend_config_renderer.dat', 'wb') - data.tofile(file) - file.close() - - -def generate_reverb_payload_equivalent_to_rend_config_hospital_patientroom_cfg(): - # based on config_hospital_patientroom.cfg - # note that because of encoding, resolution is lost and behaviour may not be bit-exact compared to .cfg file based values - data = bitarray( - get_count_or_index_code(1) # fgdNrGrids - + fgdMethod.Individual_Frequencies.value # fgdMethod - + get_count_or_index_code(31) # fgdNrBands - - - + concatenate(get_frequency_code, # fgdCenterFreq - [ 20.0, 25.0, 31.5, 40.0, 50.0, 63.0, 80.0, 100.0, 125.0, 160.0, - 200.0, 250.0, 315.0, 400.0, 500.0, 630.0, 800.0, 1000.0, 1250.0, 1600.0, - 2000.0, 2500.0, 3150.0, 4000.0, 5000.0, 6300.0, 8000.0, 10000.0, 12500.0, 16000.0, - 20000.0 ]) - - + get_count_or_index_code(1) # AcousticEnvCount - + get_id_code(0) # ID - + get_count_or_index_code(0) # FreqGridID - + get_duration_code(0.08163) # (input)Predelay - - + concatenate(get_duration_code, # RT60 - [ 0.81275, 0.61888, 0.45111, 0.34672, 0.46683, 0.53987, 0.61874, 0.70291, 0.66657, 0.73037, - 0.75090, 0.72470, 0.75486, 0.75857, 0.76844, 0.74999, 0.77622, 0.78227, 0.77441, 0.74688, - 0.73521, 0.73782, 0.71928, 0.71708, 0.71465, 0.60592, 0.52031, 0.51768, 0.52102, 0.37956, - 0.30786 ]) - - + concatenate(get_dsr_code, # DSR - [ 0.000219780698, 0.000205275364, 7.18711e-05, 4.5745977e-05, 8.381106e-06, 6.884964e-06, 6.532765e-06, 8.296928e-06, 1.0005793e-05, 9.191127e-06, - 8.635287e-06, 9.627704e-06, 1.0806965e-05, 1.0041916e-05, 7.77047e-06, 9.695803e-06, 9.594324e-06, 8.32215e-06, 7.564813e-06, 6.215871e-06, - 6.379496e-06, 6.358105e-06, 6.6696e-06, 6.369334e-06, 6.378474e-06, 3.339913e-06, 3.129318e-06, 2.892564e-06, 6.00202e-07, 3.40124e-07, - 3.37705e-07 ]) - - , endian='big') - - file = open('rend_config_hospital_patientroom.dat', 'wb') - data.tofile(file) - file.close() - - -def generate_reverb_payload_equivalent_to_rend_config_recreation_cfg(): - # based on config_recreation.cfg - # note that because of encoding, resolution is lost and behaviour may not be bit-exact compared to .cfg file based values - data = bitarray( - get_count_or_index_code(1) # fgdNrGrids - + fgdMethod.Individual_Frequencies.value # fgdMethod - + get_count_or_index_code(31) # fgdNrBands - - - + concatenate(get_frequency_code, # fgdCenterFreq - [ 20.0, 25.0, 31.5, 40.0, 50.0, 63.0, 80.0, 100.0, 125.0, 160.0, - 200.0, 250.0, 315.0, 400.0, 500.0, 630.0, 800.0, 1000.0, 1250.0, 1600.0, - 2000.0, 2500.0, 3150.0, 4000.0, 5000.0, 6300.0, 8000.0, 10000.0, 12500.0, 16000.0, - 20000.0 ]) - - + get_count_or_index_code(1) # AcousticEnvCount - + get_id_code(0) # ID - + get_count_or_index_code(0) # FreqGridID - + get_duration_code(0.43031) # (input)Predelay - - + concatenate(get_duration_code, # RT60 - [ 4.51916, 4.89553, 4.83276, 5.00198, 5.34468, 5.76026, 6.36818, 6.95503, 7.27557, 7.62559, - 8.08892, 8.16002, 8.13900, 8.17919, 8.16280, 8.46226, 9.61806, 9.93048, 9.81353, 8.59340, - 8.38885, 8.36823, 6.51845, 3.76089, 3.75374, 3.57451, 1.28724, 1.22174, 1.22448, 1.71631, - 2.14343 ]) - - + concatenate(get_dsr_code, # DSR - [ 9.18578e-07, 7.63803e-07, 9.23183e-07, 1.048656e-06, 1.61449e-06, 2.13745e-06, 2.854805e-06, 3.979651e-06, 6.229977e-06, 7.782421e-06, - 9.091754e-06, 8.545798e-06, 7.482083e-06, 7.351071e-06, 7.947039e-06, 8.152676e-06, 5.201189e-06, 4.744103e-06, 4.397069e-06, 3.017449e-06, - 2.958383e-06, 2.725911e-06, 7.94912e-07, 6.20198e-07, 5.71181e-07, 5.5546e-08, 1.3987e-08, 1.338e-08, 1.322e-09, 1.3e-11, - 4e-12 ]) - - , endian='big') - - file = open('rend_config_recreation.dat', 'wb') - data.tofile(file) - file.close() - - -#test() -generate_reverb_payload_equivalent_to_rend_config_renderer_cfg() -generate_reverb_payload_equivalent_to_rend_config_hospital_patientroom_cfg() -generate_reverb_payload_equivalent_to_rend_config_recreation_cfg() diff --git a/scripts/reverb/test.cfg b/scripts/reverb/test.cfg new file mode 100644 index 0000000000000000000000000000000000000000..7c670056b6140967072b6bcca3562c3a5db4dfa4 --- /dev/null +++ b/scripts/reverb/test.cfg @@ -0,0 +1,47 @@ +[roomAcoustics] +frequencyGridCount = 3; +acousticEnvironmentCount = 1; + +[frequencyGrid:0] +method = individualFrequencies; +nrBands = 31; +frequencies = [20.0, 25.0, 31.5, 40.0, + 50.0, 63.0, 80.0, 100.0, + 125.0, 160.0, 200.0, 250.0, + 315.0, 400.0, 500.0, 630.0, + 800.0, 1000.0, 1250.0, 1600.0, + 2000.0, 2500.0, 3150.0, 4000.0, + 5000.0, 6300.0, 8000.0, 10000.0, + 12500.0, 16000.0, 20000.0]; + +[frequencyGrid:1] +method = defaultBanding; +defaultGrid = 2; + +[frequencyGrid:2] +method = startHopAmount; +nrBands = 31; +startFrequency = 20; +frequencyHop = 1.259921050; + +[acousticEnvironment:0] +frequencyGridIndex = 1; +predelay = 0.1; +rt60 = [1.3622, 1.4486, 1.3168, 1.5787, + 1.4766, 1.3954, 1.2889, 1.3462, + 1.0759, 1.0401, 1.0970, 1.0850, + 1.0910, 1.0404, 1.0499, 1.0699, + 1.1028, 1.1714, 1.1027, 1.0666, + 1.0550, 1.0553, 1.0521, 1.0569, + 1.0421, 0.97822, 0.80487, 0.75944, + 0.71945, 0.61682, 0.60031]; + +dsr = [1.9952632e-08, 1.9952632e-08, 1.2589251e-08, 1.5848926e-08, 1.2589251e-08, 1.9952632e-08, 2.511887e-08, 3.9810708e-08, 1e-07, 1.9952633e-07, + 3.981071e-07, 6.3095763e-07, 7.943284e-07, 6.3095763e-07, 5.01187e-07, 5.01187e-07, 6.3095763e-07, 6.3095763e-07, 7.943284e-07, 6.3095763e-07, + 5.01187e-07, 6.3095763e-07, 6.3095763e-07, 6.3095763e-07, 5.01187e-07, 2.511887e-07, 1.2589251e-07, 1e-07, 6.309576e-08, 3.1622776e-08, + 2.511887e-08]; + +hasEarlyReflections = true; +earlyReflectionsSize = [4.0, 3.0, 2.5]; +absorptionCoeffs = [0.2, 0.2, 0.2, 0.2, 0.3, 0.8]; + diff --git a/scripts/reverb/text_to_binary_payload.py b/scripts/reverb/text_to_binary_payload.py new file mode 100644 index 0000000000000000000000000000000000000000..2223979bcec2b8308d97dc1c7d2bb1bf564f7c5a --- /dev/null +++ b/scripts/reverb/text_to_binary_payload.py @@ -0,0 +1,197 @@ +#!/usr/bin/env python3 + +""" + (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. +""" + +# +# Read a text-based configuration file and generate the equivalent binary payload. +# Makes use of the pyhton configuration file parser configparser, +# and of the payload configuration functions in generate_acoustic_environments_metadata.py. +# The configuration file format is as follows: +# +# [
:] +#