Skip to content

Commit 4db254e

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 68e2c7c commit 4db254e

File tree

1 file changed

+111
-49
lines changed

1 file changed

+111
-49
lines changed

src/audio/selector/tune/sof_selector_blobs.m

Lines changed: 111 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -11,46 +11,57 @@
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

2121
% Matrix for 1:1 pass-through
22-
sel.rsvd0 = 0;
23-
sel.rsvd1 = 0;
22+
sel.ch_count = [8 8]; % Number of channels
23+
sel.ch_config = [12 12]; % Values of enum ipc4_channel_config: IPC4_CHANNEL_CONFIG_7_POINT_1
24+
sel.ch_out = 8;
2425
sel.coeffs = diag(ones(8, 1));
25-
write_blob(sel, "passthrough");
26+
passthrough_pack8 = write_blob(sel, "passthrough");
2627

2728
% Stereo to mono downmix
29+
sel.ch_count = [2 1];
30+
sel.ch_config = [1 0];
2831
sel.coeffs = zeros(8,8);
2932
sel.coeffs(1, 1) = 0.7071;
3033
sel.coeffs(1, 2) = 0.7071;
31-
write_blob(sel, "downmix_stereo_to_mono");
34+
stereo_to_mono_pack8 = write_blob(sel, "downmix_stereo_to_mono");
3235

3336
% 5.1 to stereo downmix
37+
sel.ch_count = [6 2];
38+
sel.ch_config = [8 1]; % IPC4_CHANNEL_CONFIG_5_POINT_1 to IPC4_CHANNEL_CONFIG_STEREO
3439
fl = 1; fr = 2; fc = 3; lfe = 4; sl = 5; sr = 6;
3540
m = zeros(8,8);
3641
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;
3742
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;
3843
sel.coeffs = m;
39-
write_blob(sel, "downmix_51_to_stereo");
4044
sel.coeffs(1, lfe) = 10^(+4/20); % +10 dB, attenuate by -6 dB to left
4145
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");
46+
sixch_to_stereo_pack8 = write_blob(sel, "downmix_51_to_stereo_with_lfe");
4347

4448
% 5.1 to mono downmix
49+
sel.ch_count = [6 1];
50+
sel.ch_config = [8 0]; % IPC4_CHANNEL_CONFIG_5_POINT_1 to IPC4_CHANNEL_CONFIG_MONO
51+
sel.ch_in = 6;
52+
sel.ch_out = 1;
4553
fl = 1; fr = 2; fc = 3; lfe = 4; sl = 5; sr = 6;
4654
m = zeros(8,8);
4755
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;
4856
sel.coeffs = m;
49-
write_blob(sel, "downmix_51_to_mono");
5057
sel.coeffs(1, lfe) = 10^(+10/20);
51-
write_blob(sel, "downmix_51_to_mono_with_lfe");
58+
sixch_to_mono_pack8 = write_blob(sel, "downmix_51_to_mono_with_lfe");
5259

5360
% 7.1 to 5.1 downmix
61+
sel.ch_count = [8 6];
62+
sel.ch_config = [12 8]; % IPC4_CHANNEL_CONFIG_7_POINT_1 to IPC4_CHANNEL_CONFIG_5_POINT_1
63+
sel.ch_in = 8;
64+
sel.ch_out = 6;
5465
fl8 = 1; fr8 = 2; fc8 = 3; lfe8 = 4; bl8 = 5; br8 = 6; sl8 = 7; sr8 = 8;
5566
fl6 = 1; fr6 = 2; fc6 = 3; lfe6 = 4; sl6 = 5; sr6 = 6;
5667
m = zeros(8,8);
@@ -63,50 +74,83 @@ function sof_selector_blobs()
6374
m(sr6, br8) = 1;
6475
m(lfe6, lfe8) = 1;
6576
sel.coeffs = m;
66-
write_blob(sel, "downmix_71_to_51");
77+
eightch_to_sixch_pack8 = write_blob(sel, "downmix_71_to_51");
6778

