Finished more generic float types in helpers.rs

This commit is contained in:
Weird Constructor 2021-08-08 09:43:16 +02:00
parent d6c1a38102
commit 14bf59bfac
6 changed files with 103 additions and 89 deletions

View file

@ -3,7 +3,16 @@
// See README.md and COPYING for details. // See README.md and COPYING for details.
use std::cell::RefCell; use std::cell::RefCell;
use num_traits::{Float, FloatConst, cast::FromPrimitive}; use num_traits::{Float, FloatConst, cast::FromPrimitive, cast::ToPrimitive};
macro_rules! trait_alias {
($name:ident = $base1:ident + $($base2:ident +)+) => {
pub trait $name: $base1 $(+ $base2)+ { }
impl<T: $base1 $(+ $base2)+> $name for T { }
};
}
trait_alias!(Flt = Float + FloatConst + ToPrimitive + FromPrimitive +);
/// Logarithmic table size of the table in [fast_cos] / [fast_sin]. /// Logarithmic table size of the table in [fast_cos] / [fast_sin].
static FAST_COS_TAB_LOG2_SIZE : usize = 9; static FAST_COS_TAB_LOG2_SIZE : usize = 9;
@ -703,27 +712,32 @@ macro_rules! fc {
($F: ident, $e: expr) => { F::from_f64($e).unwrap() } ($F: ident, $e: expr) => { F::from_f64($e).unwrap() }
} }
#[inline]
fn f<F: Flt>(x: f64) -> F { F::from_f64(x).unwrap() }
fn fclamp<F: Flt>(x: F, mi: F, mx: F) -> F { x.max(mi).min(mx) }
fn fclampc<F: Flt>(x: F, mi: f64, mx: f64) -> F { x.max(f(mi)).min(f(mx)) }
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct DelayBuffer<F: Float> { pub struct DelayBuffer<F: Flt> {
data: Vec<F>, data: Vec<F>,
wr: usize, wr: usize,
srate: F, srate: F,
} }
impl<F: Float + FromPrimitive> DelayBuffer<F> { impl<F: Flt> DelayBuffer<F> {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
data: vec![fc!(F,0.0); DEFAULT_DELAY_BUFFER_SAMPLES], data: vec![f(0.0); DEFAULT_DELAY_BUFFER_SAMPLES],
wr: 0, wr: 0,
srate: fc!(F, 44100.0), srate: f(44100.0),
} }
} }
pub fn new_with_size(size: usize) -> Self { pub fn new_with_size(size: usize) -> Self {
Self { Self {
data: vec![fc!(F, 0.0); size], data: vec![f(0.0); size],
wr: 0, wr: 0,
srate: fc!(F, 44100.0), srate: f(44100.0),
} }
} }
@ -732,7 +746,7 @@ impl<F: Float + FromPrimitive> DelayBuffer<F> {
} }
pub fn reset(&mut self) { pub fn reset(&mut self) {
self.data.fill(0.0); self.data.fill(f(0.0));
self.wr = 0; self.wr = 0;
} }
@ -778,8 +792,8 @@ impl<F: Float + FromPrimitive> DelayBuffer<F> {
pub fn linear_interpolate_at(&self, delay_time_ms: F) -> F { pub fn linear_interpolate_at(&self, delay_time_ms: F) -> F {
let data = &self.data[..]; let data = &self.data[..];
let len = data.len(); let len = data.len();
let s_offs = (delay_time_ms * self.srate) / 1000.0; let s_offs = (delay_time_ms * self.srate) / f(1000.0);
let offs = s_offs.floor() as usize % len; let offs = s_offs.floor().to_usize().unwrap() % len;
let fract = s_offs.fract(); let fract = s_offs.fract();
let i = (self.wr + len) - offs; let i = (self.wr + len) - offs;
@ -787,7 +801,7 @@ impl<F: Float + FromPrimitive> DelayBuffer<F> {
let x1 = data[(i + 1) % len]; let x1 = data[(i + 1) % len];
let fract = fract as F; let fract = fract as F;
x0 * (1.0 - fract) + x1 * fract x0 * (f::<F>(1.0) - fract) + x1 * fract
} }
/// Fetch a sample from the delay buffer at the given time. /// Fetch a sample from the delay buffer at the given time.
@ -797,8 +811,8 @@ impl<F: Float + FromPrimitive> DelayBuffer<F> {
pub fn cubic_interpolate_at(&self, delay_time_ms: F) -> F { pub fn cubic_interpolate_at(&self, delay_time_ms: F) -> F {
let data = &self.data[..]; let data = &self.data[..];
let len = data.len(); let len = data.len();
let s_offs = (delay_time_ms * self.srate) / 1000.0; let s_offs = (delay_time_ms * self.srate) / f(1000.0);
let offs = s_offs.floor() as usize % len; let offs = s_offs.floor().to_usize().unwrap() % len;
let fract = s_offs.fract(); let fract = s_offs.fract();
let i = (self.wr + len) - offs; let i = (self.wr + len) - offs;
@ -815,10 +829,10 @@ impl<F: Float + FromPrimitive> DelayBuffer<F> {
let x1 = data[(i + 1) % len]; let x1 = data[(i + 1) % len];
let x2 = data[(i + 2) % len]; let x2 = data[(i + 2) % len];
let c = (x1 - xm1) * 0.5; let c = (x1 - xm1) * f(0.5);
let v = x0 - x1; let v = x0 - x1;
let w = c + v; let w = c + v;
let a = w + v + (x2 - x0) * 0.5; let a = w + v + (x2 - x0) * f(0.5);
let b_neg = w + a; let b_neg = w + a;
let fract = fract as F; let fract = fract as F;
@ -828,7 +842,10 @@ impl<F: Float + FromPrimitive> DelayBuffer<F> {
#[inline] #[inline]
pub fn nearest_at(&self, delay_time_ms: F) -> F { pub fn nearest_at(&self, delay_time_ms: F) -> F {
let len = self.data.len(); let len = self.data.len();
let offs = ((delay_time_ms * self.srate) / 1000.0).floor() as usize % len; let offs =
((delay_time_ms * self.srate)
/ f(1000.0))
.floor().to_usize().unwrap() % len;
let idx = ((self.wr + len) - offs) % len; let idx = ((self.wr + len) - offs) % len;
self.data[idx] self.data[idx]
} }
@ -845,11 +862,11 @@ impl<F: Float + FromPrimitive> DelayBuffer<F> {
const DEFAULT_ALLPASS_COMB_SAMPLES : usize = 8 * 48000; const DEFAULT_ALLPASS_COMB_SAMPLES : usize = 8 * 48000;
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct AllPass<F: Float> { pub struct AllPass<F: Flt> {
delay: DelayBuffer<F>, delay: DelayBuffer<F>,
} }
impl<F: Float> AllPass<F> { impl<F: Flt> AllPass<F> {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
delay: DelayBuffer::new_with_size(DEFAULT_ALLPASS_COMB_SAMPLES), delay: DelayBuffer::new_with_size(DEFAULT_ALLPASS_COMB_SAMPLES),
@ -956,7 +973,7 @@ pub fn process_1pole_lowpass(input: f32, freq: f32, israte: f32, z: &mut f32) ->
} }
#[derive(Debug, Clone, Copy, Default)] #[derive(Debug, Clone, Copy, Default)]
pub struct OnePoleLPF<F: Float> { pub struct OnePoleLPF<F: Flt> {
israte: F, israte: F,
a: F, a: F,
b: F, b: F,
@ -964,29 +981,29 @@ pub struct OnePoleLPF<F: Float> {
z: F, z: F,
} }
impl<F: Float + FloatConst> OnePoleLPF<F> { impl<F: Flt> OnePoleLPF<F> {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
israte: 1.0 / 44100.0, israte: f::<F>(1.0) / f(44100.0),
a: 0.0, a: f::<F>(0.0),
b: 0.0, b: f::<F>(0.0),
freq: 1000.0, freq: f::<F>(1000.0),
z: 0.0, z: f::<F>(0.0),
} }
} }
pub fn reset(&mut self) { pub fn reset(&mut self) {
self.z = 0.0; self.z = f(0.0);
} }
#[inline] #[inline]
fn recalc(&mut self) { fn recalc(&mut self) {
self.b = (-F::TAU * self.freq * self.israte).exp(); self.b = (f::<F>(-1.0) * F::TAU() * self.freq * self.israte).exp();
self.a = 1.0 - self.b; self.a = f::<F>(1.0) - self.b;
} }
pub fn set_sample_rate(&mut self, srate: F) { pub fn set_sample_rate(&mut self, srate: F) {
self.israte = 1.0 / srate; self.israte = f::<F>(1.0) / srate;
self.recalc(); self.recalc();
} }
@ -1045,7 +1062,7 @@ pub fn process_1pole_highpass(input: f32, freq: f32, israte: f32, z: &mut f32, y
} }
#[derive(Debug, Clone, Copy, Default)] #[derive(Debug, Clone, Copy, Default)]
pub struct OnePoleHPF<F: Float> { pub struct OnePoleHPF<F: Flt> {
israte: F, israte: F,
a: F, a: F,
b: F, b: F,
@ -1054,32 +1071,32 @@ pub struct OnePoleHPF<F: Float> {
y: F, y: F,
} }
impl<F: Float + FloatConst> OnePoleHPF<F> { impl<F: Flt> OnePoleHPF<F> {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
israte: 1.0 / 44100.0, israte: f(1.0 / 44100.0),
a: 0.0, a: f(0.0),
b: 0.0, b: f(0.0),
freq: 1000.0, freq: f(1000.0),
z: 0.0, z: f(0.0),
y: 0.0, y: f(0.0),
} }
} }
pub fn reset(&mut self) { pub fn reset(&mut self) {
self.z = 0.0; self.z = f(0.0);
self.y = 0.0; self.y = f(0.0);
} }
#[inline] #[inline]
fn recalc(&mut self) { fn recalc(&mut self) {
self.b = (-F::TAU * self.freq * self.israte).exp(); self.b = (f::<F>(-1.0) * F::TAU() * self.freq * self.israte).exp();
self.a = (1.0 + self.b) / 2.0; self.a = (f::<F>(1.0) + self.b) / f(2.0);
} }
pub fn set_sample_rate(&mut self, srate: F) { pub fn set_sample_rate(&mut self, srate: F) {
self.israte = 1.0 / srate; self.israte = f::<F>(1.0) / srate;
self.recalc(); self.recalc();
} }
@ -1401,38 +1418,38 @@ pub fn process_stilson_moog(
// Copyright (C) 2020 TheWaveWarden // Copyright (C) 2020 TheWaveWarden
// under GPLv3 or any later // under GPLv3 or any later
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct DCBlockFilter<F: Float> { pub struct DCBlockFilter<F: Flt> {
xm1: F, xm1: F,
ym1: F, ym1: F,
r: F, r: F,
} }
impl<F: Float> DCBlockFilter<F> { impl<F: Flt> DCBlockFilter<F> {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
xm1: 0.0, xm1: f(0.0),
ym1: 0.0, ym1: f(0.0),
r: 0.995, r: f(0.995),
} }
} }
pub fn reset(&mut self) { pub fn reset(&mut self) {
self.xm1 = 0.0; self.xm1 = f(0.0);
self.ym1 = 0.0; self.ym1 = f(0.0);
} }
pub fn set_sample_rate(&mut self, srate: F) { pub fn set_sample_rate(&mut self, srate: F) {
self.r = 0.995; self.r = f(0.995);
if srate > 90000.0 { if srate > f(90000.0) {
self.r = 0.9965; self.r = f(0.9965);
} else if srate > 120000.0 { } else if srate > f(120000.0) {
self.r = 0.997; self.r = f(0.997);
} }
} }
pub fn next(&mut self, input: F) -> F { pub fn next(&mut self, input: F) -> F {
let y = input as f64 - self.xm1 + self.r * self.ym1; let y = input - self.xm1 + self.r * self.ym1;
self.xm1 = input as f64; self.xm1 = input;
self.ym1 = y; self.ym1 = y;
y as F y as F
} }
@ -1883,7 +1900,7 @@ impl VPSOscillator {
/// An LFO with a variable reverse point, which can go from reverse Saw, to Tri /// An LFO with a variable reverse point, which can go from reverse Saw, to Tri
/// and to Saw, depending on the reverse point. /// and to Saw, depending on the reverse point.
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct TriSawLFO<F: Float> { pub struct TriSawLFO<F: Flt> {
/// The (inverse) sample rate. Eg. 1.0 / 44100.0. /// The (inverse) sample rate. Eg. 1.0 / 44100.0.
israte: F, israte: F,
/// The current oscillator phase. /// The current oscillator phase.
@ -1901,17 +1918,17 @@ pub struct TriSawLFO<F: Float> {
init_phase: F, init_phase: F,
} }
impl<F: Float> TriSawLFO<F> { impl<F: Flt> TriSawLFO<F> {
pub fn new() -> Self { pub fn new() -> Self {
let mut this = Self { let mut this = Self {
israte: 1.0 / 44100.0, israte: f(1.0 / 44100.0),
phase: 0.0, phase: f(0.0),
rev: 0.5, rev: f(0.5),
rising: true, rising: true,
freq: 1.0, freq: f(1.0),
fall_r: 0.0, fall_r: f(0.0),
rise_r: 0.0, rise_r: f(0.0),
init_phase: 0.0, init_phase: f(0.0),
}; };
this.recalc(); this.recalc();
this this
@ -1924,19 +1941,19 @@ impl<F: Float> TriSawLFO<F> {
#[inline] #[inline]
fn recalc(&mut self) { fn recalc(&mut self) {
self.rev = self.rev.clamp(0.0001, 0.999); self.rev = fclampc(self.rev, 0.0001, 0.999);
self.rise_r = 1.0 / self.rev; self.rise_r = f::<F>( 1.0) / self.rev;
self.fall_r = -1.0 / (1.0 - self.rev); self.fall_r = f::<F>(-1.0) / (f::<F>(1.0) - self.rev);
} }
pub fn set_sample_rate(&mut self, srate: F) { pub fn set_sample_rate(&mut self, srate: F) {
self.israte = 1.0 / (srate as F); self.israte = f::<F>(1.0) / (srate as F);
self.recalc(); self.recalc();
} }
pub fn reset(&mut self) { pub fn reset(&mut self) {
self.phase = self.init_phase; self.phase = self.init_phase;
self.rev = 0.5; self.rev = f(0.5);
self.rising = true; self.rising = true;
} }
@ -1949,8 +1966,8 @@ impl<F: Float> TriSawLFO<F> {
#[inline] #[inline]
pub fn next_unipolar(&mut self) -> F { pub fn next_unipolar(&mut self) -> F {
if self.phase >= 1.0 { if self.phase >= f(1.0) {
self.phase -= 1.0; self.phase = self.phase - f(1.0);
self.rising = true; self.rising = true;
} }
@ -1965,14 +1982,14 @@ impl<F: Float> TriSawLFO<F> {
self.phase * self.fall_r - self.fall_r self.phase * self.fall_r - self.fall_r
}; };
self.phase += self.freq * self.israte; self.phase = self.phase + self.freq * self.israte;
s s
} }
#[inline] #[inline]
pub fn next_bipolar(&mut self) -> F { pub fn next_bipolar(&mut self) -> F {
(self.next_unipolar() * 2.0) - 1.0 (self.next_unipolar() * f(2.0)) - f(1.0)
} }
} }

View file

@ -1845,7 +1845,7 @@ mod tests {
#[test] #[test]
fn check_node_size_staying_small() { fn check_node_size_staying_small() {
assert_eq!(std::mem::size_of::<Node>(), 48); assert_eq!(std::mem::size_of::<Node>(), 56);
assert_eq!(std::mem::size_of::<NodeId>(), 2); assert_eq!(std::mem::size_of::<NodeId>(), 2);
assert_eq!(std::mem::size_of::<ParamId>(), 24); assert_eq!(std::mem::size_of::<ParamId>(), 24);
} }

View file

@ -4,9 +4,7 @@
use crate::nodes::{NodeAudioContext, NodeExecContext}; use crate::nodes::{NodeAudioContext, NodeExecContext};
use crate::dsp::{ use crate::dsp::{
NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext, denorm
GraphAtomData, GraphFun, NodeContext,
denorm
}; };
use super::helpers::crossfade; use super::helpers::crossfade;
use super::dattorro::{ use super::dattorro::{
@ -161,7 +159,7 @@ impl DspNode for PVerb {
_atoms: &[SAtom], inputs: &[ProcBuf], _atoms: &[SAtom], inputs: &[ProcBuf],
outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals)
{ {
use crate::dsp::{out, inp, out_idx}; use crate::dsp::{inp, out_idx};
let in_l = inp::PVerb::in_l(inputs); let in_l = inp::PVerb::in_l(inputs);
let in_r = inp::PVerb::in_r(inputs); let in_r = inp::PVerb::in_r(inputs);

View file

@ -73,7 +73,7 @@ impl DspNode for TsLfo {
atoms: &[SAtom], inputs: &[ProcBuf], atoms: &[SAtom], inputs: &[ProcBuf],
outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals)
{ {
use crate::dsp::{out, inp, denorm, at}; use crate::dsp::{out, inp, denorm};
let time = inp::TsLfo::time(inputs); let time = inp::TsLfo::time(inputs);
let trig = inp::TsLfo::trig(inputs); let trig = inp::TsLfo::trig(inputs);

View file

@ -47,17 +47,16 @@ fn check_node_allp() {
// allpass feedback of the original signal for 2ms: // allpass feedback of the original signal for 2ms:
// XXX: the smearing before and after the allpass is due to the // XXX: the smearing before and after the allpass is due to the
// cubic interpolation! // cubic interpolation!
v.append(&mut vec![-0.01606654, 0.13159, 0.54748535]); v.append(&mut vec![0.0, 0.0]);
v.append(&mut vec![0.51; (2.0 * 44.1_f32).ceil() as usize - 3]); v.append(&mut vec![0.51; (2.0 * 44.1_f32).ceil() as usize]);
v.append(&mut vec![0.52606, 0.37840945, -0.037485]);
// 1ms allpass silence like before: // 1ms allpass silence like before:
v.append(&mut vec![0.0; (1.0 * 44.1_f32).floor() as usize - 6]); v.append(&mut vec![0.0; (1.0 * 44.1_f32).floor() as usize - 1]);
// 2ms the previous 1.0 * 0.7 fed back into the filter, // 2ms the previous 1.0 * 0.7 fed back into the filter,
// including even more smearing due to cubic interpolation: // including even more smearing due to cubic interpolation:
v.append(&mut vec![-0.000354, 0.00615, -0.005424, -0.17565, -0.39786, -0.3550714]); // v.append(&mut vec![-0.000354, 0.00615, -0.005424, -0.17565, -0.39786, -0.3550714]);
v.append(&mut vec![-0.357; (2.0 * 44.1_f32).floor() as usize - 5]); v.append(&mut vec![-0.357; (2.0 * 44.1_f32).floor() as usize + 1]);
v.append(&mut vec![-0.3566457, -0.363158, -0.35157552, -0.18134634, 0.040867306, -0.0019286368]); v.append(&mut vec![0.0; 10]);
//d// println!("res={:?}", res.1); //d// println!("res={:?}", res.1);
assert_vec_feq!(res.0, v); assert_vec_feq!(res.0, v);

View file

@ -1064,8 +1064,8 @@ fn check_node_sfilter_moog_lowpass() {
let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 13, 22050.0, 0.0); let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 13, 22050.0, 0.0);
assert_eq!( assert_eq!(
avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050, 22051], &fft[..]), vec![ avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050, 22051], &fft[..]), vec![
(0, 16), (100, 16), (1000, 16), (4000, 16), (12000, 16), (0, 16), (100, 16), (1000, 16), (4000, 16), (12000, 8),
(16000, 16), (20000, 8), (22050, 8) (16000, 16), (20000, 8), (22050, 0)
]); ]);
// Low Pass Stilson/Moog @ 22050Hz RES=1.0 // Low Pass Stilson/Moog @ 22050Hz RES=1.0