diff --git a/Workspace_msvc/lib_rend.vcxproj b/Workspace_msvc/lib_rend.vcxproj
index 0ec9061cf82ff8774d6641e15ebf4d03f8d03bdc..852cb8f14bc40454a9cb9881ce16996d5991d428 100644
--- a/Workspace_msvc/lib_rend.vcxproj
+++ b/Workspace_msvc/lib_rend.vcxproj
@@ -239,6 +239,7 @@
+
@@ -251,6 +252,7 @@
+
diff --git a/lib_com/common_api_types.h b/lib_com/common_api_types.h
index 1a2d7d77c3b397d939a67782ef4611ab0a6593a0..3cbc64e52a6e10bd17c97b853ae57853e617a96b 100644
--- a/lib_com/common_api_types.h
+++ b/lib_com/common_api_types.h
@@ -52,6 +52,9 @@
#define RENDERER_HEAD_POSITIONS_PER_FRAME 4
+#ifdef EARLY_REFLECTIONS
+#define QC_ABS_COEFF 6
+#endif
/*----------------------------------------------------------------------------------*
* Common API structures
@@ -184,6 +187,13 @@ typedef struct _IVAS_ROOM_ACOUSTICS_CONFIG
float pAcoustic_dsr[IVAS_CLDFB_NO_CHANNELS_MAX]; /* - The room's Diffuse to Source Ratio per center frequency */
float acousticPreDelay; /* Time elapsed between input signal and late reverberation start, float, range [0.001..10] */
float inputPreDelay; /* Offset in seconds from where DSR is computed in the RIR (0 = at source), float, range [0.001..10] */
+#ifdef EARLY_REFLECTIONS
+ int16_t use_er; /* ER activation flag */
+ int32_t lowComplexity; /* Low complexity ER flag */
+ IVAS_VECTOR3 dimensions; /* Room dimensions [m] */
+ float AbsCoeff[QC_ABS_COEFF]; /* Absorption coeffs */
+ IVAS_VECTOR3 ListenerOrigin; /* Listener origin */
+#endif
} IVAS_ROOM_ACOUSTICS_CONFIG_DATA;
#ifdef SPLIT_REND_WITH_HEAD_ROT
diff --git a/lib_com/ivas_cnst.h b/lib_com/ivas_cnst.h
index 6d89e222ecc83cd3a1afe3fab60d16aa1f13a001..3d66723ecbcee9509c0913325a6dcc30a6f17e23 100644
--- a/lib_com/ivas_cnst.h
+++ b/lib_com/ivas_cnst.h
@@ -1891,6 +1891,36 @@ typedef enum
#define IVAS_LIMITER_THRESHOLD 32729 /* -0.01 dBFS */
#define IVAS_LIMITER_ATTACK_SECONDS 0.005f
+
+#ifdef EARLY_REFLECTIONS
+/*----------------------------------------------------------------------------------*
+ * Early Reflection constants
+ *----------------------------------------------------------------------------------*/
+#define ER_ABS_COEFF 6
+#define ER_MAX_SOURCES 25
+#define ER_REF_ORDER 1
+#define ER_NUM_REF 6
+
+#define ER_AIR_COEFF (0.00137f)
+#define ER_SOUND_SPEED (343.0f)
+#define ER_MIN_WALL_DIST (0.1f)
+#define ER_EUCLIDEAN_SCALE (1.29246971E-26f)
+
+#define ER_DEFAULT_ROOM_L (3.0f)
+#define ER_DEFAULT_ROOM_W (4.0f)
+#define ER_DEFAULT_ROOM_H (5.0f)
+#define ER_RADIUS (1.0f)
+#define ER_LIST_ORIGIN_X (0.0f)
+#define ER_LIST_ORIGIN_Y (0.0f)
+#define ER_LIST_HEIGHT (1.6f)
+
+#define ER_MIN_ROOM_DIMENSION (1.0f)
+#define ER_MAX_ROOM_DIMENSION (999.0f)
+#define ER_MIN_ABS_COEFF (0.0f)
+#define ER_MAX_ABS_COEFF (1.0f)
+
+#endif
+
/*----------------------------------------------------------------------------------*
* Stereo downmix EVS constants
*----------------------------------------------------------------------------------*/
diff --git a/lib_com/ivas_error.h b/lib_com/ivas_error.h
index 22dbfe69816739f816da2664fdcbb66e580353a0..09309416083b633297ad388dd347bc287e2fa2ee 100644
--- a/lib_com/ivas_error.h
+++ b/lib_com/ivas_error.h
@@ -138,6 +138,9 @@ typedef enum
#ifdef CONTROL_METADATA_REVERB
IVAS_ERR_INVALID_RENDER_CONFIG,
IVAS_ERR_ACOUSTIC_ENVIRONMENT_MISSING,
+#ifdef EARLY_REFLECTIONS
+ IVAS_ERR_INVALID_ER_PARAM,
+#endif
#ifdef CONTROL_METADATA_DIRECTIVITY
IVAS_ERR_DIRECTIVITY_PATTERN_ID_MISSING,
#endif
diff --git a/lib_dec/lib_dec.c b/lib_dec/lib_dec.c
index e88e6edd1b3c49df23b8ff2e705dc7af067eb7fd..4b2678ad4c4abe52754ed29d8e4e8508a1af87d2 100644
--- a/lib_dec/lib_dec.c
+++ b/lib_dec/lib_dec.c
@@ -1637,6 +1637,11 @@ ivas_error IVAS_DEC_GetRenderConfig(
hRCout->split_rend_config.rendererSelection = hRCin->split_rend_config.rendererSelection;
#endif
+#ifdef EARLY_REFLECTIONS
+ hRCout->room_acoustics.use_er = hRCin->roomAcoustics.use_er;
+ hRCout->room_acoustics.lowComplexity = hRCin->roomAcoustics.lowComplexity;
+#endif
+
return IVAS_ERR_OK;
}
@@ -1678,6 +1683,20 @@ ivas_error IVAS_DEC_FeedRenderConfig(
hRenderConfig->roomAcoustics.nBands = renderConfig.room_acoustics.nBands;
hRenderConfig->roomAcoustics.acousticPreDelay = renderConfig.room_acoustics.acousticPreDelay;
hRenderConfig->roomAcoustics.inputPreDelay = renderConfig.room_acoustics.inputPreDelay;
+
+#ifdef EARLY_REFLECTIONS
+ hRenderConfig->roomAcoustics.use_er = 0;
+ if ( renderConfig.room_acoustics.use_er == 1 )
+ {
+ hRenderConfig->roomAcoustics.use_er = renderConfig.room_acoustics.use_er;
+ hRenderConfig->roomAcoustics.lowComplexity = renderConfig.room_acoustics.lowComplexity;
+ hRenderConfig->roomAcoustics.dimensions = renderConfig.room_acoustics.dimensions;
+ hRenderConfig->roomAcoustics.ListenerOrigin = renderConfig.room_acoustics.ListenerOrigin;
+
+ mvr2r( renderConfig.room_acoustics.AbsCoeff, hRenderConfig->roomAcoustics.AbsCoeff, ER_ABS_COEFF );
+ }
+#endif
+
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 );
diff --git a/lib_dec/rom_dec.c b/lib_dec/rom_dec.c
index 6f0751dc56a154317a734c8617baa807e1e25300..ea78271f9ecef30d88055dbeb2b2fcecd6eb8d6f 100644
--- a/lib_dec/rom_dec.c
+++ b/lib_dec/rom_dec.c
@@ -247,5 +247,4 @@ const float w_hamm_sana16k_2[L_PROT_HAMM_LEN2_16k] =
const float h_high3_32[L_FIR_FER2] = {-0.0517f, -0.0587f, -0.0820f, -0.1024f, -0.1164f, 0.8786f, -0.1164f, -0.1024f, -0.0820f, -0.0587f, -0.0517f};
const float h_high3_16[L_FIR_FER2] = { 0.f, -0.0205f, -0.0651f, -0.1256f, -0.1792f, 0.8028f, -0.1792f, -0.1256f, -0.0651f, -0.0205f, 0.f };
-
/* clang-format on */
diff --git a/lib_dec/rom_dec.h b/lib_dec/rom_dec.h
index 604bfc2fe0ce9ef7ad37db1daad5d009a5bf0ee8..4905ef8f3ab2c35b294a2f73fbe7fe4075da4f58 100644
--- a/lib_dec/rom_dec.h
+++ b/lib_dec/rom_dec.h
@@ -71,5 +71,4 @@ extern const float w_hamm_sana48k_2[L_PROT_HAMM_LEN2_48k];
extern const float h_high3_32[L_FIR_FER2];
extern const float h_high3_16[L_FIR_FER2];
-
#endif
diff --git a/lib_rend/ivas_crend.c b/lib_rend/ivas_crend.c
index e33304356017dc0b89a9cbfdb1cc05dc2b83b518..33ca0ed1899a10b6919489ce8bb672b582ff1019 100644
--- a/lib_rend/ivas_crend.c
+++ b/lib_rend/ivas_crend.c
@@ -898,6 +898,195 @@ static ivas_error ivas_rend_initCrend(
return IVAS_ERR_OK;
}
+#ifdef EARLY_REFLECTIONS
+/*-------------------------------------------------------------------------
+ * ivas_shoebox_data_init()
+ *
+ * Initialize shoebox_data_t handle
+ *------------------------------------------------------------------------*/
+
+static ivas_error ivas_shoebox_data_init(
+ shoebox_data_t *hShoeboxData /* i/o: shoebox_data_t handle */
+)
+{
+ int16_t i;
+
+ if ( hShoeboxData == NULL )
+ {
+ return IVAS_ERR_WRONG_PARAMS;
+ }
+
+ for ( i = 0; i < 150; i++ )
+ {
+ hShoeboxData->data[i] = 0.0f;
+ }
+ for ( i = 0; i < 1; i++ )
+ {
+ hShoeboxData->size[i] = 0;
+ }
+
+ return IVAS_ERR_OK;
+}
+
+/*-------------------------------------------------------------------------
+ * ivas_shoebox_output_init()
+ *
+ * Initialize shoebox_output_t handle
+ *------------------------------------------------------------------------*/
+
+static ivas_error ivas_shoebox_output_init(
+ shoebox_output_t *hShoeboxOutput /* i/o: shoebox_output_t handle */
+)
+{
+ if ( hShoeboxOutput == NULL )
+ {
+ return IVAS_ERR_WRONG_PARAMS;
+ }
+
+ hShoeboxOutput->n_sources = 0;
+ hShoeboxOutput->n_ref = 0;
+
+ ivas_shoebox_data_init( &hShoeboxOutput->times );
+ ivas_shoebox_data_init( &hShoeboxOutput->gains );
+ ivas_shoebox_data_init( &hShoeboxOutput->az_angle );
+ ivas_shoebox_data_init( &hShoeboxOutput->el_angle );
+
+ return IVAS_ERR_OK;
+}
+
+/*-------------------------------------------------------------------------
+ * ivas_shoebox_config_init()
+ *
+ * Initialize shoebox_config_t handle
+ *------------------------------------------------------------------------*/
+
+static ivas_error ivas_shoebox_config_init(
+ shoebox_config_t *hShoeboxConfig /* i/o: shoebox_config_t handle */
+)
+{
+ int16_t i;
+
+ if ( hShoeboxConfig == NULL )
+ {
+ return IVAS_ERR_WRONG_PARAMS;
+ }
+
+ hShoeboxConfig->room_L = 0.0f;
+ hShoeboxConfig->room_W = 0.0f;
+ hShoeboxConfig->room_H = 0.0f;
+
+ for ( i = 0; i < ER_ABS_COEFF; i++ )
+ {
+ hShoeboxConfig->abs_coeff[i] = 0.0f;
+ }
+ for ( i = 0; i < 3; i++ )
+ {
+ hShoeboxConfig->list_orig[i] = 0.0f;
+ }
+
+ return IVAS_ERR_OK;
+}
+
+/*-------------------------------------------------------------------------
+ * ivas_shoebox_obj_init()
+ *
+ * Initialize shoebox_obj_t handle
+ *------------------------------------------------------------------------*/
+
+static ivas_error ivas_shoebox_obj_init(
+ shoebox_obj_t *hShoeboxObj /* i/o: shoebox_obj_t handle */
+)
+{
+ int16_t i;
+
+ if ( hShoeboxObj == NULL )
+ {
+ return IVAS_ERR_WRONG_PARAMS;
+ }
+
+ hShoeboxObj->isCartesian = 0;
+ hShoeboxObj->isRelative = 0;
+ hShoeboxObj->isZHeight = 0;
+ hShoeboxObj->isRadians = 0;
+ hShoeboxObj->MAX_SOURCES = 0;
+ hShoeboxObj->max_bands = 0;
+ hShoeboxObj->REF_ORDER = 0;
+
+ for ( i = 0; i < 75; i++ )
+ {
+ hShoeboxObj->src_pos[i] = 0.0f;
+ }
+ for ( i = 0; i < 25; i++ )
+ {
+ hShoeboxObj->src_dist[i] = 0.0f;
+ }
+ for ( i = 0; i < 3; i++ )
+ {
+ hShoeboxObj->list_pos[i] = 0.0f;
+ }
+
+ hShoeboxObj->nSrc = 0;
+ hShoeboxObj->radius = 0.0f;
+ hShoeboxObj->min_wall_dist = 0.0f;
+ hShoeboxObj->soundspeed = 0.0f;
+ hShoeboxObj->air_coeff = 0.0f;
+
+ ivas_shoebox_config_init( &hShoeboxObj->cal );
+
+ return IVAS_ERR_OK;
+}
+
+/*-------------------------------------------------------------------------
+ * ivas_er_init()
+ *
+ * Initialize early reflections handle
+ *------------------------------------------------------------------------*/
+
+static ivas_error ivas_er_init(
+ er_struct_t *reflections /* i/o: early reflections handle */
+)
+{
+ int16_t i;
+
+ if ( reflections == NULL )
+ {
+ return IVAS_ERR_WRONG_PARAMS;
+ }
+
+ reflections->mode = AUDIO_CONFIG_INVALID;
+ reflections->use_er = 0;
+ reflections->is_ready = 0;
+ reflections->circ_len = 0;
+ reflections->circ_insert = 0;
+ reflections->n_total_reflections = 0;
+ reflections->is_cartesian = 0;
+ reflections->is_relative = 0;
+ reflections->max_frame_size = 0;
+ reflections->output_Fs = 0.0f;
+
+ for ( i = 0; i < 75; i++ )
+ {
+ reflections->source_positions[i] = 0.0f;
+ }
+ for ( i = 0; i < 3; i++ )
+ {
+ reflections->user_origin[i] = 0.0f;
+ if ( i == 2 )
+ {
+ reflections->user_origin[i] = ER_LIST_HEIGHT;
+ }
+ }
+
+ reflections->circ_buffers = NULL;
+ reflections->closest_ch_idx = NULL;
+
+ ivas_shoebox_output_init( &reflections->shoebox_data );
+ ivas_shoebox_obj_init( &reflections->shoebox_lib );
+
+ return IVAS_ERR_OK;
+}
+#endif
+
/*-------------------------------------------------------------------------
* ivas_rend_initCrendWrapper()
*
@@ -957,6 +1146,9 @@ ivas_error ivas_rend_initCrendWrapper(
hCrend->freq_buffer_re_diffuse = NULL;
hCrend->freq_buffer_im_diffuse = NULL;
hCrend->hReverb = NULL;
+#ifdef EARLY_REFLECTIONS
+ hCrend->reflections = NULL;
+#endif
hCrend->delay_line_rw_index = 0;
hCrend->diffuse_delay_line_rw_index = 0;
hCrend->hTrack = NULL;
@@ -1139,6 +1331,39 @@ ivas_error ivas_rend_openCrend(
{
return error;
}
+
+#ifdef EARLY_REFLECTIONS
+ if ( hRendCfg->roomAcoustics.use_er == 1 )
+ {
+
+ /* Allocate memory for reflections */
+ hCrend->reflections = (er_struct_t *) malloc( sizeof( er_struct_t ) );
+ if ( !hCrend->reflections )
+ {
+ return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Early Reflections" );
+ }
+ ivas_er_init( hCrend->reflections );
+ hCrend->reflections->use_er = hRendCfg->roomAcoustics.use_er;
+ hCrend->reflections->lowComplexity = hRendCfg->roomAcoustics.lowComplexity;
+
+ /* Set sample rate and frame size */
+ hCrend->reflections->output_Fs = (float) output_Fs;
+ hCrend->reflections->max_frame_size = (int16_t) ( output_Fs / FRAMES_PER_SEC );
+
+ /* Init Shoebox */
+ shoebox_config_init( &hCrend->reflections->shoebox_lib.cal, hRendCfg );
+
+ /* Init and compute Reflections */
+ if ( ( error = er_init( hCrend->reflections, inConfig ) ) != IVAS_ERR_OK )
+ {
+ return error;
+ };
+ }
+ else
+ {
+ hCrend->reflections = NULL;
+ }
+#endif
}
else
{
@@ -1246,6 +1471,26 @@ void ivas_rend_closeCrend(
ivas_reverb_close( &hCrend->hReverb );
+#ifdef EARLY_REFLECTIONS
+ if ( hCrend->reflections != NULL )
+ {
+ if ( hCrend->reflections->closest_ch_idx != NULL )
+ {
+ free( hCrend->reflections->closest_ch_idx );
+ hCrend->reflections->closest_ch_idx = NULL;
+ }
+
+ if ( hCrend->reflections->circ_buffers != NULL )
+ {
+ free( hCrend->reflections->circ_buffers );
+ hCrend->reflections->circ_buffers = NULL;
+ }
+
+ free( hCrend->reflections );
+ hCrend->reflections = NULL;
+ }
+#endif
+
free( hCrend );
hCrend = NULL;
#ifdef SPLIT_REND_WITH_HEAD_ROT
@@ -1513,6 +1758,24 @@ ivas_error ivas_rend_crendProcess(
for ( subframe_idx = 0; subframe_idx < MAX_PARAM_SPATIAL_SUBFRAMES; subframe_idx++ )
{
+#ifdef EARLY_REFLECTIONS
+ /* Early Reflections */
+ if ( hCrend->reflections != NULL )
+ {
+ if ( hCrend->reflections->use_er == 1 && hCrend->reflections->is_ready == 1 )
+ {
+ if ( ( error = er_process( hCrend->reflections,
+ subframe_len,
+ subframe_idx,
+ output,
+ inRendConfig ) ) != IVAS_ERR_OK )
+ {
+ return error;
+ }
+ }
+ }
+#endif
+
if ( hDecoderConfig && combinedOrientationEnabled )
{
/* Orientation tracking */
@@ -1607,6 +1870,15 @@ ivas_error ivas_rend_crendProcessSubframe(
IVAS_REND_AudioConfig outRendConfig;
int8_t combinedOrientationEnabled;
+#ifdef EARLY_REFLECTIONS
+ CREND_HANDLE hCrend;
+#ifdef SPLIT_REND_WITH_HEAD_ROT
+ hCrend = pCrend->hCrend[0];
+#else
+ hCrend = pCrend->hCrend;
+#endif
+#endif
+
combinedOrientationEnabled = 0;
if ( hCombinedOrientationData != NULL )
{
@@ -1667,6 +1939,24 @@ ivas_error ivas_rend_crendProcessSubframe(
{
subframe_len = hTcBuffer->subframe_nbslots[subframe_idx] * hTcBuffer->n_samples_granularity;
+#ifdef EARLY_REFLECTIONS
+ /* Early Reflections */
+ if ( hCrend->reflections != NULL )
+ {
+ if ( hCrend->reflections->use_er == 1 && hCrend->reflections->is_ready == 1 )
+ {
+ if ( ( error = er_process( hCrend->reflections,
+ subframe_len,
+ subframe_idx,
+ output,
+ inRendConfig ) ) != IVAS_ERR_OK )
+ {
+ return error;
+ }
+ }
+ }
+#endif
+
if ( hDecoderConfig && combinedOrientationEnabled )
{
/* Rotation in SHD for:
diff --git a/lib_rend/ivas_prot_rend.h b/lib_rend/ivas_prot_rend.h
index 50b363f192697fbbb2d5d216ec8053579ed19c9f..2ae5be6759580733454a932db3f87a7a4342c167 100644
--- a/lib_rend/ivas_prot_rend.h
+++ b/lib_rend/ivas_prot_rend.h
@@ -1204,6 +1204,69 @@ void ivas_reverb_get_hrtf_set_properties(
);
+#ifdef EARLY_REFLECTIONS
+/*---------------------------------------------------------------------------------*
+ * Shoebox Prototypes
+ *-----------------------------------------------------------------------------------*/
+
+void shoebox_config_init(
+ shoebox_config_t *cal,
+ RENDER_CONFIG_HANDLE pConfig
+);
+
+void shoebox_get_config(
+ const shoebox_obj_t *obj,
+ shoebox_config_t *s
+);
+
+void shoebox_init(
+ shoebox_obj_t *obj,
+ shoebox_config_t *cal
+);
+
+void shoebox_set_scene (
+ shoebox_obj_t *obj,
+ shoebox_output_t *ER_PARAMS,
+ const float list_pos[3],
+ const float src_pos_data[],
+ uint16_t isCartesian,
+ uint16_t isRelative
+);
+#endif
+
+#ifdef EARLY_REFLECTIONS
+/*---------------------------------------------------------------------------------*
+ * Reflections compute and process Prototypes
+ *-----------------------------------------------------------------------------------*/
+
+ivas_error er_init(
+ er_struct_t *reflections,
+ AUDIO_CONFIG inConfig
+);
+
+ivas_error er_set_reflections_mode(
+ er_struct_t *reflections,
+ AUDIO_CONFIG mode
+);
+
+ivas_error er_compute_reflections(
+ er_struct_t *reflections
+);
+
+ivas_error er_encoder_init(
+ er_struct_t *reflections
+);
+
+ivas_error er_process(
+ er_struct_t *reflections,
+ int16_t frame_size,
+ int16_t subframe_idx,
+ float **io,
+ IVAS_REND_AudioConfig inConfig
+);
+
+#endif
+
/*---------------------------------------------------------------------------------*
* Rotation Prototypes
*-----------------------------------------------------------------------------------*/
@@ -1225,7 +1288,9 @@ void Euler2Quat(
float deg2rad( float degrees );
-
+#ifdef EARLY_REFLECTIONS
+float rad2deg( float radians );
+#endif
void QuatToRotMat(
const IVAS_QUATERNION quat, /* i : quaternion describing the rotation */
diff --git a/lib_rend/ivas_reflections.c b/lib_rend/ivas_reflections.c
new file mode 100644
index 0000000000000000000000000000000000000000..bfeaf87ff0126dbe74862b36886c9f9196a6c009
--- /dev/null
+++ b/lib_rend/ivas_reflections.c
@@ -0,0 +1,548 @@
+/******************************************************************************************************
+
+ (C) 2022-2023 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository. All Rights Reserved.
+
+ This software is protected by copyright law and by international treaties.
+ The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository retain full ownership rights in their respective contributions in
+ the software. This notice grants no license of any kind, including but not limited to patent
+ license, nor is any license granted by implication, estoppel or otherwise.
+
+ Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
+ contributions.
+
+ This software is provided "AS IS", without any express or implied warranties. The software is in the
+ development stage. It is intended exclusively for experts who have experience with such software and
+ solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
+ and fitness for a particular purpose are hereby disclaimed and excluded.
+
+ Any dispute, controversy or claim arising under or in relation to providing this software shall be
+ submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
+ accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
+ the United Nations Convention on Contracts on the International Sales of Goods.
+
+*******************************************************************************************************/
+
+#include "options.h"
+
+#ifdef EARLY_REFLECTIONS
+
+#include
+#include
+#include "prot.h"
+#include "rom_dec.h"
+#include "lib_rend.h"
+#include "ivas_prot_rend.h"
+#include "ivas_stat_rend.h"
+#include "ivas_cnst.h"
+#include "ivas_prot.h"
+#include "ivas_rom_com.h"
+#include "wmc_auto.h"
+#ifdef DEBUGGING
+#include "debug.h"
+#endif
+
+uint16_t LC_mixing_5_1[5] = { 0, 1, 2, 0, 1 };
+uint16_t LC_mixing_7_1[7] = { 0, 1, 2, 3, 4, 3, 4 };
+uint16_t LC_mixing_5_1_2[7] = { 0, 1, 2, 3, 4, 0, 1 };
+uint16_t LC_mixing_5_1_4[9] = { 0, 1, 2, 3, 4, 0, 1, 2, 3 };
+uint16_t LC_mixing_7_1_4[11] = { 0, 1, 2, 3, 4, 3, 4, 0, 1, 2, 3 };
+
+/*-----------------------------------------------------------------------------------------*
+ * Function er_init
+ *
+ * Initializes the reflections data structure according to the requested input config.
+ *-----------------------------------------------------------------------------------------*/
+
+
+ivas_error er_init(
+ er_struct_t *reflections,
+ AUDIO_CONFIG mode )
+{
+ ivas_error error;
+ IVAS_REND_AudioConfig outRendConfig;
+ uint8_t i;
+
+ /* Set to defaults for shoebox */
+ reflections->is_ready = 0;
+ reflections->mode = AUDIO_CONFIG_INVALID;
+ reflections->is_cartesian = 0;
+ reflections->is_relative = 1;
+ reflections->shoebox_data.n_ref = ER_NUM_REF;
+ reflections->user_origin[0] = 0.0f;
+ reflections->user_origin[1] = 0.0f;
+ reflections->user_origin[2] = ER_LIST_HEIGHT;
+
+ /* Store scene origin if present */
+ for ( i = 0; i < 3; i++ )
+ {
+ reflections->user_origin[i] = reflections->shoebox_lib.cal.list_orig[i];
+ }
+
+ /* Init Shoebox */
+ shoebox_init( &reflections->shoebox_lib, &reflections->shoebox_lib.cal );
+
+ /* Set mode */
+ if ( ( error = er_set_reflections_mode( reflections, mode ) ) != IVAS_ERR_OK )
+ {
+ return error;
+ }
+
+ /* Compute the static reflections (first frame) */
+ if ( ( error = er_compute_reflections( reflections ) ) != IVAS_ERR_OK )
+ {
+ return error;
+ }
+
+ reflections->closest_ch_idx = (uint16_t *) malloc( reflections->n_total_reflections * sizeof( uint16_t ) );
+ if ( !reflections->closest_ch_idx )
+ {
+ return IVAS_ERR_FAILED_ALLOC;
+ }
+ set_s( (int16_t *) reflections->closest_ch_idx, 0, reflections->n_total_reflections );
+
+ outRendConfig = getRendAudioConfigFromIvasAudioConfig( reflections->mode );
+ if ( ( error = getAudioConfigNumChannels( outRendConfig, &( reflections->nchan_out ) ) ) != IVAS_ERR_OK )
+ {
+ return error;
+ }
+
+ /* Initialize Encoder */
+ if ( ( error = er_encoder_init( reflections ) ) != IVAS_ERR_OK )
+ {
+ return error;
+ }
+
+ /* Update flag to indicate that reflection module is ready to process */
+ reflections->is_ready = 1;
+
+ return error;
+}
+/*-----------------------------------------------------------------------------------------*
+ Function er_set_reflections_mode
+
+ Function sets the ER source positions based on the audio config
+ *-----------------------------------------------------------------------------------------*/
+
+ivas_error er_set_reflections_mode(
+ er_struct_t *reflections,
+ AUDIO_CONFIG mode )
+{
+ ivas_error error;
+ uint16_t ch;
+ error = IVAS_ERR_OK;
+
+ if ( reflections->mode == mode )
+ {
+ return error;
+ }
+
+ reflections->is_ready = 0;
+ reflections->mode = mode;
+
+ switch ( reflections->mode )
+ {
+ case AUDIO_CONFIG_MONO:
+ reflections->shoebox_data.n_sources = 1;
+ reflections->n_LC_sources = 1;
+ reflections->LC_mixing = LC_mixing_5_1;
+ reflections->source_positions[0] = 0;
+ reflections->source_positions[1] = 0;
+ reflections->source_positions[2] = ER_RADIUS;
+ break;
+ case AUDIO_CONFIG_STEREO:
+ reflections->shoebox_data.n_sources = 2;
+ reflections->n_LC_sources = 2;
+ reflections->LC_mixing = LC_mixing_5_1;
+ for ( ch = 0; ch < reflections->shoebox_data.n_sources; ch++ )
+ {
+ reflections->source_positions[3 * ch] = deg2rad( ls_azimuth_CICP2[ch] );
+ reflections->source_positions[1 + ( 3 * ch )] = deg2rad( ls_elevation_CICP2[ch] );
+ reflections->source_positions[2 + ( 3 * ch )] = ER_RADIUS;
+ }
+ break;
+ case AUDIO_CONFIG_5_1:
+ reflections->shoebox_data.n_sources = 5;
+ reflections->n_LC_sources = 3;
+ reflections->LC_mixing = LC_mixing_5_1;
+ for ( ch = 0; ch < reflections->shoebox_data.n_sources; ch++ )
+ {
+ reflections->source_positions[3 * ch] = deg2rad( ls_azimuth_CICP6[ch] );
+ reflections->source_positions[1 + ( 3 * ch )] = deg2rad( ls_elevation_CICP6[ch] );
+ reflections->source_positions[2 + ( 3 * ch )] = ER_RADIUS;
+ }
+ break;
+ case AUDIO_CONFIG_7_1:
+ reflections->shoebox_data.n_sources = 7;
+ reflections->n_LC_sources = 5;
+ reflections->LC_mixing = LC_mixing_7_1;
+ for ( ch = 0; ch < reflections->shoebox_data.n_sources; ch++ )
+ {
+ reflections->source_positions[3 * ch] = deg2rad( ls_azimuth_CICP12[ch] );
+ reflections->source_positions[1 + ( 3 * ch )] = deg2rad( ls_elevation_CICP12[ch] );
+ reflections->source_positions[2 + ( 3 * ch )] = ER_RADIUS;
+ }
+ break;
+ case AUDIO_CONFIG_5_1_2:
+ reflections->shoebox_data.n_sources = 7;
+ reflections->n_LC_sources = 5;
+ reflections->LC_mixing = LC_mixing_5_1_2;
+ for ( ch = 0; ch < reflections->shoebox_data.n_sources; ch++ )
+ {
+ reflections->source_positions[3 * ch] = deg2rad( ls_azimuth_CICP14[ch] );
+ reflections->source_positions[1 + ( 3 * ch )] = deg2rad( ls_elevation_CICP14[ch] );
+ reflections->source_positions[2 + ( 3 * ch )] = ER_RADIUS;
+ }
+ break;
+ case AUDIO_CONFIG_5_1_4:
+ reflections->shoebox_data.n_sources = 9;
+ reflections->n_LC_sources = 5;
+ reflections->LC_mixing = LC_mixing_5_1_4;
+ for ( ch = 0; ch < reflections->shoebox_data.n_sources; ch++ )
+ {
+ reflections->source_positions[3 * ch] = deg2rad( ls_azimuth_CICP16[ch] );
+ reflections->source_positions[1 + ( 3 * ch )] = deg2rad( ls_elevation_CICP16[ch] );
+ reflections->source_positions[2 + ( 3 * ch )] = ER_RADIUS;
+ }
+ break;
+ case AUDIO_CONFIG_7_1_4:
+ reflections->shoebox_data.n_sources = 11;
+ reflections->n_LC_sources = 5;
+ reflections->LC_mixing = LC_mixing_7_1_4;
+ for ( ch = 0; ch < reflections->shoebox_data.n_sources; ch++ )
+ {
+ reflections->source_positions[3 * ch] = deg2rad( ls_azimuth_CICP19[ch] );
+ reflections->source_positions[1 + ( 3 * ch )] = deg2rad( ls_elevation_CICP19[ch] );
+ reflections->source_positions[2 + ( 3 * ch )] = ER_RADIUS;
+ }
+ break;
+ case AUDIO_CONFIG_HOA3:
+ reflections->use_er = 0;
+ break;
+ case AUDIO_CONFIG_HOA2:
+ reflections->use_er = 0;
+ break;
+ case AUDIO_CONFIG_FOA:
+ reflections->use_er = 0;
+ break;
+ default:
+ reflections->mode = AUDIO_CONFIG_INVALID;
+ return IVAS_ERROR( IVAS_ERR_INVALID_ER_PARAM, "Unsupported reflections mode" );
+ }
+
+ return error;
+}
+
+
+/*-----------------------------------------------------------------------------------------*
+ Function er_encoder_init
+
+ Function that initializes the er encoder
+ *-----------------------------------------------------------------------------------------*/
+
+ivas_error er_encoder_init(
+ er_struct_t *reflections )
+{
+ ivas_error error = IVAS_ERR_OK;
+ uint16_t i, j, src_idx;
+ uint16_t min_index = 0;
+ float p_x, p_y, p_z;
+ float p_x_src, p_y_src, p_z_src;
+ float tmp;
+ float dist, min_dist = 0;
+
+ if ( !reflections )
+ {
+ error = IVAS_ERR_FAILED_ALLOC;
+ return error;
+ }
+
+ if ( getAudioConfigType( getRendAudioConfigFromIvasAudioConfig( reflections->mode ) ) == IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED )
+ {
+ /* Compute MC-snap location (closest channel position to reflection direction) */
+ for ( i = 0; i < reflections->n_total_reflections; i++ )
+ {
+ /* Compute cartesian points for reflection (from degrees) */
+ p_x = ER_RADIUS * ( (float) cos( deg2rad( reflections->shoebox_data.el_angle.data[i] ) ) * (float) cos( deg2rad( reflections->shoebox_data.az_angle.data[i] ) ) );
+ p_y = ER_RADIUS * ( (float) cos( deg2rad( reflections->shoebox_data.el_angle.data[i] ) ) * (float) sin( deg2rad( reflections->shoebox_data.az_angle.data[i] ) ) );
+ p_z = ER_RADIUS * ( (float) sin( deg2rad( reflections->shoebox_data.el_angle.data[i] ) ) );
+
+ /* Calculate the euclidean distance to each point in the config ls setup */
+ for ( j = 0; j < reflections->nchan_out; j++ )
+ {
+ /* Ignore LFE */
+ if ( j != LFE_CHANNEL )
+ {
+ src_idx = ( j > LFE_CHANNEL ) ? j - 1 : j;
+
+ p_x_src = reflections->source_positions[src_idx * 3 + 2] * ( (float) cos( reflections->source_positions[src_idx * 3 + 1] ) * (float) cos( reflections->source_positions[src_idx * 3] ) );
+ p_y_src = reflections->source_positions[src_idx * 3 + 2] * ( (float) cos( reflections->source_positions[src_idx * 3 + 1] ) * (float) sin( reflections->source_positions[src_idx * 3] ) );
+ p_z_src = reflections->source_positions[src_idx * 3 + 2] * (float) sin( reflections->source_positions[src_idx * 3 + 1] );
+
+ tmp = ( p_x_src - p_x ) * ( p_x_src - p_x );
+ tmp += ( p_y_src - p_y ) * ( p_y_src - p_y );
+ tmp += ( p_z_src - p_z ) * ( p_z_src - p_z );
+ dist = (float) sqrt( tmp );
+
+ /* Save index of closest channel */
+ if ( src_idx == 0 )
+ {
+ min_dist = dist;
+ min_index = j;
+ }
+ else
+ {
+ if ( dist < min_dist )
+ {
+ min_dist = dist;
+ min_index = j;
+ }
+ }
+ }
+ }
+
+ reflections->closest_ch_idx[i] = (uint16_t) min_index;
+ }
+ }
+
+
+ return error;
+}
+
+
+/*-----------------------------------------------------------------------------------------*
+ Function er_compute_reflections
+
+ Function computes reflections using the shoebox library and sets up the circular buffers
+ structure for the early reflections process
+ *-----------------------------------------------------------------------------------------*/
+
+ivas_error er_compute_reflections(
+ er_struct_t *reflections )
+{
+ ivas_error error = IVAS_ERR_OK;
+ uint16_t circ_len, i, j;
+ float tmp;
+
+ reflections->is_ready = 0;
+
+ /* Disabled case */
+ if ( reflections->mode == AUDIO_CONFIG_INVALID )
+ {
+ return error;
+ }
+
+ /* Run shoebox with current reflection parameters */
+ shoebox_set_scene( &( reflections->shoebox_lib ), &( reflections->shoebox_data ),
+ reflections->shoebox_lib.cal.list_orig, reflections->source_positions,
+ reflections->is_cartesian, reflections->is_relative );
+
+ /* Convert reflection times in seconds to samples and keep track of max */
+ circ_len = 0;
+ for ( i = 0; i < reflections->shoebox_data.n_sources; i++ )
+ {
+ for ( j = 0; j < reflections->shoebox_data.n_ref; j++ )
+ {
+ tmp = reflections->shoebox_data.times.data[j + ( i * (int) reflections->shoebox_data.n_ref )];
+ tmp = (float) round( tmp * reflections->output_Fs );
+ reflections->shoebox_data.times.data[j + ( i * (int) reflections->shoebox_data.n_ref )] = tmp;
+ circ_len = ( (uint16_t) tmp > circ_len ) ? (uint16_t) tmp : circ_len;
+ }
+ }
+
+ /* If max delay is less than max frame size, use max frame size to compute circ buffer length */
+ circ_len = ( circ_len > (uint16_t) reflections->max_frame_size ) ? circ_len : (uint16_t) reflections->max_frame_size;
+ circ_len += (uint16_t) reflections->max_frame_size;
+
+ /* If circ buffers exist and size is the same, reset memory to all zeros */
+ /* If size is different, reallocate circ buffers */
+ /* Otherwise allocate new circ buffers */
+ if ( reflections->circ_buffers )
+ {
+ if ( reflections->circ_len == circ_len )
+ {
+ /* circ buffers exist and size is the same */
+ set_f( reflections->circ_buffers, 0.0f,
+ reflections->shoebox_data.n_sources * reflections->circ_len );
+ }
+ else
+ {
+ /* circ buffers exist but size is different */
+ reflections->circ_len = circ_len;
+ free( reflections->circ_buffers );
+ reflections->circ_buffers = (float *) malloc(
+ reflections->shoebox_data.n_sources * reflections->circ_len * sizeof( float ) );
+ set_f( reflections->circ_buffers, 0.0f,
+ reflections->shoebox_data.n_sources * reflections->circ_len );
+ }
+ }
+ else
+ {
+ /* circ buffers do not exist */
+ reflections->circ_len = circ_len;
+ reflections->circ_buffers = (float *) malloc(
+ reflections->shoebox_data.n_sources * reflections->circ_len * sizeof( float ) );
+ set_f( reflections->circ_buffers, 0.0f,
+ reflections->shoebox_data.n_sources * reflections->circ_len );
+ }
+
+ /* Check that circ buffers were allocated */
+ if ( !reflections->circ_buffers )
+ {
+ return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Early Reflections buffers" );
+ }
+
+ /* Initialize circular buffer insertion point */
+ reflections->circ_insert = reflections->circ_len - (uint16_t) reflections->max_frame_size;
+
+ /* Get total reflections number */
+ reflections->n_total_reflections = reflections->shoebox_data.n_sources * reflections->shoebox_data.n_ref;
+
+ /* Check that reflection buffers were allocated */
+ if ( error != IVAS_ERR_OK )
+ {
+ return error;
+ }
+
+ return error;
+}
+
+/*-----------------------------------------------------------------------------------------*
+Function er_process
+
+Takes a buffer of N channels, returns a buffer of N*6 channels containing the early
+reflections (one per wall). The process is a delay line architecture
+*-----------------------------------------------------------------------------------------*/
+
+
+ivas_error er_process(
+ er_struct_t *reflections,
+ int16_t subframe_size,
+ int16_t subframe_idx,
+ float **io,
+ IVAS_REND_AudioConfig inConfig )
+{
+ ivas_error error = IVAS_ERR_OK;
+ uint16_t i, j, k, subframe_offset;
+ uint16_t ref_no, ref_delay;
+ uint16_t n_ref_sources, n_ref;
+ int16_t samp_idx, in_ch_idx, buf_ch_idx, ref_out_idx;
+ float ref_gain;
+ float *buffer_ch;
+
+ if ( !reflections )
+ {
+ return IVAS_ERR_INIT_ERROR;
+ }
+
+ /* should not arrive here if reflections are disabled but in case it does just do nothing */
+ if ( reflections->use_er != 1 )
+ {
+ return error;
+ }
+
+ /* Ensure all reflection memory is allocated */
+ if ( !reflections->circ_buffers ||
+ !reflections->is_ready )
+ {
+ return IVAS_ERR_INIT_ERROR;
+ }
+
+ subframe_offset = subframe_idx * subframe_size;
+ n_ref = reflections->shoebox_data.n_ref;
+
+ /* If low complexity ER are requested only compute ER for n_LC_sources */
+ if ( reflections->lowComplexity )
+ {
+ n_ref_sources = reflections->n_LC_sources;
+ }
+ else
+ {
+ n_ref_sources = reflections->shoebox_data.n_sources;
+ }
+
+ /* Channel case, copy input into buffers panning for LC mode and skipping LFE */
+ if ( getAudioConfigType( inConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED )
+ {
+ /* Loop through all input sources filling circular buffers */
+ for ( i = 0; i < reflections->shoebox_data.n_sources; i++ )
+ {
+ /* Pull correct circular buffer depending on complexity mode */
+ buf_ch_idx = ( reflections->lowComplexity == 1 ) ? reflections->LC_mixing[i] : i;
+ buffer_ch = &( reflections->circ_buffers[buf_ch_idx * reflections->circ_len] );
+
+ /* Skip LFE from input buffer */
+ in_ch_idx = ( i >= LFE_CHANNEL ) ? i + 1 : i;
+ samp_idx = reflections->circ_insert;
+
+ /* If less than number of reflection sources, overwrite buffer */
+ if ( i == buf_ch_idx )
+ {
+ for ( j = 0; j < subframe_size; j++ )
+ {
+ buffer_ch[samp_idx++] = io[in_ch_idx][j + subframe_offset];
+ samp_idx = samp_idx % reflections->circ_len;
+ }
+ }
+ /* Accumulate with buffer for low complexity mixed sources */
+ else
+ {
+ for ( j = 0; j < subframe_size; j++ )
+ {
+ buffer_ch[samp_idx++] += io[in_ch_idx][j + subframe_offset];
+ samp_idx = samp_idx % reflections->circ_len;
+ }
+ }
+ }
+ }
+ else
+ {
+ return IVAS_ERR_INVALID_INPUT_FORMAT;
+ }
+
+ /* Loop through sources retrieve reflections from circ buffers */
+ for ( i = 0; i < n_ref_sources; i++ )
+ {
+ /* Access correct row of input circ buffer */
+ buffer_ch = &( reflections->circ_buffers[i * reflections->circ_len] );
+
+ /* Loop through reflections */
+ for ( j = 0; j < n_ref; j++ )
+ {
+ ref_no = j + ( i * n_ref );
+ ref_gain = reflections->shoebox_data.gains.data[ref_no];
+ ref_delay = (uint16_t) reflections->shoebox_data.times.data[ref_no];
+ ref_out_idx = reflections->closest_ch_idx[ref_no];
+
+ /* Determine start idx of reflection in circ buffer based on
+ current insert idx and reflection delay */
+ samp_idx = (int) reflections->circ_insert - ref_delay;
+ if ( samp_idx < 0 )
+ {
+ samp_idx = (int) reflections->circ_len + samp_idx;
+ }
+
+ /* Pull reflection from circ buffer and apply gain */
+ for ( k = 0; k < subframe_size; k++ )
+ {
+ io[ref_out_idx][k + subframe_offset] += buffer_ch[samp_idx++] * ref_gain;
+ samp_idx = samp_idx % reflections->circ_len;
+ }
+ }
+ }
+
+ /* Increment circular buffer start index */
+ reflections->circ_insert = ( reflections->circ_insert + subframe_size ) % reflections->circ_len;
+
+ return error;
+}
+
+
+#endif
diff --git a/lib_rend/ivas_render_config.c b/lib_rend/ivas_render_config.c
index 2972b57f847e16140fc142dced8c92af88c56c17..8bb5a957e80af259e196fd371b016800179cbd8a 100644
--- a/lib_rend/ivas_render_config.c
+++ b/lib_rend/ivas_render_config.c
@@ -49,6 +49,10 @@
#define IVAS_REVERB_DEFAULT_PRE_DELAY 0.016f
#define IVAS_REVERB_DEFAULT_INPUT_DELAY 0.1f
+#ifdef EARLY_REFLECTIONS
+#define IVAS_REVERB_DEFAULT_USE_ER 0
+#endif
+
/*-----------------------------------------------------------------------*
* ivas_render_config_open()
@@ -116,6 +120,9 @@ ivas_error ivas_render_config_init_from_rom(
( *hRenderConfig )->roomAcoustics.nBands = IVAS_REVERB_DEFAULT_N_BANDS;
( *hRenderConfig )->roomAcoustics.acousticPreDelay = IVAS_REVERB_DEFAULT_PRE_DELAY;
( *hRenderConfig )->roomAcoustics.inputPreDelay = IVAS_REVERB_DEFAULT_INPUT_DELAY;
+#ifdef EARLY_REFLECTIONS
+ ( *hRenderConfig )->roomAcoustics.use_er = IVAS_REVERB_DEFAULT_USE_ER;
+#endif
set_zero( &( *hRenderConfig )->roomAcoustics.pFc_input[0], CLDFB_NO_CHANNELS_MAX );
set_zero( &( *hRenderConfig )->roomAcoustics.pAcoustic_rt60[0], CLDFB_NO_CHANNELS_MAX );
set_zero( &( *hRenderConfig )->roomAcoustics.pAcoustic_dsr[0], CLDFB_NO_CHANNELS_MAX );
diff --git a/lib_rend/ivas_reverb.c b/lib_rend/ivas_reverb.c
index fd485ffbce7c504b055750bb4c532b9eec6dc980..b110cd372d50cd819c7a79521a2dbbd648a2d7b7 100644
--- a/lib_rend/ivas_reverb.c
+++ b/lib_rend/ivas_reverb.c
@@ -1182,6 +1182,14 @@ ivas_error ivas_reverb_open(
pState->pConfig.roomAcoustics.override = hRenderConfig->roomAcoustics.override;
pState->pConfig.roomAcoustics.nBands = hRenderConfig->roomAcoustics.nBands;
+#ifdef EARLY_REFLECTIONS
+ if ( hRenderConfig->roomAcoustics.use_er == 1 )
+ {
+ pState->pConfig.roomAcoustics.use_er = hRenderConfig->roomAcoustics.use_er;
+ pState->pConfig.roomAcoustics.lowComplexity = hRenderConfig->roomAcoustics.lowComplexity;
+ }
+#endif
+
/* set up input downmix */
pState->dmx_gain = calc_dmx_gain();
diff --git a/lib_rend/ivas_rotation.c b/lib_rend/ivas_rotation.c
index c7d372d65d5ae08c6bbd7103f35008dfed804224..324b88549a381e088dce1ff1a81ae1b3165ef180 100644
--- a/lib_rend/ivas_rotation.c
+++ b/lib_rend/ivas_rotation.c
@@ -272,6 +272,27 @@ float deg2rad(
return PI_OVER_180 * degrees;
}
+#ifdef EARLY_REFLECTIONS
+/*-------------------------------------------------------------------------
+ * rad2deg()
+ *
+ * Converts normalized radians to degrees
+ *------------------------------------------------------------------------*/
+float rad2deg(
+ float radians )
+{
+ while ( radians >= EVS_PI )
+ {
+ radians = radians - EVS_PI;
+ }
+ while ( radians <= -EVS_PI )
+ {
+ radians = radians + EVS_PI;
+ }
+ return _180_OVER_PI * radians;
+}
+#endif
+
/*-------------------------------------------------------------------------
* rotateAziEle()
*
diff --git a/lib_rend/ivas_shoebox.c b/lib_rend/ivas_shoebox.c
new file mode 100644
index 0000000000000000000000000000000000000000..90db7575fdec414beae1ba5fb5075f1df08ca377
--- /dev/null
+++ b/lib_rend/ivas_shoebox.c
@@ -0,0 +1,458 @@
+/******************************************************************************************************
+
+ (C) 2022-2023 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository. All Rights Reserved.
+
+ This software is protected by copyright law and by international treaties.
+ The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository retain full ownership rights in their respective contributions in
+ the software. This notice grants no license of any kind, including but not limited to patent
+ license, nor is any license granted by implication, estoppel or otherwise.
+
+ Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
+ contributions.
+
+ This software is provided "AS IS", without any express or implied warranties. The software is in the
+ development stage. It is intended exclusively for experts who have experience with such software and
+ solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
+ and fitness for a particular purpose are hereby disclaimed and excluded.
+
+ Any dispute, controversy or claim arising under or in relation to providing this software shall be
+ submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
+ accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
+ the United Nations Convention on Contracts on the International Sales of Goods.
+
+*******************************************************************************************************/
+
+#include "options.h"
+
+#ifdef EARLY_REFLECTIONS
+
+#include
+#include
+#include "ivas_prot_rend.h"
+#include "ivas_stat_rend.h"
+#include "ivas_cnst.h"
+#include "prot.h"
+#include "wmc_auto.h"
+
+/*-----------------------------------------------------------------------------------------*
+ * Function shoebox_config_init
+ *
+ * Function transfer the parameters from the reverb config handle to the shoebox
+ * calibration data structure.
+ *-----------------------------------------------------------------------------------------*/
+
+void shoebox_config_init(
+ shoebox_config_t *cal,
+ RENDER_CONFIG_HANDLE hRenderConfig /* i : Renderer configuration handle */
+)
+{
+ int32_t wall_idx;
+
+ cal->room_L = hRenderConfig->roomAcoustics.dimensions.x;
+ cal->room_W = hRenderConfig->roomAcoustics.dimensions.y;
+ cal->room_H = hRenderConfig->roomAcoustics.dimensions.z;
+
+ /* Absorption Coefficients */
+ /* Convention: [Front wall, Back wall, Left wall, Right wall, Ceiling, Floor] */
+ for ( wall_idx = 0; wall_idx < 6; wall_idx++ )
+ {
+ cal->abs_coeff[wall_idx] = hRenderConfig->roomAcoustics.AbsCoeff[wall_idx];
+ }
+
+ /* Listener position (only X and Y can be pos. or neg. ) */
+ cal->list_orig[0] = hRenderConfig->roomAcoustics.ListenerOrigin.x;
+ cal->list_orig[1] = hRenderConfig->roomAcoustics.ListenerOrigin.y;
+ cal->list_orig[2] = hRenderConfig->roomAcoustics.ListenerOrigin.z;
+}
+
+/*-----------------------------------------------------------------------------------------*
+ * Function shoebox_init
+ *
+ * Function initializes the shoebox operating parameters by setting limits and defaults,
+ * also contains the calibration structure.
+ *-----------------------------------------------------------------------------------------*/
+
+void shoebox_init(
+ shoebox_obj_t *obj,
+ shoebox_config_t *cal )
+{
+ uint16_t i;
+
+ /* Add cal to obj struct */
+ obj->cal = *cal;
+ /* Add defaults */
+ obj->max_bands = 1;
+ obj->MAX_SOURCES = ER_MAX_SOURCES;
+ obj->REF_ORDER = ER_REF_ORDER;
+
+ /* Positions */
+ set_f( &obj->src_pos[0], 0.0f, 75U );
+ set_f( &obj->src_dist[0], 0.0f, 25U );
+
+ for ( i = 0; i < 3; i++ )
+ {
+ obj->list_pos[i] = cal->list_orig[i];
+ }
+
+ /* Pointer */
+ obj->nSrc = 0;
+
+ /* Flags */
+ obj->isCartesian = 1;
+ obj->isRelative = 1;
+ obj->isZHeight = 1;
+ obj->isRadians = 1;
+
+ /* Params */
+ obj->radius = ER_RADIUS;
+ obj->min_wall_dist = ER_MIN_WALL_DIST;
+ obj->soundspeed = ER_SOUND_SPEED;
+ obj->air_coeff = ER_AIR_COEFF;
+}
+
+/*-----------------------------------------------------------------------------------------*
+ * Function shoebox_bound
+ *
+ * SHOEBOX_BOUND takes in CARTESIAN coordinates of either a receiver or
+ * source and checks if it is within the virtual room boundaries established
+ * by the surface parameters. If object is out of bounds, then new cartesian
+ * coordinates are established to collapse the object position.
+ *-----------------------------------------------------------------------------------------*/
+
+
+static void shoebox_bound(
+ shoebox_obj_t *obj,
+ float *out_pos )
+{
+ float out_tmp;
+ int32_t i;
+
+ out_tmp = ( obj->cal.room_L / 2.0f ) - obj->min_wall_dist;
+ if ( ( out_pos[0] > out_tmp ) || ( out_pos[0] < ( ( ( -obj->cal.room_L ) / 2.0f ) + obj->min_wall_dist ) ) )
+ {
+ if ( out_pos[0] < 0.0f )
+ {
+ i = -1;
+ }
+ else
+ {
+ i = ( out_pos[0] > 0.0f ) ? ( (int32_t) 1 ) : ( (int32_t) 0 );
+ }
+ out_pos[0] = out_tmp * ( (float) i );
+ }
+ out_tmp = ( obj->cal.room_W / 2.0f ) - obj->min_wall_dist;
+ if ( ( out_pos[1] > out_tmp ) || ( out_pos[1] < ( ( ( -obj->cal.room_W ) / 2.0f ) + obj->min_wall_dist ) ) )
+ {
+ if ( out_pos[1] < 0.0f )
+ {
+ i = -1;
+ }
+ else
+ {
+ i = ( out_pos[1] > 0.0f ) ? ( (int32_t) 1 ) : ( (int32_t) 0 );
+ }
+ out_pos[1] = out_tmp * ( (float) i );
+ }
+ out_tmp = ( obj->cal.room_H / 2.0f ) - obj->min_wall_dist;
+ if ( ( out_pos[2] > out_tmp ) || ( out_pos[2] < ( ( ( -obj->cal.room_H ) / 2.0f ) + obj->min_wall_dist ) ) )
+ {
+ if ( out_pos[2] < 0.0f )
+ {
+ i = -1;
+ }
+ else
+ {
+ i = ( out_pos[2] > 0.0f ) ? ( (int32_t) 1 ) : ( (int32_t) 0 );
+ }
+ out_pos[2] = out_tmp * ( (float) i );
+ }
+}
+
+/*-----------------------------------------------------------------------------------------*
+ * Function shoebox_get_coord
+ *
+ * Transform relative spherical coordinate to 3D cartesian point
+ *-----------------------------------------------------------------------------------------*/
+
+static void shoebox_get_coord(
+ shoebox_obj_t *obj,
+ float *fcnOutput_data,
+ const float src_pos_data[],
+ float *tmp_pos,
+ float out_tmp,
+ int32_t coord,
+ int32_t loop_ub,
+ int32_t k,
+ uint16_t isRelative )
+{
+ float tmp_data[75];
+ float rcoselev;
+ int32_t tmp_size_idx_1;
+ int32_t n;
+
+ tmp_size_idx_1 = 3;
+ if ( obj->isCartesian == 0 )
+ {
+ /* Convert Spherical to Cartesian */
+ if ( obj->isRadians == 0 )
+ {
+ for ( n = 0; n < loop_ub; n++ )
+ {
+ fcnOutput_data[n] = deg2rad( src_pos_data[k + n] );
+ }
+ }
+ tmp_data[2] = fcnOutput_data[2] * sinf( fcnOutput_data[1] );
+ rcoselev = fcnOutput_data[2] * cosf( fcnOutput_data[1] );
+ tmp_data[0] = rcoselev * cosf( fcnOutput_data[0] );
+ tmp_data[1] = rcoselev * sinf( fcnOutput_data[0] );
+ }
+ else
+ {
+ /* CARTESIAN CASE */
+ tmp_size_idx_1 = loop_ub;
+ for ( n = 0; n < loop_ub; n++ )
+ {
+ tmp_data[n] = src_pos_data[k + n];
+ }
+ if ( obj->isZHeight != 0.0f )
+ {
+ /* FIX Z COORDINATE */
+ tmp_data[2] = src_pos_data[k + 2] - ( obj->cal.room_H / 2.0f );
+ }
+ }
+ for ( k = 0; k < tmp_size_idx_1; k++ )
+ {
+ obj->src_pos[( coord + k ) - 1] = tmp_data[k];
+ }
+ /* CENTER TO LISTENER */
+ if ( ( out_tmp + 1.0f ) > ( ( out_tmp + 1.0f ) + 2.0f ) )
+ {
+ k = 1;
+ }
+ else
+ {
+ k = (int32_t) ( (float) ( out_tmp + 1.0f ) );
+ }
+ tmp_pos[0] = obj->src_pos[k - 1];
+ tmp_pos[1] = obj->src_pos[k];
+ tmp_pos[2] = obj->src_pos[k + 1];
+ if ( isRelative != 0.0f )
+ {
+ tmp_pos[0] += obj->list_pos[0];
+ tmp_pos[1] += obj->list_pos[1];
+ tmp_pos[2] += obj->list_pos[2];
+ }
+}
+
+/*-----------------------------------------------------------------------------------------*
+ * Function shoebox_get_euclidian_distance_internal
+ *
+ * Get 3D source distance from receiver
+ *-----------------------------------------------------------------------------------------*/
+
+static float shoebox_get_euclidian_distance_internal(
+ shoebox_obj_t *obj,
+ float *tmp_pos,
+ float *scale )
+{
+ float absxk, out_tmp, t;
+
+ absxk = fabsf( obj->list_pos[0] - tmp_pos[0] );
+ if ( absxk > ER_EUCLIDEAN_SCALE )
+ {
+ out_tmp = 1.0f;
+ *scale = absxk;
+ }
+ else
+ {
+ t = absxk / ER_EUCLIDEAN_SCALE;
+ out_tmp = t * t;
+ }
+ absxk = fabsf( obj->list_pos[1] - tmp_pos[1] );
+ if ( absxk > *scale )
+ {
+ t = *scale / absxk;
+ out_tmp = ( ( out_tmp * t ) * t ) + 1.0f;
+ *scale = absxk;
+ }
+ else
+ {
+ t = absxk / *scale;
+ out_tmp += t * t;
+ }
+ absxk = fabsf( obj->list_pos[2] - tmp_pos[2] );
+ if ( absxk > *scale )
+ {
+ t = *scale / absxk;
+ out_tmp = ( ( out_tmp * t ) * t ) + 1.0f;
+ *scale = absxk;
+ }
+ else
+ {
+ t = absxk / *scale;
+ out_tmp += t * t;
+ }
+ return out_tmp;
+}
+
+
+/*-----------------------------------------------------------------------------------------*
+ * Function shoebox_set_scene
+ *
+ * Initial scene setup returning computed reflection (arrival times, DOA and gain).
+ *-----------------------------------------------------------------------------------------*/
+
+
+void shoebox_set_scene(
+ shoebox_obj_t *obj,
+ shoebox_output_t *ER_PARAMS,
+ const float list_pos[3],
+ const float src_pos_data[],
+ uint16_t isCartesian,
+ uint16_t isRelative )
+{
+ float tmp_pos[3];
+ float out_tmp;
+ int32_t i, j, k, n;
+ int32_t loop_ub;
+ /* ------------- SET FLAGS ------------- */
+ obj->isCartesian = isCartesian;
+ obj->isRelative = isRelative;
+ /* ------------- CHECK DIMENSIONS ------------- */
+ if ( ER_PARAMS->n_sources > obj->MAX_SOURCES )
+ {
+ obj->nSrc = obj->MAX_SOURCES;
+ }
+ else
+ {
+ obj->nSrc = ER_PARAMS->n_sources;
+ }
+ /* ---------- RESET DATA HOLDERS ---------- */
+ set_f( &obj->src_pos[0], 0.0f, 75U );
+ obj->list_pos[0] = list_pos[0];
+ obj->list_pos[1] = list_pos[1];
+ obj->list_pos[2] = list_pos[2];
+ /* ---------- ADJUST LISTENER ------------- */
+ if ( obj->isZHeight != 0 )
+ {
+ obj->list_pos[2] = list_pos[2] - ( obj->cal.room_H / 2.0f );
+ }
+ tmp_pos[1] = obj->list_pos[1];
+ tmp_pos[2] = obj->list_pos[2];
+
+ shoebox_bound( obj, obj->list_pos );
+
+ /* ---------- SOURCE LOOP ------------- */
+ i = (int32_t) obj->nSrc;
+ for ( j = 0; j < i; j++ )
+ {
+ float fcnOutput_data[75];
+ float rcoselev;
+ float scale;
+ int32_t coord;
+ /* idx = single(i); */
+ out_tmp = 3.0f * ( ( ( (float) j ) + 1.0f ) - 1.0f );
+ /* GET COORDINATE IN CARTESIAN ABSOLUTE FORMAT */
+ if ( ( out_tmp + 1.0f ) > ( ( out_tmp + 1.0f ) + 2.0f ) )
+ {
+ k = 0;
+ n = 0;
+ coord = 1;
+ }
+ else
+ {
+ k = ( (int32_t) ( (float) ( out_tmp + 1.0f ) ) ) - 1;
+ n = (int32_t) ( (float) ( ( out_tmp + 1.0f ) + 2.0f ) );
+ coord = (int32_t) ( (float) ( out_tmp + 1.0f ) );
+ }
+ loop_ub = n - k;
+ for ( n = 0; n < loop_ub; n++ )
+ {
+ fcnOutput_data[n] = src_pos_data[k + n];
+ }
+
+
+ shoebox_get_coord( obj, fcnOutput_data, src_pos_data, tmp_pos, out_tmp, coord, loop_ub, k, isRelative );
+
+ shoebox_bound( obj, tmp_pos );
+
+ scale = ER_EUCLIDEAN_SCALE;
+
+ out_tmp = shoebox_get_euclidian_distance_internal( obj, tmp_pos, &scale );
+
+ obj->src_dist[( (int32_t) ( (float) ( ( (float) j ) + 1.0f ) ) ) - 1] = scale * sqrtf( out_tmp );
+
+ /* COMPUTE PATTERNS */
+
+ /* SHOEBOX_COMPUTE: fills an input structure (4 array fields of length NxR ) with the */
+ /* Early reflection metadata (time of arrival, gain, az, el). */
+ /* */
+ /* Input: */
+ /* 1. obj : Module data holder */
+ /* 2. ER_struct : Early reflection structure */
+ /* 3. src_num : Index of source to compute patterns for */
+ /* ------ */
+ out_tmp = obj->src_dist[( (int32_t) ( (float) ( ( (float) j ) + 1.0f ) ) ) - 1];
+ for ( loop_ub = 0; loop_ub < 6; loop_ub++ )
+ {
+ float im_pos[3];
+ float path_dist;
+ /* Retrieve coordinate and surface sign */
+ coord = ( (int32_t) ceilf( ( ( (float) loop_ub ) + 1.0f ) / 2.0f ) ) - 1;
+ rcoselev = ( ( (float) loop_ub ) + 1.0f ) + ( ER_PARAMS->n_ref * ( ( ( (float) j ) + 1.0f ) - 1.0f ) );
+ /* Initialize image position coordinates */
+ im_pos[0] = tmp_pos[0];
+ im_pos[1] = tmp_pos[1];
+ im_pos[2] = tmp_pos[2];
+ /* Calculate image projection coordinate based on current surface axis */
+ if ( ( loop_ub + 1 ) < 3 )
+ {
+ scale = obj->cal.room_L;
+ }
+ else if ( ( loop_ub + 1 ) < 5 )
+ {
+ scale = obj->cal.room_W;
+ }
+ else
+ {
+ scale = obj->cal.room_H;
+ }
+ im_pos[coord] =
+ tmp_pos[coord] +
+ ( 2.0f * ( ( ( ( -( 1.0f - ( fmodf( ( (float) loop_ub ) + 1.0f, 2.0f ) * 2.0f ) ) ) * scale ) / 2.0f ) - tmp_pos[coord] ) );
+ /* 0. Get euclidean distance from IMAGE SOURCE [N,W] to LIST */
+ scale = ER_EUCLIDEAN_SCALE;
+ path_dist = shoebox_get_euclidian_distance_internal( obj, im_pos, &scale );
+
+ path_dist = scale * sqrtf( path_dist );
+ /* 1. Compute time-of arrival (TOA) */
+ ER_PARAMS->times.data[( (int32_t) rcoselev ) - 1] = path_dist / obj->soundspeed;
+ /* 2./3. DOA */
+ ER_PARAMS->az_angle.data[( (int32_t) rcoselev ) - 1] =
+ rad2deg(
+ atan2f( im_pos[1] - obj->list_pos[1], im_pos[0] - obj->list_pos[0] ) );
+ ER_PARAMS->el_angle.data[( (int32_t) rcoselev ) - 1] =
+ rad2deg(
+ asinf( ( im_pos[2] - obj->list_pos[2] ) / path_dist ) );
+ /* 4. Compute gain taking into account air and surface absorption */
+ /* and propagation loss */
+ if ( path_dist < out_tmp )
+ {
+ path_dist = out_tmp;
+ }
+ ER_PARAMS->gains.data[( (int32_t) rcoselev ) - 1] =
+ ( ( 1.0f - obj->cal.abs_coeff[loop_ub] ) * ( out_tmp / path_dist ) ) - ( path_dist * obj->air_coeff );
+ }
+ }
+}
+
+
+#endif
diff --git a/lib_rend/ivas_stat_rend.h b/lib_rend/ivas_stat_rend.h
index e0818b20ae4a19e9544a1721a2e02948bcdfd6d9..6e78e069b4c0cf15ba3e1cf543eaf40485048244 100644
--- a/lib_rend/ivas_stat_rend.h
+++ b/lib_rend/ivas_stat_rend.h
@@ -924,6 +924,13 @@ typedef struct ivas_roomAcoustics_t
float pAcoustic_dsr[CLDFB_NO_CHANNELS_MAX]; /* - The room's Diffuse to Source Ratio per center frequency */
float acousticPreDelay; /* Time elapsed between input signal and late reverberation start, float, range [0.001..10] */
float inputPreDelay; /* Offset in seconds from where DSR is computed in the RIR (0 = at source), float, range [0.001..10] */
+#ifdef EARLY_REFLECTIONS
+ int16_t use_er; /* ER activation flag */
+ int32_t lowComplexity; /* Low complexity ER flag */
+ IVAS_VECTOR3 dimensions; /* Room dimensions [m] */
+ float AbsCoeff[ER_ABS_COEFF]; /* Absorption coeffs */
+ IVAS_VECTOR3 ListenerOrigin; /* Listener origin */
+#endif
} ivas_roomAcoustics_t;
@@ -1023,6 +1030,96 @@ typedef struct ivas_reverb_state_t
} REVERB_DATA, *REVERB_HANDLE;
+#ifdef EARLY_REFLECTIONS
+/*----------------------------------------------------------------------------------*
+ * Shoebox structure
+ *----------------------------------------------------------------------------------*/
+
+/* This structure holds the original bitstream metadata */
+
+typedef struct
+{
+ float room_L;
+ float room_W;
+ float room_H;
+ float abs_coeff[ER_ABS_COEFF];
+ float list_orig[3];
+} shoebox_config_t;
+
+/* This structure holds the corrected( bounded ) source and listener positions */
+
+typedef struct
+{
+ uint16_t isCartesian;
+ uint16_t isRelative;
+ uint16_t isZHeight;
+ uint16_t isRadians;
+ uint16_t MAX_SOURCES;
+ uint16_t max_bands;
+ uint16_t REF_ORDER;
+ float src_pos[75];
+ float src_dist[25];
+ float list_pos[3];
+ uint16_t nSrc;
+ float radius;
+ float min_wall_dist;
+ float soundspeed;
+ float air_coeff;
+ shoebox_config_t cal;
+} shoebox_obj_t;
+
+
+typedef struct shoebox_data_t
+{
+ float data[150];
+ int32_t size[1];
+} shoebox_data_t;
+
+
+typedef struct
+{
+ uint16_t n_sources;
+ uint16_t n_ref;
+ shoebox_data_t times;
+ shoebox_data_t gains;
+ shoebox_data_t az_angle;
+ shoebox_data_t el_angle;
+} shoebox_output_t;
+
+#endif
+
+#ifdef EARLY_REFLECTIONS
+/*----------------------------------------------------------------------------------*
+ * Reflections structure
+ *----------------------------------------------------------------------------------*/
+
+/* This structure holds the original source positions */
+typedef struct er_struct_t
+{
+ AUDIO_CONFIG mode;
+ int16_t nchan_out;
+ uint16_t use_er;
+ uint32_t lowComplexity;
+ uint16_t n_LC_sources;
+ uint16_t *LC_mixing;
+ uint16_t is_ready;
+ uint16_t circ_len;
+ uint16_t circ_insert;
+ uint16_t n_total_reflections;
+ uint16_t is_cartesian;
+ uint16_t is_relative;
+ uint32_t max_frame_size;
+ float output_Fs;
+ float source_positions[75];
+ float user_origin[3];
+ float *circ_buffers;
+ uint16_t *closest_ch_idx;
+ shoebox_output_t shoebox_data;
+ shoebox_obj_t shoebox_lib;
+} er_struct_t;
+
+#endif
+
/*----------------------------------------------------------------------------------*
* TD ISM Object Renderer structure
*----------------------------------------------------------------------------------*/
@@ -1316,6 +1413,9 @@ typedef struct ivas_crend_state_t
REVERB_HANDLE hReverb;
int16_t delay_line_rw_index;
int16_t diffuse_delay_line_rw_index;
+#ifdef EARLY_REFLECTIONS
+ er_struct_t *reflections;
+#endif
} CREND_DATA, *CREND_HANDLE;
diff --git a/lib_rend/lib_rend.c b/lib_rend/lib_rend.c
index cbf6143e5e938f73924c4832fcb168351a414f94..253c1d84b6b5caa3c53f5093cd570fa91f2ed122 100644
--- a/lib_rend/lib_rend.c
+++ b/lib_rend/lib_rend.c
@@ -5003,6 +5003,11 @@ int16_t IVAS_REND_GetRenderConfig(
hRCout->split_rend_config.rendererSelection = hRCin->split_rend_config.rendererSelection;
#endif
+#ifdef EARLY_REFLECTIONS
+ hRCout->room_acoustics.use_er = hRCin->roomAcoustics.use_er;
+ hRCout->room_acoustics.lowComplexity = hRCin->roomAcoustics.lowComplexity;
+#endif
+
return IVAS_ERR_OK;
}
@@ -5053,6 +5058,19 @@ int16_t IVAS_REND_FeedRenderConfig(
mvr2r( renderConfig.directivity, hRenderConfig->directivity, 3 );
#endif
+#ifdef EARLY_REFLECTIONS
+ hRenderConfig->roomAcoustics.use_er = 0;
+ if ( renderConfig.room_acoustics.use_er == 1 )
+ {
+ hRenderConfig->roomAcoustics.use_er = renderConfig.room_acoustics.use_er;
+ hRenderConfig->roomAcoustics.lowComplexity = renderConfig.room_acoustics.lowComplexity;
+ hRenderConfig->roomAcoustics.dimensions = renderConfig.room_acoustics.dimensions;
+ hRenderConfig->roomAcoustics.ListenerOrigin = renderConfig.room_acoustics.ListenerOrigin;
+
+ mvr2r( renderConfig.room_acoustics.AbsCoeff, hRenderConfig->roomAcoustics.AbsCoeff, ER_ABS_COEFF );
+ }
+#endif
+
#ifdef SPLIT_REND_WITH_HEAD_ROT
hRenderConfig->split_rend_config = renderConfig.split_rend_config;
/* Overwrite any pose correction settings if 0 DOF (no pose correction) was selected */
diff --git a/lib_util/render_config_reader.c b/lib_util/render_config_reader.c
index d83875466a05d98b81a7f0bbed4bbd8b80d65800..84991c871d47c47f03f9e6c275a34836870f8db9 100644
--- a/lib_util/render_config_reader.c
+++ b/lib_util/render_config_reader.c
@@ -96,6 +96,7 @@ typedef enum _FREQ_GRID_MODE
#ifdef EARLY_REFLECTIONS
typedef struct
{
+ uint16_t use_er; /* Activation Flag */
IVAS_VECTOR3 dimensions; /* Room dimensions [m] */
float pAbsCoeff[N_ABS_COEFFS]; /* Absorption coeffs table */
IVAS_VECTOR3 *pListenerOrigin; /* Listener origin */
@@ -1251,6 +1252,10 @@ static ivas_error RenderConfigReader_checkValues(
IVAS_ROOM_ACOUSTICS_CONFIG_DATA *pRoom_acoustics;
pRoom_acoustics = &hRenderConfig->room_acoustics;
tab_value_err_count = 0;
+#ifdef EARLY_REFLECTIONS
+ int16_t wall_idx;
+#endif
+
/* Verify the number of frequency bands in the config input data */
if ( ( pRoom_acoustics->nBands > N_BANDS_MAX ) || ( pRoom_acoustics->nBands < N_BANDS_MIN ) )
@@ -1326,6 +1331,52 @@ static ivas_error RenderConfigReader_checkValues(
}
#endif /* DEBUGGING */
+
+#ifdef EARLY_REFLECTIONS
+ if ( pRoom_acoustics->use_er == 1 )
+ {
+ /* Room dimensions */
+ if ( pRoom_acoustics->dimensions.x < ER_MIN_ROOM_DIMENSION )
+ {
+ pRoom_acoustics->dimensions.x = ER_MIN_ROOM_DIMENSION;
+ }
+ if ( pRoom_acoustics->dimensions.x > ER_MAX_ROOM_DIMENSION )
+ {
+ pRoom_acoustics->dimensions.x = ER_MAX_ROOM_DIMENSION;
+ }
+ if ( pRoom_acoustics->dimensions.y < ER_MIN_ROOM_DIMENSION )
+ {
+ pRoom_acoustics->dimensions.y = ER_MIN_ROOM_DIMENSION;
+ }
+ if ( pRoom_acoustics->dimensions.y > ER_MAX_ROOM_DIMENSION )
+ {
+ pRoom_acoustics->dimensions.y = ER_MAX_ROOM_DIMENSION;
+ }
+ if ( pRoom_acoustics->dimensions.z < ER_MIN_ROOM_DIMENSION )
+ {
+ pRoom_acoustics->dimensions.z = ER_MIN_ROOM_DIMENSION;
+ }
+ if ( pRoom_acoustics->dimensions.z > ER_MAX_ROOM_DIMENSION )
+ {
+ pRoom_acoustics->dimensions.z = ER_MAX_ROOM_DIMENSION;
+ }
+
+ /* Abs Coeff */
+ for ( wall_idx = 0; wall_idx < ER_ABS_COEFF; wall_idx++ )
+ {
+ if ( pRoom_acoustics->AbsCoeff[wall_idx] < ER_MIN_ABS_COEFF )
+ {
+ pRoom_acoustics->AbsCoeff[wall_idx] = ER_MIN_ABS_COEFF;
+ }
+ if ( pRoom_acoustics->AbsCoeff[wall_idx] > ER_MAX_ABS_COEFF )
+ {
+ pRoom_acoustics->AbsCoeff[wall_idx] = ER_MAX_ABS_COEFF;
+ }
+ }
+ }
+
+#endif
+
return IVAS_ERR_OK;
}
@@ -1734,6 +1785,10 @@ static ivas_error RenderConfigReader_readBinary(
}
#ifdef EARLY_REFLECTIONS
+ /*****************************************/
+ /* Read the early reflections parameters */
+ /*****************************************/
+
/* Has early reflections */
if ( ( error = read_bin_bool( pRenderConfigReader, &value ) ) != IVAS_ERR_OK )
{
@@ -1748,6 +1803,8 @@ static ivas_error RenderConfigReader_readBinary(
/* Initialize memory pointers to allow safe freeing ico eg errors */
pRenderConfigReader->pAE[n].pEarlyReflections->pListenerOrigin = NULL;
+ pRenderConfigReader->pAE[n].pEarlyReflections->use_er = 1;
+
/* Room sizes */
if ( ( error = get_bin_distance( pRenderConfigReader, true, &pRenderConfigReader->pAE[n].pEarlyReflections->dimensions.x ) ) != IVAS_ERR_OK )
{
@@ -1812,6 +1869,16 @@ static ivas_error RenderConfigReader_readBinary(
return error;
}
}
+ else /* load defaults if origin is not specified in config */
+ {
+ if ( ( pRenderConfigReader->pAE[n].pEarlyReflections->pListenerOrigin = malloc( sizeof( IVAS_VECTOR3 ) ) ) == NULL )
+ {
+ return IVAS_ERR_FAILED_ALLOC;
+ }
+ pRenderConfigReader->pAE[n].pEarlyReflections->pListenerOrigin->x = ER_LIST_ORIGIN_X;
+ pRenderConfigReader->pAE[n].pEarlyReflections->pListenerOrigin->y = ER_LIST_ORIGIN_Y;
+ pRenderConfigReader->pAE[n].pEarlyReflections->pListenerOrigin->z = ER_LIST_HEIGHT;
+ }
/* Low complexity mode */
if ( ( error = read_bin_bool( pRenderConfigReader, &pRenderConfigReader->pAE[n].pEarlyReflections->lowComplexity ) ) != IVAS_ERR_OK )
@@ -2557,6 +2624,10 @@ ivas_error RenderConfigReader_read(
{
return IVAS_ERR_INVALID_RENDER_CONFIG;
}
+ else if ( aeHasERsize == TRUE && aeHasERabs == TRUE )
+ {
+ pRenderConfigReader->pAE[acIdx].pEarlyReflections->use_er = 1;
+ }
#endif
free( pValue );
@@ -2973,6 +3044,9 @@ ivas_error RenderConfigReader_getAcousticEnvironment(
)
{
uint16_t n, m;
+#ifdef EARLY_REFLECTIONS
+ uint16_t j;
+#endif
if ( pRenderConfigReader == NULL || pAcEnv == NULL )
{
@@ -2985,13 +3059,38 @@ ivas_error RenderConfigReader_getAcousticEnvironment(
{
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];
}
+
+#ifdef EARLY_REFLECTIONS
+ /* If ER are allocated then propagate parameters */
+ if ( pRenderConfigReader->pAE[n].pEarlyReflections != 0 )
+ {
+ pAcEnv->use_er = pRenderConfigReader->pAE[n].pEarlyReflections->use_er; /* ER activation flag */
+ pAcEnv->lowComplexity = pRenderConfigReader->pAE[n].pEarlyReflections->lowComplexity; /* Low complexity flag */
+ pAcEnv->dimensions = pRenderConfigReader->pAE[n].pEarlyReflections->dimensions;
+ /* Use default listener origin position if non provided */
+ if ( pRenderConfigReader->pAE[n].pEarlyReflections->pListenerOrigin == NULL )
+ {
+ if ( ( pRenderConfigReader->pAE[n].pEarlyReflections->pListenerOrigin = malloc( sizeof( IVAS_VECTOR3 ) ) ) == NULL )
+ {
+ return IVAS_ERR_FAILED_ALLOC;
+ }
+ pRenderConfigReader->pAE[n].pEarlyReflections->pListenerOrigin->x = ER_LIST_ORIGIN_X;
+ pRenderConfigReader->pAE[n].pEarlyReflections->pListenerOrigin->y = ER_LIST_ORIGIN_Y;
+ pRenderConfigReader->pAE[n].pEarlyReflections->pListenerOrigin->z = ER_LIST_HEIGHT;
+ }
+ pAcEnv->ListenerOrigin = *pRenderConfigReader->pAE[n].pEarlyReflections->pListenerOrigin;
+ for ( j = 0; j < QC_ABS_COEFF; j++ )
+ {
+ pAcEnv->AbsCoeff[j] = pRenderConfigReader->pAE[n].pEarlyReflections->pAbsCoeff[j];
+ }
+ }
+#endif
return IVAS_ERR_OK;
}
}
diff --git a/scripts/config/self_test.prm b/scripts/config/self_test.prm
index 205ff96f1868166aec0a20989cc952337e27f8ec..c6cca4696261a9e238d130dfdd62a3842b8f795b 100644
--- a/scripts/config/self_test.prm
+++ b/scripts/config/self_test.prm
@@ -1167,6 +1167,22 @@
../IVAS_cod -mc 7_1_4 512000 48 testv/stv714MC48c.wav bit
../IVAS_dec -render_config testv/rend_config_renderer.cfg BINAURAL_ROOM_REVERB 48 bit testv/stv714MC48c.wav_MC714_512000_48-48_MC_Config_renderer.tst
+// Multi-channel 7_1_4 at 512 kbps, 48kHz in, 48kHz out, BINAURAL_ROOM out Config early reflections
+../IVAS_cod -mc 7_1_4 512000 48 testv/stv714MC48c.wav bit
+../IVAS_dec -render_config testv/rend_config_ER_v1.cfg BINAURAL_ROOM_REVERB 48 bit testv/stv714MC48c.wav_MC714_512000_48-48_ER_v1.tst
+
+// Multi-channel 7_1_4 at 512 kbps, 48kHz in, 48kHz out, BINAURAL_ROOM out Config early reflections, listener origin
+../IVAS_cod -mc 7_1_4 512000 48 testv/stv714MC48c.wav bit
+../IVAS_dec -render_config testv/rend_config_ER_v2.cfg BINAURAL_ROOM_REVERB 48 bit testv/stv714MC48c.wav_MC714_512000_48-48_MC_ER_v2.tst
+
+// Multi-channel 7_1_4 at 512 kbps, 48kHz in, 48kHz out, BINAURAL_ROOM out Config early reflections, low complexity, listener origin
+../IVAS_cod -mc 7_1_4 512000 48 testv/stv714MC48c.wav bit
+../IVAS_dec -render_config testv/rend_config_ER_v3.cfg BINAURAL_ROOM_REVERB 48 bit testv/stv714MC48c.wav_MC714_512000_48-48_MC_ER_v3.tst
+
+// Multi-channel 5_1 at 512 kbps, 48kHz in, 48kHz out, BINAURAL_ROOM out Config early reflections, head rotation
+../IVAS_cod -mc 5_1 512000 48 testv/stv51MC48c.wav bit
+../IVAS_dec -render_config testv/rend_config_ER_v1.cfg -t testv/headrot_case00_3000_q.csv BINAURAL_ROOM_REVERB 48 bit testv/stv51MC48c.wav_MC51_512000_48-48_MC_ER_v1_hrot.tst
+
// Multi-channel 5_1 bitrate switching from 13.2 kbps to 512 kbps, 48kHz in, 48kHz out, 7_1_4 out
../IVAS_cod -mc 5_1 ../scripts/switchPaths/sw_mctech_5fr.bin 48 testv/stv51MC48c.wav bit
../IVAS_dec 7_1_4 48 bit testv/stv51MC48c.wav_sw_48-48_7_1_4.tst
diff --git a/scripts/reverb/generate_acoustic_environments_metadata.py b/scripts/reverb/generate_acoustic_environments_metadata.py
index 6c771319958276cadc67e132306689a87ddcf82e..5cd6195d03b8c46a9a744de3a443b84ad28f3876 100644
--- a/scripts/reverb/generate_acoustic_environments_metadata.py
+++ b/scripts/reverb/generate_acoustic_environments_metadata.py
@@ -499,13 +499,11 @@ def generate_reverb_payload_equivalent_to_rend_config_renderer_cfg_plus_early_re
+ '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')
@@ -557,8 +555,6 @@ def generate_reverb_payload_equivalent_to_rend_config_renderer_cfg_plus_early_re
+ '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 ])
@@ -723,6 +719,233 @@ def generate_reverb_payload_equivalent_to_rend_config_recreation_cfg():
file.close()
+def generate_reverb_payload_ER_v0():
+ # 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(1) # fgdNrGrids
+ # frequency grid
+ + fgdMethod.Individual_Frequencies.value # fgdMethod
+ + get_count_or_index_code(24) # fgdNrBands
+
+ + concatenate(get_frequency_code, # fgdCenterFreq
+ [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])
+
+ + 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
+ [0.87, 0.66, 0.47, 0.41,
+ 0.32, 0.37, 0.28, 0.30,
+ 0.29, 0.29, 0.28, 0.30,
+ 0.31, 0.34, 0.34, 0.34,
+ 0.34, 0.33, 0.32, 0.29,
+ 0.28, 0.24, 0.24, 0.2])
+
+ + concatenate(get_dsr_code, # DSR
+ [2.511887e-07, 1e-07, 1.2589251e-07, 1e-07,
+ 5.01187e-08, 5.01187e-08, 7.9432844e-08, 1e-07,
+ 6.309576e-08, 5.01187e-08, 7.9432844e-08, 1e-07,
+ 5.01187e-08, 1e-07, 7.9432844e-08, 6.309576e-08,
+ 7.9432844e-08, 5.01187e-08, 6.309576e-08, 3.9810708e-08,
+ 3.9810708e-08, 2.511887e-08, 1.9952632e-08, 1.2589251e-08])
+
+ + '1' # hasEarlyReflections
+ + concatenate(lambda code : get_distance_code(code, True),
+ [ 2.0, 2.0, 3.0 ]) # room dimensions
+ + concatenate(get_absorption_code, # absorptionCode
+ [ 0.2, 0.1, 0.1, 0.1, 0.3, 0.1 ])
+ + '1' # listener origin flag
+ + '1' # isPositiveX
+ + '1' # isPositiveY
+ + concatenate(lambda d : get_distance_code(d, True),
+ [ 0.0, 0.0, 1.5 ]) # listener origin (x, y, z)
+ + '1' # lowComplexity
+ + '0' # directivity
+ , endian='big')
+
+ file = open('rend_config_ER_v0.dat', 'wb')
+ data.tofile(file)
+ file.close()
+
+
+def generate_reverb_payload_ER_v1():
+ # 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(1) # fgdNrGrids
+ # frequency grid
+ + fgdMethod.Individual_Frequencies.value # fgdMethod
+ + get_count_or_index_code(24) # fgdNrBands
+
+ + concatenate(get_frequency_code, # fgdCenterFreq
+ [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])
+
+ + 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
+ [0.87, 0.66, 0.47, 0.41,
+ 0.32, 0.37, 0.28, 0.30,
+ 0.29, 0.29, 0.28, 0.30,
+ 0.31, 0.34, 0.34, 0.34,
+ 0.34, 0.33, 0.32, 0.29,
+ 0.28, 0.24, 0.24, 0.2])
+
+ + concatenate(get_dsr_code, # DSR
+ [2.511887e-07, 1e-07, 1.2589251e-07, 1e-07,
+ 5.01187e-08, 5.01187e-08, 7.9432844e-08, 1e-07,
+ 6.309576e-08, 5.01187e-08, 7.9432844e-08, 1e-07,
+ 5.01187e-08, 1e-07, 7.9432844e-08, 6.309576e-08,
+ 7.9432844e-08, 5.01187e-08, 6.309576e-08, 3.9810708e-08,
+ 3.9810708e-08, 2.511887e-08, 1.9952632e-08, 1.2589251e-08])
+
+ + '1' # hasEarlyReflections
+ + concatenate(lambda code : get_distance_code(code, True),
+ [ 3.0, 3.0, 4.0 ]) # room dimensions
+ + concatenate(get_absorption_code, # absorptionCode
+ [ 0.3, 0.2, 0.2, 0.2, 0.3, 0.1 ])
+ + '0' # listener origin flag
+ + '0' # lowComplexity
+ + '0' # directivity
+ , endian='big')
+
+ file = open('rend_config_ER_v1.dat', 'wb')
+ data.tofile(file)
+ file.close()
+
+def generate_reverb_payload_ER_v2():
+ # 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(1) # fgdNrGrids
+ # frequency grid
+ + fgdMethod.Individual_Frequencies.value # fgdMethod
+ + get_count_or_index_code(24) # fgdNrBands
+
+ + concatenate(get_frequency_code, # fgdCenterFreq
+ [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])
+
+ + 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
+ [0.87, 0.66, 0.47, 0.41,
+ 0.32, 0.37, 0.28, 0.30,
+ 0.29, 0.29, 0.28, 0.30,
+ 0.31, 0.34, 0.34, 0.34,
+ 0.34, 0.33, 0.32, 0.29,
+ 0.28, 0.24, 0.24, 0.2])
+
+ + concatenate(get_dsr_code, # DSR
+ [2.511887e-07, 1e-07, 1.2589251e-07, 1e-07,
+ 5.01187e-08, 5.01187e-08, 7.9432844e-08, 1e-07,
+ 6.309576e-08, 5.01187e-08, 7.9432844e-08, 1e-07,
+ 5.01187e-08, 1e-07, 7.9432844e-08, 6.309576e-08,
+ 7.9432844e-08, 5.01187e-08, 6.309576e-08, 3.9810708e-08,
+ 3.9810708e-08, 2.511887e-08, 1.9952632e-08, 1.2589251e-08])
+
+ + '1' # hasEarlyReflections
+ + concatenate(lambda code : get_distance_code(code, True),
+ [ 3.0, 3.0, 4.0 ]) # room dimensions
+ + concatenate(get_absorption_code, # absorptionCode
+ [ 0.3, 0.2, 0.3, 0.4, 0.3, 0.4 ])
+ + '1' # listener origin flag
+ + '1' # isPositiveX
+ + '0' # isPositiveY
+ + concatenate(lambda d : get_distance_code(d, True),
+ [ 0.5, 0.5, 1.5]) # listener origin (x, y, z)
+ + '0' # lowComplexity
+ + '0' # directivity
+ , endian='big')
+
+ file = open('rend_config_ER_v2.dat', 'wb')
+ data.tofile(file)
+ file.close()
+
+
+def generate_reverb_payload_ER_v3():
+ # 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(1) # fgdNrGrids
+ # frequency grid
+ + fgdMethod.Individual_Frequencies.value # fgdMethod
+ + get_count_or_index_code(24) # fgdNrBands
+
+ + concatenate(get_frequency_code, # fgdCenterFreq
+ [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])
+
+ + 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
+ [0.87, 0.66, 0.47, 0.41,
+ 0.32, 0.37, 0.28, 0.30,
+ 0.29, 0.29, 0.28, 0.30,
+ 0.31, 0.34, 0.34, 0.34,
+ 0.34, 0.33, 0.32, 0.29,
+ 0.28, 0.24, 0.24, 0.2])
+
+ + concatenate(get_dsr_code, # DSR
+ [2.511887e-07, 1e-07, 1.2589251e-07, 1e-07,
+ 5.01187e-08, 5.01187e-08, 7.9432844e-08, 1e-07,
+ 6.309576e-08, 5.01187e-08, 7.9432844e-08, 1e-07,
+ 5.01187e-08, 1e-07, 7.9432844e-08, 6.309576e-08,
+ 7.9432844e-08, 5.01187e-08, 6.309576e-08, 3.9810708e-08,
+ 3.9810708e-08, 2.511887e-08, 1.9952632e-08, 1.2589251e-08])
+
+ + '1' # hasEarlyReflections
+ + concatenate(lambda code : get_distance_code(code, True),
+ [4.0, 4.0, 5.0]) # room dimensions
+ + concatenate(get_absorption_code, # absorptionCode
+ [0.1, 0.2, 0.2, 0.2, 0.1, 0.1])
+ + '1' # listener origin flag
+ + '0' # isPositiveX
+ + '1' # isPositiveY
+ + concatenate(lambda d : get_distance_code(d, True),
+ [ 1.0, 0.5, 1.5]) # listener origin (x, y, z)
+ + '1' # lowComplexity
+ + '0' # directivity
+ , endian='big')
+
+ file = open('rend_config_ER_v3.dat', 'wb')
+ data.tofile(file)
+ file.close()
+
+
if __name__ == "__main__":
#test()
generate_reverb_payload_equivalent_to_rend_config_renderer_cfg()
@@ -731,6 +954,12 @@ if __name__ == "__main__":
generate_reverb_payload_equivalent_to_rend_config_renderer_directivity_cfg()
generate_reverb_payload_equivalent_to_config_directivity_cfg()
+ # generate_reverb_payload_aggressive_ER()
+
+ generate_reverb_payload_ER_v0()
+ generate_reverb_payload_ER_v1()
+ generate_reverb_payload_ER_v2()
+ generate_reverb_payload_ER_v3()
- #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()
+ # 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()
\ No newline at end of file
diff --git a/scripts/testv/rend_config_ER_v0.cfg b/scripts/testv/rend_config_ER_v0.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..1d3e6fa4f828daa1c8699e9a3d195da4b87cfdd2
--- /dev/null
+++ b/scripts/testv/rend_config_ER_v0.cfg
@@ -0,0 +1,38 @@
+[roomAcoustics]
+frequencyGridCount = 1;
+acousticEnvironmentCount = 1;
+
+[frequencyGrid:0]
+method = individualFrequencies;
+nrBands = 24;
+frequencies = [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];
+
+[acousticEnvironment:0]
+frequencyGridIndex = 0;
+predelay = 0.108;
+rt60 = [0.87, 0.66, 0.47, 0.41,
+ 0.32, 0.37, 0.28, 0.30,
+ 0.29, 0.29, 0.28, 0.30,
+ 0.31, 0.34, 0.34, 0.34,
+ 0.34, 0.33, 0.32, 0.29,
+ 0.28, 0.24, 0.24, 0.2];
+
+dsr = [2.511887e-07, 1e-07, 1.2589251e-07, 1e-07,
+ 5.01187e-08, 5.01187e-08, 7.9432844e-08, 1e-07,
+ 6.309576e-08, 5.01187e-08, 7.9432844e-08, 1e-07,
+ 5.01187e-08, 1e-07, 7.9432844e-08, 6.309576e-08,
+ 7.9432844e-08, 5.01187e-08, 6.309576e-08, 3.9810708e-08,
+ 3.9810708e-08, 2.511887e-08, 1.9952632e-08, 1.2589251e-08];
+
+earlyReflectionsSize = [ 2.0, 2.0, 3.0 ];
+absorptionCoeffs = [ 0.2, 0.1, 0.1, 0.1, 0.3, 0.1 ];
+lowComplexity = TRUE;
+listenerOrigin = [ 0.0, 0.0, 1.5 ];
+
+#[general]
+#binaryConfig = rend_config_ER_v0.dat;
\ No newline at end of file
diff --git a/scripts/testv/rend_config_ER_v0.dat b/scripts/testv/rend_config_ER_v0.dat
new file mode 100644
index 0000000000000000000000000000000000000000..af1e7ffa16110a821969c2ea24c546d561f0eff3
--- /dev/null
+++ b/scripts/testv/rend_config_ER_v0.dat
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a0e5cdb59fa93168feb1d4b973b1b2c2128fe103db5422b5ac4249f51bbf45a0
+size 84
diff --git a/scripts/testv/rend_config_ER_v1.cfg b/scripts/testv/rend_config_ER_v1.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..3a6228e863af293bc936b389b475edaa70f4e6b6
--- /dev/null
+++ b/scripts/testv/rend_config_ER_v1.cfg
@@ -0,0 +1,37 @@
+[roomAcoustics]
+frequencyGridCount = 1;
+acousticEnvironmentCount = 1;
+
+[frequencyGrid:0]
+method = individualFrequencies;
+nrBands = 24;
+frequencies = [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];
+
+[acousticEnvironment:0]
+frequencyGridIndex = 0;
+predelay = 0.108;
+rt60 = [0.87, 0.66, 0.47, 0.41,
+ 0.32, 0.37, 0.28, 0.30,
+ 0.29, 0.29, 0.28, 0.30,
+ 0.31, 0.34, 0.34, 0.34,
+ 0.34, 0.33, 0.32, 0.29,
+ 0.28, 0.24, 0.24, 0.2];
+
+dsr = [2.511887e-07, 1e-07, 1.2589251e-07, 1e-07,
+ 5.01187e-08, 5.01187e-08, 7.9432844e-08, 1e-07,
+ 6.309576e-08, 5.01187e-08, 7.9432844e-08, 1e-07,
+ 5.01187e-08, 1e-07, 7.9432844e-08, 6.309576e-08,
+ 7.9432844e-08, 5.01187e-08, 6.309576e-08, 3.9810708e-08,
+ 3.9810708e-08, 2.511887e-08, 1.9952632e-08, 1.2589251e-08];
+
+earlyReflectionsSize = [3.0, 3.0, 4.0];
+absorptionCoeffs = [ 0.3, 0.2, 0.2, 0.2, 0.3, 0.1 ];
+lowComplexity = FALSE;
+
+#[general]
+#binaryConfig = rend_config_ER_v1.dat;
\ No newline at end of file
diff --git a/scripts/testv/rend_config_ER_v1.dat b/scripts/testv/rend_config_ER_v1.dat
new file mode 100644
index 0000000000000000000000000000000000000000..187af6705809c39800245499f319764f78d05693
--- /dev/null
+++ b/scripts/testv/rend_config_ER_v1.dat
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:4a92c702caf083634ffbcbd013d5c7fe2ad5bf09ebd4440c1021e9b56b3f33ae
+size 80
diff --git a/scripts/testv/rend_config_ER_v2.cfg b/scripts/testv/rend_config_ER_v2.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..2d504af6ba2105df3fb012a87c480a604f211f78
--- /dev/null
+++ b/scripts/testv/rend_config_ER_v2.cfg
@@ -0,0 +1,38 @@
+[roomAcoustics]
+frequencyGridCount = 1;
+acousticEnvironmentCount = 1;
+
+[frequencyGrid:0]
+method = individualFrequencies;
+nrBands = 24;
+frequencies = [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];
+
+[acousticEnvironment:0]
+frequencyGridIndex = 0;
+predelay = 0.108;
+rt60 = [0.87, 0.66, 0.47, 0.41,
+ 0.32, 0.37, 0.28, 0.30,
+ 0.29, 0.29, 0.28, 0.30,
+ 0.31, 0.34, 0.34, 0.34,
+ 0.34, 0.33, 0.32, 0.29,
+ 0.28, 0.24, 0.24, 0.2];
+
+dsr = [2.511887e-07, 1e-07, 1.2589251e-07, 1e-07,
+ 5.01187e-08, 5.01187e-08, 7.9432844e-08, 1e-07,
+ 6.309576e-08, 5.01187e-08, 7.9432844e-08, 1e-07,
+ 5.01187e-08, 1e-07, 7.9432844e-08, 6.309576e-08,
+ 7.9432844e-08, 5.01187e-08, 6.309576e-08, 3.9810708e-08,
+ 3.9810708e-08, 2.511887e-08, 1.9952632e-08, 1.2589251e-08];
+
+earlyReflectionsSize = [3.0, 3.0, 4.0];
+absorptionCoeffs = [ 0.3, 0.2, 0.3, 0.4, 0.3, 0.4 ];
+lowComplexity = FALSE;
+listenerOrigin = [0.5, -0.5, 1.5];
+
+#[general]
+#binaryConfig = rend_config_ER_v2.dat;
\ No newline at end of file
diff --git a/scripts/testv/rend_config_ER_v2.dat b/scripts/testv/rend_config_ER_v2.dat
new file mode 100644
index 0000000000000000000000000000000000000000..57cc0ca3118d23a7e6d74ff8b23e6fe0bd6011e6
--- /dev/null
+++ b/scripts/testv/rend_config_ER_v2.dat
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:75503e1e51276c3980f4bcf1a31a9fe632e3b14e88fe18652c7f17697aa580e5
+size 86
diff --git a/scripts/testv/rend_config_ER_v3.cfg b/scripts/testv/rend_config_ER_v3.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..a70c644a8a372e000caf3c69715821bdacda90c7
--- /dev/null
+++ b/scripts/testv/rend_config_ER_v3.cfg
@@ -0,0 +1,38 @@
+[roomAcoustics]
+frequencyGridCount = 1;
+acousticEnvironmentCount = 1;
+
+[frequencyGrid:0]
+method = individualFrequencies;
+nrBands = 24;
+frequencies = [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];
+
+[acousticEnvironment:0]
+frequencyGridIndex = 0;
+predelay = 0.108;
+rt60 = [0.87, 0.66, 0.47, 0.41,
+ 0.32, 0.37, 0.28, 0.30,
+ 0.29, 0.29, 0.28, 0.30,
+ 0.31, 0.34, 0.34, 0.34,
+ 0.34, 0.33, 0.32, 0.29,
+ 0.28, 0.24, 0.24, 0.2];
+
+dsr = [2.511887e-07, 1e-07, 1.2589251e-07, 1e-07,
+ 5.01187e-08, 5.01187e-08, 7.9432844e-08, 1e-07,
+ 6.309576e-08, 5.01187e-08, 7.9432844e-08, 1e-07,
+ 5.01187e-08, 1e-07, 7.9432844e-08, 6.309576e-08,
+ 7.9432844e-08, 5.01187e-08, 6.309576e-08, 3.9810708e-08,
+ 3.9810708e-08, 2.511887e-08, 1.9952632e-08, 1.2589251e-08];
+
+earlyReflectionsSize = [4.0, 4.0, 5.0];
+absorptionCoeffs = [ 0.1, 0.2, 0.2, 0.2, 0.1, 0.1 ];
+lowComplexity = TRUE;
+listenerOrigin = [-1, 0.5, 1.5];
+
+#[general]
+#binaryConfig = rend_config_ER_v3.dat;
\ No newline at end of file
diff --git a/scripts/testv/rend_config_ER_v3.dat b/scripts/testv/rend_config_ER_v3.dat
new file mode 100644
index 0000000000000000000000000000000000000000..280cf26d0d9b2b24f827be29002505f179283392
--- /dev/null
+++ b/scripts/testv/rend_config_ER_v3.dat
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:425e97bd84110a35bd204a5d7f60e2e01cc2e1e96611ed3bca4b5877380194d3
+size 85
diff --git a/scripts/testv/rend_config_renderer_cfg_plus_early_reflections_listener_origin.cfg b/scripts/testv/rend_config_renderer_cfg_plus_early_reflections_listener_origin.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..ead63890b5b0f400b4876679d314ca90fa968384
--- /dev/null
+++ b/scripts/testv/rend_config_renderer_cfg_plus_early_reflections_listener_origin.cfg
@@ -0,0 +1,2 @@
+[general]
+binaryConfig = rend_config_renderer_cfg_plus_early_reflections_listener_origin.dat;
\ No newline at end of file
diff --git a/scripts/testv/rend_config_renderer_cfg_plus_early_reflections_listener_origin.dat b/scripts/testv/rend_config_renderer_cfg_plus_early_reflections_listener_origin.dat
new file mode 100644
index 0000000000000000000000000000000000000000..4d16889420b92e61443e943ad8147c0ea4fbb244
--- /dev/null
+++ b/scripts/testv/rend_config_renderer_cfg_plus_early_reflections_listener_origin.dat
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ff2025be8627eeaa88a58417ebf4a8bc02ef648e87897a63ef2e45a88e67565b
+size 145
diff --git a/scripts/testv/rend_config_renderer_cfg_plus_early_reflections_no_listener_origin.cfg b/scripts/testv/rend_config_renderer_cfg_plus_early_reflections_no_listener_origin.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..2f122473c67ac7e57e5bf8c2a8f8a9cec21320df
--- /dev/null
+++ b/scripts/testv/rend_config_renderer_cfg_plus_early_reflections_no_listener_origin.cfg
@@ -0,0 +1,2 @@
+[general]
+binaryConfig = rend_config_renderer_cfg_plus_early_reflections_no_listener_origin.dat;
\ No newline at end of file
diff --git a/scripts/testv/rend_config_renderer_cfg_plus_early_reflections_no_listener_origin.dat b/scripts/testv/rend_config_renderer_cfg_plus_early_reflections_no_listener_origin.dat
new file mode 100644
index 0000000000000000000000000000000000000000..39b5aaf89a866eac6309a4580152814ea03586a2
--- /dev/null
+++ b/scripts/testv/rend_config_renderer_cfg_plus_early_reflections_no_listener_origin.dat
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:5bab8146537e4d7051a727587d950ac73e857764cb5fa1a09fdb1c4323f470ea
+size 139