diff --git a/crates/tek/src/core.rs b/crates/tek/src/core.rs index b23e43b1..621074be 100644 --- a/crates/tek/src/core.rs +++ b/crates/tek/src/core.rs @@ -14,9 +14,9 @@ pub use self::{ /// Prototypal case of implementor macro. /// Saves 4loc per data pats. #[macro_export] macro_rules! from { - (|$self:ident: $Source:ty| $Target:ty = $cb:expr) => { - impl From<$Source> for $Target { - fn from (state: $Source) -> Self { $cb } + ($(<$lt:lifetime>)?|$state:ident:$Source:ty|$Target:ty=$cb:expr) => { + impl $(<$lt>)? From<$Source> for $Target { + fn from ($state:$Source) -> Self { $cb } } }; } diff --git a/crates/tek/src/core/color.rs b/crates/tek/src/core/color.rs index 81041984..0c96d043 100644 --- a/crates/tek/src/core/color.rs +++ b/crates/tek/src/core/color.rs @@ -25,13 +25,10 @@ pub struct ItemPalette { pub darkest: ItemColor, } /// Adds TUI RGB representation to an OKHSL value. -impl From> for ItemColor { - fn from (okhsl: Okhsl) -> Self { Self { okhsl, rgb: okhsl_to_rgb(okhsl) } } -} +from!(|okhsl: Okhsl|ItemColor = Self { okhsl, rgb: okhsl_to_rgb(okhsl) }); /// Adds OKHSL representation to a TUI RGB value. -impl From for ItemColor { - fn from (rgb: Color) -> Self { Self { rgb, okhsl: rgb_to_okhsl(rgb) } } -} +from!(|rgb: Color|ItemColor = Self { rgb, okhsl: rgb_to_okhsl(rgb) }); +// A single color within item theme parameters, in OKHSL and RGB representations. impl ItemColor { pub fn random () -> Self { let mut rng = thread_rng(); diff --git a/crates/tek/src/midi.rs b/crates/tek/src/midi.rs index 9e8ff123..22300e80 100644 --- a/crates/tek/src/midi.rs +++ b/crates/tek/src/midi.rs @@ -101,7 +101,6 @@ pub struct PhrasePlayerModel { /// MIDI output buffer pub note_buf: Vec, } - impl std::fmt::Debug for PhrasePlayerModel { fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { f.debug_struct("PhrasePlayerModel") @@ -111,34 +110,26 @@ impl std::fmt::Debug for PhrasePlayerModel { .finish() } } - -impl From<&ClockModel> for PhrasePlayerModel { - fn from (clock: &ClockModel) -> Self { - Self { - clock: clock.clone(), - midi_ins: vec![], - midi_outs: vec![], - note_buf: vec![0;8], - reset: true, - recording: false, - monitoring: false, - overdub: false, - play_phrase: None, - next_phrase: None, - notes_in: RwLock::new([false;128]).into(), - notes_out: RwLock::new([false;128]).into(), - } - } -} - -impl From<(&ClockModel, &Arc>)> for PhrasePlayerModel { - fn from ((clock, phrase): (&ClockModel, &Arc>)) -> Self { - let mut model = Self::from(clock); - model.play_phrase = Some((Moment::zero(&clock.timebase), Some(phrase.clone()))); - model - } -} - +from!(|clock: &ClockModel| PhrasePlayerModel = Self { + clock: clock.clone(), + midi_ins: vec![], + midi_outs: vec![], + note_buf: vec![0;8], + reset: true, + recording: false, + monitoring: false, + overdub: false, + play_phrase: None, + next_phrase: None, + notes_in: RwLock::new([false;128]).into(), + notes_out: RwLock::new([false;128]).into(), +}); +from!(|state: (&ClockModel, &Arc>)|PhrasePlayerModel = { + let (clock, phrase) = state; + let mut model = Self::from(clock); + model.play_phrase = Some((Moment::zero(&clock.timebase), Some(phrase.clone()))); + model +}); has_clock!(|self:PhrasePlayerModel|&self.clock); impl HasMidiIns for PhrasePlayerModel { diff --git a/crates/tek/src/midi/midi_note.rs b/crates/tek/src/midi/midi_note.rs index abbc4bc0..408bfddb 100644 --- a/crates/tek/src/midi/midi_note.rs +++ b/crates/tek/src/midi/midi_note.rs @@ -1,6 +1,5 @@ use crate::*; use Ordering::Relaxed; - pub trait MidiViewport: MidiRange + MidiPoint + HasSize { /// Make sure cursor is within range fn autoscroll (&self) { @@ -17,8 +16,11 @@ pub trait MidiViewport: MidiRange + MidiPoint + HasSize { /// Make sure best usage of screen space is achieved by default fn autozoom (&self) { } + fn autozoom_n (&self) { + } + fn autozoom_t (&self) { + } } - #[derive(Debug, Clone)] pub struct MidiRangeModel { /// Length of visible time axis @@ -34,18 +36,14 @@ pub struct MidiRangeModel { // Lowest note displayed pub note_lo: Arc, } -impl From<(usize, bool)> for MidiRangeModel { - fn from ((time_zoom, time_lock): (usize, bool)) -> Self { - Self { - note_axis: Arc::new(0.into()), - note_lo: Arc::new(0.into()), - time_axis: Arc::new(0.into()), - time_start: Arc::new(0.into()), - time_zoom: Arc::new(time_zoom.into()), - time_lock: Arc::new(time_lock.into()), - } - } -} +from!(|data:(usize, bool)|MidiRangeModel = Self { + note_axis: Arc::new(0.into()), + note_lo: Arc::new(0.into()), + time_axis: Arc::new(0.into()), + time_start: Arc::new(0.into()), + time_zoom: Arc::new(data.0.into()), + time_lock: Arc::new(data.1.into()), +}); pub trait MidiRange { fn time_zoom (&self) -> usize; fn set_time_zoom (&mut self, x: usize); diff --git a/crates/tek/src/plugin.rs b/crates/tek/src/plugin.rs index 086f17bf..efbe4cd0 100644 --- a/crates/tek/src/plugin.rs +++ b/crates/tek/src/plugin.rs @@ -76,13 +76,7 @@ impl Plugin { } pub struct PluginAudio(Arc>); - -impl From<&Arc>> for PluginAudio { - fn from (model: &Arc>) -> Self { - Self(model.clone()) - } -} - +from!(|model: &Arc>| PluginAudio = Self(model.clone())); audio!(|self: PluginAudio, client_, _scope|{ let state = &mut*self.0.write().unwrap(); match state.plugin.as_mut() { diff --git a/crates/tek/src/tui/arranger_mode_v.rs b/crates/tek/src/tui/arranger_mode_v.rs index 0af95251..1a6c4608 100644 --- a/crates/tek/src/tui/arranger_mode_v.rs +++ b/crates/tek/src/tui/arranger_mode_v.rs @@ -5,7 +5,7 @@ pub struct ArrangerVColSep { scenes_w: u16, sep_fg: Color, } -from!(|source:&ArrangerTui|ArrangerVColSep = Self { +from!(|state:&ArrangerTui|ArrangerVColSep = Self { cols: track_widths(state.tracks()), scenes_w: 3 + ArrangerScene::longest_name(state.scenes()) as u16, sep_fg: TuiTheme::separator_fg(false), @@ -139,7 +139,7 @@ pub struct ArrangerVHead<'a> { timebase: &'a Arc, current: &'a Arc, } -from!(<'a>|state: &'a ArrangerTui|ArrangerVHead<'a>, { // A +from!(<'a>|state: &'a ArrangerTui|ArrangerVHead<'a> = Self { // A tracks: &state.tracks, cols: track_widths(state.tracks()), focused: true, @@ -149,22 +149,6 @@ from!(<'a>|state: &'a ArrangerTui|ArrangerVHead<'a>, { // A timebase: state.clock().timebase(), current: &state.clock().playhead, }); - -impl<'a> From<&'a ArrangerTui> for ArrangerVHead<'a> { // B - fn from (state: &'a ArrangerTui) -> Self { - Self { - tracks: &state.tracks, - cols: track_widths(state.tracks()), - focused: true, - selected: state.selected, - scenes_w: 3 + ArrangerScene::longest_name(state.scenes()) as u16, - header_h: 3, - timebase: state.clock().timebase(), - current: &state.clock().playhead, - } - } -} - render!(|self: ArrangerVHead<'a>|row!( (track, w) in self.tracks.iter().zip(self.cols.iter().map(|col|col.0)) => { diff --git a/crates/tek/src/tui/status_bar.rs b/crates/tek/src/tui/status_bar.rs index 05f47c3e..6b67e352 100644 --- a/crates/tek/src/tui/status_bar.rs +++ b/crates/tek/src/tui/status_bar.rs @@ -41,23 +41,19 @@ impl Bar for SequencerStatus { todo!() } } - -impl From<&SequencerTui> for SequencerStatus { - fn from (state: &SequencerTui) -> Self { - let samples = state.clock.chunk.load(Ordering::Relaxed); - let rate = state.clock.timebase.sr.get() as f64; - let buffer = samples as f64 / rate; - let width = state.size.w(); - Self { - width, - playing: state.clock.is_rolling(), - cpu: state.perf.percentage().map(|cpu|format!("│{cpu:.01}%")), - size: format!("{}x{}│", width, state.size.h()), - res: format!("│{}s│{:.1}kHz│{:.1}ms│", samples, rate / 1000., buffer * 1000.), - } +from!(|state:&SequencerTui|SequencerStatus = { + let samples = state.clock.chunk.load(Ordering::Relaxed); + let rate = state.clock.timebase.sr.get() as f64; + let buffer = samples as f64 / rate; + let width = state.size.w(); + Self { + width, + playing: state.clock.is_rolling(), + cpu: state.perf.percentage().map(|cpu|format!("│{cpu:.01}%")), + size: format!("{}x{}│", width, state.size.h()), + res: format!("│{}s│{:.1}kHz│{:.1}ms│", samples, rate / 1000., buffer * 1000.), } -} - +}); render!(|self: SequencerStatus|Fixed::h(2, lay!([ { let single = |binding, command|row!([" ", col!([