From ebb5dd3a9b68aeedc2f11adbd2f4ee576cbc6384 Mon Sep 17 00:00:00 2001 From: Weird Constructor Date: Sat, 10 Jul 2021 22:45:08 +0200 Subject: [PATCH] added high pass implementations too now. --- src/dsp/helpers.rs | 32 +++++++++++++++++++++ src/dsp/node_sfilter.rs | 61 +++++++++++++++++++++-------------------- tests/node_sfilter.rs | 3 +- 3 files changed, 65 insertions(+), 31 deletions(-) diff --git a/src/dsp/helpers.rs b/src/dsp/helpers.rs index 48d620d..7e9e70c 100644 --- a/src/dsp/helpers.rs +++ b/src/dsp/helpers.rs @@ -715,6 +715,23 @@ pub fn process_1pole_lowpass(input: f64, freq: f64, israte: f64, z: &mut f64) -> *z } +// one pole hp from valley rack free: +// https://github.com/ValleyAudio/ValleyRackFree/blob/v1.0/src/Common/DSP/OnePoleFilters.cpp +#[inline] +pub fn process_1pole_highpass(input: f64, freq: f64, israte: f64, z: &mut f64, y: &mut f64) -> f64 { + let b = (-std::f64::consts::TAU * freq * israte).exp(); + let a = (1.0 + b) / 2.0; + let a1 = - a; + + let v = + a * input + + a1 * *z + + b * *y; + *y = v; + *z = input; + v +} + // one pole from: // http://www.willpirkle.com/Downloads/AN-4VirtualAnalogFilters.pdf // (page 5) @@ -732,6 +749,21 @@ pub fn process_1pole_tpt_lowpass(input: f64, freq: f64, israte: f64, z: &mut f64 v2 } +// one pole from: +// http://www.willpirkle.com/Downloads/AN-4VirtualAnalogFilters.pdf +// (page 5) +#[inline] +pub fn process_1pole_tpt_highpass(input: f64, freq: f64, israte: f64, z: &mut f64) -> f64 { + let g = (std::f64::consts::PI * freq * israte).tan(); + let a1 = g / (1.0 + g); + + let v1 = a1 * (input - *z); + let v2 = v1 + *z; + *z = v2 + v1; + + input - v2 +} + // translated from Odin 2 Synthesizer Plugin // Copyright (C) 2020 TheWaveWarden // under GPLv3 or any later diff --git a/src/dsp/node_sfilter.rs b/src/dsp/node_sfilter.rs index 5cee422..4ed006d 100644 --- a/src/dsp/node_sfilter.rs +++ b/src/dsp/node_sfilter.rs @@ -4,16 +4,21 @@ use crate::nodes::{NodeAudioContext, NodeExecContext}; use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext}; -use crate::dsp::helpers::{process_1pole_lowpass, process_1pole_tpt_lowpass}; +use crate::dsp::helpers::{ + process_1pole_lowpass, + process_1pole_highpass, + process_1pole_tpt_lowpass, + process_1pole_tpt_highpass, +}; #[macro_export] macro_rules! fa_sfilter_type { ($formatter: expr, $v: expr, $denorm_v: expr) => { { let s = match ($v.round() as usize) { 0 => "LP(1p)", - 1 => "LP(1p,TPT)", + 1 => "LP(1pt)", 2 => "HP(1p)", - 3 => "HP(1p,TPT)", + 3 => "HP(1pt)", _ => "?", }; write!($formatter, "{}", s) @@ -80,48 +85,46 @@ impl DspNode for SFilter { let out = out::SFilter::sig(outputs); match ftype.i() { - // one pole lp from valley rack free: - // https://github.com/ValleyAudio/ValleyRackFree/blob/v1.0/src/Common/DSP/OnePoleFilters.cpp 0 => { for frame in 0..ctx.nframes() { let input = inp.read(frame) as f64; let freq = (denorm::SFilter::freq(freq, frame) as f64); out.write(frame, - process_1pole_lowpass(input, freq, self.israte, &mut self.z) + process_1pole_lowpass( + input, freq, self.israte, &mut self.z) as f32); } }, - // one pole from: - // http://www.willpirkle.com/Downloads/AN-4VirtualAnalogFilters.pdf - // (page 5) 1 => { for frame in 0..ctx.nframes() { let input = inp.read(frame) as f64; let freq = (denorm::SFilter::freq(freq, frame) as f64); out.write(frame, - process_1pole_tpt_lowpass(input, freq, self.israte, &mut self.z) + process_1pole_tpt_lowpass( + input, freq, self.israte, &mut self.z) + as f32); + } + }, + 2 => { + for frame in 0..ctx.nframes() { + let input = inp.read(frame) as f64; + let freq = (denorm::SFilter::freq(freq, frame) as f64); + out.write(frame, + process_1pole_highpass( + input, freq, self.israte, &mut self.z, &mut self.y) + as f32); + } + }, + 3 => { + for frame in 0..ctx.nframes() { + let input = inp.read(frame) as f64; + let freq = (denorm::SFilter::freq(freq, frame) as f64); + out.write(frame, + process_1pole_tpt_highpass( + input, freq, self.israte, &mut self.z) as f32); } }, -// // From https://en.wikipedia.org/wiki/RC_circuit -// // has the same output as the SVF variant, takes the same amount of time. -// 3 => { -// for frame in 0..ctx.nframes() { -// let input = inp.read(frame) as f64; -// let c = -// 2.0 -// / (std::f64::consts::TAU -// * (denorm::SFilter::freq(freq, frame) as f64) -// * self.israte); -// -// let y = (input + self.z - self.y * (1.0 - c)) / (1.0 + c); -// self.z = input; -// self.y = y; -// -// // highpass: self.z - self.y -// out.write(frame, y as f32); -// } -// }, _ => {}, } } diff --git a/tests/node_sfilter.rs b/tests/node_sfilter.rs index 5ba9f68..332287b 100644 --- a/tests/node_sfilter.rs +++ b/tests/node_sfilter.rs @@ -20,7 +20,7 @@ fn check_node_sfilter_compare() { .out(None, None, noise.out("sig"))); matrix.place(1, 2, Cell::empty(out) .input(out.inp("ch2"), None, None)); - pset_d(&mut matrix, sf, "freq", 100.0); + pset_d(&mut matrix, sf, "freq", 440.0); matrix.sync().unwrap(); let ta = std::time::Instant::now(); @@ -44,7 +44,6 @@ fn check_node_sfilter_compare() { let ta = std::time::Instant::now().duration_since(ta); println!("ta2 Elapsed: {:?}", ta); - pset_s(&mut matrix, sf, "ftype", 2); let ta = std::time::Instant::now();