wip: phrases by reference instead of index

This commit is contained in:
🪞👃🪞 2024-10-08 13:56:46 +03:00
parent 25e54eba4e
commit 5b2b04dcf9
2 changed files with 147 additions and 113 deletions

View file

@ -48,7 +48,7 @@ pub struct ArrangementTrack<E: Engine> {
#[derive(Default)]
pub struct Scene {
pub name: Arc<RwLock<String>>,
pub clips: Vec<Option<usize>>,
pub clips: Vec<Option<Arc<RwLock<Phrase>>>>,
}
#[derive(PartialEq, Clone, Copy)]
/// Represents the current user selection in the arranger
@ -89,6 +89,7 @@ pub struct ArrangerRenameModal<E: Engine> {
pub result: Arc<RwLock<String>>,
pub cursor: usize
}
/// General methods for arrangement
impl<E: Engine> Arrangement<E> {
pub fn new (name: &str, phrases: &Arc<RwLock<PhrasePool<E>>>) -> Self {
Self {
@ -104,38 +105,18 @@ impl<E: Engine> Arrangement<E> {
pub fn activate (&mut self) {
match self.selected {
ArrangementFocus::Scene(s) => {
for (track_index, track) in self.tracks.iter_mut().enumerate() {
track.player.phrase = self.scenes[s].clips[track_index];
for (t, track) in self.tracks.iter_mut().enumerate() {
track.player.phrase = self.scenes[s].clips[t].clone();
track.player.reset = true;
}
},
ArrangementFocus::Clip(t, s) => {
self.tracks[t].player.phrase = self.scenes[s].clips[t];
self.tracks[t].player.phrase = self.scenes[s].clips[t].clone();
self.tracks[t].player.reset = true;
},
_ => {}
}
}
pub fn sequencer (&self) -> Option<&ArrangementTrack<E>> {
self.selected.track()
.map(|track|self.tracks.get(track))
.flatten()
}
pub fn sequencer_mut (&mut self) -> Option<&mut ArrangementTrack<E>> {
self.selected.track()
.map(|track|self.tracks.get_mut(track))
.flatten()
}
pub fn show_phrase (&mut self) {
let (scene, track) = (self.selected.scene(), self.selected.track());
if let (Some(scene_index), Some(track_index)) = (scene, track) {
let scene = self.scenes.get(scene_index);
let track = self.tracks.get_mut(track_index);
if let (Some(scene), Some(track)) = (scene, track) {
track.player.phrase = scene.clips[track_index]
}
}
}
pub fn is_first_row (&self) -> bool {
let selected = self.selected;
selected.is_mix() || selected.is_track()
@ -150,10 +131,13 @@ impl<E: Engine> Arrangement<E> {
_ => false
}
}
pub fn track (&self) -> Option<&PhrasePlayer<E>> {
}
/// Methods for tracks in arrangement
impl<E: Engine> Arrangement<E> {
pub fn track (&self) -> Option<&ArrangementTrack<E>> {
self.selected.track().map(|t|self.tracks.get(t)).flatten()
}
pub fn track_mut (&mut self) -> Option<&mut PhrasePlayer<E>> {
pub fn track_mut (&mut self) -> Option<&mut ArrangementTrack<E>> {
self.selected.track().map(|t|self.tracks.get_mut(t)).flatten()
}
pub fn track_next (&mut self) {
@ -164,8 +148,8 @@ impl<E: Engine> Arrangement<E> {
}
pub fn track_add (&mut self, name: Option<&str>) -> Usually<&mut ArrangementTrack<E>> {
self.tracks.push(name.map_or_else(
|| PhrasePlayer::new(&self.track_default_name()),
|name| PhrasePlayer::new(name),
|| ArrangementTrack::new(&self.track_default_name()),
|name| ArrangementTrack::new(name),
));
let index = self.tracks.len() - 1;
Ok(&mut self.tracks[index])
@ -176,6 +160,26 @@ impl<E: Engine> Arrangement<E> {
pub fn track_default_name (&self) -> String {
format!("Track {}", self.tracks.len() + 1)
}
pub fn track_widths (&self) -> Vec<(usize, usize)> {
let to_len = |track: &ArrangementTrack<E>|track.name.read().unwrap().len();
let mut lens: Vec<usize> = self.tracks.iter().map(to_len).collect();
for scene in self.scenes.iter() {
for track_index in 0..self.tracks.len() {
if let Some(phrase) = scene.clip(track_index) {
let len = phrase.read().unwrap().name.read().unwrap().len();
lens[track_index] = lens[track_index].max(len);
}
}
}
let mut total = 0;
let mut to_x_and_w = |len: &usize|{ total = total + *len; (total - *len, *len) };
let mut lens: Vec<(usize, usize)> = lens.iter().map(to_x_and_w).collect();
lens.push((0, total));
lens
}
}
/// Methods for scenes in arrangement
impl<E: Engine> Arrangement<E> {
pub fn scene (&self) -> Option<&Scene> {
self.selected.scene().map(|s|self.scenes.get(s)).flatten()
}
@ -203,9 +207,31 @@ impl<E: Engine> Arrangement<E> {
pub fn scene_default_name (&self) -> String {
format!("Scene {}", self.scenes.len() + 1)
}
pub fn phrase (&self) -> Option<&Arc<RwLock<Phrase>>> {
let track_id = self.selected.track()?;
self.tracks.get(track_id)?.phrases.get((*self.scene()?.clips.get(track_id)?)?)
}
/// Methods for phrases in arrangement
impl<E: Engine> Arrangement<E> {
pub fn sequencer (&self) -> Option<&ArrangementTrack<E>> {
self.selected.track()
.map(|track|self.tracks.get(track))
.flatten()
}
pub fn sequencer_mut (&mut self) -> Option<&mut ArrangementTrack<E>> {
self.selected.track()
.map(|track|self.tracks.get_mut(track))
.flatten()
}
pub fn show_phrase (&mut self) {
let (scene, track) = (self.selected.scene(), self.selected.track());
if let (Some(scene_index), Some(track_index)) = (scene, track) {
let scene = self.scenes.get(scene_index);
let track = self.tracks.get_mut(track_index);
if let (Some(scene), Some(track)) = (scene, track) {
track.player.phrase = scene.clips[track_index].clone()
}
}
}
pub fn phrase (&self) -> Option<Arc<RwLock<Phrase>>> {
self.scene()?.clips.get(self.selected.track()?)?.clone()
}
pub fn phrase_del (&mut self) {
let track_index = self.selected.track();
@ -219,72 +245,68 @@ impl<E: Engine> Arrangement<E> {
});
}
pub fn phrase_next (&mut self) {
let track_index = self.selected.track();
let scene_index = self.selected.scene();
track_index
.and_then(|index|self.tracks.get_mut(index).map(|track|(index, track)))
.and_then(|(track_index, track)|{
let phrases = track.phrases.len();
scene_index
.and_then(|index|self.scenes.get_mut(index))
.and_then(|scene|{
if let Some(phrase_index) = scene.clips[track_index] {
if phrase_index >= phrases - 1 {
scene.clips[track_index] = None;
} else {
scene.clips[track_index] = Some(phrase_index + 1);
}
} else if phrases > 0 {
scene.clips[track_index] = Some(0);
}
Some(())
})
});
todo!();
//let track_index = self.selected.track();
//let scene_index = self.selected.scene();
//track_index
//.and_then(|index|self.tracks.get_mut(index).map(|track|(index, track)))
//.and_then(|(track_index, track)|{
//let phrases = track.phrases.len();
//scene_index
//.and_then(|index|self.scenes.get_mut(index))
//.and_then(|scene|{
//if let Some(phrase_index) = scene.clips[track_index] {
//if phrase_index >= phrases - 1 {
//scene.clips[track_index] = None;
//} else {
//scene.clips[track_index] = Some(phrase_index + 1);
//}
//} else if phrases > 0 {
//scene.clips[track_index] = Some(0);
//}
//Some(())
//})
//});
}
pub fn phrase_prev (&mut self) {
let track_index = self.selected.track();
let scene_index = self.selected.scene();
track_index
.and_then(|index|self.tracks.get_mut(index).map(|track|(index, track)))
.and_then(|(track_index, track)|{
let phrases = track.phrases.len();
scene_index
.and_then(|index|self.scenes.get_mut(index))
.and_then(|scene|{
if let Some(phrase_index) = scene.clips[track_index] {
scene.clips[track_index] = if phrase_index == 0 {
None
} else {
Some(phrase_index - 1)
};
} else if phrases > 0 {
scene.clips[track_index] = Some(phrases - 1);
}
Some(())
})
});
todo!();
//let track_index = self.selected.track();
//let scene_index = self.selected.scene();
//track_index
//.and_then(|index|self.tracks.get_mut(index).map(|track|(index, track)))
//.and_then(|(track_index, track)|{
//let phrases = track.phrases.len();
//scene_index
//.and_then(|index|self.scenes.get_mut(index))
//.and_then(|scene|{
//if let Some(phrase_index) = scene.clips[track_index] {
//scene.clips[track_index] = if phrase_index == 0 {
//None
//} else {
//Some(phrase_index - 1)
//};
//} else if phrases > 0 {
//scene.clips[track_index] = Some(phrases - 1);
//}
//Some(())
//})
//});
}
}
impl<E: Engine> ArrangementTrack<E> {
pub fn new (name: &str) -> Self {
Self {
name: Arc::new(RwLock::new(name.into())),
inputs: vec![],
player: PhrasePlayer::new(name),
outputs: vec![],
}
}
pub fn longest_name (tracks: &[Self]) -> usize {
tracks.iter()
.map(|s|s.name.read().unwrap().len())
.fold(0, usize::max)
}
pub fn clip_name_lengths (tracks: &[Self]) -> Vec<(usize, usize)> {
let mut total = 0;
let mut lengths: Vec<(usize, usize)> = tracks.iter().map(|track|{
let len = 4 + track.phrases
.iter()
.fold(track.name.read().unwrap().len(), |len, phrase|{
len.max(phrase.read().unwrap().name.read().unwrap().len())
});
total = total + len;
(len, total - len)
}).collect();
lengths.push((0, total));
lengths
}
}
/// Focus identification methods
impl ArrangementFocus {
@ -309,12 +331,8 @@ impl ArrangementFocus {
tracks.get(*t),
scenes.get(*s),
) {
if let Some(Some(slot)) = scene.clips.get(*t) {
if let Some(clip) = track.phrases.get(*slot) {
format!("T{t} S{s} C{slot} ({})", &clip.read().unwrap().name.read().unwrap())
} else {
format!("T{t} S{s}: Empty")
}
if let Some(clip) = scene.clip(*t) {
format!("T{t} S{s} C{}", &clip.read().unwrap().name.read().unwrap())
} else {
format!("T{t} S{s}: Empty")
}
@ -428,7 +446,10 @@ impl<E: Engine + Send> Exit for ArrangerRenameModal<E> {
fn exit (&mut self) { self.done = true }
}
impl 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<Arc<RwLock<Phrase>>>]>
) -> Self {
Self {
name: Arc::new(RwLock::new(name.as_ref().into())),
clips: clips.as_ref().iter().map(|x|x.clone()).collect(),
@ -450,7 +471,7 @@ impl Scene {
/// Returns true if all phrases in the scene are currently playing
pub fn is_playing <E: Engine> (&self, tracks: &[ArrangementTrack<E>]) -> bool {
self.clips.iter().enumerate()
.all(|(track_index, phrase_index)|match phrase_index {
.all(|(track_index, clip)|match clip {
Some(i) => tracks
.get(track_index)
.map(|track|track.player.phrase == Some(*i))
@ -473,4 +494,11 @@ impl Scene {
.map(|s|s.name.read().unwrap().len())
.fold(0, usize::max)
}
pub fn clip (&self, index: usize) -> Option<&Arc<RwLock<Phrase>>> {
if let Some(Some(clip)) = self.clips.get(index) {
Some(clip)
} else {
None
}
}
}

View file

@ -58,9 +58,7 @@ impl Handle<Tui> for Arranger<Tui> {
} else if focus == 1 && is_last_row {
self.focus_next();
} else {
return
return self.focused_mut().handle(from)
}
},
key!(KeyCode::Up) => {
@ -93,12 +91,22 @@ impl Focus<3, Tui> for Arranger<Tui> {
impl Arranger<Tui> {
pub fn rename_selected (&mut self) {
let Arrangement { selected, ref name, ref tracks, ref scenes, .. } = self.arrangement;
self.modal = Some(Box::new(ArrangerRenameModal::new(selected, &match selected {
ArrangementFocus::Mix => name.clone(),
ArrangementFocus::Track(t) => tracks[t].name.clone(),
ArrangementFocus::Scene(s) => scenes[s].name.clone(),
ArrangementFocus::Clip(t, s) => tracks[t].phrases[s].read().unwrap().name.clone(),
})));
self.modal = match selected {
ArrangementFocus::Mix => {
Some(Box::new(ArrangerRenameModal::new(selected, &name)))
},
ArrangementFocus::Track(t) => {
Some(Box::new(ArrangerRenameModal::new(selected, &tracks[t].name)))
},
ArrangementFocus::Scene(s) => {
Some(Box::new(ArrangerRenameModal::new(selected, &scenes[s].name)))
},
ArrangementFocus::Clip(t, s) => if let Some(ref clip) = scenes[s].clips[t] {
Some(Box::new(ArrangerRenameModal::new(selected, &clip.read().unwrap().name)))
} else {
None
}
};
}
}
impl Focusable<Tui> for Arrangement<Tui> {
@ -212,10 +220,12 @@ impl<'a> Content for VerticalArranger<'a, Tui> {
fn content (&self) -> impl Widget<Engine = Tui> {
let Self(state, factor) = self;
let (cols, rows) = if *factor == 0 {(
ArrangementTrack::clip_name_lengths(state.tracks.as_slice()),
state.track_widths(),
//ArrangementTrack::clip_name_lengths(state.tracks.as_slice()),
Scene::ppqs(state.tracks.as_slice(), state.scenes.as_slice()),
)} else {(
ArrangementTrack::clip_name_lengths(state.tracks.as_slice()),
state.track_widths(),
//ArrangementTrack::clip_name_lengths(state.tracks.as_slice()),
(0..=state.scenes.len()).map(|i|(factor*PPQ, factor*PPQ*i)).collect::<Vec<_>>(),
)};
//let height = rows.last().map(|(w,y)|(y+w)/PPQ).unwrap_or(16);
@ -241,8 +251,7 @@ impl<'a> Content for VerticalArranger<'a, Tui> {
(Some(track), Some(Some(clip))) => match track.phrases.get(*clip) {
Some(phrase) => {
let name = &(phrase as &Arc<RwLock<Phrase>>).read().unwrap().name;
let name = name.read().unwrap();
let name = format!("{clip:02} {}", name);
let name = format!("{}", name.read().unwrap());
add(&name.as_str().push_x(1).fixed_x(w))?;
if (track as &PhrasePlayer<_>).phrase == Some(*clip) {
color = COLOR_PLAYING
@ -262,7 +271,7 @@ impl<'a> Content for VerticalArranger<'a, Tui> {
let playing = scene.is_playing(tracks);
Stack::right(move |add| {
add(&scene_name(scene, playing, height))?;
for (track, (w, _x)) in cols.iter().enumerate() {
for (track, (w, _)) in cols.iter().enumerate() {
add(&scene_clip(scene, track, *w as u16, height))?;
}
Ok(())
@ -572,10 +581,7 @@ impl<'a> Content for HorizontalArranger<'a, Tui> {
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.read().unwrap()),
None => "...."
};
let label = format!("{}", clip.read().unwrap().name.read().unwrap());
to.blit(&label, x + x2, y2, Some(if active_track && active_scene {
Style::default().not_dim().yellow().bold()
} else {
@ -617,7 +623,7 @@ impl Content for ArrangerRenameModal<Tui> {
//to.blit(&"▂", area.x() + 3 + label.len() as u16 + 1 + self.cursor as u16, y, style);
//Ok(Some(area))
//Ok(())
}
}
}
impl Handle<Tui> for ArrangerRenameModal<Tui> {
fn handle (&mut self, from: &TuiInput) -> Perhaps<bool> {