From 6d4a62931134c7acd3f68ededaea115933047e55 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Fri, 9 May 2025 19:47:47 +0300 Subject: [PATCH 01/15] implement expose stubs for subcommands --- crates/app/src/api.rs | 63 ++++++++++++++++++++++++++++++++++++++++ crates/app/src/config.rs | 8 ++--- deps/tengri | 2 +- 3 files changed, 68 insertions(+), 5 deletions(-) diff --git a/crates/app/src/api.rs b/crates/app/src/api.rs index 8f25f108..21dd4b30 100644 --- a/crates/app/src/api.rs +++ b/crates/app/src/api.rs @@ -18,6 +18,45 @@ handle!(TuiIn: |self: App, input|Ok(if let Some(command) = self.config.keys.comm })); #[tengri_proc::expose] impl App { + fn _todo_isize_stub (&self) -> isize { + todo!() + } + fn _todo_clip_cmd_stub (&self) -> ClipCommand { + todo!() + } + fn _todo_clock_cmd_stub (&self) -> ClockCommand { + todo!() + } + fn _todo_sampler_cmd_stub (&self) -> SamplerCommand { + todo!() + } + fn _todo_pool_cmd_stub (&self) -> PoolCommand { + todo!() + } + fn _todo_output_cmd_stub (&self) -> OutputCommand { + todo!() + } + fn _todo_input_cmd_stub (&self) -> InputCommand { + todo!() + } + fn _todo_midi_edit_cmd_stub (&self) -> MidiEditCommand { + todo!() + } + fn _todo_message_cmd_stub (&self) -> MessageCommand { + todo!() + } + fn _todo_scene_cmd_stub (&self) -> SceneCommand { + todo!() + } + fn _todo_device_cmd_stub (&self) -> DeviceCommand { + todo!() + } + fn _todo_track_cmd_stub (&self) -> TrackCommand { + todo!() + } + fn _todo_item_theme_stub (&self) -> ItemTheme { + todo!() + } fn focus_editor (&self) -> bool { self.is_editing() } @@ -161,6 +200,27 @@ handle!(TuiIn: |self: App, input|Ok(if let Some(command) = self.config.keys.comm } #[tengri_proc::expose] impl MidiPool { + fn _todo_bool_stub (&self) -> bool { + todo!() + } + fn _todo_path_buf_stub (&self) -> PathBuf { + todo!() + } + fn _todo_arc_str_stub (&self) -> Arc { + todo!() + } + fn _todo_clip_command_stub (&self) -> PoolClipCommand { + todo!() + } + fn _todo_file_command_stub (&self) -> FileBrowserCommand { + todo!() + } + fn _todo_length_command_stub (&self) -> ClipLengthCommand { + todo!() + } + fn _todo_rename_command_stub (&self) -> ClipRenameCommand { + todo!() + } fn clip_new (&self) -> MidiClip { self.new_clip() } @@ -185,6 +245,9 @@ handle!(TuiIn: |self: App, input|Ok(if let Some(command) = self.config.keys.comm } #[tengri_proc::expose] impl MidiEditor { + fn _todo_opt_clip_stub (&self) -> Option>> { + todo!() + } fn time_lock (&self) -> bool { self.get_time_lock() } diff --git a/crates/app/src/config.rs b/crates/app/src/config.rs index fc996811..10a84445 100644 --- a/crates/app/src/config.rs +++ b/crates/app/src/config.rs @@ -122,8 +122,7 @@ impl Configuration { return Err(format!("(e4) unexpected non-symbol {next:?}").into()) }; - let next = exp.next(); - if let Some(Token { value: Value::Str(path), .. }) = next { + if let Some(Token { value: Value::Str(path), .. }) = exp.peek() { let path = base.as_ref().parent().unwrap().join(unquote(path)); if !std::fs::exists(&path)? { return Err(format!("(e5) not found: {path:?}").into()) @@ -133,8 +132,9 @@ impl Configuration { println!("ok"); let cond = cond.unwrap(); map.add_layer_if( - Box::new(|state|{ - Context::get(state, &Value::Sym(cond)).unwrap_or(false) + Box::new(move |state|{ + let mut exp = exp.clone(); + Context::get(state, &mut exp).unwrap_or(false) }), keys ); diff --git a/deps/tengri b/deps/tengri index 22d63eed..ab07fd2b 160000 --- a/deps/tengri +++ b/deps/tengri @@ -1 +1 @@ -Subproject commit 22d63eed9c9cb5bed5016d851f90773e0f60280d +Subproject commit ab07fd2b4303e1c91325aa3f5bc0014ec5a82961 From 0cb259b7b53245a6fc2d5d59e22ba4d1752db9d9 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Fri, 9 May 2025 20:02:44 +0300 Subject: [PATCH 02/15] reduce compiler warnings --- crates/engine/src/lib.rs | 3 +-- deps/tengri | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/engine/src/lib.rs b/crates/engine/src/lib.rs index b4840a09..fb4352f8 100644 --- a/crates/engine/src/lib.rs +++ b/crates/engine/src/lib.rs @@ -5,8 +5,7 @@ mod note; pub use self::note::*; pub mod jack; pub use self::jack::*; pub mod midi; pub use self::midi::*; -pub(crate) use std::sync::{Arc, RwLock, atomic::{AtomicUsize, AtomicBool, Ordering::Relaxed}}; -pub(crate) use std::path::PathBuf; +pub(crate) use std::sync::{Arc, atomic::{AtomicUsize, AtomicBool, Ordering::Relaxed}}; pub(crate) use std::fmt::Debug; pub(crate) use std::ops::{Add, Sub, Mul, Div, Rem}; diff --git a/deps/tengri b/deps/tengri index ab07fd2b..60c07710 160000 --- a/deps/tengri +++ b/deps/tengri @@ -1 +1 @@ -Subproject commit ab07fd2b4303e1c91325aa3f5bc0014ec5a82961 +Subproject commit 60c077102421ed8a7d6cb8674e4380ec6396ca84 From ec5e2a982b10beb6515c0254b3581c604b842054 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Fri, 9 May 2025 20:21:54 +0300 Subject: [PATCH 03/15] config: update view identifiers --- config/config_arranger.edn | 10 +++++----- config/config_groovebox.edn | 14 +++++++------- config/config_sampler.edn | 8 ++++---- config/config_sequencer.edn | 10 +++++----- config/config_transport.edn | 2 +- deps/tengri | 2 +- 6 files changed, 23 insertions(+), 23 deletions(-) diff --git a/config/config_arranger.edn b/config/config_arranger.edn index 8ff9c181..189966b3 100644 --- a/config/config_arranger.edn +++ b/config/config_arranger.edn @@ -3,12 +3,12 @@ (info "A session grid.") (view - (bsp/a :modal - (bsp/s (fixed/y 1 :transport) - (bsp/n (fixed/y 1 :status) + (bsp/a :view-dialog + (bsp/s (fixed/y 1 :view-transport) + (bsp/n (fixed/y 1 :view-status) (fill/xy (bsp/a - (fill/xy (align/e :pool)) - :arranger)))))) + (fill/xy (align/e :view-pool)) + :view-arranger)))))) (keys (layer-if :mode-message "./keys_message.edn") diff --git a/config/config_groovebox.edn b/config/config_groovebox.edn index c3815b89..e4a5974d 100644 --- a/config/config_groovebox.edn +++ b/config/config_groovebox.edn @@ -3,13 +3,13 @@ (info "A sequencer with built-in sampler.") (view - (bsp/a :modal - (bsp/s (fixed/y 1 :transport) - (bsp/n (fixed/y 1 :status) - (bsp/n (fixed/y 5 :sample-viewer) - (bsp/w (fixed/x :w-sidebar :pool) - (bsp/e :samples-keys - (fill/y :editor)))))))) + (bsp/a :view-dialog + (bsp/s (fixed/y 1 :view-transport) + (bsp/n (fixed/y 1 :view-status) + (bsp/n (fixed/y 5 :view-sample-viewer) + (bsp/w (fixed/x :w-sidebar :view-pool) + (bsp/e :view-samples-keys + (fill/y :view-editor)))))))) (keys (layer-if :mode-pool-import "./keys_pool_file.edn") diff --git a/config/config_sampler.edn b/config/config_sampler.edn index 4d8fd6cb..8f6c209a 100644 --- a/config/config_sampler.edn +++ b/config/config_sampler.edn @@ -3,10 +3,10 @@ (info "A sampling soundboard.") (view - (bsp/a :modal - (bsp/s (fixed/y 1 :transport) - (bsp/n (fixed/y 1 :status) - (fill/xy :samples-grid))))) + (bsp/a :view-dialog + (bsp/s (fixed/y 1 :view-transport) + (bsp/n (fixed/y 1 :view-status) + (fill/xy :view-samples-grid))))) (keys (layer "./keys_global.edn") diff --git a/config/config_sequencer.edn b/config/config_sequencer.edn index 1c1b6dfd..5a6d4029 100644 --- a/config/config_sequencer.edn +++ b/config/config_sequencer.edn @@ -3,12 +3,12 @@ (info "A MIDI sequencer.") (view - (bsp/a :modal - (bsp/s (fixed/y 1 :transport) - (bsp/n (fixed/y 1 :status) + (bsp/a :view-dialog + (bsp/s (fixed/y 1 :view-transport) + (bsp/n (fixed/y 1 :view-status) (fill/xy (bsp/a - (fill/xy (align/e :pool)) - :editor))))) + (fill/xy (align/e :view-pool)) + :view-editor))))) (keys (layer-if :mode-pool-import "./keys_pool_file.edn") diff --git a/config/config_transport.edn b/config/config_transport.edn index 00f28567..b84f0279 100644 --- a/config/config_transport.edn +++ b/config/config_transport.edn @@ -2,7 +2,7 @@ (info "A JACK transport controller.") -(view :transport) +(view :view-transport) (keys (layer "./keys_global.edn") diff --git a/deps/tengri b/deps/tengri index 60c07710..3bb38f2d 160000 --- a/deps/tengri +++ b/deps/tengri @@ -1 +1 @@ -Subproject commit 60c077102421ed8a7d6cb8674e4380ec6396ca84 +Subproject commit 3bb38f2d27afc294349f72b1a2f7936bc9338d4f From bfa0ea11638127bb3ec8363cc10898f9f83059c9 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Fri, 9 May 2025 20:24:01 +0300 Subject: [PATCH 04/15] keys: fix arranger selection --- config/keys_arranger.edn | 16 ++++++++-------- crates/app/src/api.rs | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/config/keys_arranger.edn b/config/keys_arranger.edn index 741062e0..ba467da7 100644 --- a/config/keys_arranger.edn +++ b/config/keys_arranger.edn @@ -8,11 +8,11 @@ (@shift-T track add) (@shift-Z device picker) -(@up select :scene-prev) -(@w select :scene-prev) -(@down select :scene-next) -(@s select :scene-next) -(@left select :track-prev) -(@a select :track-prev) -(@right select :track-next) -(@d select :track-next) +(@up select :select-scene-prev) +(@w select :select-scene-prev) +(@down select :select-scene-next) +(@s select :select-scene-next) +(@left select :select-track-prev) +(@a select :select-track-prev) +(@right select :select-track-next) +(@d select :select-track-next) diff --git a/crates/app/src/api.rs b/crates/app/src/api.rs index 21dd4b30..ada08eb1 100644 --- a/crates/app/src/api.rs +++ b/crates/app/src/api.rs @@ -152,22 +152,22 @@ handle!(TuiIn: |self: App, input|Ok(if let Some(command) = self.config.keys.comm fn scene_selected (&self) -> Option { self.selected.scene() } - fn scene_select_next (&self) -> Selection { - self.selected.scene_next(self.scenes.len()) - } - fn scene_select_prev (&self) -> Selection { - self.selected.scene_prev() - } fn track_count (&self) -> usize { self.tracks.len() } fn track_selected (&self) -> Option { self.selected.track() } - fn track_select_next (&self) -> Selection { + fn select_scene_next (&self) -> Selection { + self.selected.scene_next(self.scenes.len()) + } + fn select_scene_prev (&self) -> Selection { + self.selected.scene_prev() + } + fn select_track_next (&self) -> Selection { self.selected.track_next(self.tracks.len()) } - fn track_select_prev (&self) -> Selection { + fn select_track_prev (&self) -> Selection { self.selected.track_prev() } fn clip_selected (&self) -> Option>> { From 419a07de8c9ed5a3998bbcbe8d61fc6229c0755e Mon Sep 17 00:00:00 2001 From: unspeaker Date: Fri, 9 May 2025 21:17:22 +0300 Subject: [PATCH 05/15] wip: providing subcommands --- crates/app/src/api.rs | 116 ++++++++++++++++----------------------- crates/device/src/lv2.rs | 11 ---- deps/tengri | 2 +- 3 files changed, 47 insertions(+), 82 deletions(-) diff --git a/crates/app/src/api.rs b/crates/app/src/api.rs index ada08eb1..4eb728af 100644 --- a/crates/app/src/api.rs +++ b/crates/app/src/api.rs @@ -21,39 +21,6 @@ handle!(TuiIn: |self: App, input|Ok(if let Some(command) = self.config.keys.comm fn _todo_isize_stub (&self) -> isize { todo!() } - fn _todo_clip_cmd_stub (&self) -> ClipCommand { - todo!() - } - fn _todo_clock_cmd_stub (&self) -> ClockCommand { - todo!() - } - fn _todo_sampler_cmd_stub (&self) -> SamplerCommand { - todo!() - } - fn _todo_pool_cmd_stub (&self) -> PoolCommand { - todo!() - } - fn _todo_output_cmd_stub (&self) -> OutputCommand { - todo!() - } - fn _todo_input_cmd_stub (&self) -> InputCommand { - todo!() - } - fn _todo_midi_edit_cmd_stub (&self) -> MidiEditCommand { - todo!() - } - fn _todo_message_cmd_stub (&self) -> MessageCommand { - todo!() - } - fn _todo_scene_cmd_stub (&self) -> SceneCommand { - todo!() - } - fn _todo_device_cmd_stub (&self) -> DeviceCommand { - todo!() - } - fn _todo_track_cmd_stub (&self) -> TrackCommand { - todo!() - } fn _todo_item_theme_stub (&self) -> ItemTheme { todo!() } @@ -209,18 +176,6 @@ handle!(TuiIn: |self: App, input|Ok(if let Some(command) = self.config.keys.comm fn _todo_arc_str_stub (&self) -> Arc { todo!() } - fn _todo_clip_command_stub (&self) -> PoolClipCommand { - todo!() - } - fn _todo_file_command_stub (&self) -> FileBrowserCommand { - todo!() - } - fn _todo_length_command_stub (&self) -> ClipLengthCommand { - todo!() - } - fn _todo_rename_command_stub (&self) -> ClipRenameCommand { - todo!() - } fn clip_new (&self) -> MidiClip { self.new_clip() } @@ -352,6 +307,35 @@ handle!(TuiIn: |self: App, input|Ok(if let Some(command) = self.config.keys.comm None }) } + fn color (app: &mut App, theme: ItemTheme) -> Perhaps { + Ok(app.set_color(Some(theme)).map(|theme|Self::Color{theme})) + } + fn enqueue (app: &mut App, clip: Option>>) -> Perhaps { + todo!() + } + fn history (app: &mut App, delta: isize) -> Perhaps { + todo!() + } + fn zoom (app: &mut App, zoom: usize) -> Perhaps { + todo!() + } + fn launch (app: &mut App) -> Perhaps { + app.launch(); + Ok(None) + } + fn select (app: &mut App, selection: Selection) -> Perhaps { + app.select(selection); + Ok(None) + //("select" [t: usize, s: usize] Some(match (t.expect("no track"), s.expect("no scene")) { + //(0, 0) => Self::Select(Selection::Mix), + //(t, 0) => Self::Select(Selection::Track(t)), + //(0, s) => Self::Select(Selection::Scene(s)), + //(t, s) => Self::Select(Selection::TrackClip { track: t, scene: s }) }))) + } + fn stop_all (app: &mut App) -> Perhaps { + app.stop_all(); + Ok(None) + } fn sampler (app: &mut App, command: SamplerCommand) -> Perhaps { Ok(app.sampler_mut() .map(|s|command.delegate(s, |command|Self::Sampler{command})) @@ -382,34 +366,26 @@ handle!(TuiIn: |self: App, input|Ok(if let Some(command) = self.config.keys.comm fn message (app: &mut App, command: MessageCommand) -> Perhaps { Ok(command.delegate(app, |command|Self::Message{command})?) } - fn color (app: &mut App, theme: ItemTheme) -> Perhaps { - Ok(app.set_color(Some(theme)).map(|theme|Self::Color{theme})) +} + +impl<'state> Context<'state, ClockCommand> for App { + fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option { + Context::get(&self.clock, iter) } - fn enqueue (app: &mut App, clip: Option>>) -> Perhaps { - todo!() +} +impl<'state> Context<'state, MidiEditCommand> for App { + fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option { + self.editor().map(|e|Context::get(e, iter)).flatten() } - fn history (app: &mut App, delta: isize) -> Perhaps { - todo!() +} +impl<'state> Context<'state, PoolCommand> for App { + fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option { + self.pool().map(|p|Context::get(p, iter)).flatten() } - fn zoom (app: &mut App, zoom: usize) -> Perhaps { - todo!() - } - fn launch (app: &mut App) -> Perhaps { - app.launch(); - Ok(None) - } - fn select (app: &mut App, selection: Selection) -> Perhaps { - app.select(selection); - Ok(None) - //("select" [t: usize, s: usize] Some(match (t.expect("no track"), s.expect("no scene")) { - //(0, 0) => Self::Select(Selection::Mix), - //(t, 0) => Self::Select(Selection::Track(t)), - //(0, s) => Self::Select(Selection::Scene(s)), - //(t, s) => Self::Select(Selection::TrackClip { track: t, scene: s }) }))) - } - fn stop_all (app: &mut App) -> Perhaps { - app.stop_all(); - Ok(None) +} +impl<'state> Context<'state, SamplerCommand> for App { + fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option { + self.sampler().map(|p|Context::get(p, iter)).flatten() } } diff --git a/crates/device/src/lv2.rs b/crates/device/src/lv2.rs index 47429b87..b1f0b505 100644 --- a/crates/device/src/lv2.rs +++ b/crates/device/src/lv2.rs @@ -2,15 +2,4 @@ mod lv2_model; pub use self::lv2_model::*; mod lv2_audio; pub use self::lv2_audio::*; mod lv2_gui; pub use self::lv2_gui::*; mod lv2_tui; pub use self::lv2_tui::*; - pub(self) use std::thread::JoinHandle; - -pub(self) use ::livi::{ - World, - Instance, - Plugin as LiviPlugin, - Features, - FeaturesBuilder, - Port as LiviPort, - event::LV2AtomSequence, -}; diff --git a/deps/tengri b/deps/tengri index 3bb38f2d..20ccff13 160000 --- a/deps/tengri +++ b/deps/tengri @@ -1 +1 @@ -Subproject commit 3bb38f2d27afc294349f72b1a2f7936bc9338d4f +Subproject commit 20ccff13de1957c1268c6fec64048d8ae1767fd5 From 75f8fd8746bb82db0ab06a27b20ea9a8664a267a Mon Sep 17 00:00:00 2001 From: unspeaker Date: Fri, 9 May 2025 21:37:52 +0300 Subject: [PATCH 06/15] engine: stop jack processing on mutex poison --- crates/engine/src/jack/jack_client.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/engine/src/jack/jack_client.rs b/crates/engine/src/jack/jack_client.rs index 5adb9a3e..b1200529 100644 --- a/crates/engine/src/jack/jack_client.rs +++ b/crates/engine/src/jack/jack_client.rs @@ -85,7 +85,11 @@ impl Jack { // implements audio and MIDI input and output on a realtime basis. ClosureProcessHandler::new(Box::new({ let app = app.clone(); - move|c: &_, s: &_|app.write().unwrap().process(c, s) + move|c: &_, s: &_|if let Ok(mut app) = app.write() { + app.process(c, s) + } else { + Control::Quit + } }) as BoxedAudioHandler<'j>), )?; *self.state.write().unwrap() = Active(client); From e684415c2f8c5a5ec06b904a95c866107817f4d9 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Fri, 9 May 2025 21:43:07 +0300 Subject: [PATCH 07/15] arranger: fix t keybind on main (thx @magicpotatobean) --- config/keys_arranger.edn | 2 +- crates/app/src/api.rs | 6 ++++++ crates/app/src/model/selection.rs | 10 ++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/config/keys_arranger.edn b/config/keys_arranger.edn index ba467da7..998d2349 100644 --- a/config/keys_arranger.edn +++ b/config/keys_arranger.edn @@ -1,6 +1,6 @@ (@c color) (@q launch) -(@t select :track 0) +(@t select :select-track-header) (@tab edit :clip) (@shift-I input add) (@shift-O output add) diff --git a/crates/app/src/api.rs b/crates/app/src/api.rs index 4eb728af..408f5555 100644 --- a/crates/app/src/api.rs +++ b/crates/app/src/api.rs @@ -131,6 +131,9 @@ handle!(TuiIn: |self: App, input|Ok(if let Some(command) = self.config.keys.comm fn select_scene_prev (&self) -> Selection { self.selected.scene_prev() } + fn select_track_header (&self) -> Selection { + self.selected.track_header(self.tracks.len()) + } fn select_track_next (&self) -> Selection { self.selected.track_next(self.tracks.len()) } @@ -373,16 +376,19 @@ impl<'state> Context<'state, ClockCommand> for App { Context::get(&self.clock, iter) } } + impl<'state> Context<'state, MidiEditCommand> for App { fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option { self.editor().map(|e|Context::get(e, iter)).flatten() } } + impl<'state> Context<'state, PoolCommand> for App { fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option { self.pool().map(|p|Context::get(p, iter)).flatten() } } + impl<'state> Context<'state, SamplerCommand> for App { fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option { self.sampler().map(|p|Context::get(p, iter)).flatten() diff --git a/crates/app/src/model/selection.rs b/crates/app/src/model/selection.rs index 82d588cc..d4560a94 100644 --- a/crates/app/src/model/selection.rs +++ b/crates/app/src/model/selection.rs @@ -53,6 +53,16 @@ impl Selection { _ => None } } + pub fn track_header (&self, track_count: usize) -> Self { + use Selection::*; + match self { + Mix => Track(0), + Scene(_) => Mix, + Track(t) => Track((t + 1) % track_count), + TrackClip { track, .. } => Track(*track), + _ => todo!(), + } + } pub fn track_next (&self, len: usize) -> Self { use Selection::*; match self { From b433688f221180861253c11828f8fb784dbbc44c Mon Sep 17 00:00:00 2001 From: unspeaker Date: Fri, 9 May 2025 21:45:12 +0300 Subject: [PATCH 08/15] arranger: remove wasd keybinds --- config/keys_arranger.edn | 4 ---- 1 file changed, 4 deletions(-) diff --git a/config/keys_arranger.edn b/config/keys_arranger.edn index 998d2349..2ab14fb8 100644 --- a/config/keys_arranger.edn +++ b/config/keys_arranger.edn @@ -9,10 +9,6 @@ (@shift-Z device picker) (@up select :select-scene-prev) -(@w select :select-scene-prev) (@down select :select-scene-next) -(@s select :select-scene-next) (@left select :select-track-prev) -(@a select :select-track-prev) (@right select :select-track-next) -(@d select :select-track-next) From 65d054a03be2d8fafef99ddf6977de5a0eddd7d5 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Fri, 9 May 2025 21:45:22 +0300 Subject: [PATCH 09/15] arranger: fix :mode- -> :focus- --- config/config_arranger.edn | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/config/config_arranger.edn b/config/config_arranger.edn index 189966b3..6ee23998 100644 --- a/config/config_arranger.edn +++ b/config/config_arranger.edn @@ -11,17 +11,17 @@ :view-arranger)))))) (keys - (layer-if :mode-message "./keys_message.edn") - (layer-if :mode-device-add "./keys_device_add.edn") - (layer-if :mode-pool-import "./keys_pool_file.edn") - (layer-if :mode-pool-export "./keys_pool_file.edn") - (layer-if :mode-pool-rename "./keys_clip_rename.edn") - (layer-if :mode-pool-length "./keys_clip_length.edn") - (layer "./keys_global.edn") - (layer-if :mode-editor "./keys_editor.edn") - (layer-if :mode-clip "./keys_clip.edn") - (layer-if :mode-track "./keys_track.edn") - (layer-if :mode-scene "./keys_scene.edn") - (layer-if :mode-mix "./keys_mix.edn") - (layer "./keys_clock.edn") - (layer "./keys_arranger.edn")) + (layer-if :focus-message "./keys_message.edn") + (layer-if :focus-device-add "./keys_device_add.edn") + (layer-if :focus-pool-import "./keys_pool_file.edn") + (layer-if :focus-pool-export "./keys_pool_file.edn") + (layer-if :focus-pool-rename "./keys_clip_rename.edn") + (layer-if :focus-pool-length "./keys_clip_length.edn") + (layer "./keys_global.edn") + (layer-if :focus-editor "./keys_editor.edn") + (layer-if :focus-clip "./keys_clip.edn") + (layer-if :focus-track "./keys_track.edn") + (layer-if :focus-scene "./keys_scene.edn") + (layer-if :focus-mix "./keys_mix.edn") + (layer "./keys_clock.edn") + (layer "./keys_arranger.edn")) From b69a89aac9e53113ec228bb896cc9346566218bf Mon Sep 17 00:00:00 2001 From: unspeaker Date: Fri, 9 May 2025 21:45:49 +0300 Subject: [PATCH 10/15] groovebox: fix :mode- -> :focus- --- config/config_groovebox.edn | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/config/config_groovebox.edn b/config/config_groovebox.edn index e4a5974d..748e7156 100644 --- a/config/config_groovebox.edn +++ b/config/config_groovebox.edn @@ -12,11 +12,11 @@ (fill/y :view-editor)))))))) (keys - (layer-if :mode-pool-import "./keys_pool_file.edn") - (layer-if :mode-pool-export "./keys_pool_file.edn") - (layer-if :mode-pool-rename "./keys_clip_rename.edn") - (layer-if :mode-pool-length "./keys_clip_length.edn") - (layer "./keys_global.edn") - (layer-if :mode-editor "./keys_editor.edn") - (layer "./keys_clock.edn") - (layer "./keys_arranger.edn")) + (layer-if :focus-pool-import "./keys_pool_file.edn") + (layer-if :focus-pool-export "./keys_pool_file.edn") + (layer-if :focus-pool-rename "./keys_clip_rename.edn") + (layer-if :focus-pool-length "./keys_clip_length.edn") + (layer "./keys_global.edn") + (layer-if :focus-editor "./keys_editor.edn") + (layer "./keys_clock.edn") + (layer "./keys_arranger.edn")) From 4394e033521bf10da8040cdacdc8034f41c8fd4e Mon Sep 17 00:00:00 2001 From: unspeaker Date: Fri, 9 May 2025 21:46:59 +0300 Subject: [PATCH 11/15] groovebox/sampler: remove wasd keybinds --- config/config_groovebox.edn | 6 +++--- config/keys_sampler.edn | 8 -------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/config/config_groovebox.edn b/config/config_groovebox.edn index 748e7156..9280ec14 100644 --- a/config/config_groovebox.edn +++ b/config/config_groovebox.edn @@ -1,4 +1,4 @@ -(name "Arranger") +(name "Groovebox") (info "A sequencer with built-in sampler.") @@ -17,6 +17,6 @@ (layer-if :focus-pool-rename "./keys_clip_rename.edn") (layer-if :focus-pool-length "./keys_clip_length.edn") (layer "./keys_global.edn") - (layer-if :focus-editor "./keys_editor.edn") (layer "./keys_clock.edn") - (layer "./keys_arranger.edn")) + (layer "./keys_editor.edn") + (layer "./keys_sampler")) diff --git a/config/keys_sampler.edn b/config/keys_sampler.edn index 8bfb03c9..1dd4f2dc 100644 --- a/config/keys_sampler.edn +++ b/config/keys_sampler.edn @@ -1,13 +1,5 @@ (@up sampler select :sample-up) -(@w sampler select :sample-up) - (@down sampler select :sample-down) -(@s sampler select :sample-down) - (@left sampler select :sample-left) -(@a sampler select :sample-left) - (@right sampler select :sample-right) -(@d sampler select :sample-right) - (@r sampler record/toggle :sample) From 5c74ffd91611ee346f91a224d17e7f401758f693 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Fri, 9 May 2025 21:47:23 +0300 Subject: [PATCH 12/15] docs: remove mention of wasd keybinds --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 65fb7107..1245d348 100644 --- a/README.md +++ b/README.md @@ -25,17 +25,17 @@ or [**matrix** `@unspeaker:matrix.org`](https://matrix.to/#/@unspeaker:matrix.or ## keymaps * Arranger: - * [x] `arrows/wasd`: navigate - * [x] `tab`: enter editor + * [x] arrows: navigate + * [x] tab: enter editor * [x] `q`: enqueue clip * [x] space: play/pause * Editor: - * [x] `arrows/wasd`: navigate + * [x] arrows: navigate * [x] `,` / `.`: change note length - * [x] `enter`: write note + * [x] enter: write note * [x] `-` / `=`: zoom midi editor * [ ] `z`: zoom lock/unlock - * [ ] `del`: delete + * [ ] del: delete * Global: * [x] esc: options menu * [x] f1: help/command list From 9e8572ae0f44edba8cc9bd4b4584f092e33ffcd5 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Fri, 9 May 2025 22:11:15 +0300 Subject: [PATCH 13/15] tests compile again --- crates/app/examples/midi_import.rs | 7 +++++-- crates/app/src/lib.rs | 26 ++++++++++++++++++++++++++ crates/app/src/view.rs | 20 ++++++++++---------- crates/device/src/sequencer.rs | 28 +--------------------------- crates/engine/src/lib.rs | 18 +++++++++--------- 5 files changed, 51 insertions(+), 48 deletions(-) diff --git a/crates/app/examples/midi_import.rs b/crates/app/examples/midi_import.rs index 90b848a1..339bb880 100644 --- a/crates/app/examples/midi_import.rs +++ b/crates/app/examples/midi_import.rs @@ -11,7 +11,10 @@ impl HasClips for ExampleClips { } } fn main () -> Result<(), Box> { - let mut clips = ExampleClips(Arc::new(vec![].into())); - PoolClipCommand::Import(0, std::path::PathBuf::from("./example.mid")).execute(&mut clips)?; + let mut clips = MidiPool::default();//ExampleClips(Arc::new(vec![].into())); + PoolClipCommand::Import { + index: 0, + path: std::path::PathBuf::from("./example.mid") + }.execute(&mut clips)?; Ok(()) } diff --git a/crates/app/src/lib.rs b/crates/app/src/lib.rs index c83d835b..cda6e94b 100644 --- a/crates/app/src/lib.rs +++ b/crates/app/src/lib.rs @@ -122,3 +122,29 @@ mod view; pub use self::view::*; let _ = app.h_outputs(); let _ = app.h_scenes(); } + +#[cfg(test)] #[test] fn test_midi_edit () { + let editor = MidiEditor::default(); + let mut editor = MidiEditor { + mode: PianoHorizontal::new(Some(&Arc::new(RwLock::new(MidiClip::stop_all())))), + size: Default::default(), + //keys: Default::default(), + }; + let _ = editor.put_note(true); + let _ = editor.put_note(false); + let _ = editor.clip_status(); + let _ = editor.edit_status(); + struct TestEditorHost(Option); + has_editor!(|self: TestEditorHost|{ + editor = self.0; + editor_w = 0; + editor_h = 0; + is_editing = false; + }); + let mut host = TestEditorHost(Some(editor)); + let _ = host.editor(); + let _ = host.editor_mut(); + let _ = host.is_editing(); + let _ = host.editor_w(); + let _ = host.editor_h(); +} diff --git a/crates/app/src/view.rs b/crates/app/src/view.rs index 22bf3d02..271c8251 100644 --- a/crates/app/src/view.rs +++ b/crates/app/src/view.rs @@ -4,10 +4,10 @@ pub(crate) use ::tengri::tui::ratatui::prelude::Position; #[tengri_proc::view(TuiOut)] impl App { - fn view_nil (&self) -> impl Content + use<'_> { + pub fn view_nil (&self) -> impl Content + use<'_> { "nil" } - fn view_status (&self) -> impl Content + use<'_> { + pub fn view_status (&self) -> impl Content + use<'_> { self.update_clock(); let cache = self.view_cache.read().unwrap(); view_status( @@ -15,7 +15,7 @@ impl App { cache.sr.view.clone(), cache.buf.view.clone(), cache.lat.view.clone(), ) } - fn view_transport (&self) -> impl Content + use<'_> { + pub fn view_transport (&self) -> impl Content + use<'_> { self.update_clock(); let cache = self.view_cache.read().unwrap(); view_transport( @@ -23,25 +23,25 @@ impl App { cache.bpm.view.clone(), cache.beat.view.clone(), cache.time.view.clone(), ) } - fn view_arranger (&self) -> impl Content + use<'_> { + pub fn view_arranger (&self) -> impl Content + use<'_> { ArrangerView::new(self) } - fn view_pool (&self) -> impl Content + use<'_> { + pub fn view_pool (&self) -> impl Content + use<'_> { self.pool().map(|p|Fixed::x(self.w_sidebar(), PoolView(self.is_editing(), p))) } - fn view_editor (&self) -> impl Content + use<'_> { + pub fn view_editor (&self) -> impl Content + use<'_> { self.editor().map(|e|Bsp::n(Bsp::e(e.clip_status(), e.edit_status()), e)) } - fn view_samples_keys (&self) -> impl Content + use<'_> { + pub fn view_samples_keys (&self) -> impl Content + use<'_> { self.sampler().map(|s|s.view_list(false, self.editor().unwrap())) } - fn view_samples_grid (&self) -> impl Content + use<'_> { + pub fn view_samples_grid (&self) -> impl Content + use<'_> { self.sampler().map(|s|s.view_grid()) } - fn view_sample_viewer (&self) -> impl Content + use<'_> { + pub fn view_sample_viewer (&self) -> impl Content + use<'_> { self.sampler().map(|s|s.view_sample(self.editor().unwrap().get_note_pos())) } - fn view_dialog (&self) -> impl Content + use<'_> { + pub fn view_dialog (&self) -> impl Content + use<'_> { When::new(self.dialog.is_some(), Bsp::b( Fill::xy(Tui::fg_bg(Rgb(64,64,64), Rgb(32,32,32), "")), Fixed::xy(30, 15, Tui::fg_bg(Rgb(255,255,255), Rgb(16,16,16), Bsp::b( diff --git a/crates/device/src/sequencer.rs b/crates/device/src/sequencer.rs index 8bccc2eb..ba8ab65e 100644 --- a/crates/device/src/sequencer.rs +++ b/crates/device/src/sequencer.rs @@ -13,7 +13,7 @@ mod seq_view; pub use self::seq_view::*; let mut clip = MidiClip::new("clip", true, 1, None, None); clip.set_length(96); clip.toggle_loop(); - clip.record_event(12, midly::MidiMessage::NoteOn { key: 36.into(), vel: 100.into() }); + clip.record_event(12, MidiMessage::NoteOn { key: 36.into(), vel: 100.into() }); assert!(clip.contains_note_on(36.into(), 6, 18)); assert_eq!(&clip.notes, &clip.duplicate().notes); @@ -25,29 +25,3 @@ mod seq_view; pub use self::seq_view::*; let player = MidiPlayer::default(); println!("{player:?}"); } - -#[cfg(test)] #[test] fn test_midi_edit () { - let editor = MidiEditor::default(); - let mut editor = MidiEditor { - mode: PianoHorizontal::new(Some(&Arc::new(RwLock::new(MidiClip::stop_all())))), - size: Default::default(), - keys: Default::default(), - }; - let _ = editor.put_note(true); - let _ = editor.put_note(false); - let _ = editor.clip_status(); - let _ = editor.edit_status(); - struct TestEditorHost(Option); - has_editor!(|self: TestEditorHost|{ - editor = self.0; - editor_w = 0; - editor_h = 0; - is_editing = false; - }); - let mut host = TestEditorHost(Some(editor)); - let _ = host.editor(); - let _ = host.editor_mut(); - let _ = host.is_editing(); - let _ = host.editor_w(); - let _ = host.editor_h(); -} diff --git a/crates/engine/src/lib.rs b/crates/engine/src/lib.rs index fb4352f8..860178fc 100644 --- a/crates/engine/src/lib.rs +++ b/crates/engine/src/lib.rs @@ -58,14 +58,14 @@ impl InteriorMutable for AtomicUsize { #[cfg(test)] #[test] fn test_midi_range () { let model = MidiRangeModel::from((1, false)); - let _ = model.time_len(); - let _ = model.time_zoom(); - let _ = model.time_lock(); - let _ = model.time_start(); - let _ = model.time_axis(); - let _ = model.time_end(); + let _ = model.get_time_len(); + let _ = model.get_time_zoom(); + let _ = model.get_time_lock(); + let _ = model.get_time_start(); + let _ = model.get_time_axis(); + let _ = model.get_time_end(); - let _ = model.note_lo(); - let _ = model.note_axis(); - let _ = model.note_hi(); + let _ = model.get_note_lo(); + let _ = model.get_note_axis(); + let _ = model.get_note_hi(); } From 5fa5a875b77ae2b58711bb310037cc7354569c75 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Fri, 9 May 2025 23:22:28 +0300 Subject: [PATCH 14/15] clock: fix play/pause --- config/keys_clock.edn | 4 ++-- crates/app/src/lib.rs | 20 ++++++++------------ crates/app/src/model/scene.rs | 11 +++++++---- crates/device/src/clock/clock_api.rs | 6 +++--- deps/tengri | 2 +- 5 files changed, 21 insertions(+), 22 deletions(-) diff --git a/config/keys_clock.edn b/config/keys_clock.edn index 5a0763be..3f707559 100644 --- a/config/keys_clock.edn +++ b/config/keys_clock.edn @@ -1,2 +1,2 @@ -(@space clock toggle) -(@shift-space clock toggle 0) +(@space clock toggle-playback 0) +(@shift-space clock toggle-playback 0) diff --git a/crates/app/src/lib.rs b/crates/app/src/lib.rs index cda6e94b..f1d59d7f 100644 --- a/crates/app/src/lib.rs +++ b/crates/app/src/lib.rs @@ -42,33 +42,29 @@ mod config; pub use self::config::*; mod model; pub use self::model::*; mod view; pub use self::view::*; -#[cfg(test)] #[test] fn test_model () { +#[cfg(test)] #[test] fn test_model () -> Usually<()> { let mut app = App::default(); let _ = app.clip(); let _ = app.toggle_loop(); -} - -#[cfg(test)] #[test] fn test_model_scene () { - let mut app = App::default(); + //let _ = app.tracks_add(8, None, &[], &[])?; + //let _ = app.track_add_focus()?; let _ = app.scene_longest(); let _ = app.scene(); let _ = app.scene_mut(); - let _ = app.scene_add(None, None); - app.scene_del(0); + let _ = app.scene_add(None, None)?; + let _ = app.scene_add_focus()?; + let scene = app.scene_del(0); let scene = Scene::default(); let _ = scene.pulses(); let _ = scene.is_playing(&[]); -} - -#[cfg(test)] #[test] fn test_view_clock () { - let _ = button_play_pause(true); - let mut app = App::default(); let _ = app.view_transport(); let _ = app.view_status(); let _ = app.update_clock(); + Ok(()) } #[cfg(test)] #[test] fn test_view_layout () { + let _ = button_play_pause(true); let _ = button_2("", "", true); let _ = button_2("", "", false); let _ = button_3("", "", "", true); diff --git a/crates/app/src/model/scene.rs b/crates/app/src/model/scene.rs index 5159eeb0..353133ac 100644 --- a/crates/app/src/model/scene.rs +++ b/crates/app/src/model/scene.rs @@ -46,13 +46,16 @@ pub trait HasScenes: HasSelection + HasEditor + Send + Sync { self.scenes().iter().map(|s|s.name.len()).fold(0, usize::max) } fn scene (&self) -> Option<&Scene> { - self.selected().scene().and_then(|s|self.scenes().get(s)) + self.selected().scene() + .and_then(|s|self.scenes().get(s)) } fn scene_mut (&mut self) -> Option<&mut Scene> { - self.selected().scene().and_then(|s|self.scenes_mut().get_mut(s)) + self.selected().scene() + .and_then(|s|self.scenes_mut().get_mut(s)) } - fn scene_del (&mut self, index: usize) { - self.selected().scene().and_then(|s|Some(self.scenes_mut().remove(index))); + fn scene_del (&mut self, index: usize) -> Option { + self.selected().scene() + .and_then(|s|Some(self.scenes_mut().remove(index))) } /// Set the color of a scene, returning the previous one. fn scene_set_color (&mut self, index: usize, color: ItemTheme) -> ItemTheme { diff --git a/crates/device/src/clock/clock_api.rs b/crates/device/src/clock/clock_api.rs index e9161ec4..e8544525 100644 --- a/crates/device/src/clock/clock_api.rs +++ b/crates/device/src/clock/clock_api.rs @@ -29,11 +29,11 @@ impl ClockCommand { state.pause_at(position)?; Ok(None) } - fn toggle_playback (state: &mut Clock, position: Option) -> Perhaps { + fn toggle_playback (state: &mut Clock, position: u32) -> Perhaps { if state.is_rolling() { - state.pause_at(position)?; + state.pause_at(Some(position))?; } else { - state.play_from(position)?; + state.play_from(Some(position))?; } Ok(None) } diff --git a/deps/tengri b/deps/tengri index 20ccff13..cb8fd269 160000 --- a/deps/tengri +++ b/deps/tengri @@ -1 +1 @@ -Subproject commit 20ccff13de1957c1268c6fec64048d8ae1767fd5 +Subproject commit cb8fd26922fd1cfad4ceadeb89e48544531a178e From ccf21cbdfeb501ec58845cc88d659291bd13b496 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Fri, 9 May 2025 23:26:07 +0300 Subject: [PATCH 15/15] editor: fix keybinds (replace slash with hyphen) --- config/config_groovebox.edn | 2 +- config/keys_editor.edn | 43 ++++++++++++++++--------------------- 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/config/config_groovebox.edn b/config/config_groovebox.edn index 9280ec14..59bc032a 100644 --- a/config/config_groovebox.edn +++ b/config/config_groovebox.edn @@ -19,4 +19,4 @@ (layer "./keys_global.edn") (layer "./keys_clock.edn") (layer "./keys_editor.edn") - (layer "./keys_sampler")) + (layer "./keys_sampler.edn")) diff --git a/config/keys_editor.edn b/config/keys_editor.edn index 88245b5c..09c225f6 100644 --- a/config/keys_editor.edn +++ b/config/keys_editor.edn @@ -1,30 +1,25 @@ -(@up editor note/pos :note-pos-next) -(@w editor note/pos :note-pos-next) -(@down editor note/pos :note-pos-prev) -(@s editor note/pos :note-pos-prev) +(@up editor note-pos :note-pos-next) +(@down editor note-pos :note-pos-prev) +(@pgup editor note-pos :note-pos-next-octave) +(@pgdn editor note-pos :note-pos-prev-octave) -(@pgup editor note/pos :note-pos-next-octave) -(@pgdn editor note/pos :note-pos-prev-octave) +(@comma editor note-len :note-len-prev) +(@period editor note-len :note-len-next) +(@lt editor note-len :note-len-prev) +(@gt editor note-len :note-len-next) -(@comma editor note/len :note-len-prev) -(@period editor note/len :note-len-next) -(@lt editor note/len :note-len-prev) -(@gt editor note/len :note-len-next) +(@plus editor note-range :note-range-next) +(@underscore editor note-range :note-range-prev) -(@plus editor note/range :note-range-next) -(@underscore editor note/range :note-range-prev) +(@left editor time-pos :time-pos-prev) +(@right editor time-pos :time-pos-next) -(@left editor time/pos :time-pos-prev) -(@a editor time/pos :time-pos-prev) -(@right editor time/pos :time-pos-next) -(@d editor time/pos :time-pos-next) +(@equal editor time-zoom :time-zoom-prev) +(@minus editor time-zoom :time-zoom-next) -(@equal editor time/zoom :time-zoom-prev) -(@minus editor time/zoom :time-zoom-next) +(@z editor time-lock) -(@z editor time/lock) - -(@enter editor note/put) -(@shift-enter editor note/append) -(@del editor note/del) -(@shift-del editor note/del) +(@enter editor note-put) +(@shift-enter editor note-append) +(@del editor note-del) +(@shift-del editor note-del)