From 42e2ef2a5098aeee5255216006d2df5c8b39fbbd Mon Sep 17 00:00:00 2001 From: unspeaker Date: Thu, 2 Jan 2025 16:01:40 +0100 Subject: [PATCH] use Command::delegate, extract SamplerStatus --- src/clock/clock_tui.rs | 2 +- src/groovebox.rs | 85 +++++++++++++++++------------------ src/sampler.rs | 30 ++++--------- src/sampler/sampler_status.rs | 9 ++++ 4 files changed, 58 insertions(+), 68 deletions(-) create mode 100644 src/sampler/sampler_status.rs diff --git a/src/clock/clock_tui.rs b/src/clock/clock_tui.rs index c3a6d747..6d866858 100644 --- a/src/clock/clock_tui.rs +++ b/src/clock/clock_tui.rs @@ -96,7 +96,7 @@ impl OutputStats { format!("{:.0}Hz", rate) }, buffer_size: format!("{chunk}"), - latency: format!("{}", chunk as f64 / rate * 1000.), + latency: format!("{:.3}ms", chunk as f64 / rate * 1000.), } } } diff --git a/src/groovebox.rs b/src/groovebox.rs index 6196f87e..cc19d5ab 100644 --- a/src/groovebox.rs +++ b/src/groovebox.rs @@ -102,7 +102,7 @@ render!(Tui: (self: Groovebox) => { let w = self.size.w(); let phrase_w = if w > 60 { 20 } else if w > 40 { 15 } else { 10 }; let pool_w = if self.pool.visible { phrase_w } else { 0 }; - let sampler_w = if self.pool.visible { phrase_w } else { 0 }; + let sampler_w = if self.pool.visible { phrase_w } else { 4 }; let sample_h = if self.pool.visible { 8 } else { 0 }; let note_pt = self.editor.note_point(); let color = self.player.play_phrase().as_ref() @@ -120,35 +120,32 @@ render!(Tui: (self: Groovebox) => { ))), ))), Bsp::n( - Bsp::s( - Fixed::y(1, self.sampler.mapped[note_pt].as_ref().map(|sample|format!( - "Sample {}-{}", - sample.read().unwrap().start, - sample.read().unwrap().end, - ))), - Bsp::a( - Outer(Style::default().fg(TuiTheme::g(128))), - Fill::x(Fixed::y(sample_h, if let Some((_, sample)) = &self.sampler.recording { - SampleViewer(Some(sample.clone())) - } else if let Some(sample) = &self.sampler.mapped[note_pt] { - SampleViewer(Some(sample.clone())) - } else { - SampleViewer(None) - })), - ), + Bsp::a( + Outer(Style::default().fg(TuiTheme::g(128))), + Fill::x(Fixed::y(sample_h, if let Some((_, sample)) = &self.sampler.recording { + SampleViewer(Some(sample.clone())) + } else if let Some(sample) = &self.sampler.mapped[note_pt] { + SampleViewer(Some(sample.clone())) + } else { + SampleViewer(None) + })), ), - Bsp::w( - Fixed::x(pool_w, Align::e(Fill::y(PoolView(&self.pool)))), - Fill::xy(Bsp::e( - Fixed::x(sampler_w, sampler), - Bsp::s( - selector, - Bsp::n( - MidiEditStatus(&self.editor), - &self.editor, + Bsp::n( + Bsp::e( + Fixed::y(1, SamplerStatus(&self.sampler, note_pt)), + MidiEditStatus(&self.editor), + ), + Bsp::w( + Fixed::x(pool_w, Align::e(Fill::y(PoolView(&self.pool)))), + Fill::xy(Bsp::e( + Fixed::x(sampler_w, sampler), + Bsp::s( + selector, + &self.editor, + ), ), - ), - )) + ) + ), ) ) )) @@ -215,39 +212,37 @@ input_to_command!(GrooveboxCommand: |state: Groovebox, input|match input.ev }); command!(|self: GrooveboxCommand, state: Groovebox|match self { + Self::History(delta) => { + todo!("undo/redo") + }, + Self::Enqueue(phrase) => { + state.player.enqueue_next(phrase.as_ref()); + None + }, Self::Pool(cmd) => { - let mut default = |cmd: PoolCommand|cmd - .execute(&mut state.pool) - .map(|x|x.map(Self::Pool)); match cmd { // autoselect: automatically load selected phrase in editor PoolCommand::Select(_) => { - let undo = default(cmd)?; + let undo = cmd.delegate(&mut state.pool, Self::Pool)?; state.editor.set_phrase(Some(state.pool.phrase())); undo }, // update color in all places simultaneously PoolCommand::Phrase(SetColor(index, _)) => { - let undo = default(cmd)?; + let undo = cmd.delegate(&mut state.pool, Self::Pool)?; state.editor.set_phrase(Some(state.pool.phrase())); undo }, - _ => default(cmd)? + _ => cmd.delegate(&mut state.pool, Self::Pool)? } }, Self::Editor(cmd) => { - let default = ||cmd.execute(&mut state.editor).map(|x|x.map(Self::Editor)); - match cmd { - _ => default()? - } + cmd.delegate(&mut state.editor, Self::Editor)? }, - Self::Clock(cmd) => cmd.execute(state)?.map(Self::Clock), - Self::Sampler(cmd) => cmd.execute(&mut state.sampler)?.map(Self::Sampler), - Self::Enqueue(phrase) => { - state.player.enqueue_next(phrase.as_ref()); - None + Self::Clock(cmd) => { + cmd.delegate(state, Self::Clock)? }, - Self::History(delta) => { - todo!("undo/redo") + Self::Sampler(cmd) => { + cmd.delegate(&mut state.sampler, Self::Sampler)? }, }); diff --git a/src/sampler.rs b/src/sampler.rs index 3e0ec2e7..5e6e23cd 100644 --- a/src/sampler.rs +++ b/src/sampler.rs @@ -1,3 +1,11 @@ +mod sample; pub use self::sample::*; +mod voice; pub use self::voice::*; +mod sampler_tui; pub use self::sampler_tui::*; +mod sampler_status; pub use self::sampler_status::*; +mod sample_import; pub use self::sample_import::*; +mod sample_list; pub use self::sample_list::*; +mod sample_viewer; pub use self::sample_viewer::*; + use crate::*; use KeyCode::Char; use std::fs::File; @@ -13,28 +21,6 @@ use symphonia::{ default::get_codecs, }; -pub mod sample; -pub(crate) use self::sample::*; -pub use self::sample::Sample; - -pub mod voice; -pub(crate) use self::voice::*; -pub use self::voice::Voice; - -pub mod sampler_tui; -pub(crate) use self::sampler_tui::*; -pub use self::sampler_tui::SamplerTui; - -pub mod sample_import; -pub(crate) use self::sample_import::*; - -pub mod sample_list; -pub(crate) use self::sample_list::*; -pub use self::sample_list::SampleList; - -pub mod sample_viewer; -pub(crate) use self::sample_viewer::*; -pub use self::sample_viewer::SampleViewer; /// The sampler plugin plays sounds. #[derive(Debug)] diff --git a/src/sampler/sampler_status.rs b/src/sampler/sampler_status.rs new file mode 100644 index 00000000..a948dfb7 --- /dev/null +++ b/src/sampler/sampler_status.rs @@ -0,0 +1,9 @@ +use crate::*; + +pub struct SamplerStatus<'a>(pub &'a Sampler, pub usize); + +render!(Tui: (self: SamplerStatus<'a>) => self.0.mapped[self.1].as_ref().map(|sample|format!( + "Sample {}-{}", + sample.read().unwrap().start, + sample.read().unwrap().end, +)).unwrap_or_else(||"No sample".to_string()));