2015-05-28 12:21:38 -07:00
|
|
|
/* used to resemble https://github.com/swh/ladspa/blob/master/util/biquad.h */
|
2014-02-05 23:53:23 -08:00
|
|
|
|
2015-05-28 12:21:38 -07:00
|
|
|
typedef struct {
|
|
|
|
double a1, a2, b0, b1, b2, x1, x2, y1, y2;
|
|
|
|
} biquad;
|
2013-11-11 07:59:19 -08:00
|
|
|
|
2015-05-28 12:21:38 -07:00
|
|
|
typedef struct {
|
|
|
|
double b0, b1, b2, a0, a1, a2;
|
|
|
|
} biquad_interim;
|
2013-05-22 15:56:59 -07:00
|
|
|
|
2015-04-04 06:48:27 -07:00
|
|
|
INNER void
|
2014-02-05 23:47:16 -08:00
|
|
|
biquad_init(biquad *bq)
|
|
|
|
{
|
2013-11-10 13:17:39 -08:00
|
|
|
bq->x1 = bq->x2 = bq->y1 = bq->y2 = 0;
|
2013-05-22 15:56:59 -07:00
|
|
|
}
|
|
|
|
|
2015-04-06 11:26:47 -07:00
|
|
|
static biquad_interim
|
2013-09-10 02:54:14 -07:00
|
|
|
design(double cw, double sw,
|
|
|
|
double num0, double num1, double num2,
|
2014-02-05 23:47:16 -08:00
|
|
|
double den0, double den1, double den2)
|
|
|
|
{
|
2013-05-22 15:56:59 -07:00
|
|
|
return (biquad_interim) {
|
2013-09-10 02:54:14 -07:00
|
|
|
.b0 = num0* (1 + cw) + num1*sw + num2* (1 - cw),
|
|
|
|
.b1 = num0*-2*(1 + cw) + num2*2*(1 - cw),
|
|
|
|
.b2 = num0* (1 + cw) - num1*sw + num2* (1 - cw),
|
|
|
|
.a0 = den0* (1 + cw) + den1*sw + den2* (1 - cw),
|
|
|
|
.a1 = den0*-2*(1 + cw) + den2*2*(1 - cw),
|
|
|
|
.a2 = den0* (1 + cw) - den1*sw + den2* (1 - cw),
|
2013-05-22 15:56:59 -07:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2015-05-28 16:45:14 -07:00
|
|
|
// TODO: rename to biquad_gen_raw, fix up parameters like you did with svf
|
2015-04-05 17:45:59 -07:00
|
|
|
static biquad
|
2014-02-05 23:47:16 -08:00
|
|
|
biquad_gen(filter_t type, double fc, double gain, double bw, double fs)
|
|
|
|
{
|
2013-09-10 02:54:14 -07:00
|
|
|
double w0, cw, sw, A, As, Q;
|
2013-05-22 15:56:59 -07:00
|
|
|
w0 = ANGULAR_LIM(fc, fs);
|
|
|
|
cw = cos(w0);
|
|
|
|
sw = sin(w0);
|
2013-09-10 02:54:14 -07:00
|
|
|
A = DB2LIN(gain/2);
|
|
|
|
As = sqrt(A);
|
2014-02-03 15:02:24 -08:00
|
|
|
Q = M_SQRT1_2*(1 - (w0/M_PI)*(w0/M_PI))/bw;
|
2013-05-22 15:56:59 -07:00
|
|
|
|
|
|
|
biquad_interim bqi;
|
2014-02-03 15:02:24 -08:00
|
|
|
|
|
|
|
#define d(n0,n1,n2,d0,d1,d2) bqi = design(cw,sw,n0,n1,n2,d0,d1,d2)
|
|
|
|
switch (type) {
|
|
|
|
case FILT_PEAKING: d(1, A/Q, 1, 1, 1/A/Q, 1); break;
|
|
|
|
case FILT_LOWSHELF: d(1, As/Q, A, 1, 1/As/Q, 1/A); break;
|
|
|
|
case FILT_HIGHSHELF: d(A, As/Q, 1, 1/A, 1/As/Q, 1); break;
|
|
|
|
case FILT_LOWPASS: d(0, 0, 1, 1, 1/Q, 1); break;
|
|
|
|
case FILT_HIGHPASS: d(1, 0, 0, 1, 1/Q, 1); break;
|
|
|
|
case FILT_ALLPASS: d(1, -1/Q, 1, 1, 1/Q, 1); break;
|
|
|
|
case FILT_BANDPASS: d(0, 1, 0, 1, 1/Q, 1); break;
|
|
|
|
case FILT_BANDPASS_2: d(0, 1/Q, 0, 1, 1/Q, 1); break;
|
|
|
|
case FILT_NOTCH: d(1, 0, 1, 1, 1/Q, 1); break;
|
|
|
|
case FILT_GAIN: d(A, A, A, 1/A, 1/A, 1/A); break;
|
|
|
|
}
|
|
|
|
#undef d
|
2013-05-22 15:56:59 -07:00
|
|
|
|
|
|
|
double a0r = 1/bqi.a0;
|
2013-06-17 01:52:48 -07:00
|
|
|
|
2013-11-15 19:15:50 -08:00
|
|
|
biquad out;
|
|
|
|
out.b0 = a0r*bqi.b0;
|
|
|
|
out.b1 = a0r*bqi.b1;
|
|
|
|
out.b2 = a0r*bqi.b2;
|
|
|
|
out.a1 = -a0r*bqi.a1;
|
|
|
|
out.a2 = -a0r*bqi.a2;
|
|
|
|
return out;
|
2013-05-22 15:56:59 -07:00
|
|
|
}
|
|
|
|
|
2015-04-04 06:48:27 -07:00
|
|
|
INNER double
|
2014-02-05 23:47:16 -08:00
|
|
|
biquad_run(biquad *bq, double x)
|
|
|
|
{
|
2014-02-05 23:32:24 -08:00
|
|
|
double y;
|
2013-05-22 15:56:59 -07:00
|
|
|
|
2013-11-16 10:19:05 -08:00
|
|
|
y = bq->b0*x + bq->b1*bq->x1 + bq->b2*bq->x2
|
|
|
|
+ bq->a1*bq->y1 + bq->a2*bq->y2;
|
2013-05-22 15:56:59 -07:00
|
|
|
bq->x2 = bq->x1;
|
|
|
|
bq->x1 = x;
|
|
|
|
bq->y2 = bq->y1;
|
|
|
|
bq->y1 = y;
|
|
|
|
|
|
|
|
return y;
|
|
|
|
}
|
2015-04-05 17:45:59 -07:00
|
|
|
|
2015-06-06 17:25:18 -07:00
|
|
|
TEMPLATE INNER void
|
2015-04-05 17:45:59 -07:00
|
|
|
biquad_run_block_stereo(biquad *bq_L, biquad *bq_R,
|
2015-06-06 17:25:18 -07:00
|
|
|
T *buf, ulong count)
|
2015-04-05 17:45:59 -07:00
|
|
|
{
|
2015-06-06 17:25:18 -07:00
|
|
|
T b0, b1, b2, a1, a2, x1, x2, y1, y2;
|
2015-04-06 11:26:47 -07:00
|
|
|
|
2015-06-06 17:25:18 -07:00
|
|
|
b0 = T(bq_L->b0);
|
|
|
|
b1 = T(bq_L->b1);
|
|
|
|
b2 = T(bq_L->b2);
|
|
|
|
a1 = T(bq_L->a1);
|
|
|
|
a2 = T(bq_L->a2);
|
2015-06-06 10:42:14 -07:00
|
|
|
|
2015-06-06 17:25:18 -07:00
|
|
|
x1 = T(bq_L->x1, bq_R->x1);
|
|
|
|
x2 = T(bq_L->x2, bq_R->x2);
|
|
|
|
y1 = T(bq_L->y1, bq_R->y1);
|
|
|
|
y2 = T(bq_L->y2, bq_R->y2);
|
2015-04-06 11:26:47 -07:00
|
|
|
|
|
|
|
for (ulong i = 0; i < count; i++) {
|
2015-06-06 17:25:18 -07:00
|
|
|
T x = buf[i];
|
|
|
|
T y = b0*x + b1*x1 + b2*x2 + a1*y1 + a2*y2;
|
2015-04-05 17:45:59 -07:00
|
|
|
x2 = x1;
|
|
|
|
y2 = y1;
|
|
|
|
x1 = x;
|
|
|
|
y1 = y;
|
2015-04-06 11:26:47 -07:00
|
|
|
buf[i] = y;
|
2015-04-05 17:45:59 -07:00
|
|
|
}
|
|
|
|
|
2015-04-06 11:26:47 -07:00
|
|
|
bq_L->x1 = x1[0];
|
|
|
|
bq_R->x1 = x1[1];
|
|
|
|
bq_L->x2 = x2[0];
|
|
|
|
bq_R->x2 = x2[1];
|
|
|
|
bq_L->y1 = y1[0];
|
|
|
|
bq_R->y1 = y1[1];
|
|
|
|
bq_L->y2 = y2[0];
|
|
|
|
bq_R->y2 = y2[1];
|
2015-04-05 17:45:59 -07:00
|
|
|
}
|