mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 12:16:42 +01:00
reenable global play/pause
This commit is contained in:
parent
86f37fb278
commit
340919830a
12 changed files with 208 additions and 165 deletions
|
|
@ -2,8 +2,8 @@ use crate::*;
|
|||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum ClockCommand {
|
||||
Play(Option<usize>),
|
||||
Pause(Option<usize>),
|
||||
Play(Option<u32>),
|
||||
Pause(Option<u32>),
|
||||
SeekUsec(f64),
|
||||
SeekSample(f64),
|
||||
SeekPulse(f64),
|
||||
|
|
@ -15,73 +15,35 @@ pub enum ClockCommand {
|
|||
impl<T: ClockApi> Command<T> for ClockCommand {
|
||||
fn execute (self, state: &mut T) -> Perhaps<Self> {
|
||||
use ClockCommand::*;
|
||||
Ok(Some(match self {
|
||||
Play(_start) => {
|
||||
todo!()
|
||||
},
|
||||
Pause(_start) => {
|
||||
todo!()
|
||||
},
|
||||
SeekUsec(usec) => {
|
||||
state.current().update_from_usec(usec);
|
||||
return Ok(None)
|
||||
},
|
||||
SeekSample(sample) => {
|
||||
state.current().update_from_sample(sample);
|
||||
return Ok(None)
|
||||
},
|
||||
SeekPulse(pulse) => {
|
||||
state.current().update_from_pulse(pulse);
|
||||
return Ok(None)
|
||||
},
|
||||
SetBpm(bpm) => SetBpm(state.timebase().bpm.set(bpm)),
|
||||
SetQuant(quant) => SetQuant(state.quant().set(quant)),
|
||||
SetSync(sync) => SetSync(state.sync().set(sync)),
|
||||
}))
|
||||
match self {
|
||||
Play(start) => state.play_from(start)?,
|
||||
Pause(pause) => state.pause_at(pause)?,
|
||||
SeekUsec(usec) => state.current().update_from_usec(usec),
|
||||
SeekSample(sample) => state.current().update_from_sample(sample),
|
||||
SeekPulse(pulse) => state.current().update_from_pulse(pulse),
|
||||
SetBpm(bpm) => return Ok(Some(SetBpm(state.timebase().bpm.set(bpm)))),
|
||||
SetQuant(quant) => return Ok(Some(SetQuant(state.quant().set(quant)))),
|
||||
SetSync(sync) => return Ok(Some(SetSync(state.sync().set(sync)))),
|
||||
};
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ClockApi: Send + Sync {
|
||||
/// Current moment in time
|
||||
fn current (&self) -> &Arc<Instant>;
|
||||
/// Temporal resolution in all units
|
||||
fn timebase (&self) -> &Arc<Timebase> {
|
||||
&self.current().timebase
|
||||
}
|
||||
fn sr (&self) -> &SampleRate {
|
||||
&self.timebase().sr
|
||||
}
|
||||
fn bpm (&self) -> &BeatsPerMinute {
|
||||
&self.timebase().bpm
|
||||
}
|
||||
fn ppq (&self) -> &PulsesPerQuaver {
|
||||
&self.timebase().ppq
|
||||
}
|
||||
|
||||
/// Note quantization factor
|
||||
fn quant (&self) -> &Arc<Quantize>;
|
||||
fn next_quant (&self) -> f64 {
|
||||
next_note_length(self.quant().get() as usize) as f64
|
||||
}
|
||||
fn prev_quant (&self) -> f64 {
|
||||
prev_note_length(self.quant().get() as usize) as f64
|
||||
}
|
||||
|
||||
/// Launch quantization factor
|
||||
fn sync (&self) -> &Arc<LaunchSync>;
|
||||
fn next_sync (&self) -> f64 {
|
||||
next_note_length(self.sync().get() as usize) as f64
|
||||
}
|
||||
fn prev_sync (&self) -> f64 {
|
||||
prev_note_length(self.sync().get() as usize) as f64
|
||||
}
|
||||
|
||||
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 }
|
||||
}
|
||||
|
||||
/// Current moment in time
|
||||
fn current (&self) -> &Arc<Instant>;
|
||||
/// Current temporal resolutions
|
||||
fn timebase (&self) -> &Arc<Timebase> { &self.current().timebase }
|
||||
/// Current sample rate
|
||||
fn sr (&self) -> &SampleRate { &self.timebase().sr }
|
||||
/// Current tempo
|
||||
fn bpm (&self) -> &BeatsPerMinute { &self.timebase().bpm }
|
||||
/// Current MIDI resolution
|
||||
fn ppq (&self) -> &PulsesPerQuaver { &self.timebase().ppq }
|
||||
/// Handle to JACK transport
|
||||
fn transport_handle (&self) -> &Arc<Transport>;
|
||||
/// Playback state
|
||||
|
|
@ -89,12 +51,39 @@ pub trait ClockApi: Send + Sync {
|
|||
/// Global sample and usec at which playback started
|
||||
fn transport_offset (&self) -> &Arc<RwLock<Option<(usize, usize)>>>;
|
||||
|
||||
fn is_stopped (&self) -> bool {
|
||||
*self.transport_state().read().unwrap() == Some(TransportState::Stopped)
|
||||
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 }
|
||||
}
|
||||
|
||||
fn play_from (&mut self, start: Option<u32>) -> Usually<()> {
|
||||
if let Some(start) = start {
|
||||
self.transport_handle().locate(start)?;
|
||||
}
|
||||
self.transport_handle().start()?;
|
||||
self.update_transport_state()
|
||||
}
|
||||
fn is_rolling (&self) -> bool {
|
||||
*self.transport_state().read().unwrap() == Some(TransportState::Rolling)
|
||||
}
|
||||
|
||||
fn pause_at (&mut self, pause: Option<u32>) -> Usually<()> {
|
||||
self.transport_handle().stop()?;
|
||||
if let Some(pause) = pause {
|
||||
self.transport_handle().locate(pause)?;
|
||||
}
|
||||
self.update_transport_state()
|
||||
}
|
||||
fn is_stopped (&self) -> bool {
|
||||
*self.transport_state().read().unwrap() == Some(TransportState::Stopped)
|
||||
}
|
||||
|
||||
fn update_transport_state (&self) -> Usually<()> {
|
||||
*self.transport_state().write().unwrap() = Some(self.transport_handle().query_state()?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn toggle_play (&self) -> Usually<()> {
|
||||
let playing = self.transport_state().read().unwrap().expect("1st sample has not been processed yet");
|
||||
let playing = match playing {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
pub use tek_core::*;
|
||||
pub(crate) use tek_core::*;
|
||||
pub(crate) use tek_core::midly::{*, live::LiveEvent, num::u7};
|
||||
pub(crate) use std::thread::JoinHandle;
|
||||
pub(crate) use std::fmt::{Debug, Formatter, Error};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue