diff --git a/CMakeLists.txt b/CMakeLists.txt index 84a44e4e35e62f14239eb0e588586089a2016977..ab640932fcce12b79873b76a1c519d1cd4c8c9ce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -215,6 +215,13 @@ add_executable(ISAR_post_rend apps/isar_post_rend.c) target_link_libraries(ISAR_post_rend lib_basop lib_isar lib_util lib_com) target_include_directories(ISAR_post_rend PRIVATE lib_basop lib_isar) +add_executable(ambi_converter apps/ambi_converter.c) +target_link_libraries(ambi_converter lib_util lib_com lib_basop) +if(UNIX) + target_link_libraries(ambi_converter m) +endif() +target_include_directories(ambi_converter PRIVATE lib_basop lib_util lib_com lib_debug) + if(COPY_EXECUTABLES_FROM_BUILD_DIR) # Optionally copy executables to the same place where Make puts them (useful for tests that expect executables in specific places) add_custom_command(TARGET IVAS_cod POST_BUILD VERBATIM COMMAND "${CMAKE_COMMAND}" -E copy "$" "${CMAKE_CURRENT_SOURCE_DIR}/") diff --git a/Makefile b/Makefile index 691ff9d72584bc44bfa5bf3c685b4009ad973616..4febdc988d1832014ecec97f84297363936c42f1 100644 --- a/Makefile +++ b/Makefile @@ -21,6 +21,7 @@ CLI_APIDEC ?= IVAS_dec CLI_APIENC ?= IVAS_cod CLI_APIREND ?= IVAS_rend CLI_APIPOSTREND ?= ISAR_post_rend +CLI_AMBICONVERT ?= ambi_converter LIB_LIBBASOP ?= libivasbasop.a LIB_LIBCOM ?= libivascom.a LIB_LIBDEBUG ?= libivasdebug.a @@ -165,10 +166,12 @@ OBJS_LIBREND = $(addprefix $(OBJDIR)/,$(SRCS_LIBREND:.c=.o)) OBJS_LIBISAR = $(addprefix $(OBJDIR)/,$(SRCS_LIBISAR:.c=.o)) OBJS_LC3PLUS = $(addprefix $(OBJDIR)/,$(SRCS_LC3PLUS:.c=.o)) OBJS_LIBUTIL = $(addprefix $(OBJDIR)/,$(SRCS_LIBUTIL:.c=.o)) +OBJS_AMBICONVERT = $(OBJDIR)/ambi_convert.o OBJS_CLI_APIDEC = $(OBJDIR)/decoder.o OBJS_CLI_APIENC = $(OBJDIR)/encoder.o OBJS_CLI_APPREND = $(OBJDIR)/renderer.o OBJS_CLI_APPPOSTREND = $(OBJDIR)/isar_post_rend.o +OBJS_CLI_AMBICONVERT = $(OBJDIR)/ambi_converter.o DEPS = $(addprefix $(OBJDIR)/,$(SRCS_LIBBASOP:.c=.P) $(SRCS_LIBCOM:.c=.P) $(SRCS_LIBDEBUG:.c=.P) $(SRCS_LIBDEC:.c=.P) \ $(SRCS_LIBENC:.c=.P) $(SRCS_LIBUTIL:.c=.P) $(SRCS_LIBREND:.c=.P) $(SRCS_LIBISAR:.c=.P) \ @@ -223,13 +226,16 @@ $(CLI_APIREND): $(OBJS_CLI_APPREND) $(LIB_LIBBASOP) $(LIB_LIBREND) $(LIB_LIBCOM) $(CLI_APIPOSTREND): $(OBJS_CLI_APPPOSTREND) $(LIB_LIBBASOP) $(LIB_LIBISAR) $(LIB_LIBCOM) $(LIB_LIBUTIL) $(LIB_LIBDEBUG) $(LIB_LC3PLUS) $(QUIET_LINK)$(CC) $(LDFLAGS) $(OBJS_CLI_APPPOSTREND) -L. -livasbasop -lisar -livasutil -livasdebug -livascom -llc3plus $(LDLIBS) -o $(CLI_APIPOSTREND) +$(CLI_AMBICONVERT): $(OBJS_CLI_AMBICONVERT) $(OBJS_AMBICONVERT) $(LIB_LIBBASOP) $(LIB_LIBCOM) + $(QUIET_LINK)$(CC) $(LDFLAGS) $(OBJS_CLI_AMBICONVERT) $(OBJS_AMBICONVERT) -L. -livascom -livasbasop $(LDLIBS) -o $(CLI_AMBICONVERT) + libs: $(LIB_LIBBASOP) $(LIB_LIBENC) $(LIB_LIBDEBUG) $(LIB_LIBCOM) $(LIB_LIBDEC) $(LIB_LIBREND) $(LIB_LIBISAR) $(LIB_LC3PLUS) $(LIB_LIBUTIL) clean: $(QUIET)$(RM) $(OBJS_LIBENC) $(OBJS_LIBDEC) $(DEPS) $(QUIET)$(RM) $(DEPS:.P=.d) $(QUIET)test ! -d $(OBJDIR) || rm -rf $(OBJDIR) - $(QUIET)$(RM) $(CLI_APIENC) $(CLI_APIDEC) $(CLI_APIREND) $(CLI_APIPOSTREND) $(LIB_LIBENC) $(LIB_LIBDEBUG) $(OBJS_LIBBASOP) $(LIB_LIBCOM) $(LIB_LIBDEC) $(LIB_LIBUTIL) $(LIB_LIBREND) $(LIB_LIBISAR) $(LIB_LC3PLUS) + $(QUIET)$(RM) $(CLI_APIENC) $(CLI_APIDEC) $(CLI_APIREND) $(CLI_APIPOSTREND) $(CLI_AMBICONVERT) $(LIB_LIBENC) $(LIB_LIBDEBUG) $(OBJS_LIBBASOP) $(LIB_LIBCOM) $(LIB_LIBDEC) $(LIB_LIBUTIL) $(LIB_LIBREND) $(LIB_LIBISAR) $(LIB_LC3PLUS) $(OBJDIR)/%.o : %.c | $(OBJDIR) $(QUIET_CC)$(CC) $(CFLAGS) -c -MD -o $@ $< diff --git a/Workspace_msvc/Workspace_msvc.sln b/Workspace_msvc/Workspace_msvc.sln index a87706281425321fc00be09891067b01d53125ee..abb9650fc7d5dda70bc0f21d8faaa5ae3b27526a 100644 --- a/Workspace_msvc/Workspace_msvc.sln +++ b/Workspace_msvc/Workspace_msvc.sln @@ -45,6 +45,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "isar_post_rend", "isar_post EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_basop", "lib_basop.vcxproj", "{63747FE7-94BA-410C-8D7F-EB47555DD994}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ambi_converter", "ambi_converter.vcxproj", "{2074FFD6-8056-4C5F-8A08-0B2607D1FEFF}" + ProjectSection(ProjectDependencies) = postProject + {39EC200D-7795-4FF8-B214-B24EDA5526AE} = {39EC200D-7795-4FF8-B214-B24EDA5526AE} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -131,6 +136,12 @@ Global {63747FE7-94BA-410C-8D7F-EB47555DD994}.Release|Win32.ActiveCfg = Release|Win32 {63747FE7-94BA-410C-8D7F-EB47555DD994}.Release|Win32.Build.0 = Release|Win32 {63747FE7-94BA-410C-8D7F-EB47555DD994}.Release|x64.ActiveCfg = Release|Win32 + {2074FFD6-8056-4C5F-8A08-0B2607D1FEFF}.Debug|Win32.ActiveCfg = Debug|Win32 + {2074FFD6-8056-4C5F-8A08-0B2607D1FEFF}.Debug|Win32.Build.0 = Debug|Win32 + {2074FFD6-8056-4C5F-8A08-0B2607D1FEFF}.Debug|x64.ActiveCfg = Debug|Win32 + {2074FFD6-8056-4C5F-8A08-0B2607D1FEFF}.Release|Win32.ActiveCfg = Release|Win32 + {2074FFD6-8056-4C5F-8A08-0B2607D1FEFF}.Release|Win32.Build.0 = Release|Win32 + {2074FFD6-8056-4C5F-8A08-0B2607D1FEFF}.Release|x64.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Workspace_msvc/ambi_converter.vcxproj b/Workspace_msvc/ambi_converter.vcxproj new file mode 100644 index 0000000000000000000000000000000000000000..caedd2c6f13a4a58e7155a70d7658086e95a7351 --- /dev/null +++ b/Workspace_msvc/ambi_converter.vcxproj @@ -0,0 +1,172 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + ambi_converter + {2074FFD6-8056-4C5F-8A08-0B2607D1FEFF} + renderer + 10.0.17763.0 + + + + Application + v141 + false + MultiByte + + + Application + v141 + false + MultiByte + + + + + + + + + + + + + + + <_ProjectFileVersion>15.0.27428.2015 + + + ..\ + .\Debug_$(ProjectName)\ + false + false + ambi_converter + + + ..\ + .\Release_$(ProjectName)\ + false + false + ambi_converter + + + + $(IntDir)$(ProjectName).tlb + + + + Disabled + ..\lib_basop;..\lib_enc;..\lib_dec;..\lib_com;..\lib_debug;..\lib_util;..\lib_isar;..\lib_rend;..\lib_lc3plus;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;WIN32;$(Macros);%(PreprocessorDefinitions) + + EnableFastChecks + MultiThreadedDebug + false + + + $(IntDir)$(ProjectName).pdb + Level4 + true + OldStyle + Default + %(DisableSpecificWarnings) + false + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c0c + + + + $(OutDir)$(TargetName).exe + true + + true + $(IntDir)$(ProjectName).pdb + Console + false + + MachineX86 + + + + + $(IntDir)$(ProjectName).tlb + + + + MaxSpeed + AnySuitable + false + Neither + false + false + ..\lib_basop;..\lib_enc;..\lib_dec;..\lib_com;..\lib_debug;..\lib_util;..\lib_isar;..\lib_rend;..\lib_lc3plus;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_WARNINGS;$(Macros);%(PreprocessorDefinitions) + true + + Default + MultiThreaded + true + Precise + false + + + $(IntDir)$(ProjectName).pdb + Level4 + true + + Default + %(DisableSpecificWarnings) + false + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c0c + + + $(OutDir)$(TargetName).exe + true + + false + $(IntDir)$(ProjectName).pdb + Console + false + + MachineX86 + libcmtd.lib + + + + + + + + {63747fe7-94ba-410c-8d7f-eb47555dd994} + + + {39ec200d-7795-4ff8-b214-b24eda5526ae} + + + {2FA8F384-0775-F3B7-F8C3-85209222FC70} + false + + + + + + + + + + + \ No newline at end of file diff --git a/Workspace_msvc/lib_util.vcxproj b/Workspace_msvc/lib_util.vcxproj index 00574f411e793e87d9a2c9fd3a5cefcd1ee7da7a..73a48f23e8967698270fd835193b8da1b580b7bb 100644 --- a/Workspace_msvc/lib_util.vcxproj +++ b/Workspace_msvc/lib_util.vcxproj @@ -100,6 +100,7 @@ + @@ -162,4 +163,4 @@ - \ No newline at end of file + diff --git a/apps/ambi_converter.c b/apps/ambi_converter.c new file mode 100644 index 0000000000000000000000000000000000000000..76619c904887b59c7a312b051ce40b2ab5f4c691 --- /dev/null +++ b/apps/ambi_converter.c @@ -0,0 +1,198 @@ +/****************************************************************************************************** + + (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 +#include "../lib_util/tinywavein_c.h" +#include "../lib_util/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 = AMBI_MAX_FRAME_LENGTH; + uint32_t numSamplesRead32 = 0; + // uint32_t numSamplesClipped = 0; + uint32_t numFramesClipped = 0; + + int16_t bps; + int16_t samples[AMBI_MAX_FRAME_LENGTH * AMBI_MAX_CHANNELS]; + int16_t order = 0; + int16_t numChannels; + const char *name_conventions[6] = { "ACN-SN3D", "ACN-N3D", "FuMa-MaxN", "FuMa-FuMa", "SID-SN3D", "SID-N3D" }; + + AMBI_FMT in_format, out_format; + + Word16 samples_f_in[AMBI_MAX_FRAME_LENGTH * AMBI_MAX_CHANNELS]; + Word16 samples_f_out[AMBI_MAX_FRAME_LENGTH * AMBI_MAX_CHANNELS]; + Word16 *in[AMBI_MAX_CHANNELS], *out[AMBI_MAX_CHANNELS]; + + for ( int16_t j = 0; j < AMBI_MAX_CHANNELS; j++ ) + { + in[j] = &samples_f_in[j * AMBI_MAX_FRAME_LENGTH]; + out[j] = &samples_f_out[j * AMBI_MAX_FRAME_LENGTH]; + } + + printf( "Ambisonics converter program\n" ); + if ( argc != 5 ) + { + printf( "----------------------------------------------------------------------------------\n" ); + printf( "Usage:\n" ); + printf( "./ambi_converter 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] ); + if ( in_format < 0 || out_format < 0 || in_format > 5 || out_format > 5 ) + { + printf( "input_convention and output convention must be an integer number in [0,5]\n" ); + return -1; + } + printf( "In: [%s], Out: [%s]\n", name_conventions[in_format], name_conventions[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 ); + + numSamples = ( samplingRate * 20 * numChannels ) / 1000; /* 20ms worth of samples */ + while ( ReadWavShort( wavFile_in, samples, numSamples, &numSamplesRead32 ) == __TWI_SUCCESS ) + { + int32_t err = 0; + + if ( !numSamplesRead32 ) + { + break; + } + + for ( uint16_t i = 0; i < (uint16_t) numSamplesRead32 / numChannels; i++ ) + { + for ( int16_t j = 0; j < numChannels; j++ ) + { + in[j][i] = (Word16) samples[i * numChannels + j]; + } + } + + err = convert_ambi_format( in, out, order, in_format, out_format, ( const uint16_t )( numSamples / numChannels ) ); + if ( err == AMBI_CONVERT_CLIPPING_DETECTED ) + { + numFramesClipped++; + } + else if ( err != 0 ) + { + printf( "Error converting the input signal!\n" ); + return err; + } + + + for ( uint16_t i = 0; i < (uint16_t) numSamplesRead32 / numChannels; i++ ) + { + for ( int16_t j = 0; j < numChannels; j++ ) + { + // int s1_i; + // Word16 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; + samples[i * numChannels + j] = out[j][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 ( numFramesClipped ) + { + printf( "Warning: %d frames have clipped!\n", numFramesClipped ); + } + + return 0; +} diff --git a/lib_util/ambi_convert.c b/lib_util/ambi_convert.c index 0bf2bf226236edeb1681ccb64d67490e58cc3df0..430d7ade2226e88142a50c59e5a14a47d9c97ce3 100644 --- a/lib_util/ambi_convert.c +++ b/lib_util/ambi_convert.c @@ -32,8 +32,9 @@ #include #include -#include "wmc_auto.h" +#include "stl.h" #include "ambi_convert.h" +#include "wmc_auto.h" #define ONE_1_Q29 536870912l /* 1.0f */ #define ONE_OVER_2_Q29 268435456l /* 1.0f/2.0f */ @@ -98,25 +99,25 @@ static const Word32 FM_SN3D[AMBI_MAX_CHANNELS] = { SQRT_2_Q29, channel re-ordering tables ---------------------------- */ -static const int16_t REORDER_FM_ACN[AMBI_MAX_CHANNELS] = { 0, +static const Word16 REORDER_FM_ACN[AMBI_MAX_CHANNELS] = { 0, + 2, 3, 1, + 8, 6, 4, 5, 7, + 15, 13, 11, 9, 10, 12, 14 }; + +static const Word16 REORDER_SID_ACN[AMBI_MAX_CHANNELS] = { 0, 2, 3, 1, - 8, 6, 4, 5, 7, - 15, 13, 11, 9, 10, 12, 14 }; + 5, 7, 8, 6, 4, + 10, 12, 14, 15, 13, 11, 9 }; -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 Word16 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_FM[AMBI_MAX_CHANNELS] = { 0, +static const Word16 REORDER_ACN_SID[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 }; + 8, 4, 7, 5, 6, + 15, 9, 14, 10, 13, 11, 12 }; /* ---------------------------------- API functions for the conversion @@ -129,17 +130,19 @@ static const int16_t REORDER_ACN_SID[AMBI_MAX_CHANNELS] = { 0, --------------------------------------------------------------------------*/ 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 *in[], /* i: input ambisonics channels, Q0 */ + Word16 *out[], /* o: output ambisonics channels, Q0 */ + const Word16 order, /* i: ambisonics order */ + const AMBI_FMT in_format, /* i: input ambisonics format */ + const AMBI_FMT out_format, /* i: output ambisonics format */ + const int16_t frame_length /* i: input/output frame length */ ) { - Word16 tmp[AMBI_MAX_CHANNELS * L_FRAME48k]; + Word16 tmp[AMBI_MAX_CHANNELS * AMBI_MAX_FRAME_LENGTH]; Word16 *p_tmp[AMBI_MAX_CHANNELS]; - AMBI_CONVERT_ERROR err = AMBI_CONVERT_OK; + AMBI_CONVERT_ERROR err_normalize = AMBI_CONVERT_OK; + AMBI_CONVERT_ERROR err_reorder = AMBI_CONVERT_OK; AMBI_CHANNEL_ORDER ch_ord_in = AMBI_CHANNEL_ORDER_ACN; AMBI_CHANNEL_ORDER ch_ord_out = AMBI_CHANNEL_ORDER_ACN; @@ -151,6 +154,11 @@ AMBI_CONVERT_ERROR convert_ambi_format( assert( order <= 3 ); + if ( frame_length > AMBI_MAX_FRAME_LENGTH ) + { + return AMBI_CONVERT_UNSUPPORTED_FRAME_LENGTH; + } + if ( in_format != AMBI_FMT_ACN_SN3D && out_format != AMBI_FMT_ACN_SN3D ) { assert( 0 && "Conversion only supported to and from ACN-SN3D" ); @@ -161,7 +169,7 @@ AMBI_CONVERT_ERROR convert_ambi_format( { p_tmp[j] = &tmp[i]; move32(); - i = add( i, L_FRAME48k ); + i = add( i, frame_length ); } SWITCH( in_format ) @@ -252,70 +260,73 @@ AMBI_CONVERT_ERROR convert_ambi_format( { IF( ch_ord_in != ch_ord_out ) { - IF( ( err = renormalize_channels( in, p_tmp, order, ch_norm_in, ch_norm_out ) ) != AMBI_CONVERT_OK ) + err_normalize = renormalize_channels( in, p_tmp, order, ch_norm_in, ch_norm_out, frame_length ); + IF( ( err_normalize != AMBI_CONVERT_OK ) && ( err_normalize != AMBI_CONVERT_CLIPPING_DETECTED ) ) { - return err; + return err_normalize; } - IF( ( err = reorder_channels( p_tmp, out, order, ch_ord_in, ch_ord_out ) ) != AMBI_CONVERT_OK ) + IF( ( err_reorder = reorder_channels( p_tmp, out, order, ch_ord_in, ch_ord_out, frame_length ) ) != AMBI_CONVERT_OK ) { - return err; + return err_reorder; } } ELSE { - IF( ( err = renormalize_channels( in, out, order, ch_norm_in, ch_norm_out ) ) != AMBI_CONVERT_OK ) + err_normalize = renormalize_channels( in, out, order, ch_norm_in, ch_norm_out, frame_length ); + IF( ( err_normalize != AMBI_CONVERT_OK ) && ( err_normalize != AMBI_CONVERT_CLIPPING_DETECTED ) ) { - return err; + return err_normalize; } } } 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 ) + IF( ( err_reorder = reorder_channels( in, out, order, ch_ord_in, ch_ord_out, frame_length ) ) != AMBI_CONVERT_OK ) { - return err; + return err_reorder; } } 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 ) + IF( ( err_reorder = reorder_channels( in, p_tmp, order, ch_ord_in, ch_ord_out, frame_length ) ) != AMBI_CONVERT_OK ) { - return err; + return err_reorder; } - IF( ( err = renormalize_channels( p_tmp, out, order, ch_norm_in, ch_norm_out ) ) != AMBI_CONVERT_OK ) + err_normalize = renormalize_channels( p_tmp, out, order, ch_norm_in, ch_norm_out, frame_length ); + IF( ( err_normalize != AMBI_CONVERT_OK ) && ( err_normalize != AMBI_CONVERT_CLIPPING_DETECTED ) ) { - return err; + return err_normalize; } } ELSE { - IF( ( err = renormalize_channels( in, out, order, ch_norm_in, ch_norm_out ) ) != AMBI_CONVERT_OK ) + IF( ( err_normalize = renormalize_channels( in, out, order, ch_norm_in, ch_norm_out, frame_length ) ) != AMBI_CONVERT_OK ) { - return err; + return err_normalize; } } } 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 ) + IF( ( err_reorder = reorder_channels( in, out, order, ch_ord_in, ch_ord_out, frame_length ) ) != AMBI_CONVERT_OK ) { - return err; + return err_reorder; } } 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 ) ); + Word16 i_chan = 0; + Word16 n_chan = i_mult2( add( order, 1 ), add( order, 1 ) ); FOR( i_chan = 0; i_chan < n_chan; i_chan++ ) { - int16_t i = 0; + Word16 i_s = 0; move16(); - FOR( i = 0; i < L_FRAME48k; i++ ) + FOR( i_s = 0; i_s < frame_length; i_s++ ) { - out[i_chan][i] = in[i_chan][i]; + out[i_chan][i_s] = in[i_chan][i_s]; move16(); } } @@ -325,7 +336,7 @@ AMBI_CONVERT_ERROR convert_ambi_format( assert( 0 && "This should never happen!" ); } - return AMBI_CONVERT_OK; + return err_normalize; } /*-------------------------------------------------------------------------* @@ -335,15 +346,16 @@ AMBI_CONVERT_ERROR convert_ambi_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 */ + Word16 *in[], /* i: input ambisonics channels, Q0 */ + Word16 *out[], /* o: output ambisonics channels, Q0 */ + const Word16 order, /* i: ambisonics order */ + const AMBI_CHANNEL_NORM in_format, /* i: input ambisonics format */ + const AMBI_CHANNEL_NORM out_format, /* i: output ambisonics format */ + const int16_t frame_length /* i: input/output frame length */ ) { - int16_t n_chan = i_mult2( add( order, 1 ), add( order, 1 ) ); - int16_t i_chan, i; + Word16 n_chan = i_mult2( add( order, 1 ), add( order, 1 ) ); + Word16 i_chan, i; const Word32 *conversion_table = 0; Word32 minval = 0; Word32 maxval = 0; @@ -408,7 +420,7 @@ AMBI_CONVERT_ERROR renormalize_channels( Word32 conversion_factor = conversion_table[i_chan]; Word32 outval; move32(); - FOR( i = 0; i < L_FRAME48k; i++ ) + FOR( i = 0; i < frame_length; i++ ) { Word64 tmp; tmp = W_mult0_32_32( (Word32) in[i_chan][i], conversion_factor ); @@ -416,6 +428,7 @@ AMBI_CONVERT_ERROR renormalize_channels( outval = W_extract_l( W_shr( tmp, Q29 ) ); minval = L_min( minval, outval ); maxval = L_min( maxval, outval ); + outval = L_min( MAX16B, L_max( MIN16B, outval ) ); /* saturation */ out[i_chan][i] = extract_l( outval ); } } @@ -433,17 +446,18 @@ AMBI_CONVERT_ERROR renormalize_channels( --------------------------------------------------------------------------*/ 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 */ + Word16 *in[], /* i: input ambisonics channels, Q0 */ + Word16 *out[], /* o: output ambisonics channels, Q0 */ + const Word16 order, /* i: ambisonics order */ + const AMBI_CHANNEL_ORDER in_format, /* i: input ambisonics format */ + const AMBI_CHANNEL_ORDER out_format, /* i: output ambisonics format */ + const int16_t frame_length /* i: input/output frame length */ ) { - int16_t n_chan = i_mult2( add( order, 1 ), add( order, 1 ) ); - int16_t i_chan, i; + Word16 n_chan = i_mult2( add( order, 1 ), add( order, 1 ) ); + Word16 i_chan, i; Word16 tmp[AMBI_MAX_CHANNELS]; - const int16_t *idx_table = 0; + const Word16 *idx_table = 0; IF( in_format == AMBI_CHANNEL_ORDER_ACN ) { @@ -484,11 +498,11 @@ AMBI_CONVERT_ERROR reorder_channels( return AMBI_CONVERT_UNSUPPORTED_CONVERSION; } - FOR( i = 0; i < L_FRAME48k; i++ ) + FOR( i = 0; i < frame_length; i++ ) { FOR( i_chan = 0; i_chan < n_chan; i_chan++ ) { - int16_t idx = idx_table[i_chan]; + Word16 idx = idx_table[i_chan]; move16(); tmp[i_chan] = in[idx][i]; move16(); diff --git a/lib_util/ambi_convert.h b/lib_util/ambi_convert.h index 207bd276f1c98f1552f49e3d0560023765ec5686..cbb50af3fb2f999074cf067aadbc7c959b821bb5 100644 --- a/lib_util/ambi_convert.h +++ b/lib_util/ambi_convert.h @@ -33,17 +33,12 @@ #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" +#include "stl.h" +#include "cnst.h" - -#define L_FRAME48k 960 -#define AMBI_MAX_CHANNELS 16 +#define AMBI_MAX_FRAME_LENGTH 960 /* 20ms at 48 kHz Sampling rate */ +#define AMBI_MAX_CHANNELS 16 typedef enum { @@ -74,30 +69,34 @@ typedef enum { AMBI_CONVERT_OK = 0, AMBI_CONVERT_UNSUPPORTED_CONVERSION, + AMBI_CONVERT_UNSUPPORTED_FRAME_LENGTH, 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 */ + Word16 *in[], /* i: input ambisonics channels, Q0 */ + Word16 *out[], /* o: output ambisonics channels, Q0 */ + const Word16 order, /* i: ambisonics order */ + const AMBI_FMT in_format, /* i: input ambisonics format */ + const AMBI_FMT out_format, /* i: output ambisonics format */ + const int16_t frame_length /* i: input/output frame length */ ); 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 */ + Word16 *in[], /* i: input ambisonics channels, Q0 */ + Word16 *out[], /* o: output ambisonics channels, Q0 */ + const Word16 order, /* i: ambisonics order */ + const AMBI_CHANNEL_NORM in_format, /* i: input ambisonics format */ + const AMBI_CHANNEL_NORM out_format, /* i: output ambisonics format */ + const int16_t frame_length /* i: input/output frame length */ ); 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 */ + Word16 *in[], /* i: input ambisonics channels, Q0 */ + Word16 *out[], /* o: output ambisonics channels, Q0 */ + const Word16 order, /* i: ambisonics order */ + const AMBI_CHANNEL_ORDER in_format, /* i: input ambisonics format */ + const AMBI_CHANNEL_ORDER out_format, /* i: output ambisonics format */ + const int16_t frame_length /* i: input/output frame length */ ); #endif