arranger: rename track/scene/clip

This commit is contained in:
🪞👃🪞 2024-08-22 19:00:58 +03:00
parent ea463db139
commit 70b1ec5a02
15 changed files with 53 additions and 40 deletions

View file

@ -36,7 +36,7 @@ pub fn main () -> Usually<()> {
let jack = app.jack.as_ref().unwrap(); let jack = app.jack.as_ref().unwrap();
let midi_in = jack.register_port("midi-in", MidiIn)?; let midi_in = jack.register_port("midi-in", MidiIn)?;
let midi_outs = app.arranger.tracks.iter() 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::<Vec<_>>(); .collect::<Vec<_>>();
(midi_in, midi_outs) (midi_in, midi_outs)
}; };

View file

@ -11,6 +11,8 @@ pub use ratatui::style::Stylize;
pub use clojure_reader::{edn::{read, Edn}, error::Error as EdnError}; pub use clojure_reader::{edn::{read, Edn}, error::Error as EdnError};
pub use once_cell::sync::Lazy; pub use once_cell::sync::Lazy;
pub use std::sync::atomic::{Ordering, AtomicBool}; 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::error::Error;
pub(crate) use std::io::{stdout}; pub(crate) use std::io::{stdout};

View file

@ -6,7 +6,7 @@ use tek_core::Direction;
/// Represents the tracks and scenes of the composition. /// Represents the tracks and scenes of the composition.
pub struct Arranger { pub struct Arranger {
/// Name of arranger /// Name of arranger
pub name: String, pub name: Arc<RwLock<String>>,
/// Collection of tracks. /// Collection of tracks.
pub tracks: Vec<Sequencer>, pub tracks: Vec<Sequencer>,
/// Collection of scenes. /// Collection of scenes.
@ -25,7 +25,7 @@ pub struct Arranger {
impl Arranger { impl Arranger {
pub fn new (name: &str) -> Self { pub fn new (name: &str) -> Self {
Self { Self {
name: name.into(), name: Arc::new(RwLock::new(name.into())),
mode: ArrangerViewMode::VerticalCompact2, mode: ArrangerViewMode::VerticalCompact2,
selected: ArrangerFocus::Clip(0, 0), selected: ArrangerFocus::Clip(0, 0),
scenes: vec![], scenes: vec![],
@ -67,15 +67,4 @@ impl Arranger {
//self.sequencer.show(phrase) //self.sequencer.show(phrase)
Ok(()) 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(),
}
)));
}
} }

View file

@ -75,4 +75,8 @@ pub const KEYMAP_ARRANGER: &'static [KeyBinding<Arranger>] = keymap!(Arranger {
arranger.rename_selected(); arranger.rename_selected();
Ok(true) Ok(true)
}], }],
[Char('l'), NONE, "length", "set length of item at cursor", |arranger: &mut Arranger| {
todo!();
Ok(true)
}]
}); });

View file

