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>, pub clock: Clock, pub pool: PoolModel, pub tracks: Vec, pub scenes: Vec, pub splits: [u16;2], pub selected: ArrangerSelection, pub mode: ArrangerMode, pub color: ItemPalette, pub size: Measure, pub note_buf: Vec, pub midi_buf: Vec>>, 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>) -> 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>> { 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(); } } } }