flatten midi playback logic furter

This commit is contained in:
🪞👃🪞 2024-12-26 00:20:04 +01:00
parent f57589e83a
commit 2492537c32

View file

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