diff --git a/src/audio/selector/selector.c b/src/audio/selector/selector.c index 40a4a2c5b888..eb51f9eab005 100644 --- a/src/audio/selector/selector.c +++ b/src/audio/selector/selector.c @@ -37,6 +37,10 @@ #include #include +#if CONFIG_IPC_MAJOR_4 +#define SEL_MAX_CONFIG_BLOB_SIZE (SEL_MAX_NUM_CONFIGS * sizeof(struct ipc4_selector_coeffs_config)) +#endif + LOG_MODULE_REGISTER(selector, CONFIG_SOF_LOG_LEVEL); #if CONFIG_IPC_MAJOR_3 @@ -574,7 +578,7 @@ static void build_config(struct comp_data *cd, struct module_config *cfg) /* Build default coefficient array (unity Q10 on diagonal, i.e. pass-through mode) */ memset(&cd->coeffs_config, 0, sizeof(cd->coeffs_config)); for (i = 0; i < MIN(SEL_SOURCE_CHANNELS_MAX, SEL_SINK_CHANNELS_MAX); i++) - cd->coeffs_config.coeffs[i][i] = 1 << 10; + cd->coeffs_config.coeffs[i][i] = SEL_COEF_ONE_Q10; } static int selector_init(struct processing_module *mod) @@ -617,8 +621,8 @@ static int selector_init(struct processing_module *mod) if (!cd) return -ENOMEM; - cd->sel_ipc4_cfg.init_payload_fmt = payload_fmt; md->private = cd; + cd->sel_ipc4_cfg.init_payload_fmt = payload_fmt; if (payload_fmt == IPC4_SEL_INIT_PAYLOAD_BASE_WITH_EXT) { size_t size = sizeof(struct sof_selector_ipc4_pin_config); @@ -733,6 +737,7 @@ static int selector_free(struct processing_module *mod) comp_dbg(mod->dev, "entry"); + mod_free(mod, cd->multi_coeffs_config); mod_free(mod, cd); return 0; @@ -769,13 +774,51 @@ static int selector_set_config(struct processing_module *mod, uint32_t config_id size_t response_size) { struct comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + int n; if (config_id == IPC4_SELECTOR_COEFFS_CONFIG_ID) { - if (data_offset_size != sizeof(cd->coeffs_config)) + if (data_offset_size > SEL_MAX_CONFIG_BLOB_SIZE || + pos != MODULE_CFG_FRAGMENT_SINGLE) { + comp_err(dev, "Failure with size %u pos %u", data_offset_size, pos); return -EINVAL; + } - memcpy_s(&cd->coeffs_config, sizeof(cd->coeffs_config), fragment, data_offset_size); - return 0; + /* The size must be N times the coefficient vectors size of one channels + * up/down mix profile. + */ + n = data_offset_size / sizeof(struct ipc4_selector_coeffs_config); + if (n < 1 || data_offset_size != n * sizeof(struct ipc4_selector_coeffs_config)) { + comp_err(dev, "Invalid configuration size."); + return -EINVAL; + } + + cd->num_configs = n; + if (cd->multi_coeffs_config) { + if (cd->multi_coeffs_config_size < data_offset_size) { + /* Configuration exist but the allocation is too + * small to write over. + */ + mod_free(mod, cd->multi_coeffs_config); + cd->multi_coeffs_config_size = data_offset_size; + cd->multi_coeffs_config = + mod_alloc(mod, cd->multi_coeffs_config_size); + } + } else { + /* No existing configuration */ + cd->multi_coeffs_config_size = data_offset_size; + cd->multi_coeffs_config = mod_alloc(mod, cd->multi_coeffs_config_size); + } + + if (!cd->multi_coeffs_config) { + comp_err(dev, "Failed to allocate configuration blob."); + return -ENOMEM; + } + + /* Copy the configuration and notify for need to re-configure */ + cd->new_config = true; + return memcpy_s(cd->multi_coeffs_config, cd->multi_coeffs_config_size, + fragment, data_offset_size); } return -EINVAL; @@ -788,6 +831,111 @@ static int selector_get_config(struct processing_module *mod, uint32_t config_id return 0; } +/** + * \brief Loop the array of mix coefficients sets and find a set with matching channels + * in and out count. + * \param[in] cd Selector component data. + * \param[in] source_channels Number of channels in source. + * \param[in] sink_channels Number of channels in sink. + * + * \return Pointer to the matching ipc4_selector_coeffs_config if found, or NULL if + * no matching configuration exists. + */ +static struct ipc4_selector_coeffs_config *selector_config_array_search(struct comp_data *cd, + int source_channels, + int sink_channels) +{ + struct ipc4_selector_coeffs_config *found = NULL; + int i; + + for (i = 0; i < cd->num_configs; i++) { + if (cd->multi_coeffs_config[i].source_channels_count == source_channels && + cd->multi_coeffs_config[i].sink_channels_count == sink_channels) { + found = &cd->multi_coeffs_config[i]; + break; + } + } + + return found; +} + +/** + * \brief Get mix coefficients set from configuration blob with multiple coefficients sets. + * Also activate more efficient pass-through copy mode if the coefficients indicate 1:1 + * copy from source to sink. + * \param[in,out] mod Selector base module device. + * \param[in] source_channels Number of channels in source. + * \param[in] sink_channels Number of channels in sink. + * + * \return Error code. + */ +static int selector_find_coefficients(struct processing_module *mod) +{ + struct comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + struct ipc4_selector_coeffs_config *config; + uint32_t source_channels = cd->config.in_channels_count; + uint32_t sink_channels = cd->config.out_channels_count; + int16_t coef; + int ret, i, j; + + /* In set_config() the blob is copied to cd->multi_coeffs_config. A legacy blob contains a + * single set of mix coefficients without channels information. A new blob with multiple + * configurations has the source and sink channels count information. If there has been no + * set_config(), then the cd->coeffs_config has been initialized in set_selector_params() + * to mix with coefficients SEL_COEF_ONE_Q10 for matching input and output channels. + */ + if (cd->multi_coeffs_config) { + config = cd->multi_coeffs_config; + if (cd->num_configs > 1) { + config = selector_config_array_search(cd, source_channels, sink_channels); + /* If not found, check if pass-through mix is defined for the max + * channels count (8). + */ + if (!config && source_channels == sink_channels) + config = selector_config_array_search(cd, SEL_SOURCE_CHANNELS_MAX, + SEL_SINK_CHANNELS_MAX); + + if (!config) { + comp_err(dev, "No mix coefficients found for %d to %d channels.", + source_channels, sink_channels); + return -EINVAL; + } + } + + ret = memcpy_s(&cd->coeffs_config, sizeof(struct ipc4_selector_coeffs_config), + config, sizeof(*config)); + if (ret) + return ret; + } + + /* The pass-through copy function can be used if coefficients are a unit matrix for + * 1:1 stream copy. + */ + if (source_channels == sink_channels) { + cd->passthrough = true; + for (i = 0; i < sink_channels; i++) { + for (j = 0; j < source_channels; j++) { + coef = cd->coeffs_config.coeffs[i][j]; + if ((i == j && coef != SEL_COEF_ONE_Q10) || (i != j && coef != 0)) { + cd->passthrough = false; + break; + } + } + } + } else { + cd->passthrough = false; + } + + if (cd->passthrough) + comp_info(dev, "Passthrough mode."); + else + comp_info(dev, "Using coefficients for %d to %d channels.", + source_channels, sink_channels); + + return 0; +} + /** * \brief Copies and processes stream data. * \param[in,out] mod Selector base module device. @@ -799,11 +947,29 @@ static int selector_process(struct processing_module *mod, struct output_stream_buffer *output_buffers, int num_output_buffers) { + struct audio_stream *source; + struct audio_stream *sink; struct comp_data *cd = module_get_private_data(mod); uint32_t avail_frames = input_buffers[0].size; + int ret; comp_dbg(mod->dev, "entry"); + if (cd->new_config) { + cd->new_config = false; + ret = selector_find_coefficients(mod); + if (ret) + return ret; + } + + if (cd->passthrough) { + source = input_buffers->data; + sink = output_buffers->data; + audio_stream_copy(source, 0, sink, 0, avail_frames * cd->config.in_channels_count); + module_update_buffer_position(input_buffers, output_buffers, avail_frames); + return 0; + } + if (avail_frames) /* copy selected channels from in to out */ cd->sel_func(mod, input_buffers, output_buffers, avail_frames); @@ -850,17 +1016,7 @@ static int selector_prepare(struct processing_module *mod, /* get sink data format and period bytes */ cd->sink_format = audio_stream_get_frm_fmt(&sinkb->stream); cd->sink_period_bytes = audio_stream_period_bytes(&sinkb->stream, dev->frames); - - /* There is an assumption that sink component will report out - * proper number of channels [1] for selector to actually - * reduce channel count between source and sink - */ - comp_info(dev, "source sink channel = %u %u", - audio_stream_get_channels(&sourceb->stream), - audio_stream_get_channels(&sinkb->stream)); - sink_size = audio_stream_get_size(&sinkb->stream); - md->mpd.in_buff_size = cd->source_period_bytes; md->mpd.out_buff_size = cd->sink_period_bytes; @@ -891,6 +1047,11 @@ static int selector_prepare(struct processing_module *mod, return -EINVAL; } + if (cd->new_config) { + cd->new_config = false; + return selector_find_coefficients(mod); + } + return 0; } @@ -908,7 +1069,9 @@ static int selector_reset(struct processing_module *mod) cd->source_period_bytes = 0; cd->sink_period_bytes = 0; cd->sel_func = NULL; - + cd->num_configs = 0; + cd->passthrough = false; + cd->new_config = false; return 0; } diff --git a/src/audio/selector/tune/sof_selector_blobs.m b/src/audio/selector/tune/sof_selector_blobs.m index 83b38be64e3e..1b370d4030de 100644 --- a/src/audio/selector/tune/sof_selector_blobs.m +++ b/src/audio/selector/tune/sof_selector_blobs.m @@ -11,46 +11,59 @@ % SPDX-License-Identifier: BSD-3-Clause % -% Copyright (c) 2025, Intel Corporation. +% Copyright (c) 2025-2026, Intel Corporation. function sof_selector_blobs() % See ITU-R BS.775-4 for mix coefficient values sof_selector_paths(true); + % Values of enum ipc4_channel_config + IPC4_CHANNEL_CONFIG_MONO = 0; + IPC4_CHANNEL_CONFIG_STEREO = 1; + IPC4_CHANNEL_CONFIG_QUATRO = 5; + IPC4_CHANNEL_CONFIG_5_POINT_1 = 8; + IPC4_CHANNEL_CONFIG_7_POINT_1 = 12; + % Matrix for 1:1 pass-through - sel.rsvd0 = 0; - sel.rsvd1 = 0; + sel.ch_count = [8 8]; % Number of channels + sel.ch_config = [IPC4_CHANNEL_CONFIG_7_POINT_1 IPC4_CHANNEL_CONFIG_7_POINT_1]; sel.coeffs = diag(ones(8, 1)); - write_blob(sel, "passthrough"); + passthrough_pack8 = write_blob(sel, "passthrough"); % Stereo to mono downmix + sel.ch_count = [2 1]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_STEREO IPC4_CHANNEL_CONFIG_MONO]; sel.coeffs = zeros(8,8); sel.coeffs(1, 1) = 0.7071; sel.coeffs(1, 2) = 0.7071; - write_blob(sel, "downmix_stereo_to_mono"); + stereo_to_mono_pack8 = write_blob(sel, "downmix_stereo_to_mono"); % 5.1 to stereo downmix + sel.ch_count = [6 2]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_5_POINT_1 IPC4_CHANNEL_CONFIG_STEREO]; fl = 1; fr = 2; fc = 3; lfe = 4; sl = 5; sr = 6; m = zeros(8,8); m(1, fl) = 1.0000; m(1, fr) = 0.0000; m(1, fc) = 0.7071; m(1, sl) = 0.7071; m(1, sr) = 0.0000; m(2, fl) = 0.0000; m(2, fr) = 1.0000; m(2, fc) = 0.7071; m(2, sl) = 0.0000; m(2, sr) = 0.7071; sel.coeffs = m; - write_blob(sel, "downmix_51_to_stereo"); sel.coeffs(1, lfe) = 10^(+4/20); % +10 dB, attenuate by -6 dB to left sel.coeffs(2, lfe) = 10^(+4/20); % +10 dB, attenuate by -6 dB to right - write_blob(sel, "downmix_51_to_stereo_with_lfe"); + sixch_to_stereo_pack8 = write_blob(sel, "downmix_51_to_stereo_with_lfe"); % 5.1 to mono downmix + sel.ch_count = [6 1]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_5_POINT_1 IPC4_CHANNEL_CONFIG_MONO]; fl = 1; fr = 2; fc = 3; lfe = 4; sl = 5; sr = 6; m = zeros(8,8); m(1, fl) = 0.7071; m(1, fr) = 0.7071; m(1, fc) = 1.0000; m(1, sl) = 0.5000; m(1, sr) = 0.5000; sel.coeffs = m; - write_blob(sel, "downmix_51_to_mono"); sel.coeffs(1, lfe) = 10^(+10/20); - write_blob(sel, "downmix_51_to_mono_with_lfe"); + sixch_to_mono_pack8 = write_blob(sel, "downmix_51_to_mono_with_lfe"); % 7.1 to 5.1 downmix + sel.ch_count = [8 6]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_7_POINT_1 IPC4_CHANNEL_CONFIG_5_POINT_1]; fl8 = 1; fr8 = 2; fc8 = 3; lfe8 = 4; bl8 = 5; br8 = 6; sl8 = 7; sr8 = 8; fl6 = 1; fr6 = 2; fc6 = 3; lfe6 = 4; sl6 = 5; sr6 = 6; m = zeros(8,8); @@ -63,50 +76,69 @@ function sof_selector_blobs() m(sr6, br8) = 1; m(lfe6, lfe8) = 1; sel.coeffs = m; - write_blob(sel, "downmix_71_to_51"); + eightch_to_sixch_pack8 = write_blob(sel, "downmix_71_to_51"); - % 7.1 to 5.1 downmix + % 7.1 to stereo downmix + sel.ch_count = [8 2]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_7_POINT_1 IPC4_CHANNEL_CONFIG_STEREO]; fl = 1; fr = 2; fc = 3; lfe = 4; bl = 5; br = 6; sl = 7; sr = 8; m = zeros(8,8); m(1, fl) = 1.0000; m(1, fr) = 0.0000; m(1, fc) = 0.7071; m(1, sl) = 0.7071; m(1, sr) = 0.0000; m(1, bl) = 0.7071; m(1, br) = 0.0000; m(2, fl) = 0.0000; m(2, fr) = 1.0000; m(2, fc) = 0.7071; m(2, sl) = 0.0000; m(2, sr) = 0.7071; m(2, bl) = 0.0000; m(2, br) = 0.7071; sel.coeffs = m; - write_blob(sel, "downmix_71_to_stereo"); sel.coeffs(1, lfe) = 10^(+4/20); % +10 dB, attenuate by -6 dB to left sel.coeffs(2, lfe) = 10^(+4/20); % +10 dB, attenuate by -6 dB to right - write_blob(sel, "downmix_71_to_stereo_with_lfe"); + eightch_to_stereo_pack8 = write_blob(sel, "downmix_71_to_stereo_with_lfe"); % 7.1 to mono downmix + sel.ch_count = [8 1]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_7_POINT_1 IPC4_CHANNEL_CONFIG_MONO]; fl = 1; fc = 3; fr = 2; sr = 8; br = 6; bl = 5; sl = 7; lfe = 4; m = zeros(8,8); m(1, fl) = 0.7071; m(1, fr) = 0.7071; m(1, fc) = 1.0000; m(1, sl) = 0.5000; m(1, sr) = 0.5000; m(1, bl) = 0.5000; m(1, br) = 0.5000; sel.coeffs = m; - write_blob(sel, "downmix_71_to_mono"); m(1, lfe) = 10^(+19/20); % +10 dB - write_blob(sel, "downmix_71_to_mono_with_lfe"); + eightch_to_mono_pack8 = write_blob(sel, "downmix_71_to_mono_with_lfe"); % mono to stereo upmix + sel.ch_count = [1 2]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_MONO IPC4_CHANNEL_CONFIG_STEREO]; sel.coeffs = zeros(8,8); sel.coeffs(1, 1) = 10^(-3/20); sel.coeffs(2, 1) = 10^(-3/20); - write_blob(sel, "upmix_mono_to_stereo"); + mono_to_stereo_pack8 = write_blob(sel, "upmix_mono_to_stereo"); % mono to 5.1 / 7.1 upmix - fc = 3 + sel.ch_count = [1 6]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_MONO IPC4_CHANNEL_CONFIG_5_POINT_1]; + fc = 3; sel.coeffs = zeros(8,8); sel.coeffs(fc, 1) = 1; - write_blob(sel, "upmix_mono_to_51"); - write_blob(sel, "upmix_mono_to_71"); + mono_to_sixch_pack8 = write_blob(sel, "upmix_mono_to_51"); + sel.ch_count = [1 8]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_MONO IPC4_CHANNEL_CONFIG_7_POINT_1]; + mono_to_eightch_pack8 = write_blob(sel, "upmix_mono_to_71"); % stereo to 5.1 / 7.1 upmix + sel.ch_count = [2 6]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_STEREO IPC4_CHANNEL_CONFIG_5_POINT_1]; fl = 1; fr = 2; sel.coeffs = zeros(8,8); sel.coeffs(fl, 1) = 1; sel.coeffs(fr, 2) = 1; - write_blob(sel, "upmix_stereo_to_51"); - write_blob(sel, "upmix_stereo_to_71"); + stereo_to_sixch_pack8 = write_blob(sel, "upmix_stereo_to_51"); + sel.ch_count = [2 8]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_STEREO IPC4_CHANNEL_CONFIG_7_POINT_1]; + stereo_to_eightch_pack8 = write_blob(sel, "upmix_stereo_to_71"); + + % For blob format with multiple up/down-mix profiles, intended + % for playback decoder offload conversions. + multi_pack8 = [passthrough_pack8 mono_to_stereo_pack8 sixch_to_stereo_pack8 eightch_to_stereo_pack8]; + write_8bit_packed(multi_pack8, 'stereo_endpoint_playback_updownmix'); % Stereo to L,L,R,R + sel.ch_count = [2 4]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_STEREO IPC4_CHANNEL_CONFIG_QUATRO]; sel.coeffs = [ 1 0 0 0 0 0 0 0 ; ... 1 0 0 0 0 0 0 0 ; ... 0 1 0 0 0 0 0 0 ; ... @@ -118,6 +150,8 @@ function sof_selector_blobs() write_blob(sel, "xover_selector_lr_to_llrr"); % Stereo to R,R,L,L + sel.ch_count = [2 4]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_STEREO IPC4_CHANNEL_CONFIG_QUATRO]; sel.coeffs = [ 0 1 0 0 0 0 0 0 ; ... 0 1 0 0 0 0 0 0 ; ... 1 0 0 0 0 0 0 0 ; ... @@ -129,6 +163,8 @@ function sof_selector_blobs() write_blob(sel, "xover_selector_lr_to_rrll"); % Stereo to L,R,L,R + sel.ch_count = [2 4]; + sel.ch_config = [IPC4_CHANNEL_CONFIG_STEREO IPC4_CHANNEL_CONFIG_QUATRO]; sel.coeffs = [ 1 0 0 0 0 0 0 0 ; ... 0 1 0 0 0 0 0 0 ; ... 1 0 0 0 0 0 0 0 ; ... @@ -142,32 +178,55 @@ function sof_selector_blobs() sof_selector_paths(false); end -function write_blob(sel, blobname) +function pack8 = write_blob(sel, blobname) + pack8 = pack_selector_config(sel); + pack8_copy = pack8; + pack8_copy(1:4) = uint8([0 0 0 0]); + write_8bit_packed(pack8_copy, blobname); +end + +function write_8bit_packed(pack8, blobname) + blob8 = sof_selector_build_blob(pack8); str_config = "selector_config"; str_exported = "Exported with script sof_selector_blobs.m"; - str_howto = "cd tools/tune/selector; octave sof_selector_blobs.m" + str_howto = "cd tools/tune/selector; octave sof_selector_blobs.m"; sof_tools = '../../../../tools'; sof_tplg = fullfile(sof_tools, 'topology'); sof_tplg_selector = fullfile(sof_tplg, 'topology2/include/components/micsel'); + tplg2_fn = sprintf("%s/%s.conf", sof_tplg_selector, blobname); + sof_check_create_dir(tplg2_fn); + sof_tplg2_write(tplg2_fn, blob8, str_config, str_exported, str_howto); +end - sel +function pack8 = pack_selector_config(sel) - sum_coefs = sum(sel.coeffs, 2)' - max_sum_coef = max(sum_coefs) + sum_coefs = sum(sel.coeffs, 2)'; + max_sum_coef = max(sum_coefs); if max_sum_coef > 1 scale = 1 / max_sum_coef; else scale = 1; end - scale sel.coeffs = scale .* sel.coeffs'; + coeffs_vec = reshape(sel.coeffs, 1, []); % convert to row vector + coeffs_q10 = int16(round(coeffs_vec .* 1024)); % Q6.10 + pack8 = uint8(zeros(1, 2 * length(coeffs_q10) + 4)); - blob8 = sof_selector_build_blob(sel); - tplg2_fn = sprintf("%s/%s.conf", sof_tplg_selector, blobname); - sof_check_create_dir(tplg2_fn); - sof_tplg2_write(tplg2_fn, blob8, str_config, str_exported, str_howto); -end + % header + j = 1; + pack8(j:j + 1) = uint8(sel.ch_count); + j = j + 2; + pack8(j:j + 1) = uint8(sel.ch_config); + j = j + 2; + + % coeffs matrix + for i = 1:length(coeffs_q10) + pack8(j:j+1) = int16_to_byte(coeffs_q10(i)); + j = j + 2; + end + + end function sof_selector_paths(enable) @@ -179,15 +238,11 @@ function sof_selector_paths(enable) end end -function blob8 = sof_selector_build_blob(sel) +function blob8 = sof_selector_build_blob(pack8) - s = size(sel.coeffs); blob_type = 0; blob_param_id = 0; % IPC4_SELECTOR_COEFFS_CONFIG_ID - data_length = s(1) * s(2) + 2; - data_size = 2 * data_length; % int16_t matrix - coeffs_vec = reshape(sel.coeffs, 1, []); % convert to row vector - coeffs_q10 = int16(round(coeffs_vec .* 1024)); % Q6.10 + data_size = length(pack8); ipc_ver = 4; [abi_bytes, abi_size] = sof_get_abi(data_size, ipc_ver, blob_type, blob_param_id); blob_size = data_size + abi_size; @@ -195,17 +250,7 @@ function sof_selector_paths(enable) blob8(1:abi_size) = abi_bytes; j = abi_size + 1; - % header - blob8(j:j+1) = int16_to_byte(int16(sel.rsvd0)); - j = j + 2; - blob8(j:j+1) = int16_to_byte(int16(sel.rsvd1)); - j = j + 2; - - % coeffs matrix - for i = 1:(s(1) * s(2)) - blob8(j:j+1) = int16_to_byte(coeffs_q10(i)); - j = j + 2; - end + blob8(j:j+data_size-1) = pack8; end function bytes = int16_to_byte(word) diff --git a/src/include/sof/audio/selector.h b/src/include/sof/audio/selector.h index cd4aa926c7f4..e977a47af9a9 100644 --- a/src/include/sof/audio/selector.h +++ b/src/include/sof/audio/selector.h @@ -27,6 +27,9 @@ struct comp_buffer; struct comp_dev; +/** \brief Default mix gain. */ +#define SEL_COEF_ONE_Q10 1024 /* int16(1 * 2^10) */ + #if CONFIG_IPC_MAJOR_3 /** \brief Supported channel count on input. */ #define SEL_SOURCE_2CH 2 @@ -43,6 +46,9 @@ struct comp_dev; /** \brief Maximum supported channel count on output. */ #define SEL_SINK_CHANNELS_MAX 8 +/** \brief Maximum number of configurations in the blob received with set_config() */ +#define SEL_MAX_NUM_CONFIGS 8 + #define SEL_NUM_IN_PIN_FMTS 1 #define SEL_NUM_OUT_PIN_FMTS 1 @@ -60,8 +66,10 @@ enum ipc4_selector_config_id { /** \brief IPC4 mixing coefficients configuration. */ struct ipc4_selector_coeffs_config { - uint16_t rsvd0; /**< Unused field, keeps the structure aligned with common layout */ - uint16_t rsvd1; /**< Unused field, keeps the structure aligned with common layout */ + uint8_t source_channels_count; /**< Used when multiple profiles are packed into one blob. */ + uint8_t sink_channels_count; /**< Used when multiple profiles are packed into one blob. */ + uint8_t source_channel_config; /**< Used when multiple profiles are packed into one blob. */ + uint8_t sink_channel_config; /**< Used when multiple profiles are packed into one blob. */ /** Mixing coefficients in Q10 fixed point format */ int16_t coeffs[SEL_SINK_CHANNELS_MAX][SEL_SOURCE_CHANNELS_MAX]; @@ -109,6 +117,8 @@ struct comp_data { #if CONFIG_IPC_MAJOR_4 struct sof_selector_ipc4_config sel_ipc4_cfg; struct ipc4_selector_coeffs_config coeffs_config; + struct ipc4_selector_coeffs_config *multi_coeffs_config; + size_t multi_coeffs_config_size; #endif uint32_t source_period_bytes; /**< source number of period bytes */ @@ -117,6 +127,9 @@ struct comp_data { enum sof_ipc_frame sink_format; /**< sink frame format */ struct sof_sel_config config; /**< component configuration data */ sel_func sel_func; /**< channel selector processing function */ + int num_configs; /**< Number of coefficients sets in configuration blob. */ + bool passthrough; /**< Use a passthrough copy function when no up/down mix. */ + bool new_config; /**< True if new configuration has been received */ }; /** \brief Selector processing functions map. */ diff --git a/tools/topology/topology2/include/components/micsel/downmix_51_to_mono.conf b/tools/topology/topology2/include/components/micsel/downmix_51_to_mono.conf deleted file mode 100644 index cd1f65b86454..000000000000 --- a/tools/topology/topology2/include/components/micsel/downmix_51_to_mono.conf +++ /dev/null @@ -1,26 +0,0 @@ -# Exported with script sof_selector_blobs.m 04-Jun-2025 -# cd tools/tune/selector; octave sof_selector_blobs.m -Object.Base.data."selector_config" { - bytes " - 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, - 0x84,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0xd4,0x00,0xd4,0x00, - 0x2c,0x01,0x00,0x00,0x96,0x00,0x96,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00" -} diff --git a/tools/topology/topology2/include/components/micsel/downmix_51_to_stereo.conf b/tools/topology/topology2/include/components/micsel/downmix_51_to_stereo.conf deleted file mode 100644 index 3f7b32a251d8..000000000000 --- a/tools/topology/topology2/include/components/micsel/downmix_51_to_stereo.conf +++ /dev/null @@ -1,26 +0,0 @@ -# Exported with script sof_selector_blobs.m 04-Jun-2025 -# cd tools/tune/selector; octave sof_selector_blobs.m -Object.Base.data."selector_config" { - bytes " - 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, - 0x84,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0xa8,0x01,0x00,0x00, - 0x2c,0x01,0x00,0x00,0x2c,0x01,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x01, - 0x2c,0x01,0x00,0x00,0x00,0x00,0x2c,0x01, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00" -} diff --git a/tools/topology/topology2/include/components/micsel/downmix_71_to_mono.conf b/tools/topology/topology2/include/components/micsel/downmix_71_to_mono.conf deleted file mode 100644 index 1e67d36bf839..000000000000 --- a/tools/topology/topology2/include/components/micsel/downmix_71_to_mono.conf +++ /dev/null @@ -1,26 +0,0 @@ -# Exported with script sof_selector_blobs.m 04-Jun-2025 -# cd tools/tune/selector; octave sof_selector_blobs.m -Object.Base.data."selector_config" { - bytes " - 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, - 0x84,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0xa4,0x00,0xa4,0x00, - 0xe8,0x00,0x00,0x00,0x74,0x00,0x74,0x00, - 0x74,0x00,0x74,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00" -} diff --git a/tools/topology/topology2/include/components/micsel/downmix_71_to_stereo.conf b/tools/topology/topology2/include/components/micsel/downmix_71_to_stereo.conf deleted file mode 100644 index df6af38dde34..000000000000 --- a/tools/topology/topology2/include/components/micsel/downmix_71_to_stereo.conf +++ /dev/null @@ -1,26 +0,0 @@ -# Exported with script sof_selector_blobs.m 04-Jun-2025 -# cd tools/tune/selector; octave sof_selector_blobs.m -Object.Base.data."selector_config" { - bytes " - 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, - 0x84,0x00,0x00,0x00,0x01,0xd0,0x01,0x03, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x48,0x01,0x00,0x00, - 0xe8,0x00,0x00,0x00,0xe8,0x00,0x00,0x00, - 0xe8,0x00,0x00,0x00,0x00,0x00,0x48,0x01, - 0xe8,0x00,0x00,0x00,0x00,0x00,0xe8,0x00, - 0x00,0x00,0xe8,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00" -} diff --git a/tools/topology/topology2/include/components/micsel/stereo_endpoint_playback_updownmix.conf b/tools/topology/topology2/include/components/micsel/stereo_endpoint_playback_updownmix.conf new file mode 100644 index 000000000000..70500ef0e0fa --- /dev/null +++ b/tools/topology/topology2/include/components/micsel/stereo_endpoint_playback_updownmix.conf @@ -0,0 +1,75 @@ +# Exported with script sof_selector_blobs.m 10-Mar-2026 +# cd tools/tune/selector; octave sof_selector_blobs.m +Object.Base.data."selector_config" { + bytes " + 0x53,0x4f,0x46,0x34,0x00,0x00,0x00,0x00, + 0x10,0x02,0x00,0x00,0x01,0xd0,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x08,0x08,0x0c,0x0c,0x00,0x04,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x04,0x01,0x02,0x00,0x01, + 0xd5,0x02,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xd5,0x02,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x06,0x02,0x08,0x01,0x00,0x01,0x00,0x00, + 0xb5,0x00,0x96,0x01,0xb5,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, + 0xb5,0x00,0x96,0x01,0x00,0x00,0xb5,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x08,0x02,0x0c,0x01, + 0xda,0x00,0x00,0x00,0x9a,0x00,0x59,0x01, + 0x9a,0x00,0x00,0x00,0x9a,0x00,0x00,0x00, + 0x00,0x00,0xda,0x00,0x9a,0x00,0x59,0x01, + 0x00,0x00,0x9a,0x00,0x00,0x00,0x9a,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00" +}