launch countdown/switchover, pt.2

This commit is contained in:
🪞👃🪞 2024-11-01 20:52:14 +02:00
parent 3df8e87840
commit 97a7bf5b1d
3 changed files with 31 additions and 12 deletions

View file

@ -236,12 +236,20 @@ impl<E: Engine> Arrangement<E> {
size: Measure::new(),
}
}
fn is_stopped (&self) -> bool {
*self.clock.playing.read().unwrap() == Some(TransportState::Stopped)
}
pub fn activate (&mut self) {
match self.selected {
ArrangementFocus::Scene(s) => {
for (t, track) in self.tracks.iter_mut().enumerate() {
track.player.enqueue_next(self.scenes[s].clips[t].as_ref());
}
// TODO make transport available here, so that
// activating a scene when stopped starts playback
//if self.is_stopped() {
//self.transport.toggle_play()
//}
},
ArrangementFocus::Clip(t, s) => {
self.tracks[t].player.enqueue_next(self.scenes[s].clips[t].as_ref());

View file

@ -11,7 +11,7 @@ impl<E: Engine> Audio for Sequencer<E> {
impl Audio for PhrasePlayer {
fn process (&mut self, _: &Client, scope: &ProcessScope) -> Control {
let has_midi_outputs = self.has_midi_outputs();
let has_midi_inputs = self.has_midi_inputs();
let has_midi_inputs = self.has_midi_inputs();
if has_midi_outputs {
// Clear output buffer(s)
self.clear(scope, false);
@ -45,11 +45,12 @@ impl PhrasePlayer {
all_notes_off(&mut self.midi_out_buf); self.reset = false;
}
}
fn is_rolling (&self) -> bool {
*self.clock.playing.read().unwrap() == Some(TransportState::Rolling)
}
/// Return playing phrase with starting point
fn playing (&self) -> Option<(usize, Arc<RwLock<Phrase>>)> {
if let (
Some(TransportState::Rolling), Some((started, Some(ref phrase)))
) = (*self.clock.playing.read().unwrap(), &self.phrase) {
if let (true, Some((started, Some(ref phrase)))) = (self.is_rolling(), &self.phrase) {
Some((started.sample().get() as usize, phrase.clone()))
} else {
None
@ -57,9 +58,7 @@ impl PhrasePlayer {
}
/// Return next phrase with starting point
fn enqueued (&self) -> Option<(usize, Arc<RwLock<Phrase>>)> {
if let (
Some(TransportState::Rolling), Some((start_at, Some(ref phrase)))
) = (*self.clock.playing.read().unwrap(), &self.next_phrase) {
if let (true, Some((start_at, Some(ref phrase)))) = (self.is_rolling(), &self.next_phrase) {
Some((start_at.sample().get() as usize, phrase.clone()))
} else {
None
@ -76,6 +75,10 @@ impl PhrasePlayer {
let notes_on = &mut self.notes_out.write().unwrap();
let mut buf = Vec::with_capacity(8);
for (sample, tick) in ticks {
// If a next phrase is enqueued, and we're past the end of the current one,
// break the loop here (FIXME count tick correctly)
if self.next_phrase.is_some() && tick >= phrase.length { break }
// Output events from phrase at appropriate frames of output buffer
let tick = tick % phrase.length;
for message in phrase.notes[tick].iter() {
buf.clear();
@ -88,6 +91,9 @@ impl PhrasePlayer {
}
}).unwrap()
}
if let Some((start, ref phrase)) = self.enqueued() {
// TODO switch to next phrase and fill in remaining ticks from it
}
}
fn record (&mut self, scope: &ProcessScope) {
let sample0 = scope.last_frame_time() as usize;
@ -101,7 +107,9 @@ impl PhrasePlayer {
for input in self.midi_inputs.iter() {
for (sample, event, bytes) in parse_midi_input(input.iter(scope)) {
if let LiveEvent::Midi { message, .. } = event {
if self.monitoring { self.midi_out_buf[sample].push(bytes.to_vec()) }
if self.monitoring {
self.midi_out_buf[sample].push(bytes.to_vec())
}
if self.recording {
phrase.record_event({
let pulse = self.clock.timebase().samples_to_pulse(
@ -117,6 +125,9 @@ impl PhrasePlayer {
}
}
}
if let Some((start, ref phrase)) = self.enqueued() {
// TODO switch to next phrase and record into it
}
}
fn monitor (&mut self, scope: &ProcessScope) {
let mut notes_in = self.notes_in.write().unwrap();

View file

@ -2,13 +2,13 @@ use crate::*;
#[derive(Debug, Default)]
pub struct TransportTime {
/// Current moment in time
pub instant: Instant,
pub instant: Instant,
/// Note quantization factor
pub quant: TimeUnit,
pub quant: TimeUnit,
/// Launch quantization factor
pub sync: TimeUnit,
pub sync: TimeUnit,
/// Playback state
pub playing: RwLock<Option<TransportState>>,
pub playing: RwLock<Option<TransportState>>,
}
impl TransportTime {
pub fn timebase (&self) -> &Arc<Timebase> { &self.instant.timebase }