Made the first MidiP test work properly

This commit is contained in:
Weird Constructor 2022-08-11 20:29:06 +02:00
parent 22698c3a1a
commit 60281a86b7
6 changed files with 97 additions and 17 deletions

View file

@ -94,6 +94,7 @@ impl DspNode for MidiP {
let note = (chan.note as f32 - 57.0) / 120.0; let note = (chan.note as f32 - 57.0) / 120.0;
freq.write(frame, note); freq.write(frame, note);
println!("FRAME: {}, gate={}, freq={}", frame, chan.gate, chan.note);
if chan.gate > 0 { if chan.gate > 0 {
// insert a single sample of silence, for retriggering // insert a single sample of silence, for retriggering

View file

@ -31,7 +31,7 @@ pub use node_conf::*;
pub use node_exec::*; pub use node_exec::*;
pub use node_graph_ordering::NodeGraphOrdering; pub use node_graph_ordering::NodeGraphOrdering;
pub use node_prog::*; pub use node_prog::*;
pub use note_buffer::{NoteBuffer, NoteChannelState}; pub use note_buffer::{NoteBuffer, NoteChannelState, HxTimedEvent, HxMidiEvent, EventWindowing};
use crate::dsp::{Node, SAtom}; use crate::dsp::{Node, SAtom};
pub use crate::monitor::MinMaxMonitorSamples; pub use crate::monitor::MinMaxMonitorSamples;

View file

@ -5,7 +5,7 @@
use super::NoteBuffer; use super::NoteBuffer;
use super::{ use super::{
DropMsg, GraphMessage, NodeProg, FB_DELAY_TIME_US, MAX_ALLOCATED_NODES, MAX_FB_DELAY_SIZE, 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::dsp::{Node, NodeContext, NodeId, MAX_BLOCK_SIZE};
use crate::monitor::{MonitorBackend, MON_SIG_CNT}; 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 /// You can use it's source as reference for your own audio
/// DSP thread processing function. /// DSP thread processing function.
pub fn test_run(&mut self, seconds: f32, realtime: bool) -> (Vec<f32>, Vec<f32>) { pub fn test_run(&mut self, seconds: f32, realtime: bool, mut events: Vec<HxTimedEvent>) -> (Vec<f32>, Vec<f32>) {
const SAMPLE_RATE: f32 = 44100.0; const SAMPLE_RATE: f32 = 44100.0;
self.set_sample_rate(SAMPLE_RATE); self.set_sample_rate(SAMPLE_RATE);
self.process_graph_updates(); self.process_graph_updates();
let mut ev_win = EventWindowing::new();
let mut nframes = (seconds * SAMPLE_RATE) as usize; let mut nframes = (seconds * SAMPLE_RATE) as usize;
let input = vec![0.0; nframes]; 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 }; let cur_nframes = if nframes >= MAX_BLOCK_SIZE { MAX_BLOCK_SIZE } else { nframes };
nframes -= cur_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 { let mut context = crate::Context {
nframes: cur_nframes, nframes: cur_nframes,
output: &mut [ output: &mut [

View file

@ -5,16 +5,32 @@
use crate::dsp::MAX_BLOCK_SIZE; use crate::dsp::MAX_BLOCK_SIZE;
#[derive(Debug, Clone, Copy)] #[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 /// The frame number in the current block by the audio driver or plugin API/DAW
timing: usize, 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)] #[derive(Debug, Clone, Copy)]
pub enum MidiEvent { pub enum HxMidiEvent {
NoteOn { channel: u8, note: u8, vel: f32 }, NoteOn { channel: u8, note: u8, vel: f32 },
NoteOff { channel: u8, note: u8, vel: f32 }, NoteOff { channel: u8, note: u8 },
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
@ -74,7 +90,8 @@ impl NoteBuffer {
#[inline] #[inline]
pub fn note_on(&mut self, channel: u8, note: u8) { 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)]; 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; chan.note = note;
} }
@ -97,8 +114,8 @@ impl NoteBuffer {
} }
} }
struct EventWindowing { pub struct EventWindowing {
pub event: Option<TimedEvent>, pub event: Option<HxTimedEvent>,
} }
impl EventWindowing { impl EventWindowing {
@ -114,17 +131,15 @@ impl EventWindowing {
} }
#[inline] #[inline]
pub fn feed(&mut self, event: TimedEvent) { pub fn feed(&mut self, event: HxTimedEvent) {
self.event = Some(event); self.event = Some(event);
} }
#[inline] #[inline]
pub fn next_event_in_range(&mut self, to_time: usize) -> Option<NoteEvent> { pub fn next_event_in_range(&mut self, to_time: usize) -> Option<(usize, HxMidiEvent)> {
let to_time = to_time as u32;
if let Some(event) = self.event.take() { if let Some(event) = self.event.take() {
if event.timing() < to_time { if event.timing < to_time {
return Some(event); return Some((event.timing, event.kind));
} else { } else {
self.event = Some(event); self.event = Some(event);
} }

View file

@ -7,6 +7,7 @@ pub use hexodsp::matrix::*;
pub use hexodsp::nodes::new_node_engine; pub use hexodsp::nodes::new_node_engine;
pub use hexodsp::MatrixCellChain; pub use hexodsp::MatrixCellChain;
pub use hexodsp::NodeExecutor; pub use hexodsp::NodeExecutor;
pub use hexodsp::nodes::{HxTimedEvent, HxMidiEvent};
use hound; use hound;
@ -518,7 +519,7 @@ pub fn run_realtime_no_input(
seconds: f32, seconds: f32,
sleep_a_bit: bool, sleep_a_bit: bool,
) -> (Vec<f32>, Vec<f32>) { ) -> (Vec<f32>, Vec<f32>) {
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)> { pub fn calc_rms_mimax_each_ms(buf: &[f32], ms: f32) -> Vec<(f32, f32, f32)> {

30
tests/node_midip.rs Normal file
View file

@ -0,0 +1,30 @@
// Copyright (c) 2022 Weird Constructor <weirdconstructor@gmail.com>
// 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),
]);
}