#![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) { 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");