From 7a46c38a004b82bee8791940cc35ba1f1ded5643 Mon Sep 17 00:00:00 2001 From: Weird Constructor Date: Thu, 15 Jul 2021 06:28:44 +0200 Subject: [PATCH] use f32 instead of f64 for filtering --- src/dsp/helpers.rs | 30 +++++++------- src/dsp/node_sfilter.rs | 86 ++++++++++++++++++++++++++++++++++------- 2 files changed, 87 insertions(+), 29 deletions(-) diff --git a/src/dsp/helpers.rs b/src/dsp/helpers.rs index add8ac7..0430320 100644 --- a/src/dsp/helpers.rs +++ b/src/dsp/helpers.rs @@ -791,8 +791,8 @@ impl Comb { /// // ... do something with the result here. /// } ///``` -pub fn process_1pole_lowpass(input: f64, freq: f64, israte: f64, z: &mut f64) -> f64 { - let b = (-std::f64::consts::TAU * freq * israte).exp(); +pub fn process_1pole_lowpass(input: f32, freq: f32, israte: f32, z: &mut f32) -> f32 { + let b = (-std::f32::consts::TAU * freq * israte).exp(); let a = 1.0 - b; *z = a * input + *z * b; *z @@ -824,8 +824,8 @@ pub fn process_1pole_lowpass(input: f64, freq: f64, israte: f64, z: &mut f64) -> /// // ... do something with the result here. /// } ///``` -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(); +pub fn process_1pole_highpass(input: f32, freq: f32, israte: f32, z: &mut f32, y: &mut f32) -> f32 { + let b = (-std::f32::consts::TAU * freq * israte).exp(); let a = (1.0 + b) / 2.0; let v = @@ -863,8 +863,8 @@ pub fn process_1pole_highpass(input: f64, freq: f64, israte: f64, z: &mut f64, y /// // ... do something with the result here. /// } ///``` -pub fn process_1pole_tpt_lowpass(input: f64, freq: f64, israte: f64, z: &mut f64) -> f64 { - let g = (std::f64::consts::PI * freq * israte).tan(); +pub fn process_1pole_tpt_lowpass(input: f32, freq: f32, israte: f32, z: &mut f32) -> f32 { + let g = (std::f32::consts::PI * freq * israte).tan(); let a = g / (1.0 + g); let v1 = a * (input - *z); @@ -901,8 +901,8 @@ pub fn process_1pole_tpt_lowpass(input: f64, freq: f64, israte: f64, z: &mut f64 /// // ... do something with the result here. /// } ///``` -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(); +pub fn process_1pole_tpt_highpass(input: f32, freq: f32, israte: f32, z: &mut f32) -> f32 { + let g = (std::f32::consts::PI * freq * israte).tan(); let a1 = g / (1.0 + g); let v1 = a1 * (input - *z); @@ -952,11 +952,11 @@ const FILTER_OVERSAMPLE_HAL_CHAMBERLIN : usize = 2; ///``` #[inline] pub fn process_hal_chamberlin_svf( - input: f64, freq: f64, res: f64, israte: f64, band: &mut f64, low: &mut f64) - -> (f64, f64) + input: f32, freq: f32, res: f32, israte: f32, band: &mut f32, low: &mut f32) + -> (f32, f32) { let q = 1.0 - res; - let cutoff = 2.0 * (std::f64::consts::PI * freq * 0.5 * israte).sin(); + let cutoff = 2.0 * (std::f32::consts::PI * freq * 0.5 * israte).sin(); let mut high = 0.0; let mut notch = 0.0; @@ -1015,11 +1015,11 @@ pub fn process_hal_chamberlin_svf( // thanks, andy! #[inline] pub fn process_simper_svf( - input: f64, freq: f64, res: f64, israte: f64, ic1eq: &mut f64, ic2eq: &mut f64 -) -> (f64, f64, f64) { - let g = (std::f64::consts::PI * freq * israte).tan(); + input: f32, freq: f32, res: f32, israte: f32, ic1eq: &mut f32, ic2eq: &mut f32 +) -> (f32, f32, f32) { + let g = (std::f32::consts::PI * freq * israte).tan(); // XXX: the 1.989 were tuned by hand, so the resonance is more audible. - let k = 2f64 - (1.989f64 * res); + let k = 2f32 - (1.989f32 * res); let a1 = 1.0 / (1.0 + (g * (g + k))); let a2 = g * a1; diff --git a/src/dsp/node_sfilter.rs b/src/dsp/node_sfilter.rs index 324eff9..de66a1d 100644 --- a/src/dsp/node_sfilter.rs +++ b/src/dsp/node_sfilter.rs @@ -38,9 +38,11 @@ macro_rules! fa_sfilter_type { ($formatter: expr, $v: expr, $denorm_v: expr) => /// A simple amplifier #[derive(Debug, Clone)] pub struct SFilter { - israte: f64, - z: f64, - y: f64, + israte: f32, + z: f32, + y: f32, + k: f32, + h: f32, otype: i8, } @@ -50,6 +52,8 @@ impl SFilter { israte: 1.0 / 44100.0, z: 0.0, y: 0.0, + k: 0.0, + h: 0.0, otype: -1, } } @@ -102,6 +106,56 @@ The (Andrew) Simper state variable filter is a newer design. "#; } +macro_rules! process_filter_fun32 { + ($nframes: expr, $inp: expr, $out: ident, $freq: ident, $res: ident, + $input: ident, $minfreq: expr, $maxfreq: expr, $block: block) => { { + for frame in 0..$nframes { + let $input = $inp.read(frame); + let $freq = denorm::SFilter::freq($freq, frame); + let $freq = $freq.clamp($minfreq, $maxfreq); + let $res = denorm::SFilter::res($res, frame); + let $res = $res.clamp(0.0, 0.99); + let s = $block; + $out.write(frame, s); + } + } }; + ($nframes: expr, $inp: expr, $out: ident, $freq: ident, $res: ident, + $input: ident, $maxfreq: expr, $block: block) => { { + for frame in 0..$nframes { + let $input = $inp.read(frame); + let $freq = denorm::SFilter::freq($freq, frame); + let $freq = $freq.clamp(1.0, $maxfreq); + let $res = denorm::SFilter::res($res, frame); + let $res = $res.clamp(0.0, 0.99); + let s = $block; + $out.write(frame, s); + } + } }; + ($nframes: expr, $inp: expr, $out: ident, $freq: ident, $res: ident, + $maxres: expr, $input: ident, $maxfreq: expr, $block: block) => { { + for frame in 0..$nframes { + let $input = $inp.read(frame); + let $freq = denorm::SFilter::freq($freq, frame); + let $freq = $freq.clamp(1.0, $maxfreq); + let $res = denorm::SFilter::res($res, frame); + let $res = $res.clamp(0.0, $maxres); + let s = $block; + $out.write(frame, s); + } + } }; + ($nframes: expr, $inp: expr, $out: ident, $freq: ident, + $input: ident, $maxfreq: expr, $block: block) => { { + for frame in 0..$nframes { + let $input = $inp.read(frame); + let $freq = denorm::SFilter::freq($freq, frame); + let $freq = $freq.clamp(1.0, $maxfreq); + let s = $block; + $out.write(frame, s); + } + } } +} + + macro_rules! process_filter_fun { ($nframes: expr, $inp: expr, $out: ident, $freq: ident, $res: ident, $input: ident, $minfreq: expr, $maxfreq: expr, $block: block) => { { @@ -155,11 +209,13 @@ impl DspNode for SFilter { fn outputs() -> usize { 1 } fn set_sample_rate(&mut self, srate: f32) { - self.israte = 1.0 / (srate as f64); + self.israte = 1.0 / srate; } fn reset(&mut self) { self.z = 0.0; self.y = 0.0; + self.k = 0.0; + self.h = 0.0; self.otype = -1; } @@ -183,40 +239,42 @@ impl DspNode for SFilter { if ftype != self.otype { self.y = 0.0; self.z = 0.0; + self.k = 0.0; + self.h = 0.0; self.otype = ftype; } match ftype { 0 => { // Lowpass - process_filter_fun!( + process_filter_fun32!( ctx.nframes(), inp, out, freq, input, 22000.0, { process_1pole_lowpass( input, freq, self.israte, &mut self.z) }) }, 1 => { // Lowpass TPT - process_filter_fun!( + process_filter_fun32!( ctx.nframes(), inp, out, freq, input, 22000.0, { process_1pole_tpt_lowpass( input, freq, self.israte, &mut self.z) }) }, 2 => { // Highpass - process_filter_fun!( + process_filter_fun32!( ctx.nframes(), inp, out, freq, input, 22000.0, { process_1pole_highpass( input, freq, self.israte, &mut self.z, &mut self.y) }) }, 3 => { // Highpass TPT - process_filter_fun!( + process_filter_fun32!( ctx.nframes(), inp, out, freq, input, 22000.0, { process_1pole_tpt_highpass( input, freq, self.israte, &mut self.z) }) }, 4 => { // Low Pass Hal Chamberlin SVF - process_filter_fun!( + process_filter_fun32!( ctx.nframes(), inp, out, freq, res, input, 2.0, 16000.0, { let (_high, _notch) = process_hal_chamberlin_svf( @@ -226,7 +284,7 @@ impl DspNode for SFilter { }); }, 5 => { // High Pass Hal Chamberlin SVF - process_filter_fun!( + process_filter_fun32!( ctx.nframes(), inp, out, freq, res, input, 16000.0, { let (high, _notch) = process_hal_chamberlin_svf( @@ -236,7 +294,7 @@ impl DspNode for SFilter { }); }, 6 => { // Band Pass Hal Chamberlin SVF - process_filter_fun!( + process_filter_fun32!( ctx.nframes(), inp, out, freq, res, input, 16000.0, { let (_high, _notch) = process_hal_chamberlin_svf( @@ -246,7 +304,7 @@ impl DspNode for SFilter { }); }, 7 => { // Notch Hal Chamberlin SVF - process_filter_fun!( + process_filter_fun32!( ctx.nframes(), inp, out, freq, res, input, 16000.0, { let (_high, notch) = process_hal_chamberlin_svf( @@ -256,12 +314,12 @@ impl DspNode for SFilter { }); }, 8 => { // Simper SVF Low Pass - process_filter_fun!( + process_filter_fun32!( ctx.nframes(), inp, out, freq, res, 1.0, input, 22000.0, { let (low, _band, _high) = process_simper_svf( input, freq, res, self.israte, - &mut self.z, &mut self.y); + &mut self.k, &mut self.h); low }); },