68-
% 7.1 to 5.1 downmix
79+
% 7.1 to stereo downmix
80+
sel.ch_count = [8 2];
81+
sel.ch_config = [12 1]; % IPC4_CHANNEL_CONFIG_7_POINT_1 to IPC4_CHANNEL_CONFIG_STEREO
82+
sel.ch_in = 8;
83+
sel.ch_out = 2;
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 = [12 0]; % IPC4_CHANNEL_CONFIG_7_POINT_1 to IPC4_CHANNEL_CONFIG_MONO
96+
sel.ch_in = 8;
97+
sel.ch_out = 1;
8098
fl = 1; fc = 3; fr = 2; sr = 8; br = 6; bl = 5; sl = 7; lfe = 4;
8199
m = zeros(8,8);
82100
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;
83101
sel.coeffs = m;
84-
write_blob(sel, "downmix_71_to_mono");
85102
m(1, lfe) = 10^(+19/20); % +10 dB
86-
write_blob(sel, "downmix_71_to_mono_with_lfe");
103+
eightch_to_mono_pack8 = write_blob(sel, "downmix_71_to_mono_with_lfe");
87104

88105
% mono to stereo upmix
106+
sel.ch_count = [1 2];
107+
sel.ch_config = [0 1]; % IPC4_CHANNEL_CONFIG_MONO to IPC4_CHANNEL_CONFIG_STEREO
108+
sel.ch_in = 1;
109+
sel.ch_out = 2;
89110
sel.coeffs = zeros(8,8);
90111
sel.coeffs(1, 1) = 10^(-3/20);
91112
sel.coeffs(2, 1) = 10^(-3/20);
92-
write_blob(sel, "upmix_mono_to_stereo");
113+
mono_to_stereo_pack8 = write_blob(sel, "upmix_mono_to_stereo");
93114

94115
% mono to 5.1 / 7.1 upmix
95-
fc = 3
116+
sel.ch_count = [1 6];
117+
sel.ch_config = [0 8]; % IPC4_CHANNEL_CONFIG_MONO to IPC4_CHANNEL_CONFIG_5_POINT_1
118+
sel.ch_in = 1;
119+
sel.ch_out = 6;
120+
fc = 3;
96121
sel.coeffs = zeros(8,8);
97122
sel.coeffs(fc, 1) = 1;
98-
write_blob(sel, "upmix_mono_to_51");
99-
write_blob(sel, "upmix_mono_to_71");
123+
mono_to_sixch_pack8 = write_blob(sel, "upmix_mono_to_51");
124+
sel.ch_count = [1 8];
125+
sel.ch_config = [0 12]; % IPC4_CHANNEL_CONFIG_MONO to IPC4_CHANNEL_CONFIG_7_POINT_1
126+
mono_to_eightch_pack8 = write_blob(sel, "upmix_mono_to_71");
100127

101128
% stereo to 5.1 / 7.1 upmix
129+
sel.ch_count = [2 6];
130+
sel.ch_config = [1 8]; % IPC4_CHANNEL_CONFIG_STEREO to IPC4_CHANNEL_CONFIG_5_POINT_1
131+
sel.ch_in = 2;
132+
sel.ch_out = 6;
102133
fl = 1; fr = 2;
103134
sel.coeffs = zeros(8,8);
104135
sel.coeffs(fl, 1) = 1;
105136
sel.coeffs(fr, 2) = 1;
106-
write_blob(sel, "upmix_stereo_to_51");
107-
write_blob(sel, "upmix_stereo_to_71");
137+
stereo_to_sixch_pack8 = write_blob(sel, "upmix_stereo_to_51");
138+
sel.ch_count = [2 8];
139+
sel.ch_config = [1 12]; % IPC4_CHANNEL_CONFIG_STEREO to IPC4_CHANNEL_CONFIG_7_POINT_1
140+
sel.ch_in = 2;
141+
sel.ch_out = 8;
142+
stereo_to_eightch_pack8 = write_blob(sel, "upmix_stereo_to_71");
143+
144+
% For blob format with multiple up/down-mix profiles, intended
145+
% for playback decoder offload conversions.
146+
multi_pack8 = [passthrough_pack8 mono_to_stereo_pack8 sixch_to_stereo_pack8 eightch_to_stereo_pack8];
147+
write_8bit_packed(multi_pack8, 'stereo_endpoint_playback_updownmix');
108148

