diff --git a/rust/pm-grid/src/main.rs b/rust/pm-grid/src/main.rs index 9849306..a88830f 100644 --- a/rust/pm-grid/src/main.rs +++ b/rust/pm-grid/src/main.rs @@ -19,6 +19,7 @@ #![no_main] extern crate alloc; +use alloc::collections::VecDeque; use alloc::string::String; use alloc::vec::Vec; use embedded_alloc::LlffHeap as Heap; @@ -781,6 +782,9 @@ fn main() -> ! { let (mut nextrep_x, mut nextrep_y) = (0i64, 0i64); let mut last_frame_us = 0i64; let mut hb_us = 0i64; + // pending USB-MIDI packets: the bulk endpoint holds one 4-byte packet at a time, so simultaneous + // notes are queued here and drained one-per-poll (otherwise the 2nd note of a chord is dropped). + let mut note_q: VecDeque<[u8; 4]> = VecDeque::new(); loop { let us = now_us(); @@ -842,10 +846,21 @@ fn main() -> ! { px = x; py = y; - // ---- scheduler: advance clocks, send a USB-MIDI note-on per lane hit (ch10) ---- + // ---- scheduler: advance clocks, queue a USB-MIDI note-on per lane hit (ch10) ---- app.tick(now_ns, |note, vel| { - let _ = midi.send_bytes([0x09, 0x99, note, vel]); // cable 0, note-on, channel 10 + if note_q.len() < 64 { + note_q.push_back([0x09, 0x99, note, vel]); // cable 0, note-on, channel 10 + } }); + // drain the queue to the endpoint: send until it's busy (WouldBlock), keep the rest for the + // next poll. This is why chords play in full instead of dropping all but the first note. + while let Some(&pkt) = note_q.front() { + if midi.send_bytes(pkt).is_ok() { + note_q.pop_front(); + } else { + break; + } + } // ---- ticker scroll advance (~120ms) ---- // (uses the frame clock implicitly; scroll_off wraps mod scroll_total)