From 286dec0f4006e62e5203658e36fc9d74b1a3f7fe Mon Sep 17 00:00:00 2001 From: unspeaker Date: Fri, 29 Nov 2024 00:28:53 +0100 Subject: [PATCH] remove FixedAxis and ScaledAxis --- crates/tek_core/src/space.rs | 66 ----- crates/tek_tui/src/tui_control_arranger.rs | 8 +- .../tek_tui/src/tui_control_phrase_editor.rs | 260 ++++++++---------- crates/tek_tui/src/tui_control_sequencer.rs | 4 +- crates/tek_tui/src/tui_model_phrase_editor.rs | 86 ++++-- crates/tek_tui/src/tui_view_phrase_editor.rs | 89 +++--- 6 files changed, 223 insertions(+), 290 deletions(-) diff --git a/crates/tek_core/src/space.rs b/crates/tek_core/src/space.rs index 80384a61..a3a684a7 100644 --- a/crates/tek_core/src/space.rs +++ b/crates/tek_core/src/space.rs @@ -33,72 +33,6 @@ impl Coordinate for T where T: Send + Sync + Copy + Into {} -#[derive(Debug)] -pub struct FixedAxis { - pub start: T, - pub point: Option, - pub clamp: Option, -} - -#[derive(Debug)] -pub struct ScaledAxis { - pub start: T, - pub scale: T, - pub point: Option, - pub clamp: Option, -} - -macro_rules! impl_axis_common { ($A:ident $T:ty) => { - impl $A<$T> { - #[inline] pub fn start_set (&mut self, n: $T) -> $T { - self.start = n; - self.start - } - #[inline] pub fn start_plus (&self, n: $T) -> $T { - (self.start + n).min(self.clamp.unwrap_or(<$T>::MAX)) - } - #[inline] pub fn start_inc (&mut self, n: $T) -> $T { - self.start_set(self.start_plus(n)) - } - #[inline] pub fn start_minus (&self, n: $T) -> $T { - self.start.saturating_sub(n) - } - #[inline] pub fn start_dec (&mut self, n: $T) -> $T { - self.start = self.start_minus(n); - self.start - } - - #[inline] pub fn point_set (&mut self, n: Option<$T>) -> Option<$T> { - self.point = n; - self.point - } - #[inline] pub fn point_plus (&self, n: $T) -> Option<$T> { - self.point.map(|p|(p + n).min(self.clamp.unwrap_or(<$T>::MAX))) - } - #[inline] pub fn point_inc (&mut self, n: $T) -> Option<$T> { - self.point_set(self.point_plus(n)) - } - #[inline] pub fn point_minus (&self, n: $T) -> Option<$T> { - self.point.map(|p|p.saturating_sub(n)) - } - #[inline] pub fn point_dec (&mut self, n: $T) -> Option<$T> { - self.point_set(self.point_minus(n)) - } - - } -} } -impl_axis_common!(FixedAxis u16); -impl_axis_common!(FixedAxis usize); -impl_axis_common!(ScaledAxis u16); -impl_axis_common!(ScaledAxis usize); - -impl ScaledAxis { - #[inline] pub fn scale_set (&mut self, n: T) -> T { - self.scale = n; - n - } -} - // TODO: return impl Point and impl Size instead of [N;x] // to disambiguate between usage of 2-"tuple"s diff --git a/crates/tek_tui/src/tui_control_arranger.rs b/crates/tek_tui/src/tui_control_arranger.rs index 6176f48d..b478240d 100644 --- a/crates/tek_tui/src/tui_control_arranger.rs +++ b/crates/tek_tui/src/tui_control_arranger.rs @@ -32,7 +32,7 @@ impl Command for ArrangerCommand { Track(cmd) => cmd.execute(state)?.map(Track), Clip(cmd) => cmd.execute(state)?.map(Clip), Phrases(cmd) => cmd.execute(&mut state.phrases)?.map(Phrases), - Editor(cmd) => cmd.execute(state)?.map(Editor), + Editor(cmd) => cmd.execute(&mut state.editor)?.map(Editor), Clock(cmd) => cmd.execute(state)?.map(Clock), Zoom(zoom) => { todo!(); }, Select(selected) => { @@ -140,7 +140,9 @@ fn to_arranger_command (state: &ArrangerTui, input: &TuiInput) -> Option Cmd::Editor(PhraseCommand::Show(state.phrase_to_edit().clone())), + key!(Char('e')) => Cmd::Editor(PhraseCommand::Show(Some( + state.phrases.phrases[state.phrases.phrase.load(Ordering::Relaxed)].clone() + ))), _ => match state.focused() { ArrangerFocus::Transport(_) => { match TransportCommand::input_to_command(state, input)? { @@ -149,7 +151,7 @@ fn to_arranger_command (state: &ArrangerTui, input: &TuiInput) -> Option { - Cmd::Editor(PhraseCommand::input_to_command(state, input)?) + Cmd::Editor(PhraseCommand::input_to_command(&state.editor, input)?) }, ArrangerFocus::Phrases => { Cmd::Phrases(PhrasesCommand::input_to_command(&state.phrases, input)?) diff --git a/crates/tek_tui/src/tui_control_phrase_editor.rs b/crates/tek_tui/src/tui_control_phrase_editor.rs index 8eb91a52..b54012c2 100644 --- a/crates/tek_tui/src/tui_control_phrase_editor.rs +++ b/crates/tek_tui/src/tui_control_phrase_editor.rs @@ -3,105 +3,141 @@ use crate::*; #[derive(Clone, Debug)] pub enum PhraseCommand { // TODO: 1-9 seek markers that by default start every 8th of the phrase - ToggleDirection, - EnterEditMode, - ExitEditMode, - NoteAppend, - NoteSet, - NoteCursorSet(Option), - NoteLengthSet(usize), - NoteScrollSet(usize), - TimeCursorSet(Option), - TimeScrollSet(usize), - TimeZoomSet(usize), + AppendNote, + PutNote, + SetNoteCursor(usize), + SetNoteLength(usize), + SetNoteScroll(usize), + SetTimeCursor(usize), + SetTimeScroll(usize), + SetTimeZoom(usize), Show(Option>>), + SetEditMode(PhraseEditMode), + ToggleDirection, } -impl InputToCommand for PhraseCommand { - fn input_to_command (state: &T, from: &TuiInput) -> Option { +impl InputToCommand for PhraseCommand { + fn input_to_command (state: &PhraseEditorModel, from: &TuiInput) -> Option { use PhraseCommand::*; use KeyCode::{Char, Enter, Esc, Up, Down, PageUp, PageDown, Left, Right}; Some(match from.event() { key!(Char('`')) => ToggleDirection, - key!(Enter) => EnterEditMode, - key!(Esc) => ExitEditMode, - key!(Char('a')) => NoteAppend, - key!(Char('s')) => NoteSet, - key!(Char('[')) => NoteLengthSet(prev_note_length(state.note_len())), - key!(Char(']')) => NoteLengthSet(next_note_length(state.note_len())), - key!(Char('-')) => TimeZoomSet(next_note_length(state.time_axis().read().unwrap().scale)), - key!(Char('_')) => TimeZoomSet(next_note_length(state.time_axis().read().unwrap().scale)), - key!(Char('=')) => TimeZoomSet(prev_note_length(state.time_axis().read().unwrap().scale)), - key!(Char('+')) => TimeZoomSet(prev_note_length(state.time_axis().read().unwrap().scale)), - key!(Up) => match state.phrase_editor_entered() { - true => NoteCursorSet(state.note_axis().write().unwrap().point_plus(1)), - false => NoteScrollSet(state.note_axis().write().unwrap().start_plus(1)), - }, - key!(Down) => match state.phrase_editor_entered() { - true => NoteCursorSet(state.note_axis().write().unwrap().point_minus(1)), - false => NoteScrollSet(state.note_axis().write().unwrap().start_minus(1)), - }, - key!(PageUp) => match state.phrase_editor_entered() { - true => NoteCursorSet(state.note_axis().write().unwrap().point_plus(3)), - false => NoteScrollSet(state.note_axis().write().unwrap().start_plus(3)), - }, - key!(PageDown) => match state.phrase_editor_entered() { - true => NoteCursorSet(state.note_axis().write().unwrap().point_minus(3)), - false => NoteScrollSet(state.note_axis().write().unwrap().start_minus(3)), - }, - key!(Left) => match state.phrase_editor_entered() { - true => TimeCursorSet(state.note_axis().write().unwrap().point_minus(1)), - false => TimeScrollSet(state.note_axis().write().unwrap().start_minus(1)), - }, - key!(Right) => match state.phrase_editor_entered() { - true => TimeCursorSet(state.note_axis().write().unwrap().point_plus(1)), - false => TimeScrollSet(state.note_axis().write().unwrap().start_plus(1)), - }, + key!(Enter) => SetEditMode(PhraseEditMode::Note), + key!(Esc) => SetEditMode(PhraseEditMode::Scroll), + key!(Char('-')) => SetTimeZoom( + next_note_length(state.time_scale.load(Ordering::Relaxed)) + ), + key!(Char('_')) => SetTimeZoom( + next_note_length(state.time_scale.load(Ordering::Relaxed)) + ), + key!(Char('=')) => SetTimeZoom( + prev_note_length(state.time_scale.load(Ordering::Relaxed)) + ), + key!(Char('+')) => SetTimeZoom( + prev_note_length(state.time_scale.load(Ordering::Relaxed)) + ), + _ => match state.edit_mode { + PhraseEditMode::Scroll => match from.event() { + key!(Up) => SetNoteCursor( + state.note_point.load(Ordering::Relaxed) + 1 + ), + key!(Down) => SetNoteCursor( + state.note_point.load(Ordering::Relaxed).saturating_sub(1) + ), + key!(PageUp) => SetNoteCursor( + state.note_point.load(Ordering::Relaxed) + 3 + ), + key!(PageDown) => SetNoteCursor( + state.note_point.load(Ordering::Relaxed).saturating_sub(3) + ), + key!(Left) => SetTimeCursor( + state.note_point.load(Ordering::Relaxed).saturating_sub(1) + ), + key!(Right) => SetTimeCursor( + state.note_point.load(Ordering::Relaxed) + 1 + ), + _ => return None + }, + PhraseEditMode::Note => match from.event() { + key!(Up) => SetNoteScroll( + state.note_start.load(Ordering::Relaxed) + 1 + ), + key!(Down) => SetNoteScroll( + state.note_start.load(Ordering::Relaxed).saturating_sub(1) + ), + key!(PageUp) => SetNoteScroll( + state.note_start.load(Ordering::Relaxed) + 3 + ), + key!(PageDown) => SetNoteScroll( + state.note_start.load(Ordering::Relaxed).saturating_sub(3) + ), + key!(Left) => SetTimeScroll( + state.note_start.load(Ordering::Relaxed).saturating_sub(1) + ), + key!(Right) => SetTimeScroll( + state.note_start.load(Ordering::Relaxed) + 1 + ), + key!(Char('a')) => AppendNote, + key!(Char('s')) => PutNote, + key!(Char('[')) => SetNoteLength(prev_note_length(state.note_len)), + key!(Char(']')) => SetNoteLength(next_note_length(state.note_len)), + _ => return None + }, + } _ => return None }) } } -impl Command for PhraseCommand { - fn execute (self, state: &mut T) -> Perhaps { +impl Command for PhraseCommand { + fn execute (self, state: &mut PhraseEditorModel) -> Perhaps { use PhraseCommand::*; Ok(match self { Show(phrase) => { - state.edit_phrase(phrase); + state.phrase = phrase; None }, - ToggleDirection => { todo!() }, - EnterEditMode => { - state.focus_enter(); + ToggleDirection => { + todo!() + }, + SetEditMode(mode) => { + state.edit_mode = mode; + None + } + AppendNote => { + state.put_note(); + state.time_cursor_advance(); None }, - ExitEditMode => { - state.focus_exit(); + PutNote => { + state.put_note(); None }, - NoteAppend => { - if state.phrase_editor_entered() { - state.put_note(); - state.time_cursor_advance(); - } + SetTimeCursor(time) => { + state.time_point.store(time, Ordering::Relaxed); None }, - NoteSet => { if state.phrase_editor_entered() { state.put_note(); } None }, - TimeCursorSet(time) => { state.time_axis().write().unwrap().point_set(time); None }, - TimeScrollSet(time) => { state.time_axis().write().unwrap().start_set(time); None }, - TimeZoomSet(zoom) => { state.time_axis().write().unwrap().scale_set(zoom); None }, - NoteScrollSet(note) => { state.note_axis().write().unwrap().start_set(note); None }, - NoteLengthSet(time) => { *state.note_len_mut() = time; None }, - NoteCursorSet(note) => { - let mut axis = state.note_axis().write().unwrap(); - axis.point_set(note); - if let Some(point) = axis.point { - if point > 73 { - axis.point = Some(73); - } - if point < axis.start { - axis.start = (point / 2) * 2; - } + SetTimeScroll(time) => { + state.time_start.store(time, Ordering::Relaxed); + None + }, + SetTimeZoom(zoom) => { + state.time_scale.store(zoom, Ordering::Relaxed); + None + }, + SetNoteScroll(note) => { + state.note_start.store(note, Ordering::Relaxed); + None + }, + SetNoteLength(time) => { + state.note_len = time; + None + }, + SetNoteCursor(note) => { + let start = state.note_start.load(Ordering::Relaxed); + state.note_point.store(note, Ordering::Relaxed); + if note < start { + state.note_start.store((note / 2) * 2, Ordering::Relaxed); } None }, @@ -109,75 +145,3 @@ impl Command for PhraseCommand { }) } } - -pub trait PhraseEditorControl { - fn edit_phrase (&mut self, phrase: Option>>); - fn phrase_to_edit (&self) -> Option>>; - fn phrase_editing (&self) -> &Option>>; - fn phrase_editor_entered (&self) -> bool; - fn time_axis (&self) -> &RwLock>; - fn note_axis (&self) -> &RwLock>; - fn note_len (&self) -> usize; - fn note_len_mut (&mut self) -> &mut usize; - fn put_note (&mut self); - fn time_cursor_advance (&self) { - let point = self.time_axis().read().unwrap().point; - let length = self.phrase_editing().as_ref().map(|p|p.read().unwrap().length).unwrap_or(1); - let forward = |time|(time + self.note_len()) % length; - self.time_axis().write().unwrap().point = point.map(forward); - } -} - -macro_rules! impl_phrase_editor_control { - ( - $Struct:ident $(:: $field:ident)* - [$Focus:expr] - [$self1:ident: $phrase_to_edit:expr] - [$self2:ident, $phrase:ident: $edit_phrase:expr] - ) => { - impl PhraseEditorControl for $Struct { - fn phrase_to_edit (&$self1) -> Option>> { - $phrase_to_edit - } - fn edit_phrase (&mut $self2, $phrase: Option>>) { - $edit_phrase - //self.editor.show(self.selected_phrase().as_ref()); - //state.editor.phrase = phrase.clone(); - //state.focus(ArrangerFocus::PhraseEditor); - //state.focus_enter(); - //todo!("edit_phrase") - } - fn phrase_editing (&self) -> &Option>> { - todo!("phrase_editing") - } - fn phrase_editor_entered (&self) -> bool { - self.entered && self.focused() == $Focus - } - fn time_axis (&self) -> &RwLock> { - &self.editor.time_axis - } - fn note_axis (&self) -> &RwLock> { - &self.editor.note_axis - } - fn note_len (&self) -> usize { - self.editor.note_len - } - fn note_len_mut (&mut self) -> &mut usize { - &mut self.editor.note_len - } - fn put_note (&mut self) { - todo!("put_note") - } - } - } -} -impl_phrase_editor_control!(SequencerTui - [SequencerFocus::PhraseEditor] - [self: Some(self.phrases.phrases[self.phrases.phrase.load(Ordering::Relaxed)].clone())] - [self, phrase: self.editor.show(phrase)] -); -impl_phrase_editor_control!(ArrangerTui - [ArrangerFocus::PhraseEditor] - [self: todo!()] - [self, phrase: todo!()] -); diff --git a/crates/tek_tui/src/tui_control_sequencer.rs b/crates/tek_tui/src/tui_control_sequencer.rs index 1e2b4b8b..dc9a7d07 100644 --- a/crates/tek_tui/src/tui_control_sequencer.rs +++ b/crates/tek_tui/src/tui_control_sequencer.rs @@ -24,7 +24,7 @@ impl Command for SequencerCommand { Ok(match self { Focus(cmd) => cmd.execute(state)?.map(Focus), Phrases(cmd) => cmd.execute(&mut state.phrases)?.map(Phrases), - Editor(cmd) => cmd.execute(state)?.map(Editor), + Editor(cmd) => cmd.execute(&mut state.editor)?.map(Editor), Clock(cmd) => cmd.execute(state)?.map(Clock), Enqueue(phrase) => { state.player.enqueue_next(phrase.as_ref()); @@ -78,7 +78,7 @@ pub fn to_sequencer_command (state: &SequencerTui, input: &TuiInput) -> Option return None, }, SequencerFocus::PhraseEditor => Editor( - PhraseCommand::input_to_command(state, input)? + PhraseCommand::input_to_command(&state.editor, input)? ), SequencerFocus::PhraseList => match input.event() { key!(Enter) => Enqueue(Some( diff --git a/crates/tek_tui/src/tui_model_phrase_editor.rs b/crates/tek_tui/src/tui_model_phrase_editor.rs index 61f176fe..c1befde3 100644 --- a/crates/tek_tui/src/tui_model_phrase_editor.rs +++ b/crates/tek_tui/src/tui_model_phrase_editor.rs @@ -10,12 +10,6 @@ pub struct PhraseEditorModel { pub(crate) keys: Buffer, /// The full piano roll is rendered to this buffer pub(crate) buffer: BigBuffer, - /// Cursor/scroll/zoom in pitch axis - pub(crate) note_axis: RwLock>, - /// Cursor/scroll/zoom in time axis - pub(crate) time_axis: RwLock>, - /// Display mode - pub(crate) mode: bool, /// Notes currently held at input pub(crate) notes_in: Arc>, /// Notes currently held at output @@ -23,14 +17,34 @@ pub struct PhraseEditorModel { /// Current position of global playhead pub(crate) now: Arc, /// Width and height of notes area at last render - pub(crate) size: Measure + pub(crate) size: Measure, + + pub(crate) note_start: AtomicUsize, + pub(crate) note_point: AtomicUsize, + pub(crate) note_clamp: AtomicUsize, + + pub(crate) time_start: AtomicUsize, + pub(crate) time_point: AtomicUsize, + pub(crate) time_clamp: AtomicUsize, + pub(crate) time_scale: AtomicUsize, + + pub(crate) edit_mode: PhraseEditMode, } impl std::fmt::Debug for PhraseEditorModel { fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { f.debug_struct("PhraseEditorModel") - .field("note_axis", &self.time_axis) - .field("time_axis", &self.note_axis) + .field("note_axis", &format!("{} {} {}", + self.note_start.load(Ordering::Relaxed), + self.note_point.load(Ordering::Relaxed), + self.note_clamp.load(Ordering::Relaxed), + )) + .field("time_axis", &format!("{} {} {} {}", + self.time_start.load(Ordering::Relaxed), + self.time_point.load(Ordering::Relaxed), + self.time_clamp.load(Ordering::Relaxed), + self.time_scale.load(Ordering::Relaxed), + )) .finish() } } @@ -38,30 +52,44 @@ impl std::fmt::Debug for PhraseEditorModel { impl Default for PhraseEditorModel { fn default () -> Self { Self { - phrase: None, - note_len: 24, - keys: keys_vert(), - buffer: Default::default(), - mode: false, - notes_in: RwLock::new([false;128]).into(), - notes_out: RwLock::new([false;128]).into(), - now: Pulse::default().into(), - size: Measure::new(), - note_axis: RwLock::new(FixedAxis { - start: 12, - point: Some(36), - clamp: Some(127) - }), - time_axis: RwLock::new(ScaledAxis { - start: 00, - point: Some(00), - clamp: Some(000), - scale: 24 - }), + phrase: None, + note_len: 24, + keys: keys_vert(), + buffer: Default::default(), + notes_in: RwLock::new([false;128]).into(), + notes_out: RwLock::new([false;128]).into(), + now: Pulse::default().into(), + size: Measure::new(), + edit_mode: PhraseEditMode::Scroll, + note_start: 12.into(), + note_point: 36.into(), + note_clamp: 127.into(), + time_start: 0.into(), + time_point: 0.into(), + time_clamp: 0.into(), + time_scale: 24.into(), } } } +impl PhraseEditorModel { + pub fn put_note (&mut self) { + todo!("put_note") + } + pub fn time_cursor_advance (&self) { + let point = self.time_point.load(Ordering::Relaxed); + let length = self.phrase.as_ref().map(|p|p.read().unwrap().length).unwrap_or(1); + let forward = |time|(time + self.note_len) % length; + self.time_point.store(forward(point), Ordering::Relaxed); + } +} + +#[derive(Copy, Clone, Debug)] +pub enum PhraseEditMode { + Note, + Scroll, +} + pub trait HasEditor { fn editor (&self) -> &PhraseEditorModel; fn editor_focused (&self) -> bool; diff --git a/crates/tek_tui/src/tui_view_phrase_editor.rs b/crates/tek_tui/src/tui_view_phrase_editor.rs index 9f9c9bb7..28999476 100644 --- a/crates/tek_tui/src/tui_view_phrase_editor.rs +++ b/crates/tek_tui/src/tui_view_phrase_editor.rs @@ -8,24 +8,36 @@ pub struct PhraseView<'a> { pub(crate) keys: &'a Buffer, pub(crate) buffer: &'a BigBuffer, pub(crate) note_len: usize, - pub(crate) note_axis: &'a RwLock>, - pub(crate) time_axis: &'a RwLock>, pub(crate) now: &'a Arc, + + pub(crate) note_start: &'a AtomicUsize, + pub(crate) note_point: &'a AtomicUsize, + pub(crate) note_clamp: &'a AtomicUsize, + + pub(crate) time_start: &'a AtomicUsize, + pub(crate) time_point: &'a AtomicUsize, + pub(crate) time_clamp: &'a AtomicUsize, + pub(crate) time_scale: &'a AtomicUsize, } impl<'a, T: HasEditor> From<&'a T> for PhraseView<'a> { fn from (state: &'a T) -> Self { Self { - focused: state.editor_focused(), - entered: state.editor_entered(), - note_len: state.editor().note_len, - phrase: &state.editor().phrase, - size: &state.editor().size, - keys: &state.editor().keys, - buffer: &state.editor().buffer, - note_axis: &state.editor().note_axis, - time_axis: &state.editor().time_axis, - now: &state.editor().now + focused: state.editor_focused(), + entered: state.editor_entered(), + note_len: state.editor().note_len, + phrase: &state.editor().phrase, + size: &state.editor().size, + keys: &state.editor().keys, + buffer: &state.editor().buffer, + now: &state.editor().now, + note_start: &state.editor().note_start, + note_point: &state.editor().note_point, + note_clamp: &state.editor().note_clamp, + time_start: &state.editor().time_start, + time_point: &state.editor().time_point, + time_clamp: &state.editor().time_clamp, + time_scale: &state.editor().time_scale, } } } @@ -33,13 +45,14 @@ impl<'a, T: HasEditor> From<&'a T> for PhraseView<'a> { impl<'a> Content for PhraseView<'a> { type Engine = Tui; fn content (&self) -> impl Widget { - let Self { - focused, entered, phrase, size, keys, buffer, note_len, note_axis, time_axis, now - } = self; - let FixedAxis { start: note_start, point: note_point, clamp: note_clamp } - = *note_axis.read().unwrap(); - let ScaledAxis { start: time_start, point: time_point, clamp: time_clamp, scale: time_scale } - = *time_axis.read().unwrap(); + let Self { focused, entered, phrase, size, keys, buffer, note_len, now, .. } = self; + let note_start = self.note_start.load(Ordering::Relaxed); + let note_point = self.note_point.load(Ordering::Relaxed); + let note_clamp = self.note_clamp.load(Ordering::Relaxed); + let time_start = self.time_start.load(Ordering::Relaxed); + let time_point = self.time_point.load(Ordering::Relaxed); + let time_clamp = self.time_clamp.load(Ordering::Relaxed); + let time_scale = self.time_scale.load(Ordering::Relaxed); //let color = Color::Rgb(0,255,0); //let color = phrase.as_ref().map(|p|p.read().unwrap().color.base.rgb).unwrap_or(color); let keys = CustomWidget::new(|to:[u16;2]|Ok(Some(to.clip_w(5))), move|to: &mut TuiOutput|{ @@ -57,11 +70,8 @@ impl<'a> Content for PhraseView<'a> { let area = to.area(); let h = area.h() as usize; size.set_wh(area.w(), h); - let mut axis = note_axis.write().unwrap(); - if let Some(point) = axis.point { - if point.saturating_sub(axis.start) > (h * 2).saturating_sub(1) { - axis.start += 2; - } + if note_point.saturating_sub(note_start) > (h * 2).saturating_sub(1) { + self.note_start.store(note_start + 2, Ordering::Relaxed); } Ok(if to.area().h() >= 2 { let area = to.area(); @@ -82,14 +92,12 @@ impl<'a> Content for PhraseView<'a> { let cursor = CustomWidget::new(|to|Ok(Some(to)), move|to: &mut TuiOutput|{ Ok(if *focused && *entered { let area = to.area(); - if let (Some(time), Some(note)) = (time_point, note_point) { - let x1 = area.x() + (time / time_scale) as u16; - let x2 = x1 + (note_len / time_scale) as u16; - let y = area.y() + note.saturating_sub(note_start) as u16 / 2; - let c = if note % 2 == 0 { "▀" } else { "▄" }; - for x in x1..x2 { - to.blit(&c, x, y, Some(Style::default().fg(Color::Rgb(0,255,0)))); - } + let x1 = area.x() + (time_point / time_scale) as u16; + let x2 = x1 + (note_len / time_scale) as u16; + let y = area.y() + note_point.saturating_sub(note_start) as u16 / 2; + let c = if note_point % 2 == 0 { "▀" } else { "▄" }; + for x in x1..x2 { + to.blit(&c, x, y, Some(Style::default().fg(Color::Rgb(0,255,0)))); } }) }); @@ -100,8 +108,7 @@ impl<'a> Content for PhraseView<'a> { move|to: &mut TuiOutput|{ if let Some(_) = phrase { let now = now.get() as usize; // TODO FIXME: self.now % phrase.read().unwrap().length; - let time_clamp = time_clamp - .expect("time_axis of sequencer expected to be clamped"); + let time_clamp = time_clamp; for x in 0..(time_clamp/time_scale).saturating_sub(time_start) { let this_step = time_start + (x + 0) * time_scale; let next_step = time_start + (x + 1) * time_scale; @@ -136,7 +143,7 @@ impl<'a> Content for PhraseView<'a> { //); if *focused && *entered { lower_right = format!("┤Note: {} {}├─{lower_right}", - note_axis.read().unwrap().point.unwrap(), + note_point, pulses_to_name(*note_len)); //lower_right = format!("Note: {} (+{}:{}|{}) {upper_right}", //pulses_to_name(*note_len), @@ -206,11 +213,9 @@ const NTH_OCTAVE: [&'static str; 11] = [ impl PhraseEditorModel { pub fn put (&mut self) { - if let (Some(phrase), Some(time), Some(note)) = ( - &self.phrase, - self.time_axis.read().unwrap().point, - self.note_axis.read().unwrap().point, - ) { + if let Some(phrase) = &self.phrase { + let time = self.time_point.load(Ordering::Relaxed); + let note = self.note_point.load(Ordering::Relaxed); let mut phrase = phrase.write().unwrap(); let key: u7 = u7::from((127 - note) as u8); let vel: u7 = 100.into(); @@ -225,11 +230,11 @@ impl PhraseEditorModel { pub fn show (&mut self, phrase: Option>>) { if let Some(phrase) = phrase { self.phrase = Some(phrase.clone()); - self.time_axis.write().unwrap().clamp = Some(phrase.read().unwrap().length); + self.time_clamp.store(phrase.read().unwrap().length, Ordering::Relaxed); self.buffer = Self::redraw(&*phrase.read().unwrap()); } else { self.phrase = None; - self.time_axis.write().unwrap().clamp = Some(0); + self.time_clamp.store(0, Ordering::Relaxed); self.buffer = Default::default(); } }