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.
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].
static FAST_COS_TAB_LOG2_SIZE : usize = 9;
@ -703,27 +712,32 @@ macro_rules! fc {
($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)]
pub struct DelayBuffer<F: Float> {
pub struct DelayBuffer<F: Flt> {
data: Vec<F>,
wr: usize,
srate: F,
}
impl<F: Float + FromPrimitive> DelayBuffer<F> {
impl<F: Flt> DelayBuffer<F> {
pub fn new() -> Self {
Self {
data: vec![fc!(F,0.0); DEFAULT_DELAY_BUFFER_SAMPLES],
data: vec![f(0.0); DEFAULT_DELAY_BUFFER_SAMPLES],
wr: 0,
srate: fc!(F, 44100.0),
srate: f(44100.0),
}
}
pub fn new_with_size(size: usize) -> Self {
Self {
data: vec![fc!(F, 0.0); size],
data: vec![f(0.0); size],
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) {
self.data.fill(0.0);
self.data.fill(f(0.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 {
let data = &self.data[..];
let len = data.len();
let s_offs = (delay_time_ms * self.srate) / 1000.0;
let offs = s_offs.floor() as usize % len;
let s_offs = (delay_time_ms * self.srate) / f(1000.0);
let offs = s_offs.floor().to_usize().unwrap() % len;
let fract = s_offs.fract();
let i = (self.wr + len) - offs;
@ -787,7 +801,7 @@ impl<F: Float + FromPrimitive> DelayBuffer<F> {
let x1 = data[(i + 1) % len];
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.
@ -797,8 +811,8 @@ impl<F: Float + FromPrimitive> DelayBuffer<F> {
pub fn cubic_interpolate_at(&self, delay_time_ms: F) -> F {
let data = &self.data[..];
let len = data.len();
let s_offs = (delay_time_ms * self.srate) / 1000.0;
let offs = s_offs.floor() as usize % len;
let s_offs = (delay_time_ms * self.srate) / f(1000.0);
let offs = s_offs.floor().to_usize().unwrap() % len;
let fract = s_offs.fract();
let i = (self.wr + len) - offs;
@ -815,10 +829,10 @@ impl<F: Float + FromPrimitive> DelayBuffer<F> {
let x1 = data[(i + 1) % 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 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 fract = fract as F;
@ -828,7 +842,10 @@ impl<F: Float + FromPrimitive> DelayBuffer<F> {
#[inline]
pub fn nearest_at(&self, delay_time_ms: F) -> F {
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;
self.data[idx]
}
@ -845,11 +862,11 @@ impl<F: Float + FromPrimitive> DelayBuffer<F> {
const DEFAULT_ALLPASS_COMB_SAMPLES : usize = 8 * 48000;
#[derive(Debug, Clone, Default)]
pub struct AllPass<F: Float> {
pub struct AllPass<F: Flt> {
delay: DelayBuffer<F>,
}
impl<F: Float> AllPass<F> {
impl<F: Flt> AllPass<F> {
pub fn new() -> Self {
Self {
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)]
pub struct OnePoleLPF<F: Float> {
pub struct OnePoleLPF<F: Flt> {
israte: F,
a: F,
b: F,
@ -964,29 +981,29 @@ pub struct OnePoleLPF<F: Float> {
z: F,
}
impl<F: Float + FloatConst> OnePoleLPF<F> {
impl<F: Flt> OnePoleLPF<F> {
pub fn new() -> Self {
Self {
israte: 1.0 / 44100.0,
a: 0.0,
b: 0.0,
freq: 1000.0,
z: 0.0,
israte: f::<F>(1.0) / f(44100.0),
a: f::<F>(0.0),
b: f::<F>(0.0),
freq: f::<F>(1000.0),
z: f::<F>(0.0),
}
}
pub fn reset(&mut self) {
self.z = 0.0;
self.z = f(0.0);
}
#[inline]
fn recalc(&mut self) {
self.b = (-F::TAU * self.freq * self.israte).exp();
self.a = 1.0 - self.b;
self.b = (f::<F>(-1.0) * F::TAU() * self.freq * self.israte).exp();
self.a = f::<F>(1.0) - self.b;
}
pub fn set_sample_rate(&mut self, srate: F) {
self.israte = 1.0 / srate;
self.israte = f::<F>(1.0) / srate;
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)]
pub struct OnePoleHPF<F: Float> {
pub struct OnePoleHPF<F: Flt> {
israte: F,
a: F,
b: F,
@ -1054,32 +1071,32 @@ pub struct OnePoleHPF<F: Float> {
y: F,
}
impl<F: Float + FloatConst> OnePoleHPF<F> {
impl<F: Flt> OnePoleHPF<F> {
pub fn new() -> Self {
Self {
israte: 1.0 / 44100.0,
a: 0.0,
b: 0.0,
freq: 1000.0,
z: 0.0,
y: 0.0,
israte: f(1.0 / 44100.0),
a: f(0.0),
b: f(0.0),
freq: f(1000.0),
z: f(0.0),
y: f(0.0),
}
}
pub fn reset(&mut self) {
self.z = 0.0;
self.y = 0.0;
self.z = f(0.0);
self.y = f(0.0);
}
#[inline]
fn recalc(&mut self) {
self.b = (-F::TAU * self.freq * self.israte).exp();
self.a = (1.0 + self.b) / 2.0;
self.b = (f::<F>(-1.0) * F::TAU() * self.freq * self.israte).exp();
self.a = (f::<F>(1.0) + self.b) / f(2.0);
}
pub fn set_sample_rate(&mut self, srate: F) {
self.israte = 1.0 / srate;
self.israte = f::<F>(1.0) / srate;
self.recalc();
}
@ -1401,38 +1418,38 @@ pub fn process_stilson_moog(
// Copyright (C) 2020 TheWaveWarden
// under GPLv3 or any later
#[derive(Debug, Clone, Copy)]
pub struct DCBlockFilter<F: Float> {
pub struct DCBlockFilter<F: Flt> {
xm1: F,
ym1: F,
r: F,
}
impl<F: Float> DCBlockFilter<F> {
impl<F: Flt> DCBlockFilter<F> {
pub fn new() -> Self {
Self {
xm1: 0.0,
ym1: 0.0,
r: 0.995,
xm1: f(0.0),
ym1: f(0.0),
r: f(0.995),
}
}
pub fn reset(&mut self) {
self.xm1 = 0.0;
self.ym1 = 0.0;
self.xm1 = f(0.0);
self.ym1 = f(0.0);
}
pub fn set_sample_rate(&mut self, srate: F) {
self.r = 0.995;
if srate > 90000.0 {
self.r = 0.9965;
} else if srate > 120000.0 {
self.r = 0.997;
self.r = f(0.995);
if srate > f(90000.0) {
self.r = f(0.9965);
} else if srate > f(120000.0) {
self.r = f(0.997);
}
}
pub fn next(&mut self, input: F) -> F {
let y = input as f64 - self.xm1 + self.r * self.ym1;
self.xm1 = input as f64;
let y = input - self.xm1 + self.r * self.ym1;
self.xm1 = input;
self.ym1 = y;
y as F
}
@ -1883,7 +1900,7 @@ impl VPSOscillator {
/// An LFO with a variable reverse point, which can go from reverse Saw, to Tri
/// and to Saw, depending on the reverse point.
#[derive(Debug, Clone, Copy)]
pub struct TriSawLFO<F: Float> {
pub struct TriSawLFO<F: Flt> {
/// The (inverse) sample rate. Eg. 1.0 / 44100.0.
israte: F,
/// The current oscillator phase.
@ -1901,17 +1918,17 @@ pub struct TriSawLFO<F: Float> {
init_phase: F,
}
impl<F: Float> TriSawLFO<F> {
impl<F: Flt> TriSawLFO<F> {
pub fn new() -> Self {
let mut this = Self {
israte: 1.0 / 44100.0,
phase: 0.0,
rev: 0.5,
israte: f(1.0 / 44100.0),
phase: f(0.0),
rev: f(0.5),
rising: true,
freq: 1.0,
fall_r: 0.0,
rise_r: 0.0,
init_phase: 0.0,
freq: f(1.0),
fall_r: f(0.0),
rise_r: f(0.0),
init_phase: f(0.0),
};
this.recalc();
this
@ -1924,19 +1941,19 @@ impl<F: Float> TriSawLFO<F> {
#[inline]
fn recalc(&mut self) {
self.rev = self.rev.clamp(0.0001, 0.999);
self.rise_r = 1.0 / self.rev;
self.fall_r = -1.0 / (1.0 - self.rev);
self.rev = fclampc(self.rev, 0.0001, 0.999);
self.rise_r = f::<F>( 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) {
self.israte = 1.0 / (srate as F);
self.israte = f::<F>(1.0) / (srate as F);
self.recalc();
}
pub fn reset(&mut self) {
self.phase = self.init_phase;
self.rev = 0.5;
self.rev = f(0.5);
self.rising = true;
}
@ -1949,8 +1966,8 @@ impl<F: Float> TriSawLFO<F> {
#[inline]
pub fn next_unipolar(&mut self) -> F {
if self.phase >= 1.0 {
self.phase -= 1.0;
if self.phase >= f(1.0) {
self.phase = self.phase - f(1.0);
self.rising = true;
}
@ -1965,14 +1982,14 @@ impl<F: Float> TriSawLFO<F> {
self.phase * self.fall_r - self.fall_r
};
self.phase += self.freq * self.israte;
self.phase = self.phase + self.freq * self.israte;
s
}
#[inline]
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]
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::<ParamId>(), 24);
}

View file

@ -4,9 +4,7 @@
use crate::nodes::{NodeAudioContext, NodeExecContext};
use crate::dsp::{
NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals,
GraphAtomData, GraphFun, NodeContext,
denorm
NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext, denorm
};
use super::helpers::crossfade;
use super::dattorro::{
@ -161,7 +159,7 @@ impl DspNode for PVerb {
_atoms: &[SAtom], inputs: &[ProcBuf],
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_r = inp::PVerb::in_r(inputs);

View file

@ -73,7 +73,7 @@ impl DspNode for TsLfo {
atoms: &[SAtom], inputs: &[ProcBuf],
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 trig = inp::TsLfo::trig(inputs);

View file

@ -47,17 +47,16 @@ fn check_node_allp() {
// allpass feedback of the original signal for 2ms:
// XXX: the smearing before and after the allpass is due to the
// cubic interpolation!
v.append(&mut vec![-0.01606654, 0.13159, 0.54748535]);
v.append(&mut vec![0.51; (2.0 * 44.1_f32).ceil() as usize - 3]);
v.append(&mut vec![0.52606, 0.37840945, -0.037485]);
v.append(&mut vec![0.0, 0.0]);
v.append(&mut vec![0.51; (2.0 * 44.1_f32).ceil() as usize]);
// 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,
// 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.357; (2.0 * 44.1_f32).floor() as usize - 5]);
v.append(&mut vec![-0.3566457, -0.363158, -0.35157552, -0.18134634, 0.040867306, -0.0019286368]);
// 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 + 1]);
v.append(&mut vec![0.0; 10]);
//d// println!("res={:?}", res.1);
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);
assert_eq!(
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),
(16000, 16), (20000, 8), (22050, 8)
(0, 16), (100, 16), (1000, 16), (4000, 16), (12000, 8),
(16000, 16), (20000, 8), (22050, 0)
]);
// Low Pass Stilson/Moog @ 22050Hz RES=1.0