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 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::<Vec<_>>();
(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 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};

View file

@ -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<RwLock<String>>,
/// Collection of tracks.
pub tracks: Vec<Sequencer>,
/// 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(),
}
)));
}
}

View file

@ -75,4 +75,8 @@ pub const KEYMAP_ARRANGER: &'static [KeyBinding<Arranger>] = keymap!(Arranger {
arranger.rename_selected();
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),
};
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)?;

View file

@ -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<RwLock<String>>,
cursor: usize
}
impl ArrangerRenameModal {
pub fn new (target: ArrangerFocus, value: String) -> Self {
pub fn new (target: ArrangerFocus, value: &Arc<RwLock<String>>) -> 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);

View file

@ -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)

View file

@ -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 {

View file

@ -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,

View file

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

View file

@ -3,7 +3,7 @@ use crate::*;
#[derive(Debug)]
/// A MIDI sequence.
pub struct Phrase {
pub name: String,
pub name: Arc<RwLock<String>>,
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<PhraseData>) -> 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)
}
}

View file

@ -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<RwLock<String>>,
pub clips: Vec<Option<usize>>,
}
@ -32,7 +32,7 @@ impl Scene {
Ok(scene)
}
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();
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)
}

View file

@ -3,7 +3,7 @@ use tek_core::Direction;
/// Phrase editor.
pub struct Sequencer {
pub name: String,
pub name: Arc<RwLock<String>>,
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,

View file

@ -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;

View file

@ -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)
}
}