mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 12:16:42 +01:00
105 lines
3.9 KiB
Rust
105 lines
3.9 KiB
Rust
use crate::*;
|
|
/// A timer with starting point, current time, and quantization
|
|
#[derive(Debug, Default)] pub struct TransportTime {
|
|
/// Playback state
|
|
pub playing: RwLock<Option<TransportState>>,
|
|
/// Global sample and usec at which playback started
|
|
pub started: RwLock<Option<(usize, usize)>>,
|
|
/// Current moment in time
|
|
pub current: Instant,
|
|
/// Note quantization factor
|
|
pub quant: Quantize,
|
|
/// Launch quantization factor
|
|
pub sync: LaunchSync,
|
|
}
|
|
impl TransportTime {
|
|
#[inline] pub fn timebase (&self) -> &Arc<Timebase> { &self.current.timebase }
|
|
#[inline] pub fn pulse (&self) -> f64 { self.current.pulse.get() }
|
|
#[inline] pub fn quant (&self) -> f64 { self.quant.get() }
|
|
#[inline] pub fn sync (&self) -> f64 { self.sync.get() }
|
|
#[inline] pub fn next_launch_pulse (&self) -> usize {
|
|
let sync = self.sync.get() as usize;
|
|
let pulse = self.current.pulse.get() as usize;
|
|
if pulse % sync == 0 { pulse } else { (pulse / sync + 1) * sync }
|
|
}
|
|
}
|
|
/// Stores and displays time-related state.
|
|
pub struct TransportToolbar<E: Engine> {
|
|
_engine: PhantomData<E>,
|
|
/// JACK client handle (needs to not be dropped for standalone mode to work).
|
|
pub jack: Arc<RwLock<JackClient>>,
|
|
/// JACK transport handle.
|
|
pub transport: Transport,
|
|
/// Current sample rate, tempo, and PPQ.
|
|
pub clock: Arc<TransportTime>,
|
|
/// Enable metronome?
|
|
pub metronome: bool,
|
|
/// Whether the toolbar is focused
|
|
pub focused: bool,
|
|
/// Which part of the toolbar is focused
|
|
pub focus: TransportToolbarFocus,
|
|
}
|
|
/// Which item of the transport toolbar is focused
|
|
#[derive(Clone, Copy, PartialEq)]
|
|
pub enum TransportToolbarFocus { Bpm, Sync, PlayPause, Clock, Quant, }
|
|
impl<E: Engine> TransportToolbar<E> {
|
|
pub fn new (jack: &Arc<RwLock<JackClient>>, clock: Option<&Arc<TransportTime>>) -> Self {
|
|
Self {
|
|
_engine: Default::default(),
|
|
focused: false,
|
|
focus: TransportToolbarFocus::PlayPause,
|
|
metronome: false,
|
|
transport: jack.read().unwrap().transport(),
|
|
jack: jack.clone(),
|
|
clock: match clock {
|
|
Some(clock) => clock.clone(),
|
|
None => {
|
|
let timebase = Arc::new(Timebase::default());
|
|
Arc::new(TransportTime {
|
|
playing: Some(TransportState::Stopped).into(),
|
|
quant: 24.into(),
|
|
sync: (timebase.ppq.get() * 4.).into(),
|
|
current: Instant::default(),
|
|
started: None.into(),
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
pub fn toggle_play (&mut self) -> Usually<()> {
|
|
let playing = self.clock.playing.read().unwrap().expect("1st sample has not been processed yet");
|
|
let playing = match playing {
|
|
TransportState::Stopped => {
|
|
self.transport.start()?;
|
|
Some(TransportState::Starting)
|
|
},
|
|
_ => {
|
|
self.transport.stop()?;
|
|
self.transport.locate(0)?;
|
|
Some(TransportState::Stopped)
|
|
},
|
|
};
|
|
*self.clock.playing.write().unwrap() = playing;
|
|
Ok(())
|
|
}
|
|
}
|
|
impl TransportToolbarFocus {
|
|
pub fn next (&mut self) {
|
|
*self = match self {
|
|
Self::PlayPause => Self::Bpm,
|
|
Self::Bpm => Self::Quant,
|
|
Self::Quant => Self::Sync,
|
|
Self::Sync => Self::Clock,
|
|
Self::Clock => Self::PlayPause,
|
|
}
|
|
}
|
|
pub fn prev (&mut self) {
|
|
*self = match self {
|
|
Self::PlayPause => Self::Clock,
|
|
Self::Bpm => Self::PlayPause,
|
|
Self::Quant => Self::Bpm,
|
|
Self::Sync => Self::Quant,
|
|
Self::Clock => Self::Sync,
|
|
}
|
|
}
|
|
}
|