pm-grid: fix dropped notes in chords (queue USB-MIDI packets)
The bulk MIDI endpoint holds one 4-byte packet until the host reads it (~once per USB frame), so calling send_bytes twice for simultaneous lane hits dropped the 2nd note (WouldBlock, silently ignored). Queue note-ons in a VecDeque and drain one-per-poll, keeping the rest for the next iteration — chords now play in full (staggered ~1ms, imperceptible) instead of all-but-one. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
56bff7e599
commit
47ffb46aa2
1 changed files with 17 additions and 2 deletions
|
|
@ -19,6 +19,7 @@
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
use alloc::collections::VecDeque;
|
||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use embedded_alloc::LlffHeap as Heap;
|
use embedded_alloc::LlffHeap as Heap;
|
||||||
|
|
@ -781,6 +782,9 @@ fn main() -> ! {
|
||||||
let (mut nextrep_x, mut nextrep_y) = (0i64, 0i64);
|
let (mut nextrep_x, mut nextrep_y) = (0i64, 0i64);
|
||||||
let mut last_frame_us = 0i64;
|
let mut last_frame_us = 0i64;
|
||||||
let mut hb_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 {
|
loop {
|
||||||
let us = now_us();
|
let us = now_us();
|
||||||
|
|
@ -842,10 +846,21 @@ fn main() -> ! {
|
||||||
px = x;
|
px = x;
|
||||||
py = y;
|
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| {
|
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) ----
|
// ---- ticker scroll advance (~120ms) ----
|
||||||
// (uses the frame clock implicitly; scroll_off wraps mod scroll_total)
|
// (uses the frame clock implicitly; scroll_off wraps mod scroll_total)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue