mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-10 13:46:42 +01:00
122 lines
3.5 KiB
Rust
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,
|
|
}
|
|
}
|
|
}
|