tek/crates/tek_sequencer/src/transport.rs

122 lines
3.5 KiB
Rust

use crate::*;
/// Stores and displays time-related state.
pub struct TransportToolbar<E: Engine> {
_engine: PhantomData<E>,
/// Enable metronome?
pub metronome: bool,
/// Current sample rate, tempo, and PPQ.
pub timebase: Arc<Timebase>,
/// JACK client handle (needs to not be dropped for standalone mode to work).
pub jack: Option<JackClient>,
/// JACK transport handle.
pub transport: Option<Transport>,
/// Global frame and usec at which playback started
pub started: Option<(usize, usize)>,
/// Whether the toolbar is focused
pub focused: bool,
/// Which part of the toolbar is focused
pub focus: TransportToolbarFocus,
/// Playback state
pub playing: Option<TransportState>,
/// Current tempo
pub bpm: f64,
/// Quantization factor
pub quant: usize,
/// Launch sync
pub sync: usize,
/// Current time in frames
pub frame: usize,
/// Current time in pulses
pub pulse: usize,
/// Current time in microseconds
pub usecs: usize,
/// Pulses per quarter note
pub ppq: usize,
}
#[derive(Clone, Copy, PartialEq)]
pub enum TransportToolbarFocus {
Bpm,
Sync,
PlayPause,
Clock,
Quant,
}
impl<E: Engine> TransportToolbar<E> {
pub fn new (transport: Option<Transport>) -> Self {
let timebase = Arc::new(Timebase::default());
Self {
_engine: Default::default(),
focused: false,
focus: TransportToolbarFocus::PlayPause,
playing: Some(TransportState::Stopped),
bpm: timebase.bpm(),
quant: 24,
sync: timebase.ppq() as usize * 4,
frame: 0,
pulse: 0,
ppq: 0,
usecs: 0,
metronome: false,
started: None,
jack: None,
transport,
timebase,
}
}
pub fn toggle_play (&mut self) -> Usually<()> {
let transport = self.transport.as_ref().unwrap();
self.playing = match self.playing.expect("1st frame has not been processed yet") {
TransportState::Stopped => {
transport.start()?;
Some(TransportState::Starting)
},
_ => {
transport.stop()?;
transport.locate(0)?;
Some(TransportState::Stopped)
},
};
Ok(())
}
pub fn bpm (&self) -> usize {
self.timebase.bpm() as usize
}
pub fn ppq (&self) -> usize {
self.timebase.ppq() as usize
}
pub fn pulse (&self) -> usize {
self.timebase.frame_to_pulse(self.frame as f64) as usize
}
pub fn usecs (&self) -> usize {
self.timebase.frame_to_usec(self.frame as f64) as usize
}
pub fn quant (&self) -> usize {
self.quant
}
pub fn sync (&self) -> usize {
self.sync
}
}
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,
}
}
}