From 761ec78282d3063a911c72fd16588cbae21a1b0a Mon Sep 17 00:00:00 2001 From: unspeaker Date: Tue, 10 Dec 2024 20:16:06 +0100 Subject: [PATCH] flip it puside down --- crates/tek/src/api/clock.rs | 55 ++++++++++++----------------- crates/tek/src/api/phrase.rs | 2 +- crates/tek/src/tui/app_sequencer.rs | 34 +++++++++--------- crates/tek/src/tui/phrase_list.rs | 4 +-- 4 files changed, 42 insertions(+), 53 deletions(-) diff --git a/crates/tek/src/api/clock.rs b/crates/tek/src/api/clock.rs index 8e6e8574..6276b6b9 100644 --- a/crates/tek/src/api/clock.rs +++ b/crates/tek/src/api/clock.rs @@ -33,23 +33,6 @@ impl Command for ClockCommand { } } -#[derive(Clone)] -pub struct Timeline { - pub timebase: Arc, - pub started: Arc>>, - pub loopback: Arc>>, -} - -impl Default for Timeline { - fn default () -> Self { - Self { - timebase: Arc::new(Timebase::default()), - started: RwLock::new(None).into(), - loopback: RwLock::new(None).into(), - } - } -} - #[derive(Clone)] pub struct ClockModel { /// JACK transport handle. @@ -60,6 +43,8 @@ pub struct ClockModel { pub global: Arc, /// Global sample and usec at which playback started pub started: Arc>>, + /// Playback offset (when playing not from start) + pub offset: Arc, /// Current playhead position pub playhead: Arc, /// Note quantization factor @@ -83,6 +68,7 @@ impl From<&Arc>> for ClockModel { chunk: Arc::new((chunk as usize).into()), global: Arc::new(Moment::zero(&timebase)), playhead: Arc::new(Moment::zero(&timebase)), + offset: Arc::new(Moment::zero(&timebase)), started: RwLock::new(None).into(), timebase, } @@ -158,31 +144,34 @@ impl ClockModel { self.chunk.store(n_frames, Ordering::Relaxed); } pub fn update_from_scope (&self, scope: &ProcessScope) -> Usually<()> { + // Store buffer length self.set_chunk(scope.n_frames() as usize); + + // Store reported global frame and usec let CycleTimes { current_frames, current_usecs, .. } = scope.cycle_times()?; self.global.sample.set(current_frames as f64); self.global.usec.set(current_usecs as f64); + + // If transport has just started or just stopped, + // update starting point: let mut started = self.started.write().unwrap(); - match self.transport.query_state()? { - TransportState::Rolling => { - if started.is_none() { - let moment = Moment::zero(&self.timebase); - moment.sample.set(current_frames as f64); - moment.usec.set(current_usecs as f64); - *started = Some(moment); - } + match (self.transport.query_state()?, started.as_ref()) { + (TransportState::Rolling, None) => { + let moment = Moment::zero(&self.timebase); + moment.sample.set(current_frames as f64); + moment.usec.set(current_usecs as f64); + *started = Some(moment); }, - TransportState::Stopped => { - if started.is_some() { - *started = None; - } + (TransportState::Stopped, Some(_)) => { + *started = None; }, _ => {} }; - self.playhead.update_from_sample(match *started { - Some(ref instant) => current_frames as f64 - instant.sample.get(), - None => 0. - }); + + self.playhead.update_from_sample(started.as_ref() + .map(|started|current_frames as f64 - started.sample.get()) + .unwrap_or(0.)); + Ok(()) } } diff --git a/crates/tek/src/api/phrase.rs b/crates/tek/src/api/phrase.rs index 7125856a..05a88f71 100644 --- a/crates/tek/src/api/phrase.rs +++ b/crates/tek/src/api/phrase.rs @@ -159,7 +159,7 @@ impl Phrase { impl Default for Phrase { fn default () -> Self { - Self::new("(empty)", false, 0, None, Some(ItemColor::from(Color::Rgb(0, 0, 0)).into())) + Self::new("null", false, 0, None, Some(ItemColor::from(Color::Rgb(0, 0, 0)).into())) } } diff --git a/crates/tek/src/tui/app_sequencer.rs b/crates/tek/src/tui/app_sequencer.rs index effd20c5..3d4c4b48 100644 --- a/crates/tek/src/tui/app_sequencer.rs +++ b/crates/tek/src/tui/app_sequencer.rs @@ -107,38 +107,38 @@ impl Audio for SequencerTui { } } -render!(|self: SequencerTui|lay!([ - self.size, - Tui::shrink_y(1, col!([ +render!(|self: SequencerTui|lay!([self.size, Tui::split_up(1, + Tui::fill_xy(Tui::at_s(SequencerStatusBar::from(self))), + Tui::split_up(2, TransportView::from((self, if let SequencerFocus::Transport(_) = self.focus.inner() { true } else { false })), row!([ - Tui::fixed_x(20, Tui::split_up(2, PhraseSelector::edit_phrase( - &self.editor.phrase, - self.focused() == SequencerFocus::PhraseEditor, - self.entered() - ), col!([ - PhraseSelector::play_phrase( - &self.player, - self.focused() == SequencerFocus::PhrasePlay, - self.entered() - ), + Tui::fixed_x(20, Tui::split_up(4, col!([ PhraseSelector::next_phrase( &self.player, self.focused() == SequencerFocus::PhraseNext, self.entered() ), + PhraseSelector::play_phrase( + &self.player, + self.focused() == SequencerFocus::PhrasePlay, + self.entered() + ), + ]), col!([ + PhraseSelector::edit_phrase( + &self.editor.phrase, + self.focused() == SequencerFocus::PhraseEditor, + self.entered() + ), PhraseListView::from(self), - ]))), PhraseView::from(self) ]) - ])), - Tui::fill_xy(Tui::at_s(SequencerStatusBar::from(self))), -])); + ) +)])); impl HasClock for SequencerTui { fn clock (&self) -> &ClockModel { diff --git a/crates/tek/src/tui/phrase_list.rs b/crates/tek/src/tui/phrase_list.rs index 1b32f448..2849e52d 100644 --- a/crates/tek/src/tui/phrase_list.rs +++ b/crates/tek/src/tui/phrase_list.rs @@ -270,13 +270,13 @@ fn to_phrases_command (state: &PhraseListModel, input: &TuiInput) -> Option Cmd::Select( index.saturating_add(1) % state.phrases().len() ), - key!(Char(',')) => if index > 1 { + key!(Char('<')) => if index > 1 { state.set_phrase_index(state.phrase_index().saturating_sub(1)); Cmd::Phrase(Pool::Swap(index - 1, index)) } else { return None }, - key!(Char('.')) => if index < count.saturating_sub(1) { + key!(Char('>')) => if index < count.saturating_sub(1) { state.set_phrase_index(state.phrase_index() + 1); Cmd::Phrase(Pool::Swap(index + 1, index)) } else {