Skip to content

Commit 473cb8b

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 866e3c0 commit 473cb8b

1 file changed

Lines changed: 94 additions & 49 deletions

File tree

src/audio/selector/tune/sof_selector_blobs.m

Lines changed: 94 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -11,46 +11,59 @@
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];
2431
sel.coeffs = diag(ones(8, 1));
25-
write_blob(sel, "passthrough");
32+
passthrough_pack8 = write_blob(sel, "passthrough");
2633

2734
% Stereo to mono downmix
35+
sel.ch_count = [2 1];
36+
sel.ch_config = [IPC4_CHANNEL_CONFIG_STEREO IPC4_CHANNEL_CONFIG_MONO];
2837
sel.coeffs = zeros(8,8);
2938
sel.coeffs(1, 1) = 0.7071;
3039
sel.coeffs(1, 2) = 0.7071;
31-
write_blob(sel, "downmix_stereo_to_mono");
40+
stereo_to_mono_pack8 = write_blob(sel, "downmix_stereo_to_mono");
3241

3342
% 5.1 to stereo downmix
43+
sel.ch_count = [6 2];
44+
sel.ch_config = [IPC4_CHANNEL_CONFIG_5_POINT_1 IPC4_CHANNEL_CONFIG_STEREO];
3445
fl = 1; fr = 2; fc = 3; lfe = 4; sl = 5; sr = 6;
3546
m = zeros(8,8);
3647
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;
3748
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;
3849
sel.coeffs = m;
39-
write_blob(sel, "downmix_51_to_stereo");
4050
sel.coeffs(1, lfe) = 10^(+4/20); % +10 dB, attenuate by -6 dB to left
4151
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");
52+
sixch_to_stereo_pack8 = write_blob(sel, "downmix_51_to_stereo_with_lfe");
4353

4454
% 5.1 to mono downmix
55+
sel.ch_count = [6 1];
56+
sel.ch_config = [IPC4_CHANNEL_CONFIG_5_POINT_1 IPC4_CHANNEL_CONFIG_MONO];
4557
fl = 1; fr = 2; fc = 3; lfe = 4; sl = 5; sr = 6;
4658
m = zeros(8,8);
4759
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;
4860
sel.coeffs = m;
49-
write_blob(sel, "downmix_51_to_mono");
5061
sel.coeffs(1, lfe) = 10^(+10/20);
51-
write_blob(sel, "downmix_51_to_mono_with_lfe");
62+
sixch_to_mono_pack8 = write_blob(sel, "downmix_51_to_mono_with_lfe");
5263

5364
% 7.1 to 5.1 downmix
65+
sel.ch_count = [8 6];
66+
sel.ch_config = [IPC4_CHANNEL_CONFIG_7_POINT_1 IPC4_CHANNEL_CONFIG_5_POINT_1];
5467
fl8 = 1; fr8 = 2; fc8 = 3; lfe8 = 4; bl8 = 5; br8 = 6; sl8 = 7; sr8 = 8;
5568
fl6 = 1; fr6 = 2; fc6 = 3; lfe6 = 4; sl6 = 5; sr6 = 6;
5669
m = zeros(8,8);
@@ -63,50 +76,69 @@ function sof_selector_blobs()
6376
m(sr6, br8) = 1;
6477
m(lfe6, lfe8) = 1;
6578
sel.coeffs = m;
66-
write_blob(sel, "downmix_71_to_51");
79+
eightch_to_sixch_pack8 = write_blob(sel, "downmix_71_to_51");
6780

68-
% 7.1 to 5.1 downmix
81+
% 7.1 to stereo downmix
82+
sel.ch_count = [8 2];
83+
sel.ch_config = [IPC4_CHANNEL_CONFIG_7_POINT_1 IPC4_CHANNEL_CONFIG_STEREO];
6984
fl = 1; fr = 2; fc = 3; lfe = 4; bl = 5; br = 6; sl = 7; sr = 8;
7085
m = zeros(8,8);
7186
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;
7287
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;
7388
sel.coeffs = m;
74-
write_blob(sel, "downmix_71_to_stereo");
7589
sel.coeffs(1, lfe) = 10^(+4/20); % +10 dB, attenuate by -6 dB to left
7690
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");
91+
eightch_to_stereo_pack8 = write_blob(sel, "downmix_71_to_stereo_with_lfe");
7892

7993
% 7.1 to mono downmix
94+
sel.ch_count = [8 1];
95+
sel.ch_config = [IPC4_CHANNEL_CONFIG_7_POINT_1 IPC4_CHANNEL_CONFIG_MONO];
8096
fl = 1; fc = 3; fr = 2; sr = 8; br = 6; bl = 5; sl = 7; lfe = 4;
8197
m = zeros(8,8);
8298
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;
8399
sel.coeffs = m;
84-
write_blob(sel, "downmix_71_to_mono");
85100
m(1, lfe) = 10^(+19/20); % +10 dB
86-
write_blob(sel, "downmix_71_to_mono_with_lfe");
101+
eightch_to_mono_pack8 = write_blob(sel, "downmix_71_to_mono_with_lfe");
87102