@ -40,7 +40,7 @@ impl ArrangerStandalone {
show_sequencer: Some(tek_core::Direction::Down), show_sequencer: Some(tek_core::Direction::Down),
}; };
if let Some(name) = args.name { if let Some(name) = args.name {
app.arranger.name = name.clone(); *app.arranger.name.write().unwrap() = name.clone();
} }
for _ in 0..args.tracks { for _ in 0..args.tracks {
let track = app.arranger.track_add(None)?; let track = app.arranger.track_add(None)?;

View file

@ -1,20 +1,36 @@
use crate::*; 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). /// Appears on first run (i.e. if state dir is missing).
pub struct ArrangerRenameModal { pub struct ArrangerRenameModal {
done: bool, done: bool,
target: ArrangerFocus, target: ArrangerFocus,
value: String, value: String,
result: Arc<RwLock<String>>,
cursor: usize cursor: usize
} }
impl ArrangerRenameModal { impl ArrangerRenameModal {
pub fn new (target: ArrangerFocus, value: String) -> Self { pub fn new (target: ArrangerFocus, value: &Arc<RwLock<String>>) -> Self {
Self { Self {
done: false, done: false,
target, target,
value: value.to_string(), value: value.read().unwrap().clone(),
cursor: value.len() cursor: value.read().unwrap().len(),
result: value.clone(),
} }
} }
} }
@ -52,7 +68,8 @@ handle!(ArrangerRenameModal |self, e| {
self.exit(); self.exit();
}, },
KeyCode::Enter => { KeyCode::Enter => {
todo!(); *self.result.write().unwrap() = self.value.clone();
self.exit();
}, },
KeyCode::Left => { KeyCode::Left => {
self.cursor = self.cursor.saturating_sub(1); self.cursor = self.cursor.saturating_sub(1);

View file

@ -34,7 +34,7 @@ impl Arranger {
pub fn track_name_max_len (tracks: &[Sequencer]) -> usize { pub fn track_name_max_len (tracks: &[Sequencer]) -> usize {
tracks.iter() tracks.iter()
.map(|s|s.name.len()) .map(|s|s.name.read().unwrap().len())
.fold(0, usize::max) .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 mut lengths: Vec<(usize, usize)> = tracks.iter().map(|track|{
let len = 4 + track.phrases let len = 4 + track.phrases
.iter() .iter()
.fold(track.name.len(), |len, phrase|{ .fold(track.name.read().unwrap().len(), |len, phrase|{
len.max(phrase.read().unwrap().name.len()) len.max(phrase.read().unwrap().name.read().unwrap().len())
}); });
total = total + len; total = total + len;
(len, total - len) (len, total - len)

View file

@ -34,7 +34,7 @@ impl<'a> Render for TrackNameColumn<'a> {
let selected = selected.track() == Some(index); let selected = selected.track() == Some(index);
let style = if selected { yellow } else { white }; let style = if selected { yellow } else { white };
format!(" {index:>02} ").blit(buf, area.x, area.y + y, style)?; 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 { for y in y+1..y+height {
"".blit(buf, x + x2, y, sep)?; "".blit(buf, x + x2, y, sep)?;
} }
let mut x3 = scene.name.len() as u16; let name = scene.name.read().unwrap();
scene.name.blit(buf, x + x2, y, sep)?; let mut x3 = name.len() as u16;
name.blit(buf, x + x2, y, sep)?;
for (i, clip) in scene.clips.iter().enumerate() { for (i, clip) in scene.clips.iter().enumerate() {
let active_track = selected.track() == Some(i); let active_track = selected.track() == Some(i);
if let Some(clip) = clip { if let Some(clip) = clip {
let y2 = y + 2 + i as u16 * 2; let y2 = y + 2 + i as u16 * 2;
let label = match tracks[i].phrases.get(*clip) { 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 => "...." None => "...."
}; };
label.blit(buf, x + x2, y2, Some(if active_track && active_scene { label.blit(buf, x + x2, y2, Some(if active_track && active_scene {

View file

@ -162,7 +162,7 @@ impl<'a> Render for TracksHeader<'a> {
if x > width { if x > width {
break 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 }) Ok(Rect { x: area.x, y, width, height: 2 })
} }
@ -211,7 +211,7 @@ fn scene_row <'a> (
let Rect { y, width, .. } = area; let Rect { y, width, .. } = area;
let playing = scene.is_playing(tracks); let playing = scene.is_playing(tracks);
(if playing { "" } else { " " }).blit(buf, area.x, y, None)?; (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()); let style = Some(Style::default().white());
for (track, (w, x)) in track_cols.iter().enumerate() { for (track, (w, x)) in track_cols.iter().enumerate() {
let x = *x as u16 + offset; let x = *x as u16 + offset;
@ -223,7 +223,7 @@ fn scene_row <'a> (
) { ) {
if let Some(phrase) = track.phrases.get(*clip) { if let Some(phrase) = track.phrases.get(*clip) {
let phrase = phrase.read().unwrap(); 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) { if track.sequence == Some(*clip) {
fill_bg(buf, Rect { fill_bg(buf, Rect {
x: x - 1, x: x - 1,

View file

@ -13,7 +13,7 @@ submod! {
arranger_handle arranger_handle
arranger_track arranger_track
arranger_view arranger_view
arranger_modal arranger_rename
midi midi
phrase phrase
scene scene

View file

@ -3,7 +3,7 @@ use crate::*;
#[derive(Debug)] #[derive(Debug)]
/// A MIDI sequence. /// A MIDI sequence.
pub struct Phrase { pub struct Phrase {
pub name: String, pub name: Arc<RwLock<String>>,
pub length: usize, pub length: usize,
pub notes: PhraseData, pub notes: PhraseData,
pub looped: Option<(usize, usize)>, pub looped: Option<(usize, usize)>,
@ -22,7 +22,7 @@ impl Default for Phrase {
impl Phrase { impl Phrase {
pub fn new (name: &str, length: usize, notes: Option<PhraseData>) -> Self { pub fn new (name: &str, length: usize, notes: Option<PhraseData>) -> Self {
Self { Self {
name: name.to_string(), name: Arc::new(RwLock::new(name.into())),
length, length,
notes: notes.unwrap_or(vec![Vec::with_capacity(16);length]), notes: notes.unwrap_or(vec![Vec::with_capacity(16);length]),
looped: Some((0, length)), looped: Some((0, length)),
@ -130,7 +130,7 @@ impl Phrase {
}, },
_ => panic!("unexpected in phrase '{name}': {edn:?}"), _ => panic!("unexpected in phrase '{name}': {edn:?}"),
}); });
phrase.name = name; *phrase.name.write().unwrap() = name;
Ok(phrase) Ok(phrase)
} }
} }

View file

@ -3,7 +3,7 @@ use crate::*;
/// A collection of phrases to play on each track. /// A collection of phrases to play on each track.
#[derive(Default)] #[derive(Default)]
pub struct Scene { pub struct Scene {
pub name: String, pub name: Arc<RwLock<String>>,
pub clips: Vec<Option<usize>>, pub clips: Vec<Option<usize>>,
} }
@ -32,7 +32,7 @@ impl Scene {
Ok(scene) Ok(scene)
} }
pub fn new (name: impl AsRef<str>, clips: impl AsRef<[Option<usize>]>) -> Self { pub fn new (name: impl AsRef<str>, clips: impl AsRef<[Option<usize>]>) -> 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(); let clips = clips.as_ref().iter().map(|x|x.clone()).collect();
Self { name, clips, } Self { name, clips, }
} }
@ -55,7 +55,7 @@ impl Scene {
pub fn scene_name_max_len (scenes: &[Scene]) -> usize { pub fn scene_name_max_len (scenes: &[Scene]) -> usize {
scenes.iter() scenes.iter()
.map(|s|s.name.len()) .map(|s|s.name.read().unwrap().len())
.fold(0, usize::max) .fold(0, usize::max)
} }

View file

@ -3,7 +3,7 @@ use tek_core::Direction;
/// Phrase editor. /// Phrase editor.
pub struct Sequencer { pub struct Sequencer {
pub name: String, pub name: Arc<RwLock<String>>,
pub mode: bool, pub mode: bool,
pub focused: bool, pub focused: bool,
pub entered: bool, pub entered: bool,
@ -46,7 +46,7 @@ pub struct Sequencer {
impl Sequencer { impl Sequencer {
pub fn new (name: &str) -> Self { pub fn new (name: &str) -> Self {
Self { Self {
name: name.into(), name: Arc::new(RwLock::new(name.into())),
monitoring: false, monitoring: false,
recording: false, recording: false,
overdub: true, overdub: true,

View file

@ -19,7 +19,7 @@ impl Sequencer {
let args = SequencerCli::parse(); let args = SequencerCli::parse();
let mut seq = Self::new(""); let mut seq = Self::new("");
if let Some(name) = args.name { if let Some(name) = args.name {
seq.name = name.clone(); seq.name = Arc::new(RwLock::new(name.clone()));
} }
if let Some(ppq) = args.ppq { if let Some(ppq) = args.ppq {
seq.ppq = ppq; seq.ppq = ppq;

View file

@ -53,7 +53,7 @@ impl<'a> Render for SequenceName<'a> {
let frame = Rect { x, y, width: 10, height: 4 }; let frame = Rect { x, y, width: 10, height: 4 };
Lozenge(Style::default().fg(Nord::BG2)).draw(buf, frame)?; Lozenge(Style::default().fg(Nord::BG2)).draw(buf, frame)?;
"Name:".blit(buf, x + 1, y + 1, STYLE_LABEL)?; "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) Ok(frame)
} }
} }