/* A simple octal machine for 12 dB/oct low/high pass and 6 dB/oct band pass filtering (state variable 2-pole filter). Works in mono. Avelino Herrera Morales. address@hidden address@hidden */ #include #include #include "util.h" #include "machine.h" /* Three parameters: cutoff frequency, resonance and filter type. */ enum {ix_cutoff, ix_resonance, ix_filter_type} param_index; param_spec svfilter_params[] = { /* First parameter: cutoff. */ { small, slider, "Cutoff", "Cutoff frequency", 0x00, /* 0 Hz. */ 0xFF, /* Sampling freq / 2. */ 0xFF, }, /* Second parameter: resonance. */ { small, slider, "Resonance", "Resonance", 0x00, /* Auto-osc. */ 0xFF, /* No resonance. */ 0xFF }, /* Third parameter: filter type. */ { small, slider, "Filter type" "Filter type: 0=Low pass, 1=band pass 2=high pass", 0x00, 0x02, 0x00 /* By default low pass type. */ } }; /* State of the state variable filter. */ typedef struct { samp low, mid, hig; /* Signal history. */ float freq, reso; /* Cutoff freq and resonance. */ int filter_type; /* Idem third parameter. */ } svfilter_state; int ox_init(machine_type *t) { t->long_name = "2-pole state variable filter (Avelino Herrera)"; t->short_name = "svfilter"; t->max_tracks = 1; t->input_channels = 1; t->output_channels = 1; t->num_params = 2; t->param_specs = svfilter_params; return 1; } void ox_create(machine *m) { svfilter_state *s; s = malloc(sizeof(svfilter_state)); s->low = s->mid = s->hig = 0; s->freq = s->reso = 1; m->state = (void *) s; return; } void ox_destroy(machine *m) { free(m->state); m->state = NULL; return; } void ox_update(machine *m) { svfilter_state *s; float cut, res; s = (svfilter_state *) m->state; cut = (float) m->params[0][ix_cutoff]; res = (float) m->params[0][ix_resonance]; /* Scale [0..255] to [0..1]. */ cut /= 255.0; res /= 255.0; s->freq = cut; s->reso = res; s->filter_type = (int) m->params[0][ix_filter_type]; return; } const char *ox_desc(int which_param, param value) { static char temp_string[80]; float x; int percent; sprintf(temp_string, "ERROR"); if ((which_param == ix_cutoff) || (which_param == ix_resonance)) { x = ((float) value) / 255.0; percent = (int)(x * 100); sprintf(temp_string, "%d%%", percent); } else if (which_param == ix_filter_type) { switch (value) { case 0 : sprintf(temp_string, "low pass"); break; case 1 : sprintf(temp_string, "band pass"); break; case 2 : sprintf(temp_string, "high pass"); break; } } return temp_string; } int ox_work(machine *m, int block_size) { int i, filter_type; svfilter_state *s; float feedback, hig, mid, low, freq, reso; s = (svfilter_state *) m->state; /* Store at local variables to avoid massive use of '->' operand in the main loop. */ hig = s->hig; mid = s->mid; low = s->low; freq = s->freq; reso = s->reso; filter_type = s->filter_type; for (i = 0; i < block_size; i++) { /* A discrete implementation of a state variable filter (an adder plus two integrators in cascade). */ feedback = reso * mid; hig = m->lin[i] - feedback - low; mid += hig * freq; low += mid * freq; /* Output can be extracted from the three circuit points to obtain low pass, band pass or hig pass. */ switch (filter_type) { case 0 : m->lout[i] = low; break; /* Low pass. */ case 1 : m->lout[i] = mid; break; /* Band pass. */ case 2 : m->lout[i] = hig; break; /* High pass. */ } } /* Store filter state for next block. */ s->hig = hig; s->mid = mid; s->low = low; return 1; } void ox_track(machine *m, int change) { }