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 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/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/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..8bc7e6b79ec3 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_NONE + +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.c b/src/audio/up_down_mixer/up_down_mixer.c index e1cb4d9e13bc..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); @@ -335,12 +347,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,26 +373,75 @@ 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); + 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"); @@ -389,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; } @@ -405,40 +472,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; } 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_generic.c b/src/audio/up_down_mixer/up_down_mixer_generic.c new file mode 100644 index 000000000000..df0a4b912b10 --- /dev/null +++ b/src/audio/up_down_mixer/up_down_mixer_generic.c @@ -0,0 +1,1280 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2022-2025 Intel Corporation. +// +// Author: Bartosz Kokoszko +// Seppo Ingalsuo + +#include +#include +#include +#include + +#include "up_down_mixer.h" + +#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) +{ + + 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) +{ + + 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) +{ + + 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) +{ + + 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) +{ + + 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) +{ + + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + /* 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) */ 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) */ 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__ */ 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/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] 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) 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 */ 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 +}