Skip to content

Commit 01532fc

Browse files
committed
Audio: Selector: Tune: Add blob with all up/down-mix profiles
This patch modifies the configuration blobs build script sof_selector_blobs.m to create one blob that contains several of them for the purpose to up or down-mix DSP offloaded decoder output. The blob uses the reserved fields of selector configuration to describe source and sink channel counts and channel config values. The exported blob is "stereo_endpoint_playback_updownmix.conf". The single configuration blobs continue to be with the reserved fields as zeros. The .conf blobs may be removed later when other topologies are modified to not use them. Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
1 parent 064f411 commit 01532fc

File tree

1 file changed

+96
-49
lines changed

1 file changed

+96
-49
lines changed

src/audio/selector/tune/sof_selector_blobs.m

Lines changed: 96 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -11,46 +11,60 @@
1111

1212
% SPDX-License-Identifier: BSD-3-Clause
1313
%
14-
% Copyright (c) 2025, Intel Corporation.
14+
% Copyright (c) 2025-2026, Intel Corporation.
1515

1616
function sof_selector_blobs()
1717

1818
% See ITU-R BS.775-4 for mix coefficient values
1919
sof_selector_paths(true);
2020

21+
% Values of enum ipc4_channel_config
22+
IPC4_CHANNEL_CONFIG_MONO = 0;
23+
IPC4_CHANNEL_CONFIG_STEREO = 1;
24+
IPC4_CHANNEL_CONFIG_QUATRO = 5;
25+
IPC4_CHANNEL_CONFIG_5_POINT_1 = 8;
26+
IPC4_CHANNEL_CONFIG_7_POINT_1 = 12;
27+
2128
% Matrix for 1:1 pass-through
22-
sel.rsvd0 = 0;
23-
sel.rsvd1 = 0;
29+
sel.ch_count = [8 8]; % Number of channels
30+
sel.ch_config = [IPC4_CHANNEL_CONFIG_7_POINT_1 IPC4_CHANNEL_CONFIG_7_POINT_1];
31+
sel.ch_out = 8;
2432
sel.coeffs = diag(ones(8, 1));
25-
write_blob(sel, "passthrough");
33+
passthrough_pack8 = write_blob(sel, "passthrough");
2634

2735
% Stereo to mono downmix
36+
sel.ch_count = [2 1];
37+
sel.ch_config = [IPC4_CHANNEL_CONFIG_STEREO IPC4_CHANNEL_CONFIG_MONO];
2838
sel.coeffs = zeros(8,8);
2939
sel.coeffs(1, 1) = 0.7071;
3040
sel.coeffs(1, 2) = 0.7071;
31-
write_blob(sel, "downmix_stereo_to_mono");
41+
stereo_to_mono_pack8 = write_blob(sel, "downmix_stereo_to_mono");
3242

3343
% 5.1 to stereo downmix
44+
sel.ch_count = [6 2];
45+
sel.ch_config = [IPC4_CHANNEL_CONFIG_5_POINT_1 IPC4_CHANNEL_CONFIG_STEREO];
3446
fl = 1; fr = 2; fc = 3; lfe = 4; sl = 5; sr = 6;
3547
m = zeros(8,8);
3648
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;
3749
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;
3850
sel.coeffs = m;
39-
write_blob(sel, "downmix_51_to_stereo");
4051
sel.coeffs(1, lfe) = 10^(+4/20); % +10 dB, attenuate by -6 dB to left
4152
sel.coeffs(2, lfe) = 10^(+4/20); % +10 dB, attenuate by -6 dB to right
42-
write_blob(sel, "downmix_51_to_stereo_with_lfe");
53+
sixch_to_stereo_pack8 = write_blob(sel, "downmix_51_to_stereo_with_lfe");
4354

4455
% 5.1 to mono downmix
56+
sel.ch_count = [6 1];
57+
sel.ch_config = [IPC4_CHANNEL_CONFIG_5_POINT_1 IPC4_CHANNEL_CONFIG_MONO];
4558
fl = 1; fr = 2; fc = 3; lfe = 4; sl = 5; sr = 6;
4659
m = zeros(8,8);
4760
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;
4861
sel.coeffs = m;
49-
write_blob(sel, "downmix_51_to_mono");
5062
sel.coeffs(1, lfe) = 10^(+10/20);
51-
write_blob(sel, "downmix_51_to_mono_with_lfe");
63+
sixch_to_mono_pack8 = write_blob(sel, "downmix_51_to_mono_with_lfe");
5264

