wip: refactor pt.14: 138 errors

This commit is contained in:
🪞👃🪞 2024-11-10 23:22:26 +01:00
parent fbf217e108
commit 8b68a993bc
9 changed files with 95 additions and 100 deletions

View file

@ -99,9 +99,11 @@ impl ArrangementScene {
}).collect() }).collect()
} }
} }
pub fn longest_name (scenes: &[Self]) -> usize { pub fn longest_name (scenes: &[Self]) -> usize {
scenes.iter().map(|s|s.name.read().unwrap().len()).fold(0, usize::max) scenes.iter().map(|s|s.name.read().unwrap().len()).fold(0, usize::max)
} }
/// Returns the pulse length of the longest phrase in the scene /// Returns the pulse length of the longest phrase in the scene
pub fn pulses (&self) -> usize { pub fn pulses (&self) -> usize {
self.clips.iter().fold(0, |a, p|{ self.clips.iter().fold(0, |a, p|{

View file

@ -872,6 +872,7 @@ impl<E: Engine, A: Widget<Engine = E>, B: Widget<Engine = E>> Widget for Split<E
} }
/// A widget that tracks its render width and height /// A widget that tracks its render width and height
#[derive(Debug)]
pub struct Measure<E: Engine>(PhantomData<E>, AtomicUsize, AtomicUsize); pub struct Measure<E: Engine>(PhantomData<E>, AtomicUsize, AtomicUsize);
impl<E: Engine> Measure<E> { impl<E: Engine> Measure<E> {

View file

@ -1,5 +1,19 @@
use crate::*; use crate::*;
pub struct SequencerAudio {
transport: Arc<RwLock<Transport>>,
player: Arc<RwLock<MIDIPlayer>>,
}
/// 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 { pub struct MIDIPlayerAudio {
model: Arc<RwLock<MIDIPlayer>> model: Arc<RwLock<MIDIPlayer>>
} }

View file

@ -1,7 +1,7 @@
use crate::*; use crate::*;
pub struct ArrangementEditor<E: Engine> { pub struct ArrangementEditor<E: Engine> {
pub state: Arrangement, pub model: Arrangement,
/// Currently selected element. /// Currently selected element.
pub selected: ArrangementEditorFocus, pub selected: ArrangementEditorFocus,
/// Display mode of arranger /// Display mode of arranger
@ -39,12 +39,6 @@ impl ArrangementEditorMode {
} }
} }
impl<E: Engine> Audio for ArrangementEditor<E> {
#[inline] fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control {
self.state.process(client, scope)
}
}
impl Content for ArrangementEditor<Tui> { impl Content for ArrangementEditor<Tui> {
type Engine = Tui; type Engine = Tui;
fn content (&self) -> impl Widget<Engine = Tui> { fn content (&self) -> impl Widget<Engine = Tui> {
@ -61,9 +55,9 @@ impl Content for ArrangementEditor<Tui> {
} }
impl<E: Engine> ArrangementEditor<E> { impl<E: Engine> ArrangementEditor<E> {
pub fn new (state: Arrangement) -> Self { pub fn new (model: Arrangement) -> Self {
Self { Self {
state, model,
selected: ArrangementEditorFocus::Clip(0, 0), selected: ArrangementEditorFocus::Clip(0, 0),
mode: ArrangementEditorMode::Vertical(2), mode: ArrangementEditorMode::Vertical(2),
color: Color::Rgb(28, 35, 25).into(), color: Color::Rgb(28, 35, 25).into(),
@ -76,30 +70,30 @@ impl<E: Engine> ArrangementEditor<E> {
impl<E: Engine> ArrangementEditor<E> { impl<E: Engine> ArrangementEditor<E> {
pub fn track (&self) -> Option<&ArrangementTrack> { 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> { 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> { 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> { 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<Arc<RwLock<Phrase>>> { pub fn phrase (&self) -> Option<Arc<RwLock<Phrase>>> {
self.scene()?.clips.get(self.selected.track()?)?.clone() self.scene()?.clips.get(self.selected.track()?)?.clone()
} }
pub fn track_del (&mut self) { 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) { 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)> { pub fn track_widths (&self) -> Vec<(usize, usize)> {
let mut widths = vec![]; let mut widths = vec![];
let mut total = 0; let mut total = 0;
for track in self.tracks.iter() { for track in self.model.tracks.iter() {
let width = track.width; let width = track.width;
widths.push((width, total)); widths.push((width, total));
total += width; total += width;
@ -111,20 +105,22 @@ impl<E: Engine> ArrangementEditor<E> {
let track_index = self.selected.track(); let track_index = self.selected.track();
let scene_index = self.selected.scene(); let scene_index = self.selected.scene();
track_index 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 .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)); .map(|scene|scene.clips[track_index] = None));
} }
pub fn phrase_put (&mut self) { pub fn phrase_put (&mut self) {
if let ArrangementEditorFocus::Clip(track, scene) = self.selected { 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) { pub fn phrase_get (&mut self) {
if let ArrangementEditorFocus::Clip(track, scene) = self.selected { if let ArrangementEditorFocus::Clip(track, scene) = self.selected {
if let Some(phrase) = &self.scenes[scene].clips[track] { if let Some(phrase) = &self.model.scenes[scene].clips[track] {
let mut phrases = self.phrases.write().unwrap(); let mut phrases = self.model.phrases.write().unwrap();
if let Some(index) = phrases.index_of(&*phrase.read().unwrap()) { if let Some(index) = phrases.index_of(&*phrase.read().unwrap()) {
phrases.phrase = index; phrases.phrase = index;
} }
@ -133,8 +129,8 @@ impl<E: Engine> ArrangementEditor<E> {
} }
pub fn phrase_next (&mut self) { pub fn phrase_next (&mut self) {
if let ArrangementEditorFocus::Clip(track, scene) = self.selected { if let ArrangementEditorFocus::Clip(track, scene) = self.selected {
if let Some(ref mut phrase) = self.scenes[scene].clips[track] { if let Some(ref mut phrase) = self.model.scenes[scene].clips[track] {
let phrases = self.phrases.read().unwrap(); let phrases = self.model.phrases.read().unwrap();
let index = phrases.index_of(&*phrase.read().unwrap()); let index = phrases.index_of(&*phrase.read().unwrap());
if let Some(index) = index { if let Some(index) = index {
if index < phrases.phrases.len().saturating_sub(1) { if index < phrases.phrases.len().saturating_sub(1) {
@ -146,8 +142,8 @@ impl<E: Engine> ArrangementEditor<E> {
} }
pub fn phrase_prev (&mut self) { pub fn phrase_prev (&mut self) {
if let ArrangementEditorFocus::Clip(track, scene) = self.selected { if let ArrangementEditorFocus::Clip(track, scene) = self.selected {
if let Some(ref mut phrase) = self.scenes[scene].clips[track] { if let Some(ref mut phrase) = self.model.scenes[scene].clips[track] {
let phrases = self.phrases.read().unwrap(); let phrases = self.model.phrases.read().unwrap();
let index = phrases.index_of(&*phrase.read().unwrap()); let index = phrases.index_of(&*phrase.read().unwrap());
if let Some(index) = index { if let Some(index) = index {
if index > 0 { if index > 0 {

View file

@ -2,7 +2,7 @@ use crate::*;
pub struct PhrasePoolView<E: Engine> { pub struct PhrasePoolView<E: Engine> {
_engine: PhantomData<E>, _engine: PhantomData<E>,
pub state: PhrasePool, pub model: PhrasePool,
/// Selected phrase /// Selected phrase
pub phrase: usize, pub phrase: usize,
/// Scroll offset /// Scroll offset
@ -24,7 +24,7 @@ pub enum PhrasePoolMode {
} }
impl<E: Engine> PhrasePoolView<E> { impl<E: Engine> PhrasePoolView<E> {
pub fn new (state: PhrasePool) -> Self { pub fn new (model: PhrasePool) -> Self {
Self { Self {
_engine: Default::default(), _engine: Default::default(),
scroll: 0, scroll: 0,
@ -32,14 +32,14 @@ impl<E: Engine> PhrasePoolView<E> {
mode: None, mode: None,
focused: false, focused: false,
entered: false, entered: false,
state, model,
} }
} }
pub fn len (&self) -> usize { pub fn len (&self) -> usize {
self.state.phrases.len() self.model.phrases.len()
} }
pub fn phrase (&self) -> &Arc<RwLock<Phrase>> { pub fn phrase (&self) -> &Arc<RwLock<Phrase>> {
&self.state.phrases[self.phrase] &self.model.phrases[self.phrase]
} }
pub fn index_before (&self, index: usize) -> usize { pub fn index_before (&self, index: usize) -> usize {
index.overflowing_sub(1).0.min(self.len() - 1) index.overflowing_sub(1).0.min(self.len() - 1)
@ -48,8 +48,8 @@ impl<E: Engine> PhrasePoolView<E> {
(index + 1) % self.len() (index + 1) % self.len()
} }
pub fn index_of (&self, phrase: &Phrase) -> Option<usize> { pub fn index_of (&self, phrase: &Phrase) -> Option<usize> {
for i in 0..self.state.phrases.len() { for i in 0..self.model.phrases.len() {
if *self.state.phrases[i].read().unwrap() == *phrase { return Some(i) } if *self.model.phrases[i].read().unwrap() == *phrase { return Some(i) }
} }
return None return None
} }
@ -60,46 +60,46 @@ impl<E: Engine> PhrasePoolView<E> {
} }
pub fn delete_selected (&mut self) { pub fn delete_selected (&mut self) {
if self.phrase > 0 { if self.phrase > 0 {
self.state.phrases.remove(self.phrase); self.model.phrases.remove(self.phrase);
self.phrase = self.phrase.min(self.state.phrases.len().saturating_sub(1)); self.phrase = self.phrase.min(self.model.phrases.len().saturating_sub(1));
} }
} }
pub fn append_new (&mut self, name: Option<&str>, color: Option<ItemColorTriplet>) { pub fn append_new (&mut self, name: Option<&str>, color: Option<ItemColorTriplet>) {
self.state.phrases.push(Self::new_phrase(name, color)); self.model.phrases.push(Self::new_phrase(name, color));
self.phrase = self.state.phrases.len() - 1; self.phrase = self.model.phrases.len() - 1;
} }
pub fn insert_new (&mut self, name: Option<&str>, color: Option<ItemColorTriplet>) { pub fn insert_new (&mut self, name: Option<&str>, color: Option<ItemColorTriplet>) {
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; self.phrase += 1;
} }
pub fn insert_dup (&mut self) { 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); 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; self.phrase += 1;
} }
pub fn begin_rename (&mut self) { pub fn begin_rename (&mut self) {
self.mode = Some(PhrasePoolMode::Rename( self.mode = Some(PhrasePoolMode::Rename(
self.phrase, 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) { pub fn begin_length (&mut self) {
self.mode = Some(PhrasePoolMode::Length( self.mode = Some(PhrasePoolMode::Length(
self.phrase, self.phrase,
self.state.phrases[self.phrase].read().unwrap().length, self.model.phrases[self.phrase].read().unwrap().length,
PhraseLengthFocus::Bar PhraseLengthFocus::Bar
)); ));
} }
pub fn move_up (&mut self) { pub fn move_up (&mut self) {
if self.phrase > 1 { 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; self.phrase -= 1;
} }
} }
pub fn move_down (&mut self) { pub fn move_down (&mut self) {
if self.phrase < self.state.phrases.len().saturating_sub(1) { if self.phrase < self.model.phrases.len().saturating_sub(1) {
self.state.phrases.swap(self.phrase + 1, self.phrase); self.model.phrases.swap(self.phrase + 1, self.phrase);
self.phrase += 1; self.phrase += 1;
} }
} }
@ -109,9 +109,9 @@ impl<E: Engine> PhrasePoolView<E> {
impl Content for PhrasePoolView<Tui> { impl Content for PhrasePoolView<Tui> {
type Engine = Tui; type Engine = Tui;
fn content (&self) -> impl Widget<Engine = Tui> { fn content (&self) -> impl Widget<Engine = Tui> {
let Self { focused, state, mode, .. } = self; let Self { focused, model, mode, .. } = self;
let content = col!( 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 Phrase { ref name, color, length, .. } = *phrase.read().unwrap();
let mut length = PhraseLength::new(length, None); let mut length = PhraseLength::new(length, None);
if let Some(PhrasePoolMode::Length(phrase, new_length, focus)) = mode { if let Some(PhrasePoolMode::Length(phrase, new_length, focus)) = mode {
@ -136,7 +136,7 @@ impl Content for PhrasePoolView<Tui> {
let content = content.fill_xy().bg(Color::Rgb(28, 35, 25)).border(border); 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 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_left = format!("[{}] Phrases", if self.entered {""} else {" "});
let upper_right = format!("({})", state.len()); let upper_right = format!("({})", model.phrases.len());
lay!( lay!(
content, content,
TuiStyle::fg(upper_left.to_string(), title_color).push_x(1).align_nw().fill_xy(), TuiStyle::fg(upper_left.to_string(), title_color).push_x(1).align_nw().fill_xy(),

View file

@ -15,15 +15,6 @@ pub struct SequencerView<E: Engine> {
pub player: MIDIPlayer, pub player: MIDIPlayer,
} }
/// JACK process callback for sequencer app
impl<E: Engine> Audio for SequencerView<E> {
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<Tui> { impl Content for SequencerView<Tui> {
type Engine = Tui; type Engine = Tui;
fn content (&self) -> impl Widget<Engine = Tui> { fn content (&self) -> impl Widget<Engine = Tui> {

View file

@ -14,10 +14,10 @@ use crate::*;
impl<E: Engine> FocusGrid for SequencerView<E> { impl<E: Engine> FocusGrid for SequencerView<E> {
type Item = SequencerFocus; type Item = SequencerFocus;
fn cursor (&self) -> (usize, usize) { fn cursor (&self) -> (usize, usize) {
self.focus_cursor self.cursor
} }
fn cursor_mut (&mut self) -> &mut (usize, usize) { fn cursor_mut (&mut self) -> &mut (usize, usize) {
&mut self.focus_cursor &mut self.cursor
} }
fn layout (&self) -> &[&[SequencerFocus]] { &[ fn layout (&self) -> &[&[SequencerFocus]] { &[
&[SequencerFocus::Transport], &[SequencerFocus::Transport],
@ -34,10 +34,8 @@ impl<E: Engine> FocusGrid for SequencerView<E> {
} }
fn update_focus (&mut self) { fn update_focus (&mut self) {
let focused = self.focused(); let focused = self.focused();
if let Some(transport) = self.transport.as_ref() { self.transport.focused = focused == SequencerFocus::Transport;
transport.write().unwrap().focused = focused == SequencerFocus::Transport self.phrases.focused = focused == SequencerFocus::PhrasePool;
} self.editor.focused = focused == SequencerFocus::PhraseEditor;
self.phrases.write().unwrap().focused = focused == SequencerFocus::PhrasePool;
self.editor.focused = focused == SequencerFocus::PhraseEditor;
} }
} }

View file

@ -1,31 +1,24 @@
use crate::*; use crate::*;
use tek_api::Transport; use tek_api::Transport;
/// Stores and displays time-related state. /// Stores and displays time-related info.
#[derive(Debug)] #[derive(Debug)]
pub struct TransportView<E: Engine> { pub struct TransportView<E: Engine> {
_engine: PhantomData<E>, _engine: PhantomData<E>,
pub state: Transport, pub model: Transport,
pub focus: TransportViewFocus, pub focus: TransportViewFocus,
pub focused: bool, pub focused: bool,
pub size: Measure<E>, pub size: Measure<E>,
} }
/// JACK process callback for transport app
impl<E: Engine> Audio for TransportView<E> {
fn process (&mut self, client: &Client, scope: &ProcessScope) -> Control {
self.state.process(client, scope);
Control::Continue
}
}
impl<E: Engine> TransportView<E> { impl<E: Engine> TransportView<E> {
pub fn new (jack: &Arc<RwLock<JackClient>>, clock: Option<&Arc<Clock>>) -> Self { pub fn new (jack: &Arc<RwLock<JackClient>>, clock: Option<&Arc<Clock>>) -> Self {
Self { Self {
_engine: Default::default(), _engine: Default::default(),
focused: false, focused: false,
focus: TransportViewFocus::PlayPause, focus: TransportViewFocus::PlayPause,
state: Transport { size: Measure::new(),
model: Transport {
metronome: false, metronome: false,
transport: jack.read().unwrap().transport(), transport: jack.read().unwrap().transport(),
jack: jack.clone(), jack: jack.clone(),
@ -53,7 +46,7 @@ impl Content for TransportView<Tui> {
lay!( lay!(
self.focus.wrap(self.focused, TransportViewFocus::PlayPause, &Styled( self.focus.wrap(self.focused, TransportViewFocus::PlayPause, &Styled(
None, None,
match *self.clock.playing.read().unwrap() { match *self.model.clock.playing.read().unwrap() {
Some(TransportState::Rolling) => "▶ PLAYING", Some(TransportState::Rolling) => "▶ PLAYING",
Some(TransportState::Starting) => "READY ...", Some(TransportState::Starting) => "READY ...",
Some(TransportState::Stopped) => "⏹ STOPPED", Some(TransportState::Stopped) => "⏹ STOPPED",
@ -63,20 +56,20 @@ impl Content for TransportView<Tui> {
row!( row!(
self.focus.wrap(self.focused, TransportViewFocus::Bpm, &Outset::X(1u16, { 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) } 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! { //let quant = self.focus.wrap(self.focused, TransportViewFocus::Quant, &Outset::X(1u16, row! {
//"QUANT ", ppq_to_name(self.quant as usize) //"QUANT ", ppq_to_name(self.quant as usize)
//})), //})),
self.focus.wrap(self.focused, TransportViewFocus::Sync, &Outset::X(1u16, row! { 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(), ).align_w().fill_x(),
self.focus.wrap(self.focused, TransportViewFocus::Clock, &{ self.focus.wrap(self.focused, TransportViewFocus::Clock, &{
let time1 = self.clock.current.format_beat(); let time1 = self.model.clock.current.format_beat();
let time2 = self.clock.current.usec.format_msu(); let time2 = self.model.clock.current.usec.format_msu();
row!("B" ,time1.as_str(), " T", time2.as_str()).outset_x(1) row!("B" ,time1.as_str(), " T", time2.as_str()).outset_x(1)
}).align_e().fill_x(), }).align_e().fill_x(),

View file

@ -13,7 +13,7 @@ impl Handle<Tui> for TransportView<Tui> {
} }
impl InputToCommand<Tui, TransportView<Tui>> for TransportViewCommand { impl InputToCommand<Tui, TransportView<Tui>> for TransportViewCommand {
fn input_to_command (state: &TransportView<Tui>, input: &TuiInput) -> Option<Self> { fn input_to_command (view: &TransportView<Tui>, input: &TuiInput) -> Option<Self> {
use TransportViewFocus as Focus; use TransportViewFocus as Focus;
use FocusCommand as FocusCmd; use FocusCommand as FocusCmd;
use TransportCommand as Cmd; use TransportCommand as Cmd;
@ -22,31 +22,31 @@ impl InputToCommand<Tui, TransportView<Tui>> for TransportViewCommand {
key!(KeyCode::Left) => Self::Focus(FocusCmd::Prev), key!(KeyCode::Left) => Self::Focus(FocusCmd::Prev),
key!(KeyCode::Right) => Self::Focus(FocusCmd::Next), key!(KeyCode::Right) => Self::Focus(FocusCmd::Next),
key!(KeyCode::Char('.')) => Self::Transport(match state.focus { key!(KeyCode::Char('.')) => Self::Transport(match view.focus {
Focus::Bpm => Cmd::SetBpm(state.state.clock.timebase().bpm.get() + 1.0), Focus::Bpm => Cmd::SetBpm(view.model.clock.timebase().bpm.get() + 1.0),
Focus::Quant => Cmd::SetQuant(next_note_length(state.state.clock.quant.get()as usize)as f64), Focus::Quant => Cmd::SetQuant(next_note_length(view.model.clock.quant.get()as usize)as f64),
Focus::Sync => Cmd::SetSync(next_note_length(state.state.clock.sync.get()as usize)as f64+1.), Focus::Sync => Cmd::SetSync(next_note_length(view.model.clock.sync.get()as usize)as f64+1.),
Focus::PlayPause => {todo!()}, Focus::PlayPause => {todo!()},
Focus::Clock => {todo!()} Focus::Clock => {todo!()}
}), }),
key!(KeyCode::Char(',')) => Self::Transport(match state.focus { key!(KeyCode::Char(',')) => Self::Transport(match view.focus {
Focus::Bpm => Cmd::SetBpm(state.state.clock.timebase().bpm.get() - 1.0), Focus::Bpm => Cmd::SetBpm(view.model.clock.timebase().bpm.get() - 1.0),
Focus::Quant => Cmd::SetQuant(prev_note_length(state.state.clock.quant.get()as usize)as f64), Focus::Quant => Cmd::SetQuant(prev_note_length(view.model.clock.quant.get()as usize)as f64),
Focus::Sync => Cmd::SetSync(prev_note_length(state.state.clock.sync.get()as usize)as f64+1.), Focus::Sync => Cmd::SetSync(prev_note_length(view.model.clock.sync.get()as usize)as f64+1.),
Focus::PlayPause => {todo!()}, Focus::PlayPause => {todo!()},
Focus::Clock => {todo!()} Focus::Clock => {todo!()}
}), }),
key!(KeyCode::Char('>')) => Self::Transport(match state.focus { key!(KeyCode::Char('>')) => Self::Transport(match view.focus {
Focus::Bpm => Cmd::SetBpm(state.state.clock.timebase().bpm.get() + 0.001), Focus::Bpm => Cmd::SetBpm(view.model.clock.timebase().bpm.get() + 0.001),
Focus::Quant => Cmd::SetQuant(next_note_length(state.state.clock.quant.get()as usize)as f64), Focus::Quant => Cmd::SetQuant(next_note_length(view.model.clock.quant.get()as usize)as f64),
Focus::Sync => Cmd::SetSync(next_note_length(state.state.clock.sync.get()as usize)as f64+1.), Focus::Sync => Cmd::SetSync(next_note_length(view.model.clock.sync.get()as usize)as f64+1.),
Focus::PlayPause => {todo!()}, Focus::PlayPause => {todo!()},
Focus::Clock => {todo!()} Focus::Clock => {todo!()}
}), }),
key!(KeyCode::Char('<')) => Self::Transport(match state.focus { key!(KeyCode::Char('<')) => Self::Transport(match view.focus {
Focus::Bpm => Cmd::SetBpm(state.state.clock.timebase().bpm.get() - 0.001), Focus::Bpm => Cmd::SetBpm(view.model.clock.timebase().bpm.get() - 0.001),
Focus::Quant => Cmd::SetQuant(prev_note_length(state.state.clock.quant.get()as usize)as f64), Focus::Quant => Cmd::SetQuant(prev_note_length(view.model.clock.quant.get()as usize)as f64),
Focus::Sync => Cmd::SetSync(prev_note_length(state.state.clock.sync.get()as usize)as f64+1.), Focus::Sync => Cmd::SetSync(prev_note_length(view.model.clock.sync.get()as usize)as f64+1.),
Focus::PlayPause => {todo!()}, Focus::PlayPause => {todo!()},
Focus::Clock => {todo!()} Focus::Clock => {todo!()}
}), }),
@ -57,7 +57,7 @@ impl InputToCommand<Tui, TransportView<Tui>> for TransportViewCommand {
} }
impl<E: Engine> Command<TransportView<E>> for TransportViewCommand { impl<E: Engine> Command<TransportView<E>> for TransportViewCommand {
fn execute (self, state: &mut TransportView<E>) -> Perhaps<Self> { fn execute (self, view: &mut TransportView<E>) -> Perhaps<Self> {
Ok(Some(match self { Ok(Some(match self {
Self::Focus(command) => Self::Focus({ Self::Focus(command) => Self::Focus({
use FocusCommand::*; use FocusCommand::*;
@ -70,9 +70,9 @@ impl<E: Engine> Command<TransportView<E>> for TransportViewCommand {
Self::Transport(command) => Self::Transport({ Self::Transport(command) => Self::Transport({
use TransportCommand::*; use TransportCommand::*;
match command { match command {
SetBpm(bpm) => SetBpm(state.state.clock.timebase().bpm.set(bpm)), SetBpm(bpm) => SetBpm(view.model.clock.timebase().bpm.set(bpm)),
SetQuant(quant) => SetQuant(state.state.clock.quant.set(quant)), SetQuant(quant) => SetQuant(view.model.clock.quant.set(quant)),
SetSync(sync) => SetSync(state.state.clock.sync.set(sync)), SetSync(sync) => SetSync(view.model.clock.sync.set(sync)),
_ => { todo!() } _ => { todo!() }
} }
}), }),