88103
% mono to stereo upmix
104+
sel.ch_count = [1 2];
105+
sel.ch_config = [IPC4_CHANNEL_CONFIG_MONO IPC4_CHANNEL_CONFIG_STEREO];
89106
sel.coeffs = zeros(8,8);
90107
sel.coeffs(1, 1) = 10^(-3/20);
91108
sel.coeffs(2, 1) = 10^(-3/20);
92-
write_blob(sel, "upmix_mono_to_stereo");
109+
mono_to_stereo_pack8 = write_blob(sel, "upmix_mono_to_stereo");
93110

94111
% mono to 5.1 / 7.1 upmix
95-
fc = 3
112+
sel.ch_count = [1 6];
113+
sel.ch_config = [IPC4_CHANNEL_CONFIG_MONO IPC4_CHANNEL_CONFIG_5_POINT_1];
114+
fc = 3;
96115
sel.coeffs = zeros(8,8);
97116
sel.coeffs(fc, 1) = 1;
98-
write_blob(sel, "upmix_mono_to_51");
99-
write_blob(sel, "upmix_mono_to_71");
117+
mono_to_sixch_pack8 = write_blob(sel, "upmix_mono_to_51");
118+
sel.ch_count = [1 8];
119+
sel.ch_config = [IPC4_CHANNEL_CONFIG_MONO IPC4_CHANNEL_CONFIG_7_POINT_1];
120+
mono_to_eightch_pack8 = write_blob(sel, "upmix_mono_to_71");
100121

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

109139
% Stereo to L,L,R,R
140+
sel.ch_count = [2 4];
141+
sel.ch_config = [IPC4_CHANNEL_CONFIG_STEREO IPC4_CHANNEL_CONFIG_QUATRO];
110142
sel.coeffs = [ 1 0 0 0 0 0 0 0 ; ...
111143
1 0 0 0 0 0 0 0 ; ...
112144
0 1 0 0 0 0 0 0 ; ...
@@ -118,6 +150,8 @@ function sof_selector_blobs()
118150
write_blob(sel, "xover_selector_lr_to_llrr");
119151

120152
% Stereo to R,R,L,L
153+
sel.ch_count = [2 4];
154+
sel.ch_config = [IPC4_CHANNEL_CONFIG_STEREO IPC4_CHANNEL_CONFIG_QUATRO];
121155
sel.coeffs = [ 0 1 0 0 0 0 0 0 ; ...
122156
0 1 0 0 0 0 0 0 ; ...
123157
1 0 0 0 0 0 0 0 ; ...
@@ -129,6 +163,8 @@ function sof_selector_blobs()
129163
write_blob(sel, "xover_selector_lr_to_rrll");
130164

131165
% Stereo to L,R,L,R
166+
sel.ch_count = [2 4];
167+
sel.ch_config = [IPC4_CHANNEL_CONFIG_STEREO IPC4_CHANNEL_CONFIG_QUATRO];
132168
sel.coeffs = [ 1 0 0 0 0 0 0 0 ; ...
133169
0 1 0 0 0 0 0 0 ; ...
134170
1 0 0 0 0 0 0 0 ; ...
@@ -142,32 +178,55 @@ function sof_selector_blobs()
142178
sof_selector_paths(false);
143179
end
144180

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

153-
sel
201+
function pack8 = pack_selector_config(sel)
154202

155-
sum_coefs = sum(sel.coeffs, 2)'
156-
max_sum_coef = max(sum_coefs)
203+
sum_coefs = sum(sel.coeffs, 2)';
204+
max_sum_coef = max(sum_coefs);
157205
if max_sum_coef > 1
158206
scale = 1 / max_sum_coef;
159207
else
160208
scale = 1;
161209
end
162210

163-
scale
164211
sel.coeffs = scale .* sel.coeffs';
212+
coeffs_vec = reshape(sel.coeffs, 1, []); % convert to row vector
213+
coeffs_q10 = int16(round(coeffs_vec .* 1024)); % Q6.10
214+
pack8 = uint8(zeros(1, 2 * length(coeffs_q10) + 4));
165215

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
216+
% header
217+
j = 1;
218+
pack8(j:j + 1) = uint8(sel.ch_count);
219+
j = j + 2;
220+
pack8(j:j + 1) = uint8(sel.ch_config);
221+
j = j + 2;
222+
223+
% coeffs matrix
224+
for i = 1:length(coeffs_q10)
225+
pack8(j:j+1) = int16_to_byte(coeffs_q10(i));
226+
j = j + 2;
227+
end
228+
229+
end
171230

172231
function sof_selector_paths(enable)
173232

@@ -179,33 +238,19 @@ function sof_selector_paths(enable)
179238
end
180239
end
181240

182-
function blob8 = sof_selector_build_blob(sel)
241+
function blob8 = sof_selector_build_blob(pack8)
183242

184-
s = size(sel.coeffs);
185243
blob_type = 0;
186244
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
245+
data_size = length(pack8);
191246
ipc_ver = 4;
192247
[abi_bytes, abi_size] = sof_get_abi(data_size, ipc_ver, blob_type, blob_param_id);
193248
blob_size = data_size + abi_size;
194249
blob8 = uint8(zeros(1, blob_size));
195250
blob8(1:abi_size) = abi_bytes;
196251
j = abi_size + 1;
197252

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
253+
blob8(j:j+data_size-1) = pack8;
209254
end
210255

211256
function bytes = int16_to_byte(word)

0 commit comments

Comments
 (0)