tek/src/model/arranger.rs

234 lines
7.4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use crate::{core::*, model::*};
/// Represents the tracks and scenes of the composition.
pub struct Arranger {
/// Display mode of arranger
pub mode: bool,
/// Currently selected element.
pub selected: ArrangerFocus,
/// Collection of tracks.
pub tracks: Vec<Track>,
/// Collection of scenes.
pub scenes: Vec<Scene>,
pub focused: bool,
pub entered: bool,
}
impl Arranger {
pub fn new () -> Self {
Self {
mode: false,
selected: ArrangerFocus::Clip(0, 0),
scenes: vec![],
tracks: vec![],
entered: true,
focused: true,
}
}
pub fn activate (&mut self) {
match self.selected {
ArrangerFocus::Scene(s) => {
for (track_index, track) in self.tracks.iter_mut().enumerate() {
track.sequence = self.scenes[s].clips[track_index];
track.reset = true;
}
},
ArrangerFocus::Clip(t, s) => {
self.tracks[t].sequence = self.scenes[s].clips[t];
self.tracks[t].reset = true;
},
_ => {}
}
}
}
/// Track management methods
impl Arranger {
pub fn track (&self) -> Option<&Track> {
self.selected.track().map(|t|self.tracks.get(t)).flatten()
}
pub fn track_mut (&mut self) -> Option<&mut Track> {
self.selected.track().map(|t|self.tracks.get_mut(t)).flatten()
}
pub fn track_next (&mut self) {
self.selected.track_next(self.tracks.len())
}
pub fn track_prev (&mut self) {
self.selected.track_prev()
}
pub fn track_add (&mut self, name: Option<&str>) -> Usually<&mut Track> {
self.tracks.push(name.map_or_else(
|| Track::new(&self.track_default_name()),
|name| Track::new(name),
)?);
let index = self.tracks.len() - 1;
Ok(&mut self.tracks[index])
}
pub fn track_del (&mut self) {
unimplemented!("Arranger::track_del");
}
pub fn track_default_name (&self) -> String {
format!("Track {}", self.tracks.len() + 1)
}
}
/// Scene management methods
impl Arranger {
pub fn scene (&self) -> Option<&Scene> {
self.selected.scene().map(|s|self.scenes.get(s)).flatten()
}
pub fn scene_mut (&mut self) -> Option<&mut Scene> {
self.selected.scene().map(|s|self.scenes.get_mut(s)).flatten()
}
pub fn scene_next (&mut self) {
self.selected.scene_next(self.scenes.len())
}
pub fn scene_prev (&mut self) {
self.selected.scene_prev()
}
pub fn scene_add (&mut self, name: Option<&str>) -> Usually<&mut Scene> {
let clips = vec![None;self.tracks.len()];
self.scenes.push(match name {
Some(name) => Scene::new(name, clips),
None => Scene::new(&self.track_default_name(), clips),
});
let index = self.scenes.len() - 1;
Ok(&mut self.scenes[index])
}
pub fn scene_del (&mut self) {
unimplemented!("Arranger::scene_del");
}
pub fn scene_default_name (&self) -> String {
format!("Scene {}", self.scenes.len() + 1)
}
}
/// Phrase management methods
impl Arranger {
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)?)?)
}
//pub fn phrase_mut (&mut self) -> Option<&mut Phrase> {
//let track_id = self.selected.track()?;
//let clip = *self.scene()?.clips.get(track_id)?;
//self.tracks.get_mut(track_id)?.phrases.get_mut(clip?)
//}
pub fn phrase_next (&mut self) {
unimplemented!();
//if let Some((track_index, track)) = self.track_mut() {
//let phrases = track.phrases.len();
//if let Some((_, scene)) = self.scene_mut() {
//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);
//}
//}
//}
}
pub fn phrase_prev (&mut self) {
unimplemented!();
//if let Some((track_index, track)) = self.track_mut() {
//let phrases = track.phrases.len();
//if let Some((_, scene)) = self.scene_mut() {
//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);
//}
//}
//}
}
}
#[derive(PartialEq)]
/// Represents the current user selection in the arranger
pub enum ArrangerFocus {
/// The whole mix is selected
Mix,
/// A track is selected.
Track(usize),
/// A scene is selected.
Scene(usize),
/// A clip (track × scene) is selected.
Clip(usize, usize),
}
/// Identification methods
impl ArrangerFocus {
pub fn is_track (&self) -> bool {
match self { Self::Track(_) => true, _ => false }
}
pub fn is_scene (&self) -> bool {
match self { Self::Scene(_) => true, _ => false }
}
pub fn is_clip (&self) -> bool {
match self { Self::Clip(_, _) => true, _ => false }
}
}
/// Track methods
impl ArrangerFocus {
pub fn track (&self) -> Option<usize> {
match self {
Self::Clip(t, _) => Some(*t),
Self::Track(t) => Some(*t),
_ => None
}
}
pub fn track_next (&mut self, last_track: usize) {
*self = match self {
Self::Mix => Self::Track(0),
Self::Track(t) => Self::Track(last_track.min(*t + 1)),
Self::Scene(s) => Self::Clip(0, *s),
Self::Clip(t, s) => Self::Clip(last_track.min(*t + 1), *s),
}
}
pub fn track_prev (&mut self) {
*self = match self {
Self::Mix => Self::Mix,
Self::Scene(s) => Self::Scene(*s),
Self::Track(0) => Self::Mix,
Self::Track(t) => Self::Track(*t - 1),
Self::Clip(t, s) => Self::Clip(t.saturating_sub(1), *s),
}
}
}
/// Scene methods
impl ArrangerFocus {
pub fn scene (&self) -> Option<usize> {
match self {
Self::Clip(_, s) => Some(*s),
Self::Scene(s) => Some(*s),
_ => None
}
}
pub fn scene_next (&mut self, last_scene: usize) {
*self = match self {
Self::Mix => Self::Scene(0),
Self::Track(t) => Self::Scene(*t),
Self::Scene(s) => Self::Scene(last_scene.min(*s + 1)),
Self::Clip(t, s) => Self::Clip(*t, last_scene.min(*s + 1)),
}
}
pub fn scene_prev (&mut self) {
*self = match self {
Self::Mix => Self::Mix,
Self::Track(t) => Self::Track(*t),
Self::Scene(0) => Self::Mix,
Self::Scene(s) => Self::Scene(*s - 1),
Self::Clip(t, s) => Self::Clip(*t, s.saturating_sub(1)),
}
}
}