diff --git a/crates/tek/src/midi/midi_play.rs b/crates/tek/src/midi/midi_play.rs index 6a703e3f..12d414c7 100644 --- a/crates/tek/src/midi/midi_play.rs +++ b/crates/tek/src/midi/midi_play.rs @@ -24,48 +24,47 @@ pub trait MidiPlaybackApi: HasPlayPhrase + HasClock + HasMidiOuts { 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(); - // 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) - } + // If a phrase is playing, write a chunk of MIDI events from it to the output buffer. + // If no phrase is playing, prepare for switchover immediately. + self.play_phrase().as_ref().map_or(true, |(started, phrase)|{ + self.play_phrase_chunk(scope, note_buf, out, started, phrase) + }) + } + + fn play_phrase_chunk ( + &self, + scope: &ProcessScope, + note_buf: &mut Vec, + out: &mut [Vec>], + started: &Moment, + phrase: &Option>> + ) -> bool { + // 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 = (scope.last_frame_time() as usize).saturating_sub( + started.sample.get() as usize + + 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) + // 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 = self.clock().timebase().pulses_between_samples(sample, sample + scope.n_frames() as usize); + // Notes active during current chunk. + 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 { + // If a next phrase is enqueued, and we're past the end of the current one, + // break the loop here (FIXME count pulse correctly) + let past_end = if phrase.is_some() { pulse >= length } else { true }; + if self.next_phrase().is_some() && past_end { + return true + } + // 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 } + false } fn play_pulse (