use crate::*; /// Process MIDI events pub fn process_events( process_handler: &mut ProcessHandler, 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(()) }