use crate::core::*; pub type PhraseData = BTreeMap>; pub type MIDIMessage = Vec; pub type MIDIChunk = [Option>]; pub struct Phrase { pub name: String, pub length: usize, pub notes: PhraseData, } impl Phrase { pub fn new (name: &str, length: usize, notes: Option) -> Self { Self { name: name.to_string(), length, notes: notes.unwrap_or(BTreeMap::new()) } } /// Check if a range `start..end` contains MIDI Note On `k` pub fn contains_note_on (&self, k: u7, start: usize, end: usize) -> bool { for (_, (_, events)) in self.notes.range(start..end).enumerate() { for event in events.iter() { match event { MidiMessage::NoteOn {key,..} => { if *key == k { return true } } _ => {} } } } return false } /// Write a chunk of MIDI events to an output port. pub fn process_out ( &self, output: &mut MIDIChunk, notes_on: &mut Vec, timebase: &Arc, frame0: usize, frames: usize, ) { let start = frame0 as f64; let end = start + frames as f64; let repeat = timebase.pulses_frames(self.length as f64); let ticks = timebase.frames_to_ticks(start, end, repeat); //panic!("{start} {end} {repeat} {ticks:?}"); for (time, tick) in ticks.iter() { let events = self.notes.get(&(*tick as usize)); if events.is_none() { continue } for message in events.unwrap().iter() { let mut buf = vec![]; let channel = 0.into(); let message = *message; match message { MidiMessage::NoteOn { key, .. } => notes_on[key.as_int() as usize] = true, MidiMessage::NoteOff { key, .. } => notes_on[key.as_int() as usize] = false, _ => {} } LiveEvent::Midi { channel, message }.write(&mut buf).unwrap(); let t = *time as usize; if output[t].is_none() { output[t] = Some(vec![]); } if let Some(Some(frame)) = output.get_mut(t) { frame.push(buf); } } } } /// Read a chunk of MIDI events from an input port. pub fn process_in ( &mut self, input: ::jack::MidiIter, notes_on: &mut Vec, mut monitor: Option<&mut MIDIChunk>, record: bool, timebase: &Arc, frame0: usize, ) { for RawMidi { time, bytes } in input { let time = time as usize; let pulse = timebase.frames_pulses((frame0 + time) as f64) as usize; if let LiveEvent::Midi { message, .. } = LiveEvent::parse(bytes).unwrap() { if let MidiMessage::NoteOn { key, vel: _ } = message { notes_on[key.as_int() as usize] = true; if let Some(ref mut monitor) = monitor { if monitor[time].is_none() { monitor[time] = Some(vec![]); } if let Some(Some(frame)) = monitor.get_mut(time) { frame.push(bytes.into()) } } if record { let contains = self.notes.contains_key(&pulse); if contains { self.notes.get_mut(&pulse).unwrap().push(message.clone()); } else { self.notes.insert(pulse, vec![message.clone()]); } } } else if let midly::MidiMessage::NoteOff { key, vel: _ } = message { notes_on[key.as_int() as usize] = false; if let Some(ref mut monitor) = monitor { if monitor[time].is_none() { monitor[time] = Some(vec![]); } if let Some(Some(frame)) = monitor.get_mut(time) { frame.push(bytes.into()) } } if record { let contains = self.notes.contains_key(&pulse); if contains { self.notes.get_mut(&pulse).unwrap().push(message.clone()); } else { self.notes.insert(pulse, vec![message.clone()]); } } } } } } } impl Default for Phrase { fn default () -> Self { Self::new("", 0, None) } }