From fb3bb7dab20142271544f4a566e7219a8ee03dfa Mon Sep 17 00:00:00 2001 From: Weird Constructor Date: Thu, 1 Jul 2021 05:06:46 +0200 Subject: [PATCH] finished noise implementation --- src/dsp/mod.rs | 2 +- src/dsp/node_noise.rs | 95 +++++++++++++-------------- tests/node_noise.rs | 145 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 194 insertions(+), 48 deletions(-) create mode 100644 tests/node_noise.rs diff --git a/src/dsp/mod.rs b/src/dsp/mod.rs index d6bcb24..6c8ea77 100644 --- a/src/dsp/mod.rs +++ b/src/dsp/mod.rs @@ -499,7 +499,7 @@ macro_rules! node_list { (2 g n_id d_id r_id f_def stp_d -1.0, 1.0, 0.7) [0 sig], noise => Noise UIType::Generic UICategory::Osc - (0 atv n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0) + (0 atv n_id d_id r_id f_def stp_d -1.0, 1.0, 1.0) (1 offs n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0) {2 0 mode setting(0) fa_noise_mode 0 1} [0 sig], diff --git a/src/dsp/node_noise.rs b/src/dsp/node_noise.rs index 9d132d4..a48713b 100644 --- a/src/dsp/node_noise.rs +++ b/src/dsp/node_noise.rs @@ -4,7 +4,7 @@ use crate::nodes::{NodeAudioContext, NodeExecContext}; use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals}; -//use crate::dsp::helpers::}; +use crate::dsp::helpers::Rng; #[macro_export] macro_rules! fa_noise_mode { ($formatter: expr, $v: expr, $denorm_v: expr) => { { @@ -20,22 +20,35 @@ macro_rules! fa_noise_mode { ($formatter: expr, $v: expr, $denorm_v: expr) => { /// A simple amplifier #[derive(Debug, Clone)] pub struct Noise { + seed: u64, + rng: Rng, } impl Noise { - pub fn new(_nid: &NodeId) -> Self { + pub fn new(nid: &NodeId) -> Self { + let mut rng = Rng::new(); + rng.seed( + (0x193a67f4a8a6d769_u64).wrapping_add( + 0x131415 * (nid.instance() as u64 + 1))); + Self { + seed: nid.instance() as u64, + rng, } } pub const atv : &'static str = - "Noise atv\n...\nRange: (-1..1)"; + "Noise atv\n.Attenuverter input, to attenuate or inverter \ + the noise.\nRange: (-1..1)"; pub const offs : &'static str = - "Noise offs\n...\nRange: (-1..1)"; + "Noise offs\n.Offset input, that is added to the output \ + signal after attenuvertig it.\nRange: (-1..1)"; pub const mode : &'static str = - "Noise mode\n..."; + "Noise mode\nYou can switch between 'Bipolar' noise, which \ + uses the full range from -1 to 1, or 'Unipolar' noise that \ + only uses the range from 0 to 1."; pub const sig : &'static str = - "Noise sig\nThe output of the dry/wet mix.\nRange: (-1..1)"; + "Noise sig\nThe noise output.\nRange: (-1..1)"; pub const DESC : &'static str = r#"A Simple Noise Oscillator @@ -59,10 +72,13 @@ unipolar and bipolar output. impl DspNode for Noise { fn outputs() -> usize { 1 } - fn set_sample_rate(&mut self, srate: f32) { + fn set_sample_rate(&mut self, _srate: f32) { } fn reset(&mut self) { + self.rng.seed( + (0x193a67f4a8a6d769_u64).wrapping_add( + 0x131415 * (self.seed + 1))); } #[inline] @@ -73,47 +89,32 @@ impl DspNode for Noise { { use crate::dsp::{at, out, inp, denorm}; -// let buffer = &mut *self.buffer; -// -// let mode = at::Delay::mode(atoms); -// let inp = inp::Delay::inp(inputs); -// let trig = inp::Delay::trig(inputs); -// let time = inp::Delay::time(inputs); -// let fb = inp::Delay::fb(inputs); -// let mix = inp::Delay::mix(inputs); -// let out = out::Delay::sig(outputs); + let mode = at::Noise::mode(atoms); + let atv = inp::Noise::atv(inputs); + let offs = inp::Noise::offs(inputs); + let out = out::Noise::sig(outputs); -// if mode.i() == 0 { -// for frame in 0..ctx.nframes() { -// let dry = inp.read(frame); -// -// let out_sample = -// buffer.cubic_interpolate_at( -// denorm::Delay::time(time, frame)); -// -// buffer.feed(dry + out_sample * denorm::Delay::fb(fb, frame)); -// -// out.write(frame, -// crossfade(dry, out_sample, -// denorm::Delay::mix(mix, frame).clamp(0.0, 1.0))); -// } -// } else { -// for frame in 0..ctx.nframes() { -// let dry = inp.read(frame); -// -// let clock_samples = -// self.clock.next(denorm::Delay::trig(trig, frame)); -// let out_sample = buffer.at(clock_samples as usize); -// -// buffer.feed(dry + out_sample * denorm::Delay::fb(fb, frame)); -// -// out.write(frame, -// crossfade(dry, out_sample, -// denorm::Delay::mix(mix, frame).clamp(0.0, 1.0))); -// } -// } + let rng = &mut self.rng; -// let last_frame = ctx.nframes() - 1; -// ctx_vals[0].set(out.read(last_frame)); + if mode.i() == 0 { + for frame in 0..ctx.nframes() { + let s = (rng.next() * 2.0) - 1.0; + let s = s + * denorm::Noise::atv(atv, frame) + + denorm::Noise::offs(offs, frame); + out.write(frame, s); + } + + } else { + for frame in 0..ctx.nframes() { + let s = rng.next() + * denorm::Noise::atv(atv, frame) + + denorm::Noise::offs(offs, frame); + out.write(frame, s); + } + } + + let last_frame = ctx.nframes() - 1; + ctx_vals[0].set(out.read(last_frame)); } } diff --git a/tests/node_noise.rs b/tests/node_noise.rs new file mode 100644 index 0000000..d611f04 --- /dev/null +++ b/tests/node_noise.rs @@ -0,0 +1,145 @@ +mod common; +use common::*; + +#[test] +fn check_node_noise_bipolar() { + let (node_conf, mut node_exec) = new_node_engine(); + let mut matrix = Matrix::new(node_conf, 3, 3); + + let noise = NodeId::Noise(0); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(noise) + .out(None, None, noise.out("sig"))); + matrix.place(0, 1, Cell::empty(out) + .input(out.inp("ch1"), None, None)); + matrix.sync().unwrap(); + + let (out_l, _) = run_for_ms(&mut node_exec, 25.0); + + assert_float_eq!(out_l[0], 0.1545); + assert_float_eq!(out_l[10], 0.5924); + assert_float_eq!(out_l[11], -0.3643); + + let rms_mimax = calc_rms_mimax_each_ms(&out_l[..], 10.0); + assert_rmsmima!(rms_mimax[0], (0.3374, -0.9958, 0.9971)); + assert_rmsmima!(rms_mimax[1], (0.3384, -0.9997, 0.9993)); +} + +#[test] +fn check_node_noise_seed() { + let (node_conf, mut node_exec) = new_node_engine(); + let mut matrix = Matrix::new(node_conf, 3, 3); + + let noise = NodeId::Noise(0); + let nois2 = NodeId::Noise(1); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(noise) + .out(None, None, noise.out("sig"))); + matrix.place(0, 1, Cell::empty(out) + .input(out.inp("ch1"), None, None)); + matrix.place(1, 0, Cell::empty(nois2) + .out(None, None, nois2.out("sig"))); + matrix.place(1, 1, Cell::empty(out) + .input(out.inp("ch2"), None, None)); + matrix.sync().unwrap(); + + let (out_l, out_r) = run_for_ms(&mut node_exec, 25.0); + + assert_float_eq!(out_l[0], 0.1545); + assert_float_eq!(out_l[10], 0.5924); + + assert_float_eq!(out_r[0], -0.2156); + assert_float_eq!(out_r[10], 0.9441); +} + +#[test] +fn check_node_noise_unipolar() { + let (node_conf, mut node_exec) = new_node_engine(); + let mut matrix = Matrix::new(node_conf, 3, 3); + + let noise = NodeId::Noise(0); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(noise) + .out(None, None, noise.out("sig"))); + matrix.place(0, 1, Cell::empty(out) + .input(out.inp("ch1"), None, None)); + pset_s(&mut matrix, noise, "mode", 1); + matrix.sync().unwrap(); + + let (out_l, _) = run_for_ms(&mut node_exec, 25.0); + + assert_float_eq!(out_l[0], 0.5772); + assert_float_eq!(out_l[10], 0.7962); + assert_float_eq!(out_l[11], 0.3178); + + let rms_mimax = calc_rms_mimax_each_ms(&out_l[..], 10.0); + assert_rmsmima!(rms_mimax[0], (0.3214, 0.002, 0.9985)); + assert_rmsmima!(rms_mimax[1], (0.3373, 0.0001, 0.9996)); +} + + +#[test] +fn check_node_noise_atv_offs() { + let (node_conf, mut node_exec) = new_node_engine(); + let mut matrix = Matrix::new(node_conf, 3, 3); + + let noise = NodeId::Noise(0); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(noise) + .out(None, None, noise.out("sig"))); + matrix.place(0, 1, Cell::empty(out) + .input(out.inp("ch1"), None, None)); + pset_s(&mut matrix, noise, "mode", 1); + pset_n(&mut matrix, noise, "atv", 0.5); + pset_n(&mut matrix, noise, "offs", 0.3); + matrix.sync().unwrap(); + + let (out_l, _) = run_for_ms(&mut node_exec, 100.0); + let rms_mimax = calc_rms_mimax_each_ms(&out_l[..], 100.0); + println!("mima {:?}", rms_mimax); + assert_rmsmima!(rms_mimax[0], (0.3223, 0.3, 0.7998)); +} + +#[test] +fn check_node_noise_atv_offs_2() { + let (node_conf, mut node_exec) = new_node_engine(); + let mut matrix = Matrix::new(node_conf, 3, 3); + + let noise = NodeId::Noise(0); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(noise) + .out(None, None, noise.out("sig"))); + matrix.place(0, 1, Cell::empty(out) + .input(out.inp("ch1"), None, None)); + pset_s(&mut matrix, noise, "mode", 1); + pset_n(&mut matrix, noise, "atv", -0.5); + pset_n(&mut matrix, noise, "offs", -0.4); + matrix.sync().unwrap(); + + let (out_l, _) = run_for_ms(&mut node_exec, 100.0); + let rms_mimax = calc_rms_mimax_each_ms(&out_l[..], 100.0); + println!("mima {:?}", rms_mimax); + assert_rmsmima!(rms_mimax[0], (0.4422, -0.8998, -0.4)); +} + +#[test] +fn check_node_noise_atv_offs_bipolar() { + let (node_conf, mut node_exec) = new_node_engine(); + let mut matrix = Matrix::new(node_conf, 3, 3); + + let noise = NodeId::Noise(0); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(noise) + .out(None, None, noise.out("sig"))); + matrix.place(0, 1, Cell::empty(out) + .input(out.inp("ch1"), None, None)); + pset_s(&mut matrix, noise, "mode", 0); + pset_n(&mut matrix, noise, "atv", 0.5); + pset_n(&mut matrix, noise, "offs", 0.4); + matrix.sync().unwrap(); + + let (out_l, _) = run_for_ms(&mut node_exec, 100.0); + let rms_mimax = calc_rms_mimax_each_ms(&out_l[..], 100.0); + println!("mima {:?}", rms_mimax); + assert_rmsmima!(rms_mimax[0], (0.2407, -0.0998, 0.8996)); +}