Last active
December 14, 2015 22:38
-
-
Save mharju/5159260 to your computer and use it in GitHub Desktop.
Not so buggy filter code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Ah. Better. | |
typedef struct { | |
float x1, x2, y1, y2; | |
float c0, c1, c2, c3, c4; | |
} biquad_t; | |
typedef enum { | |
HIGH_SHELF, | |
LOW_SHELF, | |
PEAK_EQ | |
} biquad_filter_type_t; | |
// | |
#include <math.h> | |
#include <stdlib.h> | |
#include "biquad.h" | |
biquad_t* biquad_new(biquad_filter_type_t type, float f0, float dbGain, float Q) { | |
biquad_t *filter = (biquad_t*)malloc(sizeof(biquad_t)); | |
filter->type = type; | |
biquad_update_params(filter, f0, dbGain, Q); | |
return filter; | |
} | |
void biquad_update_params(biquad_t* filter, float f0, float dbGain, float Q) { | |
float A = pow(10, (dbGain/40)); | |
float w0 = 2 * M_PI * f0 / 48000; | |
float alpha = sin(w0)/(2*Q); | |
float a0, a1, a2, b0, b1, b2; | |
float A_alpha = 2*sqrt(A)*alpha; | |
float cos_w0 = cos(w0); | |
switch(filter->type) { | |
case HIGH_SHELF: | |
a0 = (A+1) - (A-1)*cos_w0 + A_alpha, | |
a1 = 2*( (A-1) - (A+1)*cos_w0); | |
a2 = (A+1) - (A-1)*cos_w0 - A_alpha; | |
b0 = A*( (A+1) + (A-1)*cos_w0 + A_alpha); | |
b1 = -2*A*( (A-1) + (A+1)*cos_w0); | |
b2 = A*((A+1) + (A-1)*cos_w0 - A_alpha); | |
break; | |
case LOW_SHELF: | |
a0 = (A+1) + (A-1)*cos_w0 + A_alpha; | |
a1 = -2*((A-1) + (A+1)*cos_w0); | |
a2 = (A+1) + (A-1)*cos_w0 - A_alpha; | |
b0 = A*( (A+1) - (A-1)*cos_w0 + A_alpha); | |
b1 = 2*A*( (A-1) - (A+1)*cos_w0); | |
b2 = A*( (A+1) - (A-1)*cos_w0 - A_alpha); | |
break; | |
case PEAK_EQ: | |
a0 = 1 + alpha/A; | |
a1 = -2*cos_w0; | |
a2 = 1 - alpha/A; | |
b0 = 1 + alpha*A; | |
b1 = -2*cos_w0; | |
b2 = 1 - alpha*A; | |
break; | |
} | |
filter->c0 = b0/a0; | |
filter->c1 = b1/a0; | |
filter->c2 = b2/a0; | |
filter->c3 = a1/a0; | |
filter->c4 = a2/a0; | |
filter->x1 = filter->x2 = filter->y2 = filter->y1 = 0; | |
} | |
float biquad_process_sample(float input, biquad_t *filter) { | |
float result = | |
filter->c0 * input + | |
filter->c1 * filter->x1 + | |
filter->c2 * filter->x2 - | |
filter->c3 * filter->y1 - | |
filter->c4 * filter->y2; | |
filter->x2 = filter->x1; | |
filter->x1 = input; | |
filter->y2 = filter->y1; | |
filter->y1 = result; | |
return result; | |
} | |
// | |
static biquad_t *high_shelf[2] = {NULL, NULL}; | |
static biquad_t *low_shelf[2] = {NULL, NULL}; | |
float cascade(float in) | |
{ | |
biquad_t* hs = high_shelf[channel]; | |
biquad_t* ls = low_shelf[channel]; | |
if(hs == NULL || ls == NULL) { | |
hs = high_shelf[channel] = biquad_new(HIGH_SHELF, 1479, 9.0, 4.0); | |
ls = low_shelf[channel] = biquad_new(LOW_SHELF, 22.0, 9.0, 3.9); | |
} | |
return biquad_process_sample(biquad_process_sample(in, hs), ls); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment