161 lines
4.0 KiB
Rust
161 lines
4.0 KiB
Rust
#![allow(incomplete_features)]
|
|
#![feature(generic_associated_types)]
|
|
|
|
// https://www.musicdsp.org/en/latest/Filters/236-3-band-equaliser.html
|
|
|
|
use baseplug::{Plugin, ProcessContext};
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
baseplug::model! {
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
struct ThreeBandEqModel {
|
|
#[model(min = 0.0, max = 48000.0)]
|
|
#[parameter(name = "low band")]
|
|
low_band: f32,
|
|
#[model(min = 0.0, max = 48000.0)]
|
|
#[parameter(name = "mid band")]
|
|
high_band: f32,
|
|
|
|
#[model(min = 0.0, max = 3.0)]
|
|
#[parameter(name = "low gain")]
|
|
low_gain: f32,
|
|
#[model(min = 0.0, max = 3.0)]
|
|
#[parameter(name = "mid gain")]
|
|
mid_gain: f32,
|
|
#[model(min = 0.0, max = 3.0)]
|
|
#[parameter(name = "high gain")]
|
|
high_gain: f32,
|
|
}
|
|
}
|
|
|
|
impl Default for ThreeBandEqModel {
|
|
fn default() -> Self {
|
|
Self {
|
|
low_band: 800.0,
|
|
high_band: 5000.0,
|
|
|
|
low_gain: 1.0,
|
|
mid_gain: 1.0,
|
|
high_gain: 1.0,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Default)]
|
|
struct Eq {
|
|
// Filter #1 (Low band)
|
|
f1p0: f32, // Poles ...
|
|
f1p1: f32,
|
|
f1p2: f32,
|
|
f1p3: f32,
|
|
|
|
// Filter #2 (High band)
|
|
f2p0: f32, // Poles ...
|
|
f2p1: f32,
|
|
f2p2: f32,
|
|
f2p3: f32,
|
|
|
|
// Sample history buffer
|
|
sdm1: f32, // Sample data minus 1
|
|
sdm2: f32, // 2
|
|
sdm3: f32, // 3
|
|
}
|
|
impl Eq {
|
|
#[allow(clippy::too_many_arguments)]
|
|
fn process(
|
|
&mut self,
|
|
input: f32,
|
|
lf: f32,
|
|
hf: f32,
|
|
lg: f32,
|
|
mg: f32,
|
|
hg: f32,
|
|
sample_rate: f32,
|
|
) -> f32 {
|
|
let lf = 2.0 * (std::f32::consts::PI * (lf / sample_rate)).sin();
|
|
let hf = 2.0 * (std::f32::consts::PI * (hf / sample_rate)).sin();
|
|
|
|
// Filter #1 (lowpass)
|
|
self.f1p0 += lf * (input - self.f1p0) + VSA;
|
|
self.f1p1 += lf * (self.f1p0 - self.f1p1);
|
|
self.f1p2 += lf * (self.f1p1 - self.f1p2);
|
|
self.f1p3 += lf * (self.f1p2 - self.f1p3);
|
|
|
|
let l = self.f1p3;
|
|
|
|
// Filter #2 (highpass)
|
|
self.f2p0 += hf * (input - self.f2p0) + VSA;
|
|
self.f2p1 += hf * (self.f2p0 - self.f2p1);
|
|
self.f2p2 += hf * (self.f2p1 - self.f2p2);
|
|
self.f2p3 += hf * (self.f2p2 - self.f2p3);
|
|
|
|
// we subtract from sdm3 because the filter has a three sample delay
|
|
let h = self.sdm3 - self.f2p3;
|
|
|
|
// Calculate midrange (signal - (low + high))
|
|
let m = self.sdm3 - (h + l);
|
|
|
|
// Scale
|
|
let l = l * lg;
|
|
let m = m * mg;
|
|
let h = h * hg;
|
|
|
|
// Shuffle history buffer
|
|
self.sdm3 = self.sdm2;
|
|
self.sdm2 = self.sdm1;
|
|
self.sdm1 = input;
|
|
|
|
l + m + h
|
|
}
|
|
}
|
|
|
|
#[derive(Default)]
|
|
struct ThreeBandEq {
|
|
l_eq: Eq,
|
|
r_eq: Eq,
|
|
}
|
|
|
|
/// Very small amount
|
|
const VSA: f32 = 1.0 / 4294967295.0;
|
|
|
|
impl Plugin for ThreeBandEq {
|
|
const NAME: &'static str = "basic gain";
|
|
const PRODUCT: &'static str = "basic gain";
|
|
const VENDOR: &'static str = "unnieversal";
|
|
|
|
const INPUT_CHANNELS: usize = 2;
|
|
const OUTPUT_CHANNELS: usize = 2;
|
|
|
|
type Model = ThreeBandEqModel;
|
|
|
|
#[inline]
|
|
fn new(_sample_rate: f32, _model: &ThreeBandEqModel) -> Self {
|
|
// Default cause we want to start with 0s in everything
|
|
Self::default()
|
|
}
|
|
|
|
#[inline]
|
|
fn process(&mut self, model: &ThreeBandEqModelProcess, ctx: &mut ProcessContext<Self>) {
|
|
let input = &ctx.inputs[0].buffers;
|
|
let output = &mut ctx.outputs[0].buffers;
|
|
|
|
let sr = ctx.sample_rate;
|
|
|
|
for i in 0..ctx.nframes {
|
|
// frequencies
|
|
let lf = model.low_band[i];
|
|
let hf = model.high_band[i];
|
|
|
|
// gains
|
|
let lg = model.low_gain[i];
|
|
let mg = model.mid_gain[i];
|
|
let hg = model.high_gain[i];
|
|
|
|
output[0][i] = self.l_eq.process(input[0][i], lf, hf, lg, mg, hg, sr);
|
|
output[1][i] = self.r_eq.process(input[1][i], lf, hf, lg, mg, hg, sr);
|
|
}
|
|
}
|
|
}
|
|
|
|
baseplug::vst2!(ThreeBandEq, b"tAnE");
|