From a9fb6fc17c7a4d0d3257fecd3df2c0f25a52ef95 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Fri, 27 Dec 2024 16:54:32 +0100 Subject: [PATCH] wip: samples table --- crates/cli/src/cli_groovebox.rs | 5 ++ crates/cli/src/cli_sequencer.rs | 5 ++ crates/cli/src/lib.rs | 7 +-- crates/tek/src/core/color.rs | 9 +++ crates/tek/src/core/output.rs | 13 +++- crates/tek/src/tui/app_groovebox.rs | 32 +++++++--- crates/tek/src/tui/app_sampler.rs | 69 +++++++++------------- crates/tek/src/tui/piano_h.rs | 12 +++- crates/tek/src/tui/piano_h/piano_h_keys.rs | 25 +++----- 9 files changed, 103 insertions(+), 74 deletions(-) diff --git a/crates/cli/src/cli_groovebox.rs b/crates/cli/src/cli_groovebox.rs index 68689338..d72778a6 100644 --- a/crates/cli/src/cli_groovebox.rs +++ b/crates/cli/src/cli_groovebox.rs @@ -41,3 +41,8 @@ impl GrooveboxCli { Ok(()) } } + +#[test] fn verify_groovebox_cli () { + use clap::CommandFactory; + GrooveboxCli::command().debug_assert(); +} diff --git a/crates/cli/src/cli_sequencer.rs b/crates/cli/src/cli_sequencer.rs index 40696efa..247282f7 100644 --- a/crates/cli/src/cli_sequencer.rs +++ b/crates/cli/src/cli_sequencer.rs @@ -42,3 +42,8 @@ impl SequencerCli { Ok(()) } } + +#[test] fn verify_sequencer_cli () { + use clap::CommandFactory; + SequencerCli::command().debug_assert(); +} diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs index e8d37d2b..e2d6822e 100644 --- a/crates/cli/src/lib.rs +++ b/crates/cli/src/lib.rs @@ -2,6 +2,7 @@ #[allow(unused_imports)] use clap::{self, Parser}; #[allow(unused_imports)] use tek::{*, jack::*}; +#[allow(unused)] fn connect_from (jack: &JackClient, input: &Port, ports: &[String]) -> Usually<()> { for port in ports.iter() { if let Some(port) = jack.port_by_name(port).as_ref() { @@ -13,6 +14,7 @@ fn connect_from (jack: &JackClient, input: &Port, ports: &[String]) -> U Ok(()) } +#[allow(unused)] fn connect_to (jack: &JackClient, output: &Port, ports: &[String]) -> Usually<()> { for port in ports.iter() { if let Some(port) = jack.port_by_name(port).as_ref() { @@ -23,8 +25,3 @@ fn connect_to (jack: &JackClient, output: &Port, ports: &[String]) -> U } Ok(()) } - -#[test] fn verify_sequencer_cli () { - use clap::CommandFactory; - SequencerCli::command().debug_assert(); -} diff --git a/crates/tek/src/core/color.rs b/crates/tek/src/core/color.rs index 9fc495af..fd678201 100644 --- a/crates/tek/src/core/color.rs +++ b/crates/tek/src/core/color.rs @@ -7,6 +7,15 @@ pub trait HasColor { fn color_mut (&mut self) -> &mut ItemColor; } +#[macro_export] macro_rules! has_color { + (|$self:ident:$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)?|$cb:expr) => { + impl $(<$($L),*$($T $(: $U)?),*>)? HasColor for $Struct $(<$($L),*$($T),*>)? { + fn color (&$self) -> ItemColor { &$cb } + fn color_mut (&mut $self) -> &mut ItemColor { &mut $cb } + } + } +} + /// A color in OKHSL and RGB representations. #[derive(Debug, Default, Copy, Clone, PartialEq)] pub struct ItemColor { diff --git a/crates/tek/src/core/output.rs b/crates/tek/src/core/output.rs index 5ee2a75d..ff8748a7 100644 --- a/crates/tek/src/core/output.rs +++ b/crates/tek/src/core/output.rs @@ -11,8 +11,17 @@ use crate::*; } } }; - (<$E:ty>|$self:ident:$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)?|$cb:expr) => { - impl $(<$($L),*$($T $(: $U)?),*>)? Render<$E> for $Struct $(<$($L),*$($T),*>)? { + (<$E:ty>|$self:ident:$Struct:ident$(< + $($($L:lifetime),+)? + $($($T:ident$(:$U:path)?),+)? + >)?|$cb:expr) => { + impl $(< + $($($L),+)? + $($($T$(:$U)?),+)? + >)? Render<$E> for $Struct $(< + $($($L),+)? + $($($T),+)? + >)? { fn min_size (&$self, to: <$E as Engine>::Size) -> Perhaps<<$E as Engine>::Size> { $cb.min_size(to) } diff --git a/crates/tek/src/tui/app_groovebox.rs b/crates/tek/src/tui/app_groovebox.rs index 94d48858..fad1c95f 100644 --- a/crates/tek/src/tui/app_groovebox.rs +++ b/crates/tek/src/tui/app_groovebox.rs @@ -1,11 +1,14 @@ use crate::*; use super::*; +use KeyCode::{Char, Delete, Tab, Up, Down, Left, Right}; + pub struct GrooveboxTui { pub sequencer: SequencerTui, pub sampler: SamplerTui, pub split: u16, pub focus: GrooveboxFocus } + from_jack!(|jack|GrooveboxTui { let mut sequencer = SequencerTui::try_from(jack)?; sequencer.status = false; @@ -20,29 +23,42 @@ from_jack!(|jack|GrooveboxTui { sequencer, sampler: SamplerTui::try_from(jack)?, split: 16, - focus: GrooveboxFocus::Sampler, + focus: GrooveboxFocus::Sequencer, } }); + pub enum GrooveboxFocus { Sequencer, Sampler } + audio!(|self:GrooveboxTui,_client,_process|Control::Continue); + render!(|self:GrooveboxTui|Bsp::n( Fixed::h(2, SequencerStatus::from(&self.sequencer)), - Fill::h(Bsp::s(&self.sequencer, &self.sampler)), + Fill::h(Bsp::s( + Tui::min_y(30, &self.sequencer), + Fill::h(&self.sampler), + )), )); + pub enum GrooveboxCommand { Sequencer(SequencerCommand), Sampler(SamplerCommand), } -handle!(|self:GrooveboxTui,input|GrooveboxCommand::execute_with_state(self, input)); -input_to_command!(GrooveboxCommand: |state:GrooveboxTui,input|match state.focus { - GrooveboxFocus::Sequencer => GrooveboxCommand::Sequencer( - SequencerCommand::input_to_command(&state.sequencer, input)?), - GrooveboxFocus::Sampler => GrooveboxCommand::Sampler( - SamplerCommand::input_to_command(&state.sampler, input)?), + +handle!(|self: GrooveboxTui, input|GrooveboxCommand::execute_with_state(self, input)); + +input_to_command!(GrooveboxCommand: |state: GrooveboxTui,input|match input.event() { + key_pat!(Up) | + key_pat!(Down) | + key_pat!(Left) | + key_pat!(Right) => + GrooveboxCommand::Sampler(SamplerCommand::input_to_command(&state.sampler, input)?), + _ => + GrooveboxCommand::Sequencer(SequencerCommand::input_to_command(&state.sequencer, input)?), }); + command!(|self:GrooveboxCommand,state:GrooveboxTui|match self { GrooveboxCommand::Sequencer(command) => command.execute(&mut state.sequencer)?.map(GrooveboxCommand::Sequencer), diff --git a/crates/tek/src/tui/app_sampler.rs b/crates/tek/src/tui/app_sampler.rs index c1fb49b6..049473fc 100644 --- a/crates/tek/src/tui/app_sampler.rs +++ b/crates/tek/src/tui/app_sampler.rs @@ -1,5 +1,6 @@ use crate::*; -use super::*; +use super::{*, piano_h::PianoHorizontalKeys}; + use KeyCode::Char; use std::fs::File; use symphonia::{ @@ -13,12 +14,36 @@ use symphonia::{ }, default::get_codecs, }; + pub struct SamplerTui { pub state: Sampler, pub cursor: (usize, usize), pub editing: Option>>, pub mode: Option, + /// Size of actual notes area + pub size: Measure, } + +render!(|self: SamplerTui|{ + let keys_width = 5; + let keys = move||SamplerKeys(self); + let fg = TuiTheme::g(200); + let bg = TuiTheme::g(50); + let border = Fill::wh(Outer(Style::default().fg(fg).bg(bg))); + let with_border = |x|lay!([border, Tui::inset_xy(1, 1, &x)]); + with_border(Fill::wh(Bsp::s( + "kyp", + Bsp::e( + Fixed::w(keys_width, keys()), + Fill::wh(lay!([&self.size, Fill::wh("nymka")])), + ), + ))) +}); + +struct SamplerKeys<'a>(&'a SamplerTui); +render!(|self: SamplerKeys<'a>|render(|to|Ok(render_keys_v(to, self)))); +has_color!(|self: SamplerKeys<'a>|ItemColor::default()); + pub enum SamplerMode { // Load sample from path Import(usize, FileBrowser), @@ -33,6 +58,7 @@ from_jack!(|jack|SamplerTui{ cursor: (0, 0), editing: None, mode: None, + size: Measure::new(), state: Sampler { jack: jack.clone(), name: "Sampler".into(), @@ -64,16 +90,10 @@ input_to_command!(SamplerCommand:|state:SamplerTui,input|match state.mode { _ => match input.event() { // load sample key_pat!(Char('l')) => Self::Import(FileBrowserCommand::Begin), + key_pat!(KeyCode::Up) => { todo!() }, + key_pat!(KeyCode::Down) => { todo!() }, _ => return None } - //key_pat!(KeyCode::Up) => state.cursor.0 = if state.cursor.0 == 0 { - //mapped.len() + unmapped.len() - 1 - //} else { - //state.cursor.0 - 1 - //}, - //key_pat!(KeyCode::Down) => { - //state.cursor.0 = (state.cursor.0 + 1) % (mapped.len() + unmapped.len()); - //}, //key_pat!(KeyCode::Char('p')) => if let Some(sample) = self.sample() { //voices.write().unwrap().push(Sample::play(sample, 0, &100.into())); //}, @@ -133,37 +153,6 @@ audio!(|self: SamplerTui, _client, scope|{ Control::Continue }); -render!(|self: SamplerTui|Tui::min_y(10, Fill::wh(lay!([ - - Fill::wh(render(|to|{ // border - let [x, y, w, h] = to.area(); - let green = Some(Style::default().fg(Color::Green)); - to.blit(&"🭚", x, y, green); - to.blit(&"🭥", x + w.saturating_sub(1), y, green); - to.blit(&"🬿", x, y + h.saturating_sub(1), green); - to.blit(&"🭊", x + w.saturating_sub(1), y + h.saturating_sub(1), green); - Ok(()) - })), - - col!(|add|{ - add(&Tui::push_x(2, row!([ - Tui::bold(true, "Sampler"), "|Voices: ", - &format!("{}", self.state.voices.read().unwrap().len()), - ])))?; - if let Some(SamplerMode::Import(_, browser)) = self.mode.as_ref() { - add(&browser) - } else { - add(&row!([ - " ", - col!(note in 35..=42 => { - &format!("{note:>3} ---------------- +0.0dB") - }), - ])) - } - }), - -])))); - pub struct AddSampleModal { exited: bool, dir: PathBuf, diff --git a/crates/tek/src/tui/piano_h.rs b/crates/tek/src/tui/piano_h.rs index f28639fc..867210b9 100644 --- a/crates/tek/src/tui/piano_h.rs +++ b/crates/tek/src/tui/piano_h.rs @@ -1,9 +1,15 @@ use crate::*; use super::*; -mod piano_h_cursor; use self::piano_h_cursor::*; -mod piano_h_keys; use self::piano_h_keys::*; +mod piano_h_cursor; +use self::piano_h_cursor::*; + +mod piano_h_keys; +pub(crate) use self::piano_h_keys::*; +pub use self::piano_h_keys::render_keys_v; + mod piano_h_notes; use self::piano_h_notes::*; + mod piano_h_time; use self::piano_h_time::*; pub(crate) fn note_y_iter (note_lo: usize, note_hi: usize, y0: u16) -> impl Iterator { @@ -46,11 +52,11 @@ impl PianoHorizontal { } render!(|self: PianoHorizontal|{ + let keys_width = 5; let keys = move||PianoHorizontalKeys(self); let timeline = move||PianoHorizontalTimeline(self); let notes = move||PianoHorizontalNotes(self); let cursor = move||PianoHorizontalCursor(self); - let keys_width = 5; let border = Fill::wh(Outer(Style::default().fg(self.color.dark.rgb).bg(self.color.darkest.rgb))); let with_border = |x|lay!([border, Tui::inset_xy(1, 1, &x)]); with_border(Fill::wh(Bsp::s( diff --git a/crates/tek/src/tui/piano_h/piano_h_keys.rs b/crates/tek/src/tui/piano_h/piano_h_keys.rs index 91bc29a3..1a80ece6 100644 --- a/crates/tek/src/tui/piano_h/piano_h_keys.rs +++ b/crates/tek/src/tui/piano_h/piano_h_keys.rs @@ -2,11 +2,14 @@ use crate::*; use super::note_y_iter; pub struct PianoHorizontalKeys<'a>(pub(crate) &'a PianoHorizontal); -render!(|self: PianoHorizontalKeys<'a>|render(|to|Ok({ - let color = self.0.color; - let note_lo = self.0.note_lo().get(); - let note_hi = self.0.note_hi(); - let note_point = self.0.note_point(); +render!(|self: PianoHorizontalKeys<'a>|render(|to|Ok(render_keys_v(to, self)))); +has_color!(|self: PianoHorizontalKeys<'a>|self.0.color); + +pub fn render_keys_v (to: &mut E::Output, state: &T) { + let color = state.color(); + let note_lo = state.note_lo().get(); + let note_hi = state.note_hi(); + let note_point = state.note_point(); let [x, y0, w, h] = to.area().xywh(); let key_style = Some(Style::default().fg(Color::Rgb(192, 192, 192)).bg(Color::Rgb(0, 0, 0))); let off_style = Some(Style::default().fg(TuiTheme::g(160))); @@ -22,17 +25,7 @@ render!(|self: PianoHorizontalKeys<'a>|render(|to|Ok({ to.blit(&to_note_name(note), x, screen_y, off_style) }; } - //let debug = false; - //if debug { - //to.blit(&format!("XYU"), x, y0, None); - //to.blit(&format!("x={x}"), x, y0+1, None); - //to.blit(&format!("y0={y0}"), x, y0+2, None); - //to.blit(&format!("w={w}"), x, y0+3, None); - //to.blit(&format!("h={h}"), x, y0+4, None); - //to.blit(&format!("note_lo={note_lo}"), x, y0+5, None); - //to.blit(&format!("note_hi={note_hi}"), x, y0+6, None); - //} -}))); +} fn to_key (note: usize) -> &'static str { match note % 12 {