wip(p64,e4)

This commit is contained in:
🪞👃🪞 2024-11-21 15:44:32 +01:00
parent f49823b7a7
commit fffd830e15
11 changed files with 194 additions and 217 deletions

View file

@ -2,6 +2,11 @@ use crate::*;
#[derive(Clone, Debug, PartialEq)]
pub enum ClockCommand {
Play(Option<usize>),
Pause(Option<usize>),
SeekUsec(f64),
SeekSample(f64),
SeekPulse(f64),
SetBpm(f64),
SetQuant(f64),
SetSync(f64),
@ -11,6 +16,24 @@ 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)),
@ -19,13 +42,12 @@ impl<T: ClockApi> Command<T> for ClockCommand {
}
pub trait ClockApi: Send + Sync {
/// Current moment in time
fn current (&self) -> &Arc<Instant>;
/// Temporal resolution in all units
fn timebase (&self) -> &Arc<Timebase>;
/// Note quantization factor
fn quant (&self) -> &Quantize;
/// Launch quantization factor
fn sync (&self) -> &LaunchSync;
fn timebase (&self) -> &Arc<Timebase> {
&self.current().timebase
}
fn sr (&self) -> &SampleRate {
&self.timebase().sr
}
@ -36,16 +58,93 @@ pub trait ClockApi: Send + Sync {
&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 }
}
/// Handle to JACK transport
fn transport_handle (&self) -> &Arc<Transport>;
/// Playback state
fn transport_state (&self) -> &Arc<RwLock<Option<TransportState>>>;
/// 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 is_rolling (&self) -> bool {
*self.transport_state().read().unwrap() == Some(TransportState::Rolling)
}
fn toggle_play (&self) -> Usually<()> {
let playing = self.transport_state().read().unwrap().expect("1st sample has not been processed yet");
let playing = match playing {
TransportState::Stopped => {
self.transport_handle().start()?;
Some(TransportState::Starting)
},
_ => {
self.transport_handle().stop()?;
self.transport_handle().locate(0)?;
Some(TransportState::Stopped)
},
};
*self.transport_state().write().unwrap() = playing;
Ok(())
}
}
/// Hosts the JACK callback for updating the temporal pointer and playback status.
pub struct ClockAudio<'a, T: ClockApi>(pub &'a mut T);
impl<'a, T: ClockApi> Audio for ClockAudio<'a, T> {
#[inline] fn process (&mut self, _: &Client, scope: &ProcessScope) -> Control {
let state = &mut self.0;
let times = scope.cycle_times().unwrap();
let CycleTimes { current_frames, current_usecs, next_usecs: _, period_usecs: _ } = times;
let _chunk_size = scope.n_frames() as usize;
let transport = state.transport_handle().query().unwrap();
state.current().sample.set(transport.pos.frame() as f64);
let mut playing = state.transport_state().write().unwrap();
let mut started = state.transport_offset().write().unwrap();
if *playing != Some(transport.state) {
match transport.state {
TransportState::Rolling => {
*started = Some((current_frames as usize, current_usecs as usize))
},
TransportState::Stopped => {
*started = None
},
_ => {}
}
};
*playing = Some(transport.state);
if *playing == Some(TransportState::Stopped) {
*started = None;
}
state.current().update_from_usec(match *started {
Some((_, usecs)) => current_usecs as f64 - usecs as f64,
None => 0.
});
Control::Continue
}
}