use crate::building_blocks::{Modulator, MonoEffect, SynthParameterLabel, SynthParameterValue};
use crate::building_blocks::filters::sos::*;
pub struct BiquadHpf12dB<const BUFSIZE: usize> {
cutoff: f32,
q: f32,
coefs: SOSCoefs,
delay: SOSDelay,
samplerate: f32,
cutoff_mod: Option<Modulator<BUFSIZE>>,
q_mod: Option<Modulator<BUFSIZE>>,
}
impl<const BUFSIZE: usize> BiquadHpf12dB<BUFSIZE> {
pub fn new(freq: f32, q: f32, sr: f32) -> Self {
let mut coefs: SOSCoefs = SOSCoefs::default();
BiquadHpf12dB::<BUFSIZE>::generate_coefs(&mut coefs, freq, q, sr);
BiquadHpf12dB {
cutoff: freq,
q,
coefs,
delay: SOSDelay::default(),
samplerate: sr,
cutoff_mod: None,
q_mod: None,
}
}
#[inline(always)]
pub fn generate_coefs(coefs: &mut SOSCoefs, cutoff: f32, q: f32, sr: f32) {
let k = ((std::f32::consts::PI * cutoff) / sr).tanh();
let k_pow_two = k.powf(2.0);
coefs.a1 = (2.0 * q * (k_pow_two - 1.0)) / ((k_pow_two * q) + k + q);
coefs.a2 = ((k_pow_two * q) - k + q) / ((k_pow_two * q) + k + q);
coefs.b0 = q / ((k_pow_two * q) + k + q);
coefs.b1 = -1.0 * ((2.0 * q) / ((k_pow_two * q) + k + q));
coefs.b2 = coefs.b0;
}
}
impl<const BUFSIZE: usize> MonoEffect<BUFSIZE> for BiquadHpf12dB<BUFSIZE> {
fn set_modulator(
&mut self,
par: SynthParameterLabel,
init: f32,
modulator: Modulator<BUFSIZE>,
) {
let mut update = false;
match par {
SynthParameterLabel::HighpassCutoffFrequency => {
self.cutoff = init;
self.cutoff_mod = Some(modulator);
update = true;
}
SynthParameterLabel::HighpassQFactor => {
self.q = init;
self.q_mod = Some(modulator);
update = true;
}
_ => {}
}
if update {
BiquadHpf12dB::<BUFSIZE>::generate_coefs(
&mut self.coefs,
self.cutoff,
self.q,
self.samplerate,
);
}
}
fn set_parameter(&mut self, par: SynthParameterLabel, value: &SynthParameterValue) {
let mut update = false;
if let SynthParameterValue::ScalarF32(val) = value {
match par {
SynthParameterLabel::HighpassCutoffFrequency => {
self.cutoff = *val;
update = true;
}
SynthParameterLabel::HighpassQFactor => {
self.q = *val;
update = true;
}
_ => (),
};
if update {
BiquadHpf12dB::<BUFSIZE>::generate_coefs(
&mut self.coefs,
self.cutoff,
self.q,
self.samplerate,
);
}
}
}
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] {
if self.cutoff_mod.is_some() || self.q_mod.is_some() {
let mut out_buf: [f32; BUFSIZE] = [0.0; BUFSIZE];
let cutoff_buf = if let Some(m) = self.cutoff_mod.as_mut() {
m.process(self.cutoff, start_sample, in_buffers)
} else {
[self.cutoff; BUFSIZE]
};
let q_buf = if let Some(m) = self.q_mod.as_mut() {
m.process(self.q, start_sample, in_buffers)
} else {
[self.q; BUFSIZE]
};
for i in start_sample..BUFSIZE {
BiquadHpf12dB::<BUFSIZE>::generate_coefs(
&mut self.coefs,
cutoff_buf[i],
q_buf[i],
self.samplerate,
);
out_buf[i] = process_sos_sample(&self.coefs, &mut self.delay, block[i]);
}
out_buf
} else {
process_sos_block::<BUFSIZE>(&self.coefs, &mut self.delay, block)
}
}
}