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, } } }