From f49823b7a73290ad4b1a054f3ba0f74055aabbf8 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Thu, 21 Nov 2024 15:00:45 +0100 Subject: [PATCH] wip(p63,e22) --- crates/tek_tui/src/tui_apps.rs | 2 + crates/tek_tui/src/tui_control.rs | 197 +++++++++--------------------- crates/tek_tui/src/tui_impls.rs | 112 +++++++++-------- crates/tek_tui/src/tui_init.rs | 1 + crates/tek_tui/src/tui_model.rs | 40 +++++- 5 files changed, 158 insertions(+), 194 deletions(-) diff --git a/crates/tek_tui/src/tui_apps.rs b/crates/tek_tui/src/tui_apps.rs index af4767d4..735e8f79 100644 --- a/crates/tek_tui/src/tui_apps.rs +++ b/crates/tek_tui/src/tui_apps.rs @@ -47,4 +47,6 @@ pub struct ArrangerTui { pub(crate) note_buf: Vec, /// MIDI output buffer pub(crate) midi_buf: Vec>>, + /// MIDI editor state + pub(crate) editor: PhraseEditorModel, } diff --git a/crates/tek_tui/src/tui_control.rs b/crates/tek_tui/src/tui_control.rs index d34f87a4..8d58dea1 100644 --- a/crates/tek_tui/src/tui_control.rs +++ b/crates/tek_tui/src/tui_control.rs @@ -24,6 +24,8 @@ impl TransportControl for ArrangerTui { pub trait SequencerControl: TransportControl {} +impl SequencerControl for SequencerTui {} + pub trait ArrangerControl: TransportControl { fn selected (&self) -> ArrangerSelection; fn selected_mut (&mut self) -> &mut ArrangerSelection; @@ -33,6 +35,59 @@ pub trait ArrangerControl: TransportControl { fn randomize_color (&mut self); } +impl ArrangerControl for ArrangerTui { + fn selected (&self) -> ArrangerSelection { + self.selected + } + fn selected_mut (&mut self) -> &mut ArrangerSelection { + &mut self.selected + } + fn activate (&mut self) { + if let ArrangerSelection::Scene(s) = self.selected { + for (t, track) in self.tracks().iter().enumerate() { + let phrase = self.scenes()[s].clips[t].clone(); + if track.player.play_phrase.is_some() || phrase.is_some() { + track.enqueue_next(phrase.as_ref()); + } + } + // TODO make transport available here, so that + // activating a scene when stopped starts playback + //if self.is_stopped() { + //self.transport.toggle_play() + //} + } else if let ArrangerSelection::Clip(t, s) = self.selected { + let phrase = self.scenes()[s].clips[t].clone(); + self.tracks_mut()[t].enqueue_next(phrase.as_ref()); + }; + } + fn selected_phrase (&self) -> Option>> { + self.selected_scene()?.clips.get(self.selected.track()?)?.clone() + } + fn toggle_loop (&mut self) { + if let Some(phrase) = self.selected_phrase() { + phrase.write().unwrap().toggle_loop() + } + } + fn randomize_color (&mut self) { + match self.selected { + ArrangerSelection::Mix => { + self.color = ItemColor::random_dark() + }, + ArrangerSelection::Track(t) => { + self.tracks_mut()[t].color = ItemColor::random() + }, + ArrangerSelection::Scene(s) => { + self.scenes_mut()[s].color = ItemColor::random() + }, + ArrangerSelection::Clip(t, s) => { + if let Some(phrase) = &self.scenes_mut()[s].clips[t] { + phrase.write().unwrap().color = ItemColorTriplet::random(); + } + } + } + } +} + pub trait PhrasesControl: HasPhrases { fn phrase_index (&self) -> usize; fn set_phrase_index (&self, index: usize); @@ -86,145 +141,3 @@ pub trait PhraseEditorControl: HasFocus { self.time_axis().write().unwrap().point = point.map(forward); } } - -impl SequencerControl for SequencerTui {} - -impl ArrangerControl for ArrangerTui { - fn selected (&self) -> ArrangerSelection { - self.selected - } - fn selected_mut (&mut self) -> &mut ArrangerSelection { - &mut self.selected - } - fn activate (&mut self) { - if let ArrangerSelection::Scene(s) = self.selected { - for (t, track) in self.tracks_mut().iter_mut().enumerate() { - let clip = self.scenes()[s].clips[t].as_ref(); - if track.player.play_phrase.is_some() || clip.is_some() { - track.enqueue_next(clip); - } - } - // TODO make transport available here, so that - // activating a scene when stopped starts playback - //if self.is_stopped() { - //self.transport.toggle_play() - //} - } else if let ArrangerSelection::Clip(t, s) = self.selected { - self.tracks_mut()[t].enqueue_next(self.scenes()[s].clips[t].as_ref()); - }; - } - fn selected_phrase (&self) -> Option>> { - self.selected_scene()?.clips.get(self.selected.track()?)?.clone() - } - fn toggle_loop (&mut self) { - if let Some(phrase) = self.selected_phrase() { - phrase.write().unwrap().toggle_loop() - } - } - fn randomize_color (&mut self) { - match self.selected { - ArrangerSelection::Mix => { - self.color = ItemColor::random_dark() - }, - ArrangerSelection::Track(t) => { - self.tracks_mut()[t].color = ItemColor::random() - }, - ArrangerSelection::Scene(s) => { - self.scenes_mut()[s].color = ItemColor::random() - }, - ArrangerSelection::Clip(t, s) => { - if let Some(phrase) = &self.scenes_mut()[s].clips[t] { - phrase.write().unwrap().color = ItemColorTriplet::random(); - } - } - } - } -} - -impl PhrasesControl for SequencerTui { - fn phrase_index (&self) -> usize { - self.phrases.phrase.load(Ordering::Relaxed) - } - fn set_phrase_index (&self, value: usize) { - self.phrases.phrase.store(value, Ordering::Relaxed); - } - fn phrases_mode (&self) -> &Option { - &self.phrases.mode - } - fn phrases_mode_mut (&mut self) -> &mut Option { - &mut self.phrases.mode - } -} - -impl PhrasesControl for ArrangerTui { - fn phrase_index (&self) -> usize { - self.phrases.phrase.load(Ordering::Relaxed) - } - fn set_phrase_index (&self, value: usize) { - self.phrases.phrase.store(value, Ordering::Relaxed); - } - fn phrases_mode (&self) -> &Option { - &self.phrases.mode - } - fn phrases_mode_mut (&mut self) -> &mut Option { - &mut self.phrases.mode - } -} - -impl PhraseEditorControl for SequencerTui { - fn edit_phrase (&self, phrase: &Option>>) { - //self.editor.show(self.selected_phrase().as_ref()); - //state.editor.phrase = phrase.clone(); - //state.focus(ArrangerFocus::PhraseEditor); - //state.focus_enter(); - todo!() - } - fn editing_phrase (&self) -> &Option>> { - todo!() - } - fn phrase_editor_entered (&self) -> bool { - self.entered && self.focused() == SequencerFocus::PhraseEditor - } - fn time_axis (&self) -> &RwLock> { - todo!() - } - fn note_axis (&self) -> &RwLock> { - todo!() - } - fn note_len (&self) -> usize { - todo!() - } - fn note_len_mut (&mut self) -> &mut usize { - todo!() - } - fn put_note (&mut self) { - todo!() - } -} - -impl PhraseEditorControl for ArrangerTui { - fn edit_phrase (&self, phrase: &Option>>) { - todo!() - } - fn editing_phrase (&self) -> &Option>> { - todo!() - } - fn phrase_editor_entered (&self) -> bool { - self.entered && self.focused() == ArrangerFocus::PhraseEditor - } - fn time_axis (&self) -> &RwLock> { - todo!() - } - fn note_axis (&self) -> &RwLock> { - todo!() - } - fn note_len (&self) -> usize { - todo!() - } - fn note_len_mut (&mut self) -> &mut usize { - todo!() - } - fn put_note (&mut self) { - todo!() - } -} diff --git a/crates/tek_tui/src/tui_impls.rs b/crates/tek_tui/src/tui_impls.rs index 33473a4f..500d1374 100644 --- a/crates/tek_tui/src/tui_impls.rs +++ b/crates/tek_tui/src/tui_impls.rs @@ -49,16 +49,16 @@ macro_rules! impl_has_phrases { ($Struct:ident $(:: $field:ident)*) => { impl HasPhrases for $Struct { fn phrases (&self) -> &Vec>> { - &self$(.$field)* + &self$(.$field)*.phrases } fn phrases_mut (&mut self) -> &mut Vec>> { - &mut self$(.$field)* + &mut self$(.$field)*.phrases } } } } -macro_rules! impl_has_phrase { +macro_rules! impl_midi_player { ($Struct:ident $(:: $field:ident)*) => { impl HasPhrase for $Struct { fn reset (&self) -> bool { @@ -80,11 +80,6 @@ macro_rules! impl_has_phrase { todo!() } } - } -} - -macro_rules! impl_midi_player { - ($Struct:ident $(:: $field:ident)*) => { impl MidiInputApi for $Struct { fn midi_ins(&self) -> &Vec> { todo!() @@ -132,6 +127,60 @@ macro_rules! impl_midi_player { } } +macro_rules! impl_phrases_control { + ($Struct:ident $(:: $field:ident)*) => { + impl PhrasesControl for $Struct { + fn phrase_index (&self) -> usize { + self.phrases.phrase.load(Ordering::Relaxed) + } + fn set_phrase_index (&self, value: usize) { + self.phrases.phrase.store(value, Ordering::Relaxed); + } + fn phrases_mode (&self) -> &Option { + &self.phrases.mode + } + fn phrases_mode_mut (&mut self) -> &mut Option { + &mut self.phrases.mode + } + } + } +} + +macro_rules! impl_phrase_editor_control { + ($Struct:ident $(:: $field:ident)* [$Focus:expr]) => { + impl PhraseEditorControl for $Struct { + fn edit_phrase (&self, phrase: &Option>>) { + //self.editor.show(self.selected_phrase().as_ref()); + //state.editor.phrase = phrase.clone(); + //state.focus(ArrangerFocus::PhraseEditor); + //state.focus_enter(); + todo!() + } + fn editing_phrase (&self) -> &Option>> { + todo!() + } + fn phrase_editor_entered (&self) -> bool { + self.entered && self.focused() == $Focus + } + fn time_axis (&self) -> &RwLock> { + &self.editor.time_axis + } + fn note_axis (&self) -> &RwLock> { + &self.editor.note_axis + } + fn note_len (&self) -> usize { + self.editor.note_len + } + fn note_len_mut (&mut self) -> &mut usize { + &mut self.editor.note_len + } + fn put_note (&mut self) { + todo!() + } + } + } +} + impl_jack_api!(TransportTui::jack); impl_jack_api!(SequencerTui::jack); impl_jack_api!(ArrangerTui::jack); @@ -148,45 +197,10 @@ impl_playhead_api!(ArrangerTrack); impl_has_phrases!(PhrasesModel::phrases); impl_has_phrases!(SequencerTui::phrases); impl_has_phrases!(ArrangerTui::phrases); -impl_has_phrase!(SequencerTui::player); -impl_has_phrase!(ArrangerTrack::player); -impl_has_phrase!(PhrasePlayerModel); -impl_midi_player!(ArrangerTrack); +impl_midi_player!(SequencerTui::player); +impl_midi_player!(ArrangerTrack::player); impl_midi_player!(PhrasePlayerModel); - -impl HasScenes for ArrangerTui { - fn scenes (&self) -> &Vec { - &self.scenes - } - 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]) - } - fn selected_scene (&self) -> Option<&ArrangerScene> { - self.selected.scene().map(|s|self.scenes().get(s)).flatten() - } - fn selected_scene_mut (&mut self) -> Option<&mut ArrangerScene> { - self.selected.scene().map(|s|self.scenes_mut().get_mut(s)).flatten() - } -} - -impl HasTracks for ArrangerTui { - fn tracks (&self) -> &Vec { - &self.tracks - } - fn tracks_mut (&mut self) -> &mut Vec { - &mut self.tracks - } -} +impl_phrases_control!(SequencerTui); +impl_phrases_control!(ArrangerTui); +impl_phrase_editor_control!(SequencerTui [SequencerFocus::PhraseEditor]); +impl_phrase_editor_control!(ArrangerTui [ArrangerFocus::PhraseEditor]); diff --git a/crates/tek_tui/src/tui_init.rs b/crates/tek_tui/src/tui_init.rs index 75c25c1d..2c5b226e 100644 --- a/crates/tek_tui/src/tui_init.rs +++ b/crates/tek_tui/src/tui_init.rs @@ -39,6 +39,7 @@ impl TryFrom<&Arc>> for ArrangerTui { jack: jack.clone(), transport: TransportModel::from(jack.read().unwrap().transport()), phrases: PhrasesModel::default(), + editor: PhraseEditorModel::default(), selected: ArrangerSelection::Clip(0, 0), scenes: vec![], tracks: vec![], diff --git a/crates/tek_tui/src/tui_model.rs b/crates/tek_tui/src/tui_model.rs index 8a250618..f5fd01c4 100644 --- a/crates/tek_tui/src/tui_model.rs +++ b/crates/tek_tui/src/tui_model.rs @@ -167,6 +167,34 @@ impl Default for PhrasesModel { } } +impl HasScenes for ArrangerTui { + fn scenes (&self) -> &Vec { + &self.scenes + } + 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]) + } + fn selected_scene (&self) -> Option<&ArrangerScene> { + self.selected.scene().map(|s|self.scenes().get(s)).flatten() + } + fn selected_scene_mut (&mut self) -> Option<&mut ArrangerScene> { + self.selected.scene().map(|s|self.scenes_mut().get_mut(s)).flatten() + } +} + #[derive(Default, Debug, Clone)] pub struct ArrangerScene { /// Name of scene @@ -189,6 +217,15 @@ impl ArrangerSceneApi for ArrangerScene { } } +impl HasTracks for ArrangerTui { + fn tracks (&self) -> &Vec { + &self.tracks + } + fn tracks_mut (&mut self) -> &mut Vec { + &mut self.tracks + } +} + impl ArrangerTracksApi for ArrangerTui { fn track_add (&mut self, name: Option<&str>, color: Option) -> Usually<&mut ArrangerTrack> @@ -199,7 +236,6 @@ impl ArrangerTracksApi for ArrangerTui { name: Arc::new(name.into()), color: color.unwrap_or_else(||ItemColor::random()), player: PhrasePlayerModel::default(), - editor: PhraseEditorModel::default(), }; self.tracks_mut().push(track); let index = self.tracks().len() - 1; @@ -223,8 +259,6 @@ pub struct ArrangerTrack { pub(crate) color: ItemColor, /// MIDI player state pub(crate) player: PhrasePlayerModel, - /// MIDI editor state - pub(crate) editor: PhraseEditorModel, } impl ArrangerTrackApi for ArrangerTrack {