From 744ce21e24c92a420ffa6c093e1d63b5716bc515 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Sat, 11 Jan 2025 23:48:20 +0100 Subject: [PATCH] wip: rebinding commands... --- midi/src/midi_pool.rs | 129 ++++++++++++++++++++---------------------- tek/src/control.rs | 47 +++++++++++++++ tek/src/model.rs | 117 ++++++++++++++++++++------------------ 3 files changed, 171 insertions(+), 122 deletions(-) diff --git a/midi/src/midi_pool.rs b/midi/src/midi_pool.rs index ee09e252..6ed53f2f 100644 --- a/midi/src/midi_pool.rs +++ b/midi/src/midi_pool.rs @@ -25,6 +25,54 @@ pub trait HasClips { } } +#[derive(Debug)] +pub struct PoolModel { + pub visible: bool, + /// Collection of clips + pub clips: Arc>>>>, + /// Selected clip + pub clip: AtomicUsize, + /// Mode switch + pub mode: Option, +} +impl Default for PoolModel { + fn default () -> Self { + Self { + visible: true, + clips: Arc::from(RwLock::from(vec![])), + clip: 0.into(), + mode: None, + } + } +} +from!(|clip:&Arc>|PoolModel = { + let model = Self::default(); + model.clips.write().unwrap().push(clip.clone()); + model.clip.store(1, Relaxed); + model +}); + +#[derive(Clone, PartialEq, Debug)] +pub enum PoolCommand { + Show(bool), + /// Update the contents of the clip pool + Clip(MidiPoolCommand), + /// Select a clip from the clip pool + Select(usize), + /// Rename a clip + Rename(ClipRenameCommand), + /// Change the length of a clip + Length(ClipLengthCommand), + /// Import from file + Import(FileBrowserCommand), + /// Export to file + Export(FileBrowserCommand), +} +impl PoolCommand { + pub fn from_edn <'a> (head: &EdnItem<&str>, tail: &'a [EdnItem]) -> Self { + todo!() + } +} #[derive(Clone, Debug, PartialEq)] pub enum MidiPoolCommand { Add(usize, MidiClip), @@ -42,6 +90,20 @@ impl MidiPoolCommand { } } +/// Modes for clip pool +#[derive(Debug, Clone)] +pub enum PoolMode { + /// Renaming a pattern + Rename(usize, Arc), + /// Editing the length of a pattern + Length(usize, usize, ClipLengthFocus), + /// Load clip from disk + Import(usize, FileBrowser), + /// Save clip to disk + Export(usize, FileBrowser), +} + + impl Command for MidiPoolCommand { fn execute (self, model: &mut T) -> Perhaps { use MidiPoolCommand::*; @@ -108,38 +170,6 @@ impl Command for MidiPoolCommand { } } -#[derive(Debug)] -pub struct PoolModel { - pub visible: bool, - /// Collection of clips - pub clips: Arc>>>>, - /// Selected clip - pub clip: AtomicUsize, - /// Mode switch - pub mode: Option, - /// Rendered size - size: Measure, - /// Scroll offset - scroll: usize, -} -impl Default for PoolModel { - fn default () -> Self { - Self { - visible: true, - clips: Arc::from(RwLock::from(vec![])), - clip: 0.into(), - scroll: 0, - mode: None, - size: Measure::new(), - } - } -} -from!(|clip:&Arc>|PoolModel = { - let mut model = Self::default(); - model.clips.write().unwrap().push(clip.clone()); - model.clip.store(1, Relaxed); - model -}); pub struct PoolView<'a>(pub bool, pub &'a PoolModel); render!(TuiOut: (self: PoolView<'a>) => { @@ -167,41 +197,6 @@ render!(TuiOut: (self: PoolView<'a>) => { }))))) }); -/// Modes for clip pool -#[derive(Debug, Clone)] -pub enum PoolMode { - /// Renaming a pattern - Rename(usize, Arc), - /// Editing the length of a pattern - Length(usize, usize, ClipLengthFocus), - /// Load clip from disk - Import(usize, FileBrowser), - /// Save clip to disk - Export(usize, FileBrowser), -} - -#[derive(Clone, PartialEq, Debug)] -pub enum PoolCommand { - Show(bool), - /// Update the contents of the clip pool - Clip(MidiPoolCommand), - /// Select a clip from the clip pool - Select(usize), - /// Rename a clip - Rename(ClipRenameCommand), - /// Change the length of a clip - Length(ClipLengthCommand), - /// Import from file - Import(FileBrowserCommand), - /// Export to file - Export(FileBrowserCommand), -} -impl PoolCommand { - pub fn from_edn <'a> (head: &EdnItem<&str>, tail: &'a [EdnItem]) -> Self { - todo!() - } -} - command!(|self:PoolCommand, state: PoolModel|{ use PoolCommand::*; match self { diff --git a/tek/src/control.rs b/tek/src/control.rs index 73aab79a..6642e5f8 100644 --- a/tek/src/control.rs +++ b/tek/src/control.rs @@ -151,7 +151,54 @@ impl TrackCommand { StopAll, Clear, } +command!(|self: AppCommand, state: App|match self { + Self::Clear => { todo!() }, + Self::Clock(cmd) => cmd.delegate(state, Self::Clock)?, + Self::History(delta) => { todo!("undo/redo") }, + Self::Select(s) => { state.selected = s; None }, + Self::Scene(cmd) => cmd.delegate(state, Self::Scene)?, + Self::Track(cmd) => cmd.delegate(state, Self::Track)?, + Self::Zoom(_) => { todo!(); }, + Self::Editor(cmd) => + state.editor.as_mut().map(|editor|cmd.delegate(editor, Self::Editor)).transpose()?.flatten(), + Self::Sampler(cmd) => + state.sampler.as_mut().map(|sampler|cmd.delegate(sampler, Self::Sampler)).transpose()?.flatten(), + Self::Enqueue(clip) => + state.player.as_mut().map(|player|{player.enqueue_next(clip.as_ref());None}).flatten(), + Self::StopAll => { + for track in 0..state.tracks.len() { state.tracks[track].player.enqueue_next(None); } + None + }, + Self::Color(palette) => { + let old = state.color; + state.color = palette; + Some(Self::Color(old)) + }, + + Self::Pool(cmd) => match cmd { + // autoselect: automatically load selected clip in editor + PoolCommand::Select(_) => { + let undo = cmd.delegate(&mut state.pool, Self::Pool)?; + state.editor.set_clip(state.pool.clip().as_ref()); + undo + }, + // update color in all places simultaneously + PoolCommand::Clip(PoolCmd::SetColor(index, _)) => { + let undo = cmd.delegate(&mut state.pool, Self::Pool)?; + state.editor.set_clip(state.pool.clip().as_ref()); + undo + }, + _ => cmd.delegate(&mut state.pool, Self::Pool)? + }, + + Self::Compact(compact) => if state.compact != compact { + state.compact = compact; + Some(Self::Compact(!compact)) + } else { + None + }, +}); command!(|self: SequencerCommand, state: Sequencer|match self { Self::Clock(cmd) => cmd.delegate(state, Self::Clock)?, diff --git a/tek/src/model.rs b/tek/src/model.rs index 73ae6db3..0f137c4d 100644 --- a/tek/src/model.rs +++ b/tek/src/model.rs @@ -86,62 +86,11 @@ impl App { } } } -#[derive(Default)] pub struct Sequencer { - pub jack: Arc>, - pub compact: bool, - pub editor: MidiEditor, - pub midi_buf: Vec>>, - pub note_buf: Vec, - pub perf: PerfModel, - pub player: MidiPlayer, - pub pool: PoolModel, - pub selectors: bool, - pub size: Measure, - pub status: bool, - pub transport: bool, -} -has_size!(|self:Sequencer|&self.size); -has_clock!(|self:Sequencer|&self.player.clock); -has_clips!(|self:Sequencer|self.pool.clips); -has_editor!(|self:Sequencer|self.editor); +has_size!(|self: App|&self.size); +has_clock!(|self: App|&self.clock); +has_clips!(|self: App|self.pool.clips); +has_editor!(|self: App|self.editor); -#[derive(Default)] pub struct Groovebox { - pub jack: Arc>, - pub compact: bool, - pub editor: MidiEditor, - pub midi_buf: Vec>>, - pub note_buf: Vec, - pub perf: PerfModel, - pub player: MidiPlayer, - pub pool: PoolModel, - pub sampler: Sampler, - pub size: Measure, - pub status: bool, -} -has_clock!(|self: Groovebox|self.player.clock()); - -#[derive(Default)] pub struct Arranger { - pub clock: Clock, - pub color: ItemPalette, - pub compact: bool, - pub editing: AtomicBool, - pub editor: MidiEditor, - pub jack: Arc>, - pub midi_buf: Vec>>, - pub midi_ins: Vec>, - pub midi_outs: Vec>, - pub note_buf: Vec, - pub perf: PerfModel, - pub pool: PoolModel, - pub scenes: Vec, - pub selected: ArrangerSelection, - pub size: Measure, - pub splits: [u16;2], - pub tracks: Vec, -} -has_clock!(|self: Arranger|&self.clock); -has_clips!(|self: Arranger|self.pool.clips); -has_editor!(|self: Arranger|self.editor); #[derive(Debug)] pub struct ArrangerTrack { /// Name of track pub name: Arc, @@ -217,3 +166,61 @@ impl ArrangerSelection { } } } + +#[derive(Default)] pub struct Sequencer { + pub jack: Arc>, + pub compact: bool, + pub editor: MidiEditor, + pub midi_buf: Vec>>, + pub note_buf: Vec, + pub perf: PerfModel, + pub player: MidiPlayer, + pub pool: PoolModel, + pub selectors: bool, + pub size: Measure, + pub status: bool, + pub transport: bool, +} +has_size!(|self:Sequencer|&self.size); +has_clock!(|self:Sequencer|&self.player.clock); +has_clips!(|self:Sequencer|self.pool.clips); +has_editor!(|self:Sequencer|self.editor); +has_player!(|self:Sequencer|self.player); + +#[derive(Default)] pub struct Groovebox { + pub jack: Arc>, + pub compact: bool, + pub editor: MidiEditor, + pub midi_buf: Vec>>, + pub note_buf: Vec, + pub perf: PerfModel, + pub player: MidiPlayer, + pub pool: PoolModel, + pub sampler: Sampler, + pub size: Measure, + pub status: bool, +} +has_clock!(|self: Groovebox|self.player.clock()); + +#[derive(Default)] pub struct Arranger { + pub clock: Clock, + pub color: ItemPalette, + pub compact: bool, + pub editing: AtomicBool, + pub editor: MidiEditor, + pub jack: Arc>, + pub midi_buf: Vec>>, + pub midi_ins: Vec>, + pub midi_outs: Vec>, + pub note_buf: Vec, + pub perf: PerfModel, + pub pool: PoolModel, + pub scenes: Vec, + pub selected: ArrangerSelection, + pub size: Measure, + pub splits: [u16;2], + pub tracks: Vec, +} +has_clock!(|self: Arranger|&self.clock); +has_clips!(|self: Arranger|self.pool.clips); +has_editor!(|self: Arranger|self.editor);