ref: 88d38f3c68660480142e9e773864210ccbd4ad8e
parent: c18294ee0942343a69eaf701fdc9445041343b06
author: robs <robs>
date: Sun Dec 31 05:50:37 EST 2006
Use common functions for biquad filters.
--- a/src/biquad.c
+++ b/src/biquad.c
@@ -2,6 +2,51 @@
+int st_biquad_start(eff_t effp, char const * width_name)
+{
+ biquad_t p = (biquad_t) effp->priv;
+
+ /* Simplify: */
+ p->b2 = p->b2/p->a0;
+ p->b1 = p->b1/p->a0;
+ p->b0 = p->b0/p->a0;
+ p->a2 = p->a2/p->a0;
+ p->a1 = p->a1/p->a0;
+
+ if (p->dcNormalise) /* Normalise to AV = 0dB at DC: */
+ {
+ double normalise = (1 + p->a1 + p->a2) / (p->b0 + p->b1 + p->b2);
+ p->b0 = normalise * p->b0;
+ p->b1 = normalise * p->b1;
+ p->b2 = normalise * p->b2;
+ }
+
+ if (effp->globalinfo->octave_plot_effect)
+ {
+ printf(
+ "title('SoX effect: %s gain=%g centre=%g %s=%g (rate=%u)')\n"
+ "xlabel('Frequency (Hz)')\n"
+ "ylabel('Amplitude Response (dB)')\n"
+ "Fs=%u;minF=10;maxF=Fs/2;\n"
+ "axis([minF maxF -25 25])\n"
+ "sweepF=logspace(log10(minF),log10(maxF),200);\n"
+ "grid on\n"
+ "[h,w]=freqz([%f %f %f],[1 %f %f],sweepF,Fs);\n"
+ "semilogx(w,20*log10(h),'b')\n"
+ "pause\n"
+ , effp->name, p->gain, p->fc, width_name, p->width.q
+ , effp->ininfo.rate, effp->ininfo.rate
+ , p->b0, p->b1, p->b2, p->a1, p->a2
+ );
+ exit(0);
+ }
+
+ p->o2 = p->o1 = p->i2 = p-> i1 = 0;
+ return ST_SUCCESS;
+}
+
+
+
int st_biquad_flow(eff_t effp, const st_sample_t *ibuf, st_sample_t *obuf,
st_size_t *isamp, st_size_t *osamp)
{
--- a/src/biquad.h
+++ b/src/biquad.h
@@ -9,16 +9,17 @@
{
double gain;
double fc; /* Centre/corner/cutoff frequency */
- double oomph; /* Q, BW, or Slope */
+ union {double q, bandwidth, slope;} width; /* Depending on filter type */
bool dcNormalise; /* A treble filter should normalise at DC */
double b2, b1, b0; /* Filter coefficients */
- double a2, a1; /* Filter coefficients; a0 = 1 */
+ double a2, a1, a0; /* Filter coefficients */
st_sample_t i1, i2; /* Filter memory */
double o1, o2; /* Filter memory */
} * biquad_t;
+int st_biquad_start(eff_t effp, char const * width_name);
int st_biquad_flow(eff_t effp, const st_sample_t *ibuf, st_sample_t *obuf,
st_size_t *isamp, st_size_t *osamp);
--- a/src/equalizer.c
+++ b/src/equalizer.c
@@ -48,48 +48,28 @@
1 + (a1/a0)z^-1 + (a2/a0)z^-2
*/
-#include <math.h>
-#include "st_i.h"
+#include "biquad.h"
-static st_effect_t st_equalizer_effect;
-
-/* Filter parameters */
-typedef struct filterparams {
- float rate; /* Sample rate */
- float Q; /* Q-factor */
- float cfreq; /* Central frequency (Hz) */
- float gain; /* Gain (dB) */
- double x[3]; /* In where x[2] <=> x[ n - 2 ] */
- double y[3]; /* Out */
- double b[3]; /* From this point, equation constants... */
- double a[3];
-} *equalizer_t;
-
-static int st_equalizer_getopts(eff_t effp, int n, char **argv)
+static int equalizer_getopts(eff_t effp, int n, char **argv)
{
- equalizer_t eq = (equalizer_t) effp->priv;
- int i;
+ biquad_t eq = (biquad_t) effp->priv;
+ char dummy;
- if (n < 3)
- {
- st_fail("Usage: equalizer center-freq Q gain");
- return (ST_EOF);
- }
-
- i = 0;
- sscanf(argv[i++], "%f", &eq->cfreq);
- sscanf(argv[i++], "%f", &eq->Q);
- sscanf(argv[i++], "%f", &eq->gain);
-
- /* FIXME: Would be nice to validate the params.. */
-
- return (ST_SUCCESS);
+ if (n != 3 ||
+ sscanf(argv[0], "%lf %c", &eq->fc , &dummy) != 1 ||
+ sscanf(argv[1], "%lf %c", &eq->width.q, &dummy) != 1 ||
+ sscanf(argv[2], "%lf %c", &eq->gain , &dummy) != 1 ||
+ eq->fc <= 0 ||
+ eq->width.q <= 0) {
+ st_fail(effp->h->usage);
+ return ST_EOF;
+ }
+ return ST_SUCCESS;
}
-/* Set the filter constants */
-static int st_equalizer_start(eff_t effp)
+static int equalizer_start(eff_t effp)
{
- equalizer_t eq = (equalizer_t) effp->priv;
+ biquad_t eq = (biquad_t) effp->priv;
double w0;
double amp;
double alpha;
@@ -97,108 +77,41 @@
if (eq->gain == 0)
return ST_EFF_NULL;
- /* Sample rate */
- eq->rate = effp->ininfo.rate;
-
- w0 = 2*M_PI*eq->cfreq/eq->rate;
+ /* Set the filter constants */
+ w0 = 2*M_PI*eq->fc/effp->ininfo.rate;
amp = pow( 10, eq->gain/40 );
- alpha = sin(w0)/( 2*eq->Q );
+ alpha = sin(w0)/( 2*eq->width.q );
- st_debug("cfreq: %fHz", eq->cfreq);
- st_debug("Q: %f", eq->Q);
+ st_debug("cfreq: %fHz", eq->fc);
+ st_debug("Q: %f", eq->width.q);
st_debug("gain: %fdB", eq->gain);
- st_debug("rate: %f", eq->rate);
st_debug("w0: %f", w0);
st_debug("amp: %f", amp);
st_debug("alpha: %f", alpha);
/* Initialisation */
- eq->b[0] = 1 + alpha*amp;
- eq->b[1] = -2*cos(w0);
- eq->b[2] = 1 - alpha*amp;
- eq->a[0] = 1 + alpha/amp;
- eq->a[1] = -2*cos(w0);
- eq->a[2] = 1 - alpha/amp;
+ eq->b0 = 1 + alpha*amp;
+ eq->b1 = -2*cos(w0);
+ eq->b2 = 1 - alpha*amp;
+ eq->a0 = 1 + alpha/amp;
+ eq->a1 = -2*cos(w0);
+ eq->a2 = 1 - alpha/amp;
- eq->x[0] = 0; /* x[n] */
- eq->x[1] = 0; /* x[n-1] */
- eq->x[2] = 0; /* x[n-2] */
- eq->y[0] = 0; /* y[n] */
- eq->y[1] = 0; /* y[n-1] */
- eq->y[2] = 0; /* y[n-2] */
-
- if (effp->globalinfo->octave_plot_effect)
- {
- printf(
- "title('SoX effect: %s gain=%g centre=%g Q=%g (rate=%u)')\n"
- "xlabel('Frequency (Hz)')\n"
- "ylabel('Amplitude Response (dB)')\n"
- "Fs=%u;minF=10;maxF=Fs/2;\n"
- "axis([minF maxF -25 25])\n"
- "sweepF=logspace(log10(minF),log10(maxF),200);\n"
- "grid on\n"
- "[h,w]=freqz([%f %f %f],[%f %f %f],sweepF,Fs);\n"
- "semilogx(w,20*log10(h),'b')\n"
- "pause\n"
- , effp->name, eq->gain, eq->cfreq, eq->Q
- , effp->ininfo.rate, effp->ininfo.rate
- , eq->b[0], eq->b[1], eq->b[2], eq->a[0], eq->a[1], eq->a[2]
- );
- exit(0);
- }
-
- return (ST_SUCCESS);
+ return st_biquad_start(effp, "Q");
}
-static int st_equalizer_flow(eff_t effp, const st_sample_t *ibuf,
- st_sample_t *obuf, st_size_t *isamp,
- st_size_t *osamp)
-{
- equalizer_t eq = (equalizer_t) effp->priv;
- st_size_t len, done;
- double out;
-
- len = ((*isamp > *osamp) ? *osamp : *isamp);
-
- for(done = 0; done < len; done++) {
- eq->x[2] = eq->x[1];
- eq->x[1] = eq->x[0];
- eq->x[0] = *ibuf++;
-
- eq->y[2] = eq->y[1];
- eq->y[1] = eq->y[0];
- out = (
- (eq->b[0]/eq->a[0])*eq->x[0] +
- (eq->b[1]/eq->a[0])*eq->x[1] +
- (eq->b[2]/eq->a[0])*eq->x[2] -
- (eq->a[1]/eq->a[0])*eq->y[1] -
- (eq->a[2]/eq->a[0])*eq->y[2]
- );
- eq->y[0] = out;
-
- ST_SAMPLE_CLIP_COUNT(out, effp->clippedCount);
- *obuf++ = out;
- }
-
- *isamp = len;
- *osamp = len;
-
- return (ST_SUCCESS);
-}
-
-static st_effect_t st_equalizer_effect = {
- "equalizer",
- "Usage: equalizer central-frequency Q gain",
- 0,
- st_equalizer_getopts,
- st_equalizer_start,
- st_equalizer_flow,
- st_effect_nothing_drain,
- st_effect_nothing,
- st_effect_nothing
-};
-
const st_effect_t *st_equalizer_effect_fn(void)
{
- return &st_equalizer_effect;
+ static st_effect_t driver = {
+ "equalizer",
+ "Usage: equalizer central-frequency Q gain",
+ 0,
+ equalizer_getopts,
+ equalizer_start,
+ st_biquad_flow,
+ st_effect_nothing_drain,
+ st_effect_nothing,
+ st_effect_nothing
+ };
+ return &driver;
}
--- a/src/tone.c
+++ b/src/tone.c
@@ -13,8 +13,8 @@
#include "biquad.h"
-#include <string.h>
+
static int getopts(eff_t effp, int n, char **argv, double fc, int dcNormalise)
{
bool isFcSet = false;
@@ -21,26 +21,24 @@
double opt1 = HUGE_VAL, opt2 = HUGE_VAL;
biquad_t p = (biquad_t) effp->priv;
int ret = ST_SUCCESS;
+ char dummy;
- /* Zero all numbers, set all bools to false: */
- memset(p, 0, sizeof(*p));
-
/* Initialise non-zero numbers: */
p->dcNormalise = dcNormalise;
p->fc = fc;
- p->oomph = 0.5;
+ p->width.slope = 0.5;
/*
* This block is a little complicated -- all because I wanted
* to make it easy for the user i.e. order doesn't matter for
* optional arguments.
- * This is made possible because slope (or oomph) <= 1 and by
+ * This is made possible because slope <= 1 and by
* insisting that the centre-frequency is > 1 (Hz).
*/
if (n > 0 &&
- sscanf(argv[0], "%lf", &p->gain) &&
- (n < 2 || sscanf(argv[1], "%lf", &opt1)) &&
- (n < 3 || sscanf(argv[2], "%lf", &opt2)) &&
+ sscanf(argv[0], "%lf %c", &p->gain, &dummy) == 1 &&
+ (n < 2 || sscanf(argv[1], "%lf %c", &opt1, &dummy) == 1) &&
+ (n < 3 || sscanf(argv[2], "%lf %c", &opt2, &dummy) == 1) &&
(n < 4)) {
if (opt1 != HUGE_VAL) {
if (opt1 <= 0)
@@ -50,7 +48,7 @@
p->fc = opt1;
isFcSet = true;
} else
- p->oomph = opt1;
+ p->width.slope = opt1;
if (opt2 != HUGE_VAL) {
if (opt2 > 1) {
if (isFcSet)
@@ -61,7 +59,7 @@
if (!isFcSet)
ret = ST_EOF;
else
- p->oomph = opt2;
+ p->width.slope = opt2;
} else
ret = ST_EOF;
}
@@ -73,14 +71,13 @@
if (ret == ST_EOF)
st_fail(effp->h->usage);
-
return ret;
}
-static int st_bass_getopts (eff_t e, int n, char **a) {return getopts(e, n, a, 100, 0);}
-static int st_treble_getopts(eff_t e, int n, char **a) {return getopts(e, n, a, 3000, 1);}
+static int bass_getopts (eff_t e,int n,char **a){return getopts(e,n,a, 100,0);}
+static int treble_getopts(eff_t e,int n,char **a){return getopts(e,n,a,3000,1);}
@@ -91,92 +88,51 @@
/* Calculate intermediates: */
double A = exp(p->gain / 40 * log(10));
double w0 = 2 * M_PI * p->fc / effp->ininfo.rate;
- double alpha = sin(w0)/2 * sqrt( (A + 1/A)*(1/p->oomph - 1) + 2 );
- double a0;
+ double alpha = sin(w0)/2 * sqrt( (A + 1/A)*(1/p->width.slope - 1) + 2 );
/* Calculate filter coefficients: */
- p->b0 = A*( (A+1) - (A-1)*cos(w0) + 2*sqrt(A)*alpha ); /* Numerator. */
+ p->b0 = A*( (A+1) - (A-1)*cos(w0) + 2*sqrt(A)*alpha );
p->b1 = 2*A*( (A-1) - (A+1)*cos(w0) );
p->b2 = A*( (A+1) - (A-1)*cos(w0) - 2*sqrt(A)*alpha );
- a0 = (A+1) + (A-1)*cos(w0) + 2*sqrt(A)*alpha; /* Denominator. */
+ p->a0 = (A+1) + (A-1)*cos(w0) + 2*sqrt(A)*alpha;
p->a1 = -2*( (A-1) + (A+1)*cos(w0) );
p->a2 = (A+1) + (A-1)*cos(w0) - 2*sqrt(A)*alpha;
- /* Simplify: */
- p->b2 = p->b2/a0;
- p->b1 = p->b1/a0;
- p->b0 = p->b0/a0;
- p->a2 = p->a2/a0;
- p->a1 = p->a1/a0;
-
- if (p->dcNormalise) /* Normalise to AV = 0dB at DC: */
- {
- double normalise = (1 + p->a1 + p->a2) / (p->b0 + p->b1 + p->b2);
- p->b0 = normalise * p->b0;
- p->b1 = normalise * p->b1;
- p->b2 = normalise * p->b2;
- }
-
- if (effp->globalinfo->octave_plot_effect)
- {
- printf(
- "title('SoX effect: %s gain=%g centre=%g slope=%g (rate=%u)')\n"
- "xlabel('Frequency (Hz)')\n"
- "ylabel('Amplitude Response (dB)')\n"
- "Fs=%u;minF=10;maxF=Fs/2;\n"
- "axis([minF maxF -25 25])\n"
- "sweepF=logspace(log10(minF),log10(maxF),200);\n"
- "grid on\n"
- "[h,w]=freqz([%f %f %f],[1 %f %f],sweepF,Fs);\n"
- "semilogx(w,20*log10(h),'b')\n"
- "pause\n"
- , effp->name, p->gain, p->fc, p->oomph
- , effp->ininfo.rate, effp->ininfo.rate
- , p->b0, p->b1, p->b2, p->a1, p->a2
- );
- exit(0);
- }
- return ST_SUCCESS;
+ return st_biquad_start(effp, "slope");
}
-static st_effect_t st_bass_effect = {
- "bass",
- "Usage: bass gain [frequency] [slope]",
- 0,
- st_bass_getopts,
- st_biquad_shelf_start,
- st_biquad_flow,
- st_effect_nothing_drain,
- st_effect_nothing,
- st_effect_nothing
-};
-
-
-
st_effect_t const * st_bass_effect_fn(void)
{
- return &st_bass_effect;
+ static st_effect_t driver = {
+ "bass",
+ "Usage: bass gain [frequency] [slope]",
+ 0,
+ bass_getopts,
+ st_biquad_shelf_start,
+ st_biquad_flow,
+ st_effect_nothing_drain,
+ st_effect_nothing,
+ st_effect_nothing
+ };
+ return &driver;
}
-static st_effect_t st_treble_effect = {
- "treble",
- "Usage: treble gain [frequency] [slope]",
- 0,
- st_treble_getopts,
- st_biquad_shelf_start,
- st_biquad_flow,
- st_effect_nothing_drain,
- st_effect_nothing,
- st_effect_nothing
-};
-
-
-
st_effect_t const * st_treble_effect_fn(void)
{
- return &st_treble_effect;
+ static st_effect_t driver = {
+ "treble",
+ "Usage: treble gain [frequency] [slope]",
+ 0,
+ treble_getopts,
+ st_biquad_shelf_start,
+ st_biquad_flow,
+ st_effect_nothing_drain,
+ st_effect_nothing,
+ st_effect_nothing
+ };
+ return &driver;
}