mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-10 13:46:42 +01:00
wip: scaffold PhrasePool, PhraseEditor
This commit is contained in:
parent
ea3edec96b
commit
d821787fcf
8 changed files with 1549 additions and 1536 deletions
162
crates/tek_sequencer/src/transport.rs
Normal file
162
crates/tek_sequencer/src/transport.rs
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
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>,
|
||||
/// Quantization factor
|
||||
/// Global frame and usec at which playback started
|
||||
pub started: Option<(usize, usize)>,
|
||||
pub focused: bool,
|
||||
pub focus: TransportToolbarFocus,
|
||||
pub playing: Option<TransportState>,
|
||||
pub bpm: f64,
|
||||
pub quant: usize,
|
||||
pub sync: usize,
|
||||
pub frame: usize,
|
||||
pub pulse: usize,
|
||||
pub ppq: usize,
|
||||
pub usecs: usize,
|
||||
}
|
||||
|
||||
impl<E: Engine> TransportToolbar<E> {
|
||||
pub fn standalone () -> Usually<Arc<RwLock<Self>>> where Self: 'static {
|
||||
let jack = JackClient::Inactive(
|
||||
Client::new("tek_transport", ClientOptions::NO_START_SERVER)?.0
|
||||
);
|
||||
let mut transport = Self::new(Some(jack.transport()));
|
||||
transport.focused = true;
|
||||
let transport = Arc::new(RwLock::new(transport));
|
||||
transport.write().unwrap().jack = Some(
|
||||
jack.activate(
|
||||
&transport.clone(),
|
||||
|state: &Arc<RwLock<TransportToolbar<E>>>, client, scope| {
|
||||
state.write().unwrap().process(client, scope)
|
||||
}
|
||||
)?
|
||||
);
|
||||
Ok(transport)
|
||||
}
|
||||
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 update (&mut self, scope: &ProcessScope) -> (bool, usize, usize, usize, usize, f64) {
|
||||
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 = self.transport.as_ref().unwrap().query().unwrap();
|
||||
self.frame = transport.pos.frame() as usize;
|
||||
let mut reset = false;
|
||||
if self.playing != Some(transport.state) {
|
||||
match transport.state {
|
||||
TransportState::Rolling => {
|
||||
self.started = Some((current_frames as usize, current_usecs as usize));
|
||||
},
|
||||
TransportState::Stopped => {
|
||||
self.started = None;
|
||||
reset = true;
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
self.playing = Some(transport.state);
|
||||
(
|
||||
reset,
|
||||
current_frames as usize,
|
||||
chunk_size as usize,
|
||||
current_usecs as usize,
|
||||
next_usecs as usize,
|
||||
period_usecs as f64
|
||||
)
|
||||
}
|
||||
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<E: Engine> Audio for TransportToolbar<E> {
|
||||
fn process (&mut self, _: &Client, scope: &ProcessScope) -> Control {
|
||||
self.update(&scope);
|
||||
Control::Continue
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum TransportToolbarFocus { PlayPause, Bpm, Quant, Sync, Clock, }
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue