From 7af5bbd02b4565ead5e419b2b644845d702075e3 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Fri, 15 Nov 2024 02:01:09 +0100 Subject: [PATCH] wip: refactor pt.35 (16e) even more traits, even fewer structs --- crates/tek_api/src/api_clock.rs | 25 +++----------- crates/tek_api/src/api_playhead.rs | 2 +- crates/tek_api/src/api_scene.rs | 29 +++++----------- crates/tek_api/src/api_sequencer.rs | 16 ++++----- crates/tek_api/src/api_track.rs | 23 ++----------- crates/tek_api/src/lib.rs | 16 +++++++-- crates/tek_api/src/model_clock.rs | 12 ------- crates/tek_api/src/model_sequencer.rs | 49 --------------------------- crates/tek_api/src/model_transport.rs | 43 ----------------------- crates/tek_tui/src/tui_arranger.rs | 33 ++++++++++++++++++ crates/tek_tui/src/tui_sequencer.rs | 24 +++++++++++++ crates/tek_tui/src/tui_transport.rs | 40 +++++++++++++++------- 12 files changed, 121 insertions(+), 191 deletions(-) delete mode 100644 crates/tek_api/src/model_sequencer.rs delete mode 100644 crates/tek_api/src/model_transport.rs diff --git a/crates/tek_api/src/api_clock.rs b/crates/tek_api/src/api_clock.rs index 453b23ea..09ace6ae 100644 --- a/crates/tek_api/src/api_clock.rs +++ b/crates/tek_api/src/api_clock.rs @@ -19,11 +19,12 @@ impl Command for ClockCommand { } pub trait ClockApi { - fn quant (&self) -> &Quantize; - - fn sync (&self) -> &LaunchSync; - + /// Current moment in time fn current (&self) -> &Instant; + /// Note quantization factor + fn quant (&self) -> &Quantize; + /// Launch quantization factor + fn sync (&self) -> &LaunchSync; fn timebase (&self) -> &Timebase { &self.current().timebase @@ -38,19 +39,3 @@ pub trait ClockApi { &self.timebase().ppq } } - -pub trait HasClock { - fn clock (&self) -> &impl ClockApi; -} - -impl ClockApi for T { - fn quant (&self) -> &Quantize { - self.clock().quant() - } - fn sync (&self) -> &LaunchSync { - self.clock().sync() - } - fn current (&self) -> &Instant { - self.clock().current() - } -} diff --git a/crates/tek_api/src/api_playhead.rs b/crates/tek_api/src/api_playhead.rs index 46f3e9d4..6ab948bf 100644 --- a/crates/tek_api/src/api_playhead.rs +++ b/crates/tek_api/src/api_playhead.rs @@ -35,7 +35,7 @@ impl Command for PlayheadCommand { pub trait PlayheadApi: ClockApi { - fn transport (&self) -> &RwLock>; + fn transport (&self) -> &jack::Transport; fn playing (&self) -> &RwLock>; diff --git a/crates/tek_api/src/api_scene.rs b/crates/tek_api/src/api_scene.rs index d0a7a95a..70f2ddaa 100644 --- a/crates/tek_api/src/api_scene.rs +++ b/crates/tek_api/src/api_scene.rs @@ -3,26 +3,13 @@ use crate::*; pub trait HasScenes { fn scenes (&self) -> &Vec; fn scenes_mut (&mut self) -> &mut Vec; - - fn scene_default_name (&self) -> String { - format!("Scene {}", self.scenes().len() + 1) - } - fn scene_add (&mut self, name: Option<&str>, color: Option) - -> Usually<&mut S> - { - let name = name.map_or_else(||self.scene_default_name(), |x|x.to_string()); - let scene = ArrangerScene { - name: Arc::new(name.into()), - clips: vec![None;self.tracks().len()], - color: color.unwrap_or_else(||ItemColor::random()), - }; - self.scenes_mut().push(scene); - let index = self.scenes().len() - 1; - Ok(&mut self.scenes_mut()[index]) - } + fn scene_add (&mut self, name: Option<&str>, color: Option) -> Usually<&mut S>; fn scene_del (&mut self, index: usize) { self.scenes_mut().remove(index); } + fn scene_default_name (&self) -> String { + format!("Scene {}", self.scenes().len() + 1) + } } #[derive(Clone, Debug)] @@ -47,9 +34,9 @@ pub enum ArrangerSceneCommand { //} pub trait ArrangerSceneApi: Sized { - fn name () -> Arc>; - fn clips () -> Vec>>>; - fn color () -> ItemColor; + fn name (&self) -> Arc>; + fn clips (&self) -> &Vec>>>; + fn color (&self) -> ItemColor; fn ppqs (scenes: &[Self], factor: usize) -> Vec<(usize, usize)> { let mut total = 0; @@ -80,7 +67,7 @@ pub trait ArrangerSceneApi: Sized { /// Returns true if all phrases in the scene are /// currently playing on the given collection of tracks. fn is_playing (&self, tracks: &[ArrangerTrack]) -> bool { - self.clips().iter().any(|clip|clip.is_some()) && self.clips.iter().enumerate() + self.clips().iter().any(|clip|clip.is_some()) && self.clips().iter().enumerate() .all(|(track_index, clip)|match clip { Some(clip) => tracks .get(track_index) diff --git a/crates/tek_api/src/api_sequencer.rs b/crates/tek_api/src/api_sequencer.rs index b7dc8550..481d8249 100644 --- a/crates/tek_api/src/api_sequencer.rs +++ b/crates/tek_api/src/api_sequencer.rs @@ -1,6 +1,6 @@ use crate::*; -pub trait HasPlayer: HasJack + HasClock { +pub trait HasPlayer: HasJack { fn player (&self) -> &MIDIPlayer; fn player_mut (&mut self) -> &mut MIDIPlayer; } @@ -24,7 +24,7 @@ pub trait HasMidiBuffer { } } -pub trait HasPhrase: PlayheadApi + HasClock + HasMidiBuffer { +pub trait HasPhrase: ClockApi + PlayheadApi + HasMidiBuffer { fn phrase (&self) -> &Option<(Instant, Arc>)>; fn next_phrase (&self) -> &Option<(Instant, Arc>)>; fn next_phrase_mut (&mut self) -> &mut Option<(Instant, Arc>)>; @@ -34,13 +34,13 @@ pub trait HasPhrase: PlayheadApi + HasClock + HasMidiBuffer { //let samples = scope.n_frames() as usize; if let Some((start_at, phrase)) = &self.next_phrase() { let start = start_at.sample.get() as usize; - let sample = self.clock().started.read().unwrap().unwrap().0; + let sample = self.started().read().unwrap().unwrap().0; // If it's time to switch to the next phrase: if start <= sample0.saturating_sub(sample) { // Samples elapsed since phrase was supposed to start let skipped = sample0 - start; // Switch over to enqueued phrase - let started = Instant::from_sample(&self.clock().timebase(), start as f64); + let started = Instant::from_sample(&self.timebase(), start as f64); self.phrase = Some((started, phrase.clone())); // Unset enqueuement (TODO: where to implement looping?) *self.next_phrase_mut() = None @@ -54,9 +54,9 @@ pub trait HasPhrase: PlayheadApi + HasClock + HasMidiBuffer { } } fn enqueue_next (&mut self, phrase: Option<&Arc>>) { - let start = self.clock().next_launch_pulse(); + let start = self.next_launch_pulse(); self.next_phrase = Some(( - Instant::from_pulse(&self.clock().timebase(), start as f64), + Instant::from_pulse(&self.timebase(), start as f64), phrase.map(|p|p.clone()) )); self.reset = true; @@ -70,7 +70,7 @@ pub trait HasPhrase: PlayheadApi + HasClock + HasMidiBuffer { } } -pub trait MidiInputApi: PlayheadApi + HasMidiBuffer + HasPhrase { +pub trait MidiInputApi: ClockApi + PlayheadApi + HasMidiBuffer + HasPhrase { fn midi_ins (&self) -> &Vec>; fn midi_ins_mut (&self) -> &mut Vec>; fn has_midi_ins (&self) -> bool { @@ -147,7 +147,7 @@ pub trait MidiInputApi: PlayheadApi + HasMidiBuffer + HasPhrase { } -pub trait MidiOutputApi: PlayheadApi + HasMidiBuffer + HasPhrase + HasClock { +pub trait MidiOutputApi: ClockApi + PlayheadApi + HasMidiBuffer + HasPhrase { fn midi_outs (&self) -> &Vec>; fn midi_outs_mut (&self) -> &mut Vec>; diff --git a/crates/tek_api/src/api_track.rs b/crates/tek_api/src/api_track.rs index aef03b9f..46e763f9 100644 --- a/crates/tek_api/src/api_track.rs +++ b/crates/tek_api/src/api_track.rs @@ -3,30 +3,11 @@ use crate::*; pub trait HasTracks { fn tracks (&self) -> &Vec; fn tracks_mut (&mut self) -> &mut Vec; - + fn track_add (&mut self, name: Option<&str>, color: Option)-> Usually<&mut T>; + fn track_del (&mut self, index: usize); fn track_default_name (&self) -> String { format!("Track {}", self.tracks().len() + 1) } - fn track_add (&mut self, name: Option<&str>, color: Option) - -> Usually<&mut T> - { - let name = name.map_or_else(||self.track_default_name(), |x|x.to_string()); - let track = ArrangerTrack { - width: name.len() + 2, - color: color.unwrap_or_else(||ItemColor::random()), - player: MIDIPlayer::new(&self.jack(), &self.clock(), name.as_str())?, - name: Arc::new(name.into()), - }; - self.tracks_mut().push(track); - let index = self.tracks().len() - 1; - Ok(&mut self.tracks_mut()[index]) - } - fn track_del (&mut self, index: usize) { - self.tracks_mut().remove(index); - for scene in self.scenes_mut().iter_mut() { - scene.clips.remove(index); - } - } } #[derive(Clone, Debug)] diff --git a/crates/tek_api/src/lib.rs b/crates/tek_api/src/lib.rs index 1751dd3d..9aa58e6b 100644 --- a/crates/tek_api/src/lib.rs +++ b/crates/tek_api/src/lib.rs @@ -30,12 +30,10 @@ submod! { model_scene model_track - model_clock + //model_clock model_phrase model_player model_pool - model_sequencer - model_transport } //impl Command for ArrangerSceneCommand { @@ -100,3 +98,15 @@ submod! { //_ => todo!("arrangement: move forward") //} //} + +//impl From for Clock { + //fn from (current: Instant) -> Self { + //Self { + //playing: Some(TransportState::Stopped).into(), + //started: None.into(), + //quant: 24.into(), + //sync: (current.timebase.ppq.get() * 4.).into(), + //current, + //} + //} +//} diff --git a/crates/tek_api/src/model_clock.rs b/crates/tek_api/src/model_clock.rs index aee60f95..0374824c 100644 --- a/crates/tek_api/src/model_clock.rs +++ b/crates/tek_api/src/model_clock.rs @@ -36,15 +36,3 @@ impl PlayheadApi for Clock { &self.started } } - -impl From for Clock { - fn from (current: Instant) -> Self { - Self { - playing: Some(TransportState::Stopped).into(), - started: None.into(), - quant: 24.into(), - sync: (current.timebase.ppq.get() * 4.).into(), - current, - } - } -} diff --git a/crates/tek_api/src/model_sequencer.rs b/crates/tek_api/src/model_sequencer.rs deleted file mode 100644 index daa639a0..00000000 --- a/crates/tek_api/src/model_sequencer.rs +++ /dev/null @@ -1,49 +0,0 @@ -use crate::*; - -pub struct SequencerModel { - /// State of the JACK transport. - transport: TransportModel, - /// State of the phrase pool. - phrases: Vec>>, - /// State of the phrase player. - player: MIDIPlayer, -} - -impl HasJack for SequencerModel { - fn jack (&self) -> &Arc> { - self.transport.jack() - } -} - -impl HasClock for SequencerModel { - fn clock (&self) -> &Arc { - self.transport.clock() - } -} - -//impl TransportModelApi for SequencerModel { - //fn transport (&self) -> &jack::Transport { - //&self.transport.transport() - //} - //fn metronome (&self) -> bool { - //self.transport.metronome() - //} -//} - -impl HasPhrases for SequencerModel { - fn phrases (&self) -> &Vec>> { - &self.phrases - } - fn phrases_mut (&mut self) -> &mut Vec>> { - &mut self.phrases - } -} - -impl HasPlayer for SequencerModel { - fn player (&self) -> &MIDIPlayer { - &self.player - } - fn player_mut (&mut self) -> &mut MIDIPlayer { - &mut self.player - } -} diff --git a/crates/tek_api/src/model_transport.rs b/crates/tek_api/src/model_transport.rs deleted file mode 100644 index afc40c4a..00000000 --- a/crates/tek_api/src/model_transport.rs +++ /dev/null @@ -1,43 +0,0 @@ -use crate::*; - -pub struct TransportModel { - jack: Arc>, - /// Current sample rate, tempo, and PPQ. - clock: Arc, - /// JACK transport handle. - transport: jack::Transport, - /// Enable metronome? - metronome: bool, -} - -impl HasJack for TransportModel { - fn jack (&self) -> &Arc> { - &self.jack - } -} - -impl HasClock for TransportModel { - fn clock (&self) -> &Arc { - &self.clock - } -} - -//impl TransportModelApi for TransportModel { - //fn transport (&self) -> &jack::Transport { - //&self.transport - //} - //fn metronome (&self) -> bool { - //self.metronome - //} -//} - -impl Debug for TransportModel { - fn fmt (&self, f: &mut Formatter<'_>) -> std::result::Result<(), Error> { - f.debug_struct("transport") - .field("jack", &self.jack) - .field("transport", &"(JACK transport)") - .field("clock", &self.clock) - .field("metronome", &self.metronome) - .finish() - } -} diff --git a/crates/tek_tui/src/tui_arranger.rs b/crates/tek_tui/src/tui_arranger.rs index b8e3a89d..ce071fd8 100644 --- a/crates/tek_tui/src/tui_arranger.rs +++ b/crates/tek_tui/src/tui_arranger.rs @@ -290,6 +290,26 @@ impl HasTracks for ArrangerView { fn tracks_mut (&mut self) -> &mut Vec { &mut self.tracks } + fn track_add (&mut self, name: Option<&str>, color: Option) + -> Usually<&mut ArrangerTrack> + { + let name = name.map_or_else(||self.track_default_name(), |x|x.to_string()); + let track = ArrangerTrack { + width: name.len() + 2, + color: color.unwrap_or_else(||ItemColor::random()), + player: MIDIPlayer::new(&self.jack(), &self.clock(), name.as_str())?, + name: Arc::new(name.into()), + }; + self.tracks_mut().push(track); + let index = self.tracks().len() - 1; + Ok(&mut self.tracks_mut()[index]) + } + fn track_del (&mut self, index: usize) { + self.tracks_mut().remove(index); + for scene in self.scenes_mut().iter_mut() { + scene.clips.remove(index); + } + } } impl HasScenes for ArrangerView { @@ -299,6 +319,19 @@ impl HasScenes for ArrangerView { fn scenes_mut (&mut self) -> &mut Vec { &mut self.scenes } + fn scene_add (&mut self, name: Option<&str>, color: Option) + -> Usually<&mut ArrangerScene> + { + let name = name.map_or_else(||self.scene_default_name(), |x|x.to_string()); + let scene = ArrangerScene { + name: Arc::new(name.into()), + clips: vec![None;self.tracks().len()], + color: color.unwrap_or_else(||ItemColor::random()), + }; + self.scenes_mut().push(scene); + let index = self.scenes().len() - 1; + Ok(&mut self.scenes_mut()[index]) + } } /// Display mode of arranger diff --git a/crates/tek_tui/src/tui_sequencer.rs b/crates/tek_tui/src/tui_sequencer.rs index c6716102..c305ce9d 100644 --- a/crates/tek_tui/src/tui_sequencer.rs +++ b/crates/tek_tui/src/tui_sequencer.rs @@ -213,3 +213,27 @@ impl FocusGrid for SequencerApp { // TODO } } + +impl HasJack for SequencerView { + fn jack (&self) -> &Arc> { + self.transport.jack() + } +} + +impl HasPhrases for SequencerView { + fn phrases (&self) -> &Vec>> { + &self.phrases + } + fn phrases_mut (&mut self) -> &mut Vec>> { + &mut self.phrases + } +} + +impl HasPlayer for SequencerView { + fn player (&self) -> &MIDIPlayer { + &self.player + } + fn player_mut (&mut self) -> &mut MIDIPlayer { + &mut self.player + } +} diff --git a/crates/tek_tui/src/tui_transport.rs b/crates/tek_tui/src/tui_transport.rs index f26eb251..dfcc1ef6 100644 --- a/crates/tek_tui/src/tui_transport.rs +++ b/crates/tek_tui/src/tui_transport.rs @@ -4,11 +4,14 @@ use crate::*; impl TryFrom<&Arc>> for TransportApp { type Error = Box; fn try_from (jack: &Arc>) -> Usually { - Ok(Self::new(TransportModel { + Ok(Self::new(TransportView { metronome: false, transport: jack.read().unwrap().transport(), jack: jack.clone(), clock: Arc::new(Clock::from(Instant::default())) + focused: false, + focus: TransportViewFocus::PlayPause, + size: Measure::new(), }.into(), None, None)) } } @@ -121,18 +124,6 @@ impl Command> for TransportCommand { } } -impl From for TransportView { - fn from (model: TransportModel) -> Self { - Self { - _engine: Default::default(), - focused: false, - focus: TransportViewFocus::PlayPause, - size: Measure::new(), - model - } - } -} - /// Stores and displays time-related info. #[derive(Debug)] pub struct TransportView { @@ -298,3 +289,26 @@ impl FocusGrid for TransportApp { // TODO } } + +impl HasJack for TransportView { + fn jack (&self) -> &Arc> { + &self.jack + } +} + +impl HasClock for TransportView { + fn clock (&self) -> &Arc { + &self.clock + } +} + +impl std::fmt::Debug for TransportView { + fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), Error> { + f.debug_struct("transport") + .field("jack", &self.jack) + .field("transport", &"(JACK transport)") + .field("clock", &self.clock) + .field("metronome", &self.metronome) + .finish() + } +}