From 60281a86b79bd14086238bfd128a455322c84c55 Mon Sep 17 00:00:00 2001 From: Weird Constructor Date: Thu, 11 Aug 2022 20:29:06 +0200 Subject: [PATCH] Made the first MidiP test work properly --- src/dsp/node_midip.rs | 1 + src/nodes/mod.rs | 2 +- src/nodes/node_exec.rs | 37 ++++++++++++++++++++++++++++++++++-- src/nodes/note_buffer.rs | 41 +++++++++++++++++++++++++++------------- tests/common/mod.rs | 3 ++- tests/node_midip.rs | 30 +++++++++++++++++++++++++++++ 6 files changed, 97 insertions(+), 17 deletions(-) create mode 100644 tests/node_midip.rs diff --git a/src/dsp/node_midip.rs b/src/dsp/node_midip.rs index 7b12b58..5fc69cc 100644 --- a/src/dsp/node_midip.rs +++ b/src/dsp/node_midip.rs @@ -94,6 +94,7 @@ impl DspNode for MidiP { let note = (chan.note as f32 - 57.0) / 120.0; freq.write(frame, note); + println!("FRAME: {}, gate={}, freq={}", frame, chan.gate, chan.note); if chan.gate > 0 { // insert a single sample of silence, for retriggering diff --git a/src/nodes/mod.rs b/src/nodes/mod.rs index 309e95b..d5de649 100644 --- a/src/nodes/mod.rs +++ b/src/nodes/mod.rs @@ -31,7 +31,7 @@ pub use node_conf::*; pub use node_exec::*; pub use node_graph_ordering::NodeGraphOrdering; pub use node_prog::*; -pub use note_buffer::{NoteBuffer, NoteChannelState}; +pub use note_buffer::{NoteBuffer, NoteChannelState, HxTimedEvent, HxMidiEvent, EventWindowing}; use crate::dsp::{Node, SAtom}; pub use crate::monitor::MinMaxMonitorSamples; diff --git a/src/nodes/node_exec.rs b/src/nodes/node_exec.rs index db16984..014dd08 100644 --- a/src/nodes/node_exec.rs +++ b/src/nodes/node_exec.rs @@ -5,7 +5,7 @@ use super::NoteBuffer; use super::{ DropMsg, GraphMessage, NodeProg, FB_DELAY_TIME_US, MAX_ALLOCATED_NODES, MAX_FB_DELAY_SIZE, - MAX_SMOOTHERS, UNUSED_MONITOR_IDX, + MAX_SMOOTHERS, UNUSED_MONITOR_IDX, HxTimedEvent, EventWindowing, HxMidiEvent, }; use crate::dsp::{Node, NodeContext, NodeId, MAX_BLOCK_SIZE}; use crate::monitor::{MonitorBackend, MON_SIG_CNT}; @@ -521,11 +521,13 @@ impl NodeExecutor { /// /// You can use it's source as reference for your own audio /// DSP thread processing function. - pub fn test_run(&mut self, seconds: f32, realtime: bool) -> (Vec, Vec) { + pub fn test_run(&mut self, seconds: f32, realtime: bool, mut events: Vec) -> (Vec, Vec) { const SAMPLE_RATE: f32 = 44100.0; self.set_sample_rate(SAMPLE_RATE); self.process_graph_updates(); + let mut ev_win = EventWindowing::new(); + let mut nframes = (seconds * SAMPLE_RATE) as usize; let input = vec![0.0; nframes]; @@ -541,6 +543,37 @@ impl NodeExecutor { let cur_nframes = if nframes >= MAX_BLOCK_SIZE { MAX_BLOCK_SIZE } else { nframes }; nframes -= cur_nframes; + let buf = self.get_note_buffer(); + buf.reset(); + loop { + if ev_win.feed_me() { + if events.is_empty() { + break; + } + + ev_win.feed(events.remove(0)); + println!("FEED {}", offs); + } + + println!("CHECK {}", offs); + if let Some((timing, event)) = ev_win.next_event_in_range(offs + cur_nframes) { + buf.step_to(timing); + match event { + HxMidiEvent::NoteOn { channel, note, vel } => { + buf.note_on(channel, note); + buf.set_velocity(channel, vel); + } + HxMidiEvent::NoteOff { channel, note } => { + buf.note_off(channel, note); + } + } + + } else { + break; + } + } + self.get_note_buffer().step_to(cur_nframes - 1); + let mut context = crate::Context { nframes: cur_nframes, output: &mut [ diff --git a/src/nodes/note_buffer.rs b/src/nodes/note_buffer.rs index 9af1aec..084e8f9 100644 --- a/src/nodes/note_buffer.rs +++ b/src/nodes/note_buffer.rs @@ -5,16 +5,32 @@ use crate::dsp::MAX_BLOCK_SIZE; #[derive(Debug, Clone, Copy)] -pub struct TimedEvent { +pub struct HxTimedEvent { /// The frame number in the current block by the audio driver or plugin API/DAW timing: usize, - kind: MidiEvent, + kind: HxMidiEvent, +} + +impl HxTimedEvent { + pub fn note_on(timing: usize, channel: u8, note: u8, vel: f32) -> Self { + Self { + timing, + kind: HxMidiEvent::NoteOn { channel, note, vel } + } + } + + pub fn note_off(timing: usize, channel: u8, note: u8) -> Self { + Self { + timing, + kind: HxMidiEvent::NoteOff { channel, note } + } + } } #[derive(Debug, Clone, Copy)] -pub enum MidiEvent { +pub enum HxMidiEvent { NoteOn { channel: u8, note: u8, vel: f32 }, - NoteOff { channel: u8, note: u8, vel: f32 }, + NoteOff { channel: u8, note: u8 }, } #[derive(Debug, Clone, Copy)] @@ -74,7 +90,8 @@ impl NoteBuffer { #[inline] pub fn note_on(&mut self, channel: u8, note: u8) { let mut chan = &mut self.interleaved_chans[(self.buf_idx * 16) + (channel as usize % 16)]; - chan.gate = (chan.gate + 1) % 2 + 1; + println!("NOTE ON {}, GATE={}", note, chan.gate); + chan.gate = chan.gate % 2 + 1; chan.note = note; } @@ -97,8 +114,8 @@ impl NoteBuffer { } } -struct EventWindowing { - pub event: Option, +pub struct EventWindowing { + pub event: Option, } impl EventWindowing { @@ -114,17 +131,15 @@ impl EventWindowing { } #[inline] - pub fn feed(&mut self, event: TimedEvent) { + pub fn feed(&mut self, event: HxTimedEvent) { self.event = Some(event); } #[inline] - pub fn next_event_in_range(&mut self, to_time: usize) -> Option { - let to_time = to_time as u32; - + pub fn next_event_in_range(&mut self, to_time: usize) -> Option<(usize, HxMidiEvent)> { if let Some(event) = self.event.take() { - if event.timing() < to_time { - return Some(event); + if event.timing < to_time { + return Some((event.timing, event.kind)); } else { self.event = Some(event); } diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 942dc90..3999b39 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -7,6 +7,7 @@ pub use hexodsp::matrix::*; pub use hexodsp::nodes::new_node_engine; pub use hexodsp::MatrixCellChain; pub use hexodsp::NodeExecutor; +pub use hexodsp::nodes::{HxTimedEvent, HxMidiEvent}; use hound; @@ -518,7 +519,7 @@ pub fn run_realtime_no_input( seconds: f32, sleep_a_bit: bool, ) -> (Vec, Vec) { - node_exec.test_run(seconds, sleep_a_bit) + node_exec.test_run(seconds, sleep_a_bit, vec![]) } pub fn calc_rms_mimax_each_ms(buf: &[f32], ms: f32) -> Vec<(f32, f32, f32)> { diff --git a/tests/node_midip.rs b/tests/node_midip.rs new file mode 100644 index 0000000..e5b7822 --- /dev/null +++ b/tests/node_midip.rs @@ -0,0 +1,30 @@ +// Copyright (c) 2022 Weird Constructor +// This file is a part of HexoDSP. Released under GPL-3.0-or-later. +// See README.md and COPYING for details. + +mod common; +use common::*; + +#[test] +fn check_node_midip_gate_inserts() { + 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").node_inp("out", "ch1").place(&mut matrix, 0, 0).unwrap(); + matrix.sync().unwrap(); + + let (ch1, _) = node_exec.test_run(0.005, false, vec![ + HxTimedEvent::note_on(5, 0, 69, 1.0), + HxTimedEvent::note_on(10, 0, 68, 1.0), + HxTimedEvent::note_on(130, 0, 57, 1.0), + ]); + + let changes = collect_signal_changes(&ch1[..], 0); + + assert_eq!(changes, vec![ + (5, 100), + (11, 100), + (131, 100), + ]); +}