1 /* libSoX Biquad filter effects   (c) 2006-8 robs@users.sourceforge.net
2  *
3  * This library is free software; you can redistribute it and/or modify it
4  * under the terms of the GNU Lesser General Public License as published by
5  * the Free Software Foundation; either version 2.1 of the License, or (at
6  * your option) any later version.
7  *
8  * This library is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this library; if not, write to the Free Software Foundation,
15  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
16  *
17  *
18  * 2-pole filters designed by Robert Bristow-Johnson <rbj@audioimagination.com>
19  *   see https://webaudio.github.io/Audio-EQ-Cookbook/audio-eq-cookbook.html
20  *
21  * 1-pole filters based on code (c) 2000 Chris Bagwell <cbagwell@sprynet.com>
22  *   Algorithms: Recursive single pole low/high pass filter
23  *   Reference: The Scientist and Engineer's Guide to Digital Signal Processing
24  *
25  *   low-pass: output[N] = input[N] * A + output[N-1] * B
26  *     X = exp(-2.0 * pi * Fc)
27  *     A = 1 - X
28  *     B = X
29  *     Fc = cutoff freq / sample rate
30  *
31  *     Mimics an RC low-pass filter:
32  *
33  *     ---/\/\/\/\----------->
34  *                   |
35  *                  --- C
36  *                  ---
37  *                   |
38  *                   |
39  *                   V
40  *
41  *   high-pass: output[N] = A0 * input[N] + A1 * input[N-1] + B1 * output[N-1]
42  *     X  = exp(-2.0 * pi * Fc)
43  *     A0 = (1 + X) / 2
44  *     A1 = -(1 + X) / 2
45  *     B1 = X
46  *     Fc = cutoff freq / sample rate
47  *
48  *     Mimics an RC high-pass filter:
49  *
50  *         || C
51  *     ----||--------->
52  *         ||    |
53  *               <
54  *               > R
55  *               <
56  *               |
57  *               V
58  */
59 
60 
61 #include "biquad.h"
62 #include <assert.h>
63 #include <string.h>
64 
65 typedef biquad_t priv_t;
66 
67 
hilo1_getopts(sox_effect_t * effp,int argc,char ** argv)68 static int hilo1_getopts(sox_effect_t * effp, int argc, char **argv) {
69   return lsx_biquad_getopts(effp, argc, argv, 1, 1, 0, 1, 2, "",
70       *effp->handler.name == 'l'? filter_LPF_1 : filter_HPF_1);
71 }
72 
73 
hilo2_getopts(sox_effect_t * effp,int argc,char ** argv)74 static int hilo2_getopts(sox_effect_t * effp, int argc, char **argv) {
75   priv_t * p = (priv_t *)effp->priv;
76   if (argc > 1 && strcmp(argv[1], "-1") == 0)
77     return hilo1_getopts(effp, argc - 1, argv + 1);
78   if (argc > 1 && strcmp(argv[1], "-2") == 0)
79     ++argv, --argc;
80   p->width = sqrt(0.5); /* Default to Butterworth */
81   return lsx_biquad_getopts(effp, argc, argv, 1, 2, 0, 1, 2, "qohk",
82       *effp->handler.name == 'l'? filter_LPF : filter_HPF);
83 }
84 
85 
bandpass_getopts(sox_effect_t * effp,int argc,char ** argv)86 static int bandpass_getopts(sox_effect_t * effp, int argc, char **argv) {
87   filter_t type = filter_BPF;
88   if (argc > 1 && strcmp(argv[1], "-c") == 0)
89     ++argv, --argc, type = filter_BPF_CSG;
90   return lsx_biquad_getopts(effp, argc, argv, 2, 2, 0, 1, 2, "hkqob", type);
91 }
92 
93 
bandrej_getopts(sox_effect_t * effp,int argc,char ** argv)94 static int bandrej_getopts(sox_effect_t * effp, int argc, char **argv) {
95   return lsx_biquad_getopts(effp, argc, argv, 2, 2, 0, 1, 2, "hkqob", filter_notch);
96 }
97 
98 
allpass_getopts(sox_effect_t * effp,int argc,char ** argv)99 static int allpass_getopts(sox_effect_t * effp, int argc, char **argv) {
100   filter_t type = filter_APF;
101   int m;
102   if (argc > 1 && strcmp(argv[1], "-1") == 0)
103     ++argv, --argc, type = filter_AP1;
104   else if (argc > 1 && strcmp(argv[1], "-2") == 0)
105     ++argv, --argc, type = filter_AP2;
106   m = 1 + (type == filter_APF);
107   return lsx_biquad_getopts(effp, argc, argv, m, m, 0, 1, 2, "hkqo", type);
108 }
109 
110 
tone_getopts(sox_effect_t * effp,int argc,char ** argv)111 static int tone_getopts(sox_effect_t * effp, int argc, char **argv) {
112   priv_t * p = (priv_t *)effp->priv;
113   p->width = 0.5;
114   p->fc = *effp->handler.name == 'b'? 100 : 3000;
115   return lsx_biquad_getopts(effp, argc, argv, 1, 3, 1, 2, 0, "shkqo",
116       *effp->handler.name == 'b'?  filter_lowShelf: filter_highShelf);
117 }
118 
119 
equalizer_getopts(sox_effect_t * effp,int argc,char ** argv)120 static int equalizer_getopts(sox_effect_t * effp, int argc, char **argv) {
121   return lsx_biquad_getopts(effp, argc, argv, 3, 3, 0, 1, 2, "qohk", filter_peakingEQ);
122 }
123 
124 
band_getopts(sox_effect_t * effp,int argc,char ** argv)125 static int band_getopts(sox_effect_t * effp, int argc, char **argv) {
126   filter_t type = filter_BPF_SPK;
127   if (argc > 1 && strcmp(argv[1], "-n") == 0)
128     ++argv, --argc, type = filter_BPF_SPK_N;
129   return lsx_biquad_getopts(effp, argc, argv, 1, 2, 0, 1, 2, "hkqo", type);
130 }
131 
132 
deemph_getopts(sox_effect_t * effp,int argc,char ** argv)133 static int deemph_getopts(sox_effect_t * effp, int argc, char **argv) {
134   return lsx_biquad_getopts(effp, argc, argv, 0, 0, 0, 1, 2, "s", filter_deemph);
135 }
136 
137 
riaa_getopts(sox_effect_t * effp,int argc,char ** argv)138 static int riaa_getopts(sox_effect_t * effp, int argc, char **argv) {
139   priv_t * p = (priv_t *)effp->priv;
140   p->filter_type = filter_riaa;
141   (void)argv;
142   return --argc? lsx_usage(effp) : SOX_SUCCESS;
143 }
144 
145 
make_poly_from_roots(double const * roots,size_t num_roots,double * poly)146 static void make_poly_from_roots(
147     double const * roots, size_t num_roots, double * poly)
148 {
149   size_t i, j;
150   poly[0] = 1;
151   poly[1] = -roots[0];
152   memset(poly + 2, 0, (num_roots + 1 - 2) * sizeof(*poly));
153   for (i = 1; i < num_roots; ++i)
154     for (j = num_roots; j > 0; --j)
155       poly[j] -= poly[j - 1] * roots[i];
156 }
157 
start(sox_effect_t * effp)158 static int start(sox_effect_t * effp)
159 {
160   priv_t * p = (priv_t *)effp->priv;
161   double w0, A, alpha, mult;
162 
163   if (p->filter_type == filter_deemph) { /* See deemph.plt for documentation */
164     if (effp->in_signal.rate == 44100) {
165       p->fc    = 5283;
166       p->width = 0.4845;
167       p->gain  = -9.477;
168     }
169     else if (effp->in_signal.rate == 48000) {
170       p->fc    = 5356;
171       p->width = 0.479;
172       p->gain  = -9.62;
173     }
174     else {
175       lsx_fail("sample rate must be 44100 (audio-CD) or 48000 (DAT)");
176       return SOX_EOF;
177     }
178   }
179 
180   w0 = 2 * M_PI * p->fc / effp->in_signal.rate;
181   A  = exp(p->gain / 40 * log(10.));
182   alpha = 0, mult = dB_to_linear(max(p->gain, 0));
183 
184   if (w0 > M_PI) {
185     lsx_fail("frequency must be less than half the sample-rate (Nyquist rate)");
186     return SOX_EOF;
187   }
188 
189   /* Set defaults: */
190   p->b0 = p->b1 = p->b2 = p->a1 = p->a2 = 0;
191   p->a0 = 1;
192 
193   if (p->width) switch (p->width_type) {
194     case width_slope:
195       alpha = sin(w0)/2 * sqrt((A + 1/A)*(1/p->width - 1) + 2);
196       break;
197 
198     case width_Q:
199       alpha = sin(w0)/(2*p->width);
200       break;
201 
202     case width_bw_oct:
203       alpha = sin(w0)*sinh(log(2.)/2 * p->width * w0/sin(w0));
204       break;
205 
206     case width_bw_Hz:
207       alpha = sin(w0)/(2*p->fc/p->width);
208       break;
209 
210     case width_bw_kHz: assert(0); /* Shouldn't get here */
211 
212     case width_bw_old:
213       alpha = tan(M_PI * p->width / effp->in_signal.rate);
214       break;
215   }
216   switch (p->filter_type) {
217     case filter_LPF: /* H(s) = 1 / (s^2 + s/Q + 1) */
218       p->b0 =  (1 - cos(w0))/2;
219       p->b1 =   1 - cos(w0);
220       p->b2 =  (1 - cos(w0))/2;
221       p->a0 =   1 + alpha;
222       p->a1 =  -2*cos(w0);
223       p->a2 =   1 - alpha;
224       break;
225 
226     case filter_HPF: /* H(s) = s^2 / (s^2 + s/Q + 1) */
227       p->b0 =  (1 + cos(w0))/2;
228       p->b1 = -(1 + cos(w0));
229       p->b2 =  (1 + cos(w0))/2;
230       p->a0 =   1 + alpha;
231       p->a1 =  -2*cos(w0);
232       p->a2 =   1 - alpha;
233       break;
234 
235     case filter_BPF_CSG: /* H(s) = s / (s^2 + s/Q + 1)  (constant skirt gain, peak gain = Q) */
236       p->b0 =   sin(w0)/2;
237       p->b1 =   0;
238       p->b2 =  -sin(w0)/2;
239       p->a0 =   1 + alpha;
240       p->a1 =  -2*cos(w0);
241       p->a2 =   1 - alpha;
242       break;
243 
244     case filter_BPF: /* H(s) = (s/Q) / (s^2 + s/Q + 1)      (constant 0 dB peak gain) */
245       p->b0 =   alpha;
246       p->b1 =   0;
247       p->b2 =  -alpha;
248       p->a0 =   1 + alpha;
249       p->a1 =  -2*cos(w0);
250       p->a2 =   1 - alpha;
251       break;
252 
253     case filter_notch: /* H(s) = (s^2 + 1) / (s^2 + s/Q + 1) */
254       p->b0 =   1;
255       p->b1 =  -2*cos(w0);
256       p->b2 =   1;
257       p->a0 =   1 + alpha;
258       p->a1 =  -2*cos(w0);
259       p->a2 =   1 - alpha;
260       break;
261 
262     case filter_APF: /* H(s) = (s^2 - s/Q + 1) / (s^2 + s/Q + 1) */
263       p->b0 =   1 - alpha;
264       p->b1 =  -2*cos(w0);
265       p->b2 =   1 + alpha;
266       p->a0 =   1 + alpha;
267       p->a1 =  -2*cos(w0);
268       p->a2 =   1 - alpha;
269       break;
270 
271     case filter_peakingEQ: /* H(s) = (s^2 + s*(A/Q) + 1) / (s^2 + s/(A*Q) + 1) */
272       if (A == 1)
273         return SOX_EFF_NULL;
274       p->b0 =   1 + alpha*A;
275       p->b1 =  -2*cos(w0);
276       p->b2 =   1 - alpha*A;
277       p->a0 =   1 + alpha/A;
278       p->a1 =  -2*cos(w0);
279       p->a2 =   1 - alpha/A;
280       break;
281 
282     case filter_lowShelf: /* H(s) = A * (s^2 + (sqrt(A)/Q)*s + A)/(A*s^2 + (sqrt(A)/Q)*s + 1) */
283       if (A == 1)
284         return SOX_EFF_NULL;
285       p->b0 =    A*( (A+1) - (A-1)*cos(w0) + 2*sqrt(A)*alpha );
286       p->b1 =  2*A*( (A-1) - (A+1)*cos(w0)                   );
287       p->b2 =    A*( (A+1) - (A-1)*cos(w0) - 2*sqrt(A)*alpha );
288       p->a0 =        (A+1) + (A-1)*cos(w0) + 2*sqrt(A)*alpha;
289       p->a1 =   -2*( (A-1) + (A+1)*cos(w0)                   );
290       p->a2 =        (A+1) + (A-1)*cos(w0) - 2*sqrt(A)*alpha;
291       break;
292 
293     case filter_deemph: /* Falls through to high-shelf... */
294 
295     case filter_highShelf: /* H(s) = A * (A*s^2 + (sqrt(A)/Q)*s + 1)/(s^2 + (sqrt(A)/Q)*s + A) */
296       if (!A)
297         return SOX_EFF_NULL;
298       p->b0 =    A*( (A+1) + (A-1)*cos(w0) + 2*sqrt(A)*alpha );
299       p->b1 = -2*A*( (A-1) + (A+1)*cos(w0)                   );
300       p->b2 =    A*( (A+1) + (A-1)*cos(w0) - 2*sqrt(A)*alpha );
301       p->a0 =        (A+1) - (A-1)*cos(w0) + 2*sqrt(A)*alpha;
302       p->a1 =    2*( (A-1) - (A+1)*cos(w0)                   );
303       p->a2 =        (A+1) - (A-1)*cos(w0) - 2*sqrt(A)*alpha;
304       break;
305 
306     case filter_LPF_1: /* single-pole */
307       p->a1 = -exp(-w0);
308       p->b0 = 1 + p->a1;
309       break;
310 
311     case filter_HPF_1: /* single-pole */
312       p->a1 = -exp(-w0);
313       p->b0 = (1 - p->a1)/2;
314       p->b1 = -p->b0;
315       break;
316 
317     case filter_BPF_SPK: case filter_BPF_SPK_N: {
318       double bw_Hz;
319       if (!p->width)
320         p->width = p->fc / 2;
321       bw_Hz = p->width_type == width_Q?  p->fc / p->width :
322         p->width_type == width_bw_Hz? p->width :
323         p->fc * (pow(2., p->width) - 1) * pow(2., -0.5 * p->width); /* bw_oct */
324       #include "band.h" /* Has different licence */
325       break;
326     }
327 
328     case filter_AP1:     /* Experimental 1-pole all-pass from Tom Erbe @ UCSD */
329       p->b0 = exp(-w0);
330       p->b1 = -1;
331       p->a1 = -exp(-w0);
332       break;
333 
334     case filter_AP2:     /* Experimental 2-pole all-pass from Tom Erbe @ UCSD */
335       p->b0 = 1 - sin(w0);
336       p->b1 = -2 * cos(w0);
337       p->b2 = 1 + sin(w0);
338       p->a0 = 1 + sin(w0);
339       p->a1 = -2 * cos(w0);
340       p->a2 = 1 - sin(w0);
341       break;
342 
343     case filter_riaa: /* http://www.dsprelated.com/showmessage/73300/3.php */
344       if (effp->in_signal.rate == 44100) {
345         static const double zeros[] = {-0.2014898, 0.9233820};
346         static const double poles[] = {0.7083149, 0.9924091};
347         make_poly_from_roots(zeros, (size_t)2, &p->b0);
348         make_poly_from_roots(poles, (size_t)2, &p->a0);
349       }
350       else if (effp->in_signal.rate == 48000) {
351         static const double zeros[] = {-0.1766069, 0.9321590};
352         static const double poles[] = {0.7396325, 0.9931330};
353         make_poly_from_roots(zeros, (size_t)2, &p->b0);
354         make_poly_from_roots(poles, (size_t)2, &p->a0);
355       }
356       else if (effp->in_signal.rate == 88200) {
357         static const double zeros[] = {-0.1168735, 0.9648312};
358         static const double poles[] = {0.8590646, 0.9964002};
359         make_poly_from_roots(zeros, (size_t)2, &p->b0);
360         make_poly_from_roots(poles, (size_t)2, &p->a0);
361       }
362       else if (effp->in_signal.rate == 96000) {
363         static const double zeros[] = {-0.1141486, 0.9676817};
364         static const double poles[] = {0.8699137, 0.9966946};
365         make_poly_from_roots(zeros, (size_t)2, &p->b0);
366         make_poly_from_roots(poles, (size_t)2, &p->a0);
367       }
368       else if (effp->in_signal.rate == 192000) {
369         static const double zeros[] = {-0.1040610965, 0.9837523263};
370         static const double poles[] = {0.9328992971, 0.9983633125};
371         make_poly_from_roots(zeros, (size_t)2, &p->b0);
372         make_poly_from_roots(poles, (size_t)2, &p->a0);
373       }
374       else {
375         lsx_fail("Sample rate must be 44.1k, 48k, 88.2k, 96k, or 192k");
376         return SOX_EOF;
377       }
378       { /* Normalise to 0dB at 1kHz (Thanks to Glenn Davis) */
379         double y = 2 * M_PI * 1000 / effp->in_signal.rate;
380         double b_re = p->b0 + p->b1 * cos(-y) + p->b2 * cos(-2 * y);
381         double a_re = p->a0 + p->a1 * cos(-y) + p->a2 * cos(-2 * y);
382         double b_im = p->b1 * sin(-y) + p->b2 * sin(-2 * y);
383         double a_im = p->a1 * sin(-y) + p->a2 * sin(-2 * y);
384         double g = 1 / sqrt((sqr(b_re) + sqr(b_im)) / (sqr(a_re) + sqr(a_im)));
385         p->b0 *= g; p->b1 *= g; p->b2 *= g;
386       }
387       mult = (p->b0 + p->b1 + p->b2) / (p->a0 + p->a1 + p->a2);
388       lsx_debug("gain=%f", linear_to_dB(mult));
389       break;
390   }
391   if (effp->in_signal.mult)
392     *effp->in_signal.mult /= mult;
393   return lsx_biquad_start(effp);
394 }
395 
396 
397 #define BIQUAD_EFFECT(name,group,usage,flags) \
398 sox_effect_handler_t const * lsx_##name##_effect_fn(void) { \
399   static sox_effect_handler_t handler = { \
400     #name, usage, flags, \
401     group##_getopts, start, lsx_biquad_flow, 0, 0, 0, sizeof(biquad_t)\
402   }; \
403   return &handler; \
404 }
405 
406 BIQUAD_EFFECT(highpass,  hilo2,    "[-1|-2] frequency [width[q|o|h|k](0.707q)]", 0)
407 BIQUAD_EFFECT(lowpass,   hilo2,    "[-1|-2] frequency [width[q|o|h|k]](0.707q)", 0)
408 BIQUAD_EFFECT(bandpass,  bandpass, "[-c] frequency width[h|k|q|o]", 0)
409 BIQUAD_EFFECT(bandreject,bandrej,  "frequency width[h|k|q|o]", 0)
410 BIQUAD_EFFECT(allpass,   allpass,  "frequency width[h|k|q|o]", 0)
411 BIQUAD_EFFECT(bass,      tone,     "gain [frequency(100) [width[s|h|k|q|o]](0.5s)]", 0)
412 BIQUAD_EFFECT(treble,    tone,     "gain [frequency(3000) [width[s|h|k|q|o]](0.5s)]", 0)
413 BIQUAD_EFFECT(equalizer, equalizer,"frequency width[q|o|h|k] gain", 0)
414 BIQUAD_EFFECT(band,      band,     "[-n] center [width[h|k|q|o]]", 0)
415 BIQUAD_EFFECT(deemph,    deemph,   NULL, 0)
416 BIQUAD_EFFECT(riaa,      riaa,     NULL, 0)
417