1%% Design demo EQs and bundle them to parameter block
2
3% SPDX-License-Identifier: BSD-3-Clause
4%
5% Copyright (c) 2016-2020, Intel Corporation. All rights reserved.
6%
7% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
8
9function example_fir_eq()
10
11%% Common definitions
12fs = 48e3;
13tpath =  '../../topology/topology1/m4';
14cpath = '../../ctl';
15priv = 'DEF_EQFIR_PRIV';
16
17%% -------------------
18%% Example 1: Loudness
19%% -------------------
20blob_fn = fullfile(cpath, 'eq_fir_loudness.bin');
21alsa_fn = fullfile(cpath, 'eq_fir_loudness.txt');
22tplg_fn = fullfile(tpath, 'eq_fir_coef_loudness.m4');
23comment = 'Loudness effect, created with example_fir_eq.m';
24
25%% Design FIR loudness equalizer
26eq_loud = loudness_fir_eq(fs);
27
28%% Define a passthru EQ with one tap
29b_pass = 1;
30
31%% Quantize filter coefficients for both equalizers
32bq_pass = eq_fir_blob_quant(b_pass);
33bq_loud = eq_fir_blob_quant(eq_loud.b_fir);
34
35%% Build blob
36channels_in_config = 4;      % Setup max 4 channels EQ
37assign_response = [1 1 1 1]; % Switch to response #1
38num_responses = 2;           % Two responses pass, loud
39bm = eq_fir_blob_merge(channels_in_config, ...
40		       num_responses, ...
41		       assign_response, ...
42		       [ bq_pass bq_loud ]);
43
44%% Pack and write file
45eq_pack_export(bm, blob_fn, alsa_fn, tplg_fn, priv, comment);
46
47%% -------------------
48%% Example 2: Mid boost
49%% -------------------
50blob_fn = fullfile(cpath, 'eq_fir_mid.bin');
51alsa_fn = fullfile(cpath, 'eq_fir_mid.txt');
52tplg_fn = fullfile(tpath, 'eq_fir_coef_mid.m4');
53comment = 'Mid boost, created with example_fir_eq.m';
54
55%% Define mid frequencies boost EQ
56eq_mid = midboost_fir_eq(fs);
57
58%% Quantize filter coefficients for both equalizers
59bq_pass = eq_fir_blob_quant(eq_mid.b_fir);
60
61%% Build blob
62channels_in_config = 2;    % Setup max 2 channels EQ
63assign_response = [0 0];   % Switch to response #0
64num_responses = 1;         % One response: pass
65bm = eq_fir_blob_merge(channels_in_config, ...
66		       num_responses, ...
67		       assign_response, ...
68		       bq_pass);
69
70%% Pack and write file
71eq_pack_export(bm, blob_fn, alsa_fn, tplg_fn, priv, comment);
72
73%% -------------------
74%% Example 3: Flat EQ
75%% -------------------
76blob_fn = fullfile(cpath, 'eq_fir_flat.bin');
77alsa_fn = fullfile(cpath, 'eq_fir_flat.txt');
78tplg_fn = fullfile(tpath, 'eq_fir_coef_flat.m4');
79comment = 'Flat response, created with example_fir_eq.m';
80
81%% Define a passthru EQ with one tap
82b_pass = 1;
83
84%% Quantize filter coefficients for both equalizers
85bq_pass = eq_fir_blob_quant(b_pass);
86
87%% Build blob
88channels_in_config = 2;    % Setup max 2 channels EQ
89assign_response = [0 0];   % Switch to response #0
90num_responses = 1;         % One response: pass
91bm = eq_fir_blob_merge(channels_in_config, ...
92		       num_responses, ...
93		       assign_response, ...
94		       bq_pass);
95
96%% Pack and write file
97eq_pack_export(bm, blob_fn, alsa_fn, tplg_fn, priv, comment);
98
99%% --------------------------
100%% Example 4: Pass-through EQ
101%% --------------------------
102blob_fn = fullfile(cpath, 'eq_fir_pass.bin');
103alsa_fn = fullfile(cpath, 'eq_fir_pass.txt');
104tplg_fn = fullfile(tpath, 'eq_fir_coef_pass.m4');
105comment = 'Pass-through response, created with example_fir_eq.m';
106
107%% Define a passthru EQ with one tap
108b_pass = 1;
109
110%% Quantize filter coefficients for both equalizers
111bq_pass = eq_fir_blob_quant(b_pass);
112
113%% Build blob
114channels_in_config = 2;    % Setup max 2 channels EQ
115assign_response = [-1 -1]; % Switch to response #0
116num_responses = 1;         % One response: pass
117bm = eq_fir_blob_merge(channels_in_config, ...
118		       num_responses, ...
119		       assign_response, ...
120		       bq_pass);
121
122%% Pack and write file
123eq_pack_export(bm, blob_fn, alsa_fn, tplg_fn, priv, comment);
124
125
126%% --------------------------
127%% Done.
128%% --------------------------
129
130end
131
132%% -------------------
133%% EQ design functions
134%% -------------------
135
136function eq = loudness_fir_eq(fs)
137
138%% Derived from Fletcher-Munson curves for 80 and 60 phon
139f = [ 20,21,22,24,25,27,28,30,32,34,36,38,40,43,45,48,51,54,57,60,64, ...
140        68,72,76,81,85,90,96,102,108,114,121,128,136,144,153,162,171, ...
141        182,192,204,216,229,243,257,273,289,306,324,344,364,386,409, ...
142        434,460,487,516,547,580,614,651,690,731,775,821,870,922,977, ...
143        1036,1098,1163,1233,1307,1385,1467,1555,1648,1747,1851,1962, ...
144        2079,2203,2335,2474,2622,2779,2945,3121,3308,3505,3715,3937, ...
145        4172,4421,4686,4966,5263,5577,5910,6264,6638,7035,7455,7901, ...
146        8373,8873,9404,9966,10561,11193,11861,12570,13322,14118,14962, ...
147        15856,16803,17808,18872,20000];
148
149m = [ 0.00,-0.13,-0.27,-0.39,-0.52,-0.64,-0.77,-0.89,-1.02,-1.16,  ...
150        -1.31,-1.46,-1.61,-1.76,-1.91,-2.07,-2.24,-2.43,-2.64,-2.85, ...
151        -3.04,-3.21,-3.35,-3.48,-3.62,-3.78,-3.96,-4.16,-4.35,-4.54, ...
152        -4.72,-4.90,-5.08,-5.26,-5.45,-5.64,-5.83,-6.02,-6.19,-6.37, ...
153        -6.57,-6.77,-6.98,-7.19,-7.40,-7.58,-7.76,-7.92,-8.08,-8.25, ...
154        -8.43,-8.60,-8.76,-8.92,-9.08,-9.23,-9.38,-9.54,-9.69,-9.84, ...
155        -9.97,-10.09,-10.18,-10.26,-10.33,-10.38,-10.43,-10.48,-10.54, ...
156        -10.61,-10.70,-10.78,-10.85,-10.91,-10.95,-10.98,-11.02, ...
157        -11.05,-11.07,-11.10,-11.11,-11.11,-11.10,-11.10,-11.11, ...
158        -11.14,-11.17,-11.20,-11.21,-11.22,-11.21,-11.20,-11.20, ...
159        -11.21,-11.21,-11.20,-11.17,-11.11,-11.02,-10.91,-10.78, ...
160        -10.63,-10.46,-10.25,-10.00,-9.72,-9.39,-9.02,-8.62,-8.19, ...
161        -7.73,-7.25,-6.75,-6.25,-5.75,-5.28,-4.87,-4.54,-4.33,-4.30];
162
163%% Design EQ
164eq = eq_defaults();
165eq.fs = fs;
166eq.target_f = f;            % Set EQ frequency response target: frequencies Hz
167eq.target_m_db = m;         % Set EQ frequency response target: magnitudues dB
168eq.norm_type = 'loudness';  % Normalize criteria can be loudness/peak/1k
169eq.norm_offs_db = 0;        % Offset in dB to normalize
170
171eq.enable_fir = 1;          % By default both FIR and IIR disabled, enable one
172eq.fir_beta = 4.0;          % Use with care, low value can corrupt
173eq.fir_length = 86;         % Gives just < 292 bytes
174eq.fir_autoband = 0;        % Select manually frequency limits
175eq.fmin_fir = 100;          % Equalization starts from 100 Hz
176eq.fmax_fir = 20e3;         % Equalization ends at 20 kHz
177eq.fir_minph = 1;           % Check result carefully if 1 is used, 0 is safe
178eq = eq_compute(eq);
179
180%% Plot
181eq_plot(eq);
182
183end
184
185function eq = midboost_fir_eq(fs)
186
187eq = eq_defaults();
188
189eq.parametric_target_response = [ ...
190					eq.PEQ_LS2 1200 -12 NaN ; ...
191					eq.PEQ_HS2 7000 -12 NaN ; ...
192				];
193
194%% Design EQ
195eq.fs = fs;
196eq.norm_type = 'peak'; % Can be loudness/peak/1k to select normalize criteria
197eq.norm_offs_db = 0;   % E.g. -1 would leave 1 dB headroom if used with peak
198
199eq.enable_fir = 1;     % By default both FIR and IIR disabled, enable one
200eq.fir_beta = 3.5;     % Use with care, low value can corrupt
201eq.fir_length = 39;    % At limit of xtensa-gcc build speed
202eq.fir_autoband = 0;   % Select manually frequency limits
203eq.fmin_fir = 100;     % Equalization starts from 100 Hz
204eq.fmax_fir = 20e3;    % Equalization ends at 20 kHz
205eq.fir_minph = 1;      % If no linear phase required can test with 1
206eq = eq_compute(eq);
207
208%% Plot
209eq_plot(eq);
210
211end
212
213% Pack and write file common function for all exports
214function eq_pack_export(bm, bin_fn, ascii_fn, tplg_fn, priv, note)
215
216bp = eq_fir_blob_pack(bm);
217
218if ~isempty(bin_fn)
219	eq_blob_write(bin_fn, bp);
220end
221
222if ~isempty(ascii_fn)
223	eq_alsactl_write(ascii_fn, bp);
224end
225
226if ~isempty(tplg_fn)
227	eq_tplg_write(tplg_fn, bp, priv, note);
228end
229
230end
231