use crate::midi_observer::{MidiEvent, MidiObserver};
#[derive(Default)]
pub struct DebugMidiObserver {
pub truncate_sysex: bool,
}
impl DebugMidiObserver {
pub fn new() -> Self {
Self::default()
}
pub fn with_truncate_sysex(mut self, on: bool) -> Self {
self.truncate_sysex = on;
self
}
}
impl MidiObserver for DebugMidiObserver {
fn on_midi_event(&mut self, event: &MidiEvent, source_channel: usize) {
let body = match event {
MidiEvent::NoteOff {
channel,
note,
velocity,
} => format!(
"NoteOff midi_ch={} note={} vel={}",
channel, note, velocity
),
MidiEvent::NoteOn {
channel,
note,
velocity,
} => format!(
"NoteOn midi_ch={} note={} vel={}",
channel, note, velocity
),
MidiEvent::PolyAftertouch {
channel,
note,
pressure,
} => format!(
"PolyAfterTouch midi_ch={} note={} pressure={}",
channel, note, pressure
),
MidiEvent::ControlChange {
channel,
controller,
value,
} => format!(
"ControlChange midi_ch={} cc={} val={}",
channel, controller, value
),
MidiEvent::ProgramChange { channel, program } => {
format!("ProgramChange midi_ch={} program={}", channel, program)
}
MidiEvent::ChannelAftertouch { channel, pressure } => {
format!("ChAfterTouch midi_ch={} pressure={}", channel, pressure)
}
MidiEvent::PitchBend { channel, value } => {
format!(
"PitchBend midi_ch={} value={} (centre=8192)",
channel, value
)
}
MidiEvent::SysEx(data) => self.format_bytes("SysEx ", data, self.truncate_sysex),
MidiEvent::Raw(data) => self.format_bytes("Raw ", data, false),
};
println!("ch{:02} {}", source_channel, body);
}
}
impl DebugMidiObserver {
fn format_bytes(&self, label: &str, data: &[u8], truncate: bool) -> alloc::string::String {
let truncated = truncate && data.len() > 8;
let take = if truncated { 8 } else { data.len() };
let hex: alloc::vec::Vec<_> = data
.iter()
.take(take)
.map(|b| format!("{:02X}", b))
.collect();
let tail = if truncated { ", ..." } else { "" };
format!(
"{} len={} data=[{}{}]",
label,
data.len(),
hex.join(", "),
tail
)
}
}