5365
% 7.1 to 5.1 downmix
66+
sel.ch_count = [8 6];
67+
sel.ch_config = [IPC4_CHANNEL_CONFIG_7_POINT_1 IPC4_CHANNEL_CONFIG_5_POINT_1];
5468
fl8 = 1; fr8 = 2; fc8 = 3; lfe8 = 4; bl8 = 5; br8 = 6; sl8 = 7; sr8 = 8;
5569
fl6 = 1; fr6 = 2; fc6 = 3; lfe6 = 4; sl6 = 5; sr6 = 6;
5670
m = zeros(8,8);
@@ -63,50 +77,69 @@ function sof_selector_blobs()
6377
m(sr6, br8) = 1;
6478
m(lfe6, lfe8) = 1;
6579
sel.coeffs = m;
66-
write_blob(sel, "downmix_71_to_51");
80+
eightch_to_sixch_pack8 = write_blob(sel, "downmix_71_to_51");
6781

68-
% 7.1 to 5.1 downmix
82+
% 7.1 to stereo downmix
83+
sel.ch_count = [8 2];
84+
sel.ch_config = [IPC4_CHANNEL_CONFIG_7_POINT_1 IPC4_CHANNEL_CONFIG_STEREO];
6985
fl = 1; fr = 2; fc = 3; lfe = 4; bl = 5; br = 6; sl = 7; sr = 8;
7086
m = zeros(8,8);
7187
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;
7288
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;
7389
sel.coeffs = m;
74-
write_blob(sel, "downmix_71_to_stereo");
7590
sel.coeffs(1, lfe) = 10^(+4/20); % +10 dB, attenuate by -6 dB to left
7691
sel.coeffs(2, lfe) = 10^(+4/20); % +10 dB, attenuate by -6 dB to right
77-
write_blob(sel, "downmix_71_to_stereo_with_lfe");
92+
eightch_to_stereo_pack8 = write_blob(sel, "downmix_71_to_stereo_with_lfe");
7893

7994
% 7.1 to mono downmix
95+
sel.ch_count = [8 1];
96+
sel.ch_config = [IPC4_CHANNEL_CONFIG_7_POINT_1 IPC4_CHANNEL_CONFIG_MONO];
8097
fl = 1; fc = 3; fr = 2; sr = 8; br = 6; bl = 5; sl = 7; lfe = 4;
8198
m = zeros(8,8);
8299
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;
83100
sel.coeffs = m;
84-
write_blob(sel, "downmix_71_to_mono");
85101
m(1, lfe) = 10^(+19/20); % +10 dB
86-
write_blob(sel, "downmix_71_to_mono_with_lfe");
102+
eightch_to_mono_pack8 = write_blob(sel, "downmix_71_to_mono_with_lfe");
87103

88104
% mono to stereo upmix
105+
sel.ch_count = [1 2];
106+
sel.ch_config = [IPC4_CHANNEL_CONFIG_MONO IPC4_CHANNEL_CONFIG_STEREO];
89107
sel.coeffs = zeros(8,8);
90108
sel.coeffs(1, 1) = 10^(-3/20);
91109
sel.coeffs(2, 1) = 10^(-3/20);
92-
write_blob(sel, "upmix_mono_to_stereo");
110+
mono_to_stereo_pack8 = write_blob(sel, "upmix_mono_to_stereo");
93111

