new buffer less and simpler style of midi event processing

This commit is contained in:
Weird Constructor 2022-08-14 00:32:48 +02:00
parent 1d595fe52f
commit 0f5b44141d
4 changed files with 119 additions and 44 deletions

View file

@ -5,7 +5,7 @@
use crate::dsp::{
at, denorm, inp, out_idx, DspNode, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom,
};
use crate::nodes::{NodeAudioContext, NodeExecContext};
use crate::nodes::{HxMidiEvent, MidiEventPointer, NodeAudioContext, NodeExecContext};
#[macro_export]
macro_rules! fa_midip_chan {
@ -30,12 +30,15 @@ macro_rules! fa_midip_gmode {
/// The (stereo) output port of the plugin
#[derive(Debug, Clone)]
pub struct MidiP {
prev_gate: u8,
next_gate: i8,
cur_note: u8,
cur_gate: u8,
cur_vel: f32,
}
impl MidiP {
pub fn new(_nid: &NodeId) -> Self {
Self { prev_gate: 0 }
Self { next_gate: 0, cur_note: 0, cur_gate: 0, cur_vel: 0.0 }
}
pub const chan: &'static str = "MidiP chan\nMIDI Channel 0 to 15\n";
@ -106,29 +109,54 @@ impl DspNode for MidiP {
let gate = &mut gate[0];
let vel = &mut vel[0];
let channel = (chan.i() as usize % 16) as u8;
let midip_channel = (chan.i() as usize % 16) as u8;
let mut ptr = MidiEventPointer::new(&ectx.midi_notes[..]);
for frame in 0..ctx.nframes() {
let chan = ectx.note_buffer.get_chan_at(channel, frame as u8);
if self.next_gate > 0 {
self.cur_gate = 1;
} else if self.next_gate < 0 {
self.cur_gate = 0;
}
self.next_gate = 0;
let note = (chan.note as f32 - 69.0) / 120.0;
let note = note + det.read(frame);
freq.write(frame, note);
while let Some(ev) = ptr.next_at(frame) {
println!("MIDIP EV: {} {:?}", frame, ev);
match ev {
HxMidiEvent::NoteOn { channel, note, vel } => {
if channel != midip_channel {
continue;
}
if chan.gate & 0x10 > 0 {
// insert a single sample of silence, for retriggering
// any envelopes if the note changed but no note-off came.
if self.prev_gate > 0 && self.prev_gate != chan.gate {
gate.write(frame, 0.0);
} else {
gate.write(frame, 1.0);
if self.cur_gate > 0 {
self.next_gate = 1;
self.cur_gate = 0;
} else {
self.cur_gate = 1;
}
self.cur_note = note;
self.cur_vel = vel;
}
HxMidiEvent::NoteOff { channel, note } => {
if channel != midip_channel {
continue;
}
if self.cur_note == note {
self.next_gate = -1;
}
}
_ => (),
}
} else {
gate.write(frame, 0.0);
}
self.prev_gate = chan.gate;
vel.write(frame, chan.vel as f32);
let note = (self.cur_note as f32 - 69.0) / 120.0;
let note = note + det.read(frame);
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);
}
let last_val = gate.read(ctx.nframes() - 1);

View file

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

View file

@ -25,6 +25,9 @@ use core::arch::x86_64::{
// _MM_GET_FLUSH_ZERO_MODE
};
pub const MAX_MIDI_NOTES_PER_BLOCK: usize = 512;
pub const MAX_MIDI_CC_PER_BLOCK: usize = 1024;
/// Holds the complete allocation of nodes and
/// the program. New Nodes or the program is
/// not newly allocated in the audio backend, but it is
@ -171,13 +174,17 @@ impl Default for FeedbackBuffer {
pub struct NodeExecContext {
pub feedback_delay_buffers: Vec<FeedbackBuffer>,
pub note_buffer: NoteBuffer,
pub midi_notes: Vec<HxTimedEvent>,
pub midi_ccs: Vec<HxTimedEvent>,
}
impl NodeExecContext {
fn new() -> Self {
let mut fbdb = vec![];
fbdb.resize_with(MAX_ALLOCATED_NODES, FeedbackBuffer::new);
Self { feedback_delay_buffers: fbdb, note_buffer: NoteBuffer::new() }
let midi_notes = Vec::with_capacity(MAX_MIDI_NOTES_PER_BLOCK);
let midi_ccs = Vec::with_capacity(MAX_MIDI_CC_PER_BLOCK);
Self { feedback_delay_buffers: fbdb, note_buffer: NoteBuffer::new(), midi_notes, midi_ccs }
}
fn set_sample_rate(&mut self, srate: f32) {
@ -354,6 +361,27 @@ impl NodeExecutor {
}
}
#[inline]
pub fn feed_midi_events_from<F: FnMut() -> Option<HxTimedEvent>>(&mut self, mut f: F) {
self.exec_ctx.midi_notes.clear();
self.exec_ctx.midi_ccs.clear();
while let Some(ev) = f() {
if ev.is_cc() {
self.exec_ctx.midi_ccs.push(ev);
} else {
self.exec_ctx.midi_notes.push(ev);
}
if self.exec_ctx.midi_ccs.len() == MAX_MIDI_CC_PER_BLOCK {
break;
}
if self.exec_ctx.midi_notes.len() == MAX_MIDI_NOTES_PER_BLOCK {
break;
}
}
}
#[inline]
pub fn get_note_buffer(&mut self) -> &mut NoteBuffer {
&mut self.exec_ctx.note_buffer
@ -548,33 +576,17 @@ 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 {
self.feed_midi_events_from(|| {
if ev_win.feed_me() {
if events.is_empty() {
break;
return None;
}
ev_win.feed(events.remove(0));
}
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);
ev_win.next_event_in_range(offs, cur_nframes)
});
let mut context = crate::Context {
nframes: cur_nframes,

View file

@ -12,6 +12,14 @@ pub struct HxTimedEvent {
}
impl HxTimedEvent {
pub fn is_cc(&self) -> bool {
if let HxMidiEvent::CC { .. } = self.kind {
true
} else {
false
}
}
pub fn note_on(timing: usize, channel: u8, note: u8, vel: f32) -> Self {
Self { timing, kind: HxMidiEvent::NoteOn { channel, note, vel } }
}
@ -21,10 +29,31 @@ impl HxTimedEvent {
}
}
pub struct MidiEventPointer<'a> {
buf: &'a [HxTimedEvent],
idx: usize,
}
impl<'a> MidiEventPointer<'a> {
pub fn new(buf: &'a [HxTimedEvent]) -> Self {
Self { buf, idx: 0 }
}
pub fn next_at(&mut self, time: usize) -> Option<HxMidiEvent> {
if self.idx < self.buf.len() && self.buf[self.idx].timing <= time {
self.idx += 1;
Some(self.buf[self.idx - 1].kind)
} else {
None
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum HxMidiEvent {
NoteOn { channel: u8, note: u8, vel: f32 },
NoteOff { channel: u8, note: u8 },
CC { channel: u8, cc: u8, value: f32 },
}
#[derive(Debug, Clone, Copy)]
@ -128,10 +157,14 @@ impl EventWindowing {
}
#[inline]
pub fn next_event_in_range(&mut self, to_time: usize) -> Option<(usize, HxMidiEvent)> {
pub fn next_event_in_range(
&mut self,
to_time: usize,
block_size: usize,
) -> Option<HxTimedEvent> {
if let Some(event) = self.event.take() {
if event.timing < to_time {
return Some((event.timing, event.kind));
if event.timing < (to_time + block_size) {
return Some(HxTimedEvent { timing: event.timing - to_time, kind: event.kind });
} else {
self.event = Some(event);
}