1111
1212% SPDX-License-Identifier: BSD-3-Clause
1313%
14- % Copyright (c) 2025, Intel Corporation.
14+ % Copyright (c) 2025-2026 , Intel Corporation.
1515
1616function 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 );
143195end
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
172248function sof_selector_paths(enable )
173249
@@ -179,33 +255,19 @@ function sof_selector_paths(enable)
179255 end
180256end
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 ;
209271end
210272
211273function bytes = int16_to_byte(word )
0 commit comments