refactor: phrase chunk in/out

This commit is contained in:
🪞👃🪞 2024-06-30 19:56:45 +03:00
parent 83830d9cb3
commit 8a2693c297
3 changed files with 127 additions and 141 deletions

View file

@ -0,0 +1,109 @@
use crate::prelude::*;
use super::*;
pub type PhraseData = BTreeMap<u32, Vec<MidiMessage>>;
pub type MIDIChunk = [Option<Vec<Vec<u8>>>];
pub struct Phrase {
pub name: String,
pub length: u32,
pub notes: PhraseData,
}
impl Phrase {
pub fn new (name: &str, length: u32, notes: Option<PhraseData>) -> Self {
Self { name: name.to_string(), length, notes: notes.unwrap_or(BTreeMap::new()) }
}
/** Write a chunk of MIDI events to an output port. */
pub fn chunk_out (
&self,
output: &mut MIDIChunk,
start: usize,
length: usize,
timebase: &Arc<Timebase>,
steps: usize,
resolution: usize,
) {
let quant = timebase.frames_per_beat() as usize * steps / resolution;
let ticks = timebase.frames_to_ticks(start, start + length, quant);
for (time, tick) in ticks.iter() {
if let Some(events) = self.notes.get(&(*tick as u32)) {
for message in events.iter() {
let mut buf = vec![];
let channel = 0.into();
let message = *message;
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);
}
}
}
}
}
/** React a chunk of MIDI events from an input port. */
pub fn chunk_in (
&mut self,
port: &Port<MidiIn>,
scope: &ProcessScope,
mut monitor: Option<&mut MIDIChunk>,
record: bool,
notes_on: &mut Vec<bool>,
tick: u32,
) {
for event in port.iter(scope) {
let msg = LiveEvent::parse(event.bytes).unwrap();
match msg {
LiveEvent::Midi { message, .. } => match message {
MidiMessage::NoteOn { key, vel: _ } => {
notes_on[key.as_int() as usize] = true;
if let Some(ref mut monitor) = monitor {
let t = event.time as usize;
if monitor[t].is_none() {
monitor[t] = Some(vec![]);
}
if let Some(Some(frame)) = monitor.get_mut(t) {
frame.push(event.bytes.into())
}
}
if record {
let contains = self.notes.contains_key(&tick);
if contains {
self.notes.get_mut(&tick).unwrap().push(message.clone());
} else {
self.notes.insert(tick, vec![message.clone()]);
}
}
},
midly::MidiMessage::NoteOff { key, vel: _ } => {
notes_on[key.as_int() as usize] = false;
if let Some(ref mut monitor) = monitor {
let t = event.time as usize;
if monitor[t].is_none() {
monitor[t] = Some(vec![]);
}
if let Some(Some(frame)) = monitor.get_mut(t) {
frame.push(event.bytes.into())
}
}
if record {
let contains = self.notes.contains_key(&tick);
if contains {
self.notes.get_mut(&tick).unwrap().push(message.clone());
} else {
self.notes.insert(tick, vec![message.clone()]);
}
}
},
_ => {}
},
_ => {}
}
}
}
}