From 5be2c93c45c17e08c9ec11373ea6f174fc2fe578 Mon Sep 17 00:00:00 2001 From: Weird Constructor Date: Mon, 15 Aug 2022 05:08:01 +0200 Subject: [PATCH] Wrote gmode Trigger and a test for it --- src/dsp/node_midip.rs | 31 ++++++++++++++++++++++++++----- tests/common/mod.rs | 21 +++++++++++++++++++++ tests/node_midip.rs | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 5 deletions(-) diff --git a/src/dsp/node_midip.rs b/src/dsp/node_midip.rs index 432d05c..c12581b 100644 --- a/src/dsp/node_midip.rs +++ b/src/dsp/node_midip.rs @@ -4,6 +4,7 @@ use crate::dsp::{at, inp, out_idx, DspNode, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom}; use crate::nodes::{HxMidiEvent, MidiEventPointer, NodeAudioContext, NodeExecContext}; +use synfx_dsp::TrigSignal; #[macro_export] macro_rules! fa_midip_chan { @@ -32,16 +33,20 @@ pub struct MidiP { cur_note: u8, cur_gate: u8, cur_vel: f32, + trig_sig: TrigSignal, } impl MidiP { pub fn new(_nid: &NodeId) -> Self { - Self { next_gate: 0, cur_note: 0, cur_gate: 0, cur_vel: 0.0 } + Self { next_gate: 0, cur_note: 0, cur_gate: 0, cur_vel: 0.0, trig_sig: TrigSignal::new() } } pub const chan: &'static str = "MidiP chan\nMIDI Channel 0 to 15\n"; pub const gmode: &'static str = "MidiP gmode\nMIDI gate mode.\n- 'MIDI' gate same as MIDI input\n- 'Trigger' output only triggers on 'gate' output\n- 'Gate Len' output gate with the length of the 'gatel' parameter\n"; - pub const glen: &'static str = "MidiP glen\nMIDI gate length\nIf 'gmode' is set to 'Gate Len' this controls and overrides the gate length on a MIDI note event."; + pub const glen: &'static str = "MidiP glen\nMIDI gate length\n\ + If 'gmode' is set to 'Gate Len' this controls and overrides the gate length on a MIDI \ + note event. 'Trigger' will just send a short trigger when a note event is received. \ + 'MIDI' means the gate reflects the note on/off duration."; pub const det: &'static str = "MidiP det\nDetune input pitch a bit\nRange: (-1..1)"; pub const freq: &'static str = "MidiP freq\nMIDI note frequency, detuned by 'det'.\nRange: (-1..1)"; @@ -84,8 +89,12 @@ impl DspNode for MidiP { 0 } - 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( @@ -100,6 +109,7 @@ impl DspNode for MidiP { ) { let det = inp::MidiP::det(inputs); let chan = at::MidiP::chan(atoms); + let gmode = at::MidiP::gmode(atoms); let out_i = out_idx::MidiP::gate(); let (freq, r) = outputs.split_at_mut(out_i); let (gate, vel) = r.split_at_mut(1); @@ -111,6 +121,8 @@ impl DspNode for MidiP { let mut ptr = MidiEventPointer::new(&ectx.midi_notes[..]); + let gmode = gmode.i(); + for frame in 0..ctx.nframes() { if self.next_gate > 0 { self.cur_gate = 1; @@ -132,6 +144,7 @@ impl DspNode for MidiP { } else { self.cur_gate = 1; } + self.trig_sig.trigger(); self.cur_note = note; self.cur_vel = vel; } @@ -148,11 +161,19 @@ impl DspNode for MidiP { } } + match gmode { + 1 => { + gate.write(frame, self.trig_sig.next()); + } + _ => { + gate.write(frame, if self.cur_gate > 0 { 1.0 } else { 0.0 }); + } + } + let note = (self.cur_note as f32 - 69.0) / 120.0; let note = note + det.read(frame); //d// println!("FRAME: {} => gate={}, freq={}, next_gate={}", frame, self.cur_gate, note, self.next_gate); freq.write(frame, note); - gate.write(frame, if self.cur_gate > 0 { 1.0 } else { 0.0 }); vel.write(frame, self.cur_vel as f32); } diff --git a/tests/common/mod.rs b/tests/common/mod.rs index a8472ae..1c97825 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -335,6 +335,27 @@ pub fn collect_signal_changes(inp: &[f32], thres: i64) -> Vec<(usize, i64)> { return idxs_big; } +#[allow(dead_code)] +pub fn collect_signal_changes_both_edges(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] - last_sig) * 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; +} + #[allow(dead_code)] pub fn collect_signal_changes_flt(inp: &[f32], delta: f32) -> Vec<(usize, f32)> { let mut idxs = vec![]; diff --git a/tests/node_midip.rs b/tests/node_midip.rs index 5527ed8..844e5bc 100644 --- a/tests/node_midip.rs +++ b/tests/node_midip.rs @@ -151,3 +151,41 @@ fn check_node_midip_off_on_test() { let changes = collect_signal_changes(&ch1[..], -1); assert_eq!(changes, vec![(0, 100), (5, 0), (6, 100)]); } + +#[test] +fn check_node_midip_trigger_test() { + let (node_conf, mut node_exec) = new_node_engine(); + let mut matrix = Matrix::new(node_conf, 3, 3); + + let mut chain = MatrixCellChain::new(CellDir::B); + chain + .node_out("midip", "gate") + .set_denorm("det", 0.1) + .set_atom("gmode", SAtom::setting(1)) + .node_inp("out", "ch1") + .place(&mut matrix, 0, 0) + .unwrap(); + matrix.sync().unwrap(); + + let (ch1, _) = node_exec.test_run( + 0.015, + false, + &[HxTimedEvent::note_on(100, 0, 69, 1.0), HxTimedEvent::note_off(105, 0, 69)], + ); + + let changes = collect_signal_changes_both_edges(&ch1[..], 1); + assert_eq!(changes, vec![(100, 100), (189, -100)]); + + // Now test without the trigger signal: + node_pset_s(&mut matrix, "midip", 0, "gmode", 0); + + let (ch1, _) = node_exec.test_run( + 0.015, + false, + &[HxTimedEvent::note_on(100, 0, 69, 1.0), HxTimedEvent::note_off(105, 0, 69)], + ); + + let changes = collect_signal_changes_both_edges(&ch1[..], 1); + // As expected, now end of note at 106: + assert_eq!(changes, vec![(100, 100), (106, -100)]); +}