mirror of
https://codeberg.org/unspeaker/tek.git
synced 2026-04-04 05:10:44 +02:00
135 lines
5.2 KiB
Rust
135 lines
5.2 KiB
Rust
use crate::*;
|
|
|
|
mod arranger_command; pub(crate) use self::arranger_command::*;
|
|
mod arranger_scene; pub(crate) use self::arranger_scene::*;
|
|
mod arranger_select; pub(crate) use self::arranger_select::*;
|
|
mod arranger_track; pub(crate) use self::arranger_track::*;
|
|
mod arranger_tui; pub(crate) use self::arranger_tui::*;
|
|
mod arranger_mode; pub(crate) use self::arranger_mode::*;
|
|
mod arranger_h;
|
|
|
|
/// Root view for standalone `tek_arranger`
|
|
pub struct Arranger {
|
|
jack: Arc<RwLock<JackConnection>>,
|
|
pub clock: Clock,
|
|
pub pool: PoolModel,
|
|
pub tracks: Vec<ArrangerTrack>,
|
|
pub scenes: Vec<ArrangerScene>,
|
|
pub splits: [u16;2],
|
|
pub selected: ArrangerSelection,
|
|
pub mode: ArrangerMode,
|
|
pub color: ItemPalette,
|
|
pub size: Measure<TuiOut>,
|
|
pub note_buf: Vec<u8>,
|
|
pub midi_buf: Vec<Vec<Vec<u8>>>,
|
|
pub editor: MidiEditor,
|
|
pub perf: PerfModel,
|
|
pub compact: bool,
|
|
}
|
|
audio!(|self: Arranger, client, scope|{
|
|
// Start profiling cycle
|
|
let t0 = self.perf.get_t0();
|
|
// Update transport clock
|
|
//if Control::Quit == ClockAudio(self).process(client, scope) {
|
|
//return Control::Quit
|
|
//}
|
|
//// Update MIDI sequencers
|
|
//let tracks = &mut self.tracks;
|
|
//let note_buf = &mut self.note_buf;
|
|
//let midi_buf = &mut self.midi_buf;
|
|
//if Control::Quit == TracksAudio(tracks, note_buf, midi_buf).process(client, scope) {
|
|
//return Control::Quit
|
|
//}
|
|
// FIXME: one of these per playing track
|
|
//self.now.set(0.);
|
|
//if let ArrangerSelection::Clip(t, s) = self.selected {
|
|
//let phrase = self.scenes.get(s).map(|scene|scene.clips.get(t));
|
|
//if let Some(Some(Some(phrase))) = phrase {
|
|
//if let Some(track) = self.tracks().get(t) {
|
|
//if let Some((ref started_at, Some(ref playing))) = track.player.play_phrase {
|
|
//let phrase = phrase.read().unwrap();
|
|
//if *playing.read().unwrap() == *phrase {
|
|
//let pulse = self.current().pulse.get();
|
|
//let start = started_at.pulse.get();
|
|
//let now = (pulse - start) % phrase.length as f64;
|
|
//self.now.set(now);
|
|
//}
|
|
//}
|
|
//}
|
|
//}
|
|
//}
|
|
// End profiling cycle
|
|
self.perf.update(t0, scope);
|
|
return Control::Continue
|
|
});
|
|
has_clock!(|self: Arranger|&self.clock);
|
|
has_phrases!(|self: Arranger|self.pool.phrases);
|
|
has_editor!(|self: Arranger|self.editor);
|
|
handle!(TuiIn: |self: Arranger, input|ArrangerCommand::execute_with_state(self, input.event()));
|
|
impl Arranger {
|
|
pub fn new (jack: &Arc<RwLock<JackConnection>>) -> Self {
|
|
let clock = Clock::from(jack);
|
|
let phrase = Arc::new(RwLock::new(MidiClip::new(
|
|
"Clip", true, 4 * clock.timebase.ppq.get() as usize,
|
|
None, Some(ItemColor::random().into())
|
|
)));
|
|
Self {
|
|
clock,
|
|
pool: (&phrase).into(),
|
|
editor: (&phrase).into(),
|
|
selected: ArrangerSelection::Clip(0, 0),
|
|
scenes: vec![],
|
|
tracks: vec![],
|
|
color: ItemPalette::random(),
|
|
mode: ArrangerMode::V(1),
|
|
size: Measure::new(),
|
|
splits: [12, 20],
|
|
midi_buf: vec![vec![];65536],
|
|
note_buf: vec![],
|
|
perf: PerfModel::default(),
|
|
jack: jack.clone(),
|
|
compact: true,
|
|
}
|
|
}
|
|
pub fn selected (&self) -> ArrangerSelection {
|
|
self.selected
|
|
}
|
|
pub fn selected_mut (&mut self) -> &mut ArrangerSelection {
|
|
&mut self.selected
|
|
}
|
|
pub fn activate (&mut self) -> Usually<()> {
|
|
if let ArrangerSelection::Scene(s) = self.selected {
|
|
for (t, track) in self.tracks.iter_mut().enumerate() {
|
|
let phrase = self.scenes[s].clips[t].clone();
|
|
if track.player.play_phrase.is_some() || phrase.is_some() {
|
|
track.player.enqueue_next(phrase.as_ref());
|
|
}
|
|
}
|
|
if self.clock().is_stopped() {
|
|
self.clock().play_from(Some(0))?;
|
|
}
|
|
} else if let ArrangerSelection::Clip(t, s) = self.selected {
|
|
let phrase = self.scenes[s].clips[t].clone();
|
|
self.tracks[t].player.enqueue_next(phrase.as_ref());
|
|
};
|
|
Ok(())
|
|
}
|
|
pub fn selected_phrase (&self) -> Option<Arc<RwLock<MidiClip>>> {
|
|
self.selected_scene()?.clips.get(self.selected.track()?)?.clone()
|
|
}
|
|
pub fn toggle_loop (&mut self) {
|
|
if let Some(phrase) = self.selected_phrase() {
|
|
phrase.write().unwrap().toggle_loop()
|
|
}
|
|
}
|
|
pub fn randomize_color (&mut self) {
|
|
match self.selected {
|
|
ArrangerSelection::Mix => { self.color = ItemPalette::random() },
|
|
ArrangerSelection::Track(t) => { self.tracks[t].color = ItemPalette::random() },
|
|
ArrangerSelection::Scene(s) => { self.scenes[s].color = ItemPalette::random() },
|
|
ArrangerSelection::Clip(t, s) => if let Some(phrase) = &self.scenes[s].clips[t] {
|
|
phrase.write().unwrap().color = ItemPalette::random();
|
|
}
|
|
}
|
|
}
|
|
}
|