From 48ff7bec32811a42cdc227c2e55a711185e53ec6 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Fri, 16 May 2025 18:05:50 +0300 Subject: [PATCH 01/11] Tools: Rimage: Add Up_down_mixer to TGL and TGL-H .toml This allows to load the component in TGL IPC4 configured devices. The entries are copied from MTL those seem to work also for TGL for test usage. Signed-off-by: Seppo Ingalsuo --- tools/rimage/config/tgl-h.toml | 47 +++++++++++++++++++++++++++++++++- tools/rimage/config/tgl.toml | 47 +++++++++++++++++++++++++++++++++- 2 files changed, 92 insertions(+), 2 deletions(-) diff --git a/tools/rimage/config/tgl-h.toml b/tools/rimage/config/tgl-h.toml index f403ce798ba5..10e2994836a3 100644 --- a/tools/rimage/config/tgl-h.toml +++ b/tools/rimage/config/tgl-h.toml @@ -60,7 +60,7 @@ name = "ADSPFW" load_offset = "0x30000" [module] -count = 27 +count = 28 [[module.entry]] name = "BRNGUP" uuid = "61EB0CB9-34D8-4F59-A21D-04C54C21D3A4" @@ -606,3 +606,48 @@ count = 27 pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + [[module.entry]] + name = "UPDWMIX" + uuid = "42f8060c-832f-4dbf-b247-51e961997b34" + affinity_mask = "0x1" + instance_count = "15" + domain_types = "0" + load_type = "0" + module_type = "5" + auto_start = "0" + sched_caps = [1, 0x00008000] + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xffff, 0xc, 0x8, 0x05ff, + 1, 0, 0xffff, 0xc, 0x8, 0x45ff] + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [1, 0, 0, 0, 216, 5044000, 384, 192, 0, 5044, 0, + 2, 0, 0, 0, 216, 2660000, 384, 384, 0, 2660, 0, + 3, 0, 0, 0, 216, 3164000, 576, 384, 0, 3164, 0, + 4, 0, 0, 0, 216, 3316000, 768, 384, 0, 3316, 0, + 5, 0, 0, 0, 216, 5264000, 768, 384, 0, 5264, 0, + 6, 0, 0, 0, 216, 5440000, 768, 384, 0, 5440, 0, + 7, 0, 0, 0, 216, 2888000, 768, 192, 0, 2888, 0, + 8, 0, 0, 0, 216, 2856000, 768, 192, 0, 2856, 0, + 9, 0, 0, 0, 216, 2876000, 768, 192, 0, 2876, 0, + 10, 0, 0, 0, 216, 2956000, 960, 192, 0, 2956, 0, + 11, 0, 0, 0, 216, 2888000, 1152, 192, 0, 2888, 0, + 12, 0, 0, 0, 216, 2888000, 1152, 192, 0, 2888, 0, + 13, 0, 0, 0, 216, 2816000, 1536, 192, 0, 2816, 0, + 14, 0, 0, 0, 216, 2468000, 192, 384, 0, 2468, 0, + 15, 0, 0, 0, 216, 3084000, 576, 384, 0, 3084, 0, + 16, 0, 0, 0, 216, 3442000, 960, 384, 0, 3442, 0, + 17, 0, 0, 0, 216, 3478000, 1152, 384, 0, 3478, 0, + 18, 0, 0, 0, 216, 3478000, 1152, 384, 0, 3478, 0, + 19, 0, 0, 0, 216, 3736000, 1536, 384, 0, 3736, 0, + 20, 0, 0, 0, 216, 3216000, 192, 1152, 0, 3216, 0, + 21, 0, 0, 0, 216, 3308000, 384, 1152, 0, 3308, 0, + 22, 0, 0, 0, 216, 3616000, 768, 1152, 0, 3616, 0, + 23, 0, 0, 0, 216, 3616000, 768, 1152, 0, 3616, 0, + 24, 0, 0, 0, 216, 4916000, 1536, 1152, 0, 4916, 0, + 25, 0, 0, 0, 216, 3228000, 192, 1152, 0, 3228, 0, + 26, 0, 0, 0, 216, 3452000, 384, 1152, 0, 3452, 0, + 27, 0, 0, 0, 216, 4016000, 768, 1152, 0, 4016, 0, + 28, 0, 0, 0, 216, 5080000, 1536, 1152, 0, 5080, 0, + 29, 0, 0, 0, 216, 3552000, 384, 1536, 0, 3552, 0, + 30, 0, 0, 0, 216, 3728000, 768, 1152, 0, 3728, 0] diff --git a/tools/rimage/config/tgl.toml b/tools/rimage/config/tgl.toml index 82065f8d2d0a..5f447978740e 100644 --- a/tools/rimage/config/tgl.toml +++ b/tools/rimage/config/tgl.toml @@ -60,7 +60,7 @@ name = "ADSPFW" load_offset = "0x30000" [module] -count = 27 +count = 28 [[module.entry]] name = "BRNGUP" uuid = "61EB0CB9-34D8-4F59-A21D-04C54C21D3A4" @@ -606,3 +606,48 @@ count = 27 pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + [[module.entry]] + name = "UPDWMIX" + uuid = "42f8060c-832f-4dbf-b247-51e961997b34" + affinity_mask = "0x1" + instance_count = "15" + domain_types = "0" + load_type = "0" + module_type = "5" + auto_start = "0" + sched_caps = [1, 0x00008000] + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xffff, 0xc, 0x8, 0x05ff, + 1, 0, 0xffff, 0xc, 0x8, 0x45ff] + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [1, 0, 0, 0, 216, 5044000, 384, 192, 0, 5044, 0, + 2, 0, 0, 0, 216, 2660000, 384, 384, 0, 2660, 0, + 3, 0, 0, 0, 216, 3164000, 576, 384, 0, 3164, 0, + 4, 0, 0, 0, 216, 3316000, 768, 384, 0, 3316, 0, + 5, 0, 0, 0, 216, 5264000, 768, 384, 0, 5264, 0, + 6, 0, 0, 0, 216, 5440000, 768, 384, 0, 5440, 0, + 7, 0, 0, 0, 216, 2888000, 768, 192, 0, 2888, 0, + 8, 0, 0, 0, 216, 2856000, 768, 192, 0, 2856, 0, + 9, 0, 0, 0, 216, 2876000, 768, 192, 0, 2876, 0, + 10, 0, 0, 0, 216, 2956000, 960, 192, 0, 2956, 0, + 11, 0, 0, 0, 216, 2888000, 1152, 192, 0, 2888, 0, + 12, 0, 0, 0, 216, 2888000, 1152, 192, 0, 2888, 0, + 13, 0, 0, 0, 216, 2816000, 1536, 192, 0, 2816, 0, + 14, 0, 0, 0, 216, 2468000, 192, 384, 0, 2468, 0, + 15, 0, 0, 0, 216, 3084000, 576, 384, 0, 3084, 0, + 16, 0, 0, 0, 216, 3442000, 960, 384, 0, 3442, 0, + 17, 0, 0, 0, 216, 3478000, 1152, 384, 0, 3478, 0, + 18, 0, 0, 0, 216, 3478000, 1152, 384, 0, 3478, 0, + 19, 0, 0, 0, 216, 3736000, 1536, 384, 0, 3736, 0, + 20, 0, 0, 0, 216, 3216000, 192, 1152, 0, 3216, 0, + 21, 0, 0, 0, 216, 3308000, 384, 1152, 0, 3308, 0, + 22, 0, 0, 0, 216, 3616000, 768, 1152, 0, 3616, 0, + 23, 0, 0, 0, 216, 3616000, 768, 1152, 0, 3616, 0, + 24, 0, 0, 0, 216, 4916000, 1536, 1152, 0, 4916, 0, + 25, 0, 0, 0, 216, 3228000, 192, 1152, 0, 3228, 0, + 26, 0, 0, 0, 216, 3452000, 384, 1152, 0, 3452, 0, + 27, 0, 0, 0, 216, 4016000, 768, 1152, 0, 4016, 0, + 28, 0, 0, 0, 216, 5080000, 1536, 1152, 0, 5080, 0, + 29, 0, 0, 0, 216, 3552000, 384, 1536, 0, 3552, 0, + 30, 0, 0, 0, 216, 3728000, 768, 1152, 0, 3728, 0] From fd8931c52f67ca3e80e0290ae6bdfc99942e3240 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Wed, 21 May 2025 13:31:18 +0300 Subject: [PATCH 02/11] [do not merge] App: Boards: Enable Up_down_mixer kconfig for cAVS2.5 Signed-off-by: Seppo Ingalsuo --- app/boards/intel_adsp_cavs25.conf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/boards/intel_adsp_cavs25.conf b/app/boards/intel_adsp_cavs25.conf index 72104567491a..4b09fc80a4c8 100644 --- a/app/boards/intel_adsp_cavs25.conf +++ b/app/boards/intel_adsp_cavs25.conf @@ -79,3 +79,6 @@ CONFIG_LOG_FUNC_NAME_PREFIX_DBG=y CONFIG_LOG_OUTPUT_FORMAT_LINUX_TIMESTAMP=y CONFIG_LOG_TIMESTAMP_64BIT=y CONFIG_WINSTREAM_CONSOLE=n + +# components +CONFIG_COMP_UP_DOWN_MIXER=y From bbaff376446d41481ba6282928c6aa7d0aeb5a50 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Fri, 16 May 2025 19:25:42 +0300 Subject: [PATCH 03/11] Tools: Testbench: Add up_down_mixer component Signed-off-by: Seppo Ingalsuo --- src/arch/host/configs/library_defconfig | 1 + src/include/sof/audio/component.h | 1 + tools/testbench/utils_ipc4.c | 1 + 3 files changed, 3 insertions(+) diff --git a/src/arch/host/configs/library_defconfig b/src/arch/host/configs/library_defconfig index 1b9483ffe858..bad3d76dcab3 100644 --- a/src/arch/host/configs/library_defconfig +++ b/src/arch/host/configs/library_defconfig @@ -18,6 +18,7 @@ CONFIG_COMP_SRC=y CONFIG_COMP_SRC_IPC4_FULL_MATRIX=y CONFIG_COMP_STUBS=y CONFIG_COMP_TDFB=y +CONFIG_COMP_UP_DOWN_MIXER=y CONFIG_COMP_VOLUME=y CONFIG_COMP_VOLUME_LINEAR_RAMP=y CONFIG_COMP_VOLUME_WINDOWS_FADE=y diff --git a/src/include/sof/audio/component.h b/src/include/sof/audio/component.h index 1b9c3474a8cf..14838844339e 100644 --- a/src/include/sof/audio/component.h +++ b/src/include/sof/audio/component.h @@ -902,6 +902,7 @@ void sys_comp_module_src_interface_init(void); void sys_comp_module_src_lite_interface_init(void); void sys_comp_module_tdfb_interface_init(void); void sys_comp_module_template_comp_interface_init(void); +void sys_comp_module_up_down_mixer_interface_init(void); void sys_comp_module_volume_interface_init(void); void sys_comp_module_tester_interface_init(void); diff --git a/tools/testbench/utils_ipc4.c b/tools/testbench/utils_ipc4.c index 53d2a3666d60..120638d912bc 100644 --- a/tools/testbench/utils_ipc4.c +++ b/tools/testbench/utils_ipc4.c @@ -64,6 +64,7 @@ int tb_setup(struct sof *sof, struct testbench_prm *tp) sys_comp_module_asrc_interface_init(); sys_comp_module_tdfb_interface_init(); sys_comp_module_template_comp_interface_init(); + sys_comp_module_up_down_mixer_interface_init(); sys_comp_module_volume_interface_init(); /* other necessary initializations */ From 7808ff3200f20b52c2703606e361c9f178e56508 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Fri, 16 May 2025 19:28:56 +0300 Subject: [PATCH 04/11] Tools: Topology: Add benchmark tplg for up_down_mixer Signed-off-by: Seppo Ingalsuo --- .../topology2/cavs-benchmark-hda.conf | 17 +++++ .../development/tplg-targets-bench.cmake | 2 + .../bench/up_down_mixer_controls_capture.conf | 17 +++++ .../up_down_mixer_controls_playback.conf | 17 +++++ .../bench/up_down_mixer_hda_route.conf | 19 +++++ .../include/bench/up_down_mixer_s16.conf | 13 ++++ .../include/bench/up_down_mixer_s24.conf | 13 ++++ .../include/bench/up_down_mixer_s32.conf | 13 ++++ .../include/components/up_down_mixer.conf | 70 +++++++++++++++++++ 9 files changed, 181 insertions(+) create mode 100644 tools/topology/topology2/include/bench/up_down_mixer_controls_capture.conf create mode 100644 tools/topology/topology2/include/bench/up_down_mixer_controls_playback.conf create mode 100644 tools/topology/topology2/include/bench/up_down_mixer_hda_route.conf create mode 100644 tools/topology/topology2/include/bench/up_down_mixer_s16.conf create mode 100644 tools/topology/topology2/include/bench/up_down_mixer_s24.conf create mode 100644 tools/topology/topology2/include/bench/up_down_mixer_s32.conf create mode 100644 tools/topology/topology2/include/components/up_down_mixer.conf diff --git a/tools/topology/topology2/cavs-benchmark-hda.conf b/tools/topology/topology2/cavs-benchmark-hda.conf index 76a41a2c2c33..a613a6fc7ce7 100644 --- a/tools/topology/topology2/cavs-benchmark-hda.conf +++ b/tools/topology/topology2/cavs-benchmark-hda.conf @@ -5,6 +5,7 @@ + Define { ANALOG_PLAYBACK_PCM 'Analog Playback' @@ -606,4 +607,20 @@ IncludeByKey.BENCH_CONFIG { "template_comp32" { } + + # + # up_down_mixer component + # + + "up_down_mixer16" { + + } + + "up_down_mixer24" { + + } + + "up_down_mixer32" { + + } } diff --git a/tools/topology/topology2/development/tplg-targets-bench.cmake b/tools/topology/topology2/development/tplg-targets-bench.cmake index 312f2a957d71..2df31a4fce8c 100644 --- a/tools/topology/topology2/development/tplg-targets-bench.cmake +++ b/tools/topology/topology2/development/tplg-targets-bench.cmake @@ -21,6 +21,7 @@ set(components "src_lite" "tdfb" "template_comp" + "up_down_mixer" ) set(component_parameters @@ -37,6 +38,7 @@ set(component_parameters "BENCH_SRC_LITE_PARAMS=default" "BENCH_TDFB_PARAMS=default" "BENCH_TEMPLATE_COMP_PARAMS=default" + "BENCH_UP_DOWN_MIXER_COMP_PARAMS=default" ) set(components_s24 diff --git a/tools/topology/topology2/include/bench/up_down_mixer_controls_capture.conf b/tools/topology/topology2/include/bench/up_down_mixer_controls_capture.conf new file mode 100644 index 000000000000..37a00f6fd0c0 --- /dev/null +++ b/tools/topology/topology2/include/bench/up_down_mixer_controls_capture.conf @@ -0,0 +1,17 @@ + # Created initially with script "./bench_comp_generate.sh up_down_mixer" + # may need edits to modify controls + Object.Control { + # Un-comment the supported controls in UP_DOWN_MIXER + #bytes."1" { + # name '$ANALOG_CAPTURE_PCM UP_DOWN_MIXER bytes' + # IncludeByKey.BENCH_UP_DOWN_MIXER_PARAMS { + # "default" "include/components/up_down_mixer/default.conf" + # } + #} + #mixer."1" { + # name '$ANALOG_CAPTURE_PCM UP_DOWN_MIXER switch or volume' + #} + #enum."1" { + # name '$ANALOG_CAPTURE_PCM UP_DOWN_MIXER enum' + #} + } diff --git a/tools/topology/topology2/include/bench/up_down_mixer_controls_playback.conf b/tools/topology/topology2/include/bench/up_down_mixer_controls_playback.conf new file mode 100644 index 000000000000..48ad315460ab --- /dev/null +++ b/tools/topology/topology2/include/bench/up_down_mixer_controls_playback.conf @@ -0,0 +1,17 @@ + # Created initially with script "./bench_comp_generate.sh up_down_mixer" + # may need edits to modify controls + Object.Control { + # Un-comment the supported controls in UP_DOWN_MIXER + #bytes."1" { + # name '$ANALOG_PLAYBACK_PCM UP_DOWN_MIXER bytes' + # IncludeByKey.BENCH_UP_DOWN_MIXER_PARAMS { + # "default" "include/components/up_down_mixer/default.conf" + # } + #} + #mixer."1" { + # name '$ANALOG_PLAYBACK_PCM UP_DOWN_MIXER switch or volume' + #} + #enum."1" { + # name '$ANALOG_PLAYBACK_PCM UP_DOWN_MIXER enum' + #} + } diff --git a/tools/topology/topology2/include/bench/up_down_mixer_hda_route.conf b/tools/topology/topology2/include/bench/up_down_mixer_hda_route.conf new file mode 100644 index 000000000000..9b65902149a8 --- /dev/null +++ b/tools/topology/topology2/include/bench/up_down_mixer_hda_route.conf @@ -0,0 +1,19 @@ + # Created with script "./bench_comp_generate.sh up_down_mixer" + Object.Base.route [ + { + sink 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.playback' + source 'up_down_mixer.1.1' + } + { + sink 'up_down_mixer.1.1' + source 'host-copier.0.playback' + } + { + source 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.capture' + sink 'up_down_mixer.3.2' + } + { + source 'up_down_mixer.3.2' + sink 'host-copier.0.capture' + } + ] diff --git a/tools/topology/topology2/include/bench/up_down_mixer_s16.conf b/tools/topology/topology2/include/bench/up_down_mixer_s16.conf new file mode 100644 index 000000000000..37583f585805 --- /dev/null +++ b/tools/topology/topology2/include/bench/up_down_mixer_s16.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh up_down_mixer" + Object.Widget.up_down_mixer.1 { + index 1 + + + } + Object.Widget.up_down_mixer.2 { + index 3 + + + } + + diff --git a/tools/topology/topology2/include/bench/up_down_mixer_s24.conf b/tools/topology/topology2/include/bench/up_down_mixer_s24.conf new file mode 100644 index 000000000000..fe4b3d25bb10 --- /dev/null +++ b/tools/topology/topology2/include/bench/up_down_mixer_s24.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh up_down_mixer" + Object.Widget.up_down_mixer.1 { + index 1 + + + } + Object.Widget.up_down_mixer.2 { + index 3 + + + } + + diff --git a/tools/topology/topology2/include/bench/up_down_mixer_s32.conf b/tools/topology/topology2/include/bench/up_down_mixer_s32.conf new file mode 100644 index 000000000000..623f5ab30a21 --- /dev/null +++ b/tools/topology/topology2/include/bench/up_down_mixer_s32.conf @@ -0,0 +1,13 @@ + # Created with script "./bench_comp_generate.sh up_down_mixer" + Object.Widget.up_down_mixer.1 { + index 1 + + + } + Object.Widget.up_down_mixer.2 { + index 3 + + + } + + diff --git a/tools/topology/topology2/include/components/up_down_mixer.conf b/tools/topology/topology2/include/components/up_down_mixer.conf new file mode 100644 index 000000000000..15c29357fb59 --- /dev/null +++ b/tools/topology/topology2/include/components/up_down_mixer.conf @@ -0,0 +1,70 @@ +# +# up_down_mixer +# +# An up_down_mixer widget. All attributes defined herein are namespaced +# by alsatplg to "Object.Widget.up_down_mixer.N.attribute_name" +# +# Usage: this component can be used by instantiating it in the parent object. i.e. +# +# Object.Widget.up_down_mixer."N" { +# index 5 +# cpc 100000 +# } +# +# Where N is the unique instance number for the copier object within the same alsaconf node. + +Class.Widget."up_down_mixer" { + # + # Pipeline ID for the up_down_mixer object + # + DefineAttribute."index" {} + + # + # up_down_mixer object instance + # + DefineAttribute."instance" {} + + #include common component definition + + + attributes { + # + # The up_down_mixer widget name would be constructed using the index and + # instance attributes. For ex: "up_down_mixer.1.2". + # + !constructor [ + "index" + "instance" + ] + + # + # mandatory attributes that must be provided when the up_down_mixer class is + # instantiated + # + !mandatory [ + "num_input_pins" + "num_output_pins" + "num_input_audio_formats" + "num_output_audio_formats" + ] + + # + # immutable attributes cannot be modified in the object instance + # + !immutable [ + "uuid" + "type" + ] + + unique "instance" + } + + # + # Default attributes for up_down_mixer + # + uuid "0c:06:f8:42:2f:83:bf:4d:b2:47:51:e9:61:99:7b:34" + type "effect" + no_pm "true" + num_input_pins 1 + num_output_pins 1 +} From aad225a5b3cef3ec8c77f855f51e89c18cd85f8d Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Mon, 19 May 2025 14:00:28 +0300 Subject: [PATCH 05/11] Audio: Up_down_mixer: Handle Linux driver init In Linux the up_down_mixer is initialized as process component type without mix definitions. This change adds to init() a default pass-through configuration with same input and output format. The up/down mixing configuration can be updated with bytes control. The mixing configuration is re-initialized in added prepare() step. Signed-off-by: Seppo Ingalsuo --- src/audio/up_down_mixer/up_down_mixer.c | 47 +++++++++++++++++++- src/audio/up_down_mixer/up_down_mixer.h | 3 ++ src/audio/up_down_mixer/up_down_mixer_ipc4.h | 9 ++-- 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/src/audio/up_down_mixer/up_down_mixer.c b/src/audio/up_down_mixer/up_down_mixer.c index e1cb4d9e13bc..455a7eab769f 100644 --- a/src/audio/up_down_mixer/up_down_mixer.c +++ b/src/audio/up_down_mixer/up_down_mixer.c @@ -335,12 +335,16 @@ static int up_down_mixer_free(struct processing_module *mod) static int up_down_mixer_init(struct processing_module *mod) { + struct up_down_mixer_config default_config; struct module_config *dst = &mod->priv.cfg; - const struct ipc4_up_down_mixer_module_cfg *up_down_mixer = dst->init_data; + const struct ipc4_up_down_mixer_module_cfg *up_down_mixer_init = dst->init_data; + const struct up_down_mixer_config *up_down_mixer = &up_down_mixer_init->config; struct module_data *mod_data = &mod->priv; struct comp_dev *dev = mod->dev; struct up_down_mixer_data *cd; + size_t min_size; int ret; + int i; cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); if (!cd) { @@ -357,6 +361,47 @@ static int up_down_mixer_init(struct processing_module *mod) goto err; } + comp_info(dev, "nb_input_pins = %d, nb_output_pins = %d", + dst->nb_input_pins, dst->nb_output_pins); + + min_size = sizeof(struct ipc4_base_module_cfg); + if (dst->nb_input_pins > 0 && dst->nb_output_pins > 0) + min_size += ipc4_calc_base_module_cfg_ext_size(dst->nb_input_pins, + dst->nb_output_pins); + comp_info(dev, "ipc_config_size = %d, min_size = %d", + dev->ipc_config.ipc_config_size, min_size); + + if (dev->ipc_config.ipc_config_size > min_size) { + comp_info(dev, "init configuration found"); + cd->has_init_mix_configuration = true; + comp_info(dev, "init data: %d, %d, 0x%08x", up_down_mixer->out_channel_config, + up_down_mixer->coefficients_select, up_down_mixer->channel_map); +#if UP_DOWN_MIX_COEFFS_LENGTH == 8 + comp_info(dev, "coef[0..3]: %d, %d, %d, %d", + up_down_mixer->coefficients[0], up_down_mixer->coefficients[1], + up_down_mixer->coefficients[2], up_down_mixer->coefficients[3]); + comp_info(dev, "coef[4..7]: %d, %d, %d, %d", + up_down_mixer->coefficients[4], up_down_mixer->coefficients[5], + up_down_mixer->coefficients[6], up_down_mixer->coefficients[7]); +#endif + } else { + comp_info(dev, "no configuration in init, using default"); + cd->has_init_mix_configuration = false; +#if FORCE_REQUEST_MONO + default_config.out_channel_config = 0; + default_config.coefficients_select = 2; + default_config.channel_map = -15; + for (i = 0; i < UP_DOWN_MIX_COEFFS_LENGTH; i++) + default_config.coefficients[i] = 0; +#else + default_config.out_channel_config = up_down_mixer_init->base_cfg.audio_fmt.ch_cfg; + default_config.coefficients_select = DEFAULT_COEFFICIENTS; + for (i = 0; i < UP_DOWN_MIX_COEFFS_LENGTH; i++) + default_config.coefficients[i] = 0; +#endif + up_down_mixer = &default_config; + } + switch (up_down_mixer->coefficients_select) { case DEFAULT_COEFFICIENTS: cd->out_channel_map = create_channel_map(up_down_mixer->out_channel_config); diff --git a/src/audio/up_down_mixer/up_down_mixer.h b/src/audio/up_down_mixer/up_down_mixer.h index 52a5f1e34daa..0300070a0718 100644 --- a/src/audio/up_down_mixer/up_down_mixer.h +++ b/src/audio/up_down_mixer/up_down_mixer.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -142,6 +143,8 @@ struct up_down_mixer_data { /** In/out internal buffers */ int32_t *buf_in; int32_t *buf_out; + + bool has_init_mix_configuration; }; /** diff --git a/src/audio/up_down_mixer/up_down_mixer_ipc4.h b/src/audio/up_down_mixer/up_down_mixer_ipc4.h index 5300f5cb71d4..39cfeaa5adab 100644 --- a/src/audio/up_down_mixer/up_down_mixer_ipc4.h +++ b/src/audio/up_down_mixer/up_down_mixer_ipc4.h @@ -28,9 +28,7 @@ enum up_down_mix_coeff_select { #define UP_DOWN_MIX_COEFFS_LENGTH 8 #define IPC4_UP_DOWN_MIXER_MODULE_OUTPUT_PINS_COUNT 1 -struct ipc4_up_down_mixer_module_cfg { - struct ipc4_base_module_cfg base_cfg; - +struct up_down_mixer_config { /* * Output Channel Configuration. * Together with audio_fmt.channel_config determines module conversion ratio. @@ -64,6 +62,11 @@ struct ipc4_up_down_mixer_module_cfg { * channel decoding. */ channel_map channel_map; +}; + +struct ipc4_up_down_mixer_module_cfg { + struct ipc4_base_module_cfg base_cfg; + struct up_down_mixer_config config; } __packed __aligned(8); #endif /* __SOF_IPC4_UP_DOWN_MIXER_H__ */ From 33cba9f0030af448a37e8586c1a8a7c785fe70bc Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Mon, 19 May 2025 18:58:01 +0300 Subject: [PATCH 06/11] Audio: Up_down_mixer: Process with circular wrap The previous processing function processed entire source and sink circular size. It avoids wrap check but is more inefficient when buffer is larger than period. The return code from sink_commit_buffer() and source_release_data() is ignored to avoid a fail in stream start where first frames count can be zero. Signed-off-by: Seppo Ingalsuo --- src/audio/up_down_mixer/up_down_mixer.c | 45 +++++++++++++++++-------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/src/audio/up_down_mixer/up_down_mixer.c b/src/audio/up_down_mixer/up_down_mixer.c index 455a7eab769f..7a61637101a1 100644 --- a/src/audio/up_down_mixer/up_down_mixer.c +++ b/src/audio/up_down_mixer/up_down_mixer.c @@ -450,40 +450,57 @@ up_down_mixer_process(struct processing_module *mod, struct comp_dev *dev = mod->dev; size_t output_frames, input_frames, ret, input_cirbuf_size, output_cirbuf_size; - const uint8_t *input0_pos, *input0_start; - uint8_t *output_pos, *output_start; + const uint8_t *input_pos, *input_start, *input_end; + uint8_t *output_pos, *output_start, *output_end; + int output_frames_without_wrap; + int frames_without_wrap, frames, frames_remain; + uint32_t input_bytes; comp_dbg(dev, "up_down_mixer_process()"); output_frames = sink_get_free_frames(output_buffers[0]); input_frames = source_get_data_frames_available(input_buffers[0]); + frames = MIN(input_frames, output_frames); const size_t output_frame_bytes = sink_get_frame_bytes(output_buffers[0]); - ret = sink_get_buffer(output_buffers[0], output_frames * output_frame_bytes, + ret = sink_get_buffer(output_buffers[0], frames * output_frame_bytes, (void **)&output_pos, (void **)&output_start, &output_cirbuf_size); if (ret) return -ENODATA; - const size_t input0_frame_bytes = source_get_frame_bytes(input_buffers[0]); + const size_t input_frame_bytes = source_get_frame_bytes(input_buffers[0]); - ret = source_get_data(input_buffers[0], input_frames * input0_frame_bytes, - (const void **)&input0_pos, (const void **)&input0_start, + ret = source_get_data(input_buffers[0], frames * input_frame_bytes, + (const void **)&input_pos, (const void **)&input_start, &input_cirbuf_size); if (ret) { sink_commit_buffer(output_buffers[0], 0); return -ENODATA; } - cd->mix_routine(cd, (const void *)input0_start, input_cirbuf_size, (void *)output_start); - - ret = sink_commit_buffer(output_buffers[0], output_frames * output_frame_bytes); - if (ret) - return ret; + input_end = input_start + input_cirbuf_size; + output_end = output_start + output_cirbuf_size; + frames_remain = frames; + while (frames_remain) { + frames_without_wrap = (input_end - input_pos) / input_frame_bytes; + frames_without_wrap = MIN(frames_without_wrap, frames); + output_frames_without_wrap = (output_end - output_pos) / output_frame_bytes; + frames_without_wrap = MIN(frames_without_wrap, output_frames_without_wrap); + input_bytes = input_frame_bytes * frames_without_wrap; + cd->mix_routine(cd, (const void *)input_pos, input_bytes, (void *)output_pos); + + input_pos += input_bytes; + output_pos += frames_without_wrap * output_frame_bytes; + input_pos = (input_pos >= input_end) ? input_pos - input_cirbuf_size : input_pos; + output_pos = (output_pos >= output_end) ? + output_pos - output_cirbuf_size : output_pos; + frames_remain -= frames_without_wrap; + } - ret = source_release_data(input_buffers[0], input_frames * input0_frame_bytes); - if (ret) - return ret; + /* Ignore possible -ENODATA, can happen in start with zero frames to process */ + sink_commit_buffer(output_buffers[0], frames * output_frame_bytes); + source_release_data(input_buffers[0], frames * input_frame_bytes); return 0; } From 1b83b7709f7f26d040644c77e97127d0db918ec0 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Mon, 19 May 2025 14:01:10 +0300 Subject: [PATCH 07/11] Audio: Up_down_mix: Split HiFi3 and generic version This patch moves the generic processing stubs from up_down_mixer_hifi3.c to new file up_down_mixer_generic.c. The HiFi versions build choices are added to Kconfig. There are no functiona changes to stubs, the generic processing in e.g. testbench still fails with these. As exception, the missing sof_panic(0); is added to generic downmix16bit_stereo(). Signed-off-by: Seppo Ingalsuo --- src/audio/up_down_mixer/CMakeLists.txt | 1 + src/audio/up_down_mixer/Kconfig | 16 ++ .../up_down_mixer/up_down_mixer_generic.c | 196 ++++++++++++++++++ src/audio/up_down_mixer/up_down_mixer_hifi3.c | 194 +---------------- 4 files changed, 219 insertions(+), 188 deletions(-) create mode 100644 src/audio/up_down_mixer/up_down_mixer_generic.c diff --git a/src/audio/up_down_mixer/CMakeLists.txt b/src/audio/up_down_mixer/CMakeLists.txt index 57e9e22e3ee4..1a04dbd36453 100644 --- a/src/audio/up_down_mixer/CMakeLists.txt +++ b/src/audio/up_down_mixer/CMakeLists.txt @@ -2,3 +2,4 @@ add_local_sources(sof up_down_mixer.c) add_local_sources(sof up_down_mixer_hifi3.c) +add_local_sources(sof up_down_mixer_generic.c) diff --git a/src/audio/up_down_mixer/Kconfig b/src/audio/up_down_mixer/Kconfig index 38ce5adafb51..53c82efaed44 100644 --- a/src/audio/up_down_mixer/Kconfig +++ b/src/audio/up_down_mixer/Kconfig @@ -13,3 +13,19 @@ config COMP_UP_DOWN_MIXER 2 -> 7.1 Downmixing for mono output: 4.0, Quatro, 3.1, 2 -> 1 + +choice + prompt "Up_down_mixer HIFI level" + depends on COMP_UP_DOWN_MIXER + default UP_DOWN_MIXER_HIFI_MAX + +config UP_DOWN_MIXER_HIFI_MAX + bool "Max level available in the toolchain" + +config UP_DOWN_MIXER_HIFI_3 + bool "HIFI3 UP_DOWN_MIXER" + +config UP_DOWN_MIXER_HIFI_NONE + bool "Generic UP_DOWN_MIXER, no HIFI" + +endchoice diff --git a/src/audio/up_down_mixer/up_down_mixer_generic.c b/src/audio/up_down_mixer/up_down_mixer_generic.c new file mode 100644 index 000000000000..56755b79fe5b --- /dev/null +++ b/src/audio/up_down_mixer/up_down_mixer_generic.c @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2022-2025 Intel Corporation. +// +// Author: Bartosz Kokoszko +// Seppo Ingalsuo + +#include +#include +#include + +#include "up_down_mixer.h" + +#if SOF_USE_HIFI(NONE, UP_DOWN_MIXER) + +void upmix32bit_1_to_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void upmix16bit_1_to_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void upmix32bit_2_0_to_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void upmix16bit_2_0_to_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void upmix32bit_2_0_to_7_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void shiftcopy32bit_mono(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void shiftcopy32bit_stereo(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void downmix32bit_2_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void downmix32bit_3_0(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void downmix32bit_3_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void downmix32bit(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void downmix32bit_4_0(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void downmix32bit_5_0_mono(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void downmix32bit_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void downmix32bit_7_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void downmix16bit_stereo(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void shiftcopy16bit_mono(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void shiftcopy16bit_stereo(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void downmix16bit(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void downmix16bit_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void downmix16bit_4ch_mono(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void downmix32bit_stereo(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void downmix32bit_3_1_mono(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void downmix32bit_4_0_mono(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void downmix32bit_quatro_mono(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void downmix32bit_5_1_mono(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void downmix32bit_7_1_mono(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void downmix32bit_7_1_to_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void upmix32bit_4_0_to_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +void upmix32bit_quatro_to_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, + const uint32_t in_size, uint8_t * const out_data) +{ + sof_panic(0); +} + +#endif /* #if SOF_USE_HIFI(NONE, UP_DOWN_MIXER) */ diff --git a/src/audio/up_down_mixer/up_down_mixer_hifi3.c b/src/audio/up_down_mixer/up_down_mixer_hifi3.c index 259cf5128b9f..faff84827d71 100644 --- a/src/audio/up_down_mixer/up_down_mixer_hifi3.c +++ b/src/audio/up_down_mixer/up_down_mixer_hifi3.c @@ -1,18 +1,19 @@ // SPDX-License-Identifier: BSD-3-Clause // -// Copyright(c) 2022 Intel Corporation. All rights reserved. +// Copyright(c) 2022-2025 Intel Corporation. // // Author: Bartosz Kokoszko #include "up_down_mixer.h" -#if defined(__XCC__) && XCHAL_HAVE_HIFI3 - -#include #include #include #include +#if SOF_USE_MIN_HIFI(3, UP_DOWN_MIXER) + +#include + void upmix32bit_1_to_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { @@ -1915,187 +1916,4 @@ void upmix32bit_quatro_to_5_1(struct up_down_mixer_data *cd, const uint8_t * con } } -#else /* !XCHAL_HAVE_HIFI3 */ - -/* TODO: replace with generic ANSI C version */ - -void upmix32bit_1_to_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void upmix16bit_1_to_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void upmix32bit_2_0_to_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void upmix16bit_2_0_to_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void upmix32bit_2_0_to_7_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void shiftcopy32bit_mono(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void shiftcopy32bit_stereo(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void downmix32bit_2_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void downmix32bit_3_0(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void downmix32bit_3_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void downmix32bit(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void downmix32bit_4_0(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void downmix32bit_5_0_mono(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void downmix32bit_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void downmix32bit_7_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void downmix16bit_stereo(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ -} - -void shiftcopy16bit_mono(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void shiftcopy16bit_stereo(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void downmix16bit(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void downmix16bit_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void downmix16bit_4ch_mono(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void downmix32bit_stereo(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void downmix32bit_3_1_mono(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void downmix32bit_4_0_mono(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void downmix32bit_quatro_mono(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void downmix32bit_5_1_mono(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void downmix32bit_7_1_mono(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void downmix32bit_7_1_to_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void upmix32bit_4_0_to_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -void upmix32bit_quatro_to_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, - const uint32_t in_size, uint8_t * const out_data) -{ - sof_panic(0); -} - -#endif +#endif /* #if SOF_USE_HIFI(3, UP_DOWN_MIXER) */ From 7380bfb3ef215ddb09f3a6abfb23b137afbd52a5 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Tue, 20 May 2025 14:50:38 +0300 Subject: [PATCH 08/11] Audio: Up_down_mix: Replace simple stubs with generic C versions This patch replaces the stubs of simple conversion functions with real conversions. In these cases the xtensa C code without arithmetic operations can converted to generic with just e.g. ae_int32 to int32_t replace and AE_MOVINT with type cast. This enables to use testbench x86 build to run up_down_mixer. Also the generic versions are potential for better performance with more recent HiFi cores with improvements in compiler technology. Signed-off-by: Seppo Ingalsuo --- .../up_down_mixer/up_down_mixer_generic.c | 1144 ++++++++++++++++- 1 file changed, 1114 insertions(+), 30 deletions(-) diff --git a/src/audio/up_down_mixer/up_down_mixer_generic.c b/src/audio/up_down_mixer/up_down_mixer_generic.c index 56755b79fe5b..df0a4b912b10 100644 --- a/src/audio/up_down_mixer/up_down_mixer_generic.c +++ b/src/audio/up_down_mixer/up_down_mixer_generic.c @@ -5,6 +5,7 @@ // Author: Bartosz Kokoszko // Seppo Ingalsuo +#include #include #include #include @@ -13,184 +14,1267 @@ #if SOF_USE_HIFI(NONE, UP_DOWN_MIXER) +#define CH_COUNT_2_0 2 +#define CH_COUNT_2_1 3 +#define CH_COUNT_3_0 3 +#define CH_COUNT_3_1 4 +#define CH_COUNT_4_0 4 +#define CH_COUNT_5_0 5 +#define CH_COUNT_5_1 6 +#define CH_COUNT_7_1 8 +#define CH_COUNT_QUATRO 4 + void upmix32bit_1_to_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + + channel_map out_channel_map = cd->out_channel_map; + const int32_t *in_ptr = (const int32_t *)in_data; + int32_t *out32 = (int32_t *)out_data; + int32_t *output_left = out32 + get_channel_location(out_channel_map, CHANNEL_LEFT); + int32_t *output_center = out32 + get_channel_location(out_channel_map, CHANNEL_CENTER); + int32_t *output_right = out32 + get_channel_location(out_channel_map, CHANNEL_RIGHT); + int32_t *output_lfe = out32 + get_channel_location(out_channel_map, CHANNEL_LFE); + int32_t *output_left_surround = out32 + + get_channel_location(out_channel_map, CHANNEL_LEFT_SURROUND); + int32_t *output_right_surround = out32 + + get_channel_location(out_channel_map, CHANNEL_RIGHT_SURROUND); + int frames = in_size >> 2; + int i; + + for (i = 0; i < frames; ++i) { + output_left[i * CH_COUNT_5_1] = in_ptr[i]; + output_right[i * CH_COUNT_5_1] = in_ptr[i]; + output_center[i * CH_COUNT_5_1] = 0; + output_left_surround[i * CH_COUNT_5_1] = in_ptr[i]; + output_right_surround[i * CH_COUNT_5_1] = in_ptr[i]; + output_lfe[i * CH_COUNT_5_1] = 0; + } } void upmix16bit_1_to_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + + channel_map out_channel_map = cd->out_channel_map; + int32_t *out32 = (int32_t *)out_data; + int32_t *output_left = out32 + get_channel_location(out_channel_map, CHANNEL_LEFT); + int32_t *output_center = out32 + get_channel_location(out_channel_map, CHANNEL_CENTER); + int32_t *output_right = out32 + get_channel_location(out_channel_map, CHANNEL_RIGHT); + int32_t *output_lfe = out32 + get_channel_location(out_channel_map, CHANNEL_LFE); + int32_t *output_left_surround = out32 + + get_channel_location(out_channel_map, CHANNEL_LEFT_SURROUND); + int32_t *output_right_surround = out32 + + get_channel_location(out_channel_map, CHANNEL_RIGHT_SURROUND); + const int16_t *in_ptr = (const int16_t *)in_data; + int frames = in_size >> 1; + int i; + + for (i = 0; i < frames; ++i) { + output_left[i * CH_COUNT_5_1] = (int32_t)in_ptr[i] << 16; + output_right[i * CH_COUNT_5_1] = (int32_t)in_ptr[i] << 16; + output_center[i * CH_COUNT_5_1] = 0; + output_left_surround[i * CH_COUNT_5_1] = (int32_t)in_ptr[i] << 16; + output_right_surround[i * CH_COUNT_5_1] = (int32_t)in_ptr[i] << 16; + output_lfe[i * CH_COUNT_5_1] = 0; + } } void upmix32bit_2_0_to_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + + channel_map out_channel_map = cd->out_channel_map; + int32_t *out32 = (int32_t *)out_data; + int32_t *output_left = out32 + get_channel_location(out_channel_map, CHANNEL_LEFT); + int32_t *output_center = out32 + get_channel_location(out_channel_map, CHANNEL_CENTER); + int32_t *output_right = out32 + get_channel_location(out_channel_map, CHANNEL_RIGHT); + int32_t *output_lfe = out32 + get_channel_location(out_channel_map, CHANNEL_LFE); + int32_t *output_left_surround; + int32_t *output_right_surround; + const int32_t *in_left_ptr = (const int32_t *)in_data; + const int32_t *in_right_ptr = in_left_ptr + 1; + int frames = in_size >> 3; + int i; + + int left_surround_slot = get_channel_location(out_channel_map, CHANNEL_LEFT_SURROUND); + int right_surround_slot = get_channel_location(out_channel_map, CHANNEL_RIGHT_SURROUND); + + /* Must support also 5.1 Surround */ + if (left_surround_slot == CHANNEL_INVALID && right_surround_slot == CHANNEL_INVALID) { + left_surround_slot = get_channel_location(out_channel_map, CHANNEL_LEFT_SIDE); + right_surround_slot = get_channel_location(out_channel_map, CHANNEL_RIGHT_SIDE); + } + + output_left_surround = out32 + left_surround_slot; + output_right_surround = out32 + right_surround_slot; + + for (i = 0; i < frames; ++i) { + output_left[i * CH_COUNT_5_1] = in_left_ptr[i * CH_COUNT_2_0]; + output_right[i * CH_COUNT_5_1] = in_right_ptr[i * CH_COUNT_2_0]; + output_center[i * CH_COUNT_5_1] = 0; + output_left_surround[i * CH_COUNT_5_1] = in_left_ptr[i * CH_COUNT_2_0]; + output_right_surround[i * CH_COUNT_5_1] = in_right_ptr[i * CH_COUNT_2_0]; + output_lfe[i * CH_COUNT_5_1] = 0; + } } void upmix16bit_2_0_to_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + + channel_map out_channel_map = cd->out_channel_map; + int32_t *out32 = (int32_t *)out_data; + int32_t *output_left = out32 + get_channel_location(out_channel_map, CHANNEL_LEFT); + int32_t *output_center = out32 + get_channel_location(out_channel_map, CHANNEL_CENTER); + int32_t *output_right = out32 + get_channel_location(out_channel_map, CHANNEL_RIGHT); + int32_t *output_lfe = out32 + get_channel_location(out_channel_map, CHANNEL_LFE); + int32_t *output_left_surround; + int32_t *output_right_surround; + const int16_t *in_left_ptr = (const int16_t *)in_data; + const int16_t *in_right_ptr = in_left_ptr + 1; + int left_surround_slot = get_channel_location(out_channel_map, CHANNEL_LEFT_SURROUND); + int right_surround_slot = get_channel_location(out_channel_map, CHANNEL_RIGHT_SURROUND); + int frames = in_size >> 2; + int i; + + /* Must support also 5.1 Surround */ + if (left_surround_slot == CHANNEL_INVALID && right_surround_slot == CHANNEL_INVALID) { + left_surround_slot = get_channel_location(out_channel_map, CHANNEL_LEFT_SIDE); + right_surround_slot = get_channel_location(out_channel_map, CHANNEL_RIGHT_SIDE); + } + + output_left_surround = out32 + left_surround_slot; + output_right_surround = out32 + right_surround_slot; + + for (i = 0; i < frames; ++i) { + output_left[i * CH_COUNT_5_1] = (int32_t)in_left_ptr[i * 2] << 16; + output_right[i * CH_COUNT_5_1] = (int32_t)in_right_ptr[i * 2] << 16; + output_center[i * CH_COUNT_5_1] = 0; + output_left_surround[i * CH_COUNT_5_1] = (int32_t)in_left_ptr[i * 2] << 16; + output_right_surround[i * CH_COUNT_5_1] = (int32_t)in_right_ptr[i * 2] << 16; + output_lfe[i * CH_COUNT_5_1] = 0; + } } void upmix32bit_2_0_to_7_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + + channel_map out_channel_map = cd->out_channel_map; + int32_t *out32 = (int32_t *)out_data; + int32_t *output_left = out32 + get_channel_location(out_channel_map, CHANNEL_LEFT); + int32_t *output_center = out32 + get_channel_location(out_channel_map, CHANNEL_CENTER); + int32_t *output_right = out32 + get_channel_location(out_channel_map, CHANNEL_RIGHT); + int32_t *output_lfe = out32 + get_channel_location(out_channel_map, CHANNEL_LFE); + int32_t *output_left_surround = out32 + + get_channel_location(out_channel_map, CHANNEL_LEFT_SURROUND); + int32_t *output_right_surround = out32 + + get_channel_location(out_channel_map, CHANNEL_RIGHT_SURROUND); + int32_t *output_left_side = out32 + + get_channel_location(out_channel_map, CHANNEL_LEFT_SIDE); + int32_t *output_right_side = out32 + + get_channel_location(out_channel_map, CHANNEL_RIGHT_SIDE); + + const int32_t *in_left_ptr = (const int32_t *)in_data; + const int32_t *in_right_ptr = in_left_ptr + 1; + int frames = in_size >> 3; + int i; + + for (i = 0; i < frames; ++i) { + output_left[i * CH_COUNT_7_1] = in_left_ptr[i * 2]; + output_right[i * CH_COUNT_7_1] = in_right_ptr[i * 2]; + output_center[i * CH_COUNT_7_1] = 0; + output_left_surround[i * CH_COUNT_7_1] = in_left_ptr[i * 2]; + output_right_surround[i * CH_COUNT_7_1] = in_right_ptr[i * 2]; + output_lfe[i * CH_COUNT_7_1] = 0; + output_left_side[i * CH_COUNT_7_1] = 0; + output_right_side[i * CH_COUNT_7_1] = 0; + } } void shiftcopy32bit_mono(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + + const int32_t *in_ptr = (const int32_t *)in_data; + int32_t *out_ptr_left = (int32_t *)out_data; + int32_t *out_ptr_right = out_ptr_left + 1; + int frames = in_size >> 2; + int i; + + for (i = 0; i < frames; ++i) { + out_ptr_left[i * CH_COUNT_2_0] = in_ptr[i]; + out_ptr_right[i * CH_COUNT_2_0] = in_ptr[i]; + } } void shiftcopy32bit_stereo(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + memcpy_s(out_data, in_size, in_data, in_size); } void downmix32bit_2_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + int64_t Q_tmp_left; + int64_t Q_tmp_right; + int32_t P_coefficient_left = cd->downmix_coefficients[CHANNEL_LEFT]; + int32_t P_coefficient_right = cd->downmix_coefficients[CHANNEL_RIGHT]; + int32_t P_coefficient_lfe = cd->downmix_coefficients[CHANNEL_LFE]; + const int32_t *in32 = (const int32_t *)in_data; + const int32_t *input_left = in32 + get_channel_location(cd->in_channel_map, CHANNEL_LEFT); + const int32_t *input_right = in32 + get_channel_location(cd->in_channel_map, CHANNEL_RIGHT); + const int32_t *input_lfe = in32 + get_channel_location(cd->in_channel_map, CHANNEL_LFE); + int32_t *output_left = (int32_t *)(out_data); + int32_t *output_right = output_left + 1; + int frames = in_size / (CH_COUNT_2_1 * sizeof(int32_t)); + int i; + + for (i = 0; i < frames; i++) { + /* update output left and right channels based on input lfe channel, + * accumulate as Q1.31 * Q1.31 -> Q2.62 + */ + Q_tmp_left = (int64_t)P_coefficient_lfe * *input_lfe; + Q_tmp_right = Q_tmp_left; + input_lfe += CH_COUNT_2_1; + + /* update output left channel based on input left channel */ + Q_tmp_left += (int64_t)P_coefficient_left * *input_left; + input_left += CH_COUNT_2_1; + + /* update output right channel based on input right channel */ + Q_tmp_right += (int64_t)P_coefficient_right * *input_right; + input_right += CH_COUNT_2_1; + + /* Shift with round to Q1.31 and saturate and store output */ + *output_left = sat_int32(Q_SHIFT_RND(Q_tmp_left, 62, 31)); + *output_right = sat_int32(Q_SHIFT_RND(Q_tmp_right, 62, 31)); + output_left += CH_COUNT_2_0; + output_right += CH_COUNT_2_0; + } } void downmix32bit_3_0(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + int64_t Q_tmp_left; + int64_t Q_tmp_right; + int32_t P_coefficient_left = cd->downmix_coefficients[CHANNEL_LEFT]; + int32_t P_coefficient_center = cd->downmix_coefficients[CHANNEL_CENTER]; + int32_t P_coefficient_right = cd->downmix_coefficients[CHANNEL_RIGHT]; + const int32_t *in32 = (const int32_t *)in_data; + const int32_t *input_left = in32 + get_channel_location(cd->in_channel_map, CHANNEL_LEFT); + const int32_t *input_right = in32 + get_channel_location(cd->in_channel_map, CHANNEL_RIGHT); + const int32_t *input_center = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_CENTER); + int32_t *output_left = (int32_t *)(out_data); + int32_t *output_right = output_left + 1; + int frames = in_size / (CH_COUNT_3_0 * sizeof(int32_t)); + int i; + + for (i = 0; i < frames; i++) { + /* update output left and right channels based on input center channel, + * accumulate as Q1.31 * Q1.31 -> Q2.62 + */ + Q_tmp_left = (int64_t)P_coefficient_center * *input_center; + Q_tmp_right = Q_tmp_left; + input_center += CH_COUNT_3_0; + + /* update output left channel based on input left channel */ + Q_tmp_left += (int64_t)P_coefficient_left * *input_left; + input_left += CH_COUNT_3_0; + + /* update output right channel based on input right channel */ + Q_tmp_right += (int64_t)P_coefficient_right * *input_right; + input_right += CH_COUNT_3_0; + + /* Shift with round to Q1.31 and saturate and store output */ + *output_left = sat_int32(Q_SHIFT_RND(Q_tmp_left, 62, 31)); + *output_right = sat_int32(Q_SHIFT_RND(Q_tmp_right, 62, 31)); + output_left += CH_COUNT_2_0; + output_right += CH_COUNT_2_0; + } } void downmix32bit_3_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + int64_t Q_tmp_left; + int64_t Q_tmp_right; + int32_t P_coefficient_left = cd->downmix_coefficients[CHANNEL_LEFT]; + int32_t P_coefficient_center = cd->downmix_coefficients[CHANNEL_CENTER]; + int32_t P_coefficient_right = cd->downmix_coefficients[CHANNEL_RIGHT]; + int32_t P_coefficient_lfe = cd->downmix_coefficients[CHANNEL_LFE]; + const int32_t *in32 = (const int32_t *)in_data; + const int32_t *input_left = in32 + get_channel_location(cd->in_channel_map, CHANNEL_LEFT); + const int32_t *input_right = in32 + get_channel_location(cd->in_channel_map, CHANNEL_RIGHT); + const int32_t *input_lfe = in32 + get_channel_location(cd->in_channel_map, CHANNEL_LFE); + const int32_t *input_center = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_CENTER); + int32_t *output_left = (int32_t *)(out_data); + int32_t *output_right = output_left + 1; + int frames = in_size / (CH_COUNT_3_1 * sizeof(int32_t)); + int i; + + for (i = 0; i < frames; i++) { + /* update output left and right channels based on input lfe channel, + * accumulate as Q1.31 * Q1.31 -> Q2.62 + */ + Q_tmp_left = (int64_t)P_coefficient_center * *input_center; + Q_tmp_left = (int64_t)P_coefficient_lfe * *input_lfe; + Q_tmp_right = Q_tmp_left; + input_center += CH_COUNT_3_1; + input_lfe += CH_COUNT_3_1; + + /* update output left channel based on input left channel */ + Q_tmp_left += (int64_t)P_coefficient_left * *input_left; + input_left += CH_COUNT_3_1; + + /* update output right channel based on input right channel */ + Q_tmp_right += (int64_t)P_coefficient_right * *input_right; + input_right += CH_COUNT_3_1; + + /* Shift with round to Q1.31 and saturate and store output */ + *output_left = sat_int32(Q_SHIFT_RND(Q_tmp_left, 62, 31)); + *output_right = sat_int32(Q_SHIFT_RND(Q_tmp_right, 62, 31)); + output_left += CH_COUNT_2_0; + output_right += CH_COUNT_2_0; + } } void downmix32bit(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + int64_t Q_tmp_left = 0; + int64_t Q_tmp_right = 0; + int64_t p; + int32_t P_coefficient_left = cd->downmix_coefficients[CHANNEL_LEFT]; + int32_t P_coefficient_center = cd->downmix_coefficients[CHANNEL_CENTER]; + int32_t P_coefficient_right = cd->downmix_coefficients[CHANNEL_RIGHT]; + int32_t P_coefficient_left_surround = cd->downmix_coefficients[CHANNEL_LEFT_SURROUND]; + int32_t P_coefficient_right_surround = cd->downmix_coefficients[CHANNEL_RIGHT_SURROUND]; + int32_t P_coefficient_lfe = cd->downmix_coefficients[CHANNEL_LFE]; + const int32_t *in32 = (const int32_t *)in_data; + const int32_t *input_left = in32 + get_channel_location(cd->in_channel_map, CHANNEL_LEFT); + const int32_t *input_center = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_CENTER); + const int32_t *input_right = in32 + get_channel_location(cd->in_channel_map, CHANNEL_RIGHT); + const int32_t *input_lfe = in32 + get_channel_location(cd->in_channel_map, CHANNEL_LFE); + const int32_t *input_left_surround = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_LEFT_SURROUND); + const int32_t *input_right_surround = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_RIGHT_SURROUND); + int32_t *output_left = (int32_t *)out_data; + int32_t *output_right = output_left + 1; + + /* See what channels are available. */ + bool left = get_channel_location(cd->in_channel_map, CHANNEL_LEFT) != 0xF; + bool center = get_channel_location(cd->in_channel_map, CHANNEL_CENTER) != 0xF; + bool right = get_channel_location(cd->in_channel_map, CHANNEL_RIGHT) != 0xF; + bool lfe = get_channel_location(cd->in_channel_map, CHANNEL_LFE) != 0xF; + bool left_surround = get_channel_location(cd->in_channel_map, CHANNEL_LEFT_SURROUND) != 0xF; + bool right_surround = + get_channel_location(cd->in_channel_map, CHANNEL_RIGHT_SURROUND) != 0xF; + + int frames = in_size / (cd->in_channel_no * sizeof(int32_t)); + int sample_offset = cd->in_channel_no; + int i; + + for (i = 0; i < frames; i++) { + if (left) { + Q_tmp_left += (int64_t)P_coefficient_left * *input_left; + input_left += sample_offset; + } + if (center) { + p = (int64_t)P_coefficient_center * *input_center; + Q_tmp_left += p; + Q_tmp_right += p; + input_center += sample_offset; + } + if (right) { + Q_tmp_right += (int64_t)P_coefficient_right * *input_right; + input_right += sample_offset; + } + if (left_surround) { + p = (int64_t)P_coefficient_left_surround * *input_left_surround; + Q_tmp_left += p; + input_left_surround += sample_offset; + if (cd->in_channel_config == IPC4_CHANNEL_CONFIG_4_POINT_0) + Q_tmp_right += p; + } + if (right_surround) { + Q_tmp_right += (int64_t)P_coefficient_right_surround * + *input_right_surround; + input_right_surround += sample_offset; + } + if (lfe) { + p = (int64_t)P_coefficient_lfe * *input_lfe; + Q_tmp_left += p; + Q_tmp_right += p; + input_lfe += sample_offset; + } + + /* Shift with round to Q1.31 and saturate and store output */ + *output_left = sat_int32(Q_SHIFT_RND(Q_tmp_left, 62, 31)); + *output_right = sat_int32(Q_SHIFT_RND(Q_tmp_right, 62, 31)); + output_left += CH_COUNT_2_0; + output_right += CH_COUNT_2_0; + } } void downmix32bit_4_0(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + int64_t Q_tmp_left; + int64_t Q_tmp_right; + int64_t p; + int32_t P_coefficient_left = cd->downmix_coefficients[CHANNEL_LEFT]; + int32_t P_coefficient_center = cd->downmix_coefficients[CHANNEL_CENTER]; + int32_t P_coefficient_right = cd->downmix_coefficients[CHANNEL_RIGHT]; + int32_t P_coefficient_left_surround = cd->downmix_coefficients[CHANNEL_LEFT_SURROUND]; + + const int32_t *in32 = (const int32_t *)in_data; + const int32_t *input_left = in32 + get_channel_location(cd->in_channel_map, CHANNEL_LEFT); + const int32_t *input_right = in32 + get_channel_location(cd->in_channel_map, CHANNEL_RIGHT); + const int32_t *input_center = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_CENTER); + const int32_t *input_left_surround = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_LEFT_SURROUND); + int32_t *output_left = (int32_t *)(out_data); + int32_t *output_right = output_left + 1; + int frames = in_size / (CH_COUNT_4_0 * sizeof(int32_t)); + int i; + + for (i = 0; i < frames; i++) { + /* Accumulate as Q1.31 * Q1.31 -> Q2.62 */ + Q_tmp_left = (int64_t)P_coefficient_left * *input_left; + input_left += CH_COUNT_4_0; + + p = (int64_t)P_coefficient_center * *input_center; + Q_tmp_left += p; + Q_tmp_right = p; + input_center += CH_COUNT_4_0; + + Q_tmp_right += (int64_t)P_coefficient_right * *input_right; + input_right += CH_COUNT_4_0; + + /* for 4.0 left surround if propagated to both left and right output channels */ + p += (int64_t)P_coefficient_left_surround * *input_left_surround; + Q_tmp_left += p; + Q_tmp_right = p; + input_left_surround += CH_COUNT_4_0; + + /* Shift with round to Q1.31 and saturate and store output */ + *output_left = sat_int32(Q_SHIFT_RND(Q_tmp_left, 62, 31)); + *output_right = sat_int32(Q_SHIFT_RND(Q_tmp_right, 62, 31)); + output_left += CH_COUNT_2_0; + output_right += CH_COUNT_2_0; + } } void downmix32bit_5_0_mono(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + size_t i; + + int64_t Q_tmp; + int32_t P_coefficient_left = cd->downmix_coefficients[CHANNEL_LEFT]; + int32_t P_coefficient_center = cd->downmix_coefficients[CHANNEL_CENTER]; + int32_t P_coefficient_right = cd->downmix_coefficients[CHANNEL_RIGHT]; + int32_t P_coefficient_cs = cd->downmix_coefficients[CHANNEL_CENTER_SURROUND]; + + int32_t *in32 = (int32_t *)in_data; + + const int32_t *input_left = in32 + get_channel_location(cd->in_channel_map, CHANNEL_LEFT); + const int32_t *input_right = in32 + get_channel_location(cd->in_channel_map, CHANNEL_RIGHT); + const int32_t *input_center = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_CENTER); + const int32_t *input_cs = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_CENTER_SURROUND); + + int32_t *output = (int32_t *)(out_data); + + const uint32_t channel_no = 5; + + for (i = 0; i < in_size / (sizeof(int32_t)); i += channel_no) { + Q_tmp = (int64_t)P_coefficient_left * *input_left; + input_left += CH_COUNT_5_0; + + Q_tmp += (int64_t)P_coefficient_center * *input_center; + input_center += CH_COUNT_5_0; + + Q_tmp += (int64_t)P_coefficient_right * *input_right; + input_right += CH_COUNT_5_0; + + Q_tmp += (int64_t)P_coefficient_cs * *input_cs; + input_right += CH_COUNT_5_0; + + /* Shift with round to Q1.31 and saturate and store output */ + *output = sat_int32(Q_SHIFT_RND(Q_tmp, 62, 31)); + output++; + } } void downmix32bit_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + int64_t Q_tmp_left; + int64_t Q_tmp_right; + int32_t *in32 = (int32_t *)in_data; + int32_t *input_left_surround; + int32_t *input_right_surround; + int32_t *output_left = (int32_t *)(out_data); + int32_t *output_right = output_left + 1; + int left_surround_slot = get_channel_location(cd->in_channel_map, CHANNEL_LEFT_SURROUND); + int right_surround_slot = get_channel_location(cd->in_channel_map, CHANNEL_RIGHT_SURROUND); + + /* Must support also 5.1 Surround */ + const bool surround_5_1_channel_map = (left_surround_slot == CHANNEL_INVALID) && + (right_surround_slot == CHANNEL_INVALID); + + const int32_t *input_left = in32 + get_channel_location(cd->in_channel_map, CHANNEL_LEFT); + const int32_t *input_right = in32 + get_channel_location(cd->in_channel_map, CHANNEL_RIGHT); + const int32_t *input_lfe = in32 + get_channel_location(cd->in_channel_map, CHANNEL_LFE); + const int32_t *input_center = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_CENTER); + + if (surround_5_1_channel_map) { + input_left_surround = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_LEFT_SIDE); + input_right_surround = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_RIGHT_SIDE); + } else { + input_left_surround = in32 + left_surround_slot; + input_right_surround = in32 + right_surround_slot; + } + + /* Load the downmix coefficients. */ + int32_t P_coefficient_left = cd->downmix_coefficients[CHANNEL_LEFT]; + int32_t P_coefficient_center = cd->downmix_coefficients[CHANNEL_CENTER]; + int32_t P_coefficient_right = cd->downmix_coefficients[CHANNEL_RIGHT]; + int32_t P_coefficient_lfe = cd->downmix_coefficients[CHANNEL_LFE]; + int32_t P_coefficient_left_surround; + int32_t P_coefficient_right_surround; + + if (surround_5_1_channel_map) { + P_coefficient_left_surround = cd->downmix_coefficients[CHANNEL_LEFT_SIDE]; + P_coefficient_right_surround = cd->downmix_coefficients[CHANNEL_RIGHT_SIDE]; + } else { + P_coefficient_left_surround = cd->downmix_coefficients[CHANNEL_LEFT_SURROUND]; + P_coefficient_right_surround = cd->downmix_coefficients[CHANNEL_RIGHT_SURROUND]; + } + + + const int32_t *const end_input_left = input_left + (in_size / (sizeof(int32_t))); + + while (input_left < end_input_left) { + /* Accumulate as Q1.31 * Q1.31 -> Q2.62 */ + Q_tmp_left = (int64_t)P_coefficient_center * *input_center; + input_center += CH_COUNT_5_1; + + Q_tmp_left += (int64_t)P_coefficient_lfe * *input_lfe; + Q_tmp_right = Q_tmp_left; + input_lfe += CH_COUNT_5_1; + + Q_tmp_left += (int64_t)P_coefficient_left * *input_left; + input_left += CH_COUNT_5_1; + + Q_tmp_right += (int64_t)P_coefficient_right * *input_right; + input_right += CH_COUNT_5_1; + + Q_tmp_left += (int64_t)P_coefficient_left_surround * *input_left_surround; + input_left_surround += CH_COUNT_5_1; + + Q_tmp_right += (int64_t)P_coefficient_right_surround * *input_right_surround; + input_right_surround += CH_COUNT_5_1; + + /* Shift with round to Q1.31 and saturate and store output */ + *output_left = sat_int32(Q_SHIFT_RND(Q_tmp_left, 62, 31)); + *output_right = sat_int32(Q_SHIFT_RND(Q_tmp_right, 62, 31)); + output_left += CH_COUNT_2_0; + output_right += CH_COUNT_2_0; + } } void downmix32bit_7_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + /* Load the downmix coefficients. */ + int64_t Q_tmp_left; + int64_t Q_tmp_right; + int32_t P_coefficient_left = cd->downmix_coefficients[CHANNEL_LEFT]; + int32_t P_coefficient_center = cd->downmix_coefficients[CHANNEL_CENTER]; + int32_t P_coefficient_right = cd->downmix_coefficients[CHANNEL_RIGHT]; + int32_t P_coefficient_left_surround = cd->downmix_coefficients[CHANNEL_LEFT_SURROUND]; + int32_t P_coefficient_right_surround = cd->downmix_coefficients[CHANNEL_RIGHT_SURROUND]; + int32_t P_coefficient_lfe = cd->downmix_coefficients[CHANNEL_LFE]; + int32_t P_coefficient_left_side = cd->downmix_coefficients[CHANNEL_LEFT_SIDE]; + int32_t P_coefficient_right_side = cd->downmix_coefficients[CHANNEL_RIGHT_SIDE]; + + /* Only load the channel if it's present. */ + int32_t *in32 = (int32_t *)in_data; + + const int32_t *input_left = in32 + get_channel_location(cd->in_channel_map, CHANNEL_LEFT); + const int32_t *input_center = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_CENTER); + const int32_t *input_right = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_RIGHT); + const int32_t *input_left_surround = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_LEFT_SURROUND); + const int32_t *input_right_surround = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_RIGHT_SURROUND); + const int32_t *input_lfe = in32 + get_channel_location(cd->in_channel_map, CHANNEL_LFE); + const int32_t *input_left_side = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_LEFT_SIDE); + const int32_t *input_right_side = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_RIGHT_SIDE); + + /* Downmixer single store. */ + int32_t *output_left = (int32_t *)(out_data); + int32_t *output_right = output_left + 1; + + const int32_t *const end_input_left = input_left + (in_size / (sizeof(int32_t))); + + while (input_left < end_input_left) { + /* Accumulate as Q1.31 * Q1.31 -> Q2.62 */ + Q_tmp_left = (int64_t)P_coefficient_center * *input_center; + input_center += CH_COUNT_7_1; + + Q_tmp_left += (int64_t)P_coefficient_lfe * *input_lfe; + Q_tmp_right = Q_tmp_left; + input_lfe += CH_COUNT_7_1; + + Q_tmp_left += (int64_t)P_coefficient_left * *input_left; + input_left += CH_COUNT_7_1; + + Q_tmp_right += (int64_t)P_coefficient_right * *input_right; + input_right += CH_COUNT_7_1; + + Q_tmp_left += (int64_t)P_coefficient_left_surround * *input_left_surround; + input_left_surround += CH_COUNT_7_1; + + Q_tmp_right += (int64_t)P_coefficient_right_surround * *input_right_surround; + input_right_surround += CH_COUNT_7_1; + + Q_tmp_left += (int64_t)P_coefficient_left_side * *input_left_side; + input_left_surround += CH_COUNT_7_1; + + Q_tmp_right += (int64_t)P_coefficient_right_side * *input_right_side; + input_right_surround += CH_COUNT_7_1; + + /* Shift with round to Q1.31 and saturate and store output */ + *output_left = sat_int32(Q_SHIFT_RND(Q_tmp_left, 62, 31)); + *output_right = sat_int32(Q_SHIFT_RND(Q_tmp_right, 62, 31)); + output_left += CH_COUNT_2_0; + output_right += CH_COUNT_2_0; + } } void downmix16bit_stereo(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + int32_t sum; + const int16_t *in_data16 = (int16_t *)in_data; + int16_t *out_data16 = (int16_t *)out_data; + int idx; + + for (idx = 0; idx < (in_size >> 2); ++idx) { + sum = (int32_t)in_data16[2 * idx] + in_data16[2 * idx + 1]; + out_data16[idx] = sat_int16((sum + 1) >> 1); + } } void shiftcopy16bit_mono(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + int i; + + uint16_t *in_ptrs = (uint16_t *)in_data; + uint64_t *out_ptrs = (uint64_t *)out_data; + + for (i = 0; i < (in_size >> 1); ++i) + out_ptrs[i] = (uint64_t)in_ptrs[i] << 48 | ((uint64_t)in_ptrs[i] << 16); } void shiftcopy16bit_stereo(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + uint32_t i; + + uint32_t *in_ptrs = (uint32_t *)in_data; + uint64_t *out_ptrs = (uint64_t *)out_data; + uint32_t in_regs; + + for (i = 0; i < (in_size >> 2); ++i) { + in_regs = in_ptrs[i]; + out_ptrs[i] = (((uint64_t)in_regs & 0xffff) << 16) | + (((uint64_t)in_regs & 0xffff0000) << 32); + } } void downmix16bit(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + int64_t Q_tmp_left = 0; + int64_t Q_tmp_right = 0; + int64_t p; + int32_t P_coefficient_left = cd->downmix_coefficients[CHANNEL_LEFT]; + int32_t P_coefficient_center = cd->downmix_coefficients[CHANNEL_CENTER]; + int32_t P_coefficient_right = cd->downmix_coefficients[CHANNEL_RIGHT]; + int32_t P_coefficient_left_surround = cd->downmix_coefficients[CHANNEL_LEFT_SURROUND]; + int32_t P_coefficient_right_surround = cd->downmix_coefficients[CHANNEL_RIGHT_SURROUND]; + int32_t P_coefficient_lfe = cd->downmix_coefficients[CHANNEL_LFE]; + int32_t *output_left = (int32_t *)out_data; + int32_t *output_right = output_left + 1; + int16_t *input_left; + int16_t *input_center; + int16_t *input_right; + int16_t *input_left_surround; + int16_t *input_right_surround; + int16_t *input_lfe; + int16_t *in16 = (int16_t *)in_data; + + /* See what channels are available. */ + bool left = (get_channel_location(cd->in_channel_map, CHANNEL_LEFT) != 0xF); + bool center = (get_channel_location(cd->in_channel_map, CHANNEL_CENTER) != 0xF); + bool right = (get_channel_location(cd->in_channel_map, CHANNEL_RIGHT) != 0xF); + bool left_surround = + (get_channel_location(cd->in_channel_map, CHANNEL_LEFT_SURROUND) != 0xF); + bool right_surround = + (get_channel_location(cd->in_channel_map, CHANNEL_RIGHT_SURROUND) != 0xF); + bool lfe = (get_channel_location(cd->in_channel_map, CHANNEL_LFE) != 0xF); + + /** Calculate number of samples in a single channel. */ + int number_of_samples_in_one_channel = in_size / cd->in_channel_no >> 1; + + int sample_offset = cd->in_channel_no; + int i; + + /* No check for bool above. If false address becomes in32 + 0xf, but it is not + * used in the processing loop. + */ + input_left = in16 + get_channel_location(cd->in_channel_map, CHANNEL_LEFT); + input_center = in16 + get_channel_location(cd->in_channel_map, CHANNEL_CENTER); + input_right = in16 + get_channel_location(cd->in_channel_map, CHANNEL_RIGHT); + input_left_surround = in16 + get_channel_location(cd->in_channel_map, + CHANNEL_LEFT_SURROUND); + input_right_surround = in16 + get_channel_location(cd->in_channel_map, + CHANNEL_RIGHT_SURROUND); + input_lfe = in16 + get_channel_location(cd->in_channel_map, CHANNEL_LFE); + + for (i = 0; i < number_of_samples_in_one_channel; i++) { + if (left) { + Q_tmp_left += (int64_t)P_coefficient_left * *input_left; + input_left += sample_offset; + } + if (center) { + p = (int64_t)P_coefficient_center * *input_center; + Q_tmp_left += p; + Q_tmp_right += p; + input_center += sample_offset; + } + if (right) { + Q_tmp_right += (int64_t)P_coefficient_right * *input_right; + input_right += sample_offset; + } + if (left_surround) { + p = (int64_t)P_coefficient_left_surround * *input_left_surround; + Q_tmp_left += p; + input_left_surround += sample_offset; + if (cd->in_channel_config == IPC4_CHANNEL_CONFIG_4_POINT_0) + Q_tmp_right += p; + } + if (right_surround) { + Q_tmp_right += (int64_t)P_coefficient_right_surround * + *input_right_surround; + input_right_surround += sample_offset; + } + if (lfe) { + p = (int64_t)P_coefficient_lfe * *input_lfe; + Q_tmp_left += p; + Q_tmp_right += p; + input_lfe += sample_offset; + } + + /* Shift with round to Q1.31 and saturate and store output */ + *output_left = sat_int32(Q_SHIFT_RND(Q_tmp_left, 46, 31)); + *output_right = sat_int32(Q_SHIFT_RND(Q_tmp_right, 46, 31)); + output_left += CH_COUNT_2_0; + output_right += CH_COUNT_2_0; + } } void downmix16bit_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + int64_t Q_tmp_left; + int64_t Q_tmp_right; + int32_t P_coefficient_left = cd->downmix_coefficients[CHANNEL_LEFT]; + int32_t P_coefficient_center = cd->downmix_coefficients[CHANNEL_CENTER]; + int32_t P_coefficient_right = cd->downmix_coefficients[CHANNEL_RIGHT]; + int32_t P_coefficient_left_surround = cd->downmix_coefficients[CHANNEL_LEFT_SURROUND]; + int32_t P_coefficient_right_surround = cd->downmix_coefficients[CHANNEL_RIGHT_SURROUND]; + int32_t P_coefficient_lfe = cd->downmix_coefficients[CHANNEL_LFE]; + int32_t *output_left = (int32_t *)out_data; + int32_t *output_right = output_left + 1; + int16_t *input_left; + int16_t *input_center; + int16_t *input_right; + int16_t *input_left_surround; + int16_t *input_right_surround; + int16_t *input_lfe; + int16_t *in16 = (int16_t *)in_data; + int i; + int number_of_samples_in_one_channel = (in_size / cd->in_channel_no) >> 1; + + /* Only load the channel if it's present. */ + input_left = in16 + get_channel_location(cd->in_channel_map, CHANNEL_LEFT); + input_center = in16 + get_channel_location(cd->in_channel_map, CHANNEL_CENTER); + input_right = in16 + get_channel_location(cd->in_channel_map, CHANNEL_RIGHT); + input_lfe = in16 + get_channel_location(cd->in_channel_map, CHANNEL_LFE); + input_left_surround = in16 + + get_channel_location(cd->in_channel_map, CHANNEL_LEFT_SURROUND); + input_right_surround = in16 + + get_channel_location(cd->in_channel_map, CHANNEL_RIGHT_SURROUND); + + for (i = 0; i < number_of_samples_in_one_channel; i++) { + /* Accumulate as Q1.31 * Q1.15 -> Q2.46 */ + Q_tmp_left = (int64_t)P_coefficient_center * *input_center; + input_center += CH_COUNT_5_1; + + Q_tmp_left += (int64_t)P_coefficient_lfe * *input_lfe; + Q_tmp_right = Q_tmp_left; + input_lfe += CH_COUNT_5_1; + + Q_tmp_left += (int64_t)P_coefficient_left * *input_left; + input_left += CH_COUNT_5_1; + + Q_tmp_right += (int64_t)P_coefficient_right * *input_right; + input_right += CH_COUNT_5_1; + + Q_tmp_left += (int64_t)P_coefficient_left_surround * *input_left_surround; + input_left_surround += CH_COUNT_5_1; + + Q_tmp_right += (int64_t)P_coefficient_right_surround * *input_right_surround; + input_right_surround += CH_COUNT_5_1; + + /* Shift with round to Q1.31 and saturate and store output */ + *output_left = sat_int32(Q_SHIFT_RND(Q_tmp_left, 46, 31)); + *output_right = sat_int32(Q_SHIFT_RND(Q_tmp_right, 46, 31)); + output_left += CH_COUNT_2_0; + output_right += CH_COUNT_2_0; + } } void downmix16bit_4ch_mono(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + int32_t Q_tmp; + uint16_t coeffs[4] = {cd->downmix_coefficients[get_channel_index(cd->in_channel_map, 0)], + cd->downmix_coefficients[get_channel_index(cd->in_channel_map, 1)], + cd->downmix_coefficients[get_channel_index(cd->in_channel_map, 2)], + cd->downmix_coefficients[get_channel_index(cd->in_channel_map, 3)] + }; + + const int16_t *input_data = (const int16_t *)in_data; + int16_t *output_data = (int16_t *)out_data; + int i; + + for (i = 0; i < in_size / (sizeof(int16_t)); i += 4) { + /* Q1.15 * Q.15 -> Q2.30 */ + Q_tmp = (int32_t)coeffs[0] * input_data[0] + + (int32_t)coeffs[1] * input_data[1] + + (int32_t)coeffs[2] * input_data[2] + + (int32_t)coeffs[3] * input_data[3]; + *output_data = sat_int16(Q_SHIFT_RND(Q_tmp, 30, 15)); + input_data += CH_COUNT_4_0; + output_data++; + } } void downmix32bit_stereo(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + int64_t sum; + int32_t *in_data32 = (int32_t *)in_data; + int32_t *out_data32 = (int32_t *)out_data; + int idx; + + for (idx = 0; idx < (in_size >> 3); idx++) { + sum = (int64_t)in_data32[2 * idx] + in_data32[2 * idx + 1]; + out_data32[idx] = sat_int32((sum + 1) >> 1); + } } void downmix32bit_3_1_mono(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + int64_t Q_tmp; + int32_t P_coefficient_left = cd->downmix_coefficients[CHANNEL_LEFT]; + int32_t P_coefficient_center = cd->downmix_coefficients[CHANNEL_CENTER]; + int32_t P_coefficient_right = cd->downmix_coefficients[CHANNEL_RIGHT]; + int32_t P_coefficient_lfe = cd->downmix_coefficients[CHANNEL_LFE]; + const int32_t *in32 = (const int32_t *)in_data; + const int32_t *input_left = in32 + get_channel_location(cd->in_channel_map, CHANNEL_LEFT); + const int32_t *input_right = in32 + get_channel_location(cd->in_channel_map, CHANNEL_RIGHT); + const int32_t *input_lfe = in32 + get_channel_location(cd->in_channel_map, CHANNEL_LFE); + const int32_t *input_center = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_CENTER); + int32_t *output = (int32_t *)(out_data); + const int channel_no = 4; + int i; + + for (i = 0; i < in_size / (sizeof(int32_t)); i += channel_no) { + Q_tmp = (int64_t)P_coefficient_left * *input_left; + input_left += CH_COUNT_3_1; + + Q_tmp += (int64_t)P_coefficient_center * *input_center; + input_center += CH_COUNT_3_1; + + Q_tmp += (int64_t)P_coefficient_right * *input_right; + input_right += CH_COUNT_3_1; + + Q_tmp += (int64_t)P_coefficient_lfe * *input_lfe; + input_right += CH_COUNT_3_1; + + /* Shift with round to Q1.31 and saturate and store output */ + *output = sat_int32(Q_SHIFT_RND(Q_tmp, 62, 31)); + output++; + } } void downmix32bit_4_0_mono(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + int64_t Q_tmp; + int32_t P_coefficient_left = cd->downmix_coefficients[CHANNEL_LEFT]; + int32_t P_coefficient_center = cd->downmix_coefficients[CHANNEL_CENTER]; + int32_t P_coefficient_right = cd->downmix_coefficients[CHANNEL_RIGHT]; + int32_t P_coefficient_cs = cd->downmix_coefficients[CHANNEL_CENTER_SURROUND]; + const int32_t *in32 = (const int32_t *)in_data; + const int32_t *input_left = in32 + get_channel_location(cd->in_channel_map, CHANNEL_LEFT); + const int32_t *input_right = in32 + get_channel_location(cd->in_channel_map, CHANNEL_RIGHT); + const int32_t *input_center = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_CENTER); + const int32_t *input_cs = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_CENTER_SURROUND); + int32_t *output = (int32_t *)(out_data); + const int channel_no = 4; + int i; + + for (i = 0; i < in_size / (sizeof(int32_t)); i += channel_no) { + Q_tmp = (int64_t)P_coefficient_left * *input_left; + input_left += CH_COUNT_4_0; + + Q_tmp += (int64_t)P_coefficient_center * *input_center; + input_center += CH_COUNT_4_0; + + Q_tmp += (int64_t)P_coefficient_right * *input_right; + input_right += CH_COUNT_4_0; + + Q_tmp += (int64_t)P_coefficient_cs * *input_cs; + input_cs += CH_COUNT_4_0; + + /* Shift with round to Q1.31 and saturate and store output */ + *output = sat_int32(Q_SHIFT_RND(Q_tmp, 62, 31)); + output++; + } } void downmix32bit_quatro_mono(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + int64_t Q_tmp; + int32_t P_coefficient_left = cd->downmix_coefficients[CHANNEL_LEFT]; + int32_t P_coefficient_ls = cd->downmix_coefficients[CHANNEL_LEFT_SURROUND]; + int32_t P_coefficient_right = cd->downmix_coefficients[CHANNEL_RIGHT]; + int32_t P_coefficient_rs = cd->downmix_coefficients[CHANNEL_RIGHT_SURROUND]; + const int32_t *in32 = (const int32_t *)in_data; + const int32_t *input_left = in32 + get_channel_location(cd->in_channel_map, CHANNEL_LEFT); + const int32_t *input_right = in32 + get_channel_location(cd->in_channel_map, CHANNEL_RIGHT); + const int32_t *input_ls = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_LEFT_SURROUND); + const int32_t *input_rs = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_RIGHT_SURROUND); + int32_t *output = (int32_t *)(out_data); + const int channel_no = CH_COUNT_QUATRO; + int i; + + for (i = 0; i < in_size / (sizeof(int32_t)); i += channel_no) { + Q_tmp = (int64_t)P_coefficient_left * *input_left; + input_left += CH_COUNT_QUATRO; + + Q_tmp += (int64_t)P_coefficient_ls * *input_ls; + input_ls += CH_COUNT_QUATRO; + + Q_tmp += (int64_t)P_coefficient_right * *input_right; + input_right += CH_COUNT_QUATRO; + + Q_tmp += (int64_t)P_coefficient_rs * *input_rs; + input_rs += CH_COUNT_QUATRO; + + /* Shift with round to Q1.31 and saturate and store output */ + *output = sat_int32(Q_SHIFT_RND(Q_tmp, 62, 31)); + output++; + } } void downmix32bit_5_1_mono(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + int64_t Q_tmp; + int32_t P_coefficient_left = cd->downmix_coefficients[CHANNEL_LEFT]; + int32_t P_coefficient_center = cd->downmix_coefficients[CHANNEL_CENTER]; + int32_t P_coefficient_right = cd->downmix_coefficients[CHANNEL_RIGHT]; + int32_t P_coefficient_cs = cd->downmix_coefficients[CHANNEL_CENTER_SURROUND]; + const int32_t *in32 = (const int32_t *)in_data; + const int32_t *input_left = in32 + get_channel_location(cd->in_channel_map, CHANNEL_LEFT); + const int32_t *input_center = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_CENTER); + const int32_t *input_right = in32 + get_channel_location(cd->in_channel_map, CHANNEL_RIGHT); + const int32_t *input_cs = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_CENTER_SURROUND); + int32_t *output = (int32_t *)(out_data); + const int channel_no = CH_COUNT_5_1; + int i; + + for (i = 0; i < in_size / (sizeof(int32_t)); i += channel_no) { + Q_tmp = (int64_t)P_coefficient_left * *input_left; + input_left += CH_COUNT_5_1; + + Q_tmp += (int64_t)P_coefficient_center * *input_center; + input_center += CH_COUNT_5_1; + + Q_tmp += (int64_t)P_coefficient_right * *input_right; + input_right += CH_COUNT_5_1; + + Q_tmp += (int64_t)P_coefficient_cs * *input_cs; + input_cs += CH_COUNT_5_1; + + /* Shift with round to Q1.31 and saturate and store output */ + *output = sat_int32(Q_SHIFT_RND(Q_tmp, 62, 31)); + output++; + } } void downmix32bit_7_1_mono(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + int64_t Q_tmp; + int32_t P_coefficient_left = cd->downmix_coefficients[CHANNEL_LEFT]; + int32_t P_coefficient_center = cd->downmix_coefficients[CHANNEL_CENTER]; + int32_t P_coefficient_right = cd->downmix_coefficients[CHANNEL_RIGHT]; + int32_t P_coefficient_cs = cd->downmix_coefficients[CHANNEL_CENTER_SURROUND]; + const int32_t *in32 = (const int32_t *)in_data; + const int32_t *input_left = in32 + get_channel_location(cd->in_channel_map, CHANNEL_LEFT); + const int32_t *input_center = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_CENTER); + const int32_t *input_right = in32 + get_channel_location(cd->in_channel_map, CHANNEL_RIGHT); + const int32_t *input_cs = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_CENTER_SURROUND); + int32_t *output = (int32_t *)(out_data); + const int channel_no = CH_COUNT_7_1; + int i; + + for (i = 0; i < in_size / (sizeof(int32_t)); i += channel_no) { + Q_tmp = (int64_t)P_coefficient_left * *input_left; + input_left += CH_COUNT_7_1; + + Q_tmp += (int64_t)P_coefficient_center * *input_center; + input_center += CH_COUNT_7_1; + + Q_tmp += (int64_t)P_coefficient_right * *input_right; + input_right += CH_COUNT_7_1; + + Q_tmp += (int64_t)P_coefficient_cs * *input_cs; + input_cs += CH_COUNT_7_1; + + /* Shift with round to Q1.31 and saturate and store output */ + *output = sat_int32(Q_SHIFT_RND(Q_tmp, 62, 31)); + output++; + } } void downmix32bit_7_1_to_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + int64_t Q_tmp_right_side; + int64_t Q_tmp_left_side; + uint32_t i; + + channel_map out_channel_map = cd->out_channel_map; + uint8_t right_surround_slot = get_channel_location(out_channel_map, CHANNEL_RIGHT_SURROUND); + uint8_t left_surround_slot = get_channel_location(out_channel_map, CHANNEL_LEFT_SURROUND); + + if (left_surround_slot == CHANNEL_INVALID && right_surround_slot == CHANNEL_INVALID) { + left_surround_slot = get_channel_location(out_channel_map, CHANNEL_LEFT_SIDE); + right_surround_slot = get_channel_location(out_channel_map, CHANNEL_RIGHT_SIDE); + } + + int32_t *out32 = (int32_t *)out_data; + + int32_t *output_left_ptr = out32 + get_channel_location(out_channel_map, CHANNEL_LEFT); + int32_t *output_center_ptr = out32 + get_channel_location(out_channel_map, CHANNEL_CENTER); + int32_t *output_right_ptr = out32 + get_channel_location(out_channel_map, CHANNEL_RIGHT); + int32_t *output_side_left_ptr = out32 + left_surround_slot; + int32_t *output_side_right_ptr = out32 + right_surround_slot; + int32_t *output_lfe_ptr = out32 + get_channel_location(out_channel_map, CHANNEL_LFE); + + int32_t *in_left_ptr = (int32_t *)in_data; + int32_t *in_center_ptr = (int32_t *)(in_data + 4); + int32_t *in_right_ptr = (int32_t *)(in_data + 8); + int32_t *in_lfe_ptr = (int32_t *)(in_data + 20); + + for (i = 0; i < (in_size >> 5); ++i) { + output_left_ptr[i * 6] = in_left_ptr[i * 8]; + output_right_ptr[i * 6] = in_right_ptr[i * 8]; + output_center_ptr[i * 6] = in_center_ptr[i * 8]; + output_lfe_ptr[i * 6] = in_lfe_ptr[i * 8]; + } + + /* Load the downmix coefficients. */ + int32_t P_coefficient_left = cd->downmix_coefficients[CHANNEL_LEFT]; + int32_t P_coefficient_right = cd->downmix_coefficients[CHANNEL_RIGHT]; + int32_t P_coefficient_left_surround = cd->downmix_coefficients[CHANNEL_LEFT_SURROUND]; + int32_t P_coefficient_right_surround = cd->downmix_coefficients[CHANNEL_RIGHT_SURROUND]; + + const int32_t *in32 = (const int32_t *)in_data; + const int32_t *input_left_surround = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_LEFT_SURROUND); + const int32_t *input_right_surround = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_RIGHT_SURROUND); + const int32_t *input_left_side = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_LEFT_SIDE); + const int32_t *input_right_side = in32 + + get_channel_location(cd->in_channel_map, CHANNEL_RIGHT_SIDE); + + const int32_t *const end_input_left = input_left_surround + (in_size / (sizeof(int32_t))); + + while (input_left_surround < end_input_left) { + Q_tmp_left_side = (int64_t)P_coefficient_left * *input_left_surround; + Q_tmp_right_side = (int64_t)P_coefficient_right_surround * *input_left_surround; + input_left_surround += CH_COUNT_7_1; + + Q_tmp_left_side += (int64_t)P_coefficient_left_surround * *input_right_surround; + Q_tmp_right_side += (int64_t)P_coefficient_right * *input_right_surround; + input_right_surround += CH_COUNT_7_1; + + Q_tmp_left_side += (int64_t)P_coefficient_left * *input_left_side; + input_left_side += CH_COUNT_7_1; + + Q_tmp_right_side += (int64_t)P_coefficient_right * *input_right_side; + input_right_side += CH_COUNT_7_1; + + /* Shift with round to Q1.31 and saturate and store output */ + *output_side_left_ptr = sat_int32(Q_SHIFT_RND(Q_tmp_left_side, 46, 31)); + *output_side_right_ptr = sat_int32(Q_SHIFT_RND(Q_tmp_right_side, 46, 31)); + output_side_left_ptr += CH_COUNT_5_1; + output_side_right_ptr += CH_COUNT_5_1; + } } void upmix32bit_4_0_to_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + int64_t Q_tmp_right_side; + int64_t Q_tmp_left_side; + channel_map out_channel_map = cd->out_channel_map; + + int right_surround_slot = get_channel_location(out_channel_map, CHANNEL_RIGHT_SURROUND); + int left_surround_slot = get_channel_location(out_channel_map, CHANNEL_LEFT_SURROUND); + + if (left_surround_slot == CHANNEL_INVALID && right_surround_slot == CHANNEL_INVALID) { + left_surround_slot = get_channel_location(out_channel_map, CHANNEL_LEFT_SIDE); + right_surround_slot = get_channel_location(out_channel_map, CHANNEL_RIGHT_SIDE); + } + + int32_t *out32 = (int32_t *)out_data; + int32_t *output_left = out32 + get_channel_location(out_channel_map, CHANNEL_LEFT); + int32_t *output_center = out32 + get_channel_location(out_channel_map, CHANNEL_CENTER); + int32_t *output_right = out32 + get_channel_location(out_channel_map, CHANNEL_RIGHT); + int32_t *output_lfe = out32 + get_channel_location(out_channel_map, CHANNEL_LFE); + int32_t *output_side_left = out32 + left_surround_slot; + int32_t *output_side_right = out32 + right_surround_slot; + int32_t *in_left_ptr = (int32_t *)in_data; + int32_t *in_center_ptr = (int32_t *)(in_data + 4); + int32_t *in_right_ptr = (int32_t *)(in_data + 8); + int i; + + for (i = 0; i < (in_size >> 4); ++i) { + output_left[i * CH_COUNT_5_1] = in_left_ptr[i * CH_COUNT_4_0]; + output_right[i * CH_COUNT_5_1] = in_right_ptr[i * CH_COUNT_4_0]; + output_center[i * CH_COUNT_5_1] = in_center_ptr[i * CH_COUNT_4_0]; + output_lfe[i * CH_COUNT_5_1] = 0; + } + + /* Load the downmix coefficients. */ + int32_t P_coefficient_left_surround = cd->downmix_coefficients[CHANNEL_LEFT_SURROUND]; + int32_t P_coefficient_right_surround = cd->downmix_coefficients[CHANNEL_RIGHT_SURROUND]; + + const int32_t *input_center_surround = (int32_t *)(in_data + + (get_channel_location(cd->in_channel_map, CHANNEL_CENTER_SURROUND) << 2)); + + const int32_t *const end_input_left = input_center_surround + (in_size / (sizeof(int32_t))); + + while (input_center_surround < end_input_left) { + /* Q1.31 * Q1.31 gives Q2.62 */ + Q_tmp_left_side = (int64_t)P_coefficient_left_surround * *input_center_surround; + Q_tmp_right_side = (int64_t)P_coefficient_right_surround * *input_center_surround; + input_center_surround += CH_COUNT_4_0; + + /* Shift with round to Q1.31 and saturate and store output */ + *output_side_left = sat_int32(Q_SHIFT_RND(Q_tmp_left_side, 62, 31)); + *output_side_right = sat_int32(Q_SHIFT_RND(Q_tmp_right_side, 62, 31)); + output_side_left += CH_COUNT_5_1; + output_side_right += CH_COUNT_5_1; + } } void upmix32bit_quatro_to_5_1(struct up_down_mixer_data *cd, const uint8_t * const in_data, const uint32_t in_size, uint8_t * const out_data) { - sof_panic(0); + int i; + + channel_map out_channel_map = cd->out_channel_map; + + const uint8_t left_slot = get_channel_location(out_channel_map, CHANNEL_LEFT); + const uint8_t center_slot = get_channel_location(out_channel_map, CHANNEL_CENTER); + const uint8_t right_slot = get_channel_location(out_channel_map, CHANNEL_RIGHT); + uint8_t right_surround_slot = get_channel_location(out_channel_map, CHANNEL_RIGHT_SURROUND); + uint8_t left_surround_slot = get_channel_location(out_channel_map, CHANNEL_LEFT_SURROUND); + const uint8_t lfe_slot = get_channel_location(out_channel_map, CHANNEL_LFE); + + /* Must support also 5.1 Surround */ + const bool surround_5_1_channel_map = (left_surround_slot == CHANNEL_INVALID) && + (right_surround_slot == CHANNEL_INVALID); + + if (surround_5_1_channel_map) { + left_surround_slot = get_channel_location(cd->in_channel_map, CHANNEL_LEFT_SIDE); + right_surround_slot = get_channel_location(cd->in_channel_map, CHANNEL_RIGHT_SIDE); + } + + int32_t *output_left = (int32_t *)(out_data + (left_slot << 2)); + int32_t *output_center = (int32_t *)(out_data + (center_slot << 2)); + int32_t *output_right = (int32_t *)(out_data + (right_slot << 2)); + int32_t *output_side_left = (int32_t *)(out_data + (left_surround_slot << 2)); + int32_t *output_side_right = (int32_t *)(out_data + (right_surround_slot << 2)); + int32_t *output_lfe = (int32_t *)(out_data + (lfe_slot << 2)); + + int32_t *in_left_ptr = (int32_t *)in_data; + int32_t *in_right_ptr = (int32_t *)(in_data + 4); + int32_t *in_left_sorround_ptr = (int32_t *)(in_data + 8); + int32_t *in_right_sorround_ptr = (int32_t *)(in_data + 12); + + for (i = 0; i < (in_size >> 4); ++i) { + output_left[i * CH_COUNT_5_1] = in_left_ptr[i * CH_COUNT_QUATRO]; + output_right[i * CH_COUNT_5_1] = in_right_ptr[i * CH_COUNT_QUATRO]; + output_center[i * CH_COUNT_5_1] = 0; + output_side_left[i * CH_COUNT_5_1] = in_left_sorround_ptr[i * CH_COUNT_QUATRO]; + output_side_right[i * CH_COUNT_5_1] = in_right_sorround_ptr[i * CH_COUNT_QUATRO]; + output_lfe[i * CH_COUNT_5_1] = 0; + } } #endif /* #if SOF_USE_HIFI(NONE, UP_DOWN_MIXER) */ From 8e8caeca508a40b92c7ca6e271573604f0a77335 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Tue, 20 May 2025 16:01:00 +0300 Subject: [PATCH 09/11] [do not merge] Audio: Up_down_mixer: Force generic C version build Temporary change, force CI check for generic C version functions. Signed-off-by: Seppo Ingalsuo --- src/audio/up_down_mixer/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/audio/up_down_mixer/Kconfig b/src/audio/up_down_mixer/Kconfig index 53c82efaed44..8bc7e6b79ec3 100644 --- a/src/audio/up_down_mixer/Kconfig +++ b/src/audio/up_down_mixer/Kconfig @@ -17,7 +17,7 @@ config COMP_UP_DOWN_MIXER choice prompt "Up_down_mixer HIFI level" depends on COMP_UP_DOWN_MIXER - default UP_DOWN_MIXER_HIFI_MAX + default UP_DOWN_MIXER_HIFI_NONE config UP_DOWN_MIXER_HIFI_MAX bool "Max level available in the toolchain" From c7e2e0762c2342e4c5ef4f9a68c9cccaeba285a7 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Tue, 20 May 2025 18:58:08 +0300 Subject: [PATCH 10/11] [do not merge] Tools: Testbench: No O3 for debugger Signed-off-by: Seppo Ingalsuo --- src/arch/host/CMakeLists.txt | 2 +- tools/testbench/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/arch/host/CMakeLists.txt b/src/arch/host/CMakeLists.txt index 75314f00f556..cad2e88f7ce1 100644 --- a/src/arch/host/CMakeLists.txt +++ b/src/arch/host/CMakeLists.txt @@ -18,7 +18,7 @@ if (supports_implicit_fallthrough) endif() # C & ASM flags -target_compile_options(sof_options INTERFACE -g -O3 -fPIC -DPIC -std=c99 -std=gnu99 -fgnu89-inline +target_compile_options(sof_options INTERFACE -g -fPIC -DPIC -std=c99 -std=gnu99 -fgnu89-inline -Wall -Werror -Wmissing-prototypes ${implicit_fallthrough} -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast -Wpointer-arith -DCONFIG_LIBRARY "-imacros${CONFIG_H_PATH}") diff --git a/tools/testbench/CMakeLists.txt b/tools/testbench/CMakeLists.txt index 100dc320debf..cf39441b27cf 100644 --- a/tools/testbench/CMakeLists.txt +++ b/tools/testbench/CMakeLists.txt @@ -54,7 +54,7 @@ if (supports_implicit_fallthrough) set(implicit_fallthrough -Wimplicit-fallthrough) endif() -target_compile_options(${testbench} PRIVATE -g -O3 -Wall -Werror -Wmissing-prototypes +target_compile_options(${testbench} PRIVATE -g -Wall -Werror -Wmissing-prototypes ${implicit_fallthrough} -DCONFIG_LIBRARY -DCONFIG_LIBRARY_STATIC -imacros${config_h}) target_link_libraries(${testbench} PRIVATE -lm) From d0965100775def168c0318d44b90791935938bfd Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Fri, 23 May 2025 12:42:02 +0300 Subject: [PATCH 11/11] [do not merge] Audio: Up_down_mixer: Add traces to debug operation in test Signed-off-by: Seppo Ingalsuo --- src/audio/up_down_mixer/up_down_mixer.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/audio/up_down_mixer/up_down_mixer.c b/src/audio/up_down_mixer/up_down_mixer.c index 7a61637101a1..c042c446f136 100644 --- a/src/audio/up_down_mixer/up_down_mixer.c +++ b/src/audio/up_down_mixer/up_down_mixer.c @@ -47,6 +47,8 @@ static int set_downmix_coefficients(struct processing_module *mod, struct comp_dev *dev = mod->dev; int ret; + comp_info(dev, "set_downmix_coefficients()"); + if (cd->downmix_coefficients) { ret = memcpy_s(&custom_coeffs, sizeof(custom_coeffs), downmix_coefficients, sizeof(int32_t) * UP_DOWN_MIX_COEFFS_LENGTH); @@ -110,6 +112,8 @@ static int set_downmix_coefficients(struct processing_module *mod, static up_down_mixer_routine select_mix_out_stereo(struct comp_dev *dev, const struct ipc4_audio_format *format) { + comp_info(dev, "select_mix_out_stereo()"); + if (format->depth == IPC4_DEPTH_16BIT) { switch (format->ch_cfg) { case IPC4_CHANNEL_CONFIG_MONO: @@ -175,6 +179,8 @@ static up_down_mixer_routine select_mix_out_stereo(struct comp_dev *dev, static up_down_mixer_routine select_mix_out_mono(struct comp_dev *dev, const struct ipc4_audio_format *format) { + comp_info(dev, "select_mix_out_mono("); + if (format->depth == IPC4_DEPTH_16BIT) { switch (format->ch_cfg) { case IPC4_CHANNEL_CONFIG_STEREO: @@ -226,6 +232,8 @@ static up_down_mixer_routine select_mix_out_mono(struct comp_dev *dev, static up_down_mixer_routine select_mix_out_5_1(struct comp_dev *dev, const struct ipc4_audio_format *format) { + comp_info(dev, "select_mix_out_5_1()"); + if (format->depth == IPC4_DEPTH_16BIT) { switch (format->ch_cfg) { case IPC4_CHANNEL_CONFIG_MONO: @@ -265,6 +273,8 @@ static int init_mix(struct processing_module *mod, struct up_down_mixer_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; + comp_info(dev, "init_mix()"); + if (!format) return -EINVAL; @@ -326,6 +336,8 @@ static int up_down_mixer_free(struct processing_module *mod) { struct up_down_mixer_data *cd = module_get_private_data(mod); + comp_info(mod->dev, "up_down_mixer_free()"); + rfree(cd->buf_in); rfree(cd->buf_out); rfree(cd); @@ -405,23 +417,31 @@ static int up_down_mixer_init(struct processing_module *mod) switch (up_down_mixer->coefficients_select) { case DEFAULT_COEFFICIENTS: cd->out_channel_map = create_channel_map(up_down_mixer->out_channel_config); + comp_info(dev, "c1 out_channel map = 0x%08x", cd->out_channel_map); ret = init_mix(mod, &mod->priv.cfg.base_cfg.audio_fmt, up_down_mixer->out_channel_config, NULL); + comp_info(dev, "c1 init_mix() done"); break; case CUSTOM_COEFFICIENTS: cd->out_channel_map = create_channel_map(up_down_mixer->out_channel_config); + comp_info(dev, "c2 out_channel map = 0x%08x", cd->out_channel_map); ret = init_mix(mod, &mod->priv.cfg.base_cfg.audio_fmt, up_down_mixer->out_channel_config, up_down_mixer->coefficients); + comp_info(dev, "c2 init_mix() done"); break; case DEFAULT_COEFFICIENTS_WITH_CHANNEL_MAP: cd->out_channel_map = up_down_mixer->channel_map; + comp_info(dev, "c3 out_channel map = 0x%08x", cd->out_channel_map); ret = init_mix(mod, &mod->priv.cfg.base_cfg.audio_fmt, up_down_mixer->out_channel_config, NULL); + comp_info(dev, "c3 init_mix() done"); break; case CUSTOM_COEFFICIENTS_WITH_CHANNEL_MAP: cd->out_channel_map = up_down_mixer->channel_map; + comp_info(dev, "c4 out_channel map = 0x%08x", cd->out_channel_map); ret = init_mix(mod, &mod->priv.cfg.base_cfg.audio_fmt, up_down_mixer->out_channel_config, up_down_mixer->coefficients); + comp_info(dev, "c4 init_mix() done"); break; default: comp_err(dev, "up_down_mixer_init(): unsupported coefficient type"); @@ -434,9 +454,11 @@ static int up_down_mixer_init(struct processing_module *mod) goto err; } + comp_info(dev, "up_down_mixer_init() ready"); return 0; err: + comp_err(dev, "up_down_mixer_init() error"); up_down_mixer_free(mod); return ret; }