sof/tools/tune/eq/example_spk_eq.m

162 lines
6.3 KiB
Matlab

function example_spk_eq()
%% Design an example speaker equalizer with the provided sample data
% This equalizer by default uses a FIR and IIR components those should be
% both in the speaker pipeline.
%
% Note that IIR should be first since the included band-pass response provides
% signal headroom.
% SPDX-License-Identifier: BSD-3-Clause
%
% Copyright (c) 2016-2020, Intel Corporation. All rights reserved.
%
% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
%% Defaults
fs = 48e3;
fn.cpath3 = '../../ctl/ipc3';
fn.cpath4 = '../../ctl/ipc4';
fn.tpath1 = '../../topology/topology1/m4';
fir.tpath2 = '../../topology/topology2/include/components/eqfir';
iir.tpath2 = '../../topology/topology2/include/components/eqiir';
iir.priv = 'DEF_EQIIR_PRIV';
fir.priv = 'DEF_EQFIR_PRIV';
iir.comment = 'Speaker FIR+IIR EQ created with example_spk_eq.m';
fir.comment = 'Speaker FIR+IIR EQ created with example_spk_eq.m';
%% File names
fir.txt = 'eq_fir_spk.txt';
fir.bin = 'eq_fir_spk.bin';
fir.tplg1 = 'eq_fir_coef_spk.m4';
fir.tplg2 = 'example_speaker.conf';
iir.txt = 'eq_fir_spk.txt';
iir.bin = 'eq_fir_spk.bin';
iir.tplg1 = 'eq_fir_coef_spk.m4';
iir.tplg2 = 'example_speaker.conf';
%% Get defaults for equalizer design
eq = eq_defaults();
%% Settings for this EQ
eq.fs = fs; % Default sample rate in SOF
eq.enable_fir = 1; % Try enabling and disabling FIR part
eq.enable_iir = 1; % Try enabling and disabling IIR part
eq.norm_type = 'peak'; % Scale filters to have peak at 0 dB
eq.norm_offs_db = 0; % Can be used to control gain
eq.p_fmin = 100; % With this data start plots from 100 Hz
eq.p_fmax = 20e3; % and end to 20 kHz.
%% Get acousticial frequency response measurement data. This is
% a quite typical response for a miniature speaker. Alternatively
% the response could be read from spreadsheet column format that is
% commonly supported by audio measurement equipment. Then extract
% the frequency and magnitude columns. E.g.
%
% data = xlsread('spkr.xlsx', 1, 'A5:B78');
% eq.raw_f = data(:,1);
% eq.raw_m_db = data(:,2);
eq.raw_f = [ ...
298.533, 316.232, 334.971, 354.813, 375.838, 398.106, ...
421.699, 446.685, 473.153, 501.186, 530.887, 562.342, ...
595.663, 630.958, 668.345, 707.946, 749.895, 794.329, ...
841.397, 891.252, 944.062, 1000, 1059.26, 1122.02, ...
1188.5, 1258.93, 1333.52, 1412.54, 1496.24, 1584.9, ...
1678.81, 1778.28, 1883.65, 1995.27, 2113.49, 2238.72, ...
2371.38, 2511.89, 2660.73, 2818.39, 2985.39, 3162.28, ...
3349.66, 3548.14, 3758.38, 3981.08, 4216.97, 4466.84, ...
4731.52, 5011.88, 5308.85, 5623.42, 5956.63, 6309.58, ...
6683.45, 7079.47, 7498.95, 7943.3, 8413.97, 8912.52, ...
9440.62, 10000, 10592.6, 11220.2, 11885, 12589.3, ...
13335.2, 14125.4, 14962.4, 15849, 16788.1, 17782.8, ...
18836.5, 19952.7 ...
];
eq.raw_m_db = [ ...
58.1704, 60.074, 60.4541, 61.3079, 62.8198, 64.3749, ...
65.1556, 66.512, 67.5916, 68.6344, 69.9276, 70.7658, ...
71.1125, 72.0627, 73.5348, 75.4887, 77.3088, 79.1541, ...
80.9627, 82.0607, 81.943, 81.2228, 81.9497, 83.1848, ...
84.3375, 85.4993, 86.4642, 87.1179, 87.4424, 87.53, ...
85.7425, 85.0095, 82.9405, 82.9242, 82.7327, 83.6423, ...
83.2839, 82.4201, 84.1403, 84.6485, 83.9274, 83.3366, ...
83.3005, 84.2598, 85.1544, 86.015, 86.6519, 87.2118, ...
87.5498, 88.1742, 88.5215, 88.3801, 89.8762, 91.4418, ...
93.1845, 94.3355, 95.0918, 95.0258, 94.0337, 91.1068, ...
88.7303, 87.4853, 86.2916, 83.037, 79.8056, 78.2022, ...
76.0341, 74.5674, 69.2288, 56.1308, 68.697, 69.687, ...
68.0005, 64.698 ...
];
%% With parametric IIR EQ try to place peaking EQ at
% resonant frequencies 1.4 kHz and 7.5 kHz. The gain
% and Q values were experimented manually. Additionally
% The lowest and highest frequeciens below and above speaker
% capability are attenuated with high-pass and low-pass
% filtering.
if eq.enable_iir;
eq.peq = [ ...
eq.PEQ_HP2 100 NaN NaN; ...
eq.PEQ_PN2 1480 -7 2.0; ...
eq.PEQ_PN2 7600 -11 1.3; ...
eq.PEQ_LP2 14500 NaN NaN; ...
];
end
%% With FIR EQ try to flatten frequency response within
% 1 - 13 kHz frequency band.
if eq.enable_fir
eq.fir_minph = 1;
eq.fir_beta = 4;
eq.fir_length = 63;
eq.fir_autoband = 0;
eq.fmin_fir = 900;
eq.fmax_fir = 10700;
end
%% Design EQ
eq = eq_compute(eq);
%% Plot
eq_plot(eq, 1);
%% Export FIR part
channels_in_config = 2; % Identical two speakers
assign_response = [0 0]; % Switch to response #0
num_responses = 1; % Single response
if eq.enable_fir
bq_fir = eq_fir_blob_quant(eq.b_fir);
bm_fir = eq_fir_blob_merge(channels_in_config, ...
num_responses, ...
assign_response, ...
[ bq_fir ]);
bp_fir = eq_fir_blob_pack(bm_fir, 3); % IPC3
eq_alsactl_write(fullfile(fn.cpath3, fir.txt), bp_fir);
eq_blob_write(fullfile(fn.cpath3, fir.bin), bp_fir);
eq_tplg_write(fullfile(fn.tpath1, fir.tplg1), bp_fir, fir.priv, fir.comment);
bp_fir = eq_fir_blob_pack(bm_fir, 4); % IPC4
eq_alsactl_write(fullfile(fn.cpath4, fir.txt), bp_fir);
eq_blob_write(fullfile(fn.cpath4, fir.bin), bp_fir);
eq_tplg2_write(fullfile(fir.tpath2, fir.tplg2), bp_fir, 'eq_fir', fir.comment);
end
%% Export IIR part
if eq.enable_iir
bq_iir = eq_iir_blob_quant(eq.p_z, eq.p_p, eq.p_k);
bm_iir = eq_iir_blob_merge(channels_in_config, ...
num_responses, ...
assign_response, ...
[ bq_iir ]);
bp_iir = eq_iir_blob_pack(bm_iir, 3); % IPC3
eq_alsactl_write(fullfile(fn.cpath3, iir.txt), bp_iir);
eq_blob_write(fullfile(fn.cpath3, iir.bin), bp_iir);
eq_tplg_write(fullfile(fn.tpath1, iir.tplg1), bp_iir, iir.priv, iir.comment);
bp_iir = eq_iir_blob_pack(bm_iir, 4); % IPC4
eq_alsactl_write(fullfile(fn.cpath4, iir.txt), bp_iir);
eq_blob_write(fullfile(fn.cpath4, iir.bin), bp_iir);
eq_tplg2_write(fullfile(iir.tpath2, iir.tplg2), bp_iir, 'eq_iir', iir.comment);
end
end