extract transport

This commit is contained in:
🪞👃🪞 2024-07-12 14:23:43 +03:00
parent 449615eea8
commit 5a9ec0a63d
12 changed files with 178 additions and 182 deletions

View file

@ -5,6 +5,7 @@ pub mod plugin;
pub mod sampler;
pub mod scene;
pub mod track;
pub mod transport;
pub use self::phrase::{Phrase, PhraseData};
pub use self::scene::Scene;
@ -12,12 +13,11 @@ pub use self::track::Track;
pub use self::sampler::{Sampler, Sample, read_sample_data};
pub use self::mixer::Mixer;
pub use self::plugin::{Plugin, PluginKind, lv2::LV2Plugin};
pub use self::transport::TransportToolbar;
use crate::{core::*, view::*};
pub struct App {
/// Paths to user directories
pub xdg: Option<Arc<XdgApp>>,
/// Main JACK client.
pub jack: Option<JackClient>,
/// Map of external MIDI outs in the jack graph
@ -25,18 +25,6 @@ pub struct App {
pub midi_in: Option<Arc<Port<MidiIn>>>,
/// Names of ports to connect to main MIDI IN.
pub midi_ins: Vec<String>,
/// Main audio outputs.
pub audio_outs: Vec<Arc<Port<Unowned>>>,
/// JACK transport handle.
pub transport: Option<Transport>,
/// Current transport state
pub playing: Option<TransportState>,
/// Current position according to transport
pub playhead: usize,
/// Position of T0 for this playback within global timeline
pub play_started: Option<(usize, usize)>,
/// Current sample rate and tempo.
pub timebase: Arc<Timebase>,
/// Display mode of arranger section
pub arranger_mode: bool,
/// Display mode of chain section
@ -49,10 +37,8 @@ pub struct App {
pub modal: Option<Box<dyn Component>>,
/// Currently focused section
pub section: AppSection,
/// Whether the section is focused
/// Whether the current focus section has input priority
pub entered: bool,
/// Current frame
pub metronome: bool,
/// Display position of cursor within note range
pub note_cursor: usize,
/// Range of notes to display
@ -67,12 +53,16 @@ pub struct App {
pub track_cursor: usize,
/// Collection of tracks
pub tracks: Vec<Track>,
/// Paths to user directories
xdg: Option<Arc<XdgApp>>,
/// Main audio outputs.
audio_outs: Vec<Arc<Port<Unowned>>>,
/// Tick enable?
metronome: bool,
/// Number of frames requested by process callback
pub chunk_size: usize,
/// Quantization factor
pub quant: usize,
/// Init callbacks called once after root JACK client has activated.
pub callbacks: Vec<Box<dyn (FnOnce(Arc<RwLock<Self>>)->Usually<()>) + Send + Sync>>
chunk_size: usize,
pub transport: TransportToolbar,
}
impl App {
@ -80,11 +70,10 @@ impl App {
let xdg = Arc::new(microxdg::XdgApp::new("tek")?);
let first_run = crate::config::AppPaths::new(&xdg)?.should_create();
let jack = JackClient::Inactive(Client::new("tek", ClientOptions::NO_START_SERVER)?.0);
let transport = jack.transport();
Ok(Self {
transport: TransportToolbar::new(Some(jack.transport())),
arranger_mode: false,
audio_outs: vec![],
callbacks: vec![],
chain_mode: false,
chunk_size: 0,
entered: true,
@ -95,35 +84,30 @@ impl App {
modal: first_run.then(||crate::config::SetupModal(Some(xdg.clone())).boxed()),
note_cursor: 0,
note_start: 2,
play_started: None,
playhead: 0,
playing: None,
quant: 24,
scene_cursor: 1,
scenes: vec![],
section: AppSection::default(),
seq_mode: false,
seq_buf: BufferedSequencerView::new(96, 16384),
time_cursor: 0,
timebase: Arc::new(Timebase::default()),
track_cursor: 1,
tracks: vec![],
transport: Some(transport),
xdg: Some(xdg),
})
}
}
process!(App |self, _client, scope| {
let (
reset, current_frames, current_usecs, next_usecs, period_usecs
) = self.update_time(&scope);
reset, current_frames, chunk_size, current_usecs, next_usecs, period_usecs
) = self.transport.update(&scope);
self.chunk_size = chunk_size;
for track in self.tracks.iter_mut() {
track.process(
self.midi_in.as_ref().map(|p|p.iter(&scope)),
&self.timebase,
self.playing,
self.play_started,
self.quant,
&self.transport.timebase,
self.transport.playing,
self.transport.started,
self.transport.quant,
reset,
&scope,
(current_frames as usize, self.chunk_size),
@ -169,51 +153,6 @@ impl App {
}
Ok(app)
}
pub fn update_time (&mut self, scope: &ProcessScope) -> (bool, usize, usize, usize, f64) {
let CycleTimes {
current_frames,
current_usecs,
next_usecs,
period_usecs
} = scope.cycle_times().unwrap();
self.chunk_size = scope.n_frames() as usize;
let transport = self.transport.as_ref().unwrap().query().unwrap();
self.playhead = transport.pos.frame() as usize;
let mut reset = false;
if self.playing != Some(transport.state) {
match transport.state {
TransportState::Rolling => {
self.play_started = Some((
current_frames as usize,
current_usecs as usize,
));
},
TransportState::Stopped => {
self.play_started = None;
reset = true;
},
_ => {}
}
}
self.playing = Some(transport.state);
(
reset, current_frames as usize, current_usecs as usize, next_usecs as usize, period_usecs as f64
)
}
pub fn toggle_play (&mut self) -> Usually<()> {
self.playing = match self.playing.expect("1st frame has not been processed yet") {
TransportState::Stopped => {
self.transport.as_ref().unwrap().start()?;
Some(TransportState::Starting)
},
_ => {
self.transport.as_ref().unwrap().stop()?;
self.transport.as_ref().unwrap().locate(0)?;
Some(TransportState::Stopped)
},
};
Ok(())
}
}
#[derive(PartialEq, Clone, Copy)]