diff --git a/Cargo.lock b/Cargo.lock index 65fb99c7..fe21dcef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1521,7 +1521,6 @@ dependencies = [ "tek_device", "tek_engine", "tengri", - "tengri_proc", "toml", ] @@ -1602,15 +1601,6 @@ dependencies = [ "tengri_dsl", ] -[[package]] -name = "tengri_proc" -version = "0.13.0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "tengri_tui" version = "0.13.0" diff --git a/Cargo.toml b/Cargo.toml index 488cee90..63d91683 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,13 +23,15 @@ lto = false [workspace.dependencies.tengri] path = "./deps/tengri/tengri" +#git = "https://codeberg.org/unspeaker/tengri" +#rev = "6048d24" features = [ "tui", "dsl" ] -[workspace.dependencies.tengri_proc] -path = "./deps/tengri/proc" - [workspace.dependencies.jack] +#git = "https://codeberg.org/unspeaker/rust-jack" +#rev = "a13c1c4" path = "./deps/rust-jack" +#default-features = false [workspace.dependencies] tek_device = { path = "./crates/device" } diff --git a/config/config_arranger.edn b/config/config_arranger.edn index 3bc4b92a..cd711344 100644 --- a/config/config_arranger.edn +++ b/config/config_arranger.edn @@ -11,7 +11,6 @@ :arranger)))))) (keys - (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") diff --git a/config/keys_arranger.edn b/config/keys_arranger.edn index 741062e0..9df87746 100644 --- a/config/keys_arranger.edn +++ b/config/keys_arranger.edn @@ -1,12 +1,11 @@ -(@c color) -(@q launch) -(@t select :track 0) -(@tab edit :clip) -(@shift-I input add) -(@shift-O output add) -(@shift-S scene add) -(@shift-T track add) -(@shift-Z device picker) +(@t select :track 0) +(@tab edit :clip) +(@c color) +(@q launch) +(@shift-I input add) +(@shift-O output add) +(@shift-S scene add) +(@shift-T track add) (@up select :scene-prev) (@w select :scene-prev) diff --git a/config/keys_device_add.edn b/config/keys_device_add.edn deleted file mode 100644 index 0b3e1f7d..00000000 --- a/config/keys_device_add.edn +++ /dev/null @@ -1,4 +0,0 @@ -(@esc device select-cancel) -(@up device pick :device-kind-prev) -(@down device pick :device-kind-next) -(@enter device add :device-kind) diff --git a/crates/app/Cargo.toml b/crates/app/Cargo.toml index 9635da64..7ed1134b 100644 --- a/crates/app/Cargo.toml +++ b/crates/app/Cargo.toml @@ -4,8 +4,7 @@ edition = { workspace = true } version = { workspace = true } [dependencies] -tengri = { workspace = true } -tengri_proc = { workspace = true } +tengri = { workspace = true } tek_engine = { workspace = true } tek_device = { workspace = true } diff --git a/crates/app/src/api.rs b/crates/app/src/api.rs index a45af91d..a5e414da 100644 --- a/crates/app/src/api.rs +++ b/crates/app/src/api.rs @@ -7,20 +7,9 @@ macro_rules! ns { ($C:ty, $s:expr, $a:expr, $W:expr) => { <$C>::try_from_expr($s macro_rules! cmd { ($cmd:expr) => {{ $cmd; None }}; } macro_rules! cmd_todo { ($msg:literal) => {{ println!($msg); None }}; } -handle!(TuiIn: |self: Tek, input|Ok(if let Some(command) = self.config.keys.command(self, input) { - let undo = command.execute(self)?; - if let Some(undo) = undo { - self.history.push(undo); - } - Some(true) -} else { - None -})); - expose!([self: Tek] ([bool] (":mode-editor" self.is_editing()) - (":mode-device-add" matches!(self.modal, Some(Modal::Device(..)))) (":mode-clip" !self.is_editing() && self.selected.is_clip()) (":mode-track" !self.is_editing() && self.selected.is_track()) (":mode-scene" !self.is_editing() && self.selected.is_scene()) @@ -46,22 +35,7 @@ expose!([self: Tek] (":w-sidebar" self.w_sidebar())) ([usize] (":scene-last" self.scenes.len()) - (":track-last" self.tracks.len()) - (":device-kind" if let Some(Modal::Device(index)) = self.modal { - index - } else { - 0 - }) - (":device-kind-prev" if let Some(Modal::Device(index)) = self.modal { - index.overflowing_sub(1).0.min(self.device_kinds().len().saturating_sub(1)) - } else { - 0 - }) - (":device-kind-next" if let Some(Modal::Device(index)) = self.modal { - (index + 1) % self.device_kinds().len() - } else { - 0 - })) + (":track-last" self.tracks.len())) ([Option] (":scene" self.selected.scene()) (":track" self.selected.track())) @@ -75,45 +49,58 @@ expose!([self: Tek] (":scene-prev" self.selected.scene_prev()) (":track-next" self.selected.track_next(self.tracks.len())) (":track-prev" self.selected.track_prev()))); -expose!([self: MidiPool] - ([bool]) - ([PathBuf]) - ([Arc]) - ([MidiClip] - (":new-clip" self.new_clip()) - (":cloned-clip" self.cloned_clip())) - ([usize] - (":current" 0) - (":after" 0) - (":previous" 0) - (":next" 0)) - ([ItemColor] - (":random-color" ItemColor::random()))); -expose!([self: MidiEditor] - ([bool] - (":true" true) - (":false" false) - (":time-lock" self.time_lock().get()) - (":time-lock-toggle" !self.time_lock().get())) - ([usize] - (":note-length" self.note_len()) - (":note-pos" self.note_pos()) - (":note-pos-next" self.note_pos() + 1) - (":note-pos-prev" self.note_pos().saturating_sub(1)) - (":note-pos-next-octave" self.note_pos() + 12) - (":note-pos-prev-octave" self.note_pos().saturating_sub(12)) - (":note-len" self.note_len()) - (":note-len-next" self.note_len() + 1) - (":note-len-prev" self.note_len().saturating_sub(1)) - (":note-range" self.note_axis().get()) - (":note-range-prev" self.note_axis().get() + 1) - (":note-range-next" self.note_axis().get().saturating_sub(1)) - (":time-pos" self.time_pos()) - (":time-pos-next" self.time_pos() + self.time_zoom().get()) - (":time-pos-prev" self.time_pos().saturating_sub(self.time_zoom().get())) - (":time-zoom" self.time_zoom().get()) - (":time-zoom-next" self.time_zoom().get() + 1) - (":time-zoom-prev" self.time_zoom().get().saturating_sub(1).max(1)))); +provide!(bool: |self: MidiPool| {}); +provide!(MidiClip: |self: MidiPool| { + ":new-clip" => self.new_clip(), + ":cloned-clip" => self.cloned_clip(), +}); +provide!(PathBuf: |self: MidiPool| {}); +provide!(Arc: |self: MidiPool| {}); +provide!(usize: |self: MidiPool| { + ":current" => 0, + ":after" => 0, + ":previous" => 0, + ":next" => 0 +}); +provide!(ItemColor: |self: MidiPool| { + ":random-color" => ItemColor::random() +}); +provide!(bool: |self: MidiEditor| { + ":true" => true, + ":false" => false, + ":time-lock" => self.time_lock().get(), + ":time-lock-toggle" => !self.time_lock().get(), +}); +provide!(usize: |self: MidiEditor| { + ":note-length" => self.note_len(), + ":note-pos" => self.note_pos(), + ":note-pos-next" => self.note_pos() + 1, + ":note-pos-prev" => self.note_pos().saturating_sub(1), + ":note-pos-next-octave" => self.note_pos() + 12, + ":note-pos-prev-octave" => self.note_pos().saturating_sub(12), + ":note-len" => self.note_len(), + ":note-len-next" => self.note_len() + 1, + ":note-len-prev" => self.note_len().saturating_sub(1), + ":note-range" => self.note_axis().get(), + ":note-range-prev" => self.note_axis().get() + 1, + ":note-range-next" => self.note_axis().get().saturating_sub(1), + ":time-pos" => self.time_pos(), + ":time-pos-next" => self.time_pos() + self.time_zoom().get(), + ":time-pos-prev" => self.time_pos().saturating_sub(self.time_zoom().get()), + ":time-zoom" => self.time_zoom().get(), + ":time-zoom-next" => self.time_zoom().get() + 1, + ":time-zoom-prev" => self.time_zoom().get().saturating_sub(1).max(1), +}); + +handle!(TuiIn: |self: Tek, input|Ok(if let Some(command) = self.config.keys.command(self, input) { + let undo = command.execute(self)?; + if let Some(undo) = undo { + self.history.push(undo); + } + Some(true) +} else { + None +})); impose!([app: Tek] (TekCommand: @@ -136,7 +123,6 @@ impose!([app: Tek] ("input" [,..a] ns!(InputCommand, app, a, Self::Input)) ("output" [,..a] ns!(OutputCommand, app, a, Self::Output)) ("clip" [,..a] ns!(ClipCommand, app, a, Self::Clip)) - ("device" [,..a] ns!(DeviceCommand, app, a, Self::Device)) ("pool" [,..a] app.pool.as_ref().map(|p|ns!(PoolCommand, p, a, Self::Pool)).flatten()) ("editor" [,..a] app.editor().map(|e|ns!(MidiEditCommand, e, a, Self::Editor)).flatten()) ("sampler" [,..a] app.sampler().map(|s|ns!(SamplerCommand, s, a, Self::Sampler)).flatten()) @@ -161,11 +147,6 @@ impose!([app: Tek] (OutputCommand: ("add" [] Some(Self::Add))) - (DeviceCommand: - ("picker" [] Some(Self::Picker)) - ("pick" [index: usize] Some(Self::Pick(index.unwrap()))) - ("add" [index: usize] Some(Self::Add(index.unwrap())))) - (SceneCommand: ("add" [] Some(Self::Add)) ("delete" [a: Option] Some(Self::Del(a.flatten().unwrap()))) @@ -197,7 +178,6 @@ defcom!([self, app: Tek] (Input [cmd: InputCommand] cmd.delegate(app, Self::Input)?) (Clip [cmd: ClipCommand] cmd.delegate(app, Self::Clip)?) (Clock [cmd: ClockCommand] cmd.delegate(app, Self::Clock)?) - (Device [cmd: DeviceCommand] cmd.delegate(app, Self::Device)?) (Editor [cmd: MidiEditCommand] delegate_to_editor(app, cmd)?) (Pool [cmd: PoolCommand] delegate_to_pool(app, cmd)?) (ToggleHelp [] cmd!(app.toggle_modal(Some(Modal::Help)))) @@ -212,15 +192,10 @@ defcom!([self, app: Tek] (StopAll [] cmd!(app.stop_all()))) (InputCommand - (Add [] cmd!(app.midi_in_add()?))) + (Add [] cmd!(app.add_midi_in()?))) (OutputCommand - (Add [] cmd!(app.midi_out_add()?))) - - (DeviceCommand - (Picker [] cmd!(app.device_picker_show())) - (Pick [i: usize] cmd!(app.device_pick(i))) - (Add [i: usize] cmd!(app.device_add(i)))) + (Add [] cmd!(app.add_midi_out()?))) (TrackCommand (TogglePlay [] Some(Self::TogglePlay)) diff --git a/crates/app/src/model.rs b/crates/app/src/model.rs index 6a734eda..b8e6471c 100644 --- a/crates/app/src/model.rs +++ b/crates/app/src/model.rs @@ -383,50 +383,16 @@ impl Tek { }) } - pub(crate) fn midi_in_add (&mut self) -> Usually<()> { + pub(crate) fn add_midi_in (&mut self) -> Usually<()> { self.midi_ins.push(JackMidiIn::new(&self.jack, &format!("M/{}", self.midi_ins.len()), &[])?); Ok(()) } - pub(crate) fn midi_out_add (&mut self) -> Usually<()> { + pub(crate) fn add_midi_out (&mut self) -> Usually<()> { self.midi_outs.push(JackMidiOut::new(&self.jack, &format!("{}/M", self.midi_outs.len()), &[])?); Ok(()) } - pub(crate) fn device_picker_show (&mut self) { - self.modal = Some(Modal::Device(0)); - } - - pub(crate) fn device_pick (&mut self, index: usize) { - self.modal = Some(Modal::Device(index)); - } - - pub(crate) fn device_add (&mut self, index: usize) -> Usually<()> { - match index { - 0 => { - let jack = self.jack.clone(); - self.track_mut() - .expect("no active track") - .devices - .push({ - let sampler = Sampler::new(&jack, &"sampler", &[], &[&[], &[]], &[&[], &[]])?; - Device::Sampler(sampler) - }); - self.modal = None; - Ok(()) - }, - 1 => todo!(), - _ => unreachable!(), - } - } - - pub(crate) fn device_kinds (&self) -> &'static [&'static str] { - &[ - "Sampler", - "Plugin (LV2)", - ] - } - } has_size!(|self: Tek|&self.size); @@ -458,7 +424,6 @@ pub trait HasSelection { pub enum Modal { Help, Menu, - Device(usize) } /// Represents the current user selection in the arranger diff --git a/crates/app/src/view.rs b/crates/app/src/view.rs index 36e18146..b2b8b9e9 100644 --- a/crates/app/src/view.rs +++ b/crates/app/src/view.rs @@ -2,66 +2,26 @@ use crate::*; pub(crate) use std::fmt::Write; pub(crate) use ::tengri::tui::ratatui::prelude::Position; -#[tengri_proc::view(TuiOut)] +view!(TuiOut: |self: Tek| self.size.of(View(self, self.config.view)); { + ":nil" => Box::new("nil"), + ":modal" => self.view_modal(), + ":status" => self.view_status(), + ":transport" => self.view_transport(), + ":arranger" => self.view_arranger(), + ":pool" => self.view_pool(), + ":editor" => self.editor().map(|e|Bsp::n(Bsp::e(e.clip_status(), e.edit_status()), e)), + ":samples-keys" => self.sampler().map(|s|s.view_list(false, self.editor().unwrap())), + ":samples-grid" => self.sampler().map(|s|s.view_grid()), + ":sample-viewer" => self.sampler().map(|s|s.view_sample(self.editor().unwrap().note_pos())), +}); + +trait ScenesColors<'a> = Iterator>; + +type SceneWithColor<'a> = (usize, &'a Scene, usize, usize, Option); + impl Tek { - #[tengri::view(":nil")] - fn view_nil (&self) -> impl Content + use<'_> { - "nil" - } - - #[tengri::view(":status")] - fn view_status (&self) -> impl Content + use<'_> { - self.update_clock(); - let cache = self.view_cache.read().unwrap(); - view_status( - self.selected.describe(&self.tracks, &self.scenes), - cache.sr.view.clone(), cache.buf.view.clone(), cache.lat.view.clone(), - ) - } - - #[tengri::view(":transport")] - fn view_transport (&self) -> impl Content + use<'_> { - self.update_clock(); - let cache = self.view_cache.read().unwrap(); - view_transport( - self.clock.is_rolling(), - cache.bpm.view.clone(), cache.beat.view.clone(), cache.time.view.clone(), - ) - } - - #[tengri::view(":arranger")] - fn view_arranger (&self) -> impl Content + use<'_> { - ArrangerView::new(self) - } - - #[tengri::view(":pool")] - fn view_pool (&self) -> impl Content + use<'_> { - self.pool().map(|p|Fixed::x(self.w_sidebar(), PoolView(self.is_editing(), p))) - } - - #[tengri::view(":editor")] - fn view_editor (&self) -> impl Content + use<'_> { - self.editor().map(|e|Bsp::n(Bsp::e(e.clip_status(), e.edit_status()), e)) - } - - #[tengri::view(":samples-keys")] - fn view_samples_keys (&self) -> impl Content + use<'_> { - self.sampler().map(|s|s.view_list(false, self.editor().unwrap())) - } - - #[tengri::view(":samples-grid")] - fn view_samples_grid (&self) -> impl Content + use<'_> { - self.sampler().map(|s|s.view_grid()) - } - - #[tengri::view(":sample-viewer")] - fn view_sample_viewer (&self) -> impl Content + use<'_> { - self.sampler().map(|s|s.view_sample(self.editor().unwrap().note_pos())) - } - - #[tengri::view(":modal")] - fn view_modal (&self) -> impl Content + use<'_> { + pub fn view_modal (&self) -> impl Content + use<'_> { When::new(self.modal.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( @@ -70,7 +30,6 @@ impl Tek { .enclose(self.modal.map(|modal|match modal { Modal::Menu => self.view_modal_menu().boxed(), Modal::Help => self.view_modal_help().boxed(), - Modal::Device(index) => self.view_modal_device(index).boxed(), })) ))) )) @@ -110,14 +69,34 @@ impl Tek { Bsp::s(Tui::bold(true, "Help"), Bsp::s("", Map::south(1, bindings, binding))) } - fn view_modal_device (&self, index: usize) -> impl Content + use<'_> { - let choices = ||self.device_kinds().iter(); - let choice = move|label, i| - Fill::x(Tui::bg(if i == index { Rgb(64,128,32) } else { Rgb(0,0,0) }, - Bsp::e(if i == index { "[ " } else { " " }, - Bsp::w(if i == index { " ]" } else { " " }, - label)))); - Bsp::s(Tui::bold(true, "Add device"), Map::south(1, choices, choice)) + pub fn view_status (&self) -> impl Content + use<'_> { + self.update_clock(); + let cache = self.view_cache.read().unwrap(); + view_status( + self.selected.describe(&self.tracks, &self.scenes), + cache.sr.view.clone(), + cache.buf.view.clone(), + cache.lat.view.clone(), + ) + } + + pub fn view_transport (&self) -> impl Content + use<'_> { + self.update_clock(); + let cache = self.view_cache.read().unwrap(); + view_transport( + self.clock.is_rolling(), + cache.bpm.view.clone(), + cache.beat.view.clone(), + cache.time.view.clone(), + ) + } + + pub fn view_arranger (&self) -> impl Content + use<'_> { + ArrangerView::new(self) + } + + pub fn view_pool (&self) -> impl Content + use<'_> { + self.pool().map(|p|Fixed::x(self.w_sidebar(), PoolView(self.is_editing(), p))) } /// Spacing between tracks. @@ -221,7 +200,7 @@ impl Tek { TrackClip { track, .. } if editing => Some(track), _ => None }; - let bigger = self.editor_w(); + let bigger = self.editor_w(); self.tracks().iter().enumerate().map(move |(index, track)|{ let width = if Some(index) == active.copied() { bigger } else { track.width.max(8) }; let data = (index, track, x, x + width); @@ -357,8 +336,8 @@ impl<'a> ArrangerView<'a> { pub(crate) fn devices (&'a self) -> impl Content + 'a { let Self { width_side, width_mid, track_count, track_selected, is_editing, .. } = self; Tryptich::top(1) - .left(*width_side, button_3("z", "devices", format!("{}", 0), *is_editing)) - .right(*width_side, button_2("Z", "add device", *is_editing)) + .left(*width_side, button_3("x", "devices", format!("{}", 0), *is_editing)) + .right(*width_side, button_2("X", "add device", *is_editing)) .middle(*width_mid, per_track_top(*width_mid, ||self.tracks_with_sizes_scrolled(), move|index, track|{ wrap(if *track_selected == Some(index) { @@ -640,10 +619,6 @@ impl<'a> ArrangerView<'a> { } -trait ScenesColors<'a> = Iterator>; - -type SceneWithColor<'a> = (usize, &'a Scene, usize, usize, Option); - /// Define a type alias for iterators of sized items (columns). macro_rules! def_sizes_iter { ($Type:ident => $($Item:ty),+) => { diff --git a/deps/tengri b/deps/tengri index b543c43e..21f7f6b3 160000 --- a/deps/tengri +++ b/deps/tengri @@ -1 +1 @@ -Subproject commit b543c43e68154f049019da648064f36af1537434 +Subproject commit 21f7f6b38afc966b7b45af442935d48c8c5067d3