From d06b95df2c2dcd06a89c629282f7cc48b2af9f33 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Sat, 14 Dec 2024 20:48:55 +0100 Subject: [PATCH] double arc rwlock was silly --- crates/tek/src/tui/app_sequencer.rs | 6 +- crates/tek/src/tui/phrase_editor.rs | 89 +++++++++++++------------- crates/tek/src/tui/piano_horizontal.rs | 25 ++++---- 3 files changed, 59 insertions(+), 61 deletions(-) diff --git a/crates/tek/src/tui/app_sequencer.rs b/crates/tek/src/tui/app_sequencer.rs index 14354b0d..15908d15 100644 --- a/crates/tek/src/tui/app_sequencer.rs +++ b/crates/tek/src/tui/app_sequencer.rs @@ -137,9 +137,7 @@ pub fn to_sequencer_command (state: &SequencerTui, input: &TuiInput) -> Option if let Some((_, Some(playing_phrase))) = state.player.play_phrase() { - let editing_phrase = state.editor.phrase() - .read().unwrap().as_ref() - .map(|p|p.read().unwrap().clone()); + let editing_phrase = state.editor.phrase().as_ref().map(|p|p.read().unwrap().clone()); let selected_phrase = state.phrases.phrase().clone(); if Some(selected_phrase.read().unwrap().clone()) != editing_phrase { Editor(Show(Some(selected_phrase))) @@ -183,7 +181,7 @@ render!(|self: SequencerTui|lay!([self.size, Tui::split_up(false, 1, PhraseSelector::play_phrase(&self.player), PhraseSelector::next_phrase(&self.player), ]), Tui::split_up(false, 2, - PhraseSelector::edit_phrase(&self.editor.phrase.read().unwrap()), + PhraseSelector::edit_phrase(self.editor.phrase()), PhraseListView::from(self), ))), col!([ diff --git a/crates/tek/src/tui/phrase_editor.rs b/crates/tek/src/tui/phrase_editor.rs index 8d2f3a60..57263333 100644 --- a/crates/tek/src/tui/phrase_editor.rs +++ b/crates/tek/src/tui/phrase_editor.rs @@ -27,25 +27,15 @@ pub enum PhraseCommand { impl InputToCommand for PhraseCommand { fn input_to_command (state: &PhraseEditorModel, from: &TuiInput) -> Option { - - let length = ||state - .phrase() - .read() - .unwrap() - .as_ref() - .map(|p|p.read().unwrap().length) - .unwrap_or(1); - + let length = ||state.phrase().as_ref().map(|p|p.read().unwrap().length).unwrap_or(1); let range = state.range(); let note_lo = ||range.note_lo.load(Relaxed); let time_start = ||range.time_start.load(Relaxed); let time_zoom = ||range.time_zoom(); - let point = state.point(); let note_point = ||point.note_point(); let time_point = ||point.time_point(); let note_len = ||point.note_len(); - Some(match from.event() { key_pat!(Ctrl-Alt-Up) => SetNoteScroll(note_point() + 3), key_pat!(Ctrl-Alt-Down) => SetNoteScroll(note_point().saturating_sub(3)), @@ -88,7 +78,7 @@ impl Command for PhraseCommand { let range = state.range(); let point = state.point(); match self { - Show(phrase) => { state.set_phrase(phrase); }, + Show(phrase) => { state.set_phrase(phrase.as_ref()); }, PutNote => { state.put_note(false); }, AppendNote => { state.put_note(true); }, SetTimeZoom(x) => { range.set_time_zoom(x); }, @@ -114,51 +104,51 @@ impl Command for PhraseCommand { /// Contains state for viewing and editing a phrase pub struct PhraseEditorModel { - /// Phrase being played - pub phrase: Arc>>>>, /// Renders the phrase pub mode: Box, } impl Default for PhraseEditorModel { fn default () -> Self { - let phrase = Arc::new(RwLock::new(None)); - let mode = PianoHorizontal::new(&phrase); - Self { phrase, mode: Box::new(mode) } + Self { mode: Box::new(PianoHorizontal::new(None)) } } } render!(|self: PhraseEditorModel|self.mode); pub trait PhraseViewMode: Render + Debug + Send + Sync { - fn range (&self) -> &PhraseEditorRange; - fn point (&self) -> &PhraseEditorPoint; + fn range (&self) -> &PhraseEditorRange; + fn point (&self) -> &PhraseEditorPoint; fn buffer_size (&self, phrase: &Phrase) -> (usize, usize); - fn redraw (&mut self); - fn phrase (&self) -> &Arc>>>>; - fn set_phrase (&mut self, phrase: Option>>) { - *self.phrase().write().unwrap() = phrase; + fn redraw (&mut self); + fn phrase (&self) -> &Option>>; + fn phrase_mut (&mut self) -> &mut Option>>; + fn set_phrase (&mut self, phrase: Option<&Arc>>) { + *self.phrase_mut() = phrase.map(|p|p.clone()); self.redraw(); } } impl PhraseViewMode for PhraseEditorModel { - fn range (&self) -> &PhraseEditorRange { + fn range (&self) -> &PhraseEditorRange { self.mode.range() } - fn point (&self) -> &PhraseEditorPoint { + fn point (&self) -> &PhraseEditorPoint { self.mode.point() } fn buffer_size (&self, phrase: &Phrase) -> (usize, usize) { self.mode.buffer_size(phrase) } - fn redraw (&mut self) { + fn redraw (&mut self) { self.mode.redraw() } - fn phrase (&self) -> &Arc>>>> { + fn phrase (&self) -> &Option>> { self.mode.phrase() } - fn set_phrase (&mut self, phrase: Option>>) { + fn phrase_mut (&mut self) -> &mut Option>> { + self.mode.phrase_mut() + } + fn set_phrase (&mut self, phrase: Option<&Arc>>) { self.mode.set_phrase(phrase) } } @@ -264,25 +254,32 @@ impl PhraseEditorPoint { impl PhraseEditorModel { /// Put note at current position pub fn put_note (&mut self, advance: bool) { - if let Some(phrase) = &*self.phrase.read().unwrap() { - let point = self.point().clone(); - let note_len = point.note_len.load(Relaxed); - let time = point.time_point.load(Relaxed); - let note = point.note_point.load(Relaxed); + let mut redraw = false; + if let Some(phrase) = self.phrase() { let mut phrase = phrase.write().unwrap(); - let key: u7 = u7::from(note as u8); + let note_start = self.point().time_point(); + let note_point = self.point().note_point(); + let note_len = self.point().note_len(); + let note_end = note_start + note_len; + let key: u7 = u7::from(note_point as u8); let vel: u7 = 100.into(); - let start = time; - let end = (start + note_len) % phrase.length; - phrase.notes[time].push(MidiMessage::NoteOn { key, vel }); - phrase.notes[end].push(MidiMessage::NoteOff { key, vel }); - self.mode.redraw(); - if advance { - let time = point.time_point.load(Relaxed); - let length = phrase.length; - let forward = |time|(time + note_len) % length; - point.set_time_point(forward(time)); + let length = phrase.length; + let note_end = note_end % length; + let note_on = MidiMessage::NoteOn { key, vel }; + if !phrase.notes[note_start].iter().any(|msg|*msg == note_on) { + phrase.notes[note_start].push(note_on); } + let note_off = MidiMessage::NoteOff { key, vel }; + if !phrase.notes[note_end].iter().any(|msg|*msg == note_off) { + phrase.notes[note_end].push(note_off); + } + if advance { + self.point().set_time_point(note_end); + } + redraw = true; + } + if redraw { + self.mode.redraw(); } } } @@ -295,8 +292,8 @@ impl From<&Arc>> for PhraseEditorModel { impl From>>> for PhraseEditorModel { fn from (phrase: Option>>) -> Self { - let model = Self::default(); - *model.phrase.write().unwrap() = phrase; + let mut model = Self::default(); + *model.phrase_mut() = phrase; model } } diff --git a/crates/tek/src/tui/piano_horizontal.rs b/crates/tek/src/tui/piano_horizontal.rs index 6b7a019a..572f1f10 100644 --- a/crates/tek/src/tui/piano_horizontal.rs +++ b/crates/tek/src/tui/piano_horizontal.rs @@ -3,7 +3,7 @@ use super::*; /// A phrase, rendered as a horizontal piano roll. pub struct PianoHorizontal { - phrase: Arc>>>>, + phrase: Option>>, /// Buffer where the whole phrase is rerendered on change buffer: BigBuffer, /// Width and height of notes area at last render @@ -17,13 +17,13 @@ pub struct PianoHorizontal { } impl PianoHorizontal { - pub fn new (phrase: &Arc>>>>) -> Self { + pub fn new (phrase: Option<&Arc>>) -> Self { let size = Measure::new(); let mut range = PhraseEditorRange::default(); range.time_axis = size.x.clone(); range.note_axis = size.y.clone(); - let phrase = phrase.clone(); - let color = phrase.read().unwrap().as_ref() + let phrase = phrase.map(|p|p.clone()); + let color = phrase.as_ref() .map(|p|p.read().unwrap().color) .unwrap_or(ItemPalette::from(ItemColor::from(TuiTheme::g(64)))); Self { @@ -242,9 +242,12 @@ impl PianoHorizontal { } impl PhraseViewMode for PianoHorizontal { - fn phrase (&self) -> &Arc>>>> { + fn phrase (&self) -> &Option>> { &self.phrase } + fn phrase_mut (&mut self) -> &mut Option>> { + &mut self.phrase + } fn range (&self) -> &PhraseEditorRange { &self.range } @@ -256,9 +259,10 @@ impl PhraseViewMode for PianoHorizontal { (phrase.length / self.range.time_zoom(), 128) } fn redraw (&mut self) { - let buffer = if let Some(phrase) = &*self.phrase().read().unwrap() { + let buffer = if let Some(phrase) = self.phrase.as_ref() { let phrase = phrase.read().unwrap(); - let mut buffer = BigBuffer::from(self.buffer_size(&phrase)); + let buf_size = self.buffer_size(&phrase); + let mut buffer = BigBuffer::from(buf_size); let note_len = self.point.note_len(); let time_zoom = self.range.time_zoom(); PianoHorizontal::draw_bg(&mut buffer, &phrase, time_zoom, note_len); @@ -269,10 +273,9 @@ impl PhraseViewMode for PianoHorizontal { }; self.buffer = buffer } - fn set_phrase (&mut self, phrase: Option>>) { - *self.phrase().write().unwrap() = phrase; - self.color = self.phrase.read().unwrap().as_ref() - .map(|p|p.read().unwrap().color) + fn set_phrase (&mut self, phrase: Option<&Arc>>) { + *self.phrase_mut() = phrase.map(|p|p.clone()); + self.color = phrase.map(|p|p.read().unwrap().color.clone()) .unwrap_or(ItemPalette::from(ItemColor::from(TuiTheme::g(64)))); self.redraw(); }