diff --git a/crates/tek/src/main.rs b/crates/tek/src/main.rs index 630a10ba..0d97dd14 100644 --- a/crates/tek/src/main.rs +++ b/crates/tek/src/main.rs @@ -36,7 +36,7 @@ pub fn main () -> Usually<()> { let jack = app.jack.as_ref().unwrap(); let midi_in = jack.register_port("midi-in", MidiIn)?; let midi_outs = app.arranger.tracks.iter() - .map(|t|Some(jack.register_port(&t.name, MidiOut).unwrap())) + .map(|t|Some(jack.register_port(&t.name.read().unwrap(), MidiOut).unwrap())) .collect::>(); (midi_in, midi_outs) }; diff --git a/crates/tek_core/src/lib.rs b/crates/tek_core/src/lib.rs index 4c12a852..eb253797 100644 --- a/crates/tek_core/src/lib.rs +++ b/crates/tek_core/src/lib.rs @@ -11,6 +11,8 @@ pub use ratatui::style::Stylize; pub use clojure_reader::{edn::{read, Edn}, error::Error as EdnError}; pub use once_cell::sync::Lazy; pub use std::sync::atomic::{Ordering, AtomicBool}; +pub use std::rc::Rc; +pub use std::cell::RefCell; pub(crate) use std::error::Error; pub(crate) use std::io::{stdout}; diff --git a/crates/tek_sequencer/src/arranger.rs b/crates/tek_sequencer/src/arranger.rs index e2acc077..0d91d0a6 100644 --- a/crates/tek_sequencer/src/arranger.rs +++ b/crates/tek_sequencer/src/arranger.rs @@ -6,7 +6,7 @@ use tek_core::Direction; /// Represents the tracks and scenes of the composition. pub struct Arranger { /// Name of arranger - pub name: String, + pub name: Arc>, /// Collection of tracks. pub tracks: Vec, /// Collection of scenes. @@ -25,7 +25,7 @@ pub struct Arranger { impl Arranger { pub fn new (name: &str) -> Self { Self { - name: name.into(), + name: Arc::new(RwLock::new(name.into())), mode: ArrangerViewMode::VerticalCompact2, selected: ArrangerFocus::Clip(0, 0), scenes: vec![], @@ -67,15 +67,4 @@ impl Arranger { //self.sequencer.show(phrase) Ok(()) } - pub fn rename_selected (&mut self) { - self.modal = Some(Box::new(ArrangerRenameModal::new( - self.selected, - match self.selected { - ArrangerFocus::Mix => self.name.clone(), - ArrangerFocus::Track(t) => self.tracks[t].name.clone(), - ArrangerFocus::Scene(s) => self.scenes[s].name.clone(), - ArrangerFocus::Clip(t, s) => self.tracks[t].phrases[s].read().unwrap().name.clone(), - } - ))); - } } diff --git a/crates/tek_sequencer/src/arranger_handle.rs b/crates/tek_sequencer/src/arranger_handle.rs index 53aa0603..b2e0552f 100644 --- a/crates/tek_sequencer/src/arranger_handle.rs +++ b/crates/tek_sequencer/src/arranger_handle.rs @@ -75,4 +75,8 @@ pub const KEYMAP_ARRANGER: &'static [KeyBinding] = keymap!(Arranger { arranger.rename_selected(); Ok(true) }], + [Char('l'), NONE, "length", "set length of item at cursor", |arranger: &mut Arranger| { + todo!(); + Ok(true) + }] }); diff --git a/crates/tek_sequencer/src/arranger_main.rs b/crates/tek_sequencer/src/arranger_main.rs index 50a86ed9..cffb6fed 100644 --- a/crates/tek_sequencer/src/arranger_main.rs +++ b/crates/tek_sequencer/src/arranger_main.rs @@ -40,7 +40,7 @@ impl ArrangerStandalone { show_sequencer: Some(tek_core::Direction::Down), }; if let Some(name) = args.name { - app.arranger.name = name.clone(); + *app.arranger.name.write().unwrap() = name.clone(); } for _ in 0..args.tracks { let track = app.arranger.track_add(None)?; diff --git a/crates/tek_sequencer/src/arranger_modal.rs b/crates/tek_sequencer/src/arranger_rename.rs similarity index 75% rename from crates/tek_sequencer/src/arranger_modal.rs rename to crates/tek_sequencer/src/arranger_rename.rs index 3de7313f..3075407f 100644 --- a/crates/tek_sequencer/src/arranger_modal.rs +++ b/crates/tek_sequencer/src/arranger_rename.rs @@ -1,20 +1,36 @@ use crate::*; +impl Arranger { + pub fn rename_selected (&mut self) { + self.modal = Some(Box::new(ArrangerRenameModal::new( + self.selected, + &match self.selected { + ArrangerFocus::Mix => self.name.clone(), + ArrangerFocus::Track(t) => self.tracks[t].name.clone(), + ArrangerFocus::Scene(s) => self.scenes[s].name.clone(), + ArrangerFocus::Clip(t, s) => self.tracks[t].phrases[s].read().unwrap().name.clone(), + } + ))); + } +} + /// Appears on first run (i.e. if state dir is missing). pub struct ArrangerRenameModal { done: bool, target: ArrangerFocus, value: String, + result: Arc>, cursor: usize } impl ArrangerRenameModal { - pub fn new (target: ArrangerFocus, value: String) -> Self { + pub fn new (target: ArrangerFocus, value: &Arc>) -> Self { Self { done: false, target, - value: value.to_string(), - cursor: value.len() + value: value.read().unwrap().clone(), + cursor: value.read().unwrap().len(), + result: value.clone(), } } } @@ -52,7 +68,8 @@ handle!(ArrangerRenameModal |self, e| { self.exit(); }, KeyCode::Enter => { - todo!(); + *self.result.write().unwrap() = self.value.clone(); + self.exit(); }, KeyCode::Left => { self.cursor = self.cursor.saturating_sub(1); diff --git a/crates/tek_sequencer/src/arranger_track.rs b/crates/tek_sequencer/src/arranger_track.rs index bbb3445a..53b30aa4 100644 --- a/crates/tek_sequencer/src/arranger_track.rs +++ b/crates/tek_sequencer/src/arranger_track.rs @@ -34,7 +34,7 @@ impl Arranger { pub fn track_name_max_len (tracks: &[Sequencer]) -> usize { tracks.iter() - .map(|s|s.name.len()) + .map(|s|s.name.read().unwrap().len()) .fold(0, usize::max) } @@ -43,8 +43,8 @@ pub fn track_clip_name_lengths (tracks: &[Sequencer]) -> Vec<(usize, usize)> { let mut lengths: Vec<(usize, usize)> = tracks.iter().map(|track|{ let len = 4 + track.phrases .iter() - .fold(track.name.len(), |len, phrase|{ - len.max(phrase.read().unwrap().name.len()) + .fold(track.name.read().unwrap().len(), |len, phrase|{ + len.max(phrase.read().unwrap().name.read().unwrap().len()) }); total = total + len; (len, total - len) diff --git a/crates/tek_sequencer/src/arranger_view_h.rs b/crates/tek_sequencer/src/arranger_view_h.rs index 1a483301..923c801c 100644 --- a/crates/tek_sequencer/src/arranger_view_h.rs +++ b/crates/tek_sequencer/src/arranger_view_h.rs @@ -34,7 +34,7 @@ impl<'a> Render for TrackNameColumn<'a> { let selected = selected.track() == Some(index); let style = if selected { yellow } else { white }; format!(" {index:>02} ").blit(buf, area.x, area.y + y, style)?; - track.name.blit(buf, area.x + 4, area.y + y, style)?; + track.name.read().unwrap().blit(buf, area.x + 4, area.y + y, style)?; } } } @@ -193,14 +193,15 @@ impl<'a> Render for TrackScenesColumn<'a> { for y in y+1..y+height { "│".blit(buf, x + x2, y, sep)?; } - let mut x3 = scene.name.len() as u16; - scene.name.blit(buf, x + x2, y, sep)?; + let name = scene.name.read().unwrap(); + let mut x3 = name.len() as u16; + name.blit(buf, x + x2, y, sep)?; for (i, clip) in scene.clips.iter().enumerate() { let active_track = selected.track() == Some(i); if let Some(clip) = clip { let y2 = y + 2 + i as u16 * 2; let label = match tracks[i].phrases.get(*clip) { - Some(phrase) => &format!("{}", phrase.read().unwrap().name), + Some(phrase) => &format!("{}", phrase.read().unwrap().name.read().unwrap()), None => "...." }; label.blit(buf, x + x2, y2, Some(if active_track && active_scene { diff --git a/crates/tek_sequencer/src/arranger_view_v.rs b/crates/tek_sequencer/src/arranger_view_v.rs index 101505cd..596a7a3b 100644 --- a/crates/tek_sequencer/src/arranger_view_v.rs +++ b/crates/tek_sequencer/src/arranger_view_v.rs @@ -162,7 +162,7 @@ impl<'a> Render for TracksHeader<'a> { if x > width { break } - track.name.blit(buf, offset + x + 1, y, Some(Style::default()))?; + track.name.read().unwrap().blit(buf, offset + x + 1, y, Some(Style::default()))?; } Ok(Rect { x: area.x, y, width, height: 2 }) } @@ -211,7 +211,7 @@ fn scene_row <'a> ( let Rect { y, width, .. } = area; let playing = scene.is_playing(tracks); (if playing { "▶" } else { " " }).blit(buf, area.x, y, None)?; - scene.name.blit(buf, area.x + 1, y, None)?; + scene.name.read().unwrap().blit(buf, area.x + 1, y, None)?; let style = Some(Style::default().white()); for (track, (w, x)) in track_cols.iter().enumerate() { let x = *x as u16 + offset; @@ -223,7 +223,7 @@ fn scene_row <'a> ( ) { if let Some(phrase) = track.phrases.get(*clip) { let phrase = phrase.read().unwrap(); - phrase.name.blit(buf, x + 1, y, style)?; + phrase.name.read().unwrap().blit(buf, x + 1, y, style)?; if track.sequence == Some(*clip) { fill_bg(buf, Rect { x: x - 1, diff --git a/crates/tek_sequencer/src/lib.rs b/crates/tek_sequencer/src/lib.rs index 219d38cf..ebd22e68 100644 --- a/crates/tek_sequencer/src/lib.rs +++ b/crates/tek_sequencer/src/lib.rs @@ -13,7 +13,7 @@ submod! { arranger_handle arranger_track arranger_view - arranger_modal + arranger_rename midi phrase scene diff --git a/crates/tek_sequencer/src/phrase.rs b/crates/tek_sequencer/src/phrase.rs index f7bbc852..8c70f393 100644 --- a/crates/tek_sequencer/src/phrase.rs +++ b/crates/tek_sequencer/src/phrase.rs @@ -3,7 +3,7 @@ use crate::*; #[derive(Debug)] /// A MIDI sequence. pub struct Phrase { - pub name: String, + pub name: Arc>, pub length: usize, pub notes: PhraseData, pub looped: Option<(usize, usize)>, @@ -22,7 +22,7 @@ impl Default for Phrase { impl Phrase { pub fn new (name: &str, length: usize, notes: Option) -> Self { Self { - name: name.to_string(), + name: Arc::new(RwLock::new(name.into())), length, notes: notes.unwrap_or(vec![Vec::with_capacity(16);length]), looped: Some((0, length)), @@ -130,7 +130,7 @@ impl Phrase { }, _ => panic!("unexpected in phrase '{name}': {edn:?}"), }); - phrase.name = name; + *phrase.name.write().unwrap() = name; Ok(phrase) } } diff --git a/crates/tek_sequencer/src/scene.rs b/crates/tek_sequencer/src/scene.rs index bb832324..747ad78b 100644 --- a/crates/tek_sequencer/src/scene.rs +++ b/crates/tek_sequencer/src/scene.rs @@ -3,7 +3,7 @@ use crate::*; /// A collection of phrases to play on each track. #[derive(Default)] pub struct Scene { - pub name: String, + pub name: Arc>, pub clips: Vec>, } @@ -32,7 +32,7 @@ impl Scene { Ok(scene) } pub fn new (name: impl AsRef, clips: impl AsRef<[Option]>) -> Self { - let name = name.as_ref().into(); + let name = Arc::new(RwLock::new(name.as_ref().into())); let clips = clips.as_ref().iter().map(|x|x.clone()).collect(); Self { name, clips, } } @@ -55,7 +55,7 @@ impl Scene { pub fn scene_name_max_len (scenes: &[Scene]) -> usize { scenes.iter() - .map(|s|s.name.len()) + .map(|s|s.name.read().unwrap().len()) .fold(0, usize::max) } diff --git a/crates/tek_sequencer/src/sequencer.rs b/crates/tek_sequencer/src/sequencer.rs index 4fe1e265..bbb31ec2 100644 --- a/crates/tek_sequencer/src/sequencer.rs +++ b/crates/tek_sequencer/src/sequencer.rs @@ -3,7 +3,7 @@ use tek_core::Direction; /// Phrase editor. pub struct Sequencer { - pub name: String, + pub name: Arc>, pub mode: bool, pub focused: bool, pub entered: bool, @@ -46,7 +46,7 @@ pub struct Sequencer { impl Sequencer { pub fn new (name: &str) -> Self { Self { - name: name.into(), + name: Arc::new(RwLock::new(name.into())), monitoring: false, recording: false, overdub: true, diff --git a/crates/tek_sequencer/src/sequencer_cli.rs b/crates/tek_sequencer/src/sequencer_cli.rs index fc597206..71bf2283 100644 --- a/crates/tek_sequencer/src/sequencer_cli.rs +++ b/crates/tek_sequencer/src/sequencer_cli.rs @@ -19,7 +19,7 @@ impl Sequencer { let args = SequencerCli::parse(); let mut seq = Self::new(""); if let Some(name) = args.name { - seq.name = name.clone(); + seq.name = Arc::new(RwLock::new(name.clone())); } if let Some(ppq) = args.ppq { seq.ppq = ppq; diff --git a/crates/tek_sequencer/src/sequencer_view_h.rs b/crates/tek_sequencer/src/sequencer_view_h.rs index 785294db..dcf16707 100644 --- a/crates/tek_sequencer/src/sequencer_view_h.rs +++ b/crates/tek_sequencer/src/sequencer_view_h.rs @@ -53,7 +53,7 @@ impl<'a> Render for SequenceName<'a> { let frame = Rect { x, y, width: 10, height: 4 }; Lozenge(Style::default().fg(Nord::BG2)).draw(buf, frame)?; "Name:".blit(buf, x + 1, y + 1, STYLE_LABEL)?; - self.0.name.blit(buf, x + 1, y + 2, STYLE_VALUE)?; + self.0.name.read().unwrap().blit(buf, x + 1, y + 2, STYLE_VALUE)?; Ok(frame) } }