finished writing tests for the delay node
This commit is contained in:
parent
adfcd3f431
commit
1e0caab020
4 changed files with 379 additions and 15 deletions
|
@ -466,14 +466,16 @@ macro_rules! node_list {
|
|||
(0 inp n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0)
|
||||
(1 trig n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0)
|
||||
(2 time n_time d_time r_tms f_ms stp_m 0.0, 1.0, 250.0)
|
||||
(3 fb n_id d_id r_id f_def stp_d 0.0, 1.0, 0.0)
|
||||
(3 fb n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0)
|
||||
(4 mix n_id d_id r_id f_def stp_d 0.0, 1.0, 0.5)
|
||||
{5 0 mode setting(0) fa_delay_mode 0 1}
|
||||
[0 sig],
|
||||
test => Test UIType::Generic UICategory::IOUtil
|
||||
(0 f n_id d_id r_id f_def stp_d 0.0, 1.0, 0.5)
|
||||
{1 0 p param(0.0) fa_test_s 0 10}
|
||||
[0 sig],
|
||||
{2 1 trig param(0.0) fa_test_s 0 0}
|
||||
[0 sig]
|
||||
[1 tsig],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1028,6 +1030,13 @@ macro_rules! make_node_info_enum {
|
|||
})+
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub mod out_idx {
|
||||
$(pub mod $variant {
|
||||
$(#[inline] pub fn $out() -> usize { $out_idx })*
|
||||
})+
|
||||
}
|
||||
|
||||
mod ni {
|
||||
$(
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
use crate::nodes::{NodeAudioContext, NodeExecContext};
|
||||
use crate::dsp::{NodeId, SAtom, ProcBuf, GraphFun, GraphAtomData, DspNode, LedPhaseVals};
|
||||
use crate::dsp::helpers::{TrigSignal};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! fa_test_s { ($formatter: expr, $v: expr, $denorm_v: expr) => { {
|
||||
|
@ -28,26 +29,39 @@ macro_rules! fa_test_s { ($formatter: expr, $v: expr, $denorm_v: expr) => { {
|
|||
/// A simple amplifier
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Test {
|
||||
trig_sig: TrigSignal,
|
||||
trigger: bool,
|
||||
}
|
||||
|
||||
impl Test {
|
||||
pub fn new(_nid: &NodeId) -> Self {
|
||||
Self {
|
||||
trigger: false,
|
||||
trig_sig: TrigSignal::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub const f : &'static str = "F Test";
|
||||
pub const p : &'static str = "Test p\nAn unsmoothed parameter for automated tests.";
|
||||
pub const trig: &'static str = "Test trig\nA trigger input, that will create a short pulse on the 'tsig' output.\nRange: (-1..1)";
|
||||
pub const sig : &'static str = "Test sig\nThe output of p as signal";
|
||||
pub const tsig : &'static str = "Test tsig\nA short trigger pulse will be generated when the 'trig' input is triggered.";
|
||||
|
||||
pub const DESC : &'static str = r#""#;
|
||||
pub const HELP : &'static str = r#""#;
|
||||
|
||||
pub fn new(_nid: &NodeId) -> Self {
|
||||
Self {
|
||||
}
|
||||
}
|
||||
pub const f : &'static str = "F Test";
|
||||
pub const p : &'static str = "Test p\nJust an unsmoothed parameter for tests.";
|
||||
pub const sig : &'static str = "Test sig\nThe output of p as signal";
|
||||
}
|
||||
|
||||
impl DspNode for Test {
|
||||
fn outputs() -> usize { 1 }
|
||||
fn outputs() -> usize { 2 }
|
||||
|
||||
fn set_sample_rate(&mut self, _srate: f32) { }
|
||||
fn reset(&mut self) { }
|
||||
fn set_sample_rate(&mut self, srate: f32) {
|
||||
self.trig_sig.set_sample_rate(srate);
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
self.trig_sig.reset();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn process<T: NodeAudioContext>(
|
||||
|
@ -55,12 +69,36 @@ impl DspNode for Test {
|
|||
atoms: &[SAtom], _params: &[ProcBuf], _inputs: &[ProcBuf],
|
||||
outputs: &mut [ProcBuf], _led: LedPhaseVals)
|
||||
{
|
||||
use crate::dsp::{out, at};
|
||||
use crate::dsp::{out_idx, at};
|
||||
|
||||
let p = at::Test::p(atoms);
|
||||
let out = out::Test::sig(outputs);
|
||||
let trig = at::Test::trig(atoms);
|
||||
let tsig = out_idx::Test::tsig();
|
||||
|
||||
let (out, tsig) = outputs.split_at_mut(tsig);
|
||||
let out = &mut out[0];
|
||||
let tsig = &mut tsig[0];
|
||||
|
||||
let mut trigger = trig.i();
|
||||
if !self.trigger && trigger > 0 {
|
||||
self.trigger = true;
|
||||
|
||||
} else if !self.trigger && trigger == 0 {
|
||||
self.trigger = false;
|
||||
|
||||
} else if self.trigger {
|
||||
trigger = 0;
|
||||
}
|
||||
|
||||
for frame in 0..ctx.nframes() {
|
||||
if trigger > 0 {
|
||||
self.trig_sig.trigger();
|
||||
trigger = 0;
|
||||
}
|
||||
|
||||
out.write(frame, p.f());
|
||||
let t = self.trig_sig.next();
|
||||
tsig.write(frame, t);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -194,6 +194,27 @@ assertion failed: `(left[{}] == right[{}])`
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn collect_signal_changes(inp: &[f32], thres: i64) -> Vec<(usize, i64)> {
|
||||
let mut idxs = vec![];
|
||||
let mut last_sig = 0.0;
|
||||
for i in 0..inp.len() {
|
||||
if (inp[i] - last_sig).abs() > 0.1 {
|
||||
idxs.push((i, (inp[i] * 100.0).floor() as i64));
|
||||
last_sig = inp[i];
|
||||
}
|
||||
}
|
||||
|
||||
let mut idxs_big = vec![];
|
||||
for v in idxs.iter() {
|
||||
if v.1.abs() > thres {
|
||||
idxs_big.push(*v);
|
||||
}
|
||||
}
|
||||
|
||||
return idxs_big;
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! assert_rmsmima {
|
||||
($rms:expr, $b:expr) => {
|
||||
|
|
296
tests/node_delay.rs
Normal file
296
tests/node_delay.rs
Normal file
|
@ -0,0 +1,296 @@
|
|||
mod common;
|
||||
use common::*;
|
||||
|
||||
#[test]
|
||||
fn check_node_delay_1() {
|
||||
let (node_conf, mut node_exec) = new_node_engine();
|
||||
let mut matrix = Matrix::new(node_conf, 4, 4);
|
||||
|
||||
let ad = NodeId::Ad(0);
|
||||
let sin = NodeId::Sin(0);
|
||||
let dly = NodeId::Delay(0);
|
||||
let out = NodeId::Out(0);
|
||||
matrix.place(0, 0, Cell::empty(sin)
|
||||
.out(None, None, sin.out("sig")));
|
||||
matrix.place(0, 1, Cell::empty(ad)
|
||||
.input(ad.inp("inp"), None, None)
|
||||
.out(None, None, ad.out("sig")));
|
||||
matrix.place(0, 2, Cell::empty(dly)
|
||||
.input(dly.inp("inp"), None, None)
|
||||
.out(None, None, dly.out("sig")));
|
||||
matrix.place(0, 3, Cell::empty(out)
|
||||
.input(out.inp("ch1"), None, None)
|
||||
.out(None, None, None));
|
||||
matrix.sync().unwrap();
|
||||
|
||||
pset_d(&mut matrix, ad, "atk", 50.0);
|
||||
pset_d(&mut matrix, ad, "dcy", 50.0);
|
||||
pset_n(&mut matrix, ad, "trig", 1.0);
|
||||
|
||||
let res = run_for_ms(&mut node_exec, 500.0);
|
||||
// 441 decimation => 10ms resolution
|
||||
assert_decimated_feq!(res.0, 441, vec![
|
||||
// 10ms smoothing time
|
||||
0.0,
|
||||
// burst of sine for 100ms:
|
||||
0.018363932, -0.124816686, 0.21992423, -0.19471036, 0.00002711302,
|
||||
0.27546832, -0.35064548, 0.25555965, -0.0991776, 0.000008648983,
|
||||
// 150ms silence:
|
||||
0.0, 0.0, 0.0, 0.0, 0.0,
|
||||
0.0, 0.0, 0.0, 0.0, 0.0,
|
||||
0.0, 0.0, 0.0, 0.0, 0.0,
|
||||
// delayed burst of sine for 100ms:
|
||||
0.015279313, -0.119179465, 0.22757527, -0.22698581, 0.05398392,
|
||||
0.22569486, -0.3332433, 0.26348564, -0.11514694, 0.008539479,
|
||||
// silence afterwards:
|
||||
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
|
||||
]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_node_delay_2() {
|
||||
let (node_conf, mut node_exec) = new_node_engine();
|
||||
let mut matrix = Matrix::new(node_conf, 4, 4);
|
||||
|
||||
let dly = NodeId::Delay(0);
|
||||
let out = NodeId::Out(0);
|
||||
matrix.place(0, 2, Cell::empty(dly)
|
||||
.out(None, None, dly.out("sig")));
|
||||
matrix.place(0, 3, Cell::empty(out)
|
||||
.input(out.inp("ch1"), None, None)
|
||||
.out(None, None, None));
|
||||
matrix.sync().unwrap();
|
||||
|
||||
pset_d(&mut matrix, dly, "time", 31.0);
|
||||
pset_d(&mut matrix, dly, "inp", 1.0);
|
||||
|
||||
let res = run_for_ms(&mut node_exec, 150.0);
|
||||
// 441 decimation => 10ms resolution
|
||||
assert_decimated_feq!(res.0, 441, vec![
|
||||
// 10ms smoothing time for "inp"
|
||||
0.001133,
|
||||
// 30ms delaytime just mixing the 0.5:
|
||||
0.5, 0.5, 0.5,
|
||||
// the delayed smoothing ramp (10ms):
|
||||
0.9513,
|
||||
// the delay + input signal:
|
||||
1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0
|
||||
]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_node_delay_time_mod() {
|
||||
let (node_conf, mut node_exec) = new_node_engine();
|
||||
let mut matrix = Matrix::new(node_conf, 4, 4);
|
||||
|
||||
let sin = NodeId::Sin(0);
|
||||
let dly = NodeId::Delay(0);
|
||||
let out = NodeId::Out(0);
|
||||
matrix.place(1, 1, Cell::empty(sin)
|
||||
.out(None, None, sin.out("sig")));
|
||||
matrix.place(1, 2, Cell::empty(dly)
|
||||
.input(dly.inp("inp"), None, dly.inp("time"))
|
||||
.out(None, None, dly.out("sig")));
|
||||
matrix.place(1, 3, Cell::empty(out)
|
||||
.input(out.inp("ch1"), None, None)
|
||||
.out(None, None, None));
|
||||
matrix.sync().unwrap();
|
||||
|
||||
pset_n(&mut matrix, dly, "mix", 1.0);
|
||||
pset_d(&mut matrix, dly, "time", 100.0);
|
||||
|
||||
// skip delay time:
|
||||
run_for_ms(&mut node_exec, 100.0);
|
||||
|
||||
let fft = run_and_get_fft4096_now(&mut node_exec, 600);
|
||||
assert_eq!(fft[0], (431, 614));
|
||||
assert_eq!(fft[1], (441, 1012));
|
||||
|
||||
let sin2 = NodeId::Sin(1);
|
||||
matrix.place(0, 3, Cell::empty(sin2)
|
||||
.out(sin2.out("sig"), None, None));
|
||||
|
||||
matrix.sync().unwrap();
|
||||
pset_d(&mut matrix, sin2, "freq", 0.5);
|
||||
|
||||
// let everything settle down and the delay buffer fill with stuff:
|
||||
run_for_ms(&mut node_exec, 5000.0);
|
||||
|
||||
// skip some time to let everything settle:
|
||||
run_for_ms(&mut node_exec, 670.0);
|
||||
|
||||
let fft = run_and_get_fft4096_now(&mut node_exec, 110);
|
||||
// Expect a sine sweep over a
|
||||
// range of low frequencies:
|
||||
assert_eq!(fft[0], (108, 111));
|
||||
assert_eq!(fft[5], (312, 110));
|
||||
assert_eq!(fft[10], (700, 110));
|
||||
|
||||
// Sweep upwards:
|
||||
run_for_ms(&mut node_exec, 300.0);
|
||||
let fft = run_and_get_fft4096_now(&mut node_exec, 122);
|
||||
assert_eq!(fft[0], (2509, 123));
|
||||
assert_eq!(fft[8], (2821, 123));
|
||||
|
||||
// Sweep at mostly highest point:
|
||||
run_for_ms(&mut node_exec, 700.0);
|
||||
let fft = run_and_get_fft4096_now(&mut node_exec, 300);
|
||||
assert_eq!(fft[0], (6417, 309));
|
||||
assert_eq!(fft[4], (6471, 407));
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn check_node_delay_trig() {
|
||||
let (node_conf, mut node_exec) = new_node_engine();
|
||||
let mut matrix = Matrix::new(node_conf, 4, 4);
|
||||
|
||||
let test = NodeId::Test(0);
|
||||
let dly = NodeId::Delay(0);
|
||||
let out = NodeId::Out(0);
|
||||
matrix.place(1, 1, Cell::empty(test)
|
||||
.out(None, None, test.out("tsig")));
|
||||
matrix.place(0, 3, Cell::empty(test)
|
||||
.out(test.out("sig"), None, None));
|
||||
matrix.place(1, 2, Cell::empty(dly)
|
||||
.input(dly.inp("inp"), None, dly.inp("trig"))
|
||||
.out(None, None, dly.out("sig")));
|
||||
matrix.place(1, 3, Cell::empty(out)
|
||||
.input(out.inp("ch1"), None, None)
|
||||
.out(None, None, None));
|
||||
matrix.sync().unwrap();
|
||||
|
||||
pset_n(&mut matrix, dly, "mix", 1.0);
|
||||
pset_n(&mut matrix, dly, "mode", 1.0);
|
||||
pset_d(&mut matrix, dly, "time", 5.0);
|
||||
|
||||
// Trigger the delay 2 times, with an interval of 20ms:
|
||||
pset_n(&mut matrix, test, "p", 1.0);
|
||||
run_for_ms(&mut node_exec, 10.0);
|
||||
pset_n(&mut matrix, test, "p", 0.0);
|
||||
run_for_ms(&mut node_exec, 10.0);
|
||||
pset_n(&mut matrix, test, "p", 1.0);
|
||||
run_for_ms(&mut node_exec, 10.0);
|
||||
pset_n(&mut matrix, test, "p", 0.0);
|
||||
run_for_ms(&mut node_exec, 10.0);
|
||||
|
||||
// Now the delay should have a 20ms delay time.
|
||||
|
||||
// Emit the trigger signal:
|
||||
pset_n(&mut matrix, test, "trig", 1.0);
|
||||
|
||||
let res = run_for_ms(&mut node_exec, 30.0);
|
||||
|
||||
let mut idx_first_non_zero = 99999;
|
||||
for i in 0..res.0.len() {
|
||||
if res.0[i] > 0.0 {
|
||||
idx_first_non_zero = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We expect the signal to be delayed by 20ms:
|
||||
assert_eq!(idx_first_non_zero, (44100 * 20) / 1000);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn check_node_delay_fb() {
|
||||
let (node_conf, mut node_exec) = new_node_engine();
|
||||
let mut matrix = Matrix::new(node_conf, 4, 4);
|
||||
|
||||
let test = NodeId::Test(0);
|
||||
let dly = NodeId::Delay(0);
|
||||
let out = NodeId::Out(0);
|
||||
matrix.place(1, 1, Cell::empty(test)
|
||||
.out(None, None, test.out("tsig")));
|
||||
matrix.place(1, 2, Cell::empty(dly)
|
||||
.input(dly.inp("inp"), None, None)
|
||||
.out(None, None, dly.out("sig")));
|
||||
matrix.place(1, 3, Cell::empty(out)
|
||||
.input(out.inp("ch1"), None, None)
|
||||
.out(None, None, None));
|
||||
|
||||
pset_n(&mut matrix, dly, "mix", 1.0);
|
||||
pset_d(&mut matrix, dly, "time", 5.0);
|
||||
pset_n(&mut matrix, dly, "fb", 0.5);
|
||||
|
||||
matrix.sync().unwrap();
|
||||
|
||||
// Emit the trigger signal:
|
||||
pset_n(&mut matrix, test, "trig", 1.0);
|
||||
|
||||
let res = run_for_ms(&mut node_exec, 100.0);
|
||||
|
||||
let idxs_big = collect_signal_changes(&res.0[..], 50);
|
||||
|
||||
// We expect the signal to be delayed by 20ms:
|
||||
assert_eq!(idxs_big, vec![(220, 106), (441, 53)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_node_delay_fb_neg() {
|
||||
let (node_conf, mut node_exec) = new_node_engine();
|
||||
let mut matrix = Matrix::new(node_conf, 4, 4);
|
||||
|
||||
let test = NodeId::Test(0);
|
||||
let dly = NodeId::Delay(0);
|
||||
let out = NodeId::Out(0);
|
||||
matrix.place(1, 1, Cell::empty(test)
|
||||
.out(None, None, test.out("tsig")));
|
||||
matrix.place(1, 2, Cell::empty(dly)
|
||||
.input(dly.inp("inp"), None, None)
|
||||
.out(None, None, dly.out("sig")));
|
||||
matrix.place(1, 3, Cell::empty(out)
|
||||
.input(out.inp("ch1"), None, None)
|
||||
.out(None, None, None));
|
||||
|
||||
pset_n(&mut matrix, dly, "mix", 1.0);
|
||||
pset_d(&mut matrix, dly, "time", 10.0);
|
||||
pset_n(&mut matrix, dly, "fb", -1.0);
|
||||
|
||||
matrix.sync().unwrap();
|
||||
|
||||
// Emit the trigger signal:
|
||||
pset_n(&mut matrix, test, "trig", 1.0);
|
||||
|
||||
let res = run_for_ms(&mut node_exec, 40.0);
|
||||
|
||||
let idxs_big = collect_signal_changes(&res.0[..], 70);
|
||||
|
||||
assert_eq!(idxs_big, vec![(441, 100), (883, -100), (1325, 100)]);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn check_node_delay_fb_pos() {
|
||||
let (node_conf, mut node_exec) = new_node_engine();
|
||||
let mut matrix = Matrix::new(node_conf, 4, 4);
|
||||
|
||||
let test = NodeId::Test(0);
|
||||
let dly = NodeId::Delay(0);
|
||||
let out = NodeId::Out(0);
|
||||
matrix.place(1, 1, Cell::empty(test)
|
||||
.out(None, None, test.out("tsig")));
|
||||
matrix.place(1, 2, Cell::empty(dly)
|
||||
.input(dly.inp("inp"), None, None)
|
||||
.out(None, None, dly.out("sig")));
|
||||
matrix.place(1, 3, Cell::empty(out)
|
||||
.input(out.inp("ch1"), None, None)
|
||||
.out(None, None, None));
|
||||
|
||||
pset_n(&mut matrix, dly, "mix", 1.0);
|
||||
pset_d(&mut matrix, dly, "time", 10.0);
|
||||
pset_n(&mut matrix, dly, "fb", 1.0);
|
||||
|
||||
matrix.sync().unwrap();
|
||||
|
||||
// Emit the trigger signal:
|
||||
pset_n(&mut matrix, test, "trig", 1.0);
|
||||
|
||||
let res = run_for_ms(&mut node_exec, 40.0);
|
||||
|
||||
let idxs_big = collect_signal_changes(&res.0[..], 70);
|
||||
|
||||
assert_eq!(idxs_big, vec![(441, 100), (883, 100), (1325, 100)]);
|
||||
}
|
Loading…
Reference in a new issue