From f57589e83ae33cf0dfc934bef3a8818c037d1763 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Thu, 26 Dec 2024 00:05:42 +0100 Subject: [PATCH] flatten midi playback some more --- crates/tek/src/midi/midi_play.rs | 74 ++++++++++++++++---------------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/crates/tek/src/midi/midi_play.rs b/crates/tek/src/midi/midi_play.rs index 297dc4ac..6a703e3f 100644 --- a/crates/tek/src/midi/midi_play.rs +++ b/crates/tek/src/midi/midi_play.rs @@ -21,49 +21,51 @@ pub trait MidiPlaybackApi: HasPlayPhrase + HasClock + HasMidiOuts { fn play ( &mut self, scope: &ProcessScope, note_buf: &mut Vec, out: &mut [Vec>] ) -> 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 (