use crate::*;
/// A timer with starting point, current time, and quantization
#[derive(Debug, Default)] pub struct TransportTime {
/// Playback state
pub playing: RwLock>,
/// Global sample and usec at which playback started
pub started: RwLock >,
/// 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 { &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 {
_engine: PhantomData,
/// JACK client handle (needs to not be dropped for standalone mode to work).
pub jack: Arc>,
/// JACK transport handle.
pub transport: Transport,
/// Current sample rate, tempo, and PPQ.
pub clock: Arc,
/// 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 TransportToolbar {
pub fn new (jack: &Arc>, clock: Option<&Arc>) -> 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,
}
}
}