diff --git a/src/audio/tdfb/tune/sof_bf_line2_two_beams.m b/src/audio/tdfb/tune/sof_bf_line2_two_beams.m new file mode 100644 index 000000000000..7f7eec8dd826 --- /dev/null +++ b/src/audio/tdfb/tune/sof_bf_line2_two_beams.m @@ -0,0 +1,73 @@ +function sof_bf_line2_two_beams(fs, d, a1, a2, fn, prm) + +% sof_bf_line2_two_beams(fs, d, a1, a2, fn, prm) +% Input +% fs - sample rate +% d - microphones distance in meters +% a1 - steer angle beam 1 +% a2 - steer angle beam 2 +% fn - struct with exported blob files names +% prm +% .add_beam_beam_off - controls addition of beam off definition to blob +% .type - Use 'SDB' or 'DSB' +% .export_note - comment about build generally +% .export_howto - detailed build instruction +% + +% SPDX-License-Identifier: BSD-3-Clause +% +% Copyright (c) 2020-2024, Intel Corporation. +% +% Author: Seppo Ingalsuo + +% Get defaults +bf1 = sof_bf_defaults(); +bf1.fs = fs; + +% Setup array +bf1.array='line'; % Calculate xyz coordinates for line +bf1.mic_n = 2; +bf1.mic_d = d; +bf1.beam_off_defined = prm.add_beam_off; +bf1.type = prm.type; + +% Copy settings for bf2 +bf2 = bf1; + +% Design beamformer 1 (left) +bf1.steer_az = a1; +bf1.steer_el = 0 * a1; +bf1.input_channel_select = [0 1]; % Input two channels +bf1.output_channel_mix = [1 1]; % Mix both filters to channel 2^0 +bf1.output_channel_mix_beam_off = [1 2]; % Filter 1 to channel 2^0, etc. +bf1.output_stream_mix = [0 0]; % Mix both filters to stream 0 +bf1.num_output_channels = 2; +bf1.fn = 10; % Figs 10.... +bf1 = sof_bf_filenames_helper(bf1); +bf1 = sof_bf_design(bf1); + +% Design beamformer 2 (right) +bf2.steer_az = a2; +bf2.steer_el = 0 * a2; +bf2.input_channel_select = [0 1]; % Input two channels +bf2.output_channel_mix = [2 2]; % Mix both filters to channel 2^1 +bf2.output_channel_mix_beam_off = [0 0]; % Filters omitted +bf2.output_stream_mix = [0 0]; % Mix both filters to stream 0 +bf2.num_output_channels = 2; +bf2.fn = 20; % Figs 20.... +bf2 = sof_bf_filenames_helper(bf2); +bf2 = sof_bf_design(bf2); + +% Merge two beamformers into single description, set file names +bfm = sof_bf_merge(bf1, bf2); +bfm.sofctl3_fn = fullfile(bfm.sofctl3_path, fn.sofctl3_fn); +bfm.tplg1_fn = fullfile(bfm.tplg1_path, fn.tplg1_fn); +bfm.sofctl4_fn = fullfile(bfm.sofctl4_path, fn.sofctl4_fn); +bfm.tplg2_fn = fullfile(bfm.tplg2_path, fn.tplg2_fn); + +% Export files for topology and sof-ctl +bfm.export_note = prm.export_note; +bfm.export_howto = prm.export_howto; +sof_bf_export(bfm); + +end diff --git a/src/audio/tdfb/tune/sof_bf_line4_two_beams.m b/src/audio/tdfb/tune/sof_bf_line4_two_beams.m new file mode 100644 index 000000000000..9cefc37fc10a --- /dev/null +++ b/src/audio/tdfb/tune/sof_bf_line4_two_beams.m @@ -0,0 +1,73 @@ +function sof_bf_line4_two_beams(fs, d, a1, a2, fn, prm) + +% sof_bf_line4_two_beams(fs, d, a1, a2, fn, prm) +% Input +% fs - sample rate +% d - microphones distance in meters +% a1 - steer angle beam 1 +% a2 - steer angle beam 2 +% fn - struct with exported blob files names +% prm +% .add_beam_beam_off - controls addition of beam off definition to blob +% .type - Use 'SDB' or 'DSB' +% .export_note - comment about build generally +% .export_howto - detailed build instruction +% + +% SPDX-License-Identifier: BSD-3-Clause +% +% Copyright (c) 2020-2024, Intel Corporation. All rights reserved. +% +% Author: Seppo Ingalsuo + +% Get defaults +bf1 = sof_bf_defaults(); +bf1.fs = fs; + +% Setup array +bf1.array='line'; % Calculate xyz coordinates for line +bf1.mic_n = 4; +bf1.mic_d = d; +bf1.beam_off_defined = prm.add_beam_off; +bf1.type = prm.type; + +% Copy settings for bf2 +bf2 = bf1; + +% Design beamformer 1 (left) +bf1.steer_az = a1; +bf1.steer_el = 0 * a1; +bf1.input_channel_select = [0 1 2 3]; % Input four channels +bf1.output_channel_mix = [1 1 1 1]; % Mix filters to channel 2^0 +bf1.output_channel_mix_beam_off = [1 0 0 2]; % Filter 1 to channel 2^0, filter 4 to channel 2^1 +bf1.output_stream_mix = [0 0 0 0]; % Mix filters to stream 0 +bf1.num_output_channels = 2; +bf1.fn = 10; % Figs 10.... +bf1 = sof_bf_filenames_helper(bf1); +bf1 = sof_bf_design(bf1); + +% Design beamformer 2 (right) +bf2.steer_az = a2; +bf2.steer_el = 0 * a2; +bf2.input_channel_select = [0 1 2 3]; % Input two channels +bf2.output_channel_mix = [2 2 2 2]; % Mix filters to channel 2^1 +bf2.output_channel_mix_beam_off = [0 0 0 0]; % Filters omitted +bf2.output_stream_mix = [0 0 0 0]; % Mix filters to stream 0 +bf2.num_output_channels = 2; +bf2.fn = 20; % Figs 20.... +bf2 = sof_bf_filenames_helper(bf2); +bf2 = sof_bf_design(bf2); + +% Merge two beamformers into single description, set file names +bfm = sof_bf_merge(bf1, bf2); +bfm.sofctl3_fn = fullfile(bfm.sofctl3_path, fn.sofctl3_fn); +bfm.tplg1_fn = fullfile(bfm.tplg1_path, fn.tplg1_fn); +bfm.sofctl4_fn = fullfile(bfm.sofctl4_path, fn.sofctl4_fn); +bfm.tplg2_fn = fullfile(bfm.tplg2_path, fn.tplg2_fn); + +% Export files for topology and sof-ctl +bfm.export_note = prm.export_note; +bfm.export_howto = prm.export_howto; +sof_bf_export(bfm); + +end diff --git a/src/audio/tdfb/tune/sof_example_all.sh b/src/audio/tdfb/tune/sof_example_all.sh index eb9c6f2ab74f..2a7b45b3833c 100755 --- a/src/audio/tdfb/tune/sof_example_all.sh +++ b/src/audio/tdfb/tune/sof_example_all.sh @@ -1,12 +1,13 @@ #!/bin/bash # SPDX-License-Identifier: BSD-3-Clause -# Copyright(c) 2022 Intel Corporation. All rights reserved. +# Copyright(c) 2022-2024 Intel Corporation. set -e CONFIG_LIST=( sof_example_pass_config sof_example_line_array - sof_example_line_0mm36mm146mm182mm sof_example_circular_array sof_example_two_beams ) + sof_example_line_0mm36mm146mm182mm sof_example_circular_array + sof_example_two_beams sof_example_two_beams_default ) OCTAVE_CMD=( octave --no-window-system ) MATLAB_CMD=( matlab -nodisplay -batch ) diff --git a/src/audio/tdfb/tune/sof_example_line_array.m b/src/audio/tdfb/tune/sof_example_line_array.m index be8b60acf3fc..5ae28003fc79 100644 --- a/src/audio/tdfb/tune/sof_example_line_array.m +++ b/src/audio/tdfb/tune/sof_example_line_array.m @@ -16,8 +16,10 @@ function sof_example_line_array() az = -90:15:90; close all; line_one_beam(48e3, 50e-3, az, 2, 64); close all; line_one_beam(48e3, 68e-3, az, 2, 64); +close all; line_one_beam(48e3, 73.5e-3, az, 2, 64); close all; line_one_beam(16e3, 50e-3, az, 2, 40); close all; line_one_beam(16e3, 68e-3, az, 2, 40); +close all; line_one_beam(16e3, 73.5e-3, az, 2, 40); %% 4 mic arrays close all; line_one_beam(48e3, 28e-3, az, 4, 80); diff --git a/src/audio/tdfb/tune/sof_example_pass_config.m b/src/audio/tdfb/tune/sof_example_pass_config.m index d3e1fabc39b9..35bba9eb7186 100644 --- a/src/audio/tdfb/tune/sof_example_pass_config.m +++ b/src/audio/tdfb/tune/sof_example_pass_config.m @@ -20,7 +20,9 @@ function sof_example_pass_config() bf.num_output_channels = 2; % Two channels bf.num_output_streams = 1; % One sink stream bf.beam_off_defined = 0; % No need for separate bypass definition -bf.num_angles = 0; % No beams defined +bf.num_angles = 1; % Need at least one beam defined even +bf.steer_az = 0; % if no processing happens, claim it's +bf.steer_el = 0; % angle (0, 0). bf.num_filters = 2; % Two filters % Minimal manual design fields for successful export @@ -36,8 +38,8 @@ function sof_example_pass_config() sof_bf_export(bf); % Setup for four channels -bf.input_channel_select = [0 1 2 3]; % Input two channels -bf.output_channel_mix = [1 2 4 8]; % Filter1 -> ch0, filter2 -> ch1 +bf.input_channel_select = [0 1 2 3]; % Input four channels +bf.output_channel_mix = [1 2 4 8]; % Filter1 -> ch0, filter2 -> ch1, ... bf.output_stream_mix = [0 0 0 0]; % Mix both filters to stream 0 bf.num_output_channels = 4; % Four channels bf.num_output_streams = 1; % One sink stream @@ -53,4 +55,24 @@ function sof_example_pass_config() bf.tplg2_fn = fullfile(bf.tplg2_path, 'line4_pass.conf'); sof_bf_export(bf); + +% Setup for four channels to two channels passthrough + +bf.input_channel_select = [0 3]; % Input two channels, leftmost, rightmost mic of 4 +bf.output_channel_mix = [1 2]; % Filter1 -> ch0, filter2 -> ch1 +bf.output_stream_mix = [0 0]; % Mix both filters to stream 0 +bf.num_output_channels = 2; % Two channels +bf.num_output_streams = 1; % One sink stream + +% Minimal manual design fields for successful export +bf.num_filters = 2; +bf.w = [1 0 0 0; 1 0 0 0]'; % Two FIR filters with first tap set to one + +% Files +bf.sofctl3_fn = fullfile(bf.sofctl3_path, 'coef_line4to2_pass.txt'); +bf.tplg1_fn = fullfile(bf.tplg1_path, 'coef_line4to2_pass.m4'); +bf.sofctl4_fn = fullfile(bf.sofctl4_path, 'line4to2_pass.txt'); +bf.tplg2_fn = fullfile(bf.tplg2_path, 'line4to2_pass.conf'); +sof_bf_export(bf); + end diff --git a/src/audio/tdfb/tune/sof_example_two_beams.m b/src/audio/tdfb/tune/sof_example_two_beams.m index dc081593fb44..6b7dab549be5 100644 --- a/src/audio/tdfb/tune/sof_example_two_beams.m +++ b/src/audio/tdfb/tune/sof_example_two_beams.m @@ -20,6 +20,12 @@ function sof_example_two_beams() %% Stereo capture blobs with two beams az = [0 30 90]; azstr = az_to_string(az); + +prm.export_note = 'Created with script example_two_beams.m'; +prm.export_howto = 'cd tools/tune/tdfb; matlab -nodisplay -nosplash -nodesktop -r example_two_beams'; +prm.type = 'SDB'; +prm.add_beam_off = 1; + for fs = [16e3 48e3] %% Close all plots to avoid issues with large number of windows close all; @@ -32,7 +38,7 @@ function sof_example_two_beams() d = 50e-3; % 50 mm spacing a1 = az; % Azimuth +az deg a2 = -az; % Azimuth -az deg - line2_two_beams(fs, d, a1, a2, fn, 1); + sof_bf_line2_two_beams(fs, d, a1, a2, fn, prm); %% 2 mic 68 mm array fn.tplg1_fn = sprintf('coef_line2_68mm_pm%sdeg_%dkhz.m4', azstr, fs/1e3); @@ -42,7 +48,17 @@ function sof_example_two_beams() d = 68e-3; % 68 mm spacing a1 = az; % Azimuth +az deg a2 = -az; % Azimuth -az deg - line2_two_beams(fs, d, a1, a2, fn, 1); + sof_bf_line2_two_beams(fs, d, a1, a2, fn, prm); + + %% 2 mic 73.5 mm array + fn.tplg1_fn = sprintf('coef_line2_74mm_pm%sdeg_%dkhz.m4', azstr, fs/1e3); + fn.sofctl3_fn = sprintf('coef_line2_74mm_pm%sdeg_%dkhz.txt', azstr, fs/1e3); + fn.tplg2_fn = sprintf('line2_74mm_pm%sdeg_%dkhz.conf', azstr, fs/1e3); + fn.sofctl4_fn = sprintf('line2_74mm_pm%sdeg_%dkhz.txt', azstr, fs/1e3); + d = 73.5e-3; % 73.5 mm spacing + a1 = az; % Azimuth +az deg + a2 = -az; % Azimuth -az deg + sof_bf_line2_two_beams(fs, d, a1, a2, fn, prm); %% 4 mic 28 mm spaced array fn.tplg1_fn = sprintf('coef_line4_28mm_pm%sdeg_%dkhz.m4', azstr, fs/1e3); @@ -52,7 +68,7 @@ function sof_example_two_beams() d = 28e-3; % 28 mm spacing a1 = az; % Azimuth +az deg a2 = -az; % Azimuth -az deg - line4_two_beams(fs, d, a1, a2, fn, 1); + sof_bf_line4_two_beams(fs, d, a1, a2, fn, prm); %% 4 mic 68 mm spaced array fn.tplg1_fn = sprintf('coef_line4_68mm_pm%sdeg_%dkhz.m4', azstr, fs/1e3); @@ -62,7 +78,7 @@ function sof_example_two_beams() d = 68e-3; % 68 mm spacing a1 = az; % Azimuth +az deg a2 = -az; % Azimuth -az deg - line4_two_beams(fs, d, a1, a2, fn, 1); + sof_bf_line4_two_beams(fs, d, a1, a2, fn, prm); %% 4 mic 78 mm spaced array fn.tplg1_fn = sprintf('coef_line4_78mm_pm%sdeg_%dkhz.m4', azstr, fs/1e3); @@ -72,13 +88,14 @@ function sof_example_two_beams() d = 78e-3; % 78 mm spacing a1 = az; % Azimuth +az deg a2 = -az; % Azimuth -az deg - line4_two_beams(fs, d, a1, a2, fn, 1); + sof_bf_line4_two_beams(fs, d, a1, a2, fn, prm); end %% Export blob with just +/- 90 deg beams for testbench beampattern check close all; az = [90]; azstr = az_to_string(az); +prm.add_beam_off = 0; for fs = [16e3 48e3] %% 2 mic 50 mm array, disable beam off description in blob to force processing on fn.tplg1_fn = sprintf('coef_line2_50mm_pm%sdeg_%dkhz.m4', azstr, fs/1e3); @@ -88,7 +105,7 @@ function sof_example_two_beams() d = 50e-3; % 50 mm spacing a1 = az; % Azimuth +az deg a2 = -az; % Azimuth -az deg - line2_two_beams(fs, d, a1, a2, fn, 0); + sof_bf_line2_two_beams(fs, d, a1, a2, fn, prm); %% 4 mic 28 mm spaced array, no beam off configuration fn.tplg1_fn = sprintf('coef_line4_28mm_pm%sdeg_%dkhz.m4', azstr, fs/1e3); @@ -98,7 +115,7 @@ function sof_example_two_beams() d = 28e-3; % 28 mm spacing a1 = az; % Azimuth +az deg a2 = -az; % Azimuth -az deg - line4_two_beams(fs, d, a1, a2, fn, 0); + sof_bf_line4_two_beams(fs, d, a1, a2, fn, prm); end %% Circular array with two beams @@ -126,113 +143,6 @@ function sof_example_two_beams() end end -function line2_two_beams(fs, d, a1, a2, fn, add_beam_off); - -% Get defaults -bf1 = sof_bf_defaults(); -bf1.fs = fs; -bf1.beam_off_defined = add_beam_off; - - -% Setup array -bf1.array='line'; % Calculate xyz coordinates for line -bf1.mic_n = 2; -bf1.mic_d = d; - -% Copy settings for bf2 -bf2 = bf1; - -% Design beamformer 1 (left) -bf1.steer_az = a1; -bf1.steer_el = 0 * a1; -bf1.input_channel_select = [0 1]; % Input two channels -bf1.output_channel_mix = [1 1]; % Mix both filters to channel 2^0 -bf1.output_channel_mix_beam_off = [1 2]; % Filter 1 to channel 2^0, etc. -bf1.output_stream_mix = [0 0]; % Mix both filters to stream 0 -bf1.num_output_channels = 2; -bf1.fn = 10; % Figs 10.... -bf1 = sof_bf_filenames_helper(bf1); -bf1 = sof_bf_design(bf1); - -% Design beamformer 2 (right) -bf2.steer_az = a2; -bf2.steer_el = 0 * a2; -bf2.input_channel_select = [0 1]; % Input two channels -bf2.output_channel_mix = [2 2]; % Mix both filters to channel 2^1 -bf2.output_channel_mix_beam_off = [0 0]; % Filters omitted -bf2.output_stream_mix = [0 0]; % Mix both filters to stream 0 -bf2.num_output_channels = 2; -bf2.fn = 20; % Figs 20.... -bf2 = sof_bf_filenames_helper(bf2); -bf2 = sof_bf_design(bf2); - -% Merge two beamformers into single description, set file names -bfm = sof_bf_merge(bf1, bf2); -bfm.sofctl3_fn = fullfile(bfm.sofctl3_path, fn.sofctl3_fn); -bfm.tplg1_fn = fullfile(bfm.tplg1_path, fn.tplg1_fn); -bfm.sofctl4_fn = fullfile(bfm.sofctl4_path, fn.sofctl4_fn); -bfm.tplg2_fn = fullfile(bfm.tplg2_path, fn.tplg2_fn); - -% Export files for topology and sof-ctl -bfm.export_note = 'Created with script sof_example_two_beams.m'; -bfm.export_howto = 'cd tools/tune/tdfb; matlab -nodisplay -nosplash -nodesktop -r sof_example_two_beams'; -sof_bf_export(bfm); - -end - -function line4_two_beams(fs, d, a1, a2, fn, add_beam_off); - -% Get defaults -bf1 = sof_bf_defaults(); -bf1.fs = fs; -bf1.beam_off_defined = add_beam_off; - -% Setup array -bf1.array='line'; % Calculate xyz coordinates for line -bf1.mic_n = 4; -bf1.mic_d = d; - -% Copy settings for bf2 -bf2 = bf1; - -% Design beamformer 1 (left) -bf1.steer_az = a1; -bf1.steer_el = 0 * a1; -bf1.input_channel_select = [0 1 2 3]; % Input four channels -bf1.output_channel_mix = [1 1 1 1]; % Mix filters to channel 2^0 -bf1.output_channel_mix_beam_off = [1 0 0 2]; % Filter 1 to channel 2^0, filter 4 to channel 2^1 -bf1.output_stream_mix = [0 0 0 0]; % Mix filters to stream 0 -bf1.num_output_channels = 2; -bf1.fn = 10; % Figs 10.... -bf1 = sof_bf_filenames_helper(bf1); -bf1 = sof_bf_design(bf1); - -% Design beamformer 2 (right) -bf2.steer_az = a2; -bf2.steer_el = 0 * a2; -bf2.input_channel_select = [0 1 2 3]; % Input two channels -bf2.output_channel_mix = [2 2 2 2]; % Mix filters to channel 2^1 -bf2.output_channel_mix_beam_off = [0 0 0 0]; % Filters omitted -bf2.output_stream_mix = [0 0 0 0]; % Mix filters to stream 0 -bf2.num_output_channels = 2; -bf2.fn = 20; % Figs 20.... -bf2 = sof_bf_filenames_helper(bf2); -bf2 = sof_bf_design(bf2); - -% Merge two beamformers into single description, set file names -bfm = sof_bf_merge(bf1, bf2); -bfm.sofctl3_fn = fullfile(bfm.sofctl3_path, fn.sofctl3_fn); -bfm.tplg1_fn = fullfile(bfm.tplg1_path, fn.tplg1_fn); -bfm.sofctl4_fn = fullfile(bfm.sofctl4_path, fn.sofctl4_fn); -bfm.tplg2_fn = fullfile(bfm.tplg2_path, fn.tplg2_fn); - -% Export files for topology and sof-ctl -bfm.export_note = 'Created with script sof_example_two_beams.m'; -bfm.export_howto = 'cd tools/tune/tdfb; matlab -nodisplay -nosplash -nodesktop -r sof_example_two_beams'; -sof_bf_export(bfm); - -end - function circular_two_beams(fs, r, n, a1, a2, fn, add_beam_off) % Get defaults and common settings diff --git a/src/audio/tdfb/tune/sof_example_two_beams_default.m b/src/audio/tdfb/tune/sof_example_two_beams_default.m new file mode 100644 index 000000000000..65fe1bc41563 --- /dev/null +++ b/src/audio/tdfb/tune/sof_example_two_beams_default.m @@ -0,0 +1,61 @@ +function sof_example_two_beams_default() + +% sof_example_two_beams_default() +% +% Creates configuration files for a two beams design, one +% points to -10 degrees and other to 10 degrees +% direction for default 50 mm spaced two microphones configuration. The +% beams are output to stereo and left right channels. The angle is +% slightly different for different microphones spacing. With larger +% microphones spacing the angle narrows a bit. But since the target +% is user focused audio with slight stereo effect it's acceptable. +% The bespoke blobs for a device can be applied with ALSA UCM. + +% SPDX-License-Identifier: BSD-3-Clause +% +% Copyright (c) 2024, Intel Corporation. +% +% Author: Seppo Ingalsuo + +%% Stereo capture blobs with two beams +az = [10]; +azstr = az_to_string(az); + +prm.export_note = 'Created with script sof_example_two_beams_default.m'; +prm.export_howto = 'cd tools/tune/tdfb; matlab -nodisplay -nosplash -nodesktop -r sof_example_two_beams_default'; +prm.type = 'DSB'; +prm.add_beam_off = 1; + +for fs = [16e3 48e3] + %% Close all plots to avoid issues with large number of windows + close all; + + %% 2 mic array + fn.tplg1_fn = sprintf('coef_line2_generic_pm%sdeg_%dkhz.m4', azstr, fs/1e3); + fn.sofctl3_fn = sprintf('coef_line2_generic_pm%sdeg_%dkhz.txt', azstr, fs/1e3); + fn.tplg2_fn = sprintf('line2_generic_pm%sdeg_%dkhz.conf', azstr, fs/1e3); + fn.sofctl4_fn = sprintf('line2_generic_pm%sdeg_%dkhz.txt', azstr, fs/1e3); + d = 50e-3; % 50 mm spacing + a1 = az; % Azimuth +az deg + a2 = -az; % Azimuth -az deg + sof_bf_line2_two_beams(fs, d, a1, a2, fn, prm); + + %% 4 mic array + fn.tplg1_fn = sprintf('coef_line4_generic_pm%sdeg_%dkhz.m4', azstr, fs/1e3); + fn.sofctl3_fn = sprintf('coef_line4_generic_pm%sdeg_%dkhz.txt', azstr, fs/1e3); + fn.tplg2_fn = sprintf('line4_generic_pm%sdeg_%dkhz.conf', azstr, fs/1e3); + fn.sofctl4_fn = sprintf('line4_generic_pm%sdeg_%dkhz.txt', azstr, fs/1e3); + d = 40e-3; % 40 mm spacing + a1 = az; % Azimuth +az deg + a2 = -az; % Azimuth -az deg + sof_bf_line4_two_beams(fs, d, a1, a2, fn, prm); +end + +end + +function s = az_to_string(az) + s = sprintf('%d', az(1)); + for n = 2:length(az) + s = sprintf('%s_%d', s, az(n)); + end +end