From 9bed07451fae3972afe42b700448207b8980c2af Mon Sep 17 00:00:00 2001 From: unspeaker <hora.nqma@protonmail.com> Date: Tue, 24 Dec 2024 01:15:35 +0100 Subject: [PATCH] put phrase --- .scratch.rs | 62 +++++++++++++ crates/tek/src/tui/app_arranger.rs | 101 +++++++------------- crates/tek/src/tui/arranger_clip.rs | 14 +++ crates/tek/src/tui/arranger_scene.rs | 133 ++++++++------------------- crates/tek/src/tui/arranger_track.rs | 103 +++++++++++---------- 5 files changed, 202 insertions(+), 211 deletions(-) diff --git a/.scratch.rs b/.scratch.rs index 4eead468..9bd28f30 100644 --- a/.scratch.rs +++ b/.scratch.rs @@ -311,3 +311,65 @@ //) //} +//impl Command<ArrangerModel> for ArrangerSceneCommand { +//} + //Edit(phrase) => { state.state.phrase = phrase.clone() }, + //ToggleViewMode => { state.state.mode.to_next(); }, + //Delete => { state.state.delete(); }, + //Activate => { state.state.activate(); }, + //ZoomIn => { state.state.zoom_in(); }, + //ZoomOut => { state.state.zoom_out(); }, + //MoveBack => { state.state.move_back(); }, + //MoveForward => { state.state.move_forward(); }, + //RandomColor => { state.state.randomize_color(); }, + //Put => { state.state.phrase_put(); }, + //Get => { state.state.phrase_get(); }, + //AddScene => { state.state.scene_add(None, None)?; }, + //AddTrack => { state.state.track_add(None, None)?; }, + //ToggleLoop => { state.state.toggle_loop() }, + //pub fn zoom_in (&mut self) { + //if let ArrangerEditorMode::V(factor) = self.mode { + //self.mode = ArrangerEditorMode::V(factor + 1) + //} + //} + //pub fn zoom_out (&mut self) { + //if let ArrangerEditorMode::V(factor) = self.mode { + //self.mode = ArrangerEditorMode::V(factor.saturating_sub(1)) + //} + //} + //pub fn move_back (&mut self) { + //match self.selected { + //ArrangerEditorFocus::Scene(s) => { + //if s > 0 { + //self.scenes.swap(s, s - 1); + //self.selected = ArrangerEditorFocus::Scene(s - 1); + //} + //}, + //ArrangerEditorFocus::Track(t) => { + //if t > 0 { + //self.tracks.swap(t, t - 1); + //self.selected = ArrangerEditorFocus::Track(t - 1); + //// FIXME: also swap clip order in scenes + //} + //}, + //_ => todo!("arrangement: move forward") + //} + //} + //pub fn move_forward (&mut self) { + //match self.selected { + //ArrangerEditorFocus::Scene(s) => { + //if s < self.scenes.len().saturating_sub(1) { + //self.scenes.swap(s, s + 1); + //self.selected = ArrangerEditorFocus::Scene(s + 1); + //} + //}, + //ArrangerEditorFocus::Track(t) => { + //if t < self.tracks.len().saturating_sub(1) { + //self.tracks.swap(t, t + 1); + //self.selected = ArrangerEditorFocus::Track(t + 1); + //// FIXME: also swap clip order in scenes + //} + //}, + //_ => todo!("arrangement: move forward") + //} + //} diff --git a/crates/tek/src/tui/app_arranger.rs b/crates/tek/src/tui/app_arranger.rs index eaa8ab48..8ee16467 100644 --- a/crates/tek/src/tui/app_arranger.rs +++ b/crates/tek/src/tui/app_arranger.rs @@ -177,7 +177,8 @@ handle!(<Tui>|self: ArrangerTui, input|ArrangerCommand::execute_with_state(self, Zoom(usize), Phrases(PhrasesCommand), Editor(PhraseCommand), - ShowPool(bool) + ShowPool(bool), + Put(usize, usize, Option<Arc<RwLock<Phrase>>>), } input_to_command!(ArrangerCommand: <Tui>|state: ArrangerTui, input|{ use ArrangerSelection as Selected; @@ -205,25 +206,10 @@ input_to_command!(ArrangerCommand: <Tui>|state: ArrangerTui, input|{ key_pat!(Ctrl-Char('t')) => Self::Track(ArrangerTrackCommand::Add), key_pat!(Char('0')) => match state.selected() { - Selected::Mix => StopAll, - Selected::Track(t) => return None, - Selected::Scene(s) => return None, - Selected::Clip(t, s) => return None, - }, - key_pat!(Char('g')) => if let Selected::Clip(t, s) = state.selected() { - Self::Phrases(PhrasesCommand::Select(0)) - } else { - return None - }, - key_pat!(Char('p')) => if let Selected::Clip(t, s) = state.selected() { - Self::Clip(ArrangerClipCommand::Select(0)) - } else { - return None - }, - key_pat!(Char('q')) => if let Selected::Clip(t, s) = state.selected() { - todo!("enqueue clip") - } else { - return None + Selected::Mix => StopAll, + Selected::Track(_t) => return None, + Selected::Scene(_s) => return None, + Selected::Clip(_t, _s) => return None, }, // Tab: Toggle visibility of phrase pool column key_pat!(Tab) => @@ -232,10 +218,23 @@ input_to_command!(ArrangerCommand: <Tui>|state: ArrangerTui, input|{ let t_len = state.tracks.len(); let s_len = state.scenes.len(); match state.selected() { - Selected::Mix => to_arranger_mix_command(input), - Selected::Track(t) => to_arranger_track_command(input, t, t_len), + Selected::Clip(t, s) => match input.event() { + key_pat!(Char('g')) => Some(Self::Phrases(PhrasesCommand::Select(0))), + key_pat!(Char('p')) => Some(Self::Put(t, s, Some(state.phrases.phrase().clone()))), + key_pat!(Char('q')) => { todo!("enqueue") }, + _ => to_arranger_clip_command(input, t, t_len, s, s_len) + }, Selected::Scene(s) => to_arranger_scene_command(input, s, s_len), - Selected::Clip(t, s) => to_arranger_clip_command(input, t, t_len, s, s_len), + Selected::Track(t) => to_arranger_track_command(input, t, t_len), + Selected::Mix => match input.event() { + // 0: Enqueue phrase 0 (stop all) + key_pat!(Char('0')) => Some(Self::StopAll), + key_pat!(Char('s')) => Some(Self::Select(Selected::Scene(0))), + key_pat!(Char('d')) => Some(Self::Select(Selected::Track(0))), + key_pat!(Delete) => Some(Self::Clear), + key_pat!(Char('c')) => Some(Self::Color(ItemPalette::random())), + _ => None + }, } }.or_else(||if let Some(command) = PhraseCommand::input_to_command(&state.editor, input) { Some(Self::Editor(command)) @@ -246,23 +245,6 @@ input_to_command!(ArrangerCommand: <Tui>|state: ArrangerTui, input|{ })? } }); -fn to_arranger_mix_command (input: &TuiInput) -> Option<ArrangerCommand> { - use ArrangerCommand as Cmd; - use ArrangerSelection as Select; - Some(match input.event() { - // 0: Enqueue phrase 0 (stop all) - key_pat!(Char('0')) => Cmd::StopAll, - key_pat!(Char('s')) => Cmd::Select(Select::Scene(0)), - key_pat!(Char('d')) => Cmd::Select(Select::Track(0)), - key_pat!(Char(',')) => Cmd::Zoom(0), - key_pat!(Char('.')) => Cmd::Zoom(0), - key_pat!(Char('<')) => Cmd::Zoom(0), - key_pat!(Char('>')) => Cmd::Zoom(0), - key_pat!(Delete) => Cmd::Clear, - key_pat!(Char('c')) => Cmd::Color(ItemPalette::random()), - _ => return None - }) -} command!(|self:ArrangerCommand,state:ArrangerTui|{ use ArrangerCommand::*; match self { @@ -305,38 +287,17 @@ command!(|self:ArrangerCommand,state:ArrangerTui|{ _ => default(cmd)? } }, - _ => { todo!() } + Undo => { todo!() }, + Redo => { todo!() }, + Clear => { todo!() }, + StopAll => { todo!() }, + Put(track, scene, phrase) => { + let old = state.scenes[scene].clips[track].clone(); + state.scenes[scene].clips[track] = phrase; + Some(Put(track, scene, old)) + }, } }); -command!(|self:ArrangerSceneCommand,state:ArrangerTui|match self { - //Self::Delete(index) => { state.scene_del(index); }, - Self::SetColor(index, color) => { - let old = state.scenes[index].color; - state.scenes[index].color = color; - Some(Self::SetColor(index, old)) - }, - _ => None -}); -command!(|self: ArrangerTrackCommand, state: ArrangerTui|match self { - Self::SetColor(index, color) => { - let old = state.tracks[index].color; - state.tracks[index].color = color; - Some(Self::SetColor(index, old)) - }, - _ => None -}); -command!(|self:ArrangerClipCommand, _state:ArrangerTui|match self { - _ => None -}); -#[derive(Clone, Debug)] -pub enum ArrangerClipCommand { - Play, - Get(usize, usize), - Set(usize, usize, Option<Arc<RwLock<Phrase>>>), - Edit(Option<Arc<RwLock<Phrase>>>), - SetLoop(bool), - RandomColor, -} /// Display mode of arranger #[derive(Clone, PartialEq)] diff --git a/crates/tek/src/tui/arranger_clip.rs b/crates/tek/src/tui/arranger_clip.rs index b4685fb4..0a314338 100644 --- a/crates/tek/src/tui/arranger_clip.rs +++ b/crates/tek/src/tui/arranger_clip.rs @@ -21,3 +21,17 @@ pub fn to_arranger_clip_command (input: &TuiInput, t: usize, len_t: usize, s: us _ => return None }) } + +command!(|self:ArrangerClipCommand, _state:ArrangerTui|match self { + _ => None +}); + +#[derive(Clone, Debug)] +pub enum ArrangerClipCommand { + Play, + Get(usize, usize), + Set(usize, usize, Option<Arc<RwLock<Phrase>>>), + Edit(Option<Arc<RwLock<Phrase>>>), + SetLoop(bool), + RandomColor, +} diff --git a/crates/tek/src/tui/arranger_scene.rs b/crates/tek/src/tui/arranger_scene.rs index 2b4d95a0..f9d0af70 100644 --- a/crates/tek/src/tui/arranger_scene.rs +++ b/crates/tek/src/tui/arranger_scene.rs @@ -1,4 +1,44 @@ use crate::*; +#[derive(Clone, Debug)] +pub enum ArrangerSceneCommand { + Add, + Delete(usize), + RandomColor, + Play(usize), + Swap(usize, usize), + SetSize(usize), + SetZoom(usize), + SetColor(usize, ItemPalette), +} +pub fn to_arranger_scene_command (input: &TuiInput, s: usize, len: usize) -> Option<ArrangerCommand> { + use KeyCode::{Char, Delete}; + use ArrangerCommand as Cmd; + use ArrangerSelection as Select; + use ArrangerSceneCommand as Scene; + Some(match input.event() { + key_pat!(Char('w')) => Cmd::Select(if s > 0 { Select::Scene(s - 1) } else { Select::Mix }), + key_pat!(Char('s')) => Cmd::Select(Select::Scene((s + 1).min(len.saturating_sub(1)))), + key_pat!(Char('d')) => Cmd::Select(Select::Clip(0, s)), + key_pat!(Char(',')) => Cmd::Scene(Scene::Swap(s, s - 1)), + key_pat!(Char('.')) => Cmd::Scene(Scene::Swap(s, s + 1)), + key_pat!(Char('<')) => Cmd::Scene(Scene::Swap(s, s - 1)), + key_pat!(Char('>')) => Cmd::Scene(Scene::Swap(s, s + 1)), + key_pat!(Char('q')) => Cmd::Scene(Scene::Play(s)), + key_pat!(Char('c')) => Cmd::Scene(Scene::SetColor(s, ItemPalette::random())), + key_pat!(Delete) => Cmd::Scene(Scene::Delete(s)), + //key_pat!(Char('c')) => Cmd::Track(Scene::Color(s, ItemPalette::random())), + _ => return None + }) +} +command!(|self:ArrangerSceneCommand,state:ArrangerTui|match self { + //Self::Delete(index) => { state.scene_del(index); }, + Self::SetColor(index, color) => { + let old = state.scenes[index].color; + state.scenes[index].color = color; + Some(Self::SetColor(index, old)) + }, + _ => None +}); #[derive(Default, Debug, Clone)] pub struct ArrangerScene { /// Name of scene pub(crate) name: Arc<RwLock<String>>, @@ -62,37 +102,6 @@ impl ArrangerScene { match self.clips().get(index) { Some(Some(clip)) => Some(clip), _ => None } } } -#[derive(Clone, Debug)] -pub enum ArrangerSceneCommand { - Add, - Delete(usize), - RandomColor, - Play(usize), - Swap(usize, usize), - SetSize(usize), - SetZoom(usize), - SetColor(usize, ItemPalette), -} -pub fn to_arranger_scene_command (input: &TuiInput, s: usize, len: usize) -> Option<ArrangerCommand> { - use KeyCode::{Char, Delete}; - use ArrangerCommand as Cmd; - use ArrangerSelection as Select; - use ArrangerSceneCommand as Scene; - Some(match input.event() { - key_pat!(Char('w')) => Cmd::Select(if s > 0 { Select::Scene(s - 1) } else { Select::Mix }), - key_pat!(Char('s')) => Cmd::Select(Select::Scene((s + 1).min(len.saturating_sub(1)))), - key_pat!(Char('d')) => Cmd::Select(Select::Clip(0, s)), - key_pat!(Char(',')) => Cmd::Scene(Scene::Swap(s, s - 1)), - key_pat!(Char('.')) => Cmd::Scene(Scene::Swap(s, s + 1)), - key_pat!(Char('<')) => Cmd::Scene(Scene::Swap(s, s - 1)), - key_pat!(Char('>')) => Cmd::Scene(Scene::Swap(s, s + 1)), - key_pat!(Char('q')) => Cmd::Scene(Scene::Play(s)), - key_pat!(Char('c')) => Cmd::Scene(Scene::SetColor(s, ItemPalette::random())), - key_pat!(Delete) => Cmd::Scene(Scene::Delete(s)), - //key_pat!(Char('c')) => Cmd::Track(Scene::Color(s, ItemPalette::random())), - _ => return None - }) -} impl ArrangerTui { pub fn scenes (&self) -> &Vec<ArrangerScene> { &self.scenes @@ -123,65 +132,3 @@ impl ArrangerTui { self.selected.scene().map(|s|self.scenes_mut().get_mut(s)).flatten() } } -//impl Command<ArrangerModel> for ArrangerSceneCommand { -//} - //Edit(phrase) => { state.state.phrase = phrase.clone() }, - //ToggleViewMode => { state.state.mode.to_next(); }, - //Delete => { state.state.delete(); }, - //Activate => { state.state.activate(); }, - //ZoomIn => { state.state.zoom_in(); }, - //ZoomOut => { state.state.zoom_out(); }, - //MoveBack => { state.state.move_back(); }, - //MoveForward => { state.state.move_forward(); }, - //RandomColor => { state.state.randomize_color(); }, - //Put => { state.state.phrase_put(); }, - //Get => { state.state.phrase_get(); }, - //AddScene => { state.state.scene_add(None, None)?; }, - //AddTrack => { state.state.track_add(None, None)?; }, - //ToggleLoop => { state.state.toggle_loop() }, - //pub fn zoom_in (&mut self) { - //if let ArrangerEditorMode::V(factor) = self.mode { - //self.mode = ArrangerEditorMode::V(factor + 1) - //} - //} - //pub fn zoom_out (&mut self) { - //if let ArrangerEditorMode::V(factor) = self.mode { - //self.mode = ArrangerEditorMode::V(factor.saturating_sub(1)) - //} - //} - //pub fn move_back (&mut self) { - //match self.selected { - //ArrangerEditorFocus::Scene(s) => { - //if s > 0 { - //self.scenes.swap(s, s - 1); - //self.selected = ArrangerEditorFocus::Scene(s - 1); - //} - //}, - //ArrangerEditorFocus::Track(t) => { - //if t > 0 { - //self.tracks.swap(t, t - 1); - //self.selected = ArrangerEditorFocus::Track(t - 1); - //// FIXME: also swap clip order in scenes - //} - //}, - //_ => todo!("arrangement: move forward") - //} - //} - //pub fn move_forward (&mut self) { - //match self.selected { - //ArrangerEditorFocus::Scene(s) => { - //if s < self.scenes.len().saturating_sub(1) { - //self.scenes.swap(s, s + 1); - //self.selected = ArrangerEditorFocus::Scene(s + 1); - //} - //}, - //ArrangerEditorFocus::Track(t) => { - //if t < self.tracks.len().saturating_sub(1) { - //self.tracks.swap(t, t + 1); - //self.selected = ArrangerEditorFocus::Track(t + 1); - //// FIXME: also swap clip order in scenes - //} - //}, - //_ => todo!("arrangement: move forward") - //} - //} diff --git a/crates/tek/src/tui/arranger_track.rs b/crates/tek/src/tui/arranger_track.rs index bc81c239..cde88c30 100644 --- a/crates/tek/src/tui/arranger_track.rs +++ b/crates/tek/src/tui/arranger_track.rs @@ -1,38 +1,32 @@ use crate::*; use KeyCode::{Char, Delete}; -impl ArrangerTui { - pub fn tracks (&self) -> &Vec<ArrangerTrack> { - &self.tracks - } - pub fn tracks_mut (&mut self) -> &mut Vec<ArrangerTrack> { - &mut self.tracks - } - pub fn track_next_name (&self) -> String { - format!("T{}", self.tracks().len() + 1) - } - pub fn track_add (&mut self, name: Option<&str>, color: Option<ItemPalette>) - -> Usually<&mut ArrangerTrack> - { - let name = name.map_or_else(||self.track_next_name(), |x|x.to_string()); - let track = ArrangerTrack { - width: name.len() + 2, - name: Arc::new(name.into()), - color: color.unwrap_or_else(||ItemPalette::random()), - player: PhrasePlayerModel::from(&self.clock), - }; - self.tracks_mut().push(track); - let index = self.tracks().len() - 1; - Ok(&mut self.tracks_mut()[index]) - } - pub fn track_del (&mut self, index: usize) { - self.tracks_mut().remove(index); - for scene in self.scenes_mut().iter_mut() { - scene.clips.remove(index); - } - } +pub fn to_arranger_track_command (input: &TuiInput, t: usize, len: usize) -> Option<ArrangerCommand> { + use ArrangerCommand::*; + use ArrangerSelection as Selected; + use ArrangerTrackCommand as Tracks; + Some(match input.event() { + key_pat!(Char('s')) => Select(Selected::Clip(t, 0)), + key_pat!(Char('a')) => Select(if t > 0 { Selected::Track(t - 1) } else { Selected::Mix }), + key_pat!(Char('d')) => Select(Selected::Track((t + 1).min(len.saturating_sub(1)))), + key_pat!(Char('c')) => Track(Tracks::SetColor(t, ItemPalette::random())), + key_pat!(Char(',')) => Track(Tracks::Swap(t, t - 1)), + key_pat!(Char('.')) => Track(Tracks::Swap(t, t + 1)), + key_pat!(Char('<')) => Track(Tracks::Swap(t, t - 1)), + key_pat!(Char('>')) => Track(Tracks::Swap(t, t + 1)), + key_pat!(Delete) => Track(Tracks::Delete(t)), + //key_pat!(Char('c')) => Cmd::Track(Track::Color(t, ItemPalette::random())), + _ => return None + }) } - +command!(|self: ArrangerTrackCommand, state: ArrangerTui|match self { + Self::SetColor(index, color) => { + let old = state.tracks[index].color; + state.tracks[index].color = color; + Some(Self::SetColor(index, old)) + }, + _ => None +}); #[derive(Debug)] pub struct ArrangerTrack { /// Name of track @@ -132,21 +126,34 @@ impl<'a> Audio for TracksAudio<'a> { Control::Continue } } -pub fn to_arranger_track_command (input: &TuiInput, t: usize, len: usize) -> Option<ArrangerCommand> { - use ArrangerCommand::*; - use ArrangerSelection as Selected; - use ArrangerTrackCommand as Tracks; - Some(match input.event() { - key_pat!(Char('s')) => Select(Selected::Clip(t, 0)), - key_pat!(Char('a')) => Select(if t > 0 { Selected::Track(t - 1) } else { Selected::Mix }), - key_pat!(Char('d')) => Select(Selected::Track((t + 1).min(len.saturating_sub(1)))), - key_pat!(Char('c')) => Track(Tracks::SetColor(t, ItemPalette::random())), - key_pat!(Char(',')) => Track(Tracks::Swap(t, t - 1)), - key_pat!(Char('.')) => Track(Tracks::Swap(t, t + 1)), - key_pat!(Char('<')) => Track(Tracks::Swap(t, t - 1)), - key_pat!(Char('>')) => Track(Tracks::Swap(t, t + 1)), - key_pat!(Delete) => Track(Tracks::Delete(t)), - //key_pat!(Char('c')) => Cmd::Track(Track::Color(t, ItemPalette::random())), - _ => return None - }) +impl ArrangerTui { + pub fn tracks (&self) -> &Vec<ArrangerTrack> { + &self.tracks + } + pub fn tracks_mut (&mut self) -> &mut Vec<ArrangerTrack> { + &mut self.tracks + } + pub fn track_next_name (&self) -> String { + format!("T{}", self.tracks().len() + 1) + } + pub fn track_add (&mut self, name: Option<&str>, color: Option<ItemPalette>) + -> Usually<&mut ArrangerTrack> + { + let name = name.map_or_else(||self.track_next_name(), |x|x.to_string()); + let track = ArrangerTrack { + width: name.len() + 2, + name: Arc::new(name.into()), + color: color.unwrap_or_else(||ItemPalette::random()), + player: PhrasePlayerModel::from(&self.clock), + }; + self.tracks_mut().push(track); + let index = self.tracks().len() - 1; + Ok(&mut self.tracks_mut()[index]) + } + pub fn track_del (&mut self, index: usize) { + self.tracks_mut().remove(index); + for scene in self.scenes_mut().iter_mut() { + scene.clips.remove(index); + } + } }