Made the first MidiP test work properly
This commit is contained in:
parent
22698c3a1a
commit
60281a86b7
6 changed files with 97 additions and 17 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<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;
|
||||
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 [
|
||||
|
|
|
@ -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<TimedEvent>,
|
||||
pub struct EventWindowing {
|
||||
pub event: Option<HxTimedEvent>,
|
||||
}
|
||||
|
||||
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<NoteEvent> {
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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<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)> {
|
||||
|
|
30
tests/node_midip.rs
Normal file
30
tests/node_midip.rs
Normal 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),
|
||||
]);
|
||||
}
|
Loading…
Reference in a new issue