109149
% Stereo to L,L,R,R
150+
sel.ch_count = [2 4];
151+
sel.ch_config = [13 13]; % Using IPC4_CHANNEL_CONFIG_INVALID
152+
sel.ch_in = 2;
153+
sel.ch_out = 4;
110154
sel.coeffs = [ 1 0 0 0 0 0 0 0 ; ...
111155
1 0 0 0 0 0 0 0 ; ...
112156
0 1 0 0 0 0 0 0 ; ...
@@ -118,6 +162,10 @@ function sof_selector_blobs()
118162
write_blob(sel, "xover_selector_lr_to_llrr");
119163

120164
% Stereo to R,R,L,L
165+
sel.ch_count = [2 4];
166+
sel.ch_config = [13 13];
167+
sel.ch_in = 2;
168+
sel.ch_out = 4;
121169
sel.coeffs = [ 0 1 0 0 0 0 0 0 ; ...
122170
0 1 0 0 0 0 0 0 ; ...
123171
1 0 0 0 0 0 0 0 ; ...
@@ -129,6 +177,10 @@ function sof_selector_blobs()
129177
write_blob(sel, "xover_selector_lr_to_rrll");
130178

131179
% Stereo to L,R,L,R
180+
sel.ch_count = [2 4];
181+
sel.ch_config = [13 13];
182+
sel.ch_in = 2;
183+
sel.ch_out = 4;
132184
sel.coeffs = [ 1 0 0 0 0 0 0 0 ; ...
133185
0 1 0 0 0 0 0 0 ; ...
134186
1 0 0 0 0 0 0 0 ; ...
@@ -142,32 +194,56 @@ function sof_selector_blobs()
142194
sof_selector_paths(false);
143195
end
144196

145-
function write_blob(sel, blobname)
197+
function pack8 = write_blob(sel, blobname)
198+
pack8 = pack_selector_config(sel);
199+
pack8_copy = pack8;
200+
pack8_copy(1:4) = uint8([0 0 0 0]);
201+
write_8bit_packed(pack8_copy, blobname);
202+
end
203+
204+
function write_8bit_packed(pack8, blobname)
205+
blob8 = sof_selector_build_blob(pack8);
146206
str_config = "selector_config";
147207
str_exported = "Exported with script sof_selector_blobs.m";
148-
str_howto = "cd tools/tune/selector; octave sof_selector_blobs.m"
208+
str_howto = "cd tools/tune/selector; octave sof_selector_blobs.m";
149209
sof_tools = '../../../../tools';
150210
sof_tplg = fullfile(sof_tools, 'topology');
151211
sof_tplg_selector = fullfile(sof_tplg, 'topology2/include/components/micsel');
212+
tplg2_fn = sprintf("%s/%s.conf", sof_tplg_selector, blobname);
213+
sof_check_create_dir(tplg2_fn);
214+
sof_tplg2_write(tplg2_fn, blob8, str_config, str_exported, str_howto);
215+
end
152216

153-
sel
217+
function pack8 = pack_selector_config(sel)
154218

155-
sum_coefs = sum(sel.coeffs, 2)'
156-
max_sum_coef = max(sum_coefs)
219+
sum_coefs = sum(sel.coeffs, 2)';
220+
max_sum_coef = max(sum_coefs);
157221
if max_sum_coef > 1
158222
scale = 1 / max_sum_coef;
159223
else
160224
scale = 1;
161225
end
162226

163-
scale
164227
sel.coeffs = scale .* sel.coeffs';
228+
coeffs_vec = reshape(sel.coeffs, 1, []); % convert to row vector
229+
coeffs_q10 = int16(round(coeffs_vec .* 1024)); % Q6.10
230+
pack8 = uint8(2 * length(coeffs_q10) + 4);
231+
rsvd1 = 0;
165232

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
233+
% header
234+
j = 1;
235+
pack8(j:j + 1) = uint8(sel.ch_count);
236+
j = j + 2;
237+
pack8(j:j + 1) = uint8(sel.ch_config);
238+
j = j + 2;
239+
240+
% coeffs matrix
241+
for i = 1:length(coeffs_q10)
242+
pack8(j:j+1) = int16_to_byte(coeffs_q10(i));
243+
j = j + 2;
244+
end
245+
246+
end
171247

172248
function sof_selector_paths(enable)
173249

@@ -179,33 +255,19 @@ function sof_selector_paths(enable)
179255
end
180256
end
181257

182-
function blob8 = sof_selector_build_blob(sel)
258+
function blob8 = sof_selector_build_blob(pack8)
183259

184-
s = size(sel.coeffs);
185260
blob_type = 0;
186261
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
262+
data_size = length(pack8);
191263
ipc_ver = 4;
192264
[abi_bytes, abi_size] = sof_get_abi(data_size, ipc_ver, blob_type, blob_param_id);
193265
blob_size = data_size + abi_size;
194266
blob8 = uint8(zeros(1, blob_size));
195267
blob8(1:abi_size) = abi_bytes;
196268
j = abi_size + 1;
197269

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
270+
blob8(j:j+data_size-1) = pack8;
209271
end
210272

211273
function bytes = int16_to_byte(word)

0 commit comments

Comments
 (0)