use crate::building_blocks::{Modulator, MonoEffect, SynthParameterLabel, SynthParameterValue};
pub struct PeakEq<const BUFSIZE: usize> {
center: f32,
bw: f32,
gain: f32,
h_zero: f32,
v_zero: f32,
d: f32,
del1: f32,
del2: f32,
c: f32,
samplerate: f32,
center_mod: Option<Modulator<BUFSIZE>>,
bw_mod: Option<Modulator<BUFSIZE>>,
gain_mod: Option<Modulator<BUFSIZE>>,
}
impl<const BUFSIZE: usize> PeakEq<BUFSIZE> {
pub fn new(center_freq: f32, bw: f32, gain: f32, sr: f32) -> Self {
let w_c = (2.0 * center_freq) / sr;
let w_b = (2.0 * bw) / sr;
let d = -((std::f32::consts::PI * w_c).cos());
let v_zero = 10_f32.powf(gain / 20.0); let h_zero = v_zero - 1.0;
let cf_tan = (std::f32::consts::PI * w_b / 2.0).tan();
let c = if gain >= 0.0 {
(cf_tan - 1.0) / (cf_tan + 1.0)
} else {
(cf_tan - v_zero) / (cf_tan + v_zero)
};
PeakEq {
center: center_freq,
bw,
gain,
h_zero,
v_zero,
d,
del1: 0.0,
del2: 0.0,
c,
samplerate: sr,
center_mod: None,
bw_mod: None,
gain_mod: None,
}
}
fn update_internals(&mut self, center: f32, bw: f32, gain: f32) {
let w_c = (2.0 * center) / self.samplerate;
let w_b = (2.0 * bw) / self.samplerate;
self.d = -((std::f32::consts::PI * w_c).cos());
self.v_zero = (10.0_f32).powf(gain / 20.0);
self.h_zero = self.v_zero - 1.0;
let cf_tan = (std::f32::consts::PI * w_b / 2.0).tan();
self.c = if gain >= 0.0 {
(cf_tan - 1.0) / (cf_tan + 1.0)
} else {
(cf_tan - self.v_zero) / (cf_tan + self.v_zero)
};
}
}
impl<const BUFSIZE: usize> MonoEffect<BUFSIZE> for PeakEq<BUFSIZE> {
fn set_modulator(
&mut self,
par: SynthParameterLabel,
init: f32,
modulator: Modulator<BUFSIZE>,
) {
let mut update = false;
match par {
SynthParameterLabel::PeakFrequency => {
self.center = init;
self.center_mod = Some(modulator);
update = true;
}
SynthParameterLabel::PeakGain => {
self.gain = init;
self.gain_mod = Some(modulator);
update = true;
}
SynthParameterLabel::PeakBandwidth => {
self.bw = init;
self.bw_mod = Some(modulator);
update = true;
}
_ => {}
}
if update {
self.update_internals(self.center, self.bw, self.gain);
}
}
fn set_parameter(&mut self, par: SynthParameterLabel, value: &SynthParameterValue) {
let mut update = true;
if let SynthParameterValue::ScalarF32(val) = value {
match par {
SynthParameterLabel::PeakFrequency => {
self.center = *val;
update = true;
}
SynthParameterLabel::PeakGain => {
self.gain = *val;
update = true;
}
SynthParameterLabel::PeakBandwidth => {
self.bw = *val;
update = true;
}
_ => (),
};
if update {
self.update_internals(self.center, self.bw, self.gain);
}
}
}
fn finish(&mut self) {} fn is_finished(&self) -> bool {
false
}
fn process_block(
&mut self,
block: [f32; BUFSIZE],
start_sample: usize,
in_buffers: &[Vec<f32>],
) -> [f32; BUFSIZE] {
let mut out_buf: [f32; BUFSIZE] = [0.0; BUFSIZE];
if self.center_mod.is_some() || self.bw_mod.is_some() || self.gain_mod.is_some() {
let center_buf = if let Some(m) = self.center_mod.as_mut() {
m.process(self.center, start_sample, in_buffers)
} else {
[self.center; BUFSIZE]
};
let bw_buf = if let Some(m) = self.bw_mod.as_mut() {
m.process(self.bw, start_sample, in_buffers)
} else {
[self.bw; BUFSIZE]
};
let gain_buf = if let Some(m) = self.gain_mod.as_mut() {
m.process(self.gain, start_sample, in_buffers)
} else {
[self.gain; BUFSIZE]
};
for i in start_sample..BUFSIZE {
self.update_internals(center_buf[i], bw_buf[i], gain_buf[i]);
let x_h = block[i] - self.d * (1.0 - self.c) * self.del1 + (self.c * self.del2);
let y_one =
(-1.0 * self.c * x_h) + (self.d * (1.0 - self.c) * self.del1) + self.del2;
out_buf[i] = 0.5 * self.h_zero * (block[i] - y_one) + block[i];
self.del2 = self.del1;
self.del1 = x_h;
}
} else {
for i in 0..BUFSIZE {
let x_h = block[i] - self.d * (1.0 - self.c) * self.del1 + (self.c * self.del2);
let y_one =
(-1.0 * self.c * x_h) + (self.d * (1.0 - self.c) * self.del1) + self.del2;
out_buf[i] = 0.5 * self.h_zero * (block[i] - y_one) + block[i];
self.del2 = self.del1;
self.del1 = x_h;
}
}
out_buf
}
}