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;