From 24bc33d3d0c9455883db7aa0a5ce42e51fea8512 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Sat, 26 Apr 2025 12:51:14 +0300 Subject: [PATCH] time: clock: add next_launch_instant, modularize --- crates/time/src/clock.rs | 18 +++++ crates/time/src/clock/clock_api.rs | 55 ++++++++++++++++ .../{time_clock.rs => clock/clock_model.rs} | 66 ++----------------- crates/time/src/lib.rs | 3 +- 4 files changed, 81 insertions(+), 61 deletions(-) create mode 100644 crates/time/src/clock.rs create mode 100644 crates/time/src/clock/clock_api.rs rename crates/time/src/{time_clock.rs => clock/clock_model.rs} (71%) diff --git a/crates/time/src/clock.rs b/crates/time/src/clock.rs new file mode 100644 index 00000000..4a7770b3 --- /dev/null +++ b/crates/time/src/clock.rs @@ -0,0 +1,18 @@ +use crate::*; + +mod clock_api; pub use self::clock_api::*; +mod clock_model; pub use self::clock_model::*; + +pub trait HasClock: Send + Sync { + fn clock (&self) -> &Clock; + fn clock_mut (&mut self) -> &mut Clock; +} + +#[macro_export] macro_rules! has_clock { + (|$self:ident:$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)?|$cb:expr) => { + impl $(<$($L),*$($T $(: $U)?),*>)? HasClock for $Struct $(<$($L),*$($T),*>)? { + fn clock (&$self) -> &Clock { &$cb } + fn clock_mut (&mut $self) -> &mut Clock { &mut $cb } + } + } +} diff --git a/crates/time/src/clock/clock_api.rs b/crates/time/src/clock/clock_api.rs new file mode 100644 index 00000000..a52fbccf --- /dev/null +++ b/crates/time/src/clock/clock_api.rs @@ -0,0 +1,55 @@ +use crate::*; + +#[derive(Clone, Debug, PartialEq)] +pub enum ClockCommand { + Play(Option), + Pause(Option), + SeekUsec(f64), + SeekSample(f64), + SeekPulse(f64), + SetBpm(f64), + SetQuant(f64), + SetSync(f64), +} + +provide_num!(u32: |self: Clock| {}); + +provide!(f64: |self: Clock| {}); + +atom_command!(ClockCommand: |state: Clock| { + ("play" [] Some(Self::Play(None))) + ("play" [t: u32] Some(Self::Play(t))) + ("pause" [] Some(Self::Pause(None))) + ("pause" [t: u32] Some(Self::Pause(t))) + ("toggle" [] Some(if state.is_rolling() { Self::Pause(None) } else { Self::Play(None) })) + ("toggle" [t: u32] Some(if state.is_rolling() { Self::Pause(t) } else { Self::Play(t) })) + ("seek/usec" [t: f64] Some(Self::SeekUsec(t.expect("no usec")))) + ("seek/pulse" [t: f64] Some(Self::SeekPulse(t.expect("no pulse")))) + ("seek/sample" [t: f64] Some(Self::SeekSample(t.expect("no sample")))) + ("set/bpm" [t: f64] Some(Self::SetBpm(t.expect("no bpm")))) + ("set/sync" [t: f64] Some(Self::SetSync(t.expect("no sync")))) + ("set/quant" [t: f64] Some(Self::SetQuant(t.expect("no quant")))) +}); + +impl Command for ClockCommand { + fn execute (self, state: &mut T) -> Perhaps { + self.execute(state.clock_mut()) + } +} + +impl Command for ClockCommand { + fn execute (self, state: &mut Clock) -> Perhaps { + use ClockCommand::*; + match self { + Play(start) => state.play_from(start)?, + Pause(pause) => state.pause_at(pause)?, + SeekUsec(usec) => state.playhead.update_from_usec(usec), + SeekSample(sample) => state.playhead.update_from_sample(sample), + SeekPulse(pulse) => state.playhead.update_from_pulse(pulse), + SetBpm(bpm) => return Ok(Some(SetBpm(state.timebase().bpm.set(bpm)))), + SetQuant(quant) => return Ok(Some(SetQuant(state.quant.set(quant)))), + SetSync(sync) => return Ok(Some(SetSync(state.sync.set(sync)))), + }; + Ok(None) + } +} diff --git a/crates/time/src/time_clock.rs b/crates/time/src/clock/clock_model.rs similarity index 71% rename from crates/time/src/time_clock.rs rename to crates/time/src/clock/clock_model.rs index ab33fe34..21eb0fe3 100644 --- a/crates/time/src/time_clock.rs +++ b/crates/time/src/clock/clock_model.rs @@ -1,64 +1,4 @@ use crate::*; -pub trait HasClock: Send + Sync { - fn clock (&self) -> &Clock; - fn clock_mut (&mut self) -> &mut Clock; -} -#[macro_export] macro_rules! has_clock { - (|$self:ident:$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)?|$cb:expr) => { - impl $(<$($L),*$($T $(: $U)?),*>)? HasClock for $Struct $(<$($L),*$($T),*>)? { - fn clock (&$self) -> &Clock { &$cb } - fn clock_mut (&mut $self) -> &mut Clock { &mut $cb } - } - } -} -#[derive(Clone, Debug, PartialEq)] -pub enum ClockCommand { - Play(Option), - Pause(Option), - SeekUsec(f64), - SeekSample(f64), - SeekPulse(f64), - SetBpm(f64), - SetQuant(f64), - SetSync(f64), -} -provide_num!(u32: |self: Clock| {}); -provide!(f64: |self: Clock| {}); -atom_command!(ClockCommand: |state: Clock| { - ("play" [] Some(Self::Play(None))) - ("play" [t: u32] Some(Self::Play(t))) - ("pause" [] Some(Self::Pause(None))) - ("pause" [t: u32] Some(Self::Pause(t))) - ("toggle" [] Some(if state.is_rolling() { Self::Pause(None) } else { Self::Play(None) })) - ("toggle" [t: u32] Some(if state.is_rolling() { Self::Pause(t) } else { Self::Play(t) })) - ("seek/usec" [t: f64] Some(Self::SeekUsec(t.expect("no usec")))) - ("seek/pulse" [t: f64] Some(Self::SeekPulse(t.expect("no pulse")))) - ("seek/sample" [t: f64] Some(Self::SeekSample(t.expect("no sample")))) - ("set/bpm" [t: f64] Some(Self::SetBpm(t.expect("no bpm")))) - ("set/sync" [t: f64] Some(Self::SetSync(t.expect("no sync")))) - ("set/quant" [t: f64] Some(Self::SetQuant(t.expect("no quant")))) -}); -impl Command for ClockCommand { - fn execute (self, state: &mut T) -> Perhaps { - self.execute(state.clock_mut()) - } -} -impl Command for ClockCommand { - fn execute (self, state: &mut Clock) -> Perhaps { - use ClockCommand::*; - match self { - Play(start) => state.play_from(start)?, - Pause(pause) => state.pause_at(pause)?, - SeekUsec(usec) => state.playhead.update_from_usec(usec), - SeekSample(sample) => state.playhead.update_from_sample(sample), - SeekPulse(pulse) => state.playhead.update_from_pulse(pulse), - SetBpm(bpm) => return Ok(Some(SetBpm(state.timebase().bpm.set(bpm)))), - SetQuant(quant) => return Ok(Some(SetQuant(state.quant.set(quant)))), - SetSync(sync) => return Ok(Some(SetSync(state.sync.set(sync)))), - }; - Ok(None) - } -} #[derive(Clone, Default)] pub struct Clock { @@ -87,6 +27,7 @@ pub struct Clock { /// For emitting a metronome pub click_out: Arc>>, } + impl std::fmt::Debug for Clock { fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { f.debug_struct("Clock") @@ -100,6 +41,7 @@ impl std::fmt::Debug for Clock { .finish() } } + impl Clock { pub fn new (jack: &Jack, bpm: Option) -> Usually { let (chunk, transport) = jack.with_client(|c|(c.buffer_size(), c.transport())); @@ -231,4 +173,8 @@ impl Clock { ticks_per_beat: ppq as f64 } } + + pub fn next_launch_instant (&self) -> Moment { + Moment::from_pulse(self.timebase(), self.next_launch_pulse() as f64) + } } diff --git a/crates/time/src/lib.rs b/crates/time/src/lib.rs index e2214ed2..2ad81860 100644 --- a/crates/time/src/lib.rs +++ b/crates/time/src/lib.rs @@ -1,4 +1,5 @@ -mod time_clock; pub use self::time_clock::*; +mod clock; pub use self::clock::*; + mod time_moment; pub use self::time_moment::*; mod time_note; pub use self::time_note::*; mod time_perf; pub use self::time_perf::*;