fcb_looper/src/midi.rs

68 lines
2.5 KiB
Rust

use crate::*;
/// Process MIDI events
pub fn process_events<F: ChunkFactory>(
process_handler: &mut ProcessHandler<F>,
ps: &jack::ProcessScope,
) -> Result<()> {
// First, collect all MIDI events into a fixed-size array
// This avoids allocations while solving borrow checker issues
const MAX_EVENTS: usize = 16; // Reasonable limit for real-time processing
let mut raw_events = [[0u8; 3]; MAX_EVENTS];
let mut event_count = 0;
// Collect events from the MIDI input iterator
let midi_input = process_handler.ports.midi_in.iter(ps);
for midi_event in midi_input {
if event_count < MAX_EVENTS && midi_event.bytes.len() >= 3 {
raw_events[event_count][0] = midi_event.bytes[0];
raw_events[event_count][1] = midi_event.bytes[1];
raw_events[event_count][2] = midi_event.bytes[2];
event_count += 1;
} else {
return Err(LooperError::OutOfBounds(std::panic::Location::caller()));
}
}
// Now process the collected events using wmidi
// The iterator borrow is dropped, so we can mutably borrow process_handler
for i in 0..event_count {
let event_bytes = &raw_events[i];
// Use wmidi for cleaner MIDI parsing instead of manual byte checking
match wmidi::MidiMessage::try_from(&event_bytes[..]) {
Ok(message) => {
match message {
wmidi::MidiMessage::ControlChange(_, controller, value) => {
// Only process button presses (value > 0)
if u8::from(value) > 0 {
match u8::from(controller) {
20 => {
// Button 1: Record/Play toggle
process_handler.record_toggle()?;
}
21 => {
// Button 2: Play/Mute
process_handler.play_toggle()?;
}
_ => {
// Other CC messages - ignore for now
}
}
}
}
_ => {
// Ignore other MIDI messages for now
}
}
}
Err(_) => {
// Skip malformed MIDI messages instead of panicking
continue;
}
}
}
Ok(())
}