mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
flip it puside down
This commit is contained in:
parent
5550631254
commit
761ec78282
4 changed files with 42 additions and 53 deletions
|
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue