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)] #[derive(Default)]
pub struct Scene { pub struct Scene {
pub name: Arc<RwLock<String>>, pub name: Arc<RwLock<String>>,
pub clips: Vec<Option<usize>>, pub clips: Vec<Option<Arc<RwLock<Phrase>>>>,
} }
#[derive(PartialEq, Clone, Copy)] #[derive(PartialEq, Clone, Copy)]
/// Represents the current user selection in the arranger /// Represents the current user selection in the arranger
@ -89,6 +89,7 @@ pub struct ArrangerRenameModal<E: Engine> {
pub result: Arc<RwLock<String>>, pub result: Arc<RwLock<String>>,
pub cursor: usize pub cursor: usize
} }
/// General methods for arrangement
impl<E: Engine> Arrangement<E> { impl<E: Engine> Arrangement<E> {
pub fn new (name: &str, phrases: &Arc<RwLock<PhrasePool<E>>>) -> Self { pub fn new (name: &str, phrases: &Arc<RwLock<PhrasePool<E>>>) -> Self {
Self { Self {
@ -104,38 +105,18 @@ impl<E: Engine> Arrangement<E> {
pub fn activate (&mut self) { pub fn activate (&mut self) {
match self.selected { match self.selected {
ArrangementFocus::Scene(s) => { ArrangementFocus::Scene(s) => {
for (track_index, track) in self.tracks.iter_mut().enumerate() { for (t, track) in self.tracks.iter_mut().enumerate() {
track.player.phrase = self.scenes[s].clips[track_index]; track.player.phrase = self.scenes[s].clips[t].clone();
track.player.reset = true; track.player.reset = true;
} }
}, },
ArrangementFocus::Clip(t, s) => { 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; 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 { pub fn is_first_row (&self) -> bool {
let selected = self.selected; let selected = self.selected;
selected.is_mix() || selected.is_track() selected.is_mix() || selected.is_track()
@ -150,10 +131,13 @@ impl<E: Engine> Arrangement<E> {
_ => false _ => 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() 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() self.selected.track().map(|t|self.tracks.get_mut(t)).flatten()
} }
pub fn track_next (&mut self) { 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>> { pub fn track_add (&mut self, name: Option<&str>) -> Usually<&mut ArrangementTrack<E>> {
self.tracks.push(name.map_or_else( self.tracks.push(name.map_or_else(
|| PhrasePlayer::new(&self.track_default_name()), || ArrangementTrack::new(&self.track_default_name()),
|name| PhrasePlayer::new(name), |name| ArrangementTrack::new(name),
)); ));
let index = self.tracks.len() - 1; let index = self.tracks.len() - 1;
Ok(&mut self.tracks[index]) Ok(&mut self.tracks[index])
@ -176,6 +160,26 @@ impl<E: Engine> Arrangement<E> {
pub fn track_default_name (&self) -> String { pub fn track_default_name (&self) -> String {
format!("Track {}", self.tracks.len() + 1) 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> { pub fn scene (&self) -> Option<&Scene> {
self.selected.scene().map(|s|self.scenes.get(s)).flatten() 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 { pub fn scene_default_name (&self) -> String {
format!("Scene {}", self.scenes.len() + 1) format!("Scene {}", self.scenes.len() + 1)
} }
pub fn phrase (&self) -> Option<&Arc<RwLock<Phrase>>> { }
let track_id = self.selected.track()?; /// Methods for phrases in arrangement
self.tracks.get(track_id)?.phrases.get((*self.scene()?.clips.get(track_id)?)?) 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) { pub fn phrase_del (&mut self) {
let track_index = self.selected.track(); let track_index = self.selected.track();
@ -219,72 +245,68 @@ impl<E: Engine> Arrangement<E> {
}); });
} }
pub fn phrase_next (&mut self) { pub fn phrase_next (&mut self) {
let track_index = self.selected.track(); todo!();
let scene_index = self.selected.scene(); //let track_index = self.selected.track();
track_index //let scene_index = self.selected.scene();
.and_then(|index|self.tracks.get_mut(index).map(|track|(index, track))) //track_index
.and_then(|(track_index, track)|{ //.and_then(|index|self.tracks.get_mut(index).map(|track|(index, track)))
let phrases = track.phrases.len(); //.and_then(|(track_index, track)|{
scene_index //let phrases = track.phrases.len();
.and_then(|index|self.scenes.get_mut(index)) //scene_index
.and_then(|scene|{ //.and_then(|index|self.scenes.get_mut(index))
if let Some(phrase_index) = scene.clips[track_index] { //.and_then(|scene|{
if phrase_index >= phrases - 1 { //if let Some(phrase_index) = scene.clips[track_index] {
scene.clips[track_index] = None; //if phrase_index >= phrases - 1 {
} else { //scene.clips[track_index] = None;
scene.clips[track_index] = Some(phrase_index + 1); //} else {
} //scene.clips[track_index] = Some(phrase_index + 1);
} else if phrases > 0 { //}
scene.clips[track_index] = Some(0); //} else if phrases > 0 {
} //scene.clips[track_index] = Some(0);
Some(()) //}
}) //Some(())
}); //})
//});
} }
pub fn phrase_prev (&mut self) { pub fn phrase_prev (&mut self) {
let track_index = self.selected.track(); todo!();
let scene_index = self.selected.scene(); //let track_index = self.selected.track();
track_index //let scene_index = self.selected.scene();
.and_then(|index|self.tracks.get_mut(index).map(|track|(index, track))) //track_index
.and_then(|(track_index, track)|{ //.and_then(|index|self.tracks.get_mut(index).map(|track|(index, track)))
let phrases = track.phrases.len(); //.and_then(|(track_index, track)|{
scene_index //let phrases = track.phrases.len();
.and_then(|index|self.scenes.get_mut(index)) //scene_index
.and_then(|scene|{ //.and_then(|index|self.scenes.get_mut(index))
if let Some(phrase_index) = scene.clips[track_index] { //.and_then(|scene|{
scene.clips[track_index] = if phrase_index == 0 { //if let Some(phrase_index) = scene.clips[track_index] {
None //scene.clips[track_index] = if phrase_index == 0 {
} else { //None
Some(phrase_index - 1) //} else {
}; //Some(phrase_index - 1)
} else if phrases > 0 { //};
scene.clips[track_index] = Some(phrases - 1); //} else if phrases > 0 {
} //scene.clips[track_index] = Some(phrases - 1);
Some(()) //}
}) //Some(())
}); //})
//});
} }
} }
impl<E: Engine> ArrangementTrack<E> { 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 { pub fn longest_name (tracks: &[Self]) -> usize {
tracks.iter() tracks.iter()
.map(|s|s.name.read().unwrap().len()) .map(|s|s.name.read().unwrap().len())
.fold(0, usize::max) .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 /// Focus identification methods
impl ArrangementFocus { impl ArrangementFocus {
@ -309,12 +331,8 @@ impl ArrangementFocus {
tracks.get(*t), tracks.get(*t),
scenes.get(*s), scenes.get(*s),
) { ) {
if let Some(Some(slot)) = scene.clips.get(*t) { if let Some(clip) = scene.clip(*t) {
if let Some(clip) = track.phrases.get(*slot) { format!("T{t} S{s} C{}", &clip.read().unwrap().name.read().unwrap())
format!("T{t} S{s} C{slot} ({})", &clip.read().unwrap().name.read().unwrap())
} else {
format!("T{t} S{s}: Empty")
}
} else { } else {
format!("T{t} S{s}: Empty") 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 } fn exit (&mut self) { self.done = true }
} }
impl Scene { 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 { Self {
name: Arc::new(RwLock::new(name.as_ref().into())), name: Arc::new(RwLock::new(name.as_ref().into())),
clips: clips.as_ref().iter().map(|x|x.clone()).collect(), 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 /// Returns true if all phrases in the scene are currently playing
pub fn is_playing <E: Engine> (&self, tracks: &[ArrangementTrack<E>]) -> bool { pub fn is_playing <E: Engine> (&self, tracks: &[ArrangementTrack<E>]) -> bool {
self.clips.iter().enumerate() self.clips.iter().enumerate()
.all(|(track_index, phrase_index)|match phrase_index { .all(|(track_index, clip)|match clip {
Some(i) => tracks Some(i) => tracks
.get(track_index) .get(track_index)
.map(|track|track.player.phrase == Some(*i)) .map(|track|track.player.phrase == Some(*i))
@ -473,4 +494,11 @@ impl Scene {
.map(|s|s.name.read().unwrap().len()) .map(|s|s.name.read().unwrap().len())
.fold(0, usize::max) .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 { } else if focus == 1 && is_last_row {
self.focus_next(); self.focus_next();
} else { } else {
return
return self.focused_mut().handle(from) return self.focused_mut().handle(from)
} }
}, },
key!(KeyCode::Up) => { key!(KeyCode::Up) => {
@ -93,12 +91,22 @@ impl Focus<3, Tui> for Arranger<Tui> {
impl Arranger<Tui> { impl Arranger<Tui> {
pub fn rename_selected (&mut self) { pub fn rename_selected (&mut self) {
let Arrangement { selected, ref name, ref tracks, ref scenes, .. } = self.arrangement; let Arrangement { selected, ref name, ref tracks, ref scenes, .. } = self.arrangement;
self.modal = Some(Box::new(ArrangerRenameModal::new(selected, &match selected { self.modal = match selected {
ArrangementFocus::Mix => name.clone(), ArrangementFocus::Mix => {
ArrangementFocus::Track(t) => tracks[t].name.clone(), Some(Box::new(ArrangerRenameModal::new(selected, &name)))
ArrangementFocus::Scene(s) => scenes[s].name.clone(), },
ArrangementFocus::Clip(t, s) => tracks[t].phrases[s].read().unwrap().name.clone(), 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> { impl Focusable<Tui> for Arrangement<Tui> {
@ -212,10 +220,12 @@ impl<'a> Content for VerticalArranger<'a, Tui> {
fn content (&self) -> impl Widget<Engine = Tui> { fn content (&self) -> impl Widget<Engine = Tui> {
let Self(state, factor) = self; let Self(state, factor) = self;
let (cols, rows) = if *factor == 0 {( 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()), Scene::ppqs(state.tracks.as_slice(), state.scenes.as_slice()),
)} else {( )} 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<_>>(), (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); //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(track), Some(Some(clip))) => match track.phrases.get(*clip) {
Some(phrase) => { Some(phrase) => {
let name = &(phrase as &Arc<RwLock<Phrase>>).read().unwrap().name; let name = &(phrase as &Arc<RwLock<Phrase>>).read().unwrap().name;
let name = name.read().unwrap(); let name = format!("{}", name.read().unwrap());
let name = format!("{clip:02} {}", name);
add(&name.as_str().push_x(1).fixed_x(w))?; add(&name.as_str().push_x(1).fixed_x(w))?;
if (track as &PhrasePlayer<_>).phrase == Some(*clip) { if (track as &PhrasePlayer<_>).phrase == Some(*clip) {
color = COLOR_PLAYING color = COLOR_PLAYING
@ -262,7 +271,7 @@ impl<'a> Content for VerticalArranger<'a, Tui> {
let playing = scene.is_playing(tracks); let playing = scene.is_playing(tracks);
Stack::right(move |add| { Stack::right(move |add| {
add(&scene_name(scene, playing, height))?; 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))?; add(&scene_clip(scene, track, *w as u16, height))?;
} }
Ok(()) Ok(())
@ -572,10 +581,7 @@ impl<'a> Content for HorizontalArranger<'a, Tui> {
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 = format!("{}", clip.read().unwrap().name.read().unwrap());
Some(phrase) => &format!("{}", phrase.read().unwrap().name.read().unwrap()),
None => "...."
};
to.blit(&label, x + x2, y2, Some(if active_track && active_scene { to.blit(&label, x + x2, y2, Some(if active_track && active_scene {
Style::default().not_dim().yellow().bold() Style::default().not_dim().yellow().bold()
} else { } 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); //to.blit(&"▂", area.x() + 3 + label.len() as u16 + 1 + self.cursor as u16, y, style);
//Ok(Some(area)) //Ok(Some(area))
//Ok(()) //Ok(())
} }
} }
impl Handle<Tui> for ArrangerRenameModal<Tui> { impl Handle<Tui> for ArrangerRenameModal<Tui> {
fn handle (&mut self, from: &TuiInput) -> Perhaps<bool> { fn handle (&mut self, from: &TuiInput) -> Perhaps<bool> {