diff --git a/lib_util/ambi_convert.c b/lib_util/ambi_convert.c new file mode 100644 index 0000000000000000000000000000000000000000..0bf2bf226236edeb1681ccb64d67490e58cc3df0 --- /dev/null +++ b/lib_util/ambi_convert.c @@ -0,0 +1,504 @@ +/****************************************************************************************************** + + (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#include +#include +#include "wmc_auto.h" +#include "ambi_convert.h" + +#define ONE_1_Q29 536870912l /* 1.0f */ +#define ONE_OVER_2_Q29 268435456l /* 1.0f/2.0f */ + +#define SQRT_2_Q29 759250112l /* sqrtf(2.0f) */ +#define SQRT_3_Q29 929887680l /* sqrtf(3.0f) */ +#define SQRT_5_Q29 1200479872l /* sqrtf(5.0f) */ +#define SQRT_7_Q29 1420426880l /* sqrtf(7.0f) */ + +#define INV_SQRT_2_Q29 379625024l /* 1.0f/sqrtf(2.0f) */ +#define INV_SQRT_3_Q29 309962528l /* 1.0f/sqrtf(3.0f) */ +#define INV_SQRT_5_Q29 240095920l /* 1.0f/sqrtf(5.0f) */ +#define INV_SQRT_7_Q29 202918096l /* 1.0f/sqrtf(7.0f) */ + +#define TWO_OVER_SQRT_3_Q29 619925120l /* 2.0f/sqrtf(3.0f) */ +#define THREE_OVER_SQRT_5_Q29 720287936l /* 3.0f/sqrtf(5.0f) */ +#define SQRT_8_OVER_5_Q29 679093952l /* sqrtf(8.0f/5.0f) */ +#define SQRT_45_OVER_32_Q29 636650560l /* sqrtf(45.0f/32.0f) */ + +#define INV_TWO_OVER_SQRT_3_Q29 464943840l /* 1.0f/TWO_OVER_SQRT_3_Q29 */ +#define INV_THREE_OVER_SQRT_5_Q29 400159968l /* 1.0f/THREE_OVER_SQRT_5_Q29 */ +#define INV_SQRT_8_OVER_5_Q29 424433728l /* 1.0f/INV_SQRT_8_OVER_5_Q29 */ +#define INV_SQRT_45_OVER_32_Q29 452729280l /* 1.0f/SQRT_45_OVER_32_Q29 */ + + +/* -------------------------------- + normalization conversion tables + -------------------------------- */ + +static const Word32 SN3D_N3D[AMBI_MAX_CHANNELS] = { ONE_1_Q29, + SQRT_3_Q29, SQRT_3_Q29, SQRT_3_Q29, + SQRT_5_Q29, SQRT_5_Q29, SQRT_5_Q29, SQRT_5_Q29, SQRT_5_Q29, + SQRT_7_Q29, SQRT_7_Q29, SQRT_7_Q29, SQRT_7_Q29, SQRT_7_Q29, SQRT_7_Q29, SQRT_7_Q29 }; + +static const Word32 N3D_SN3D[AMBI_MAX_CHANNELS] = { ONE_1_Q29, + INV_SQRT_3_Q29, INV_SQRT_3_Q29, INV_SQRT_3_Q29, + INV_SQRT_5_Q29, INV_SQRT_5_Q29, INV_SQRT_5_Q29, INV_SQRT_5_Q29, INV_SQRT_5_Q29, + INV_SQRT_7_Q29, INV_SQRT_7_Q29, INV_SQRT_7_Q29, INV_SQRT_7_Q29, INV_SQRT_7_Q29, INV_SQRT_7_Q29, INV_SQRT_7_Q29 }; + + +static const Word32 SN3D_MAXN[AMBI_MAX_CHANNELS] = { ONE_1_Q29, + ONE_1_Q29, ONE_1_Q29, ONE_1_Q29, + TWO_OVER_SQRT_3_Q29, TWO_OVER_SQRT_3_Q29, ONE_1_Q29, TWO_OVER_SQRT_3_Q29, TWO_OVER_SQRT_3_Q29, + SQRT_8_OVER_5_Q29, THREE_OVER_SQRT_5_Q29, SQRT_45_OVER_32_Q29, ONE_1_Q29, SQRT_45_OVER_32_Q29, THREE_OVER_SQRT_5_Q29, SQRT_8_OVER_5_Q29 }; + +static const Word32 MAXN_SN3D[AMBI_MAX_CHANNELS] = { ONE_1_Q29, + ONE_1_Q29, ONE_1_Q29, ONE_1_Q29, + INV_TWO_OVER_SQRT_3_Q29, INV_TWO_OVER_SQRT_3_Q29, ONE_1_Q29, INV_TWO_OVER_SQRT_3_Q29, INV_TWO_OVER_SQRT_3_Q29, + INV_SQRT_8_OVER_5_Q29, INV_THREE_OVER_SQRT_5_Q29, INV_SQRT_45_OVER_32_Q29, ONE_1_Q29, INV_SQRT_45_OVER_32_Q29, INV_THREE_OVER_SQRT_5_Q29, INV_SQRT_8_OVER_5_Q29 }; + +static const Word32 SN3D_FM[AMBI_MAX_CHANNELS] = { INV_SQRT_2_Q29, + ONE_1_Q29, ONE_1_Q29, ONE_1_Q29, + TWO_OVER_SQRT_3_Q29, TWO_OVER_SQRT_3_Q29, ONE_1_Q29, TWO_OVER_SQRT_3_Q29, TWO_OVER_SQRT_3_Q29, + SQRT_8_OVER_5_Q29, THREE_OVER_SQRT_5_Q29, SQRT_45_OVER_32_Q29, ONE_1_Q29, SQRT_45_OVER_32_Q29, THREE_OVER_SQRT_5_Q29, SQRT_8_OVER_5_Q29 }; + +static const Word32 FM_SN3D[AMBI_MAX_CHANNELS] = { SQRT_2_Q29, + ONE_1_Q29, ONE_1_Q29, ONE_1_Q29, + INV_TWO_OVER_SQRT_3_Q29, INV_TWO_OVER_SQRT_3_Q29, ONE_1_Q29, INV_TWO_OVER_SQRT_3_Q29, INV_TWO_OVER_SQRT_3_Q29, + INV_SQRT_8_OVER_5_Q29, INV_THREE_OVER_SQRT_5_Q29, INV_SQRT_45_OVER_32_Q29, ONE_1_Q29, INV_SQRT_45_OVER_32_Q29, INV_THREE_OVER_SQRT_5_Q29, INV_SQRT_8_OVER_5_Q29 }; + +/* ---------------------------- + 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( + Word16 *in[], /* i: input ambisonics channels, Q0 */ + Word16 *out[], /* o: output ambisonics channels, Q0 */ + int16_t order, /* i: ambisonics order */ + AMBI_FMT in_format, /* i: input ambisonics format */ + AMBI_FMT out_format /* i: output ambisonics format */ +) +{ + + Word16 tmp[AMBI_MAX_CHANNELS * L_FRAME48k]; + Word16 *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; + + Word16 i, j; + + 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" ); + } + i = 0; + move16(); + FOR( j = 0; j < AMBI_MAX_CHANNELS; j++ ) + { + p_tmp[j] = &tmp[i]; + move32(); + i = add( i, L_FRAME48k ); + } + + SWITCH( in_format ) + { + case AMBI_FMT_ACN_SN3D: + ch_ord_in = AMBI_CHANNEL_ORDER_ACN; + ch_norm_in = AMBI_NORM_SN3D; + move16(); + move16(); + break; + case AMBI_FMT_ACN_N3D: + ch_ord_in = AMBI_CHANNEL_ORDER_ACN; + ch_norm_in = AMBI_NORM_N3D; + move16(); + move16(); + break; + case AMBI_FMT_FM_MAXN: + ch_ord_in = AMBI_CHANNEL_ORDER_FM; + ch_norm_in = AMBI_NORM_MAXN; + move16(); + move16(); + break; + case AMBI_FMT_FM_FM: + ch_ord_in = AMBI_CHANNEL_ORDER_FM; + ch_norm_in = AMBI_NORM_FM; + move16(); + move16(); + break; + case AMBI_FMT_SID_SN3D: + ch_ord_in = AMBI_CHANNEL_ORDER_SID; + ch_norm_in = AMBI_NORM_SN3D; + move16(); + move16(); + break; + case AMBI_FMT_SID_N3D: + ch_ord_in = AMBI_CHANNEL_ORDER_SID; + ch_norm_in = AMBI_NORM_N3D; + move16(); + move16(); + 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; + move16(); + move16(); + break; + case AMBI_FMT_ACN_N3D: + ch_ord_out = AMBI_CHANNEL_ORDER_ACN; + ch_norm_out = AMBI_NORM_N3D; + move16(); + move16(); + break; + case AMBI_FMT_FM_MAXN: + ch_ord_out = AMBI_CHANNEL_ORDER_FM; + ch_norm_out = AMBI_NORM_MAXN; + move16(); + move16(); + break; + case AMBI_FMT_FM_FM: + ch_ord_out = AMBI_CHANNEL_ORDER_FM; + ch_norm_out = AMBI_NORM_FM; + move16(); + move16(); + break; + case AMBI_FMT_SID_SN3D: + ch_ord_out = AMBI_CHANNEL_ORDER_SID; + ch_norm_out = AMBI_NORM_SN3D; + move16(); + move16(); + break; + case AMBI_FMT_SID_N3D: + ch_ord_out = AMBI_CHANNEL_ORDER_SID; + ch_norm_out = AMBI_NORM_N3D; + move16(); + move16(); + 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 = i_mult2( add( order, 1 ), add( order, 1 ) ); + + FOR( i_chan = 0; i_chan < n_chan; i_chan++ ) + { + int16_t i = 0; + move16(); + FOR( i = 0; i < L_FRAME48k; i++ ) + { + out[i_chan][i] = in[i_chan][i]; + move16(); + } + } + } + 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( + Word16 *in[], /* i: input ambisonics channels, Q0 */ + Word16 *out[], /* o: output ambisonics channels, Q0 */ + 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 = i_mult2( add( order, 1 ), add( order, 1 ) ); + int16_t i_chan, i; + const Word32 *conversion_table = 0; + Word32 minval = 0; + Word32 maxval = 0; + move32(); + move32(); + move32(); + + + /* 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; + move32(); + } + ELSE IF( out_format == AMBI_NORM_MAXN ) + { + conversion_table = SN3D_MAXN; + move32(); + } + ELSE IF( out_format == AMBI_NORM_FM ) + { + conversion_table = SN3D_FM; + move32(); + } + ELSE + { + return AMBI_CONVERT_UNSUPPORTED_CONVERSION; + } + } + ELSE IF( out_format == AMBI_NORM_SN3D ) + { + IF( in_format == AMBI_NORM_N3D ) + { + conversion_table = N3D_SN3D; + move32(); + } + ELSE IF( in_format == AMBI_NORM_MAXN ) + { + conversion_table = MAXN_SN3D; + move32(); + } + ELSE IF( in_format == AMBI_NORM_FM ) + { + conversion_table = FM_SN3D; + move32(); + } + ELSE + { + return AMBI_CONVERT_UNSUPPORTED_CONVERSION; + } + } + ELSE + { + return AMBI_CONVERT_UNSUPPORTED_CONVERSION; + } + + + FOR( i_chan = 0; i_chan < n_chan; i_chan++ ) + { + Word32 conversion_factor = conversion_table[i_chan]; + Word32 outval; + move32(); + FOR( i = 0; i < L_FRAME48k; i++ ) + { + Word64 tmp; + tmp = W_mult0_32_32( (Word32) in[i_chan][i], conversion_factor ); + /* tmp = W_add( tmp, ONE_OVER_2_Q29); */ /* rounding up */ + outval = W_extract_l( W_shr( tmp, Q29 ) ); + minval = L_min( minval, outval ); + maxval = L_min( maxval, outval ); + out[i_chan][i] = extract_l( outval ); + } + } + IF( ( minval < MIN16B ) || ( maxval > MAX16B ) ) + { + return AMBI_CONVERT_CLIPPING_DETECTED; + } + return AMBI_CONVERT_OK; +} + +/*-------------------------------------------------------------------------* +* reorder_channels() +* +* Reorder channels according to the selected ambisonics convention +--------------------------------------------------------------------------*/ + +AMBI_CONVERT_ERROR reorder_channels( + Word16 *in[], /* i: input ambisonics channels, Q0 */ + Word16 *out[], /* o: output ambisonics channels, Q0 */ + 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 = i_mult2( add( order, 1 ), add( order, 1 ) ); + int16_t i_chan, i; + Word16 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; + move16(); + } + ELSE IF( out_format == AMBI_CHANNEL_ORDER_SID ) + { + idx_table = REORDER_ACN_SID; + move16(); + } + 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; + move16(); + } + ELSE IF( in_format == AMBI_CHANNEL_ORDER_SID ) + { + idx_table = REORDER_SID_ACN; + move16(); + } + 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]; + move16(); + tmp[i_chan] = in[idx][i]; + move16(); + } + FOR( i_chan = 0; i_chan < n_chan; i_chan++ ) + { + out[i_chan][i] = tmp[i_chan]; + move16(); + } + } + + return AMBI_CONVERT_OK; +} diff --git a/lib_util/ambi_convert.h b/lib_util/ambi_convert.h new file mode 100644 index 0000000000000000000000000000000000000000..207bd276f1c98f1552f49e3d0560023765ec5686 --- /dev/null +++ b/lib_util/ambi_convert.h @@ -0,0 +1,103 @@ +/****************************************************************************************************** + + (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#ifndef AMBI_CONVERT_H +#define AMBI_CONVERT_H + +#include +#include "options.h" +#include "prot_fx.h" +#include "ivas_cnst.h" +#include +#include "wmc_auto.h" +#include "ivas_prot_fx.h" + + +#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_CLIPPING_DETECTED +} AMBI_CONVERT_ERROR; + +AMBI_CONVERT_ERROR convert_ambi_format( + Word16 *in[], /* i: input ambisonics channels, Q0 */ + Word16 *out[], /* o: output ambisonics channels, Q0 */ + 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( + Word16 *in[], /* i: input ambisonics channels, Q0 */ + Word16 *out[], /* o: output ambisonics channels, Q0 */ + 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( + Word16 *in[], /* i: input ambisonics channels, Q0 */ + Word16 *out[], /* o: output ambisonics channels, Q0 */ + 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