diff --git a/Workspace_msvc/lib_util.vcxproj b/Workspace_msvc/lib_util.vcxproj
index 79e5545f3fee266b8433f1b74a1926d40b570aa5..4ec7948021793313475e6f86c8e5084b7364fed0 100644
--- a/Workspace_msvc/lib_util.vcxproj
+++ b/Workspace_msvc/lib_util.vcxproj
@@ -101,6 +101,7 @@
+
@@ -128,6 +129,7 @@
+
diff --git a/lib_util/ambi_convert.c b/lib_util/ambi_convert.c
new file mode 100644
index 0000000000000000000000000000000000000000..92711b8e61c5b7c7bd75d93753a365313696de89
--- /dev/null
+++ b/lib_util/ambi_convert.c
@@ -0,0 +1,438 @@
+/******************************************************************************************************
+
+ (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository. All Rights Reserved.
+
+ This software is protected by copyright law and by international treaties.
+ The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository retain full ownership rights in their respective contributions in
+ the software. This notice grants no license of any kind, including but not limited to patent
+ license, nor is any license granted by implication, estoppel or otherwise.
+
+ Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
+ contributions.
+
+ This software is provided "AS IS", without any express or implied warranties. The software is in the
+ development stage. It is intended exclusively for experts who have experience with such software and
+ solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
+ and fitness for a particular purpose are hereby disclaimed and excluded.
+
+ Any dispute, controversy or claim arising under or in relation to providing this software shall be
+ submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
+ accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
+ the United Nations Convention on Contracts on the International Sales of Goods.
+
+*******************************************************************************************************/
+#include
+#include
+#include
+#include "ambi_convert.h"
+
+#define SQRT_2_ 1.4142135f /* sqrtf(2.0f) */
+#define SQRT_3_ 1.7320508f /* sqrtf(3.0f) */
+#define SQRT_5_ 2.2360679f /* sqrtf(5.0f) */
+#define SQRT_7_ 2.6457513f /* sqrtf(7.0f) */
+
+#define INV_SQRT_2_ 0.7071067f /* 1.0f/sqrtf(2.0f) */
+#define INV_SQRT_3_ 0.5773502f /* 1.0f/sqrtf(3.0f) */
+#define INV_SQRT_5_ 0.4472135f /* 1.0f/sqrtf(5.0f) */
+#define INV_SQRT_7_ 0.3779644f /* 1.0f/sqrtf(7.0f) */
+
+#define TWO_OVER_SQRT_3_ 1.1547005f /* 2.0f/sqrtf(3.0f) */
+#define THREE_OVER_SQRT_5_ 1.3416408f /* 3.0f/sqrtf(5.0f) */
+#define SQRT_8_OVER_5_ 1.2649110f /* sqrtf(8.0f/5.0f) */
+#define SQRT_45_OVER_32_ 1.1858541f /* sqrtf(45.0f/32.0f) */
+
+#define INV_TWO_OVER_SQRT_3_ 0.8660254f /* 1.0f/TWO_OVER_SQRT_3_ */
+#define INV_THREE_OVER_SQRT_5_ 0.7453560f /* 1.0f/THREE_OVER_SQRT_5_ */
+#define INV_SQRT_8_OVER_5_ 0.7905694f /* 1.0f/INV_SQRT_8_OVER_5_ */
+#define INV_SQRT_45_OVER_32_ 0.8432740f /* 1.0f/SQRT_45_OVER_32_ */
+
+/* --------------------------------
+ normalization conversion tables
+ -------------------------------- */
+
+static const float SN3D_N3D[AMBI_MAX_CHANNELS] = { 1.0f,
+ SQRT_3_, SQRT_3_, SQRT_3_,
+ SQRT_5_, SQRT_5_, SQRT_5_, SQRT_5_, SQRT_5_,
+ SQRT_7_, SQRT_7_, SQRT_7_, SQRT_7_, SQRT_7_, SQRT_7_, SQRT_7_ };
+
+static const float N3D_SN3D[AMBI_MAX_CHANNELS] = { 1.0f,
+ INV_SQRT_3_, INV_SQRT_3_, INV_SQRT_3_,
+ INV_SQRT_5_, INV_SQRT_5_, INV_SQRT_5_, INV_SQRT_5_, INV_SQRT_5_,
+ INV_SQRT_7_, INV_SQRT_7_, INV_SQRT_7_, INV_SQRT_7_, INV_SQRT_7_, INV_SQRT_7_, INV_SQRT_7_ };
+
+
+static const float SN3D_MAXN[AMBI_MAX_CHANNELS] = { 1.0f,
+ 1.0f, 1.0f, 1.0f,
+ TWO_OVER_SQRT_3_, TWO_OVER_SQRT_3_, 1.0f, TWO_OVER_SQRT_3_, TWO_OVER_SQRT_3_,
+ SQRT_8_OVER_5_, THREE_OVER_SQRT_5_, SQRT_45_OVER_32_, 1.0f, SQRT_45_OVER_32_, THREE_OVER_SQRT_5_, SQRT_8_OVER_5_ };
+
+static const float MAXN_SN3D[AMBI_MAX_CHANNELS] = { 1.0f,
+ 1.0f, 1.0f, 1.0f,
+ INV_TWO_OVER_SQRT_3_, INV_TWO_OVER_SQRT_3_, 1.0f, INV_TWO_OVER_SQRT_3_, INV_TWO_OVER_SQRT_3_,
+ INV_SQRT_8_OVER_5_, INV_THREE_OVER_SQRT_5_, INV_SQRT_45_OVER_32_, 1.0f, INV_SQRT_45_OVER_32_, INV_THREE_OVER_SQRT_5_, INV_SQRT_8_OVER_5_ };
+
+static const float SN3D_FM[AMBI_MAX_CHANNELS] = { INV_SQRT_2_,
+ 1.0f, 1.0f, 1.0f,
+ TWO_OVER_SQRT_3_, TWO_OVER_SQRT_3_, 1.0f, TWO_OVER_SQRT_3_, TWO_OVER_SQRT_3_,
+ SQRT_8_OVER_5_, THREE_OVER_SQRT_5_, SQRT_45_OVER_32_, 1.0f, SQRT_45_OVER_32_, THREE_OVER_SQRT_5_, SQRT_8_OVER_5_ };
+
+static const float FM_SN3D[AMBI_MAX_CHANNELS] = { SQRT_2_,
+ 1.0f, 1.0f, 1.0f,
+ INV_TWO_OVER_SQRT_3_, INV_TWO_OVER_SQRT_3_, 1.0f, INV_TWO_OVER_SQRT_3_, INV_TWO_OVER_SQRT_3_,
+ INV_SQRT_8_OVER_5_, INV_THREE_OVER_SQRT_5_, INV_SQRT_45_OVER_32_, 1.0f, INV_SQRT_45_OVER_32_, INV_THREE_OVER_SQRT_5_, INV_SQRT_8_OVER_5_ };
+
+/* ----------------------------
+ channel re-ordering tables
+ ---------------------------- */
+
+static const int16_t REORDER_FM_ACN[AMBI_MAX_CHANNELS] = { 0,
+ 2, 3, 1,
+ 8, 6, 4, 5, 7,
+ 15, 13, 11, 9, 10, 12, 14 };
+
+static const int16_t REORDER_SID_ACN[AMBI_MAX_CHANNELS] = { 0,
+ 2, 3, 1,
+ 5, 7, 8, 6, 4,
+ 10, 12, 14, 15, 13, 11, 9 };
+
+static const int16_t REORDER_ACN_FM[AMBI_MAX_CHANNELS] = { 0,
+ 3, 1, 2,
+ 6, 7, 5, 8, 4,
+ 12, 13, 11, 14, 10, 15, 9 };
+
+static const int16_t REORDER_ACN_SID[AMBI_MAX_CHANNELS] = { 0,
+ 3, 1, 2,
+ 8, 4, 7, 5, 6,
+ 15, 9, 14, 10, 13, 11, 12 };
+
+/* ----------------------------------
+ API functions for the conversion
+ ---------------------------------- */
+
+/*-------------------------------------------------------------------------*
+* convert_ambi_format()
+*
+* Convert signal between ACN-SN3D and other common ambisonics conventions
+--------------------------------------------------------------------------*/
+
+AMBI_CONVERT_ERROR convert_ambi_format(
+ float *in[], /* i: input ambisonics channels */
+ float *out[], /* o: output ambisonics channels */
+ int16_t order, /* i: ambisonics order */
+ AMBI_FMT in_format, /* i: input ambisonics format */
+ AMBI_FMT out_format /* i: output ambisonics format */
+)
+{
+
+ float tmp[AMBI_MAX_CHANNELS * L_FRAME48k];
+ float *p_tmp[AMBI_MAX_CHANNELS];
+ AMBI_CONVERT_ERROR err = AMBI_CONVERT_OK;
+
+ AMBI_CHANNEL_ORDER ch_ord_in = AMBI_CHANNEL_ORDER_ACN;
+ AMBI_CHANNEL_ORDER ch_ord_out = AMBI_CHANNEL_ORDER_ACN;
+
+ AMBI_CHANNEL_NORM ch_norm_in = AMBI_NORM_SN3D;
+ AMBI_CHANNEL_NORM ch_norm_out = AMBI_NORM_SN3D;
+
+ assert( order <= 3 );
+
+ if ( in_format != AMBI_FMT_ACN_SN3D && out_format != AMBI_FMT_ACN_SN3D )
+ {
+ assert( 0 && "Conversion only supported to and from ACN-SN3D" );
+ }
+
+ for ( int16_t j = 0; j < AMBI_MAX_CHANNELS; j++ )
+ {
+ p_tmp[j] = &tmp[j * L_FRAME48k];
+ }
+
+ switch ( in_format )
+ {
+ case AMBI_FMT_ACN_SN3D:
+ ch_ord_in = AMBI_CHANNEL_ORDER_ACN;
+ ch_norm_in = AMBI_NORM_SN3D;
+ break;
+ case AMBI_FMT_ACN_N3D:
+ ch_ord_in = AMBI_CHANNEL_ORDER_ACN;
+ ch_norm_in = AMBI_NORM_N3D;
+ break;
+ case AMBI_FMT_FM_MAXN:
+ ch_ord_in = AMBI_CHANNEL_ORDER_FM;
+ ch_norm_in = AMBI_NORM_MAXN;
+ break;
+ case AMBI_FMT_FM_FM:
+ ch_ord_in = AMBI_CHANNEL_ORDER_FM;
+ ch_norm_in = AMBI_NORM_FM;
+ break;
+ case AMBI_FMT_SID_SN3D:
+ ch_ord_in = AMBI_CHANNEL_ORDER_SID;
+ ch_norm_in = AMBI_NORM_SN3D;
+ break;
+ case AMBI_FMT_SID_N3D:
+ ch_ord_in = AMBI_CHANNEL_ORDER_SID;
+ ch_norm_in = AMBI_NORM_N3D;
+ break;
+ default:
+ return AMBI_CONVERT_UNSUPPORTED_CONVERSION;
+ }
+
+ switch ( out_format )
+ {
+ case AMBI_FMT_ACN_SN3D:
+ ch_ord_out = AMBI_CHANNEL_ORDER_ACN;
+ ch_norm_out = AMBI_NORM_SN3D;
+ break;
+ case AMBI_FMT_ACN_N3D:
+ ch_ord_out = AMBI_CHANNEL_ORDER_ACN;
+ ch_norm_out = AMBI_NORM_N3D;
+ break;
+ case AMBI_FMT_FM_MAXN:
+ ch_ord_out = AMBI_CHANNEL_ORDER_FM;
+ ch_norm_out = AMBI_NORM_MAXN;
+ break;
+ case AMBI_FMT_FM_FM:
+ ch_ord_out = AMBI_CHANNEL_ORDER_FM;
+ ch_norm_out = AMBI_NORM_FM;
+ break;
+ case AMBI_FMT_SID_SN3D:
+ ch_ord_out = AMBI_CHANNEL_ORDER_SID;
+ ch_norm_out = AMBI_NORM_SN3D;
+ break;
+ case AMBI_FMT_SID_N3D:
+ ch_ord_out = AMBI_CHANNEL_ORDER_SID;
+ ch_norm_out = AMBI_NORM_N3D;
+ break;
+ default:
+ return AMBI_CONVERT_UNSUPPORTED_CONVERSION;
+ }
+
+ if ( in_format == AMBI_FMT_ACN_SN3D && ch_norm_in != ch_norm_out )
+ {
+ if ( ch_ord_in != ch_ord_out )
+ {
+ if ( ( err = renormalize_channels( in, p_tmp, order, ch_norm_in, ch_norm_out ) ) != AMBI_CONVERT_OK )
+ {
+ return err;
+ }
+ if ( ( err = reorder_channels( p_tmp, out, order, ch_ord_in, ch_ord_out ) ) != AMBI_CONVERT_OK )
+ {
+ return err;
+ }
+ }
+ else
+ {
+ if ( ( err = renormalize_channels( in, out, order, ch_norm_in, ch_norm_out ) ) != AMBI_CONVERT_OK )
+ {
+ return err;
+ }
+ }
+ }
+ else if ( in_format == AMBI_FMT_ACN_SN3D && ch_ord_in != ch_ord_out )
+ {
+ if ( ( err = reorder_channels( in, out, order, ch_ord_in, ch_ord_out ) ) != AMBI_CONVERT_OK )
+ {
+ return err;
+ }
+ }
+ else if ( out_format == AMBI_FMT_ACN_SN3D && ch_norm_in != ch_norm_out )
+ {
+ if ( ch_ord_in != ch_ord_out )
+ {
+ if ( ( err = reorder_channels( in, p_tmp, order, ch_ord_in, ch_ord_out ) ) != AMBI_CONVERT_OK )
+ {
+ return err;
+ }
+ if ( ( err = renormalize_channels( p_tmp, out, order, ch_norm_in, ch_norm_out ) ) != AMBI_CONVERT_OK )
+ {
+ return err;
+ }
+ }
+ else
+ {
+ if ( ( err = renormalize_channels( in, out, order, ch_norm_in, ch_norm_out ) ) != AMBI_CONVERT_OK )
+ {
+ return err;
+ }
+ }
+ }
+ else if ( out_format == AMBI_FMT_ACN_SN3D && ch_ord_in != ch_ord_out )
+ {
+ if ( ( err = reorder_channels( in, out, order, ch_ord_in, ch_ord_out ) ) != AMBI_CONVERT_OK )
+ {
+ return err;
+ }
+ }
+ else if ( out_format == AMBI_FMT_ACN_SN3D && in_format == AMBI_FMT_ACN_SN3D )
+ {
+ int16_t i_chan = 0;
+ int16_t n_chan = ( order + 1 ) * ( order + 1 );
+
+ for ( i_chan = 0; i_chan < n_chan; i_chan++ )
+ {
+ int16_t i = 0;
+ for ( i = 0; i < L_FRAME48k; i++ )
+ {
+ out[i_chan][i] = in[i_chan][i];
+ }
+ }
+ }
+ else
+ {
+ assert( 0 && "This should never happen!" );
+ }
+
+ return AMBI_CONVERT_OK;
+}
+
+/*-------------------------------------------------------------------------*
+* renormalize_channels()
+*
+* Rescale audio channels according to the selected ambisonics convention
+--------------------------------------------------------------------------*/
+
+AMBI_CONVERT_ERROR renormalize_channels(
+ float *in[], /* i: input ambisonics channels */
+ float *out[], /* o: output ambisonics channels */
+ int16_t order, /* i: ambisonics order */
+ AMBI_CHANNEL_NORM in_format, /* i: input ambisonics format */
+ AMBI_CHANNEL_NORM out_format /* i: output ambisonics format */
+)
+{
+ int16_t n_chan = ( order + 1 ) * ( order + 1 );
+ int16_t i_chan, i;
+ const float *conversion_table = 0;
+
+ /* conversion factors are applied on the channels assuming that they are still/already in ACN order */
+ if ( in_format == AMBI_NORM_SN3D )
+ {
+ if ( out_format == AMBI_NORM_N3D )
+ {
+ conversion_table = SN3D_N3D;
+ }
+ else if ( out_format == AMBI_NORM_MAXN )
+ {
+ conversion_table = SN3D_MAXN;
+ }
+ else if ( out_format == AMBI_NORM_FM )
+ {
+ conversion_table = SN3D_FM;
+ }
+ else
+ {
+ return AMBI_CONVERT_UNSUPPORTED_CONVERSION;
+ }
+ }
+ else if ( out_format == AMBI_NORM_SN3D )
+ {
+ if ( in_format == AMBI_NORM_N3D )
+ {
+ conversion_table = N3D_SN3D;
+ }
+ else if ( in_format == AMBI_NORM_MAXN )
+ {
+ conversion_table = MAXN_SN3D;
+ }
+ else if ( in_format == AMBI_NORM_FM )
+ {
+ conversion_table = FM_SN3D;
+ }
+ else
+ {
+ return AMBI_CONVERT_UNSUPPORTED_CONVERSION;
+ }
+ }
+ else
+ {
+ return AMBI_CONVERT_UNSUPPORTED_CONVERSION;
+ }
+
+
+ for ( i_chan = 0; i_chan < n_chan; i_chan++ )
+ {
+ float conversion_factor = conversion_table[i_chan];
+ for ( i = 0; i < L_FRAME48k; i++ )
+ {
+ out[i_chan][i] = in[i_chan][i] * conversion_factor;
+ }
+ }
+
+ return AMBI_CONVERT_OK;
+}
+
+/*-------------------------------------------------------------------------*
+* reorder_channels()
+*
+* Reorder channels according to the selected ambisonics convention
+--------------------------------------------------------------------------*/
+
+AMBI_CONVERT_ERROR reorder_channels(
+ float *in[], /* i: input ambisonics channels */
+ float *out[], /* o: output ambisonics channels */
+ int16_t order, /* i: ambisonics order */
+ AMBI_CHANNEL_ORDER in_format, /* i: input ambisonics format */
+ AMBI_CHANNEL_ORDER out_format /* i: output ambisonics format */
+)
+{
+ int16_t n_chan = ( order + 1 ) * ( order + 1 );
+ int16_t i_chan, i;
+ float tmp[AMBI_MAX_CHANNELS];
+ const int16_t *idx_table = 0;
+
+ if ( in_format == AMBI_CHANNEL_ORDER_ACN )
+ {
+ if ( out_format == AMBI_CHANNEL_ORDER_FM )
+ {
+ idx_table = REORDER_ACN_FM;
+ }
+ else if ( out_format == AMBI_CHANNEL_ORDER_SID )
+ {
+ idx_table = REORDER_ACN_SID;
+ }
+ else
+ {
+ return AMBI_CONVERT_UNSUPPORTED_CONVERSION;
+ }
+ }
+ else if ( out_format == AMBI_CHANNEL_ORDER_ACN )
+ {
+ if ( in_format == AMBI_CHANNEL_ORDER_FM )
+ {
+ idx_table = REORDER_FM_ACN;
+ }
+ else if ( in_format == AMBI_CHANNEL_ORDER_SID )
+ {
+ idx_table = REORDER_SID_ACN;
+ }
+ else
+ {
+ return AMBI_CONVERT_UNSUPPORTED_CONVERSION;
+ }
+ }
+ else
+ {
+ return AMBI_CONVERT_UNSUPPORTED_CONVERSION;
+ }
+
+ for ( i = 0; i < L_FRAME48k; i++ )
+ {
+ for ( i_chan = 0; i_chan < n_chan; i_chan++ )
+ {
+ int16_t idx = idx_table[i_chan];
+ tmp[i_chan] = in[idx][i];
+ }
+ for ( i_chan = 0; i_chan < n_chan; i_chan++ )
+ {
+ out[i_chan][i] = tmp[i_chan];
+ }
+ }
+
+ return AMBI_CONVERT_OK;
+}
diff --git a/lib_util/ambi_convert.h b/lib_util/ambi_convert.h
new file mode 100644
index 0000000000000000000000000000000000000000..7b3093c5d369257fcc31e4471fe5b6000f04fa5c
--- /dev/null
+++ b/lib_util/ambi_convert.h
@@ -0,0 +1,95 @@
+/******************************************************************************************************
+
+ (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository. All Rights Reserved.
+
+ This software is protected by copyright law and by international treaties.
+ The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository retain full ownership rights in their respective contributions in
+ the software. This notice grants no license of any kind, including but not limited to patent
+ license, nor is any license granted by implication, estoppel or otherwise.
+
+ Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
+ contributions.
+
+ This software is provided "AS IS", without any express or implied warranties. The software is in the
+ development stage. It is intended exclusively for experts who have experience with such software and
+ solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
+ and fitness for a particular purpose are hereby disclaimed and excluded.
+
+ Any dispute, controversy or claim arising under or in relation to providing this software shall be
+ submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
+ accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
+ the United Nations Convention on Contracts on the International Sales of Goods.
+
+*******************************************************************************************************/
+
+#ifndef AMBI_CONVERT_H
+#define AMBI_CONVERT_H
+
+#include
+
+#define L_FRAME48k 960
+#define AMBI_MAX_CHANNELS 16
+
+typedef enum
+{
+ AMBI_FMT_ACN_SN3D = 0,
+ AMBI_FMT_ACN_N3D,
+ AMBI_FMT_FM_MAXN,
+ AMBI_FMT_FM_FM,
+ AMBI_FMT_SID_SN3D,
+ AMBI_FMT_SID_N3D
+} AMBI_FMT;
+
+typedef enum
+{
+ AMBI_NORM_SN3D = 0,
+ AMBI_NORM_N3D,
+ AMBI_NORM_MAXN,
+ AMBI_NORM_FM
+} AMBI_CHANNEL_NORM;
+
+typedef enum
+{
+ AMBI_CHANNEL_ORDER_ACN = 0,
+ AMBI_CHANNEL_ORDER_FM,
+ AMBI_CHANNEL_ORDER_SID
+} AMBI_CHANNEL_ORDER;
+
+typedef enum
+{
+ AMBI_CONVERT_OK = 0,
+ AMBI_CONVERT_UNSUPPORTED_CONVERSION
+} AMBI_CONVERT_ERROR;
+
+AMBI_CONVERT_ERROR convert_ambi_format(
+ float *in[], /* i: input ambisonics channels */
+ float *out[], /* o: output ambisonics channels */
+ int16_t order, /* i: ambisonics order */
+ AMBI_FMT in_format, /* i: input ambisonics format */
+ AMBI_FMT out_format /* i: output ambisonics format */
+);
+
+AMBI_CONVERT_ERROR renormalize_channels(
+ float *in[], /* i: input ambisonics channels */
+ float *out[], /* o: output ambisonics channels */
+ int16_t order, /* i: ambisonics order */
+ AMBI_CHANNEL_NORM in_format, /* i: input ambisonics format */
+ AMBI_CHANNEL_NORM out_format /* i: output ambisonics format */
+);
+
+AMBI_CONVERT_ERROR reorder_channels(
+ float *in[], /* i: input ambisonics channels */
+ float *out[], /* o: output ambisonics channels */
+ int16_t order, /* i: ambisonics order */
+ AMBI_CHANNEL_ORDER in_format, /* i: input ambisonics format */
+ AMBI_CHANNEL_ORDER out_format /* i: output ambisonics format */
+);
+#endif
diff --git a/scripts/ambi_converter.c b/scripts/ambi_converter.c
new file mode 100644
index 0000000000000000000000000000000000000000..087e90a3fd1800f25a377bfea4f6a7206877bce6
--- /dev/null
+++ b/scripts/ambi_converter.c
@@ -0,0 +1,186 @@
+/******************************************************************************************************
+
+ (C) 2022-2024 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository. All Rights Reserved.
+
+ This software is protected by copyright law and by international treaties.
+ The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository retain full ownership rights in their respective contributions in
+ the software. This notice grants no license of any kind, including but not limited to patent
+ license, nor is any license granted by implication, estoppel or otherwise.
+
+ Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
+ contributions.
+
+ This software is provided "AS IS", without any express or implied warranties. The software is in the
+ development stage. It is intended exclusively for experts who have experience with such software and
+ solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
+ and fitness for a particular purpose are hereby disclaimed and excluded.
+
+ Any dispute, controversy or claim arising under or in relation to providing this software shall be
+ submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
+ accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
+ the United Nations Convention on Contracts on the International Sales of Goods.
+
+*******************************************************************************************************/
+#include
+#include
+#include
+#include
+#include "tinywavein_c.h"
+#include "tinywaveout_c.h"
+#include "ambi_convert.h"
+
+/*-------------------------------------------------------------------------------------*
+ * Ambisonics converter program
+ *
+ * gcc ambi_converter.c ../lib_util/ambi_convert.c -I../lib_util/ -lm -o ambi_converter
+ *--------------------------------------------------------------------------------------*/
+
+int main( int argc, char *argv[] )
+{
+
+ WAVEFILEIN *wavFile_in;
+ WAVEFILEOUT *wavFile_out;
+ char *fileName_in, *fileName_out;
+
+ uint32_t samplingRate;
+ uint32_t samplesInFile;
+ uint32_t numSamples = L_FRAME48k;
+ uint32_t numSamplesRead32 = 0;
+ uint32_t numSamplesClipped = 0;
+
+ int16_t bps;
+ int16_t samples[L_FRAME48k * AMBI_MAX_CHANNELS];
+ int16_t order = 0;
+ int16_t numChannels;
+
+ AMBI_FMT in_format, out_format;
+
+ float samples_f_in[L_FRAME48k * AMBI_MAX_CHANNELS];
+ float samples_f_out[L_FRAME48k * AMBI_MAX_CHANNELS];
+ float *in[AMBI_MAX_CHANNELS], *out[AMBI_MAX_CHANNELS];
+
+ for ( int16_t j = 0; j < AMBI_MAX_CHANNELS; j++ )
+ {
+ in[j] = &samples_f_in[j * L_FRAME48k];
+ out[j] = &samples_f_out[j * L_FRAME48k];
+ }
+
+ if ( argc != 5 )
+ {
+ printf( "Ambisonics converter program\n" );
+ printf( "----------------------------------------------------------------------------------\n" );
+ printf( "Usage:\n" );
+ printf( "./ambi_conveter input_file output_file input_convention output_convention\n" );
+ printf( "\n" );
+ printf( "input_convention and output convention must be an integer number in [0,5]\n" );
+ printf( "the following conventions are supported:\n" );
+ printf( "0 : ACN-SN3D\n" );
+ printf( "1 : ACN-N3D\n" );
+ printf( "2 : FuMa-MaxN\n" );
+ printf( "3 : FuMa-FuMa\n" );
+ printf( "4 : SID-SN3D\n" );
+ printf( "5 : SID-N3D\n" );
+ printf( "\n" );
+ printf( "Either the input or the output convention must always be ACN-SN3D!\n" );
+ return -1;
+ }
+
+ fileName_in = argv[1];
+ fileName_out = argv[2];
+ in_format = atoi( argv[3] );
+ out_format = atoi( argv[4] );
+
+ printf( "In %d, Out: %d\n", in_format, out_format );
+
+ wavFile_in = OpenWav( fileName_in, &samplingRate, &numChannels, &samplesInFile, &bps );
+ if ( !wavFile_in )
+ {
+ fprintf( stderr, "Failed to open input wav file: %s\n", fileName_in );
+ return -1;
+ }
+
+ wavFile_out = CreateWav( fileName_out, samplingRate, numChannels, 16 );
+ if ( !wavFile_out )
+ {
+ fprintf( stderr, "Failed to open output wav file: %s\n", fileName_out );
+ return -1;
+ }
+
+ order = (int16_t) sqrtf( numChannels ) - 1;
+ assert( order > 0 && order <= 3 );
+
+ while ( ReadWavShort( wavFile_in, samples, numSamples, &numSamplesRead32 ) == __TWI_SUCCESS )
+ {
+ int16_t err = 0;
+
+ if ( !numSamplesRead32 )
+ {
+ break;
+ }
+
+ for ( int16_t i = 0; i < numSamplesRead32; i++ )
+ {
+ for ( int16_t j = 0; j < numChannels; j++ )
+ {
+ in[j][i] = (float) samples[i * numChannels + j];
+ }
+ }
+
+ if ( ( err = convert_ambi_format( in, out, order, in_format, out_format ) ) != 0 )
+ {
+ printf( "Error converting the input signal!\n" );
+ return err;
+ }
+
+
+ for ( int16_t i = 0; i < numSamplesRead32; i++ )
+ {
+ for ( int16_t j = 0; j < numChannels; j++ )
+ {
+ int s1_i;
+ float s1 = out[j][i];
+ if ( s1 < INT16_MIN )
+ {
+ s1_i = INT16_MIN;
+ numSamplesClipped++;
+ }
+ else if ( s1 > INT16_MAX )
+ {
+ s1_i = INT16_MAX;
+ numSamplesClipped++;
+ }
+ else
+ {
+ s1_i = (int16_t) s1;
+ }
+ samples[i * numChannels + j] = s1_i;
+ }
+ }
+
+ if ( ( err = WriteWavShort( wavFile_out, samples, numSamplesRead32 ) ) != __TWO_SUCCESS )
+ {
+ printf( "Error writing output wave file!\n" );
+ return err;
+ }
+
+ numSamplesRead32 = 0;
+ }
+
+ CloseWav( wavFile_out );
+ CloseWavIn( wavFile_in );
+
+ if ( numSamplesClipped )
+ {
+ printf( "Warning: %d samples have clipped!\n", numSamplesClipped );
+ }
+
+ return 0;
+}