94112
% mono to 5.1 / 7.1 upmix
95-
fc = 3
113+
sel.ch_count = [1 6];
114+
sel.ch_config = [IPC4_CHANNEL_CONFIG_MONO IPC4_CHANNEL_CONFIG_5_POINT_1];
115+
fc = 3;
96116
sel.coeffs = zeros(8,8);
97117
sel.coeffs(fc, 1) = 1;
98-
write_blob(sel, "upmix_mono_to_51");
99-
write_blob(sel, "upmix_mono_to_71");
118+
mono_to_sixch_pack8 = write_blob(sel, "upmix_mono_to_51");
119+
sel.ch_count = [1 8];
120+
sel.ch_config = [IPC4_CHANNEL_CONFIG_MONO IPC4_CHANNEL_CONFIG_7_POINT_1];
121+
mono_to_eightch_pack8 = write_blob(sel, "upmix_mono_to_71");
100122

101123
% stereo to 5.1 / 7.1 upmix
124+
sel.ch_count = [2 6];
125+
sel.ch_config = [IPC4_CHANNEL_CONFIG_STEREO IPC4_CHANNEL_CONFIG_5_POINT_1];
102126
fl = 1; fr = 2;
103127
sel.coeffs = zeros(8,8);
104128
sel.coeffs(fl, 1) = 1;
105129
sel.coeffs(fr, 2) = 1;
106-
write_blob(sel, "upmix_stereo_to_51");
107-
write_blob(sel, "upmix_stereo_to_71");
130+
stereo_to_sixch_pack8 = write_blob(sel, "upmix_stereo_to_51");
131+
sel.ch_count = [2 8];
132+
sel.ch_config = [IPC4_CHANNEL_CONFIG_STEREO IPC4_CHANNEL_CONFIG_7_POINT_1];
133+
stereo_to_eightch_pack8 = write_blob(sel, "upmix_stereo_to_71");
134+
135+
% For blob format with multiple up/down-mix profiles, intended
136+
% for playback decoder offload conversions.
137+
multi_pack8 = [passthrough_pack8 mono_to_stereo_pack8 sixch_to_stereo_pack8 eightch_to_stereo_pack8];
138+
write_8bit_packed(multi_pack8, 'stereo_endpoint_playback_updownmix');
108139

