From fc21c4765f3fd4c3d83f87992b8523d07c5adfe7 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Mon, 25 Nov 2024 13:46:46 +0200 Subject: [PATCH 1/3] Tools: Tune: TDFB: Add generate of few needed blobs This patch adds a few blobs generate for the beamformer. There is no need to update the blobs in tplg2 since the update has been already done with run of an earlier version of this patch. - Support two mic line array with 74 mm spacing with addition to sof_example_line_array.m and sof_example_two_beams.m - Updates beamformer pass-through configuration blob with steer angle to avoid initialize error. - Adds script sof_example_two_beams_default.m to export generic blobs for 2 and 4 mic line arrays. The parameters are such that the array mic spacing is not critical (delay-and-sum type) and narrow user faced stereo beams. The two beams design functions are split to own files for use from two scripts. Signed-off-by: Seppo Ingalsuo --- src/audio/tdfb/tune/sof_bf_line2_two_beams.m | 73 +++++++++ src/audio/tdfb/tune/sof_bf_line4_two_beams.m | 73 +++++++++ src/audio/tdfb/tune/sof_example_all.sh | 5 +- src/audio/tdfb/tune/sof_example_line_array.m | 2 + src/audio/tdfb/tune/sof_example_pass_config.m | 28 +++- src/audio/tdfb/tune/sof_example_two_beams.m | 138 +++--------------- .../tdfb/tune/sof_example_two_beams_default.m | 61 ++++++++ 7 files changed, 261 insertions(+), 119 deletions(-) create mode 100644 src/audio/tdfb/tune/sof_bf_line2_two_beams.m create mode 100644 src/audio/tdfb/tune/sof_bf_line4_two_beams.m create mode 100644 src/audio/tdfb/tune/sof_example_two_beams_default.m 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 From 2703a3e39c1bc5e2afe2ba687bf8a72c2794de17 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Mon, 25 Nov 2024 15:43:25 +0200 Subject: [PATCH 2/3] Audio: TDFB: Tune: Add export of beamformer blobs for ALSA UCM This change adds generate of multi-microphone beamformer blobs to apply with UCM2 rules for SOF. Signed-off-by: Seppo Ingalsuo --- src/audio/tdfb/tune/sof_bf_defaults.m | 2 + src/audio/tdfb/tune/sof_bf_export.m | 14 +++++ src/audio/tdfb/tune/sof_bf_filenames_helper.m | 2 + src/audio/tdfb/tune/sof_bf_line2_two_beams.m | 2 + src/audio/tdfb/tune/sof_bf_line4_two_beams.m | 2 + src/audio/tdfb/tune/sof_example_pass_config.m | 6 ++ src/audio/tdfb/tune/sof_example_two_beams.m | 58 +++++++------------ .../tdfb/tune/sof_example_two_beams_default.m | 4 ++ 8 files changed, 54 insertions(+), 36 deletions(-) diff --git a/src/audio/tdfb/tune/sof_bf_defaults.m b/src/audio/tdfb/tune/sof_bf_defaults.m index f8222b597da3..6e530c52d065 100644 --- a/src/audio/tdfb/tune/sof_bf_defaults.m +++ b/src/audio/tdfb/tune/sof_bf_defaults.m @@ -19,6 +19,8 @@ bf.array_angle = [0 0 0]; % Array rotation angles for xyz bf.tplg_fn = ''; bf.sofctl_fn = ''; +bf.ucmbin3_fn = ''; +bf.ucmbin4_fn = ''; sof_tools = '../../../../tools'; bf.tplg1_path = fullfile(sof_tools, 'topology/topology1/m4/tdfb'); bf.tplg2_path = fullfile(sof_tools, 'topology/topology2/include/components/tdfb'); diff --git a/src/audio/tdfb/tune/sof_bf_export.m b/src/audio/tdfb/tune/sof_bf_export.m index faf4cef3feb9..874ac6f9f78b 100644 --- a/src/audio/tdfb/tune/sof_bf_export.m +++ b/src/audio/tdfb/tune/sof_bf_export.m @@ -3,6 +3,8 @@ % Inputs % bf.sofctl3_fn .... filename of ascii text format blob % bf.sofctl4_fn .... filename of ascii text format blob +% bf.ucmbin3_fn .... filename of binary format blob for UCM (IPC3) +% bf.ucmbin4_fn .... filename of binary format blob for UCM (IPC4) % bf.tplg1_fn ...... filename of topology m4 format blob % bf.tplg2_fn ...... filename of topology m4 format blob % bf ............... the design procedure output @@ -116,6 +118,18 @@ tplg2_write(bf.tplg2_fn, bp4, "tdfb_config", export_note, bf.export_howto); end +if ~isempty(bf.ucmbin3_fn) + fprintf(1, 'Exporting to %s\n', bf.ucmbin3_fn); + mkdir_check(bf.sofctl3_path); + sof_ucm_blob_write(bf.ucmbin3_fn, bp3); +end + +if ~isempty(bf.ucmbin4_fn) + fprintf(1, 'Exporting to %s\n', bf.ucmbin4_fn); + mkdir_check(bf.sofctl4_path); + sof_ucm_blob_write(bf.ucmbin4_fn, bp4); +end + sof_bf_paths(false); end diff --git a/src/audio/tdfb/tune/sof_bf_filenames_helper.m b/src/audio/tdfb/tune/sof_bf_filenames_helper.m index 2a206c2e9d51..edab6825d1c3 100644 --- a/src/audio/tdfb/tune/sof_bf_filenames_helper.m +++ b/src/audio/tdfb/tune/sof_bf_filenames_helper.m @@ -53,6 +53,8 @@ bf.sofctl3_fn = fullfile(bf.sofctl3_path, sprintf('coef_%s.txt', idstr)); bf.tplg1_fn = fullfile(bf.tplg1_path, sprintf('coef_%s.m4', idstr)); bf.sofctl4_fn = fullfile(bf.sofctl4_path, sprintf('%s.txt', idstr)); +bf.ucmbin3_fn = fullfile(bf.sofctl3_path, sprintf('%s.bin', idstr)); +bf.ucmbin4_fn = fullfile(bf.sofctl4_path, sprintf('%s.bin', idstr)); bf.tplg2_fn = fullfile(bf.tplg2_path, sprintf('%s.conf', idstr)); diff --git a/src/audio/tdfb/tune/sof_bf_line2_two_beams.m b/src/audio/tdfb/tune/sof_bf_line2_two_beams.m index 7f7eec8dd826..533ed65d1b41 100644 --- a/src/audio/tdfb/tune/sof_bf_line2_two_beams.m +++ b/src/audio/tdfb/tune/sof_bf_line2_two_beams.m @@ -63,6 +63,8 @@ function sof_bf_line2_two_beams(fs, d, a1, a2, fn, prm) 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.ucmbin3_fn = fullfile(bfm.sofctl3_path, fn.ucmbin3_fn); +bfm.ucmbin4_fn = fullfile(bfm.sofctl4_path, fn.ucmbin4_fn); bfm.tplg2_fn = fullfile(bfm.tplg2_path, fn.tplg2_fn); % Export files for topology and sof-ctl diff --git a/src/audio/tdfb/tune/sof_bf_line4_two_beams.m b/src/audio/tdfb/tune/sof_bf_line4_two_beams.m index 9cefc37fc10a..a90b03e26d29 100644 --- a/src/audio/tdfb/tune/sof_bf_line4_two_beams.m +++ b/src/audio/tdfb/tune/sof_bf_line4_two_beams.m @@ -63,6 +63,8 @@ function sof_bf_line4_two_beams(fs, d, a1, a2, fn, prm) 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.ucmbin3_fn = fullfile(bfm.sofctl3_path, fn.ucmbin3_fn); +bfm.ucmbin4_fn = fullfile(bfm.sofctl4_path, fn.ucmbin4_fn); bfm.tplg2_fn = fullfile(bfm.tplg2_path, fn.tplg2_fn); % Export files for topology and sof-ctl diff --git a/src/audio/tdfb/tune/sof_example_pass_config.m b/src/audio/tdfb/tune/sof_example_pass_config.m index 35bba9eb7186..0092f978d73e 100644 --- a/src/audio/tdfb/tune/sof_example_pass_config.m +++ b/src/audio/tdfb/tune/sof_example_pass_config.m @@ -34,6 +34,8 @@ function sof_example_pass_config() bf.sofctl3_fn = fullfile(bf.sofctl3_path, 'coef_line2_pass.txt'); bf.tplg1_fn = fullfile(bf.tplg1_path, 'coef_line2_pass.m4'); bf.sofctl4_fn = fullfile(bf.sofctl4_path, 'line2_pass.txt'); +bf.ucmbin3_fn = fullfile(bf.sofctl3_path, 'line2_pass.bin'); +bf.ucmbin4_fn = fullfile(bf.sofctl4_path, 'line2_pass.bin'); bf.tplg2_fn = fullfile(bf.tplg2_path, 'line2_pass.conf'); sof_bf_export(bf); @@ -52,6 +54,8 @@ function sof_example_pass_config() bf.sofctl3_fn = fullfile(bf.sofctl3_path, 'coef_line4_pass.txt'); bf.tplg1_fn = fullfile(bf.tplg1_path, 'coef_line4_pass.m4'); bf.sofctl4_fn = fullfile(bf.sofctl4_path, 'line4_pass.txt'); +bf.ucmbin3_fn = fullfile(bf.sofctl3_path, 'line4_pass.bin'); +bf.ucmbin4_fn = fullfile(bf.sofctl4_path, 'line4_pass.bin'); bf.tplg2_fn = fullfile(bf.tplg2_path, 'line4_pass.conf'); sof_bf_export(bf); @@ -72,6 +76,8 @@ function sof_example_pass_config() 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.ucmbin3_fn = fullfile(bf.sofctl3_path, 'line4to2_pass.bin'); +bf.ucmbin4_fn = fullfile(bf.sofctl4_path, 'line4to2_pass.bin'); bf.tplg2_fn = fullfile(bf.tplg2_path, 'line4to2_pass.conf'); sof_bf_export(bf); diff --git a/src/audio/tdfb/tune/sof_example_two_beams.m b/src/audio/tdfb/tune/sof_example_two_beams.m index 6b7dab549be5..95b25d080df3 100644 --- a/src/audio/tdfb/tune/sof_example_two_beams.m +++ b/src/audio/tdfb/tune/sof_example_two_beams.m @@ -29,65 +29,37 @@ function sof_example_two_beams() for fs = [16e3 48e3] %% Close all plots to avoid issues with large number of windows close all; + a1 = az; % Azimuth +az deg + a2 = -az; % Azimuth -az deg %% 2 mic 50 mm array - fn.tplg1_fn = sprintf('coef_line2_50mm_pm%sdeg_%dkhz.m4', azstr, fs/1e3); - fn.sofctl3_fn = sprintf('coef_line2_50mm_pm%sdeg_%dkhz.txt', azstr, fs/1e3); - fn.tplg2_fn = sprintf('line2_50mm_pm%sdeg_%dkhz.conf', azstr, fs/1e3); - fn.sofctl4_fn = sprintf('line2_50mm_pm%sdeg_%dkhz.txt', azstr, fs/1e3); d = 50e-3; % 50 mm spacing - a1 = az; % Azimuth +az deg - a2 = -az; % Azimuth -az deg + fn = export_names_helper('line2', azstr, d, fs); 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); - fn.sofctl3_fn = sprintf('coef_line2_68mm_pm%sdeg_%dkhz.txt', azstr, fs/1e3); - fn.tplg2_fn = sprintf('line2_68mm_pm%sdeg_%dkhz.conf', azstr, fs/1e3); - fn.sofctl4_fn = sprintf('line2_68mm_pm%sdeg_%dkhz.txt', azstr, fs/1e3); d = 68e-3; % 68 mm spacing - a1 = az; % Azimuth +az deg - a2 = -az; % Azimuth -az deg + fn = export_names_helper('line2', azstr, d, fs); 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 + fn = export_names_helper('line2', azstr, d, fs); 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); - fn.sofctl3_fn = sprintf('coef_line4_28mm_pm%sdeg_%dkhz.txt', azstr, fs/1e3); - fn.tplg2_fn = sprintf('line4_28mm_pm%sdeg_%dkhz.conf', azstr, fs/1e3); - fn.sofctl4_fn = sprintf('line4_28mm_pm%sdeg_%dkhz.txt', azstr, fs/1e3); d = 28e-3; % 28 mm spacing - a1 = az; % Azimuth +az deg - a2 = -az; % Azimuth -az deg + fn = export_names_helper('line4', azstr, d, fs); 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); - fn.sofctl3_fn = sprintf('coef_line4_68mm_pm%sdeg_%dkhz.txt', azstr, fs/1e3); - fn.tplg2_fn = sprintf('line4_68mm_pm%sdeg_%dkhz.conf', azstr, fs/1e3); - fn.sofctl4_fn = sprintf('line4_68mm_pm%sdeg_%dkhz.txt', azstr, fs/1e3); d = 68e-3; % 68 mm spacing - a1 = az; % Azimuth +az deg - a2 = -az; % Azimuth -az deg + fn = export_names_helper('line4', azstr, d, fs); 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); - fn.sofctl3_fn = sprintf('coef_line4_78mm_pm%sdeg_%dkhz.txt', azstr, fs/1e3); - fn.tplg2_fn = sprintf('line4_78mm_pm%sdeg_%dkhz.conf', azstr, fs/1e3); - fn.sofctl4_fn = sprintf('line4_78mm_pm%sdeg_%dkhz.txt', azstr, fs/1e3); d = 78e-3; % 78 mm spacing - a1 = az; % Azimuth +az deg - a2 = -az; % Azimuth -az deg + fn = export_names_helper('line4', azstr, d, fs); sof_bf_line4_two_beams(fs, d, a1, a2, fn, prm); end @@ -268,3 +240,17 @@ function line_xyz(fs) sof_bf_export(bfm); end + +function fn = export_names_helper(arrayname, azstr, d, fs) + +mmstr = sprintf('%dmm', round(d * 1e3)); +fsstr = sprintf('%dkhz', round(fs/1e3)); +fn.tplg1_fn = sprintf('coef_%s_%s_pm%sdeg_%s.m4', arrayname, mmstr, azstr, fsstr); +fn.tplg2_fn = sprintf('%s_%s_pm%sdeg_%s.conf', arrayname, mmstr, azstr, fsstr); +fn.sofctl3_fn = sprintf('%s_%s_pm%sdeg_%s.txt', arrayname, mmstr, azstr, fsstr); +fn.sofctl4_fn = sprintf('%s_%s_pm%sdeg_%s.txt', arrayname, mmstr, azstr, fsstr); +fn.ucmbin3_fn = sprintf('%s_%s_pm%sdeg_%s.bin', arrayname, mmstr, azstr, fsstr); +fn.ucmbin4_fn = sprintf('%s_%s_pm%sdeg_%s.bin', arrayname, mmstr, azstr, fsstr); + +end + diff --git a/src/audio/tdfb/tune/sof_example_two_beams_default.m b/src/audio/tdfb/tune/sof_example_two_beams_default.m index 65fe1bc41563..779005fcde36 100644 --- a/src/audio/tdfb/tune/sof_example_two_beams_default.m +++ b/src/audio/tdfb/tune/sof_example_two_beams_default.m @@ -35,6 +35,8 @@ function sof_example_two_beams_default() 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); + fn.ucmbin3_fn = sprintf('line2_generic_pm%sdeg_%dkhz.bin', azstr, fs/1e3); + fn.ucmbin4_fn = sprintf('line2_generic_pm%sdeg_%dkhz.bin', azstr, fs/1e3); d = 50e-3; % 50 mm spacing a1 = az; % Azimuth +az deg a2 = -az; % Azimuth -az deg @@ -45,6 +47,8 @@ function sof_example_two_beams_default() 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); + fn.ucmbin3_fn = sprintf('line4_generic_pm%sdeg_%dkhz.bin', azstr, fs/1e3); + fn.ucmbin4_fn = sprintf('line4_generic_pm%sdeg_%dkhz.bin', azstr, fs/1e3); d = 40e-3; % 40 mm spacing a1 = az; % Azimuth +az deg a2 = -az; % Azimuth -az deg From 5f7e422e996609a19631d1da424372fc508fca6a Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Mon, 25 Nov 2024 17:16:29 +0200 Subject: [PATCH 3/3] Audio: TDFB: Tune: Add a README file This patch adds a README.md file that explains how various blob generate scrips are used. Signed-off-by: Seppo Ingalsuo --- src/audio/tdfb/tune/README.md | 41 +++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/audio/tdfb/tune/README.md diff --git a/src/audio/tdfb/tune/README.md b/src/audio/tdfb/tune/README.md new file mode 100644 index 000000000000..342b27d74db8 --- /dev/null +++ b/src/audio/tdfb/tune/README.md @@ -0,0 +1,41 @@ +# Settings blobs generators for TDFB + +This directory contains the scripts to generate settings blobs for +the time-domain fixed beamformer (TDFB) for various microphone array +geometries and beamformer features. + +The requirement is Octave or Matlab with signal processing package. + +The most straightforward way to generate all blobs for topologies, +sof-ctl and UCM is to run command + +``` +./sof_example_all.sh +``` + +It creates the blobs for passthrough mode, single beam blobs for +line and circular arrays, and dual beam blobs for stereo audio +capture. Running it can take about 30 minutes. + +All the topology ASCII text format blobs contain instructions +how to generate them from command line shell. E.g. these +commands do a more fine grained build. + +``` +cd $SOF_WORKSPACE/sof + +# Generate pass-through blobs +cd tools/tune/tdfb; octave --no-window-system example_pass_config.m + +# Generate blobs for line array and single beam +cd tools/tune/tdfb; octave --no-window-system example_line_array.m + +# Generate blobs for stereo capture for arrays with known mm-spacing +cd tools/tune/tdfb; matlab -nodisplay -nosplash -nodesktop -r example_two_beams + +# Generate bobs for stereo capture for generic arrays with known microphones count +cd tools/tune/tdfb; matlab -nodisplay -nosplash -nodesktop -r example_two_beams_default +``` + +Further information about TDFB component is available in SOF Docs, see +https://thesofproject.github.io/latest/algos/tdfb/time_domain_fixed_beamformer.html