fil4.lv2/src/hip.h

151 lines
3.4 KiB
C

/* fil4.lv2 - highpass
*
* Copyright (C) 2015 Robin Gareus <robin@gareus.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _FIL4_HIP_H
#define _FIL4_HIP_H
#include <math.h>
typedef struct {
float y2;
float z1, z2;
float a, q, g;
float alpha, omega, q2;
float freq, qual; // last settings
float rate;
bool en;
} HighPass;
static void hip_setup (HighPass *f, float rate, float freq, float q) {
memset (f, 0, sizeof(HighPass));
f->rate = rate;
f->freq = freq;
f->qual = q;
f->q2 = RESHP(q);
if (f->q2 < 0.f) f->q2 = 0.f;
if (f->q2 > 1.6f) f->q2 = 1.6f;
if (freq > rate / 12.f) freq = rate / 12.f;
f->alpha = exp (-2.0 * M_PI * freq / rate);
f->a = 1.0;
f->q = 0.0; // start bypassed
f->g = 0.0; // fade in
f->en = false;
}
static bool hip_interpolate (HighPass *f, bool en, float freq, float q) {
// called an interval of max 48 samples
bool changed = f->en != en;
f->en = en;
if (freq != f->freq) {
f->freq = freq;
if (freq > f->rate / 12.f) {
freq = f->rate / 12.f;
}
if (freq < 5.f) {
freq = 5.f;
}
f->omega = freq / f->rate;
f->alpha = exp (-2.0 * M_PI * f->omega);
changed = true;
}
if (f->qual != q) {
f->q2 = RESHP(q);
if (f->q2 < 0.f) f->q2 = 0.f;
if (f->q2 > 1.6f) f->q2 = 1.6f;
//printf("HI: %f -> %f\n", q, f->q2);
f->qual = q;
changed = true;
}
const float to = en ? f->alpha : 1.0;
if (fabsf(to - f->a) < 1e-5) {
f->a = to;
} else {
f->a += .01 * (to - f->a);
changed = true;
}
const float tq = en ? f->q2 : 0;
if (fabsf(tq - f->q) < 1e-5) {
f->q = tq;
} else {
f->q += .01 * (tq - f->q);
changed = true;
}
//target gain = 1 + (.5 + q) * 2 * w;
const float tg = en ? (1.f + f->omega + 2.f * f->q * f->omega) : 1.0;
if (fabsf(tg - f->g) < 1e-5) {
f->g = tg;
} else {
f->g += .01 * (tg - f->g);
changed = true;
}
if (!en) {
f->z1 += .01 * (f->z2 - f->z1) + 1e-12;
//f->z2 += .01 * (f->y2 - f->z2) + 1e-12;
}
#ifndef NO_NAN_PROTECTION
if (isnan(f->z1)) f->z1 = 0;
if (isnan(f->z2)) f->z2 = 0;
if (isnan(f->y2)) f->y2 = 0;
#endif
return changed;
}
static void hip_compute (HighPass *f, uint32_t n_samples, float *buf) {
const float a = f->a;
const float q = f->q;
const float g = f->g;
const float m1 = g/a;
const float m2 = g*q;
if (a == 1.0 && q == 0.0 && g == 1.0) {
// might as well save some computing
// (all values incl state are filtered)
return;
}
float z1 = f->z1;
float z2 = f->z2;
float y2 = f->y2;
for (uint32_t i = 0; i < n_samples; ++i) {
const float _z1 = z1; // remember previous input
const float _z2 = z2; // since buf[] is processed in-place
z1 = m1 * buf[i] - m2 * (y2 - z2); // == g * (buf[i] / a - q * (y2 - z2))
z2 = a * (z2 + z1 - _z1);
y2 = a * (y2 + z2 - _z2);
buf[i] = y2;
}
f->y2 = y2;
f->z1 = z1 + 1e-12;
f->z2 = z2 + 1e-12;
}
#endif