109140
% Stereo to L,L,R,R
141+
sel.ch_count = [2 4];
142+
sel.ch_config = [IPC4_CHANNEL_CONFIG_STEREO IPC4_CHANNEL_CONFIG_QUATRO];
110143
sel.coeffs = [ 1 0 0 0 0 0 0 0 ; ...
111144
1 0 0 0 0 0 0 0 ; ...
112145
0 1 0 0 0 0 0 0 ; ...
@@ -118,6 +151,8 @@ function sof_selector_blobs()
118151
write_blob(sel, "xover_selector_lr_to_llrr");
119152

120153
% Stereo to R,R,L,L
154+
sel.ch_count = [2 4];
155+
sel.ch_config = [IPC4_CHANNEL_CONFIG_STEREO IPC4_CHANNEL_CONFIG_QUATRO];
121156
sel.coeffs = [ 0 1 0 0 0 0 0 0 ; ...
122157
0 1 0 0 0 0 0 0 ; ...
123158
1 0 0 0 0 0 0 0 ; ...
@@ -129,6 +164,8 @@ function sof_selector_blobs()
129164
write_blob(sel, "xover_selector_lr_to_rrll");
130165

131166
% Stereo to L,R,L,R
167+
sel.ch_count = [2 4];
168+
sel.ch_config = [IPC4_CHANNEL_CONFIG_STEREO IPC4_CHANNEL_CONFIG_QUATRO];
132169
sel.coeffs = [ 1 0 0 0 0 0 0 0 ; ...
133170
0 1 0 0 0 0 0 0 ; ...
134171
1 0 0 0 0 0 0 0 ; ...
@@ -142,32 +179,56 @@ function sof_selector_blobs()
142179
sof_selector_paths(false);
143180
end
144181

145-
function write_blob(sel, blobname)
182+
function pack8 = write_blob(sel, blobname)
183+
pack8 = pack_selector_config(sel);
184+
pack8_copy = pack8;
185+
pack8_copy(1:4) = uint8([0 0 0 0]);
186+
write_8bit_packed(pack8_copy, blobname);
187+
end
188+
189+
function write_8bit_packed(pack8, blobname)
190+
blob8 = sof_selector_build_blob(pack8);
146191
str_config = "selector_config";
147192
str_exported = "Exported with script sof_selector_blobs.m";
148-
str_howto = "cd tools/tune/selector; octave sof_selector_blobs.m"
193+
str_howto = "cd tools/tune/selector; octave sof_selector_blobs.m";
149194
sof_tools = '../../../../tools';
150195
sof_tplg = fullfile(sof_tools, 'topology');
151196
sof_tplg_selector = fullfile(sof_tplg, 'topology2/include/components/micsel');
197+
tplg2_fn = sprintf("%s/%s.conf", sof_tplg_selector, blobname);
198+
sof_check_create_dir(tplg2_fn);
199+
sof_tplg2_write(tplg2_fn, blob8, str_config, str_exported, str_howto);
200+
end
152201

153-
sel
202+
function pack8 = pack_selector_config(sel)
154203

155-
sum_coefs = sum(sel.coeffs, 2)'
156-
max_sum_coef = max(sum_coefs)
204+
sum_coefs = sum(sel.coeffs, 2)';
205+
max_sum_coef = max(sum_coefs);
157206
if max_sum_coef > 1
158207
scale = 1 / max_sum_coef;
159208
else
160209
scale = 1;
161210
end
162211

163-
scale
164212
sel.coeffs = scale .* sel.coeffs';
213+
coeffs_vec = reshape(sel.coeffs, 1, []); % convert to row vector
214+
coeffs_q10 = int16(round(coeffs_vec .* 1024)); % Q6.10
215+
pack8 = uint8(2 * length(coeffs_q10) + 4);
216+
rsvd1 = 0;
165217

166-
blob8 = sof_selector_build_blob(sel);
167-
tplg2_fn = sprintf("%s/%s.conf", sof_tplg_selector, blobname);
168-
sof_check_create_dir(tplg2_fn);
169-
sof_tplg2_write(tplg2_fn, blob8, str_config, str_exported, str_howto);
170-
end
218+
% header
219+
j = 1;
220+
pack8(j:j + 1) = uint8(sel.ch_count);
221+
j = j + 2;
222+
pack8(j:j + 1) = uint8(sel.ch_config);
223+
j = j + 2;
224+
225+
% coeffs matrix
226+
for i = 1:length(coeffs_q10)
227+
pack8(j:j+1) = int16_to_byte(coeffs_q10(i));
228+
j = j + 2;
229+
end
230+
231+
end
171232

172233
function sof_selector_paths(enable)
173234

@@ -179,33 +240,19 @@ function sof_selector_paths(enable)
179240
end
180241
end
181242

182-
function blob8 = sof_selector_build_blob(sel)
243+
function blob8 = sof_selector_build_blob(pack8)
183244

184-
s = size(sel.coeffs);
185245
blob_type = 0;
186246
blob_param_id = 0; % IPC4_SELECTOR_COEFFS_CONFIG_ID
187-
data_length = s(1) * s(2) + 2;
188-
data_size = 2 * data_length; % int16_t matrix
189-
coeffs_vec = reshape(sel.coeffs, 1, []); % convert to row vector
190-
coeffs_q10 = int16(round(coeffs_vec .* 1024)); % Q6.10
247+
data_size = length(pack8);
191248
ipc_ver = 4;
192249
[abi_bytes, abi_size] = sof_get_abi(data_size, ipc_ver, blob_type, blob_param_id);
193250
blob_size = data_size + abi_size;
194251
blob8 = uint8(zeros(1, blob_size));
195252
blob8(1:abi_size) = abi_bytes;
196253
j = abi_size + 1;
197254

198-
% header
199-
blob8(j:j+1) = int16_to_byte(int16(sel.rsvd0));
200-
j = j + 2;
201-
blob8(j:j+1) = int16_to_byte(int16(sel.rsvd1));
202-
j = j + 2;
203-
204-
% coeffs matrix
205-
for i = 1:(s(1) * s(2))
206-
blob8(j:j+1) = int16_to_byte(coeffs_q10(i));
207-
j = j + 2;
208-
end
255+
blob8(j:j+data_size-1) = pack8;
209256
end
210257

211258
function bytes = int16_to_byte(word)

0 commit comments

Comments
 (0)