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 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 new file mode 100644 index 000000000000..533ed65d1b41 --- /dev/null +++ b/src/audio/tdfb/tune/sof_bf_line2_two_beams.m @@ -0,0 +1,75 @@ +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.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 +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..a90b03e26d29 --- /dev/null +++ b/src/audio/tdfb/tune/sof_bf_line4_two_beams.m @@ -0,0 +1,75 @@ +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.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 +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..0092f978d73e 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 @@ -32,12 +34,14 @@ 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); % 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 @@ -50,7 +54,31 @@ 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); + +% 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.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); + 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..95b25d080df3 100644 --- a/src/audio/tdfb/tune/sof_example_two_beams.m +++ b/src/audio/tdfb/tune/sof_example_two_beams.m @@ -20,65 +20,54 @@ 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; + 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 - line2_two_beams(fs, d, a1, a2, fn, 1); + 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 - line2_two_beams(fs, d, a1, a2, fn, 1); + 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 + d = 73.5e-3; % 73.5 mm spacing + 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 - line4_two_beams(fs, d, a1, a2, fn, 1); + 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 - line4_two_beams(fs, d, a1, a2, fn, 1); + 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 - line4_two_beams(fs, d, a1, a2, fn, 1); + fn = export_names_helper('line4', azstr, d, fs); + 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 +77,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 +87,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 +115,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 @@ -358,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 new file mode 100644 index 000000000000..779005fcde36 --- /dev/null +++ b/src/audio/tdfb/tune/sof_example_two_beams_default.m @@ -0,0 +1,65 @@ +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); + 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 + 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); + 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 + 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