From 39edc7a8448c76b00ea4fc1e9c373ec462a9459d Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Fri, 30 Jun 2023 18:53:49 +0300 Subject: [PATCH] Tools: Tune: Update crossover configurations export for tplg2 The script example_crossover.m is converted to export 2, 3, and 4 way crossover configurations for tplg1 and tplg2. The crossover parameters like number of sinks, pipeline ids of sinks, sample rate, and band limits are added to generate blob filenames. The changes include fixes for running the script with Matlab in addition to Octave. Signed-off-by: Seppo Ingalsuo --- tools/tune/crossover/crossover_build_blob.m | 37 ++---- tools/tune/crossover/crossover_coef_quant.m | 2 +- tools/tune/crossover/crossover_gen_coefs.m | 12 +- tools/tune/crossover/crossover_plot_freq.m | 8 +- tools/tune/crossover/example_crossover.m | 130 ++++++++++++++++---- 5 files changed, 124 insertions(+), 65 deletions(-) diff --git a/tools/tune/crossover/crossover_build_blob.m b/tools/tune/crossover/crossover_build_blob.m index eb6e2879a825..e5f48fd61a13 100644 --- a/tools/tune/crossover/crossover_build_blob.m +++ b/tools/tune/crossover/crossover_build_blob.m @@ -1,12 +1,12 @@ -function blob8 = crossover_build_blob(blob_struct, endian) - -%% Settings -bits_R = 32; %Q2.30 -qy_R = 30; +function blob8 = crossover_build_blob(blob_struct, endian, ipc_ver) if nargin < 2 - endian = 'little' -endif + endian = 'little'; +end + +if nargin < 3 + ipc_ver = 3; +end %% Shift values for little/big endian switch lower(endian) @@ -21,7 +21,7 @@ %% Build Blob % refer to sof/src/include/user/crossover.h for the config struct. data_size = 4 * (2 + 4 + 4 + numel(blob_struct.all_coef)); -[abi_bytes, abi_size] = crossover_get_abi(data_size); +[abi_bytes, abi_size] = get_abi(data_size, ipc_ver); blob_size = data_size + abi_size; blob8 = uint8(zeros(1, blob_size)); @@ -49,7 +49,7 @@ j=j+4; end -endfunction +end function bytes = word2byte(word, sh) bytes = uint8(zeros(1,4)); @@ -58,22 +58,3 @@ bytes(3) = bitand(bitshift(word, sh(3)), 255); bytes(4) = bitand(bitshift(word, sh(4)), 255); end - -function [bytes, nbytes] = crossover_get_abi(setsize) - -%% Return current SOF ABI header -%% Use sof-ctl to write ABI header into a file -abifn = 'crossover_get_abi.bin'; -cmd = sprintf('sof-ctl -g %d -b -o %s', setsize, abifn); -system(cmd); - -%% Read file and delete it -fh = fopen(abifn, 'r'); -if fh < 0 - error("Failed to get ABI header. Is sof-ctl installed?"); -end -[bytes, nbytes] = fread(fh, inf, 'uint8'); -fclose(fh); -delete(abifn); - -end diff --git a/tools/tune/crossover/crossover_coef_quant.m b/tools/tune/crossover/crossover_coef_quant.m index 1546845268db..f7ff948a1789 100644 --- a/tools/tune/crossover/crossover_coef_quant.m +++ b/tools/tune/crossover/crossover_coef_quant.m @@ -5,7 +5,7 @@ addpath ./../eq -if length(lowpass) != length(highpass) +if length(lowpass) ~= length(highpass) error("length of lowpass and highpass array do not match"); end diff --git a/tools/tune/crossover/crossover_gen_coefs.m b/tools/tune/crossover/crossover_gen_coefs.m index 10e00bf04d63..99ec9d829563 100644 --- a/tools/tune/crossover/crossover_gen_coefs.m +++ b/tools/tune/crossover/crossover_gen_coefs.m @@ -1,4 +1,4 @@ -function crossover = crossover_gen_coefs(fs, fc_low, fc_mid, fc_high); +function crossover = crossover_gen_coefs(fs, fc_low, fc_mid, fc_high) addpath ./../eq/ switch nargin @@ -10,19 +10,19 @@ rmpath ./../eq end -function crossover_2way = crossover_generate_2way(fs, fc); +function crossover_2way = crossover_generate_2way(fs, fc) crossover_2way.lp = [lp_iir(fs, fc, 0)]; crossover_2way.hp = [hp_iir(fs, fc, 0)]; end -function crossover_3way = crossover_generate_3way(fs, fc_low, fc_high); +function crossover_3way = crossover_generate_3way(fs, fc_low, fc_high) % Duplicate one set of coefficients. The duplicate set will be used to merge back the % output that is out of phase. crossover_3way.lp = [lp_iir(fs, fc_low, 0) lp_iir(fs, fc_high, 0) lp_iir(fs, fc_high, 0)]; crossover_3way.hp = [hp_iir(fs, fc_low, 0) hp_iir(fs, fc_high, 0) hp_iir(fs, fc_high, 0)]; end -function crossover_4way = crossover_generate_4way(fs, fc_low, fc_mid, fc_high); +function crossover_4way = crossover_generate_4way(fs, fc_low, fc_mid, fc_high) crossover_4way.lp = [lp_iir(fs, fc_low, 0) lp_iir(fs, fc_mid, 0) lp_iir(fs, fc_high, 0)]; crossover_4way.hp = [hp_iir(fs, fc_low, 0) hp_iir(fs, fc_mid, 0) hp_iir(fs, fc_high, 0)]; end @@ -54,7 +54,7 @@ b = [1 - cutoff, 0, 0]; a = [1, 0, 0]; return; - endif + end % Compute biquad coefficients for highpass filter resonance = max(0.0, resonance); % can't go negative @@ -90,7 +90,7 @@ b = [cutoff, 0, 0]; a = [1, 0, 0]; return; - endif + end % Compute biquad coefficients for lowpass filter resonance = max(0.0, resonance); % can't go negative diff --git a/tools/tune/crossover/crossover_plot_freq.m b/tools/tune/crossover/crossover_plot_freq.m index c75e18536e8b..026d37d424cc 100644 --- a/tools/tune/crossover/crossover_plot_freq.m +++ b/tools/tune/crossover/crossover_plot_freq.m @@ -18,6 +18,8 @@ % Then to plot the transferfn for y1 we would create a filter such as: % x(n) ---> LR4 LO-PASS --> LR4 LO-PASS --> y1(n) +figure; + f = linspace(1, fs/2, 500); if num_sinks == 2 @@ -63,11 +65,11 @@ end end -function [h12, w] = cascade_bqs_fr(f, fs, varargin); +function [h12, w] = cascade_bqs_fr(f, fs, varargin) bq1 = varargin{1}; bq2 = varargin{2}; -[h1, w] = freqz(bq1.b, bq1.a, f, fs); -[h2, w] = freqz(bq2.b, bq2.a, f, fs); +[h1, w1] = freqz(bq1.b, bq1.a, f, fs); +[h2, w2] = freqz(bq2.b, bq2.a, f, fs); h12 = h1.*h2; for i=3:length(varargin) bq = varargin{i}; diff --git a/tools/tune/crossover/example_crossover.m b/tools/tune/crossover/example_crossover.m index d46be04a6f0b..6bdf596abc45 100644 --- a/tools/tune/crossover/example_crossover.m +++ b/tools/tune/crossover/example_crossover.m @@ -1,54 +1,130 @@ -function example_crossover(); +function example_crossover() -% Set the parameters here -tplg_fn = "../../topology/topology1/m4/crossover_coef_default.m4" % Control Bytes File -% Use those files with sof-ctl to update the component's configuration -blob_fn = "../../ctl/crossover_coef.blob" % Blob binary file -alsa_fn = "../../ctl/crossover_coef.txt" % ALSA CSV format file +addpath ./../common + +% Sampling Frequency and Frequency cut-offs for crossover +cr.fs = 48e3; +cr.fc_low = 200; +cr.fc_med = 1000; +cr.fc_high = 3000; + +% 2 way crossover, pipeline IDs of sinks are 1 and 2 (IPC3) +% and component output pins 0 and 1 (IPC4) +cr.num_sinks = 2; +cr.sinks = [1 2]; +export_crossover(cr); +cr.sinks = [0 1]; +export_crossover(cr); + +% 3 way crossover, pipeline IDs of sinks are 1 - 3 +cr.num_sinks = 3; +cr.sinks = [1 2 3]; +export_crossover(cr); +cr.sinks = [0 1 2]; +export_crossover(cr); + +% 4 way crossover, pipeline IDs of sinks are 1 - 4 +cr.num_sinks = 4; +cr.sinks = [1 2 3 4]; +export_crossover(cr); +cr.sinks = [0 1 2 3]; +export_crossover(cr); + +rmpath ./../common + +end + +function export_crossover(cr) endian = "little"; +tpath1 = '../../topology/topology1/m4/crossover'; +tpath2 = '../../topology/topology2/include/components/crossover'; +ctlpath = '../../ctl/ipc3'; -% Sampling Frequency and Frequency cut-offs for crossover -fs = 48e3; -fc_low = 200; -fc_med = 1000; -fc_high = 3000; +str_way = sprintf('%dway', cr.num_sinks); +str_freq = get_str_freq(cr); +str_pid = get_str_pid(cr); + +% Set the parameters here +tplg1_fn = sprintf('%s/coef_%s_%s_%s.m4', tpath1, str_way, str_freq, str_pid); % Control Bytes File +tplg2_fn = sprintf('%s/coef_%s_%s_%s.conf', tpath2, str_way, str_freq, str_pid); +% Use those files with sof-ctl to update the component's configuration +blob_fn = sprintf('%s/crossover_coef_%dway.blob', ctlpath, cr.num_sinks); % Blob binary file +alsa_fn = sprintf('%s/crossover_coef_%dway.txt', ctlpath, cr.num_sinks); % ALSA CSV format file -% 4 way crossover -num_sinks = 4; % This array is an example on how to assign a buffer from pipeline 1 to output 0, % buffer from pipeline 2 to output 1, etc... % Refer to sof/src/include/user/crossover.h for more information on assigning % buffers to outputs. assign_sinks = zeros(1, 4); -assign_sinks(1) = 1; % sink[0] -assign_sinks(2) = 2; % sink[1] -assign_sinks(3) = 3; % sink[2] -assign_sinks(4) = 4; % sink[3] +assign_sinks(1:cr.num_sinks) = cr.sinks; % Generate zeros, poles and gain for crossover with the given frequencies -%crossover = crossover_gen_coefs(fs, fc_low); % 2 way crossover -% crossover = crossover_gen_coefs(fs, fc_low, fc_med); % 3 way crossover -crossover = crossover_gen_coefs(fs, fc_low, fc_med, fc_high); % 4 way crossover +switch cr.num_sinks + case 2 + crossover = crossover_gen_coefs(cr.fs, cr.fc_low); % 2 way crossover + case 3 + crossover = crossover_gen_coefs(cr.fs, cr.fc_low, cr.fc_med); % 3 way crossover + case 4 + crossover = crossover_gen_coefs(cr.fs, cr.fc_low, cr.fc_med, cr.fc_high); % 4 way crossover + otherwise + error('Illegal number of sinks %d\n', num_sinks); +end % Convert the [a,b] coefficients to values usable with SOF crossover_bqs = crossover_coef_quant(crossover.lp, crossover.hp); % Convert coefficients to sof_crossover_config struct -config = crossover_generate_config(crossover_bqs, num_sinks, assign_sinks); +config = crossover_generate_config(crossover_bqs, cr.num_sinks, assign_sinks); % Convert struct to binary blob -blob8 = crossover_build_blob(config, endian); +blob8 = crossover_build_blob(config, endian, 3); +blob8_ipc4 = crossover_build_blob(config, endian, 4); % Generate output files -addpath ./../common -tplg_write(tplg_fn, blob8, "CROSSOVER"); +mkdir_check(tpath1); +mkdir_check(tpath2); +mkdir_check(ctlpath); +tplg_write(tplg1_fn, blob8, "CROSSOVER"); +tplg2_write(tplg2_fn, blob8_ipc4, "crossover_config", 'Exported Control Bytes'); blob_write(blob_fn, blob8); alsactl_write(alsa_fn, blob8); % Plot Magnitude and Phase Response of each sink -crossover_plot_freq(crossover.lp, crossover.hp, fs, num_sinks); -rmpath ./../common +crossover_plot_freq(crossover.lp, crossover.hp, cr.fs, cr.num_sinks); + +end + +% Frequencies part for filename +function str = get_str_freq(cr) + +switch cr.num_sinks + case 2 + str = sprintf('%d_%d', cr.fs, cr.fc_low); + case 3 + str = sprintf('%d_%d_%d', cr.fs, cr.fc_low, cr.fc_med); + case 4 + str = sprintf('%d_%d_%d_%d', cr.fs, cr.fc_low, cr.fc_med, cr.fc_high); +end + +end + +% Pipeline IDs part of filename +function str = get_str_pid(cr) + +str = sprintf('%d', cr.sinks(1)); +for i = 2:cr.num_sinks + str = sprintf('%s_%d', str, cr.sinks(i)); +end + +end + +% Check if directory exists, avoid warning print for existing +function mkdir_check(new_dir) + + if ~exist(new_dir, 'dir') + mkdir(new_dir); + end -endfunction +end