diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bfdc075dbca0d146489c1859e017ffcd47bd0d70..c0d30e9e53a82e53b6be67f0d1ca2c70038ea1ee 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1209,6 +1209,7 @@ coverage-test-on-main-scheduled: stage: test artifacts: name: "$CI_JOB_NAME--$CI_COMMIT_REF_NAME--sha-$CI_COMMIT_SHA" + when: always expire_in: 1 week paths: - $CI_JOB_NAME-public @@ -1225,7 +1226,9 @@ complexity-stereo-in-stereo-out: - in_format=stereo - out_format=stereo - bash ci/complexity_measurements/getWmops.sh "$in_format" "$out_format" + - ret_val=$? - *complexity-measurements-prepare-artifacts + - exit $ret_val complexity-ism-in-binaural-out: extends: @@ -1241,7 +1244,9 @@ complexity-ism-in-binaural-out: - in_format=ISM - out_format=BINAURAL - bash ci/complexity_measurements/getWmops.sh "ISM+1 ISM+2 ISM+3 ISM+4" "$out_format" + - ret_val=$? - *complexity-measurements-prepare-artifacts + - exit $ret_val complexity-sba-hoa3-in-hoa3-out: extends: @@ -1257,7 +1262,9 @@ complexity-sba-hoa3-in-hoa3-out: - in_format=SBA - out_format=HOA3 - bash ci/complexity_measurements/getWmops.sh "$in_format" "$out_format" + - ret_val=$? - *complexity-measurements-prepare-artifacts + - exit $ret_val complexity-mc-in-7_1_4-out: extends: @@ -1273,7 +1280,9 @@ complexity-mc-in-7_1_4-out: - in_format=MC - out_format=7_1_4 - bash ci/complexity_measurements/getWmops.sh "$in_format" "$out_format" + - ret_val=$? - *complexity-measurements-prepare-artifacts + - exit $ret_val complexity-masa-in-7_1_4-out: extends: @@ -1289,7 +1298,9 @@ complexity-masa-in-7_1_4-out: - in_format=MASA - out_format=7_1_4 - bash ci/complexity_measurements/getWmops.sh "$in_format" "$out_format" + - ret_val=$? - *complexity-measurements-prepare-artifacts + - exit $ret_val complexity-StereoDmxEVS-stereo-in-mono-out: extends: @@ -1305,7 +1316,9 @@ complexity-StereoDmxEVS-stereo-in-mono-out: - in_format=StereoDmxEVS - out_format=mono - bash ci/complexity_measurements/getWmops.sh "$in_format" "$out_format" + - ret_val=$? - *complexity-measurements-prepare-artifacts + - exit $ret_val # --------------------------------------------------------------- # Other jobs diff --git a/apps/decoder.c b/apps/decoder.c index fd5cb7a00e78bfabe0d017b75203fd2964fcdad4..939085acd155997e4c125b8a111b1467ad6d4ddc 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -579,10 +579,10 @@ int main( IVAS_RENDER_CONFIG_DATA renderConfig; /* sanity check */ -#ifdef SPLIT_REND_WITH_HEAD_ROT +#ifdef SPLIT_REND_WITH_HEAD_ROT if ( arg.outputFormat != IVAS_DEC_OUTPUT_BINAURAL && arg.outputFormat != IVAS_DEC_OUTPUT_BINAURAL_ROOM_IR && arg.outputFormat != IVAS_DEC_OUTPUT_BINAURAL_ROOM_REVERB && - arg.outputFormat != IVAS_DEC_OUTPUT_SPLIT_BINAURAL_CLDFB && - arg.outputFormat != IVAS_DEC_OUTPUT_SPLIT_BINAURAL_PCM ) + arg.outputFormat != IVAS_DEC_OUTPUT_SPLIT_BINAURAL_CLDFB && + arg.outputFormat != IVAS_DEC_OUTPUT_SPLIT_BINAURAL_PCM ) { fprintf( stderr, "\nExternal Renderer Config is supported only when binaural output configurations is used as output OR when Split rendering mode is enabled. Exiting. \n" ); exit( -1 ); diff --git a/ci/complexity_measurements/getWmops.sh b/ci/complexity_measurements/getWmops.sh index baec52ab6f1e7064b3be60679d0d1aafc8f681ad..e81575892bbead122c6770e92715ebb04b5f0299 100755 --- a/ci/complexity_measurements/getWmops.sh +++ b/ci/complexity_measurements/getWmops.sh @@ -53,8 +53,11 @@ config_file="scripts/config/ci_linux_ltv.json" wmopsFilenameFlcLast=wmops_newsletter_stereo__${commit_sha}_${date} wmopsFilenameFlc=${destDir}/wmops/logs/${wmopsFilenameFlcLast} +ret_val=0 + # instrument and build ./scripts/IvasBuildAndRunChecks.py -p $config_file --checks COMPLEXITY --create_complexity_tables ${wmopsFilenameFlc} -C $ivas_format -f ${ep} --oc $output_format +ret_val=$? # get the info on worst-case operating point: WMOPS number, enc-operating mode, dec-operating mode ### WMOPS @@ -83,4 +86,4 @@ ${scriptDir}/parseNewsletterRom.py ${wmopsFilenameFlc}_PROM.csv ${wmopsFilenameF # generate java script from database tcsh ${scriptDir}/genWebpageData_Rom.csh ${destDir}/wmops/log_rom_all.txt ${destDir}/wmops/graphs_rom_flc.js Graphs_ROM - +exit $ret_val \ No newline at end of file diff --git a/lc3plus/adjust_global_gain.c b/lc3plus/adjust_global_gain.c old mode 100644 new mode 100755 diff --git a/lc3plus/al_fec_fl.c b/lc3plus/al_fec_fl.c old mode 100644 new mode 100755 diff --git a/lc3plus/apply_global_gain.c b/lc3plus/apply_global_gain.c old mode 100644 new mode 100755 diff --git a/lc3plus/ari_codec.c b/lc3plus/ari_codec.c old mode 100644 new mode 100755 diff --git a/lc3plus/attack_detector.c b/lc3plus/attack_detector.c old mode 100644 new mode 100755 diff --git a/lc3plus/clib.h b/lc3plus/clib.h old mode 100644 new mode 100755 diff --git a/lc3plus/constants.c b/lc3plus/constants.c old mode 100644 new mode 100755 diff --git a/lc3plus/constants.h b/lc3plus/constants.h old mode 100644 new mode 100755 diff --git a/lc3plus/cutoff_bandwidth.c b/lc3plus/cutoff_bandwidth.c old mode 100644 new mode 100755 diff --git a/lc3plus/dct4.c b/lc3plus/dct4.c old mode 100644 new mode 100755 diff --git a/lc3plus/dec_entropy.c b/lc3plus/dec_entropy.c old mode 100644 new mode 100755 diff --git a/lc3plus/dec_lc3_fl.c b/lc3plus/dec_lc3_fl.c old mode 100644 new mode 100755 diff --git a/lc3plus/defines.h b/lc3plus/defines.h old mode 100644 new mode 100755 diff --git a/lc3plus/detect_cutoff_warped.c b/lc3plus/detect_cutoff_warped.c old mode 100644 new mode 100755 diff --git a/lc3plus/enc_entropy.c b/lc3plus/enc_entropy.c old mode 100644 new mode 100755 diff --git a/lc3plus/enc_lc3_fl.c b/lc3plus/enc_lc3_fl.c old mode 100644 new mode 100755 diff --git a/lc3plus/estimate_global_gain.c b/lc3plus/estimate_global_gain.c old mode 100644 new mode 100755 diff --git a/lc3plus/fft/cfft.c b/lc3plus/fft/cfft.c old mode 100644 new mode 100755 diff --git a/lc3plus/fft/cfft.h b/lc3plus/fft/cfft.h old mode 100644 new mode 100755 diff --git a/lc3plus/fft/fft_15_16.h b/lc3plus/fft/fft_15_16.h old mode 100644 new mode 100755 diff --git a/lc3plus/fft/fft_240_480.h b/lc3plus/fft/fft_240_480.h old mode 100644 new mode 100755 diff --git a/lc3plus/fft/fft_2_9.h b/lc3plus/fft/fft_2_9.h old mode 100644 new mode 100755 diff --git a/lc3plus/fft/fft_32.h b/lc3plus/fft/fft_32.h old mode 100644 new mode 100755 diff --git a/lc3plus/fft/fft_384_768.h b/lc3plus/fft/fft_384_768.h old mode 100644 new mode 100755 diff --git a/lc3plus/fft/fft_60_128.h b/lc3plus/fft/fft_60_128.h old mode 100644 new mode 100755 diff --git a/lc3plus/fft/fft_generic.h b/lc3plus/fft/fft_generic.h old mode 100644 new mode 100755 diff --git a/lc3plus/fft/iis_fft.c b/lc3plus/fft/iis_fft.c old mode 100644 new mode 100755 diff --git a/lc3plus/fft/iis_fft.h b/lc3plus/fft/iis_fft.h old mode 100644 new mode 100755 diff --git a/lc3plus/fft/iisfft.c b/lc3plus/fft/iisfft.c old mode 100644 new mode 100755 diff --git a/lc3plus/fft/iisfft.h b/lc3plus/fft/iisfft.h old mode 100644 new mode 100755 diff --git a/lc3plus/functions.h b/lc3plus/functions.h old mode 100644 new mode 100755 diff --git a/lc3plus/imdct.c b/lc3plus/imdct.c old mode 100644 new mode 100755 diff --git a/lc3plus/lc3.c b/lc3plus/lc3.c old mode 100644 new mode 100755 diff --git a/lc3plus/lc3.h b/lc3plus/lc3.h old mode 100644 new mode 100755 diff --git a/lc3plus/license.h b/lc3plus/license.h old mode 100644 new mode 100755 diff --git a/lc3plus/ltpf_coder.c b/lc3plus/ltpf_coder.c old mode 100644 new mode 100755 diff --git a/lc3plus/ltpf_decoder.c b/lc3plus/ltpf_decoder.c old mode 100644 new mode 100755 diff --git a/lc3plus/makefile b/lc3plus/makefile new file mode 100755 index 0000000000000000000000000000000000000000..16758fc306b31c62b36944bdb7d44af4bc2b161f --- /dev/null +++ b/lc3plus/makefile @@ -0,0 +1,143 @@ +# GNU Makefile + +# Options +AFL = 0 +CLANG = 0 +GCOV = 0 +NO_POST_REL_CHANGES_TEST = 0 +OPTIM = 0 + +# Paths +VPATH = . +BUILD = build +CC = gcc +LINK = $(CC) + +# Binary Name +NAME_LC3 = LC3plus +# Shared Library Name +LIB_LC3 = libLC3plus.so + +# Default tool settings +CC = gcc +RM = rm -f + +# Preprocessor(-I/-D) / Compiler / Linker flags +CFLAGS += -std=c99 -fPIC \ + -pedantic -Wcast-qual -Wall -W -Wextra -Wno-long-long \ + -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes \ + -Werror-implicit-function-declaration + +LDFLAGS += -lm -g +# Include dependency flags +DEPFLAGS = -MT $@ -MMD -MP -MF $(BUILD)/$*.Td + +ifneq "$(DEBUG)" "0" + CFLAGS += -g3 + LDFLAGS += -g3 +endif + +ifeq "$(GCOV)" "1" + CFLAGS += -fprofile-arcs -ftest-coverage + LDFLAGS += -fprofile-arcs -ftest-coverage +endif + +OPTIM ?= 0 +CFLAGS += -O$(OPTIM) +CFLAGS += $(foreach DIR,$(SRC_DIRS),-I$(DIR)) + +ifeq "$(NO_POST_REL_CHANGES_TEST)" "1" +CFLAGS += -DNO_POST_REL_CHANGES +endif + +# memory sanitizer, find use of uninitialized memory +ifeq "$(CLANG)" "1" + CC = clang + CFLAGS += -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer + LDFLAGS += -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer + OPTIM = 2 +endif + +# address sanitizer, find buffer overflows +ifeq "$(CLANG)" "2" + CC = clang + CFLAGS += -fsanitize=address -fno-omit-frame-pointer + LDFLAGS += -fsanitize=address -fno-omit-frame-pointer + OPTIM = 2 +endif + +# undefined behavior sanitizer, find bugs like integer overflows +ifeq "$(CLANG)" "3" + CC = clang + CFLAGS += -fsanitize=undefined + LDFLAGS += -fsanitize=undefined + OPTIM = 2 +endif + +# for code coverate test +ifeq "$(GCOV)" "1" + CFLAGS += -fprofile-arcs -ftest-coverage + LDFLAGS += -fprofile-arcs -ftest-coverage +endif + +# verbose output +ifneq "$(VERBOSE)" "1" + QUIET = @ +endif + +# dependency magic +CC_FLAGS = '$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS)' +POSTCOMPILE = mv -f $(BUILD)/$*.Td $(BUILD)/$*.d && touch $@ + +######## Generate source / object lists ######## + +SRCS := $(notdir $(foreach DIR, $(VPATH), $(wildcard $(DIR)/*.c))) +SRCS_LIB := $(notdir $(foreach DIR, $(VPATH), $(wildcard $(DIR)/*.c))) +OBJS := $(addprefix $(BUILD)/, $(SRCS:.c=.o)) + +LIBSRCS := $(filter-out $(DIR)/ccConvert.c $(DIR)/codec_exe.c, $(SRCS)) +LIBOBJS := $(addprefix $(BUILD)/, $(LIBSRCS:.c=.o)) + +.PHONY: all clean help force + +.PRECIOUS: $(BUILD)/%.d + +all: $(NAME_LC3) + +help: + @echo 'Targets:' + @echo ' $(NAME_LC3) (default)' + @echo ' $(LIB_LC3)' + @echo 'Syntax: make [OPTION=VALUE ...]' + @echo 'Build options:' + @echo ' NO_POST_REL_CHANGES_TEST $(NO_POST_REL_CHANGES_TEST) [0,1]' + @echo ' OPTIM $(OPTIM) [0-3]' + @echo 'Debug options:' + @echo ' AFL $(AFL) [0,1]' + @echo ' CLANG $(CLANG) [0-3]' + @echo ' GCOV $(GCOV) [0,1]' + +$(NAME_LC3): $(OBJS) + @echo 'Linking' $@ + $(QUIET) $(LINK) $(OBJS) -o $@ $(LDFLAGS) + +$(LIB_LC3): $(LIBOBJS) + @echo 'Linking' $@ + $(QUIET) $(LINK) --shared $(OBJS) -o $@ $(LDFLAGS) + +clean: + $(QUIET) rm -rf $(NAME_LC3) $(LIB_LC3) $(BUILD) ccConvert + +$(BUILD)/%.o : %.c $(BUILD)/cc_flags + @echo 'Compiling' $< + $(QUIET) $(CC) $(DEPFLAGS) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< + $(QUIET) $(POSTCOMPILE) + +# force rebuild if compilation flags changed +$(BUILD)/cc_flags: force + $(QUIET) mkdir -p $(BUILD) + $(QUIET) echo $(CC_FLAGS) | cmp -s - $@ || echo $(CC_FLAGS) > $@ + +# force rebuild if include dependency changed +$(BUILD)/%.d: ; +include $(wildcard $(patsubst %, $(BUILD)/%.d, $(basename $(SRCS)))) diff --git a/lc3plus/mdct.c b/lc3plus/mdct.c old mode 100644 new mode 100755 diff --git a/lc3plus/mdct_shaping.c b/lc3plus/mdct_shaping.c old mode 100644 new mode 100755 diff --git a/lc3plus/msvc/.gitignore b/lc3plus/msvc/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..f40a919a54ac022a26a6b1bb65896bcf7f78a550 --- /dev/null +++ b/lc3plus/msvc/.gitignore @@ -0,0 +1 @@ +Win32/ \ No newline at end of file diff --git a/lc3plus/msvc/LC3plus.sln b/lc3plus/msvc/LC3plus.sln new file mode 100755 index 0000000000000000000000000000000000000000..a8ee38ea8125ddcc0d52c93bf705525b213539c9 --- /dev/null +++ b/lc3plus/msvc/LC3plus.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.168 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LC3_FL", "LC3plus.vcxproj", "{95030B82-70CD-4C6B-84D4-61096035BEA2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {95030B82-70CD-4C6B-84D4-61096035BEA2}.Debug|x64.ActiveCfg = Debug|Win32 + {95030B82-70CD-4C6B-84D4-61096035BEA2}.Debug|x64.Build.0 = Debug|Win32 + {95030B82-70CD-4C6B-84D4-61096035BEA2}.Debug|x86.ActiveCfg = Debug|Win32 + {95030B82-70CD-4C6B-84D4-61096035BEA2}.Debug|x86.Build.0 = Debug|Win32 + {95030B82-70CD-4C6B-84D4-61096035BEA2}.Release|x64.ActiveCfg = Release|x64 + {95030B82-70CD-4C6B-84D4-61096035BEA2}.Release|x64.Build.0 = Release|x64 + {95030B82-70CD-4C6B-84D4-61096035BEA2}.Release|x86.ActiveCfg = Release|Win32 + {95030B82-70CD-4C6B-84D4-61096035BEA2}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/lc3plus/msvc/LC3plus.vcxproj b/lc3plus/msvc/LC3plus.vcxproj new file mode 100755 index 0000000000000000000000000000000000000000..ffbfdf344b8cd02e064a280f53263082258b5f68 --- /dev/null +++ b/lc3plus/msvc/LC3plus.vcxproj @@ -0,0 +1,184 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {95030B82-70CD-4C6B-84D4-61096035BEA2} + Win32Proj + LC3_FL + 10.0.17763.0 + + + + StaticLibrary + true + v141 + Unicode + + + StaticLibrary + false + v141 + true + Unicode + + + + + + + + + + + + + + + true + LC3plus + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\Obj\ + + + false + LC3plus + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\Obj\ + + + + + + Level3 + ..\..\lib_com;%(AdditionalIncludeDirectories) + Disabled + MultiThreadedDebug + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + 4305;4244;4996 + + + Console + true + + + + + Level3 + + + ..\..\lib_com;%(AdditionalIncludeDirectories) + MaxSpeed + MultiThreaded + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + 4244;4305;4996 + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lc3plus/near_nyquist_detector.c b/lc3plus/near_nyquist_detector.c old mode 100644 new mode 100755 diff --git a/lc3plus/noise_factor.c b/lc3plus/noise_factor.c old mode 100644 new mode 100755 diff --git a/lc3plus/noise_filling.c b/lc3plus/noise_filling.c old mode 100644 new mode 100755 diff --git a/lc3plus/olpa.c b/lc3plus/olpa.c old mode 100644 new mode 100755 diff --git a/lc3plus/pc_apply.c b/lc3plus/pc_apply.c old mode 100644 new mode 100755 diff --git a/lc3plus/pc_classify.c b/lc3plus/pc_classify.c old mode 100644 new mode 100755 diff --git a/lc3plus/pc_main.c b/lc3plus/pc_main.c old mode 100644 new mode 100755 diff --git a/lc3plus/pc_update.c b/lc3plus/pc_update.c old mode 100644 new mode 100755 diff --git a/lc3plus/per_band_energy.c b/lc3plus/per_band_energy.c old mode 100644 new mode 100755 diff --git a/lc3plus/plc_classify.c b/lc3plus/plc_classify.c old mode 100644 new mode 100755 diff --git a/lc3plus/plc_compute_stab_fac.c b/lc3plus/plc_compute_stab_fac.c old mode 100644 new mode 100755 diff --git a/lc3plus/plc_damping_scrambling.c b/lc3plus/plc_damping_scrambling.c old mode 100644 new mode 100755 diff --git a/lc3plus/plc_main.c b/lc3plus/plc_main.c old mode 100644 new mode 100755 diff --git a/lc3plus/plc_noise_substitution.c b/lc3plus/plc_noise_substitution.c old mode 100644 new mode 100755 diff --git a/lc3plus/plc_noise_substitution0.c b/lc3plus/plc_noise_substitution0.c old mode 100644 new mode 100755 diff --git a/lc3plus/plc_phecu_f0_refine_first.c b/lc3plus/plc_phecu_f0_refine_first.c old mode 100644 new mode 100755 diff --git a/lc3plus/plc_phecu_fec_hq.c b/lc3plus/plc_phecu_fec_hq.c old mode 100644 new mode 100755 diff --git a/lc3plus/plc_phecu_hq_ecu.c b/lc3plus/plc_phecu_hq_ecu.c old mode 100644 new mode 100755 diff --git a/lc3plus/plc_phecu_lf_peak_analysis.c b/lc3plus/plc_phecu_lf_peak_analysis.c old mode 100644 new mode 100755 diff --git a/lc3plus/plc_phecu_rec_frame.c b/lc3plus/plc_phecu_rec_frame.c old mode 100644 new mode 100755 diff --git a/lc3plus/plc_phecu_setf0hz.c b/lc3plus/plc_phecu_setf0hz.c old mode 100644 new mode 100755 diff --git a/lc3plus/plc_phecu_spec_ana.c b/lc3plus/plc_phecu_spec_ana.c old mode 100644 new mode 100755 diff --git a/lc3plus/plc_phecu_subst_spec.c b/lc3plus/plc_phecu_subst_spec.c old mode 100644 new mode 100755 diff --git a/lc3plus/plc_phecu_tba_per_band_gain.c b/lc3plus/plc_phecu_tba_per_band_gain.c old mode 100644 new mode 100755 diff --git a/lc3plus/plc_phecu_tba_spect_Xavg.c b/lc3plus/plc_phecu_tba_spect_Xavg.c old mode 100644 new mode 100755 diff --git a/lc3plus/plc_phecu_tba_trans_dect_gains.c b/lc3plus/plc_phecu_tba_trans_dect_gains.c old mode 100644 new mode 100755 diff --git a/lc3plus/plc_phecu_trans_burst_ana_sub.c b/lc3plus/plc_phecu_trans_burst_ana_sub.c old mode 100644 new mode 100755 diff --git a/lc3plus/plc_tdc.c b/lc3plus/plc_tdc.c old mode 100644 new mode 100755 diff --git a/lc3plus/plc_tdc_tdac.c b/lc3plus/plc_tdc_tdac.c old mode 100644 new mode 100755 diff --git a/lc3plus/plc_update.c b/lc3plus/plc_update.c old mode 100644 new mode 100755 diff --git a/lc3plus/quantize_spec.c b/lc3plus/quantize_spec.c old mode 100644 new mode 100755 diff --git a/lc3plus/reorder_bitstream.c b/lc3plus/reorder_bitstream.c old mode 100644 new mode 100755 diff --git a/lc3plus/resamp12k8.c b/lc3plus/resamp12k8.c old mode 100644 new mode 100755 diff --git a/lc3plus/residual_coding.c b/lc3plus/residual_coding.c old mode 100644 new mode 100755 diff --git a/lc3plus/residual_decoding.c b/lc3plus/residual_decoding.c old mode 100644 new mode 100755 diff --git a/lc3plus/setup_com_lc3.c b/lc3plus/setup_com_lc3.c old mode 100644 new mode 100755 diff --git a/lc3plus/setup_dec_lc3.c b/lc3plus/setup_dec_lc3.c old mode 100644 new mode 100755 diff --git a/lc3plus/setup_dec_lc3.h b/lc3plus/setup_dec_lc3.h old mode 100644 new mode 100755 diff --git a/lc3plus/setup_enc_lc3.c b/lc3plus/setup_enc_lc3.c old mode 100644 new mode 100755 diff --git a/lc3plus/setup_enc_lc3.h b/lc3plus/setup_enc_lc3.h old mode 100644 new mode 100755 diff --git a/lc3plus/sns_compute_scf.c b/lc3plus/sns_compute_scf.c old mode 100644 new mode 100755 diff --git a/lc3plus/sns_interpolate_scf.c b/lc3plus/sns_interpolate_scf.c old mode 100644 new mode 100755 diff --git a/lc3plus/sns_quantize_scf.c b/lc3plus/sns_quantize_scf.c old mode 100644 new mode 100755 diff --git a/lc3plus/structs.h b/lc3plus/structs.h old mode 100644 new mode 100755 diff --git a/lc3plus/tinywavein_c.h b/lc3plus/tinywavein_c.h new file mode 100755 index 0000000000000000000000000000000000000000..c7bd58593c2667b8e3c4d1440e2b9dae2cbde244 --- /dev/null +++ b/lc3plus/tinywavein_c.h @@ -0,0 +1,605 @@ +/****************************************************************************** +* ETSI TS 103 634 V1.4.1 * +* Low Complexity Communication Codec Plus (LC3plus) * +* * +* Copyright licence is solely granted through ETSI Intellectual Property * +* Rights Policy, 3rd April 2019. No patent licence is granted by implication, * +* estoppel or otherwise. * +******************************************************************************/ + + +#ifndef __TINYWAVEIN_C_H__ +#define __TINYWAVEIN_C_H__ + +/*#define SUPPORT_BWF*/ + +#include +#include +#include + + +#if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64) || defined(__arm__) || \ + defined(__aarch64__) +#define __TWI_LE /* _T_iny _W_ave _I_n _L_ittle _E_ndian */ +#endif + +#if defined(__POWERPC__) +#define __TWI_BE /* _T_iny _W_ave _I_n _B_ig _E_ndian */ +#endif + +#if !defined(__TWI_LE) && !defined(__TWI_BE) +#error unknown processor +#endif + +#define __TWI_SUCCESS (0) +#define __TWI_ERROR (-1) + +#ifdef SUPPORT_BWF +typedef struct +{ + float loudnessVal; + float loudnessRange; + float maxTruePeakLevel; + float maxMomentaryLoudnes; + float maxShortTermLoudness; +} WAVEIN_LOUDNESSINFO; +#endif + +typedef struct __tinyWaveInHandle +{ + FILE * theFile; + fpos_t dataChunkPos; + unsigned int position; + unsigned int length; + unsigned int bps; +#ifdef SUPPORT_BWF + WAVEIN_LOUDNESSINFO *loudnessInfo; +#endif +} __tinyWaveInHandle, WAVEFILEIN; + +typedef struct +{ + short compressionCode; + short numberOfChannels; + unsigned int sampleRate; + unsigned int averageBytesPerSecond; + short blockAlign; + short bitsPerSample; + /* short extraFormatBytes ; */ +} SWavInfo; + +#ifdef SUPPORT_BWF +typedef struct +{ + unsigned char description[256]; + unsigned char originator[32]; + unsigned char originatorReference[32]; + unsigned char originatorDate[10]; /* ASCII: <> */ + unsigned char originationTime[8]; /* ASCII: <> */ + unsigned int timeReferenceLow; + unsigned int timeReferenceHigh; + unsigned short version; + unsigned char UMID[64]; /* Binary Bytes of SMPTE UMID */ + + signed short loudnessVal; + signed short loudnessRange; + signed short maxTruePeakLevel; + signed short maxMomentaryLoudnes; + signed short maxShortTermLoudness; + + unsigned char Reserved[180]; + + unsigned char codingHistory; /* ASCII: <> */ +} SBwfWav; +#endif + +typedef struct +{ + char chunkID[4]; + unsigned int chunkSize; + /* long dataOffset ; */ /* never used */ +} SChunk; + +/* local wrapper, always returns correct endian */ +static size_t fread_LE(void *ptr, size_t size, size_t nmemb, FILE *stream); + +#ifdef __TWI_BE +static short BigEndian16(short v); +static int BigEndian32(int v); +#endif + +/*! + * \brief Read header from a WAVEfile. Host endianess is handled accordingly. + * \fp filepointer of type FILE*. + * \wavinfo SWavInfo struct where the decoded header info is stored into. + * \return 0 on success and non-zero on failure. + * + */ +static WAVEFILEIN *OpenWav(const char *filename, unsigned int *samplerate, short *channels, unsigned int *samplesInFile, + short *bps) +{ + WAVEFILEIN *self; + + SChunk fmt_chunk, data_chunk; + int offset; + unsigned int tmpSize; + char tmpFormat[4]; + SWavInfo wavinfo = {0, 0, 0, 0, 0, 0}; + + self = (WAVEFILEIN *)calloc(1, sizeof(WAVEFILEIN)); + if (!self) + goto bail; /* return NULL; */ + + if (!filename) + goto bail; + if (!samplerate) + goto bail; + if (!channels) + goto bail; + if (!samplesInFile) + goto bail; + if (!bps) + goto bail; + + self->theFile = fopen(filename, "rb"); + if (!self->theFile) + goto bail; + + /* read RIFF-chunk */ + if (fread(tmpFormat, 1, 4, self->theFile) != 4) + { + goto bail; + } + + if (strncmp("RIFF", tmpFormat, 4)) + { + goto bail; + } + + /* Read RIFF size. Ignored. */ + fread_LE(&tmpSize, 4, 1, self->theFile); + + /* read WAVE-chunk */ + if (fread(tmpFormat, 1, 4, self->theFile) != 4) + { + goto bail; + } + + if (strncmp("WAVE", tmpFormat, 4)) + { + goto bail; + } + + /* read format/bext-chunk */ + if (fread(fmt_chunk.chunkID, 1, 4, self->theFile) != 4) + { + goto bail; + } + +#ifdef SUPPORT_BWF + /* test for bext-chunk */ + if (!strncmp("bext", fmt_chunk.chunkID, 4)) + { + /*unsigned int i;*/ + unsigned int bextSize = 0; + + if (fread_LE(&bextSize, 1, 4, self->theFile) != 4) + { + goto bail; + } + + self->loudnessInfo = (WAVEIN_LOUDNESSINFO *)calloc(1, sizeof(WAVEIN_LOUDNESSINFO)); + + if (bextSize >= 602) + { /* minimum size bext-data, w/o 'CodingHistory' */ + int i; + signed short readBuf = 0; + signed int nulbuf = 0; + + /* first skip all descriptive data */ + for (i = 0; i < 412; i++) + { + if (fread_LE(&nulbuf, 1, 1, self->theFile) != 1) + { + goto bail; + } + bextSize -= 1; + } + /* second, read loudness data */ + fread_LE(&readBuf, 2, 1, self->theFile); + bextSize -= 2; + self->loudnessInfo->loudnessVal = (float)readBuf * 0.01f; + + fread_LE(&readBuf, 2, 1, self->theFile); + bextSize -= 2; + self->loudnessInfo->loudnessRange = (float)readBuf * 0.01f; + + fread_LE(&readBuf, 2, 1, self->theFile); + bextSize -= 2; + self->loudnessInfo->maxTruePeakLevel = (float)readBuf * 0.01f; + + fread_LE(&readBuf, 2, 1, self->theFile); + bextSize -= 2; + self->loudnessInfo->maxMomentaryLoudnes = (float)readBuf * 0.01f; + + fread_LE(&readBuf, 2, 1, self->theFile); + bextSize -= 2; + self->loudnessInfo->maxShortTermLoudness = (float)readBuf * 0.01f; + + /* skip reserved data */ + for (i = 0; i < 180; i++) + { + if (fread_LE(&nulbuf, 1, 1, self->theFile) != 1) + { + goto bail; + } + bextSize -= 1; + } + } + + /* skip remaining data */ + while (bextSize) + { + int nulbuf; + if (fread_LE(&nulbuf, 1, 1, self->theFile) != 1) + { + goto bail; + } + bextSize -= 1; + } + + /* read next chunk header */ + if (fread(fmt_chunk.chunkID, 1, 4, self->theFile) != 4) + { + goto bail; + } + } +#endif + + /* skip some potential chunks up to fmt chunk */ + + while (strncmp("fmt ", fmt_chunk.chunkID, 4) != 0) + { + unsigned int chunkSize = 0; + + if (fread_LE(&chunkSize, 1, 4, self->theFile) != 4) + { + goto bail; + } + + /* skip chunk data */ + while (chunkSize) + { + int nulbuf; + if (fread_LE(&nulbuf, 1, 1, self->theFile) != 1) + { + goto bail; + } + chunkSize -= 1; + } + + /* read next chunk header */ + if (fread(fmt_chunk.chunkID, 1, 4, self->theFile) != 4) + { + goto bail; + } + } + + /* go on with fmt-chunk */ + if (strncmp("fmt ", fmt_chunk.chunkID, 4)) + { + goto bail; + } + + if (fread_LE(&fmt_chunk.chunkSize, 4, 1, self->theFile) != 1) + { /* should be 16 for PCM-format (uncompressed) */ + goto bail; + } + + + /* read info */ + fread_LE(&(wavinfo.compressionCode), 2, 1, self->theFile); + fread_LE(&(wavinfo.numberOfChannels), 2, 1, self->theFile); + fread_LE(&(wavinfo.sampleRate), 4, 1, self->theFile); + fread_LE(&(wavinfo.averageBytesPerSecond), 4, 1, self->theFile); + fread_LE(&(wavinfo.blockAlign), 2, 1, self->theFile); + fread_LE(&(wavinfo.bitsPerSample), 2, 1, self->theFile); + + if (wavinfo.compressionCode == -2) + { + fseek(self->theFile, 8, SEEK_CUR); // skip channel mask + fread_LE(&(wavinfo.compressionCode), 2, 1, self->theFile); // part of GUID + fseek(self->theFile, 14, SEEK_CUR); // skip rest of GUID + offset = fmt_chunk.chunkSize - 40; + } + else + offset = fmt_chunk.chunkSize - 16; + + if (wavinfo.compressionCode == 0x01) + { + if ((wavinfo.bitsPerSample != 16) && (wavinfo.bitsPerSample != 24) && (wavinfo.bitsPerSample != 32)) + /* we do only support 16,24 and 32 bit PCM audio */ + goto bail; + } + else + { + /* if(wavinfo.bitsPerSample != 32) */ + printf("compressioncode: %02x\n", wavinfo.compressionCode); + puts("Error! We only support 16,24 and 32 bit PCM audio"); + exit(1); + goto bail; + } + + /* Skip rest of fmt header if any. */ + for (; offset > 0; offset--) + { + fread(&tmpSize, 1, 1, self->theFile); + } + + do + { + + /* Read data chunk ID */ + if (fread(data_chunk.chunkID, 1, 4, self->theFile) != 4) + { + goto bail; + } + + /* Read chunk length. */ + + if (fread_LE(&offset, 4, 1, self->theFile) != 1) + { + goto bail; + } + + /* Check for data chunk signature. */ + if (strncmp("data", data_chunk.chunkID, 4) == 0) + { + data_chunk.chunkSize = offset; + break; + } + + /* unused 1 byte present, if size is odd */ + /* see https://www.daubnet.com/en/file-format-riff */ + if (offset % 2) + { + offset++; + } + + /* Jump over non data chunk. */ + for (; offset > 0; offset--) + { + fread(&tmpSize, 1, 1, self->theFile); + } + + } while (!feof(self->theFile)); + + /* success so far */ + *samplerate = wavinfo.sampleRate; + *channels = wavinfo.numberOfChannels; + *samplesInFile = data_chunk.chunkSize / wavinfo.numberOfChannels; + *samplesInFile /= ((wavinfo.bitsPerSample + 7) / 8); + *bps = wavinfo.bitsPerSample; + + self->position = 0; + self->bps = wavinfo.bitsPerSample; + self->length = *samplesInFile * wavinfo.numberOfChannels; + + fgetpos(self->theFile, &self->dataChunkPos); + + return self; + +bail: + free(self); + return NULL; +} + +#ifdef SUPPORT_BWF +static void ReadBWF(WAVEFILEIN *self, WAVEIN_LOUDNESSINFO **wavInLoudness) +{ + *wavInLoudness = self->loudnessInfo; +} +#endif + +static int __ReadSample16(WAVEFILEIN *self, int *sample) +{ + size_t cnt; + short v = 0; + + cnt = fread(&v, 2, 1, self->theFile); + + if (cnt != 1) + { + return __TWI_ERROR; + } + + self->position += 1; + +#ifdef __TWI_BE + v = BigEndian16(v); +#endif + *sample = v; + return __TWI_SUCCESS; +} + +static int __ReadSample24(WAVEFILEIN *self, int *sample) +{ + size_t cnt; + int v = 0; + + cnt = fread(&v, 3, 1, self->theFile); + + if (cnt != 1) + { + return __TWI_ERROR; + } + + self->position += 1; + +#ifdef __TWI_BE + v = BigEndian32(v); +#endif + + if (v >= 0x800000) + { + v |= 0xff000000; + } + + *sample = v; + + return __TWI_SUCCESS; +} + +static int __ReadSample32(WAVEFILEIN *self, int *sample) +{ + size_t cnt; + int v = 0; + + cnt = fread(&v, 4, 1, self->theFile); + + if (cnt != 1) + { + return __TWI_ERROR; + } + + self->position += 1; + +#ifdef __TWI_BE + v = BigEndian32(v); +#endif + + *sample = v >> 8; + + return __TWI_SUCCESS; +} + +static int __ReadSampleInternal(WAVEFILEIN *self, int *sample, int scale) +{ + int err; + + if (!self) + { + return __TWI_ERROR; + } + + switch (scale) + { + + case 16: err = __ReadSample16(self, sample); break; + + case 24: err = __ReadSample24(self, sample); break; + + case 32: err = __ReadSample32(self, sample); break; + + default: err = __TWI_ERROR; break; + } + + return err; +} + +/* this function returns normalized values in the range +8388607..-8388608 */ +static int ReadWavInt(WAVEFILEIN *self, int sampleBuffer[], unsigned int nSamplesToRead, unsigned int *nSamplesRead) +{ + unsigned int i; + int err = __TWI_SUCCESS; + *nSamplesRead = 0; + + if (!sampleBuffer) + { + return __TWI_ERROR; + } + + /* check if we have enough samples left, if not, + set nSamplesToRead to number of samples left. */ + if (self->position + nSamplesToRead > self->length) + { + nSamplesToRead = self->length - self->position; + } + + for (i = 0; i < nSamplesToRead; i++) + { + + int tmp; + err = __ReadSampleInternal(self, &tmp, self->bps); + if (err != __TWI_SUCCESS) + { + return err; + } + sampleBuffer[i] = tmp; + *nSamplesRead += 1; + } + + return __TWI_SUCCESS; +} + +static int CloseWavIn(WAVEFILEIN *self) +{ + if (self) + { + if (self->theFile) + { + fclose(self->theFile); + } + } + free(self); + + return __TWI_SUCCESS; +} +/* +static int ResetWavIn(WAVEFILEIN* self) +{ + if (self) { + if (self->theFile) { + fsetpos(self->theFile, &self->dataChunkPos); + self->position = 0; + } + } + return __TWI_SUCCESS; +} +*/ +/*------------- local subs ----------------*/ + +static size_t fread_LE(void *ptr, size_t size, size_t nmemb, FILE *stream) +{ +#ifdef __TWI_LE + return fread(ptr, size, nmemb, stream); +#endif +#ifdef __TWI_BE + + unsigned char x[sizeof(int)]; + unsigned char *y = (unsigned char *)ptr; + int i; + int len; + + len = fread(x, size, nmemb, stream); + + for (i = 0; i < size * nmemb; i++) + { + *y++ = x[size * nmemb - i - 1]; + } + + return len; +#endif +} + +#ifdef __TWI_BE +static short BigEndian16(short v) +{ + short a = (v & 0x0ff); + short b = (v & 0x0ff00) >> 8; + + return a << 8 | b; +} + +static int BigEndian32(int v) +{ + int a = (v & 0x0ff); + int b = (v & 0x0ff00) >> 8; + int c = (v & 0x0ff0000) >> 16; + int d = (v & 0xff000000) >> 24; + + return a << 24 | b << 16 | c << 8 | d; +} +#endif + +#endif /* __TINYWAVEIN_C_H__ */ diff --git a/lc3plus/tinywaveout_c.h b/lc3plus/tinywaveout_c.h new file mode 100755 index 0000000000000000000000000000000000000000..323b09d51cdf159aecd96b2a9dc378694d4a1186 --- /dev/null +++ b/lc3plus/tinywaveout_c.h @@ -0,0 +1,892 @@ +/****************************************************************************** +* ETSI TS 103 634 V1.4.1 * +* Low Complexity Communication Codec Plus (LC3plus) * +* * +* Copyright licence is solely granted through ETSI Intellectual Property * +* Rights Policy, 3rd April 2019. No patent licence is granted by implication, * +* estoppel or otherwise. * +******************************************************************************/ + + + + +#ifndef __TINYWAVEOUT_C_H__ +#define __TINYWAVEOUT_C_H__ + +/*#define TWO_SUPPORT_BWF*/ + +#include +#include +#include +#include +#ifdef TWO_SUPPORT_BWF +#include +#endif + +/***** Interface *********************************************************/ + +#ifndef TWO_UINT64 + #if !(defined(WIN32)) + #include + #define TWO_UINT64 uint64_t + #else + #define TWO_UINT64 unsigned __int64 + #endif +#endif + +typedef struct WAVEFILEOUT WAVEFILEOUT; +#ifdef TWO_SUPPORT_BWF +typedef struct WAVEOUT_LOUDNESSINFO WAVEOUT_LOUDNESSINFO; +#endif + +#define __TWO_SUCCESS (0) +#define __TWO_ERROR (-1) + +static WAVEFILEOUT* CreateWav( + const char *fileName, + const unsigned int sampleRate, + const unsigned int numChannels, + const unsigned int bps + ); + +#ifdef TWO_SUPPORT_BWF +static WAVEFILEOUT* CreateWavBWF( + const char *fileName, + const unsigned int sampleRate, + const unsigned int numChannels, + const unsigned int bps, + const WAVEOUT_LOUDNESSINFO *hBwfData + ); +#endif + +/* this function expects values in the 16 bit range +32767..-32768 */ +static int WriteWavShort( + WAVEFILEOUT* self, + short sampleBuffer[], + unsigned int nSamples + ); + +/* this function expects values in the 24 bit range +8388607..-8388608 */ +static int WriteWavLong( + WAVEFILEOUT* self, + int sampleBuffer[], + unsigned int nSamples + ); + +/* this function expects normalized values in the range +-1.0f */ +static int WriteWavFloat( + WAVEFILEOUT* self, + float sampleBuffer[], + unsigned int nSamples + ); + +static int CloseWav(WAVEFILEOUT* self); +#ifdef TWO_SUPPORT_BWF +static int CloseWavBWF(WAVEFILEOUT* self, WAVEOUT_LOUDNESSINFO bextData); +#endif + +/***** Implementation *********************************************************/ + +#if defined (__i386__) || defined (_M_IX86) || defined (_M_X64) || defined (__x86_64__) || defined (__arm__) || defined (__xtensa__) || defined (__aarch64__) || defined (__EMSCRIPTEN__) +#define __TWO_LE /* _T_iny _W_ave _O_ut _L_ittle _E_ndian */ +#endif + +#if defined (__POWERPC__) +#define __TWO_BE /* _T_iny _W_ave _O_ut _B_ig _E_ndian */ +#endif + +#if defined (__sparc__) +#define __TWO_BE /* _T_iny _W_ave _O_ut _B_ig _E_ndian */ +#endif + +#if ! defined (__TWO_LE) && ! defined (__TWO_BE) +#error unknown processor +#endif + +/*--- local types/structs ----------------------------------*/ + +#if defined(_MSC_VER) + #pragma pack(push, 1) +#else + #pragma pack(1) +#endif + + +#ifdef TWO_SUPPORT_BWF +struct WAVEOUT_LOUDNESSINFO { + float loudnessVal; + float loudnessRange; + float maxTruePeakLevel; + float maxMomentaryLoudnes; + float maxShortTermLoudness; +}; +#endif + + +typedef struct __tinyWaveOutHeader +{ + unsigned int riffType; /* 'RIFF/RF64' */ + unsigned int riffSize; /* file size/-1 */ + unsigned int waveType; /* 'WAVE' */ +} __tinyWaveOutHeader; + +typedef struct __tinyWaveOutDs64Chunk +{ + unsigned int formatType; /* = 'JUNK/ds64' */ + unsigned int formatSize; /* size info */ + TWO_UINT64 riffSize64; + TWO_UINT64 dataSize64; + TWO_UINT64 sampleCount64; + unsigned int tableLength; /* optional tables, always 0 for tinywaveout */ + /* here: optional tables */ +} __tinyWaveOutDs64Chunk; + +#ifdef TWO_SUPPORT_BWF +typedef struct __tinyWaveOutBextChunk +{ + unsigned int formatType; /* = 'bext' */ + unsigned int formatSize; /* size info */ + + unsigned char description[256]; + unsigned char originator[32]; + unsigned char originatorReference[32]; + unsigned char originatorDate[10]; /* ASCII: <> */ + unsigned char originationTime[8]; /* ASCII: <> */ + unsigned int timeReferenceLow; + unsigned int timeReferenceHigh; + unsigned short version; + unsigned char UMID[64]; /* Binary Bytes of SMPTE UMID */ + + signed short loudnessVal; + signed short loudnessRange; + signed short maxTruePeakLevel; + signed short maxMomentaryLoudnes; + signed short maxShortTermLoudness; + + unsigned char Reserved[180]; + + unsigned char codingHistory; /* ASCII: <> - undefined length! */ + /* for variable length, mve this out of this struct */ +} __tinyWaveOutBextChunk; +#endif + +typedef struct __tinyWaveOutFmtChunk +{ + unsigned int formatType; + unsigned int formatSize; + + unsigned short formatTag; + unsigned short numChannels; + unsigned int sampleRate; + unsigned int bytesPerSecond; + unsigned short blockAlignment; + unsigned short bitsPerSample; + + /* wav fmt ext hdr here */ +} __tinyWaveOutFmtChunk; + +typedef struct __tinyWaveOutDataChunk +{ + unsigned int dataType; + unsigned int dataSize; + +} __tinyWaveOutDataChunk; + + +struct WAVEFILEOUT { + /* for reasons of memory alignment, have 64 bit data types first */ + TWO_UINT64 dataSize; + TWO_UINT64 dataSizeLimit; /* maximum size for data chunk for 4 GB files */ + TWO_UINT64 dataSizeLimit64; /* maximum size for data chunk for 2^64 B addressable files */ + TWO_UINT64 clipCount; + FILE* theFile; + unsigned int junkChunkOffset; + unsigned int fmtChunkOffset; +#ifdef TWO_SUPPORT_BWF + unsigned int bextChunkOffset; +#endif + unsigned int dataChunkOffset; + unsigned int bps; + + /* only needed for RF64: */ + unsigned int blockAlign; /* only needed for close() of ds64 chunk */ +}; + + +/*--- local protos --------------------------------------------------*/ +static __inline unsigned int BigEndian32(char, char, char, char); +static __inline unsigned int LittleEndian32(unsigned int); +static __inline unsigned int LittleEndian32s(int); +static __inline short LittleEndian16(short); +static __inline TWO_UINT64 LittleEndian64(TWO_UINT64); +#ifdef TWO_SUPPORT_BWF +static unsigned int EncodeLoudness(float); +#endif +static __inline int __dataSizeChk( WAVEFILEOUT* self, int newbytes ); + +#if defined(_MSC_VER) + #pragma pack(pop) +#else + #pragma pack() +#endif + + +#ifdef TWO_SUPPORT_BWF +static void setDefaultLoudness(WAVEOUT_LOUDNESSINFO *x) +{ + x->loudnessVal = 1.0f; + x->loudnessRange = 2.0f; + x->maxTruePeakLevel = 3.0f; + x->maxMomentaryLoudnes = 4.0f; + x->maxShortTermLoudness = 5.0f; +} +#endif + +static WAVEFILEOUT* __CreateWavInternal( + const char *fileName, + const unsigned int sampleRate, + const unsigned int numChannels, + const unsigned int bps +#ifdef TWO_SUPPORT_BWF + , + const WAVEOUT_LOUDNESSINFO *hBwfData +#endif + ) +{ + WAVEFILEOUT* self = NULL; + __tinyWaveOutHeader whdr; + __tinyWaveOutDs64Chunk ds64ch; +#ifdef TWO_SUPPORT_BWF + __tinyWaveOutBextChunk wbextch; +#endif + __tinyWaveOutFmtChunk wfch; + __tinyWaveOutDataChunk wdch; + unsigned int blockAlignment = 0; + unsigned int ByteCnt = 0; /* Byte counter for fwrite */ + + /* pseudo use to avoid unused symbols */ + (void)WriteWavShort; + (void)WriteWavLong; + (void)WriteWavFloat; +#ifdef TWI_SUPPORT_BWF + (void)CreateWavBWF; + (void)CloseWavBWF; + (void)setDefaultLoudness; +#endif + + /* param check */ + if (!fileName) goto bail; + if (sampleRate == 0) goto bail; + if (sampleRate > 768000) goto bail; + if (numChannels == 0) goto bail; + if (numChannels > 64) goto bail; + if (bps != 16 && bps != 24 && bps != 32) goto bail; + + self = (WAVEFILEOUT*)calloc(1, sizeof(WAVEFILEOUT)); + if (!self) goto bail; /* return NULL; */ + + self->theFile = fopen(fileName, "wb+"); + if (!self->theFile) goto bail; + + /* WAV-Header */ + whdr.riffType = BigEndian32('R','I','F','F'); + whdr.riffSize = LittleEndian32(0xffffffff); /* set to maximum, if fseek() doesn't work later */ + whdr.waveType = BigEndian32('W','A','V','E'); + /* write to file */ + ByteCnt = 0; + ByteCnt += fwrite(&whdr, 1, sizeof(whdr), self->theFile); + + /* ds64/JUNK-Chunk */ + ds64ch.formatType = BigEndian32('J','U','N','K'); + ds64ch.formatSize = LittleEndian32(sizeof(__tinyWaveOutDs64Chunk) - 8); + ds64ch.riffSize64 = (TWO_UINT64) -1; + ds64ch.dataSize64 = (TWO_UINT64) -1; + ds64ch.sampleCount64 = (TWO_UINT64) -1; + ds64ch.tableLength = 0; + self->junkChunkOffset = ByteCnt; + ByteCnt += fwrite(&ds64ch, 1, sizeof(ds64ch), self->theFile); + +#ifdef TWO_SUPPORT_BWF + /* BEXT-Chunk */ + if (hBwfData) { + memset(&wbextch, 0, sizeof(__tinyWaveOutBextChunk)); + wbextch.formatType = BigEndian32('b','e','x','t'); + wbextch.formatSize = LittleEndian32(sizeof(__tinyWaveOutBextChunk) - 8); + wbextch.version = 0x0002; + wbextch.loudnessVal = EncodeLoudness(hBwfData->loudnessVal); + wbextch.loudnessRange = EncodeLoudness(hBwfData->loudnessRange); + wbextch.maxTruePeakLevel = EncodeLoudness(hBwfData->maxTruePeakLevel); + wbextch.maxMomentaryLoudnes = EncodeLoudness(hBwfData->maxMomentaryLoudnes); + wbextch.maxShortTermLoudness = EncodeLoudness(hBwfData->maxShortTermLoudness); + /* t.b.d.: more values */ + + /* write to file */ + self->bextChunkOffset = ByteCnt; + ByteCnt += fwrite(&wbextch, 1, sizeof(wbextch), self->theFile); + } +#endif + + /* FMT-Chunk */ + wfch.formatType = BigEndian32('f','m','t',' '); + wfch.formatSize = LittleEndian32(16); + switch (bps) { + case 16: + case 24: + wfch.formatTag = LittleEndian16(0x0001); /* WAVE_FORMAT_PCM */ + break; + case 32: + wfch.formatTag = LittleEndian16(0x0003); /* WAVE_FORMAT_IEEE_FLOAT */ + break; + default: + goto bail; + } + self->bps = bps; + wfch.bitsPerSample = LittleEndian16(bps); + wfch.numChannels = LittleEndian16(numChannels); + blockAlignment = numChannels * (bps >> 3); + wfch.blockAlignment = LittleEndian16(blockAlignment); + wfch.sampleRate = LittleEndian32(sampleRate); + wfch.bytesPerSecond = LittleEndian32(sampleRate * blockAlignment); + /* tbd: wavfmt ext hdr here */ + /* write to file */ + self->fmtChunkOffset = ByteCnt; + ByteCnt += fwrite(&wfch, 1, sizeof(wfch), self->theFile); + + /* DATA-Chunk */ + self->dataChunkOffset = ByteCnt; + wdch.dataType = BigEndian32('d','a','t','a'); + wdch.dataSize = LittleEndian32(0xffffffff - ByteCnt); /* yet unknown. set to maximum of 4 GB file */ + /* write to file */ + ByteCnt += fwrite(&wdch, 1, sizeof(wdch), self->theFile); + + self->dataSize = 0; + + /* self->dataSizeLimit = 0x7fffffff - ByteCnt; */ /* maximum size for data chunk for 2 GB files */ + self->dataSizeLimit = 0xffffffff - ByteCnt; /* maximum size for data chunk for 4 GB files */ + self->dataSizeLimit64 = 0xffffffffffffffff - ByteCnt; /* maximum size for data chunk for 64 bit addressable files */ + + self->clipCount = 0; + self->blockAlign = blockAlignment; + + return self; + + bail: + if ( NULL != self) { + free(self); + } + + return NULL; +} + +static WAVEFILEOUT* CreateWav( + const char* fileName, + const unsigned int sampleRate, + const unsigned int numChannels, + const unsigned int bps + ) +{ +#ifdef TWO_SUPPORT_BWF + return __CreateWavInternal(fileName, sampleRate, numChannels, bps, NULL); +#else + return __CreateWavInternal(fileName, sampleRate, numChannels, bps); +#endif +} + +#ifdef TWO_SUPPORT_BWF +static WAVEFILEOUT* CreateWavBWF( + const char *fileName, + const unsigned int sampleRate, + const unsigned int numChannels, + const unsigned int bps, + const WAVEOUT_LOUDNESSINFO *hBwfData + ) +{ + return __CreateWavInternal(fileName, sampleRate, numChannels, bps, hBwfData); +} +#endif + +#define MAX_PCM16 (+32767) +#define MIN_PCM16 (-32768) +static __inline int CLIP_PCM16(int sample, TWO_UINT64* clipcount) +{ + int tmp = sample; + + if (sample >= MAX_PCM16) { + tmp = MAX_PCM16; + (*clipcount)++; + } else { + if (sample <= MIN_PCM16) { + tmp = MIN_PCM16; + (*clipcount)++; + } + } + + return tmp; +} + +#define MAX_PCM24 (+8388607) +#define MIN_PCM24 (-8388608) +static __inline int CLIP_PCM24(int sample, TWO_UINT64* clipcount) +{ + int tmp = sample; + + if (sample >= MAX_PCM24) { + tmp = MAX_PCM24; + (*clipcount)++; + } else { + if (sample <= MIN_PCM24) { + tmp = MIN_PCM24; + (*clipcount)++; + } + } + + return tmp; +} + +#define MAX_FLOAT32 (+1.0f) +#define MIN_FLOAT32 (-1.0f) +static __inline float CLIP_FLOAT32(float sample, TWO_UINT64* clipcount) +{ + float tmp = sample; + + if (sample >= MAX_FLOAT32) { + tmp = MAX_FLOAT32; + (*clipcount)++; + } else { + if (sample <= MIN_FLOAT32) { + tmp = MIN_FLOAT32; + (*clipcount)++; + } + } + + return tmp; +} + + + +static int __WriteSample16( + WAVEFILEOUT* self, + int sample, + int scale + ) +{ + size_t cnt; + short v; + + if ((scale - 16) > 0) + sample = sample >> (scale - 16); + else + sample = (int) ((uint32_t) sample << (16 - scale)); + + v = (short)CLIP_PCM16(sample, &(self->clipCount)); +#ifdef __TWO_BE + v = LittleEndian16(v); +#endif + + cnt = fwrite(&v, sizeof(short), 1, self->theFile); + + if (cnt == 1) { + self->dataSize += 2; + return __TWO_SUCCESS; + } + + return __TWO_ERROR; +} + + +static int __WriteSample24( + WAVEFILEOUT* self, + int sample, + int scale + ) +{ + size_t cnt; + int v; + + if ((scale - 24) > 0) + sample = sample >> (scale - 24); + else + sample = (int) (((unsigned int)sample) << (24 - scale)); + + v = (int)CLIP_PCM24(sample, &(self->clipCount)); +#ifdef __TWO_BE + v = LittleEndian32s(v); +#endif + cnt = fwrite(&v, 3, 1, self->theFile); + + if (cnt == 1) { + self->dataSize += 3; + return __TWO_SUCCESS; + } + + return __TWO_ERROR; +} + + +static int __WriteSample32( + WAVEFILEOUT* self, + float sample + ) +{ + size_t cnt; + union fl_int { + float v_float; + int v_int; + }; + union fl_int v; + +#if CLIP_FLOAT + v.v_float = CLIP_FLOAT32(sample, &(self->clipCount)); +#else + v.v_float = sample; + if((sample > 1.0f) || (sample <-1.0f)) + self->clipCount++; +#endif + +#ifdef __TWO_BE + v.v_int = LittleEndian32s(v.v_int); +#endif + cnt = fwrite(&v, 4, 1, self->theFile); + + if (cnt == 1) { + self->dataSize += 4; + return __TWO_SUCCESS; + } + + return __TWO_ERROR; +} + + +static int __WriteSampleInt( + WAVEFILEOUT* self, + int sample, + int scale + ) +{ + int err; + + if (!self) return __TWO_ERROR; + + + switch (self->bps) { + + case 16: + err = __WriteSample16(self, sample, scale); + break; + + case 24: + err = __WriteSample24(self, sample, scale); + break; + + default: + err = __TWO_ERROR; + break; + } + + return err; +} + + +/* this function expects values in the 16 bit range +-32767/8 */ +static int WriteWavShort( + WAVEFILEOUT* self, + short sampleBuffer[], + unsigned int nSamples + ) +{ + unsigned long i; + int err = __TWO_SUCCESS; + + if (!self) return __TWO_ERROR; + if (!sampleBuffer) return __TWO_ERROR; + if (__dataSizeChk(self, nSamples * sizeof(short))) return __TWO_ERROR; + + for (i=0; i< nSamples; i++) { + if (self->bps == 32) + { + err = __WriteSample32(self, sampleBuffer[i] / 32768.0f); + } + else + { + err = __WriteSampleInt(self, (int)sampleBuffer[i], 16); + } + if (err != __TWO_SUCCESS) return err; + } + + return __TWO_SUCCESS; +} + + +/* this function expects values in the 24 bit range +-8388607/8 */ +static int WriteWavLong( + WAVEFILEOUT* self, + int sampleBuffer[], + unsigned int nSamples + ) +{ + unsigned long i; + int err = __TWO_SUCCESS; + + if (!self) return __TWO_ERROR; + if (!sampleBuffer) return __TWO_ERROR; + if (__dataSizeChk(self, nSamples * sizeof(int))) return __TWO_ERROR; + + for (i = 0; i < nSamples; i++) { + if (self->bps == 32) + { + err = __WriteSample32(self, sampleBuffer[i] / 8388608.0f); + } + else + { + err = __WriteSampleInt(self, sampleBuffer[i], 24); + } + if (err != __TWO_SUCCESS) return err; + } + + return __TWO_SUCCESS; +} + + +/* this function expects normalized values in the range +-1.0 */ +#define MAX_FL (+2.0f * 8388608.0f ) +#define MIN_FL (-2.0f * 8388608.0f ) +#define CLIP_FL(x) ( ((x) >= MAX_FL) ? MAX_FL : (((x) <= MIN_FL) ? MIN_FL : (x)) ) +static int WriteWavFloat( + WAVEFILEOUT* self, + float sampleBuffer[], + unsigned int nSamples + ) +{ + unsigned int i; + int err = __TWO_SUCCESS; + + if (!self) return __TWO_ERROR; + if (!sampleBuffer) return __TWO_ERROR; + if (__dataSizeChk(self, nSamples * sizeof(float))) return __TWO_ERROR; + + for (i=0; ibps == 32) + { + err = __WriteSample32(self, sampleBuffer[i]); + } + else + { + float tmp = CLIP_FL(sampleBuffer[i] * 8388608.0f); /* CLIP_FL is just to avoid an INT overrun before the actual cast to int, real clipping and counting is done below */ + err = __WriteSampleInt(self, (int) tmp, 24); + } + if (err != __TWO_SUCCESS) return err; + } + + return __TWO_SUCCESS; +} + + +static int CloseWav(WAVEFILEOUT* self) +{ + unsigned int riffSize_le = 0; + unsigned int dataSize_le = 0; + TWO_UINT64 riffSize64 = 0; + TWO_UINT64 dataSize64 = 0; + TWO_UINT64 sampleCount64 = 0; /* nr of samples in the WAVE sense: 1 sample are all pcm samples of all channels of one time slice */ + int mustWriteRF64 = 0; + + if (!self) return __TWO_ERROR; + + /* check for 4 GB (switch to RF64) */ + if ( self->dataSize > self->dataSizeLimit ) { + /* when we exceed 4 GB: switch from std wave header to RF64 header */ + mustWriteRF64 = 1; + } + + /* calc header values */ + if (mustWriteRF64 == 0) { + /* write padding byte if dataSize is uneven */ + int pad = 0; + if (self->dataSize % 2 > 0) { + char tmp= 0x00; + fwrite(&tmp, sizeof(char), 1, self->theFile); + pad = 1; + } + riffSize_le = LittleEndian32(self->dataChunkOffset - 8 + 8 + (unsigned int)self->dataSize + pad); /* sizeof(hdr) - (8 bytes of riff chunk header) + (8 bytes data chunk header) + sizeof(raw-pcm-data) + padding Byte */ + dataSize_le = LittleEndian32((unsigned int)self->dataSize); + } else { + riffSize_le = 0xffffffff; + dataSize_le = 0xffffffff; + riffSize64 = LittleEndian64( self->dataSize + (TWO_UINT64)self->dataChunkOffset ); + dataSize64 = LittleEndian64( self->dataSize ); + sampleCount64 = LittleEndian64( self->dataSize / (TWO_UINT64)self->blockAlign ); + } + + /* now overwrite length/size values in header with the actual/real ones */ + if (mustWriteRF64 == 0) { + /* riffsize32 */ + fseek(self->theFile, 4, SEEK_SET); + fwrite(&riffSize_le, sizeof(riffSize_le), 1, self->theFile); + /* datasize32 */ + fseek(self->theFile, self->dataChunkOffset + 4, SEEK_SET); + fwrite(&dataSize_le, sizeof(dataSize_le), 1, self->theFile); + } else { + unsigned int rf64sig = BigEndian32('R','F','6','4'); + unsigned int ds64sig = BigEndian32('d','s','6','4'); + + /* replace RIFF->RF64 */ + fseek(self->theFile, 0, SEEK_SET); + fwrite(&rf64sig, sizeof(rf64sig), 1, self->theFile); + + /* riffsize32 */ + fseek(self->theFile, 4, SEEK_SET); + fwrite(&riffSize_le, sizeof(riffSize_le), 1, self->theFile); + + /* replace JUNK->ds64 */ + fseek(self->theFile, self->junkChunkOffset, SEEK_SET); + fwrite(&ds64sig, sizeof(ds64sig), 1, self->theFile); + + /* riffSize64, dataSize64, sampleCount64 */ + fseek(self->theFile, self->junkChunkOffset + 8, SEEK_SET); + fwrite(&riffSize64, sizeof(riffSize64), 1, self->theFile); + fwrite(&dataSize64, sizeof(dataSize64), 1, self->theFile); + fwrite(&sampleCount64, sizeof(sampleCount64), 1, self->theFile); + + /* datasize32 */ + fseek(self->theFile, self->dataChunkOffset + 4, SEEK_SET); + fwrite(&dataSize_le, sizeof(dataSize_le), 1, self->theFile); + } + + fclose(self->theFile); + free(self); + + return __TWO_SUCCESS; +} + +#ifdef TWO_SUPPORT_BWF +static int CloseWavBWF( + WAVEFILEOUT* self, + WAVEOUT_LOUDNESSINFO bextData + ) +{ + int wordData; + + if (!self) return __TWO_ERROR; + + if (self->bextChunkOffset) { + /* Offset for Loudness Data in bext-chunk: 8: Chunk-Header, 412:prev.Data */ + fseek(self->theFile, self->bextChunkOffset+8+412, SEEK_SET); + + wordData = LittleEndian32(EncodeLoudness(bextData.loudnessVal)); + fwrite(&wordData, 2, 1, self->theFile); + + wordData = LittleEndian32(EncodeLoudness(bextData.loudnessRange)); + fwrite(&wordData, 2, 1, self->theFile); + + wordData = LittleEndian32(EncodeLoudness(bextData.maxTruePeakLevel)); + fwrite(&wordData, 2, 1, self->theFile); + + wordData = LittleEndian32(EncodeLoudness(bextData.maxMomentaryLoudnes)); + fwrite(&wordData, 2, 1, self->theFile); + + wordData = LittleEndian32(EncodeLoudness(bextData.maxShortTermLoudness)); + fwrite(&wordData, 2, 1, self->theFile); + } + + return CloseWav(self); +} +#endif + +/*------------- local subs ----------------*/ + +static __inline unsigned int BigEndian32(char a, char b, char c, char d) +{ +#ifdef __TWO_LE + return + (unsigned int) d << 24 | + (unsigned int) c << 16 | + (unsigned int) b << 8 | + (unsigned int) a ; +#else + return + (unsigned int) a << 24 | + (unsigned int) b << 16 | + (unsigned int) c << 8 | + (unsigned int) d ; +#endif +} + + +static __inline unsigned int LittleEndian32(unsigned int v) +{ +#ifdef __TWO_LE + return v; +#else + return + (v & 0x000000FF) << 24 | + (v & 0x0000FF00) << 8 | + (v & 0x00FF0000) >> 8 | + (v & 0xFF000000) >> 24 ; +#endif +} + + +/* signed version of the above */ +static __inline unsigned int LittleEndian32s(int v) +{ +#ifdef __TWO_LE + return v; +#else + return + (v & 0x000000FF) << 24 | + (v & 0x0000FF00) << 8 | + (v & 0x00FF0000) >> 8 | + (v & 0xFF000000) >> 24 ; +#endif +} + + +static __inline short LittleEndian16(short v) +{ +#ifdef __TWO_LE + return v; +#else + return ((v << 8) & 0xFF00) | ((v >> 8) & 0x00FF); +#endif +} + +static __inline TWO_UINT64 LittleEndian64(TWO_UINT64 v) +{ +#ifdef __TWO_LE + return v; +#else + return + (v & 0x00000000000000FF) << 56 | + (v & 0x000000000000FF00) << 40 | + (v & 0x0000000000FF0000) << 24 | + (v & 0x00000000FF000000) << 8 | + (v & 0x000000FF00000000) >> 8 | + (v & 0x0000FF0000000000) >> 24 | + (v & 0x00FF000000000000) >> 40 | + (v & 0xFF00000000000000) >> 56 ; +#endif +} + +#ifdef TWO_SUPPORT_BWF +static unsigned int EncodeLoudness(float x) +{ + int s = (x>0)-(x<0); + return (int)( x*100.0f + s*0.5f ); +} +#endif + +static __inline int __dataSizeChk( WAVEFILEOUT* self, int newbytes ) +{ + if (!self) return __TWO_ERROR; + + if ( (self->dataSize + ((TWO_UINT64)newbytes) ) > self->dataSizeLimit64 ) { + return __TWO_ERROR; + } + + return __TWO_SUCCESS; +} + +#endif /* __TINYWAVEOUT_C_H__ */ + + + diff --git a/lc3plus/tns_coder.c b/lc3plus/tns_coder.c old mode 100644 new mode 100755 diff --git a/lc3plus/tns_decoder.c b/lc3plus/tns_decoder.c old mode 100644 new mode 100755 diff --git a/lc3plus/util.h b/lc3plus/util.h old mode 100644 new mode 100755 diff --git a/lib_com/options.h b/lib_com/options.h index f788eb8f418bdadd0232d89dea2539312a87adf8..247c850a0ea0dbf95dcef577777a0040f7e9a7d6 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -208,6 +208,7 @@ #define SPLIT_REND_STACK_OPT #define SPLIT_REND_LC3PLUS /* FhG: split rendering using LC3plus codec */ +#define SPLIT_REND_LC3PLUS_MC /* FhG: split rendering using LC3plus codec for Multichannel content */ #define FIX_SPLIT_REND_OPEN_ERROR_HANDLING /* adds missing error handling around ivas_split_renderer_open calls */ // #define SPLIT_REND_LC3PLUS_HBR_DBG /* Override bitrate per LC3 core */ #endif diff --git a/lib_dec/ivas_dec.c b/lib_dec/ivas_dec.c index d57d5cba53a0ef81dc6ef8203c0658d5daa978a9..6db9d8417cdb5394409637dd2e2f7aab2deda503 100644 --- a/lib_dec/ivas_dec.c +++ b/lib_dec/ivas_dec.c @@ -121,7 +121,14 @@ ivas_error ivas_dec( ( output_config == AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ) { #ifdef SPLIT_REND_LC3PLUS +#ifdef SPLIT_REND_LC3PLUS_MC + assert( ( st_ivas->ivas_format == SBA_FORMAT || + ( st_ivas->ivas_format == ISM_FORMAT && st_ivas->ism_mode == ISM_MODE_DISC ) || + ( st_ivas->ivas_format == MC_FORMAT && st_ivas->mc_mode == MC_MODE_MCT ) ) && + ( output_Fs == 48000 ) && "split binaural mode is currently supported with SBA, discrete ISM, or MCT-MC formats and 48 kHz sampling rate only" ); +#else assert( ( st_ivas->ivas_format == SBA_FORMAT || ( st_ivas->ivas_format == ISM_FORMAT && st_ivas->ism_mode == ISM_MODE_DISC ) ) && ( output_Fs == 48000 ) && "split binaural mode is currently supported with SBA or discrete ISM format and 48k sampling rate only" ); +#endif #else assert( st_ivas->ivas_format == SBA_FORMAT && ( output_Fs == 48000 ) && "split binaural mode is currently supported with SBA format and 48k sampling rate only" ); #endif @@ -511,19 +518,30 @@ ivas_error ivas_dec( /* Rendering */ if ( st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV || st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV_ROOM ) { - if ( ( error = ivas_rend_crendProcess( st_ivas->hCrendWrapper, st_ivas->intern_config, st_ivas->hOutSetup.output_config, st_ivas->hDecoderConfig, - st_ivas->hCombinedOrientationData, &st_ivas->hIntSetup, st_ivas->hEFAPdata, p_output, output_Fs +#ifdef SPLIT_REND_LC3PLUS_MC + if ( output_config == AUDIO_CONFIG_BINAURAL_SPLIT_CLDFB ) + { + ivas_rend_crendProcessSplitBin( st_ivas, output, output_frame ); + } + else + { +#endif + if ( ( error = ivas_rend_crendProcess( st_ivas->hCrendWrapper, st_ivas->intern_config, st_ivas->hOutSetup.output_config, st_ivas->hDecoderConfig, + st_ivas->hCombinedOrientationData, &st_ivas->hIntSetup, st_ivas->hEFAPdata, p_output, output_Fs #ifdef SPLIT_REND_WITH_HEAD_ROT - , - 0 + , + 0 #endif - ) ) != IVAS_ERR_OK ) + ) ) != IVAS_ERR_OK ) - { - return error; - } + { + return error; + } - ivas_binaural_add_LFE( st_ivas, output_frame, p_output, p_output ); + ivas_binaural_add_LFE( st_ivas, output_frame, p_output, p_output ); +#ifdef SPLIT_REND_LC3PLUS_MC + } +#endif } else if ( st_ivas->renderer_type == RENDERER_MC ) { @@ -535,12 +553,23 @@ ivas_error ivas_dec( } else if ( st_ivas->renderer_type == RENDERER_BINAURAL_OBJECTS_TD ) { - if ( ( ivas_td_binaural_renderer( st_ivas, p_output, output_frame ) ) != IVAS_ERR_OK ) +#ifdef SPLIT_REND_LC3PLUS_MC + if ( output_config == AUDIO_CONFIG_BINAURAL_SPLIT_CLDFB ) { - return error; + ObjRenderIvasFrame_splitBinaural( st_ivas, output, output_frame ); // TODO tmu check } + else + { +#endif + if ( ( ivas_td_binaural_renderer( st_ivas, p_output, output_frame ) ) != IVAS_ERR_OK ) + { + return error; + } - ivas_binaural_add_LFE( st_ivas, output_frame, p_output, p_output ); + ivas_binaural_add_LFE( st_ivas, output_frame, p_output, p_output ); +#ifdef SPLIT_REND_LC3PLUS_MC + } +#endif } } else if ( st_ivas->mc_mode == MC_MODE_PARAMUPMIX ) diff --git a/lib_dec/ivas_init_dec.c b/lib_dec/ivas_init_dec.c index 46d6cc0904828736f3c971fb59f0911670a96d7a..cfb45b5eb0d7e1adcc615e1dada8e0efd72172fc 100644 --- a/lib_dec/ivas_init_dec.c +++ b/lib_dec/ivas_init_dec.c @@ -1333,7 +1333,7 @@ ivas_error ivas_init_decoder( &st_ivas->hRenderConfig->split_rend_config, &st_ivas->splitBinRend.splitrend.multiBinPoseData, st_ivas->hHeadTrackData->sr_pose_pred_axis ); - /* Split rendering with ISMs only supported with LC3plus */ + /* Split rendering with MC/ISMs only supported with LC3plus */ #ifndef SPLIT_REND_CLDFB_ISM assert( st_ivas->hRenderConfig->split_rend_config.codec == IVAS_SPLIT_REND_CODEC_LC3PLUS ); #endif @@ -1392,12 +1392,37 @@ ivas_error ivas_init_decoder( return error; } } +#ifdef SPLIT_REND_LC3PLUS_MC + + if ( st_ivas->hDecoderConfig->output_config == AUDIO_CONFIG_BINAURAL_SPLIT_CLDFB ) + { + ivas_renderSplitGetMultiBinPoseData( + &st_ivas->hRenderConfig->split_rend_config, + &st_ivas->splitBinRend.splitrend.multiBinPoseData, + st_ivas->hHeadTrackData->sr_pose_pred_axis ); + + /* Split rendering with MC only supported with LC3plus */ + assert( st_ivas->hRenderConfig->split_rend_config.codec == IVAS_SPLIT_REND_CODEC_LC3PLUS ); + + error = ivas_split_renderer_open( &st_ivas->splitBinRend.splitrend, + &st_ivas->hRenderConfig->split_rend_config, + hDecoderConfig->output_Fs, 0, 0 ); + if ( error != IVAS_ERR_OK ) + { + return error; + } + } +#endif if ( ( error = ivas_rend_openCrend( &( st_ivas->hCrendWrapper ), st_ivas->intern_config, st_ivas->hDecoderConfig->output_config, st_ivas->hRenderConfig, st_ivas->hSetOfHRTF, st_ivas->hDecoderConfig->output_Fs #ifdef SPLIT_REND_WITH_HEAD_ROT , +#ifdef SPLIT_REND_LC3PLUS_MC + ( st_ivas->hDecoderConfig->output_config == AUDIO_CONFIG_BINAURAL_SPLIT_CLDFB ) ? st_ivas->splitBinRend.splitrend.multiBinPoseData.num_poses : 1 +#else 1 +#endif #endif ) ) != IVAS_ERR_OK ) { diff --git a/lib_dec/ivas_output_config.c b/lib_dec/ivas_output_config.c index e87b5cd0cb5a0604a728b4b49820f306515128a2..0684349a5938a0cb923c94ad086af7b7b0df481a 100644 --- a/lib_dec/ivas_output_config.c +++ b/lib_dec/ivas_output_config.c @@ -203,7 +203,11 @@ void ivas_renderer_select( else { *internal_config = transport_config; +#ifdef SPLIT_REND_LC3PLUS_MC + if ( output_config == AUDIO_CONFIG_BINAURAL || output_config == AUDIO_CONFIG_BINAURAL_SPLIT_CLDFB || output_config == AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) +#else if ( output_config == AUDIO_CONFIG_BINAURAL ) +#endif { #ifdef DEBUGGING if ( ( ( ( st_ivas->transport_config == AUDIO_CONFIG_5_1 || st_ivas->transport_config == AUDIO_CONFIG_7_1 ) && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) ) || ( st_ivas->hDecoderConfig->force_rend == FORCE_TD_RENDERER ) ) && ( st_ivas->mc_mode == MC_MODE_MCT || st_ivas->mc_mode == MC_MODE_PARAMUPMIX ) && !( st_ivas->hDecoderConfig->force_rend == FORCE_CLDFB_RENDERER ) ) diff --git a/lib_dec/ivas_spar_decoder.c b/lib_dec/ivas_spar_decoder.c index 352d99ba9e9b7d33cd3d04a62b27dfe5483982a5..fc5be70877059810fdbd4a14a53aed12beab3dc7 100755 --- a/lib_dec/ivas_spar_decoder.c +++ b/lib_dec/ivas_spar_decoder.c @@ -1678,11 +1678,11 @@ void ivas_spar_dec_upmixer_sf( } else { - if ( hDecoderConfig->output_config == AUDIO_CONFIG_FOA || !( st_ivas->hOutSetup.output_config == AUDIO_CONFIG_BINAURAL || st_ivas->hOutSetup.output_config == AUDIO_CONFIG_BINAURAL_ROOM_IR || st_ivas->hOutSetup.output_config == AUDIO_CONFIG_BINAURAL_ROOM_REVERB + if ( hDecoderConfig->output_config == AUDIO_CONFIG_FOA || !( st_ivas->hOutSetup.output_config == AUDIO_CONFIG_BINAURAL || st_ivas->hOutSetup.output_config == AUDIO_CONFIG_BINAURAL_ROOM_IR || st_ivas->hOutSetup.output_config == AUDIO_CONFIG_BINAURAL_ROOM_REVERB #ifdef SPLIT_REND_WITH_HEAD_ROT || st_ivas->hDecoderConfig->output_config == AUDIO_CONFIG_BINAURAL_SPLIT_CLDFB || st_ivas->hDecoderConfig->output_config == AUDIO_CONFIG_BINAURAL_SPLIT_PCM #endif - ) ) + ) ) { for ( ts = 0; ts < hSpar->subframe_nbslots[hSpar->subframes_rendered]; ts++ ) { diff --git a/lib_rend/ivas_crend.c b/lib_rend/ivas_crend.c index 22ec6406d2879d690291c69c4eba608f7ab8b583..05c8945e3c3e2e7341697e37b3727f88d14124c8 100644 --- a/lib_rend/ivas_crend.c +++ b/lib_rend/ivas_crend.c @@ -1741,3 +1741,124 @@ ivas_error ivas_rend_crendProcessSubframe( return IVAS_ERR_OK; } +#ifdef SPLIT_REND_LC3PLUS_MC + + +/*-----------------------------------------------------------------------------------------* + * Function ivas_rend_crend_ProcessSplitBin() + * + * Process call for IVAS Crend renderer + *-----------------------------------------------------------------------------------------*/ + +ivas_error ivas_rend_crendProcessSplitBin( + Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */ + float output[][L_FRAME48k], /* i/o: SCE channels / Binaural synthesis */ + const int16_t output_frame /* i : output frame length */ +) +{ + int16_t i, j, sf; + int16_t pos_idx; + ivas_error error; + float gain_lfe; + float tmpLfeBuffer[L_FRAME48k]; + float tmpInputBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k]; + float *p_tmpInputBuffer[MAX_OUTPUT_CHANNELS]; + float tmpSplitBinBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k]; + MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData; + COMBINED_ORIENTATION_DATA combinedOrientationDataLocal; + COMBINED_ORIENTATION_HANDLE pCombinedOrientationDataLocal; + + pMultiBinPoseData = &st_ivas->splitBinRend.splitrend.multiBinPoseData; + + /* copy input */ + for ( i = 0; i < st_ivas->nchan_transport; ++i ) + { + mvr2r( output[i], tmpInputBuffer[i], output_frame ); + } + + for ( i = 0; i < MAX_OUTPUT_CHANNELS; ++i ) + { + p_tmpInputBuffer[i] = tmpInputBuffer[i]; + } + + /* save current head positions */ + pCombinedOrientationDataLocal = st_ivas->hCombinedOrientationData; + combinedOrientationDataLocal = *pCombinedOrientationDataLocal; + for ( sf = 1; sf < RENDERER_HEAD_POSITIONS_PER_FRAME; ++sf ) + { + combinedOrientationDataLocal.Quaternions[sf] = combinedOrientationDataLocal.Quaternions[0]; + for ( i = 0; i < 3; i++ ) + { + for ( j = 0; j < 3; j++ ) + { + combinedOrientationDataLocal.Rmat[sf][i][j] = combinedOrientationDataLocal.Rmat[0][i][j]; + } + } + } + + /* copy LFE to tmpLfeBuffer and apply gain only once */ + mvr2r( output[st_ivas->hIntSetup.index_lfe[0]], tmpLfeBuffer, output_frame ); + gain_lfe = ( ( st_ivas->hCrendWrapper != NULL ) && ( st_ivas->hCrendWrapper->hHrtfCrend != NULL ) ) ? st_ivas->hCrendWrapper->hHrtfCrend->gain_lfe : GAIN_LFE; + v_multc( tmpLfeBuffer, gain_lfe, tmpLfeBuffer, output_frame ); + + for ( pos_idx = 0; pos_idx < pMultiBinPoseData->num_poses; ++pos_idx ) + { + /* Update head positions */ + IVAS_QUATERNION Quaternions_orig[RENDERER_HEAD_POSITIONS_PER_FRAME], Quaternions_abs; + for ( i = 0; i < RENDERER_HEAD_POSITIONS_PER_FRAME; i++ ) + { + Quaternions_orig[i] = combinedOrientationDataLocal.Quaternions[i]; + Quaternions_abs.w = -3.0f; + Quat2EulerDegree( combinedOrientationDataLocal.Quaternions[i], &Quaternions_abs.z, &Quaternions_abs.y, &Quaternions_abs.x ); /*order in Quat2Euler seems to be reversed ?*/ + + Quaternions_abs.x += pMultiBinPoseData->relative_head_poses[pos_idx][0]; + Quaternions_abs.y += pMultiBinPoseData->relative_head_poses[pos_idx][1]; + Quaternions_abs.z += pMultiBinPoseData->relative_head_poses[pos_idx][2]; + combinedOrientationDataLocal.Quaternions[i] = Quaternions_abs; + QuatToRotMat( combinedOrientationDataLocal.Quaternions[i], combinedOrientationDataLocal.Rmat[i] ); + } + + /* render inplace to first two channels of tmpInputBuffer */ + pCombinedOrientationDataLocal = &combinedOrientationDataLocal; + if ( ( error = ivas_rend_crendProcess( st_ivas->hCrendWrapper, + st_ivas->intern_config, + st_ivas->hOutSetup.output_config, + st_ivas->hDecoderConfig, + pCombinedOrientationDataLocal, + &st_ivas->hIntSetup, + st_ivas->hEFAPdata, + p_tmpInputBuffer, + st_ivas->hDecoderConfig->output_Fs, + pos_idx ) ) != IVAS_ERR_OK ) + { + return error; + } + + for ( i = 0; i < BINAURAL_CHANNELS; ++i ) + { + /* accumulate LFE to output */ + v_add( tmpInputBuffer[i], tmpLfeBuffer, tmpInputBuffer[i], output_frame ); + + /* move to split bin output buffer */ + mvr2r( tmpInputBuffer[i], tmpSplitBinBuffer[pos_idx * BINAURAL_CHANNELS + i], output_frame ); + + /* overwrite rendered channels with input again for next iteration */ + mvr2r( output[i], tmpInputBuffer[i], output_frame ); + } + + /* restore original headrotation data */ + for ( i = 0; i < RENDERER_HEAD_POSITIONS_PER_FRAME; i++ ) + { + combinedOrientationDataLocal.Quaternions[i] = Quaternions_orig[i]; + } + } + + /* copy split binaural rendered signals to final output */ + for ( i = 0; i < BINAURAL_CHANNELS * pMultiBinPoseData->num_poses; ++i ) + { + mvr2r( tmpSplitBinBuffer[i], output[i], output_frame ); + } + + return IVAS_ERR_OK; +} +#endif diff --git a/lib_rend/ivas_objectRenderer.c b/lib_rend/ivas_objectRenderer.c index c249ad94860f9e929504a3c4fbd059f112eb9ea8..ef68bb71129cea6a07d429db1809da9ac1007f29 100644 --- a/lib_rend/ivas_objectRenderer.c +++ b/lib_rend/ivas_objectRenderer.c @@ -718,9 +718,17 @@ void ObjRenderIvasFrame_splitBinaural( ) { int32_t i; +#ifdef SPLIT_REND_LC3PLUS_MC + float tmpProcessing[MAX_OUTPUT_CHANNELS][L_FRAME48k]; +#else float tmpProcessing[MAX_NUM_OBJECTS][L_FRAME48k]; +#endif float tmpBinaural[MAX_HEAD_ROT_POSES * 2][L_FRAME48k]; +#ifdef SPLIT_REND_LC3PLUS_MC + float *p_tmpProcessing[MAX_OUTPUT_CHANNELS]; +#else float *p_tmpProcessing[MAX_NUM_OBJECTS]; +#endif int16_t pos_idx; IVAS_QUATERNION originalHeadRot[MAX_PARAM_SPATIAL_SUBFRAMES]; @@ -758,7 +766,11 @@ void ObjRenderIvasFrame_splitBinaural( /* Copy input audio to a processing buffer. Cannot render in-place because binaurally rendered * audio would overwrite original material, which is still needed for rendering next head pose. */ +#ifdef SPLIT_REND_LC3PLUS_MC + for ( i = 0; i < st_ivas->nchan_transport; ++i ) +#else for ( i = 0; i < MAX_NUM_OBJECTS; ++i ) +#endif { mvr2r( output[i], tmpProcessing[i], output_frame ); } @@ -790,7 +802,11 @@ void ObjRenderIvasFrame_splitBinaural( } } } +#ifdef SPLIT_REND_LC3PLUS_MC + for ( i = 0; i < st_ivas->nchan_transport; ++i ) +#else for ( i = 0; i < BINAURAL_CHANNELS; i++ ) +#endif { p_tmpProcessing[i] = tmpProcessing[i]; } diff --git a/lib_rend/ivas_prot_rend.h b/lib_rend/ivas_prot_rend.h index a761b916f766d6f9c470060cc43f527816f928c6..123d147ac424bd6857c93d2b225aeae6c0b29d8b 100644 --- a/lib_rend/ivas_prot_rend.h +++ b/lib_rend/ivas_prot_rend.h @@ -637,6 +637,15 @@ ivas_error ivas_rend_crendProcessSubframe( const int32_t output_Fs /* i : output sampling rate */ ); +#ifdef SPLIT_REND_LC3PLUS_MC +/* TODO tmu : interface cleanup */ +ivas_error ivas_rend_crendProcessSplitBin( + Decoder_Struct *st_ivas, + float output[][L_FRAME48k], + const int16_t output_frame +); +#endif + /*----------------------------------------------------------------------------------* * Reverberator *----------------------------------------------------------------------------------*/ diff --git a/lib_rend/lib_rend.c b/lib_rend/lib_rend.c index f8f1fdecf2f3595dda7b217116d38ce809336545..6bd6ff62b2d65f5b20b89c1b0a0aa20733e83723 100644 --- a/lib_rend/lib_rend.c +++ b/lib_rend/lib_rend.c @@ -177,6 +177,9 @@ typedef struct EFAP_WRAPPER efapInWrapper; TDREND_WRAPPER tdRendWrapper; CREND_WRAPPER_HANDLE crendWrapper; +#ifdef SPLIT_REND_LC3PLUS_MC + TDREND_WRAPPER splitTdRendWrappers[MAX_HEAD_ROT_POSES - 1]; /* Additional TD Rend instances used for split rendering */ +#endif REVERB_HANDLE hReverb; rotation_gains rot_gains_prev; int16_t nonDiegeticPan; @@ -2135,6 +2138,10 @@ static ivas_error updateMcPanGains( switch ( outConfig ) { case IVAS_REND_AUDIO_CONFIG_BINAURAL: +#ifdef SPLIT_REND_LC3PLUS_MC + case IVAS_REND_AUDIO_CONFIG_BINAURAL_SPLIT_CLDFB: + case IVAS_REND_AUDIO_CONFIG_BINAURAL_SPLIT_PCM: +#endif break; /* Do nothing */ case IVAS_REND_AUDIO_CONFIG_BINAURAL_ROOM_IR: case IVAS_REND_AUDIO_CONFIG_BINAURAL_ROOM_REVERB: @@ -2181,6 +2188,9 @@ static ivas_error initMcBinauralRendering( RENDER_CONFIG_DATA *hRendCfg ) { ivas_error error; +#ifdef SPLIT_REND_LC3PLUS_MC + int16_t i; +#endif int32_t outSampleRate; /* check if re-initialization */ @@ -2190,6 +2200,16 @@ static ivas_error initMcBinauralRendering( inputMc->tdRendWrapper.hHrtfTD = NULL; } +#ifdef SPLIT_REND_LC3PLUS_MC + for ( i = 0; i < MAX_HEAD_ROT_POSES - 1; ++i ) + { + if ( inputMc->splitTdRendWrappers[i].hBinRendererTd != NULL ) + { + ivas_td_binaural_close( &inputMc->splitTdRendWrappers[i].hBinRendererTd ); + inputMc->splitTdRendWrappers[i].hHrtfTD = NULL; + } + } +#endif ivas_rend_closeCrend( &inputMc->crendWrapper #ifdef SPLIT_REND_WITH_HEAD_ROT @@ -2235,6 +2255,27 @@ static ivas_error initMcBinauralRendering( return error; } +#ifdef SPLIT_REND_LC3PLUS_MC + if ( outConfig == IVAS_REND_AUDIO_CONFIG_BINAURAL_SPLIT_CLDFB || outConfig == IVAS_REND_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) + { + /* Open TD renderer wrappers */ + for ( i = 0; i < MAX_HEAD_ROT_POSES - 1; ++i ) + { + if ( ( error = ivas_td_binaural_open_ext( &inputMc->splitTdRendWrappers[i], + inConfig, + hRendCfg, + &inputMc->customLsInput, + outSampleRate ) ) != IVAS_ERR_OK ) + { + return error; + } + + /* Assert same delay as main TD renderer */ + assert( inputMc->splitTdRendWrappers[i].binaural_latency_ns == inputMc->tdRendWrapper.binaural_latency_ns ); + } + } + +#endif if ( outConfig == IVAS_REND_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) { if ( ( error = ivas_reverb_open( &( inputMc->hReverb ), getIvasAudioConfigFromRendAudioConfig( outConfig ), NULL, hRendCfg, outSampleRate ) ) != IVAS_ERR_OK ) @@ -2249,7 +2290,11 @@ static ivas_error initMcBinauralRendering( NULL, outSampleRate #ifdef SPLIT_REND_WITH_HEAD_ROT , +#ifdef SPLIT_REND_LC3PLUS_MC + ( ( outConfig == IVAS_REND_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) || ( outConfig == IVAS_REND_AUDIO_CONFIG_BINAURAL_SPLIT_CLDFB ) ) ? inputMc->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses : 1 +#else 1 +#endif #endif ) ) != IVAS_ERR_OK ) { @@ -2365,6 +2410,9 @@ static ivas_error setRendInputActiveMc( const IVAS_REND_InputId id, RENDER_CONFIG_DATA *hRendCfg ) { +#ifdef SPLIT_REND_LC3PLUS_MC + int16_t i; +#endif ivas_error error; rendering_context rendCtx; IVAS_REND_AudioConfig outConfig; @@ -2399,8 +2447,19 @@ static ivas_error setRendInputActiveMc( inputMc->hMcMasa = NULL; initRotGains( inputMc->rot_gains_prev ); inputMc->lfeRouting = defaultLfeRouting( inConfig, inputMc->customLsInput, outConfig, *inputMc->base.ctx.pCustomLsOut ); +#ifdef SPLIT_REND_LC3PLUS_MC + for ( i = 0; i < (int16_t) ( sizeof( inputMc->splitTdRendWrappers ) / sizeof( *inputMc->splitTdRendWrappers ) ); ++i ) + { + inputMc->splitTdRendWrappers[i] = defaultTdRendWrapper(); + } +#endif + +#ifdef SPLIT_REND_LC3PLUS_MC + if ( getAudioConfigType( outConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) +#else if ( outConfig == IVAS_REND_AUDIO_CONFIG_BINAURAL || outConfig == IVAS_REND_AUDIO_CONFIG_BINAURAL_ROOM_IR || outConfig == IVAS_REND_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) +#endif { if ( ( error = initMcBinauralRendering( inputMc, inConfig, outConfig, hRendCfg ) ) != IVAS_ERR_OK ) { @@ -2427,6 +2486,9 @@ static ivas_error setRendInputActiveMc( static void clearInputMc( input_mc *inputMc ) { +#ifdef SPLIT_REND_LC3PLUS_MC + int16_t i; +#endif rendering_context rendCtx; rendCtx = inputMc->base.ctx; @@ -2462,6 +2524,17 @@ static void clearInputMc( inputMc->tdRendWrapper.hHrtfTD = NULL; } +#ifdef SPLIT_REND_LC3PLUS_MC + for ( i = 0; i < MAX_HEAD_ROT_POSES - 1; ++i ) + { + if ( inputMc->splitTdRendWrappers[i].hBinRendererTd != NULL ) + { + ivas_td_binaural_close( &inputMc->splitTdRendWrappers[i].hBinRendererTd ); + inputMc->splitTdRendWrappers[i].hHrtfTD = NULL; + } + } +#endif + ivas_mcmasa_ana_close( &( inputMc->hMcMasa ) ); return; @@ -4236,7 +4309,11 @@ ivas_error IVAS_REND_ConfigureCustomInputLoudspeakerLayout( return error; } +#ifdef SPLIT_REND_LC3PLUS_MC + if ( getAudioConfigType( hIvasRend->outputConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) +#else if ( hIvasRend->outputConfig == IVAS_REND_AUDIO_CONFIG_BINAURAL || hIvasRend->outputConfig == IVAS_REND_AUDIO_CONFIG_BINAURAL_ROOM_IR || hIvasRend->outputConfig == IVAS_REND_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) +#endif { if ( ( error = initMcBinauralRendering( inputMc, inputMc->base.inConfig, hIvasRend->outputConfig, hIvasRend->hRendererConfig ) ) != IVAS_ERR_OK ) { @@ -6277,14 +6354,24 @@ static ivas_error renderActiveInputsIsm( static ivas_error renderLfeToBinaural( const input_mc *mcInput, +#ifdef SPLIT_REND_LC3PLUS_MC + const IVAS_REND_AudioConfig outConfig, +#endif IVAS_REND_AudioBuffer outAudio ) { int16_t i; int16_t lfe_idx; +#ifdef SPLIT_REND_LC3PLUS_MC + int16_t pose_idx, num_poses; +#endif float gain; float *readPtr, *writePtr; +#ifdef SPLIT_REND_LC3PLUS_MC + assert( ( getAudioConfigType( outConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) && "Must be binaural output" ); +#else assert( ( outAudio.config.numChannels == 2 ) && "Must be binaural output" ); +#endif push_wmops( "renderLfeToBinaural" ); @@ -6304,6 +6391,34 @@ static ivas_error renderLfeToBinaural( return IVAS_ERR_OK; } +#ifdef SPLIT_REND_LC3PLUS_MC + /* Copy LFE to left and right binaural channels */ + if ( mcInput->base.ctx.pSplitRendWrapper != NULL ) + { + num_poses = mcInput->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses; + } + else + { + num_poses = 1; + } + + for ( pose_idx = 0; pose_idx < num_poses; ++pose_idx ) + { + readPtr = getSmplPtr( mcInput->base.inputBuffer, lfe_idx, 0 ); + writePtr = getSmplPtr( outAudio, pose_idx * BINAURAL_CHANNELS, 0 ); + for ( i = 0; i < mcInput->base.inputBuffer.config.numSamplesPerChannel; i++ ) + { + *writePtr++ += gain * ( *readPtr++ ); + } + + readPtr = getSmplPtr( mcInput->base.inputBuffer, lfe_idx, 0 ); + writePtr = getSmplPtr( outAudio, pose_idx * BINAURAL_CHANNELS + 1, 0 ); + for ( i = 0; i < mcInput->base.inputBuffer.config.numSamplesPerChannel; i++ ) + { + *writePtr++ += gain * ( *readPtr++ ); + } + } +#else /* Copy LFE to left and right ears */ readPtr = getSmplPtr( mcInput->base.inputBuffer, lfe_idx, 0 ); writePtr = getSmplPtr( outAudio, 0, 0 ); @@ -6318,6 +6433,7 @@ static ivas_error renderLfeToBinaural( { *writePtr++ += gain * ( *readPtr++ ); } +#endif pop_wmops(); @@ -6416,7 +6532,11 @@ static ivas_error renderMcToBinaural( accumulate2dArrayToBuffer( tmpRendBuffer, &outAudio ); +#ifdef SPLIT_REND_LC3PLUS_MC + if ( ( error = renderLfeToBinaural( mcInput, outConfig, outAudio ) ) != IVAS_ERR_OK ) +#else if ( ( error = renderLfeToBinaural( mcInput, outAudio ) ) != IVAS_ERR_OK ) +#endif { return error; } @@ -6514,7 +6634,11 @@ static ivas_error renderMcToBinauralRoom( accumulate2dArrayToBuffer( tmpRendBuffer, &outAudio ); +#ifdef SPLIT_REND_LC3PLUS_MC + if ( ( error = renderLfeToBinaural( mcInput, outConfig, outAudio ) ) != IVAS_ERR_OK ) +#else if ( ( error = renderLfeToBinaural( mcInput, outAudio ) ) != IVAS_ERR_OK ) +#endif { return error; } @@ -6612,7 +6736,11 @@ static ivas_error renderMcCustomLsToBinauralRoom( accumulate2dArrayToBuffer( tmpCrendBuffer, &outAudio ); +#ifdef SPLIT_REND_LC3PLUS_MC + if ( ( error = renderLfeToBinaural( mcInput, outConfig, outAudio ) ) != IVAS_ERR_OK ) +#else if ( ( error = renderLfeToBinaural( mcInput, outAudio ) ) != IVAS_ERR_OK ) +#endif { return error; } @@ -6687,6 +6815,178 @@ static ivas_error renderMcToMasa( return IVAS_ERR_OK; } +#ifdef SPLIT_REND_LC3PLUS_MC +static ivas_error renderMcToSplitBinaural( + input_mc *mcInput, + const IVAS_REND_AudioConfig outConfig, + IVAS_REND_AudioBuffer outAudio ) +{ + int16_t i, j, sf, pos_idx; + int16_t output_frame; + ivas_error error; + const MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData; + const SPLIT_REND_WRAPPER *pSplitRendWrapper; + float tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k]; + float *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS]; + float tmpSplitBinauralBuffer[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k]; + IVAS_REND_AudioConfig inConfig; + IVAS_REND_AudioBuffer tmpRotBuffer; + COMBINED_ORIENTATION_DATA combinedOrientationDataLocal; + COMBINED_ORIENTATION_HANDLE pCombinedOrientationDataLocal; + + push_wmops( "renderMcToSplitBinaural" ); + + inConfig = mcInput->base.inConfig; + output_frame = mcInput->base.inputBuffer.config.numSamplesPerChannel; + + pSplitRendWrapper = mcInput->base.ctx.pSplitRendWrapper; + pMultiBinPoseData = &pSplitRendWrapper->multiBinPoseData; + + for ( i = 0; i < MAX_OUTPUT_CHANNELS; ++i ) + { + p_tmpRendBuffer[i] = tmpRendBuffer[i]; + } + + /* save current head positions */ + pCombinedOrientationDataLocal = *mcInput->base.ctx.pCombinedOrientationData; + combinedOrientationDataLocal = *pCombinedOrientationDataLocal; + for ( sf = 1; sf < RENDERER_HEAD_POSITIONS_PER_FRAME; ++sf ) + { + combinedOrientationDataLocal.Quaternions[sf] = combinedOrientationDataLocal.Quaternions[0]; + for ( i = 0; i < 3; i++ ) + { + for ( j = 0; j < 3; j++ ) + { + combinedOrientationDataLocal.Rmat[sf][i][j] = combinedOrientationDataLocal.Rmat[0][i][j]; + } + } + } + + + for ( pos_idx = 0; pos_idx < pMultiBinPoseData->num_poses; pos_idx++ ) + { + /* Update head positions */ + IVAS_QUATERNION Quaternions_orig[RENDERER_HEAD_POSITIONS_PER_FRAME], Quaternions_abs; + for ( i = 0; i < RENDERER_HEAD_POSITIONS_PER_FRAME; i++ ) + { + Quaternions_orig[i] = combinedOrientationDataLocal.Quaternions[i]; + Quaternions_abs.w = -3.0f; + Quat2EulerDegree( combinedOrientationDataLocal.Quaternions[i], &Quaternions_abs.z, &Quaternions_abs.y, &Quaternions_abs.x ); /*order in Quat2Euler seems to be reversed ?*/ + + Quaternions_abs.x += pMultiBinPoseData->relative_head_poses[pos_idx][0]; + Quaternions_abs.y += pMultiBinPoseData->relative_head_poses[pos_idx][1]; + Quaternions_abs.z += pMultiBinPoseData->relative_head_poses[pos_idx][2]; + combinedOrientationDataLocal.Quaternions[i] = Quaternions_abs; + QuatToRotMat( combinedOrientationDataLocal.Quaternions[i], combinedOrientationDataLocal.Rmat[i] ); + } + + if ( inConfig == IVAS_REND_AUDIO_CONFIG_LS_CUSTOM || inConfig == IVAS_REND_AUDIO_CONFIG_5_1 || inConfig == IVAS_REND_AUDIO_CONFIG_7_1 ) + { + /* tdrend processing overview: + * 1. copy from inputBuffer to tmpRendBuffer + * 2. td_binaural_renderer_ext: inplace processing in tmpRendBuffer + * 3. copy from tmpRendBuffer to tmpSplitBinBuffer + * 4. LFE mixing + * 5. tmpSplitBinBuffer accumulated to outBuffer */ + + /* copy input to tdrend input/output buffer */ + copyBufferTo2dArray( mcInput->base.inputBuffer, tmpRendBuffer ); + + /* Render */ + if ( ( error = ivas_td_binaural_renderer_ext( &mcInput->splitTdRendWrappers[pos_idx - 1], + mcInput->base.inConfig, + &mcInput->customLsInput, + &pCombinedOrientationDataLocal, + NULL, + mcInput->hReverb, + mcInput->base.inputBuffer.config.numSamplesPerChannel, + tmpRendBuffer ) ) != IVAS_ERR_OK ) + { + return error; + } + + /* Copy rendered audio to tmp storage buffer. Copying directly to output would + * overwrite original audio, which is still needed for rendering next head pose. */ + mvr2r( tmpRendBuffer[0], tmpSplitBinauralBuffer[2 * pos_idx], output_frame ); + mvr2r( tmpRendBuffer[1], tmpSplitBinauralBuffer[2 * pos_idx + 1], output_frame ); + } + else + { + /* crend processing overview: + * 1. rotateFrameMc: inputBuffer to tmpRotBuffer + * 2. crend_process: tmpRotBuffer to tmpRendBuffer + * 3. copy from tmpRendBuffer to tmpSplitBinBuffer + * 4. LFE mixing + * 5. tmpSplitBinBuffer accumulated to outBuffer */ + + /* temporary buffer for rotation in source format */ + tmpRotBuffer = mcInput->base.inputBuffer; + tmpRotBuffer.data = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) ); + + /* copy input for in-place rotation */ + mvr2r( mcInput->base.inputBuffer.data, tmpRotBuffer.data, + tmpRotBuffer.config.numChannels * tmpRotBuffer.config.numSamplesPerChannel ); + + /* perform rotation in source format to tmpRotBuffer */ + pCombinedOrientationDataLocal = &combinedOrientationDataLocal; + if ( ( error = rotateFrameMc( mcInput->base.inputBuffer, + mcInput->base.inConfig, + mcInput->customLsInput, + mcInput->base.ctx.pHeadRotData, + &pCombinedOrientationDataLocal, + mcInput->rot_gains_prev, + mcInput->efapInWrapper.hEfap, + tmpRotBuffer ) ) != IVAS_ERR_OK ) + { + return error; + } + + copyBufferTo2dArray( tmpRotBuffer, tmpRendBuffer ); + + /* call CREND (rotation already performed) */ + if ( ( error = ivas_rend_crendProcess( mcInput->crendWrapper, + getIvasAudioConfigFromRendAudioConfig( mcInput->base.inConfig ), + getIvasAudioConfigFromRendAudioConfig( outConfig ), + NULL, + NULL, + NULL, + NULL, + p_tmpRendBuffer, + *mcInput->base.ctx.pOutSampleRate, + pos_idx ) ) != IVAS_ERR_OK ) + { + return error; + } + + /* Copy rendererd audio to tmp storage buffer, Copying directly to output would + * overwrite original audio, which is still needed for rendering next head pose. */ + mvr2r( tmpRendBuffer[0], tmpSplitBinauralBuffer[2 * pos_idx], output_frame ); + mvr2r( tmpRendBuffer[1], tmpSplitBinauralBuffer[2 * pos_idx + 1], output_frame ); + + free( tmpRotBuffer.data ); + } + + /* restore original headrotation data */ + for ( i = 0; i < RENDERER_HEAD_POSITIONS_PER_FRAME; i++ ) + { + combinedOrientationDataLocal.Quaternions[i] = Quaternions_orig[i]; + } + } + + /* TODO tmu : needs delay compensation */ + if ( ( error = renderLfeToBinaural( mcInput, outConfig, outAudio ) ) != IVAS_ERR_OK ) + { + return error; + } + + accumulate2dArrayToBuffer( tmpSplitBinauralBuffer, &outAudio ); + + pop_wmops(); + + return IVAS_ERR_OK; +} + +#endif static ivas_error renderInputMc( input_mc *mcInput, IVAS_REND_AudioConfig outConfig, @@ -6737,6 +7037,12 @@ static ivas_error renderInputMc( error = renderMcToBinauralRoom( mcInput, outConfig, outAudio ); } break; +#ifdef SPLIT_REND_LC3PLUS_MC + case IVAS_REND_AUDIO_CONFIG_BINAURAL_SPLIT_CLDFB: + case IVAS_REND_AUDIO_CONFIG_BINAURAL_SPLIT_PCM: + error = renderMcToSplitBinaural( mcInput, outConfig, outAudio ); + break; +#endif default: return IVAS_ERR_INVALID_OUTPUT_FORMAT; } @@ -8339,8 +8645,13 @@ ivas_error IVAS_REND_GetSamples( || hIvasRend->outputConfig == IVAS_REND_AUDIO_CONFIG_BINAURAL_SPLIT_PCM #endif ) - /* The condition below is a temp fix for differences in procesing paths between split rendering of SBA and ISM. Should be unified */ + /* The condition below is a temp fix for differences in procesing paths between split rendering of SBA and ISM. Should be unified */ +#ifdef SPLIT_REND_LC3PLUS_MC + && ( ( hIvasRend->inputsIsm[0].base.inConfig != IVAS_REND_AUDIO_CONFIG_UNKNOWN ) || + ( hIvasRend->inputsMc[0].base.inConfig != IVAS_REND_AUDIO_CONFIG_UNKNOWN ) ) ) +#else && hIvasRend->inputsIsm[0].base.inConfig != IVAS_REND_AUDIO_CONFIG_UNKNOWN ) +#endif { /* TODO: doesn't work for multiple SBA inputs, needs to be updated like the ISM path for TD */ ivas_split_rend_bits_t bits;