1 /* libSoX Biquad filter common functions (c) 2006-7 robs@users.sourceforge.net
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.
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.
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
21 typedef biquad_t priv_t
;
23 static char const * const width_str
[] = {
26 "band-width(Hz, no warp)", /* deprecated */
27 "band-width(octaves)",
31 static char const all_width_types
[] = "hkboqs";
34 int lsx_biquad_getopts(sox_effect_t
* effp
, int argc
, char **argv
,
35 int min_args
, int max_args
, int fc_pos
, int width_pos
, int gain_pos
,
36 char const * allowed_width_types
, filter_t filter_type
)
38 priv_t
* p
= (priv_t
*)effp
->priv
;
39 char width_type
= *allowed_width_types
;
40 char dummy
, * dummy_p
; /* To check for extraneous chars. */
43 p
->filter_type
= filter_type
;
44 if (argc
< min_args
|| argc
> max_args
||
45 (argc
> fc_pos
&& ((p
->fc
= lsx_parse_frequency(argv
[fc_pos
], &dummy_p
)) <= 0 || *dummy_p
)) ||
46 (argc
> width_pos
&& ((unsigned)(sscanf(argv
[width_pos
], "%lf%c %c", &p
->width
, &width_type
, &dummy
)-1) > 1 || p
->width
<= 0)) ||
47 (argc
> gain_pos
&& sscanf(argv
[gain_pos
], "%lf %c", &p
->gain
, &dummy
) != 1) ||
48 !strchr(allowed_width_types
, width_type
) || (width_type
== 's' && p
->width
> 1))
49 return lsx_usage(effp
);
50 p
->width_type
= strchr(all_width_types
, width_type
) - all_width_types
;
51 if ((size_t)p
->width_type
>= strlen(all_width_types
))
53 if (p
->width_type
== width_bw_kHz
) {
55 p
->width_type
= width_bw_Hz
;
61 static int start(sox_effect_t
* effp
)
63 priv_t
* p
= (priv_t
*)effp
->priv
;
71 p
->o2
= p
->o1
= p
->i2
= p
->i1
= 0;
76 int lsx_biquad_start(sox_effect_t
* effp
)
78 priv_t
* p
= (priv_t
*)effp
->priv
;
82 if (effp
->global_info
->plot
== sox_plot_octave
) {
84 "%% GNU Octave file (may also work with MATLAB(R) )\n"
85 "Fs=%g;minF=10;maxF=Fs/2;\n"
86 "sweepF=logspace(log10(minF),log10(maxF),200);\n"
87 "[h,w]=freqz([%.15e %.15e %.15e],[1 %.15e %.15e],sweepF,Fs);\n"
88 "semilogx(w,20*log10(h))\n"
89 "title('SoX effect: %s gain=%g frequency=%g %s=%g (rate=%g)')\n"
90 "xlabel('Frequency (Hz)')\n"
91 "ylabel('Amplitude Response (dB)')\n"
92 "axis([minF maxF -35 25])\n"
94 "disp('Hit return to continue')\n"
96 , effp
->in_signal
.rate
, p
->b0
, p
->b1
, p
->b2
, p
->a1
, p
->a2
97 , effp
->handler
.name
, p
->gain
, p
->fc
, width_str
[p
->width_type
], p
->width
98 , effp
->in_signal
.rate
);
101 if (effp
->global_info
->plot
== sox_plot_gnuplot
) {
104 "set title 'SoX effect: %s gain=%g frequency=%g %s=%g (rate=%g)'\n"
105 "set xlabel 'Frequency (Hz)'\n"
106 "set ylabel 'Amplitude Response (dB)'\n"
108 "b0=%.15e; b1=%.15e; b2=%.15e; a1=%.15e; a2=%.15e\n"
110 "H(f)=sqrt((b0*b0+b1*b1+b2*b2+2.*(b0*b1+b1*b2)*cos(f*o)+2.*(b0*b2)*cos(2.*f*o))/(1.+a1*a1+a2*a2+2.*(a1+a1*a2)*cos(f*o)+2.*a2*cos(2.*f*o)))\n"
113 "set grid xtics ytics\n"
115 "plot [f=10:Fs/2] [-35:25] 20*log10(H(f))\n"
116 "pause -1 'Hit return to continue'\n"
117 , effp
->handler
.name
, p
->gain
, p
->fc
, width_str
[p
->width_type
], p
->width
118 , effp
->in_signal
.rate
, effp
->in_signal
.rate
119 , p
->b0
, p
->b1
, p
->b2
, p
->a1
, p
->a2
);
122 if (effp
->global_info
->plot
== sox_plot_data
) {
123 printf("# SoX effect: %s gain=%g frequency=%g %s=%g (rate=%g)\n"
130 "%24.16e\n%24.16e\n%24.16e\n"
135 "%24.16e\n%24.16e\n%24.16e\n"
136 , effp
->handler
.name
, p
->gain
, p
->fc
, width_str
[p
->width_type
], p
->width
137 , effp
->in_signal
.rate
, effp
->in_signal
.rate
138 , p
->b0
, p
->b1
, p
->b2
, 1. /* a0 */, p
->a1
, p
->a2
);
145 int lsx_biquad_flow(sox_effect_t
* effp
, const sox_sample_t
*ibuf
,
146 sox_sample_t
*obuf
, size_t *isamp
, size_t *osamp
)
148 priv_t
* p
= (priv_t
*)effp
->priv
;
149 size_t len
= *isamp
= *osamp
= min(*isamp
, *osamp
);
151 double o0
= *ibuf
*p
->b0
+ p
->i1
*p
->b1
+ p
->i2
*p
->b2
- p
->o1
*p
->a1
- p
->o2
*p
->a2
;
152 p
->i2
= p
->i1
, p
->i1
= *ibuf
++;
153 p
->o2
= p
->o1
, p
->o1
= o0
;
154 *obuf
++ = SOX_ROUND_CLIP_COUNT(o0
, effp
->clips
);
159 static int create(sox_effect_t
* effp
, int argc
, char * * argv
)
161 priv_t
* p
= (priv_t
*)effp
->priv
;
167 for (; argc
&& sscanf(*argv
, "%lf%c", d
, &c
) == 1; --argc
, ++argv
, ++d
);
168 return argc
? lsx_usage(effp
) : SOX_SUCCESS
;
171 sox_effect_handler_t
const * lsx_biquad_effect_fn(void)
173 static sox_effect_handler_t handler
= {
174 "biquad", "b0 b1 b2 a0 a1 a2", 0,
175 create
, lsx_biquad_start
, lsx_biquad_flow
, NULL
, NULL
, NULL
, sizeof(priv_t
)