From 8b68a993bcb3b268e88e8ffb98f61dd13834237a Mon Sep 17 00:00:00 2001 From: unspeaker Date: Sun, 10 Nov 2024 23:22:26 +0100 Subject: [PATCH] wip: refactor pt.14: 138 errors --- crates/tek_api/src/arrange.rs | 2 ++ crates/tek_core/src/space.rs | 1 + crates/tek_snd/src/snd_sequencer.rs | 14 ++++++++ crates/tek_tui/src/tui_arrangement.rs | 46 +++++++++++-------------- crates/tek_tui/src/tui_pool.rs | 44 +++++++++++------------ crates/tek_tui/src/tui_sequencer.rs | 9 ----- crates/tek_tui/src/tui_sequencer_foc.rs | 12 +++---- crates/tek_tui/src/tui_transport.rs | 25 +++++--------- crates/tek_tui/src/tui_transport_cmd.rs | 42 +++++++++++----------- 9 files changed, 95 insertions(+), 100 deletions(-) diff --git a/crates/tek_api/src/arrange.rs b/crates/tek_api/src/arrange.rs index b180783c..fec23742 100644 --- a/crates/tek_api/src/arrange.rs +++ b/crates/tek_api/src/arrange.rs @@ -99,9 +99,11 @@ impl ArrangementScene { }).collect() } } + pub fn longest_name (scenes: &[Self]) -> usize { scenes.iter().map(|s|s.name.read().unwrap().len()).fold(0, usize::max) } + /// Returns the pulse length of the longest phrase in the scene pub fn pulses (&self) -> usize { self.clips.iter().fold(0, |a, p|{ diff --git a/crates/tek_core/src/space.rs b/crates/tek_core/src/space.rs index 366f588c..776bf994 100644 --- a/crates/tek_core/src/space.rs +++ b/crates/tek_core/src/space.rs @@ -872,6 +872,7 @@ impl, B: Widget> Widget for Split(PhantomData, AtomicUsize, AtomicUsize); impl Measure { diff --git a/crates/tek_snd/src/snd_sequencer.rs b/crates/tek_snd/src/snd_sequencer.rs index a7668ff9..f1918ce2 100644 --- a/crates/tek_snd/src/snd_sequencer.rs +++ b/crates/tek_snd/src/snd_sequencer.rs @@ -1,5 +1,19 @@ use crate::*; +pub struct SequencerAudio { + transport: Arc>, + player: Arc>, +} + +/// JACK process callback for sequencer app +impl Audio for SequencerAudio { + fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control { + self.transport.write().unwrap().process(client, scope); + self.player.write().unwrap().process(client, scope); + Control::Continue + } +} + pub struct MIDIPlayerAudio { model: Arc> } diff --git a/crates/tek_tui/src/tui_arrangement.rs b/crates/tek_tui/src/tui_arrangement.rs index ce1f7736..918bb75a 100644 --- a/crates/tek_tui/src/tui_arrangement.rs +++ b/crates/tek_tui/src/tui_arrangement.rs @@ -1,7 +1,7 @@ use crate::*; pub struct ArrangementEditor { - pub state: Arrangement, + pub model: Arrangement, /// Currently selected element. pub selected: ArrangementEditorFocus, /// Display mode of arranger @@ -39,12 +39,6 @@ impl ArrangementEditorMode { } } -impl Audio for ArrangementEditor { - #[inline] fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control { - self.state.process(client, scope) - } -} - impl Content for ArrangementEditor { type Engine = Tui; fn content (&self) -> impl Widget { @@ -61,9 +55,9 @@ impl Content for ArrangementEditor { } impl ArrangementEditor { - pub fn new (state: Arrangement) -> Self { + pub fn new (model: Arrangement) -> Self { Self { - state, + model, selected: ArrangementEditorFocus::Clip(0, 0), mode: ArrangementEditorMode::Vertical(2), color: Color::Rgb(28, 35, 25).into(), @@ -76,30 +70,30 @@ impl ArrangementEditor { impl ArrangementEditor { pub fn track (&self) -> Option<&ArrangementTrack> { - self.selected.track().map(|t|self.state.tracks.get(t)).flatten() + self.selected.track().map(|t|self.model.tracks.get(t)).flatten() } pub fn track_mut (&mut self) -> Option<&mut ArrangementTrack> { - self.selected.track().map(|t|self.state.tracks.get_mut(t)).flatten() + self.selected.track().map(|t|self.model.tracks.get_mut(t)).flatten() } pub fn scene (&self) -> Option<&ArrangementScene> { - self.selected.scene().map(|s|self.state.scenes.get(s)).flatten() + self.selected.scene().map(|s|self.model.scenes.get(s)).flatten() } pub fn scene_mut (&mut self) -> Option<&mut ArrangementScene> { - self.selected.scene().map(|s|self.state.scenes.get_mut(s)).flatten() + self.selected.scene().map(|s|self.model.scenes.get_mut(s)).flatten() } pub fn phrase (&self) -> Option>> { self.scene()?.clips.get(self.selected.track()?)?.clone() } pub fn track_del (&mut self) { - if let Some(index) = self.selected.track() { self.state.track_del(index); } + if let Some(index) = self.selected.track() { self.model.track_del(index); } } pub fn scene_del (&mut self) { - if let Some(index) = self.selected.scene() { self.state.scene_del(index); } + if let Some(index) = self.selected.scene() { self.model.scene_del(index); } } pub fn track_widths (&self) -> Vec<(usize, usize)> { let mut widths = vec![]; let mut total = 0; - for track in self.tracks.iter() { + for track in self.model.tracks.iter() { let width = track.width; widths.push((width, total)); total += width; @@ -111,20 +105,22 @@ impl ArrangementEditor { let track_index = self.selected.track(); let scene_index = self.selected.scene(); track_index - .and_then(|index|self.tracks.get_mut(index).map(|track|(index, track))) + .and_then(|index|self.model.tracks.get_mut(index).map(|track|(index, track))) .map(|(track_index, _)|scene_index - .and_then(|index|self.scenes.get_mut(index)) + .and_then(|index|self.model.scenes.get_mut(index)) .map(|scene|scene.clips[track_index] = None)); } pub fn phrase_put (&mut self) { if let ArrangementEditorFocus::Clip(track, scene) = self.selected { - self.scenes[scene].clips[track] = Some(self.phrases.read().unwrap().phrase().clone()); + self.model.scenes[scene].clips[track] = Some( + self.model.phrases.read().unwrap().phrase().clone() + ); } } pub fn phrase_get (&mut self) { if let ArrangementEditorFocus::Clip(track, scene) = self.selected { - if let Some(phrase) = &self.scenes[scene].clips[track] { - let mut phrases = self.phrases.write().unwrap(); + if let Some(phrase) = &self.model.scenes[scene].clips[track] { + let mut phrases = self.model.phrases.write().unwrap(); if let Some(index) = phrases.index_of(&*phrase.read().unwrap()) { phrases.phrase = index; } @@ -133,8 +129,8 @@ impl ArrangementEditor { } pub fn phrase_next (&mut self) { if let ArrangementEditorFocus::Clip(track, scene) = self.selected { - if let Some(ref mut phrase) = self.scenes[scene].clips[track] { - let phrases = self.phrases.read().unwrap(); + if let Some(ref mut phrase) = self.model.scenes[scene].clips[track] { + let phrases = self.model.phrases.read().unwrap(); let index = phrases.index_of(&*phrase.read().unwrap()); if let Some(index) = index { if index < phrases.phrases.len().saturating_sub(1) { @@ -146,8 +142,8 @@ impl ArrangementEditor { } pub fn phrase_prev (&mut self) { if let ArrangementEditorFocus::Clip(track, scene) = self.selected { - if let Some(ref mut phrase) = self.scenes[scene].clips[track] { - let phrases = self.phrases.read().unwrap(); + if let Some(ref mut phrase) = self.model.scenes[scene].clips[track] { + let phrases = self.model.phrases.read().unwrap(); let index = phrases.index_of(&*phrase.read().unwrap()); if let Some(index) = index { if index > 0 { diff --git a/crates/tek_tui/src/tui_pool.rs b/crates/tek_tui/src/tui_pool.rs index 36f81e40..b6988dbb 100644 --- a/crates/tek_tui/src/tui_pool.rs +++ b/crates/tek_tui/src/tui_pool.rs @@ -2,7 +2,7 @@ use crate::*; pub struct PhrasePoolView { _engine: PhantomData, - pub state: PhrasePool, + pub model: PhrasePool, /// Selected phrase pub phrase: usize, /// Scroll offset @@ -24,7 +24,7 @@ pub enum PhrasePoolMode { } impl PhrasePoolView { - pub fn new (state: PhrasePool) -> Self { + pub fn new (model: PhrasePool) -> Self { Self { _engine: Default::default(), scroll: 0, @@ -32,14 +32,14 @@ impl PhrasePoolView { mode: None, focused: false, entered: false, - state, + model, } } pub fn len (&self) -> usize { - self.state.phrases.len() + self.model.phrases.len() } pub fn phrase (&self) -> &Arc> { - &self.state.phrases[self.phrase] + &self.model.phrases[self.phrase] } pub fn index_before (&self, index: usize) -> usize { index.overflowing_sub(1).0.min(self.len() - 1) @@ -48,8 +48,8 @@ impl PhrasePoolView { (index + 1) % self.len() } pub fn index_of (&self, phrase: &Phrase) -> Option { - for i in 0..self.state.phrases.len() { - if *self.state.phrases[i].read().unwrap() == *phrase { return Some(i) } + for i in 0..self.model.phrases.len() { + if *self.model.phrases[i].read().unwrap() == *phrase { return Some(i) } } return None } @@ -60,46 +60,46 @@ impl PhrasePoolView { } pub fn delete_selected (&mut self) { if self.phrase > 0 { - self.state.phrases.remove(self.phrase); - self.phrase = self.phrase.min(self.state.phrases.len().saturating_sub(1)); + self.model.phrases.remove(self.phrase); + self.phrase = self.phrase.min(self.model.phrases.len().saturating_sub(1)); } } pub fn append_new (&mut self, name: Option<&str>, color: Option) { - self.state.phrases.push(Self::new_phrase(name, color)); - self.phrase = self.state.phrases.len() - 1; + self.model.phrases.push(Self::new_phrase(name, color)); + self.phrase = self.model.phrases.len() - 1; } pub fn insert_new (&mut self, name: Option<&str>, color: Option) { - self.state.phrases.insert(self.phrase + 1, Self::new_phrase(name, color)); + self.model.phrases.insert(self.phrase + 1, Self::new_phrase(name, color)); self.phrase += 1; } pub fn insert_dup (&mut self) { - let mut phrase = self.state.phrases[self.phrase].read().unwrap().duplicate(); + let mut phrase = self.model.phrases[self.phrase].read().unwrap().duplicate(); phrase.color = ItemColorTriplet::random_near(phrase.color, 0.25); - self.state.phrases.insert(self.phrase + 1, Arc::new(RwLock::new(phrase))); + self.model.phrases.insert(self.phrase + 1, Arc::new(RwLock::new(phrase))); self.phrase += 1; } pub fn begin_rename (&mut self) { self.mode = Some(PhrasePoolMode::Rename( self.phrase, - self.state.phrases[self.phrase].read().unwrap().name.clone() + self.model.phrases[self.phrase].read().unwrap().name.clone() )); } pub fn begin_length (&mut self) { self.mode = Some(PhrasePoolMode::Length( self.phrase, - self.state.phrases[self.phrase].read().unwrap().length, + self.model.phrases[self.phrase].read().unwrap().length, PhraseLengthFocus::Bar )); } pub fn move_up (&mut self) { if self.phrase > 1 { - self.state.phrases.swap(self.phrase - 1, self.phrase); + self.model.phrases.swap(self.phrase - 1, self.phrase); self.phrase -= 1; } } pub fn move_down (&mut self) { - if self.phrase < self.state.phrases.len().saturating_sub(1) { - self.state.phrases.swap(self.phrase + 1, self.phrase); + if self.phrase < self.model.phrases.len().saturating_sub(1) { + self.model.phrases.swap(self.phrase + 1, self.phrase); self.phrase += 1; } } @@ -109,9 +109,9 @@ impl PhrasePoolView { impl Content for PhrasePoolView { type Engine = Tui; fn content (&self) -> impl Widget { - let Self { focused, state, mode, .. } = self; + let Self { focused, model, mode, .. } = self; let content = col!( - (i, phrase) in state.iter().enumerate() => Layers::new(|add|{ + (i, phrase) in model.phrases.iter().enumerate() => Layers::new(|add|{ let Phrase { ref name, color, length, .. } = *phrase.read().unwrap(); let mut length = PhraseLength::new(length, None); if let Some(PhrasePoolMode::Length(phrase, new_length, focus)) = mode { @@ -136,7 +136,7 @@ impl Content for PhrasePoolView { let content = content.fill_xy().bg(Color::Rgb(28, 35, 25)).border(border); let title_color = if *focused {Color::Rgb(150, 160, 90)} else {Color::Rgb(120, 130, 100)}; let upper_left = format!("[{}] Phrases", if self.entered {"■"} else {" "}); - let upper_right = format!("({})", state.len()); + let upper_right = format!("({})", model.phrases.len()); lay!( content, TuiStyle::fg(upper_left.to_string(), title_color).push_x(1).align_nw().fill_xy(), diff --git a/crates/tek_tui/src/tui_sequencer.rs b/crates/tek_tui/src/tui_sequencer.rs index f34fd87d..2e5d78a3 100644 --- a/crates/tek_tui/src/tui_sequencer.rs +++ b/crates/tek_tui/src/tui_sequencer.rs @@ -15,15 +15,6 @@ pub struct SequencerView { pub player: MIDIPlayer, } -/// JACK process callback for sequencer app -impl Audio for SequencerView { - fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control { - self.transport.process(client, scope); - self.player.process(client, scope); - Control::Continue - } -} - impl Content for SequencerView { type Engine = Tui; fn content (&self) -> impl Widget { diff --git a/crates/tek_tui/src/tui_sequencer_foc.rs b/crates/tek_tui/src/tui_sequencer_foc.rs index fb763f4c..38e11534 100644 --- a/crates/tek_tui/src/tui_sequencer_foc.rs +++ b/crates/tek_tui/src/tui_sequencer_foc.rs @@ -14,10 +14,10 @@ use crate::*; impl FocusGrid for SequencerView { type Item = SequencerFocus; fn cursor (&self) -> (usize, usize) { - self.focus_cursor + self.cursor } fn cursor_mut (&mut self) -> &mut (usize, usize) { - &mut self.focus_cursor + &mut self.cursor } fn layout (&self) -> &[&[SequencerFocus]] { &[ &[SequencerFocus::Transport], @@ -34,10 +34,8 @@ impl FocusGrid for SequencerView { } fn update_focus (&mut self) { let focused = self.focused(); - if let Some(transport) = self.transport.as_ref() { - transport.write().unwrap().focused = focused == SequencerFocus::Transport - } - self.phrases.write().unwrap().focused = focused == SequencerFocus::PhrasePool; - self.editor.focused = focused == SequencerFocus::PhraseEditor; + self.transport.focused = focused == SequencerFocus::Transport; + self.phrases.focused = focused == SequencerFocus::PhrasePool; + self.editor.focused = focused == SequencerFocus::PhraseEditor; } } diff --git a/crates/tek_tui/src/tui_transport.rs b/crates/tek_tui/src/tui_transport.rs index 8b67ea4e..5f8d9db6 100644 --- a/crates/tek_tui/src/tui_transport.rs +++ b/crates/tek_tui/src/tui_transport.rs @@ -1,31 +1,24 @@ use crate::*; use tek_api::Transport; -/// Stores and displays time-related state. +/// Stores and displays time-related info. #[derive(Debug)] pub struct TransportView { _engine: PhantomData, - pub state: Transport, + pub model: Transport, pub focus: TransportViewFocus, pub focused: bool, pub size: Measure, } -/// JACK process callback for transport app -impl Audio for TransportView { - fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control { - self.state.process(client, scope); - Control::Continue - } -} - impl TransportView { pub fn new (jack: &Arc>, clock: Option<&Arc>) -> Self { Self { _engine: Default::default(), focused: false, focus: TransportViewFocus::PlayPause, - state: Transport { + size: Measure::new(), + model: Transport { metronome: false, transport: jack.read().unwrap().transport(), jack: jack.clone(), @@ -53,7 +46,7 @@ impl Content for TransportView { lay!( self.focus.wrap(self.focused, TransportViewFocus::PlayPause, &Styled( None, - match *self.clock.playing.read().unwrap() { + match *self.model.clock.playing.read().unwrap() { Some(TransportState::Rolling) => "▶ PLAYING", Some(TransportState::Starting) => "READY ...", Some(TransportState::Stopped) => "⏹ STOPPED", @@ -63,20 +56,20 @@ impl Content for TransportView { row!( self.focus.wrap(self.focused, TransportViewFocus::Bpm, &Outset::X(1u16, { - let bpm = self.clock.timebase().bpm.get(); + let bpm = self.model.clock.timebase().bpm.get(); row! { "BPM ", format!("{}.{:03}", bpm as usize, (bpm * 1000.0) % 1000.0) } })), //let quant = self.focus.wrap(self.focused, TransportViewFocus::Quant, &Outset::X(1u16, row! { //"QUANT ", ppq_to_name(self.quant as usize) //})), self.focus.wrap(self.focused, TransportViewFocus::Sync, &Outset::X(1u16, row! { - "SYNC ", pulses_to_name(self.clock.sync.get() as usize) + "SYNC ", pulses_to_name(self.model.clock.sync.get() as usize) })) ).align_w().fill_x(), self.focus.wrap(self.focused, TransportViewFocus::Clock, &{ - let time1 = self.clock.current.format_beat(); - let time2 = self.clock.current.usec.format_msu(); + let time1 = self.model.clock.current.format_beat(); + let time2 = self.model.clock.current.usec.format_msu(); row!("B" ,time1.as_str(), " T", time2.as_str()).outset_x(1) }).align_e().fill_x(), diff --git a/crates/tek_tui/src/tui_transport_cmd.rs b/crates/tek_tui/src/tui_transport_cmd.rs index e1f70ca5..6e623f7f 100644 --- a/crates/tek_tui/src/tui_transport_cmd.rs +++ b/crates/tek_tui/src/tui_transport_cmd.rs @@ -13,7 +13,7 @@ impl Handle for TransportView { } impl InputToCommand> for TransportViewCommand { - fn input_to_command (state: &TransportView, input: &TuiInput) -> Option { + fn input_to_command (view: &TransportView, input: &TuiInput) -> Option { use TransportViewFocus as Focus; use FocusCommand as FocusCmd; use TransportCommand as Cmd; @@ -22,31 +22,31 @@ impl InputToCommand> for TransportViewCommand { key!(KeyCode::Left) => Self::Focus(FocusCmd::Prev), key!(KeyCode::Right) => Self::Focus(FocusCmd::Next), - key!(KeyCode::Char('.')) => Self::Transport(match state.focus { - Focus::Bpm => Cmd::SetBpm(state.state.clock.timebase().bpm.get() + 1.0), - Focus::Quant => Cmd::SetQuant(next_note_length(state.state.clock.quant.get()as usize)as f64), - Focus::Sync => Cmd::SetSync(next_note_length(state.state.clock.sync.get()as usize)as f64+1.), + key!(KeyCode::Char('.')) => Self::Transport(match view.focus { + Focus::Bpm => Cmd::SetBpm(view.model.clock.timebase().bpm.get() + 1.0), + Focus::Quant => Cmd::SetQuant(next_note_length(view.model.clock.quant.get()as usize)as f64), + Focus::Sync => Cmd::SetSync(next_note_length(view.model.clock.sync.get()as usize)as f64+1.), Focus::PlayPause => {todo!()}, Focus::Clock => {todo!()} }), - key!(KeyCode::Char(',')) => Self::Transport(match state.focus { - Focus::Bpm => Cmd::SetBpm(state.state.clock.timebase().bpm.get() - 1.0), - Focus::Quant => Cmd::SetQuant(prev_note_length(state.state.clock.quant.get()as usize)as f64), - Focus::Sync => Cmd::SetSync(prev_note_length(state.state.clock.sync.get()as usize)as f64+1.), + key!(KeyCode::Char(',')) => Self::Transport(match view.focus { + Focus::Bpm => Cmd::SetBpm(view.model.clock.timebase().bpm.get() - 1.0), + Focus::Quant => Cmd::SetQuant(prev_note_length(view.model.clock.quant.get()as usize)as f64), + Focus::Sync => Cmd::SetSync(prev_note_length(view.model.clock.sync.get()as usize)as f64+1.), Focus::PlayPause => {todo!()}, Focus::Clock => {todo!()} }), - key!(KeyCode::Char('>')) => Self::Transport(match state.focus { - Focus::Bpm => Cmd::SetBpm(state.state.clock.timebase().bpm.get() + 0.001), - Focus::Quant => Cmd::SetQuant(next_note_length(state.state.clock.quant.get()as usize)as f64), - Focus::Sync => Cmd::SetSync(next_note_length(state.state.clock.sync.get()as usize)as f64+1.), + key!(KeyCode::Char('>')) => Self::Transport(match view.focus { + Focus::Bpm => Cmd::SetBpm(view.model.clock.timebase().bpm.get() + 0.001), + Focus::Quant => Cmd::SetQuant(next_note_length(view.model.clock.quant.get()as usize)as f64), + Focus::Sync => Cmd::SetSync(next_note_length(view.model.clock.sync.get()as usize)as f64+1.), Focus::PlayPause => {todo!()}, Focus::Clock => {todo!()} }), - key!(KeyCode::Char('<')) => Self::Transport(match state.focus { - Focus::Bpm => Cmd::SetBpm(state.state.clock.timebase().bpm.get() - 0.001), - Focus::Quant => Cmd::SetQuant(prev_note_length(state.state.clock.quant.get()as usize)as f64), - Focus::Sync => Cmd::SetSync(prev_note_length(state.state.clock.sync.get()as usize)as f64+1.), + key!(KeyCode::Char('<')) => Self::Transport(match view.focus { + Focus::Bpm => Cmd::SetBpm(view.model.clock.timebase().bpm.get() - 0.001), + Focus::Quant => Cmd::SetQuant(prev_note_length(view.model.clock.quant.get()as usize)as f64), + Focus::Sync => Cmd::SetSync(prev_note_length(view.model.clock.sync.get()as usize)as f64+1.), Focus::PlayPause => {todo!()}, Focus::Clock => {todo!()} }), @@ -57,7 +57,7 @@ impl InputToCommand> for TransportViewCommand { } impl Command> for TransportViewCommand { - fn execute (self, state: &mut TransportView) -> Perhaps { + fn execute (self, view: &mut TransportView) -> Perhaps { Ok(Some(match self { Self::Focus(command) => Self::Focus({ use FocusCommand::*; @@ -70,9 +70,9 @@ impl Command> for TransportViewCommand { Self::Transport(command) => Self::Transport({ use TransportCommand::*; match command { - SetBpm(bpm) => SetBpm(state.state.clock.timebase().bpm.set(bpm)), - SetQuant(quant) => SetQuant(state.state.clock.quant.set(quant)), - SetSync(sync) => SetSync(state.state.clock.sync.set(sync)), + SetBpm(bpm) => SetBpm(view.model.clock.timebase().bpm.set(bpm)), + SetQuant(quant) => SetQuant(view.model.clock.quant.set(quant)), + SetSync(sync) => SetSync(view.model.clock.sync.set(sync)), _ => { todo!() } } }),