flatten midi playback some more

This commit is contained in:
🪞👃🪞 2024-12-26 00:05:42 +01:00
parent e2172f287c
commit f57589e83a

View file

@ -21,49 +21,51 @@ pub trait MidiPlaybackApi: HasPlayPhrase + HasClock + HasMidiOuts {
fn play (
&mut self, scope: &ProcessScope, note_buf: &mut Vec<u8>, out: &mut [Vec<Vec<u8>>]
) -> bool {
let mut next = false;
// Write MIDI events from currently playing phrase (if any) to MIDI output buffer
if self.clock().is_rolling() {
let sample0 = scope.last_frame_time() as usize;
let samples = scope.n_frames() as usize;
// If no phrase is playing, prepare for switchover immediately
next = self.play_phrase().is_none();
let phrase = self.play_phrase();
if !self.clock().is_rolling() {
return false
}
let playing = self.play_phrase();
if let Some((started, phrase)) = playing {
// If a phrase is playing, write a chunk of MIDI events from it to the output buffer
let mut next = false;
let sample0 = scope.last_frame_time() as usize;
let samples = scope.n_frames() as usize;
let started0 = &self.clock().started;
let timebase = self.clock().timebase();
let notes_out = self.notes_out();
let next_phrase = self.next_phrase();
if let Some((started, phrase)) = phrase {
// First sample to populate. Greater than 0 means that the first
// pulse of the phrase falls somewhere in the middle of the chunk.
let sample = started.sample.get() as usize;
let sample = sample + started0.read().unwrap().as_ref().unwrap().sample.get() as usize;
let sample = sample0.saturating_sub(sample);
// Iterator that emits sample (index into output buffer at which to write MIDI event)
// paired with pulse (index into phrase from which to take the MIDI event) for each
// sample of the output buffer that corresponds to a MIDI pulse.
let pulses = timebase.pulses_between_samples(sample, sample + samples);
// Notes active during current chunk.
let notes = &mut notes_out.write().unwrap();
for (sample, pulse) in pulses {
// If a next phrase is enqueued, and we're past the end of the current one,
// break the loop here (FIXME count pulse correctly)
next = next_phrase.is_some() && if let Some(ref phrase) = phrase {
pulse >= phrase.read().unwrap().length
} else {
true
};
if next {
break
}
// If there's a currently playing phrase, output notes from it to buffer:
if let Some(ref phrase) = phrase {
Self::play_pulse(phrase, pulse, sample, note_buf, out, notes)
}
// First sample to populate. Greater than 0 means that the first
// pulse of the phrase falls somewhere in the middle of the chunk.
let sample = started.sample.get() as usize;
let sample = sample + started0.read().unwrap().as_ref().unwrap().sample.get() as usize;
let sample = sample0.saturating_sub(sample);
// Iterator that emits sample (index into output buffer at which to write MIDI event)
// paired with pulse (index into phrase from which to take the MIDI event) for each
// sample of the output buffer that corresponds to a MIDI pulse.
let pulses = timebase.pulses_between_samples(sample, sample + samples);
// Notes active during current chunk.
let notes = &mut notes_out.write().unwrap();
for (sample, pulse) in pulses {
// If a next phrase is enqueued, and we're past the end of the current one,
// break the loop here (FIXME count pulse correctly)
next = next_phrase.is_some() && if let Some(ref phrase) = phrase {
pulse >= phrase.read().unwrap().length
} else {
true
};
if next {
break
}
// If there's a currently playing phrase, output notes from it to buffer:
if let Some(ref phrase) = phrase {
Self::play_pulse(phrase, pulse, sample, note_buf, out, notes)
}
}
next
} else {
// If no phrase is playing, prepare for switchover immediately
true
}
next
}
fn play_pulse (