double arc rwlock was silly

This commit is contained in:
🪞👃🪞 2024-12-14 20:48:55 +01:00
parent 70794e3cb9
commit d06b95df2c
3 changed files with 59 additions and 61 deletions

View file

@ -137,9 +137,7 @@ pub fn to_sequencer_command (state: &SequencerTui, input: &TuiInput) -> Option<S
// E: Toggle between editing currently playing or other phrase // E: Toggle between editing currently playing or other phrase
key_pat!(Char('e')) => if let Some((_, Some(playing_phrase))) = state.player.play_phrase() { key_pat!(Char('e')) => if let Some((_, Some(playing_phrase))) = state.player.play_phrase() {
let editing_phrase = state.editor.phrase() let editing_phrase = state.editor.phrase().as_ref().map(|p|p.read().unwrap().clone());
.read().unwrap().as_ref()
.map(|p|p.read().unwrap().clone());
let selected_phrase = state.phrases.phrase().clone(); let selected_phrase = state.phrases.phrase().clone();
if Some(selected_phrase.read().unwrap().clone()) != editing_phrase { if Some(selected_phrase.read().unwrap().clone()) != editing_phrase {
Editor(Show(Some(selected_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::play_phrase(&self.player),
PhraseSelector::next_phrase(&self.player), PhraseSelector::next_phrase(&self.player),
]), Tui::split_up(false, 2, ]), Tui::split_up(false, 2,
PhraseSelector::edit_phrase(&self.editor.phrase.read().unwrap()), PhraseSelector::edit_phrase(self.editor.phrase()),
PhraseListView::from(self), PhraseListView::from(self),
))), ))),
col!([ col!([

View file

@ -27,25 +27,15 @@ pub enum PhraseCommand {
impl InputToCommand<Tui, PhraseEditorModel> for PhraseCommand { impl InputToCommand<Tui, PhraseEditorModel> for PhraseCommand {
fn input_to_command (state: &PhraseEditorModel, from: &TuiInput) -> Option<Self> { fn input_to_command (state: &PhraseEditorModel, from: &TuiInput) -> Option<Self> {
let length = ||state.phrase().as_ref().map(|p|p.read().unwrap().length).unwrap_or(1);
let length = ||state
.phrase()
.read()
.unwrap()
.as_ref()
.map(|p|p.read().unwrap().length)
.unwrap_or(1);
let range = state.range(); let range = state.range();
let note_lo = ||range.note_lo.load(Relaxed); let note_lo = ||range.note_lo.load(Relaxed);
let time_start = ||range.time_start.load(Relaxed); let time_start = ||range.time_start.load(Relaxed);
let time_zoom = ||range.time_zoom(); let time_zoom = ||range.time_zoom();
let point = state.point(); let point = state.point();
let note_point = ||point.note_point(); let note_point = ||point.note_point();
let time_point = ||point.time_point(); let time_point = ||point.time_point();
let note_len = ||point.note_len(); let note_len = ||point.note_len();
Some(match from.event() { Some(match from.event() {
key_pat!(Ctrl-Alt-Up) => SetNoteScroll(note_point() + 3), key_pat!(Ctrl-Alt-Up) => SetNoteScroll(note_point() + 3),
key_pat!(Ctrl-Alt-Down) => SetNoteScroll(note_point().saturating_sub(3)), key_pat!(Ctrl-Alt-Down) => SetNoteScroll(note_point().saturating_sub(3)),
@ -88,7 +78,7 @@ impl Command<PhraseEditorModel> for PhraseCommand {
let range = state.range(); let range = state.range();
let point = state.point(); let point = state.point();
match self { match self {
Show(phrase) => { state.set_phrase(phrase); }, Show(phrase) => { state.set_phrase(phrase.as_ref()); },
PutNote => { state.put_note(false); }, PutNote => { state.put_note(false); },
AppendNote => { state.put_note(true); }, AppendNote => { state.put_note(true); },
SetTimeZoom(x) => { range.set_time_zoom(x); }, SetTimeZoom(x) => { range.set_time_zoom(x); },
@ -114,51 +104,51 @@ impl Command<PhraseEditorModel> for PhraseCommand {
/// Contains state for viewing and editing a phrase /// Contains state for viewing and editing a phrase
pub struct PhraseEditorModel { pub struct PhraseEditorModel {
/// Phrase being played
pub phrase: Arc<RwLock<Option<Arc<RwLock<Phrase>>>>>,
/// Renders the phrase /// Renders the phrase
pub mode: Box<dyn PhraseViewMode>, pub mode: Box<dyn PhraseViewMode>,
} }
impl Default for PhraseEditorModel { impl Default for PhraseEditorModel {
fn default () -> Self { fn default () -> Self {
let phrase = Arc::new(RwLock::new(None)); Self { mode: Box::new(PianoHorizontal::new(None)) }
let mode = PianoHorizontal::new(&phrase);
Self { phrase, mode: Box::new(mode) }
} }
} }
render!(|self: PhraseEditorModel|self.mode); render!(|self: PhraseEditorModel|self.mode);
pub trait PhraseViewMode: Render<Tui> + Debug + Send + Sync { pub trait PhraseViewMode: Render<Tui> + Debug + Send + Sync {
fn range (&self) -> &PhraseEditorRange; fn range (&self) -> &PhraseEditorRange;
fn point (&self) -> &PhraseEditorPoint; fn point (&self) -> &PhraseEditorPoint;
fn buffer_size (&self, phrase: &Phrase) -> (usize, usize); fn buffer_size (&self, phrase: &Phrase) -> (usize, usize);
fn redraw (&mut self); fn redraw (&mut self);
fn phrase (&self) -> &Arc<RwLock<Option<Arc<RwLock<Phrase>>>>>; fn phrase (&self) -> &Option<Arc<RwLock<Phrase>>>;
fn set_phrase (&mut self, phrase: Option<Arc<RwLock<Phrase>>>) { fn phrase_mut (&mut self) -> &mut Option<Arc<RwLock<Phrase>>>;
*self.phrase().write().unwrap() = phrase; fn set_phrase (&mut self, phrase: Option<&Arc<RwLock<Phrase>>>) {
*self.phrase_mut() = phrase.map(|p|p.clone());
self.redraw(); self.redraw();
} }
} }
impl PhraseViewMode for PhraseEditorModel { impl PhraseViewMode for PhraseEditorModel {
fn range (&self) -> &PhraseEditorRange { fn range (&self) -> &PhraseEditorRange {
self.mode.range() self.mode.range()
} }
fn point (&self) -> &PhraseEditorPoint { fn point (&self) -> &PhraseEditorPoint {
self.mode.point() self.mode.point()
} }
fn buffer_size (&self, phrase: &Phrase) -> (usize, usize) { fn buffer_size (&self, phrase: &Phrase) -> (usize, usize) {
self.mode.buffer_size(phrase) self.mode.buffer_size(phrase)
} }
fn redraw (&mut self) { fn redraw (&mut self) {
self.mode.redraw() self.mode.redraw()
} }
fn phrase (&self) -> &Arc<RwLock<Option<Arc<RwLock<Phrase>>>>> { fn phrase (&self) -> &Option<Arc<RwLock<Phrase>>> {
self.mode.phrase() self.mode.phrase()
} }
fn set_phrase (&mut self, phrase: Option<Arc<RwLock<Phrase>>>) { fn phrase_mut (&mut self) -> &mut Option<Arc<RwLock<Phrase>>> {
self.mode.phrase_mut()
}
fn set_phrase (&mut self, phrase: Option<&Arc<RwLock<Phrase>>>) {
self.mode.set_phrase(phrase) self.mode.set_phrase(phrase)
} }
} }
@ -264,25 +254,32 @@ impl PhraseEditorPoint {
impl PhraseEditorModel { impl PhraseEditorModel {
/// Put note at current position /// Put note at current position
pub fn put_note (&mut self, advance: bool) { pub fn put_note (&mut self, advance: bool) {
if let Some(phrase) = &*self.phrase.read().unwrap() { let mut redraw = false;
let point = self.point().clone(); if let Some(phrase) = self.phrase() {
let note_len = point.note_len.load(Relaxed);
let time = point.time_point.load(Relaxed);
let note = point.note_point.load(Relaxed);
let mut phrase = phrase.write().unwrap(); 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 vel: u7 = 100.into();
let start = time; let length = phrase.length;
let end = (start + note_len) % phrase.length; let note_end = note_end % length;
phrase.notes[time].push(MidiMessage::NoteOn { key, vel }); let note_on = MidiMessage::NoteOn { key, vel };
phrase.notes[end].push(MidiMessage::NoteOff { key, vel }); if !phrase.notes[note_start].iter().any(|msg|*msg == note_on) {
self.mode.redraw(); phrase.notes[note_start].push(note_on);
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 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<RwLock<Phrase>>> for PhraseEditorModel {
impl From<Option<Arc<RwLock<Phrase>>>> for PhraseEditorModel { impl From<Option<Arc<RwLock<Phrase>>>> for PhraseEditorModel {
fn from (phrase: Option<Arc<RwLock<Phrase>>>) -> Self { fn from (phrase: Option<Arc<RwLock<Phrase>>>) -> Self {
let model = Self::default(); let mut model = Self::default();
*model.phrase.write().unwrap() = phrase; *model.phrase_mut() = phrase;
model model
} }
} }

View file

@ -3,7 +3,7 @@ use super::*;
/// A phrase, rendered as a horizontal piano roll. /// A phrase, rendered as a horizontal piano roll.
pub struct PianoHorizontal { pub struct PianoHorizontal {
phrase: Arc<RwLock<Option<Arc<RwLock<Phrase>>>>>, phrase: Option<Arc<RwLock<Phrase>>>,
/// Buffer where the whole phrase is rerendered on change /// Buffer where the whole phrase is rerendered on change
buffer: BigBuffer, buffer: BigBuffer,
/// Width and height of notes area at last render /// Width and height of notes area at last render
@ -17,13 +17,13 @@ pub struct PianoHorizontal {
} }
impl PianoHorizontal { impl PianoHorizontal {
pub fn new (phrase: &Arc<RwLock<Option<Arc<RwLock<Phrase>>>>>) -> Self { pub fn new (phrase: Option<&Arc<RwLock<Phrase>>>) -> Self {
let size = Measure::new(); let size = Measure::new();
let mut range = PhraseEditorRange::default(); let mut range = PhraseEditorRange::default();
range.time_axis = size.x.clone(); range.time_axis = size.x.clone();
range.note_axis = size.y.clone(); range.note_axis = size.y.clone();
let phrase = phrase.clone(); let phrase = phrase.map(|p|p.clone());
let color = phrase.read().unwrap().as_ref() let color = phrase.as_ref()
.map(|p|p.read().unwrap().color) .map(|p|p.read().unwrap().color)
.unwrap_or(ItemPalette::from(ItemColor::from(TuiTheme::g(64)))); .unwrap_or(ItemPalette::from(ItemColor::from(TuiTheme::g(64))));
Self { Self {
@ -242,9 +242,12 @@ impl PianoHorizontal {
} }
impl PhraseViewMode for PianoHorizontal { impl PhraseViewMode for PianoHorizontal {
fn phrase (&self) -> &Arc<RwLock<Option<Arc<RwLock<Phrase>>>>> { fn phrase (&self) -> &Option<Arc<RwLock<Phrase>>> {
&self.phrase &self.phrase
} }
fn phrase_mut (&mut self) -> &mut Option<Arc<RwLock<Phrase>>> {
&mut self.phrase
}
fn range (&self) -> &PhraseEditorRange { fn range (&self) -> &PhraseEditorRange {
&self.range &self.range
} }
@ -256,9 +259,10 @@ impl PhraseViewMode for PianoHorizontal {
(phrase.length / self.range.time_zoom(), 128) (phrase.length / self.range.time_zoom(), 128)
} }
fn redraw (&mut self) { 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 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 note_len = self.point.note_len();
let time_zoom = self.range.time_zoom(); let time_zoom = self.range.time_zoom();
PianoHorizontal::draw_bg(&mut buffer, &phrase, time_zoom, note_len); PianoHorizontal::draw_bg(&mut buffer, &phrase, time_zoom, note_len);
@ -269,10 +273,9 @@ impl PhraseViewMode for PianoHorizontal {
}; };
self.buffer = buffer self.buffer = buffer
} }
fn set_phrase (&mut self, phrase: Option<Arc<RwLock<Phrase>>>) { fn set_phrase (&mut self, phrase: Option<&Arc<RwLock<Phrase>>>) {
*self.phrase().write().unwrap() = phrase; *self.phrase_mut() = phrase.map(|p|p.clone());
self.color = self.phrase.read().unwrap().as_ref() self.color = phrase.map(|p|p.read().unwrap().color.clone())
.map(|p|p.read().unwrap().color)
.unwrap_or(ItemPalette::from(ItemColor::from(TuiTheme::g(64)))); .unwrap_or(ItemPalette::from(ItemColor::from(TuiTheme::g(64))));
self.redraw(); self.redraw();
} }