implemente Ad node, still need to test
This commit is contained in:
parent
3fbc471ff4
commit
52ce2f26af
6 changed files with 219 additions and 103 deletions
|
@ -347,6 +347,9 @@ define_exp!{n_declick d_declick 0.0, 50.0}
|
||||||
|
|
||||||
define_exp!{n_env d_env 0.0, 1000.0}
|
define_exp!{n_env d_env 0.0, 1000.0}
|
||||||
|
|
||||||
|
// Special linear gain factor for the Out node, to be able
|
||||||
|
// to reach more exact "1.0".
|
||||||
|
define_lin!{n_ogin d_ogin 0.0, 2.0}
|
||||||
|
|
||||||
// A note about the input-indicies:
|
// A note about the input-indicies:
|
||||||
//
|
//
|
||||||
|
@ -412,7 +415,7 @@ macro_rules! node_list {
|
||||||
out => Out UIType::Generic UICategory::IOUtil
|
out => Out UIType::Generic UICategory::IOUtil
|
||||||
(0 ch1 n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0)
|
(0 ch1 n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0)
|
||||||
(1 ch2 n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0)
|
(1 ch2 n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0)
|
||||||
(2 gain n_gain d_gain r_id f_def stp_d 0.0, 1.0, 1.0)
|
(2 gain n_ogin d_ogin r_id f_def stp_d 0.0, 1.0, 1.0)
|
||||||
// node_param_idx
|
// node_param_idx
|
||||||
// | atom_idx format fun
|
// | atom_idx format fun
|
||||||
// | | name constructor| min max
|
// | | name constructor| min max
|
||||||
|
@ -426,12 +429,14 @@ macro_rules! node_list {
|
||||||
[0 sig],
|
[0 sig],
|
||||||
ad => Ad UIType::Generic UICategory::CV
|
ad => Ad UIType::Generic UICategory::CV
|
||||||
(0 inp n_id d_id r_id f_def stp_d -1.0, 1.0, 1.0)
|
(0 inp n_id d_id r_id f_def stp_d -1.0, 1.0, 1.0)
|
||||||
(1 atk n_env d_env r_ems f_ms stp_m 0.0, 1.0, 3.0)
|
(1 trig n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0)
|
||||||
(2 dcy n_env d_env r_ems f_ms stp_m 0.0, 1.0, 10.0)
|
(2 atk n_env d_env r_ems f_ms stp_m 0.0, 1.0, 3.0)
|
||||||
(3 ashp n_id d_id r_id f_def stp_d 0.0, 1.0, 0.5)
|
(3 dcy n_env d_env r_ems f_ms stp_m 0.0, 1.0, 10.0)
|
||||||
(4 dshp n_id d_id r_id f_def stp_d 0.0, 1.0, 0.5)
|
(4 ashp n_id d_id r_id f_def stp_d 0.0, 1.0, 0.5)
|
||||||
{5 0 mult setting(0) fa_ad_mult 0 2}
|
(5 dshp n_id d_id r_id f_def stp_d 0.0, 1.0, 0.5)
|
||||||
[0 sig],
|
{6 0 mult setting(0) fa_ad_mult 0 2}
|
||||||
|
[0 sig]
|
||||||
|
[1 eoet],
|
||||||
test => Test UIType::Generic UICategory::IOUtil
|
test => Test UIType::Generic UICategory::IOUtil
|
||||||
(0 f n_id d_id r_id f_def stp_d 0.0, 1.0, 0.5)
|
(0 f n_id d_id r_id f_def stp_d 0.0, 1.0, 0.5)
|
||||||
{1 0 s setting(0) fa_test_s 0 10},
|
{1 0 s setting(0) fa_test_s 0 10},
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
use crate::nodes::{NodeAudioContext, NodeExecContext};
|
use crate::nodes::{NodeAudioContext, NodeExecContext};
|
||||||
use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals};
|
use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals};
|
||||||
|
use super::helpers::{Trigger, TrigSignal, sqrt4_to_pow4};
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! fa_ad_mult { ($formatter: expr, $v: expr, $denorm_v: expr) => { {
|
macro_rules! fa_ad_mult { ($formatter: expr, $v: expr, $denorm_v: expr) => { {
|
||||||
|
@ -22,25 +23,33 @@ const AD_STAGES : i8 = 2;
|
||||||
/// A simple amplifier
|
/// A simple amplifier
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Ad {
|
pub struct Ad {
|
||||||
srate: f64,
|
inc: f64,
|
||||||
phase: f64,
|
stage: u8,
|
||||||
last_value: f32,
|
samples_ms: f64,
|
||||||
stage: i8,
|
value: f64,
|
||||||
|
last_time: f32,
|
||||||
|
trig: Trigger,
|
||||||
|
trig_sig: TrigSignal,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ad {
|
impl Ad {
|
||||||
pub fn new(_nid: &NodeId) -> Self {
|
pub fn new(_nid: &NodeId) -> Self {
|
||||||
Self {
|
Self {
|
||||||
srate: 44100.0,
|
inc: 0.0,
|
||||||
phase: 0.0,
|
stage: 0,
|
||||||
last_value: 0.0,
|
samples_ms: 44.1,
|
||||||
stage: -1,
|
value: 0.0,
|
||||||
|
last_time: -1.0,
|
||||||
|
trig: Trigger::new(),
|
||||||
|
trig_sig: TrigSignal::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub const inp : &'static str =
|
pub const inp : &'static str =
|
||||||
"Ad inp\nSignal input. If you don't connect this, and set this to 1.0 \
|
"Ad inp\nSignal input. If you don't connect this, and set this to 1.0 \
|
||||||
this will act as envelope signal generator. But you can also just \
|
this will act as envelope signal generator. But you can also just \
|
||||||
route a signal directly through this of course.\nRange: (-1..1)\n";
|
route a signal directly through this of course.\nRange: (-1..1)\n";
|
||||||
|
pub const trig : &'static str =
|
||||||
|
"Ad trig\nTrigger input that starts the attack phase.\nRange: (0..1)\n";
|
||||||
pub const atk : &'static str =
|
pub const atk : &'static str =
|
||||||
"Ad atk\nAttack time of the envelope. You can extend the maximum \
|
"Ad atk\nAttack time of the envelope. You can extend the maximum \
|
||||||
range of this with the 'mult' setting.\nRange: (0..1)\n";
|
range of this with the 'mult' setting.\nRange: (0..1)\n";
|
||||||
|
@ -63,102 +72,49 @@ impl Ad {
|
||||||
you will receive an attenuated signal here. If you set 'inp' to a \
|
you will receive an attenuated signal here. If you set 'inp' to a \
|
||||||
fixed value (for instance 1.0), this will output an envelope signal \
|
fixed value (for instance 1.0), this will output an envelope signal \
|
||||||
in the range 0.0 to 'inp' (1.0).\nRange: (-1..1)\n";
|
in the range 0.0 to 'inp' (1.0).\nRange: (-1..1)\n";
|
||||||
|
pub const eoet : &'static str =
|
||||||
|
"Ad eoet\nEnd of envelope trigger. This output sends a trigger once \
|
||||||
|
the end of the decay stage has been reached.\nRange: (0..1)";
|
||||||
pub const DESC : &'static str =
|
pub const DESC : &'static str =
|
||||||
r#"Attack-Decay Envelope
|
r#"Attack-Decay Envelope
|
||||||
|
|
||||||
This is a simple envelope offering an attack time and decay time with shape parameter.
|
This is a simple envelope offering an attack time and decay time with a shape parameter.
|
||||||
|
You can use it as envelope generator to modulate other inputs or process a signal with it directly.
|
||||||
"#;
|
"#;
|
||||||
pub const HELP : &'static str =
|
pub const HELP : &'static str =
|
||||||
r#"Ad - Attack-Decay Envelope
|
r#"Ad - Attack-Decay Envelope
|
||||||
|
|
||||||
|
This simple two stage envelope with attack and decay offers shape parameters
|
||||||
|
for each stage. The attack and decay times can be extended using the 'mult'
|
||||||
|
setting.
|
||||||
|
|
||||||
|
The 'inp' can either be used to process a signal, or set the target output
|
||||||
|
value of the envelope. In the latter case this node is just a simple
|
||||||
|
envelope generator, with which you can generate control signals to modulate
|
||||||
|
other inputs.
|
||||||
|
|
||||||
|
With the 'eoet' output you can either trigger other envelopes or via
|
||||||
|
'FbWr'/'FbRd' retrigger the envelope.
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
struct {
|
|
||||||
srate_per_ms: f64,
|
|
||||||
value : f64 = 0.0;
|
|
||||||
inc : f64 = 0.0;
|
|
||||||
stage = 0;
|
|
||||||
last_time = 0.0;
|
|
||||||
target : f64 = 1.0;
|
|
||||||
shape = 0.5;
|
|
||||||
}
|
|
||||||
set_sample_rate(srate) { self.srate_per_ms = srate / 1000.0 }
|
|
||||||
|
|
||||||
// block start:
|
|
||||||
let mut shape_src =
|
|
||||||
match stage {
|
|
||||||
2 => dcy_shape,
|
|
||||||
_ => atk_shape,
|
|
||||||
};
|
|
||||||
let mut inc_time_src =
|
|
||||||
match stage {
|
|
||||||
2 => dcy,
|
|
||||||
_ => atk,
|
|
||||||
};
|
|
||||||
let mut mult : f64 =
|
|
||||||
if mult == 1 { 10.0 } else if mult == 2 {100.0 } else { 1.0};
|
|
||||||
|
|
||||||
// each frame:
|
|
||||||
if stage == 0 {
|
|
||||||
if trigger(trig_in) {
|
|
||||||
value = 0.0;
|
|
||||||
|
|
||||||
// transition to stage 1 (attack):
|
|
||||||
stage = 1;
|
|
||||||
target = 1.0;
|
|
||||||
shape_src = atk_shape;
|
|
||||||
inc_time_src = atk;
|
|
||||||
last_time = -1.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let cur_time = denorm(inc_time_src);
|
|
||||||
if last_time != cur_time {
|
|
||||||
inc =
|
|
||||||
(target - value)
|
|
||||||
/ ((cur_time as f64) * mult * srate_per_ms);
|
|
||||||
}
|
|
||||||
|
|
||||||
value += inc;
|
|
||||||
shape = read(frame, shape_src).clamp(0.0, 1.0);
|
|
||||||
|
|
||||||
match stage {
|
|
||||||
1 => {
|
|
||||||
if value >= target {
|
|
||||||
// transition to stage 2 (decay):
|
|
||||||
stage = 2;
|
|
||||||
target = 0.0;
|
|
||||||
shape_src = dcy_shape;
|
|
||||||
inc_time_src = dcy;
|
|
||||||
last_time = -1.0;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
2 => {
|
|
||||||
if value <= target {
|
|
||||||
stage = 0;
|
|
||||||
eov_trigger.trigger();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {},
|
|
||||||
}
|
|
||||||
|
|
||||||
let in_val = inp.read(frame);
|
|
||||||
out.write(
|
|
||||||
frame,
|
|
||||||
in_val
|
|
||||||
* sqrt4_to_pow4(
|
|
||||||
value.clamp(0.0, 1.0) as f32, shape));
|
|
||||||
trig.write(frame, eov_trigger.next());
|
|
||||||
*/
|
|
||||||
|
|
||||||
impl DspNode for Ad {
|
impl DspNode for Ad {
|
||||||
fn outputs() -> usize { 1 }
|
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.samples_ms = srate as f64 / 1000.0;
|
||||||
|
self.trig_sig.set_sample_rate(srate);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset(&mut self) {
|
||||||
|
self.stage = 0;
|
||||||
|
self.value = 0.0;
|
||||||
|
self.inc = 0.0;
|
||||||
|
self.last_time = -1.0;
|
||||||
|
self.trig_sig.reset();
|
||||||
|
self.trig.reset();
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn process<T: NodeAudioContext>(
|
fn process<T: NodeAudioContext>(
|
||||||
|
@ -168,15 +124,98 @@ impl DspNode for Ad {
|
||||||
{
|
{
|
||||||
use crate::dsp::{out, inp, denorm, denorm_v, inp_dir, at};
|
use crate::dsp::{out, inp, denorm, denorm_v, inp_dir, at};
|
||||||
|
|
||||||
let out = out::Ad::sig(outputs);
|
let inp = inp::Ad::inp(inputs);
|
||||||
|
let trig = inp::Ad::trig(inputs);
|
||||||
|
let atk = inp::Ad::atk(inputs);
|
||||||
|
let dcy = inp::Ad::dcy(inputs);
|
||||||
|
let atk_shape = inp::Ad::ashp(inputs);
|
||||||
|
let dcy_shape = inp::Ad::dshp(inputs);
|
||||||
|
let mult = at::Ad::mult(atoms);
|
||||||
|
|
||||||
let last_frame = ctx.nframes() - 1;
|
// block start:
|
||||||
|
let (mut shape_src, mut inc_time_src, mut target) =
|
||||||
|
match self.stage {
|
||||||
|
1 => (atk_shape, atk, 1.0),
|
||||||
|
2 => (dcy_shape, dcy, 0.0),
|
||||||
|
_ => (atk_shape, atk, 0.0),
|
||||||
|
};
|
||||||
|
let mut mult : f64 =
|
||||||
|
match mult.i() {
|
||||||
|
1 => 10.0,
|
||||||
|
2 => 100.0,
|
||||||
|
_ => 1.0,
|
||||||
|
};
|
||||||
|
|
||||||
for frame in 0..ctx.nframes() {
|
for frame in 0..ctx.nframes() {
|
||||||
out.write(frame, 0.0);
|
// each frame:
|
||||||
|
let is_triggered =
|
||||||
|
self.trig.check_trigger(denorm::Ad::trig(trig, frame));
|
||||||
|
|
||||||
|
if self.stage == 0 && is_triggered {
|
||||||
|
// transition to stage 1 (attack):
|
||||||
|
self.stage = 1;
|
||||||
|
self.last_time = -1.0;
|
||||||
|
target = 1.0;
|
||||||
|
shape_src = atk_shape;
|
||||||
|
inc_time_src = atk;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx_vals[0].set(0.0);
|
let cur_time = denorm::Ad::atk(inc_time_src, frame);
|
||||||
|
if self.last_time != cur_time {
|
||||||
|
self.inc =
|
||||||
|
if cur_time <= 0.0001 {
|
||||||
|
target - self.value
|
||||||
|
} else {
|
||||||
|
(target - self.value)
|
||||||
|
/ ((cur_time as f64) * mult * self.samples_ms)
|
||||||
|
};
|
||||||
|
self.last_time = cur_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.value += self.inc;
|
||||||
|
let shape =
|
||||||
|
denorm::Ad::ashp(shape_src, frame)
|
||||||
|
.clamp(0.0, 1.0);
|
||||||
|
|
||||||
|
match self.stage {
|
||||||
|
1 => {
|
||||||
|
if self.value >= target {
|
||||||
|
self.stage = 2;
|
||||||
|
self.last_time = -1.0;
|
||||||
|
self.value = target;
|
||||||
|
target = 0.0;
|
||||||
|
shape_src = dcy_shape;
|
||||||
|
inc_time_src = dcy;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
2 => {
|
||||||
|
if self.value <= target {
|
||||||
|
self.stage = 0;
|
||||||
|
self.last_time = -1.0;
|
||||||
|
self.value = target;
|
||||||
|
target = 0.0;
|
||||||
|
self.trig_sig.trigger();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
let in_val = denorm::Ad::inp(inp, frame);
|
||||||
|
let out = out::Ad::sig(outputs);
|
||||||
|
//d// println!("VAL in={}, val={} shp: {}=>{}", in_val, self.value, shape,
|
||||||
|
//d// sqrt4_to_pow4(1.0, shape));
|
||||||
|
out.write(
|
||||||
|
frame,
|
||||||
|
in_val
|
||||||
|
* sqrt4_to_pow4(
|
||||||
|
self.value.clamp(0.0, 1.0) as f32,
|
||||||
|
shape));
|
||||||
|
|
||||||
|
let eoet = out::Ad::eoet(outputs);
|
||||||
|
eoet.write(frame, self.trig_sig.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx_vals[0].set(self.value as f32);
|
||||||
// ctx_vals[1].set(self.phase / self. + self.stage * );
|
// ctx_vals[1].set(self.phase / self. + self.stage * );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,9 @@ impl Out {
|
||||||
pub const mono : &'static str =
|
pub const mono : &'static str =
|
||||||
"Out mono\nIf set to 'Mono', ch1 will be sent to both output channels.\n(UI only)";
|
"Out mono\nIf set to 'Mono', ch1 will be sent to both output channels.\n(UI only)";
|
||||||
pub const gain : &'static str =
|
pub const gain : &'static str =
|
||||||
"Out gain\nThe main gain of the synthesizer output, applied to all channels.\nRange: (0..1)";
|
"Out gain\nThe main gain of the synthesizer output, applied to all channels. \
|
||||||
|
Please note that this is a linear control, to prevent inaccuracies for 1.0. \
|
||||||
|
\nRange: (0..1)";
|
||||||
pub const ch1 : &'static str =
|
pub const ch1 : &'static str =
|
||||||
"Out ch1\nAudio channel 1 (left)\nRange: (-1..1)";
|
"Out ch1\nAudio channel 1 (left)\nRange: (-1..1)";
|
||||||
pub const ch2 : &'static str =
|
pub const ch2 : &'static str =
|
||||||
|
|
|
@ -469,7 +469,7 @@ mod tests {
|
||||||
let s = mr.serialize();
|
let s = mr.serialize();
|
||||||
|
|
||||||
assert_eq!(s,
|
assert_eq!(s,
|
||||||
"{\"VERSION\":1,\"atoms\":[[\"out\",0,\"mono\",[\"i\",0]]],\"cells\":[[\"sin\",2,0,0,[-1,-1,-1],[-1,0,-1]],[\"out\",0,1,0,[-1,0,-1],[-1,-1,0]]],\"params\":[[\"out\",0,\"ch1\",0.0],[\"out\",0,\"ch2\",0.0],[\"sin\",0,\"det\",0.0],[\"sin\",1,\"det\",0.0],[\"sin\",2,\"det\",0.0],[\"sin\",0,\"freq\",0.0],[\"sin\",1,\"freq\",0.0],[\"sin\",2,\"freq\",-0.10000000149011612],[\"out\",0,\"gain\",0.7071067690849304]],\"patterns\":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]}");
|
"{\"VERSION\":1,\"atoms\":[[\"out\",0,\"mono\",[\"i\",0]]],\"cells\":[[\"sin\",2,0,0,[-1,-1,-1],[-1,0,-1]],[\"out\",0,1,0,[-1,0,-1],[-1,-1,0]]],\"params\":[[\"out\",0,\"ch1\",0.0],[\"out\",0,\"ch2\",0.0],[\"sin\",0,\"det\",0.0],[\"sin\",1,\"det\",0.0],[\"sin\",2,\"det\",0.0],[\"sin\",0,\"freq\",0.0],[\"sin\",1,\"freq\",0.0],[\"sin\",2,\"freq\",-0.10000000149011612],[\"out\",0,\"gain\",0.5]],\"patterns\":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]}");
|
||||||
|
|
||||||
let mut mr2 = MatrixRepr::deserialize(&s).unwrap();
|
let mut mr2 = MatrixRepr::deserialize(&s).unwrap();
|
||||||
|
|
||||||
|
|
|
@ -79,6 +79,35 @@ assertion failed: `(left[{}] == right[{}])`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! assert_decimated_slope_feq {
|
||||||
|
($vec:expr, $decimate:expr, $cmp_vec:expr) => {
|
||||||
|
let cmp_vec = $cmp_vec;
|
||||||
|
let mut res : Vec<f32> = vec![];
|
||||||
|
let mut prev = 0.0;
|
||||||
|
for s in $vec.iter() {
|
||||||
|
let delta = *s - prev;
|
||||||
|
res.push(delta);
|
||||||
|
prev = *s;
|
||||||
|
}
|
||||||
|
|
||||||
|
let res : Vec<f32> = res.iter().step_by($decimate).copied().collect();
|
||||||
|
|
||||||
|
for (i, (s, scmp)) in res.iter().zip(cmp_vec.iter()).enumerate() {
|
||||||
|
if (s - scmp).abs() > 0.0001 {
|
||||||
|
panic!(r#"
|
||||||
|
table_left: {:?}
|
||||||
|
|
||||||
|
table_right: {:?}
|
||||||
|
|
||||||
|
assertion failed: `(left[{}] == right[{}])`
|
||||||
|
left: `{:?}`,
|
||||||
|
right: `{:?}`"#, &res[i..], &(cmp_vec[i..]), i, i, s, scmp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! assert_rmsmima {
|
macro_rules! assert_rmsmima {
|
||||||
($rms:expr, $b:expr) => {
|
($rms:expr, $b:expr) => {
|
||||||
|
|
41
tests/node_ad.rs
Normal file
41
tests/node_ad.rs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
mod common;
|
||||||
|
use common::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn check_node_ad_1() {
|
||||||
|
let (node_conf, mut node_exec) = new_node_engine();
|
||||||
|
let mut matrix = Matrix::new(node_conf, 3, 3);
|
||||||
|
|
||||||
|
let ad = NodeId::Ad(0);
|
||||||
|
let out = NodeId::Out(0);
|
||||||
|
matrix.place(0, 0, Cell::empty(ad)
|
||||||
|
.out(None, None, ad.out("sig")));
|
||||||
|
matrix.place(0, 1, Cell::empty(out)
|
||||||
|
.input(out.inp("ch1"), None, None));
|
||||||
|
matrix.sync().unwrap();
|
||||||
|
|
||||||
|
let trig_p = ad.inp_param("trig").unwrap();
|
||||||
|
|
||||||
|
matrix.set_param(trig_p, SAtom::param(1.0));
|
||||||
|
let res = run_for_ms(&mut node_exec, 25.0);
|
||||||
|
assert_decimated_slope_feq!(res.0, 50, vec![
|
||||||
|
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
|
||||||
|
// 44.1 per ms, attack is default 3.0ms (roughly 3 * 50 samples):
|
||||||
|
0.007558584, 0.007558584, 0.007558584,
|
||||||
|
// 44.1 per ms, decay is default 10.0ms (=> roughly 9 * 50 samples):
|
||||||
|
-0.002267599, -0.0022675395, -0.002267599, -0.0022675395,
|
||||||
|
-0.0022675693, -0.0022675693, -0.0022675842, -0.0022675693,
|
||||||
|
-0.0022675726,
|
||||||
|
0.0, 0.0, 0.0, 0.0
|
||||||
|
]);
|
||||||
|
|
||||||
|
matrix.set_param(trig_p, SAtom::param(0.0));
|
||||||
|
run_for_ms(&mut node_exec, 10.0);
|
||||||
|
matrix.set_param(trig_p, SAtom::param(1.0));
|
||||||
|
let res = run_for_ms(&mut node_exec, 25.0);
|
||||||
|
//d// println!("RES: {:?}", res);
|
||||||
|
let start = res.0[330];
|
||||||
|
assert_float_eq!(start, 0.0075585);
|
||||||
|
let peak = res.0[330 + ((44.1_f64 * 3.0).floor() as usize)];
|
||||||
|
assert_float_eq!(peak, 1.0);
|
||||||
|
}
|
Loading…
Reference in a new issue