mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
move ClockModel to tek_api
This commit is contained in:
parent
4fdc3911e4
commit
a26a1f2967
13 changed files with 214 additions and 222 deletions
|
|
@ -91,30 +91,6 @@ impl TuiTheme {
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_clock_api {
|
||||
($Struct:ident $(:: $field:ident)*) => {
|
||||
impl ClockApi for $Struct {
|
||||
fn quant (&self) -> &Arc<Quantize> {
|
||||
&self$(.$field)*.quant
|
||||
}
|
||||
fn sync (&self) -> &Arc<LaunchSync> {
|
||||
&self$(.$field)*.sync
|
||||
}
|
||||
fn current (&self) -> &Arc<Instant> {
|
||||
&self$(.$field)*.current
|
||||
}
|
||||
fn transport_handle (&self) -> &Arc<Transport> {
|
||||
&self$(.$field)*.transport
|
||||
}
|
||||
fn transport_state (&self) -> &Arc<RwLock<Option<TransportState>>> {
|
||||
&self$(.$field)*.playing
|
||||
}
|
||||
fn transport_offset (&self) -> &Arc<RwLock<Option<(usize, usize)>>> {
|
||||
&self$(.$field)*.started
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
macro_rules! impl_midi_player {
|
||||
($Struct:ident $(:: $field:ident)*) => {
|
||||
impl HasPhrase for $Struct {
|
||||
|
|
@ -184,12 +160,6 @@ macro_rules! impl_midi_player {
|
|||
}
|
||||
}
|
||||
|
||||
impl_clock_api!(TransportTui::clock);
|
||||
impl_clock_api!(SequencerTui::clock);
|
||||
impl_clock_api!(ArrangerTui::clock);
|
||||
impl_clock_api!(PhrasePlayerModel::clock);
|
||||
impl_clock_api!(ArrangerTrack::player::clock);
|
||||
|
||||
impl_midi_player!(SequencerTui::player);
|
||||
impl_midi_player!(ArrangerTrack::player);
|
||||
impl_midi_player!(PhrasePlayerModel);
|
||||
|
|
@ -197,18 +167,6 @@ impl_midi_player!(PhrasePlayerModel);
|
|||
use std::fmt::{Debug, Formatter, Error};
|
||||
type DebugResult = std::result::Result<(), Error>;
|
||||
|
||||
impl Debug for ClockModel {
|
||||
fn fmt (&self, f: &mut Formatter<'_>) -> DebugResult {
|
||||
f.debug_struct("editor")
|
||||
.field("playing", &self.playing)
|
||||
.field("started", &self.started)
|
||||
.field("current", &self.current)
|
||||
.field("quant", &self.quant)
|
||||
.field("sync", &self.sync)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for TransportTui {
|
||||
fn fmt (&self, f: &mut Formatter<'_>) -> DebugResult {
|
||||
f.debug_struct("Measure")
|
||||
|
|
|
|||
|
|
@ -54,6 +54,16 @@ impl TryFrom<&Arc<RwLock<JackClient>>> for ArrangerTui {
|
|||
}
|
||||
}
|
||||
|
||||
impl HasClock for ArrangerTui {
|
||||
fn clock (&self) -> &ClockModel {
|
||||
&self.clock
|
||||
}
|
||||
}
|
||||
impl HasClock for ArrangerTrack {
|
||||
fn clock (&self) -> &ClockModel {
|
||||
&self.player.clock()
|
||||
}
|
||||
}
|
||||
impl HasPhrases for ArrangerTui {
|
||||
fn phrases (&self) -> &Vec<Arc<RwLock<Phrase>>> {
|
||||
&self.phrases.phrases
|
||||
|
|
|
|||
|
|
@ -39,6 +39,12 @@ impl TryFrom<&Arc<RwLock<JackClient>>> for SequencerTui {
|
|||
}
|
||||
}
|
||||
|
||||
impl HasClock for SequencerTui {
|
||||
fn clock (&self) -> &ClockModel {
|
||||
&self.clock
|
||||
}
|
||||
}
|
||||
|
||||
impl HasPhrases for SequencerTui {
|
||||
fn phrases (&self) -> &Vec<Arc<RwLock<Phrase>>> {
|
||||
&self.phrases.phrases
|
||||
|
|
|
|||
|
|
@ -23,6 +23,12 @@ impl TryFrom<&Arc<RwLock<JackClient>>> for TransportTui {
|
|||
}
|
||||
}
|
||||
|
||||
impl HasClock for TransportTui {
|
||||
fn clock (&self) -> &ClockModel {
|
||||
&self.clock
|
||||
}
|
||||
}
|
||||
|
||||
/// Which item of the transport toolbar is focused
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum TransportFocus {
|
||||
|
|
|
|||
|
|
@ -89,8 +89,8 @@ impl ArrangerControl for ArrangerTui {
|
|||
track.enqueue_next(phrase.as_ref());
|
||||
}
|
||||
}
|
||||
if self.is_stopped() {
|
||||
self.play_from(Some(0))?;
|
||||
if self.clock().is_stopped() {
|
||||
self.clock().play_from(Some(0))?;
|
||||
}
|
||||
} else if let ArrangerSelection::Clip(t, s) = self.selected {
|
||||
let phrase = self.scenes()[s].clips[t].clone();
|
||||
|
|
|
|||
|
|
@ -52,11 +52,11 @@ pub fn to_sequencer_command (state: &SequencerTui, input: &TuiInput) -> Option<S
|
|||
Some(match input.event() {
|
||||
// Play/pause
|
||||
key!(Char(' ')) => Clock(
|
||||
if state.is_stopped() { Play(None) } else { Pause(None) }
|
||||
if state.clock().is_stopped() { Play(None) } else { Pause(None) }
|
||||
),
|
||||
// Play from start/rewind to start
|
||||
key!(Shift-Char(' ')) => Clock(
|
||||
if state.is_stopped() { Play(Some(0)) } else { Pause(Some(0)) }
|
||||
if state.clock().is_stopped() { Play(Some(0)) } else { Pause(Some(0)) }
|
||||
),
|
||||
// Edit phrase
|
||||
key!(Char('e')) => match state.focused() {
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ impl<T: TransportControl> Command<T> for TransportCommand {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait TransportControl: ClockApi + FocusGrid + HasEnter {
|
||||
pub trait TransportControl: HasClock + FocusGrid + HasEnter {
|
||||
fn transport_focused (&self) -> Option<TransportFocus>;
|
||||
}
|
||||
|
||||
|
|
@ -73,36 +73,36 @@ where
|
|||
Some(match input.event() {
|
||||
key!(Left) => Focus(FocusCommand::Prev),
|
||||
key!(Right) => Focus(FocusCommand::Next),
|
||||
key!(Char(' ')) => Clock(if state.is_stopped() {
|
||||
key!(Char(' ')) => Clock(if state.clock().is_stopped() {
|
||||
ClockCommand::Play(None)
|
||||
} else {
|
||||
ClockCommand::Pause(None)
|
||||
}),
|
||||
key!(Shift-Char(' ')) => Clock(if state.is_stopped() {
|
||||
key!(Shift-Char(' ')) => Clock(if state.clock().is_stopped() {
|
||||
ClockCommand::Play(Some(0))
|
||||
} else {
|
||||
ClockCommand::Pause(Some(0))
|
||||
}),
|
||||
_ => match state.transport_focused().unwrap() {
|
||||
TransportFocus::Bpm => match input.event() {
|
||||
key!(Char(',')) => Clock(SetBpm(state.bpm().get() - 1.0)),
|
||||
key!(Char('.')) => Clock(SetBpm(state.bpm().get() + 1.0)),
|
||||
key!(Char('<')) => Clock(SetBpm(state.bpm().get() - 0.001)),
|
||||
key!(Char('>')) => Clock(SetBpm(state.bpm().get() + 0.001)),
|
||||
key!(Char(',')) => Clock(SetBpm(state.clock().bpm().get() - 1.0)),
|
||||
key!(Char('.')) => Clock(SetBpm(state.clock().bpm().get() + 1.0)),
|
||||
key!(Char('<')) => Clock(SetBpm(state.clock().bpm().get() - 0.001)),
|
||||
key!(Char('>')) => Clock(SetBpm(state.clock().bpm().get() + 0.001)),
|
||||
_ => return None,
|
||||
},
|
||||
TransportFocus::Quant => match input.event() {
|
||||
key!(Char(',')) => Clock(SetQuant(state.quant().prev())),
|
||||
key!(Char('.')) => Clock(SetQuant(state.quant().next())),
|
||||
key!(Char('<')) => Clock(SetQuant(state.quant().prev())),
|
||||
key!(Char('>')) => Clock(SetQuant(state.quant().next())),
|
||||
key!(Char(',')) => Clock(SetQuant(state.clock().quant.prev())),
|
||||
key!(Char('.')) => Clock(SetQuant(state.clock().quant.next())),
|
||||
key!(Char('<')) => Clock(SetQuant(state.clock().quant.prev())),
|
||||
key!(Char('>')) => Clock(SetQuant(state.clock().quant.next())),
|
||||
_ => return None,
|
||||
},
|
||||
TransportFocus::Sync => match input.event() {
|
||||
key!(Char(',')) => Clock(SetSync(state.sync().prev())),
|
||||
key!(Char('.')) => Clock(SetSync(state.sync().next())),
|
||||
key!(Char('<')) => Clock(SetSync(state.sync().prev())),
|
||||
key!(Char('>')) => Clock(SetSync(state.sync().next())),
|
||||
key!(Char(',')) => Clock(SetSync(state.clock().sync.prev())),
|
||||
key!(Char('.')) => Clock(SetSync(state.clock().sync.next())),
|
||||
key!(Char('<')) => Clock(SetSync(state.clock().sync.prev())),
|
||||
key!(Char('>')) => Clock(SetSync(state.clock().sync.next())),
|
||||
_ => return None,
|
||||
},
|
||||
TransportFocus::Clock => match input.event() {
|
||||
|
|
@ -114,14 +114,14 @@ where
|
|||
},
|
||||
TransportFocus::PlayPause => match input.event() {
|
||||
key!(Enter) => Clock(
|
||||
if state.is_stopped() {
|
||||
if state.clock().is_stopped() {
|
||||
ClockCommand::Play(None)
|
||||
} else {
|
||||
ClockCommand::Pause(None)
|
||||
}
|
||||
),
|
||||
key!(Shift-Enter) => Clock(
|
||||
if state.is_stopped() {
|
||||
if state.clock().is_stopped() {
|
||||
ClockCommand::Play(Some(0))
|
||||
} else {
|
||||
ClockCommand::Pause(Some(0))
|
||||
|
|
|
|||
|
|
@ -1,33 +1 @@
|
|||
use crate::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ClockModel {
|
||||
/// JACK transport handle.
|
||||
pub(crate) transport: Arc<Transport>,
|
||||
/// Playback state
|
||||
pub(crate) playing: Arc<RwLock<Option<TransportState>>>,
|
||||
/// Global sample and usec at which playback started
|
||||
pub(crate) started: Arc<RwLock<Option<(usize, usize)>>>,
|
||||
/// Current moment in time
|
||||
pub(crate) current: Arc<Instant>,
|
||||
/// Note quantization factor
|
||||
pub(crate) quant: Arc<Quantize>,
|
||||
/// Launch quantization factor
|
||||
pub(crate) sync: Arc<LaunchSync>,
|
||||
/// TODO: Enable metronome?
|
||||
pub(crate) metronome: bool,
|
||||
}
|
||||
|
||||
impl From<&Arc<Transport>> for ClockModel {
|
||||
fn from (transport: &Arc<Transport>) -> Self {
|
||||
Self {
|
||||
playing: RwLock::new(None).into(),
|
||||
started: RwLock::new(None).into(),
|
||||
current: Instant::default().into(),
|
||||
quant: Arc::new(24.into()),
|
||||
sync: Arc::new(384.into()),
|
||||
transport: transport.clone(),
|
||||
metronome: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,3 +46,9 @@ impl From<&ClockModel> for PhrasePlayerModel {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HasClock for PhrasePlayerModel {
|
||||
fn clock (&self) -> &ClockModel {
|
||||
&self.clock
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,8 +91,8 @@ pub fn arranger_content_vertical (
|
|||
view: &ArrangerTui,
|
||||
factor: usize
|
||||
) -> impl Widget<Engine = Tui> + use<'_> {
|
||||
let timebase = view.timebase();
|
||||
let current = view.current();
|
||||
let timebase = view.clock().timebase();
|
||||
let current = &view.clock().current;
|
||||
let tracks = view.tracks();
|
||||
let scenes = view.scenes();
|
||||
let cols = track_widths(tracks);
|
||||
|
|
|
|||
|
|
@ -54,22 +54,18 @@ impl Content for TransportView {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T> From<&'a T> for TransportView
|
||||
where
|
||||
T: ClockApi,
|
||||
Option<TransportFocus>: From<&'a T>
|
||||
{
|
||||
impl<'a, T: HasClock> From<&'a T> for TransportView where Option<TransportFocus>: From<&'a T> {
|
||||
fn from (state: &'a T) -> Self {
|
||||
let selected = state.into();
|
||||
Self {
|
||||
selected,
|
||||
focused: selected.is_some(),
|
||||
state: state.transport_state().read().unwrap().clone(),
|
||||
bpm: state.bpm().get(),
|
||||
sync: state.sync().get(),
|
||||
quant: state.quant().get(),
|
||||
beat: state.current().format_beat(),
|
||||
msu: state.current().usec.format_msu(),
|
||||
state: state.clock().playing.read().unwrap().clone(),
|
||||
bpm: state.clock().bpm().get(),
|
||||
sync: state.clock().sync.get(),
|
||||
quant: state.clock().quant.get(),
|
||||
beat: state.clock().current.format_beat(),
|
||||
msu: state.clock().current.usec.format_msu(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue