flip it puside down

This commit is contained in:
🪞👃🪞 2024-12-10 20:16:06 +01:00
parent 5550631254
commit 761ec78282
4 changed files with 42 additions and 53 deletions

View file

@ -33,23 +33,6 @@ impl<T: HasClock> Command<T> for ClockCommand {
}
}
#[derive(Clone)]
pub struct Timeline {
pub timebase: Arc<Timebase>,
pub started: Arc<RwLock<Option<Moment>>>,
pub loopback: Arc<RwLock<Option<Moment>>>,
}
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<Moment>,
/// Global sample and usec at which playback started
pub started: Arc<RwLock<Option<Moment>>>,
/// Playback offset (when playing not from start)
pub offset: Arc<Moment>,
/// Current playhead position
pub playhead: Arc<Moment>,
/// Note quantization factor
@ -83,6 +68,7 @@ impl From<&Arc<RwLock<JackClient>>> 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() {
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() {
(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(())
}
}

View file

@ -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()))
}
}

View file

@ -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 {

View file

@ -270,13 +270,13 @@ fn to_phrases_command (state: &PhraseListModel, input: &TuiInput) -> Option<Phra
key!(Down) => 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 {