mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-08 12:46:42 +01:00
arranger: rename track/scene/clip
This commit is contained in:
parent
ea463db139
commit
70b1ec5a02
15 changed files with 53 additions and 40 deletions
|
|
@ -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)
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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};
|
||||||
|
|
|
||||||
|
|
@ -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(),
|
|
||||||
}
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
}]
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -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)?;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue