tek/src/arranger.rs
2025-01-08 19:19:35 +01:00

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();
}
}
}
}