mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 04:06:45 +01:00
278 lines
11 KiB
Rust
278 lines
11 KiB
Rust
use crate::*;
|
|
|
|
impl HasPhrases for ArrangerTui {
|
|
fn phrases (&self) -> &Vec<Arc<RwLock<Phrase>>> {
|
|
&self.phrases
|
|
}
|
|
fn phrases_mut (&mut self) -> &mut Vec<Arc<RwLock<Phrase>>> {
|
|
&mut self.phrases
|
|
}
|
|
}
|
|
|
|
/// General methods for arranger
|
|
impl ArrangerTui {
|
|
pub fn selected_scene (&self) -> Option<&ArrangerScene> {
|
|
self.selected.scene().map(|s|self.scenes().get(s)).flatten()
|
|
}
|
|
pub fn selected_scene_mut (&mut self) -> Option<&mut ArrangerScene> {
|
|
self.selected.scene().map(|s|self.scenes_mut().get_mut(s)).flatten()
|
|
}
|
|
pub fn selected_phrase (&self) -> Option<Arc<RwLock<Phrase>>> {
|
|
self.selected_scene()?.clips.get(self.selected.track()?)?.clone()
|
|
}
|
|
|
|
/// Focus the editor with the current phrase
|
|
pub fn show_phrase (&mut self) {
|
|
self.editor.show(self.selected_phrase().as_ref());
|
|
}
|
|
|
|
pub fn activate (&mut self) {
|
|
let scenes = self.scenes();
|
|
let tracks = self.tracks_mut();
|
|
match self.selected {
|
|
ArrangerSelection::Scene(s) => {
|
|
for (t, track) in tracks.iter_mut().enumerate() {
|
|
let player = &mut track.player;
|
|
let clip = scenes[s].clips[t].as_ref();
|
|
if player.phrase.is_some() || clip.is_some() {
|
|
player.enqueue_next(clip);
|
|
}
|
|
}
|
|
// TODO make transport available here, so that
|
|
// activating a scene when stopped starts playback
|
|
//if self.is_stopped() {
|
|
//self.transport.toggle_play()
|
|
//}
|
|
},
|
|
ArrangerSelection::Clip(t, s) => {
|
|
tracks[t].player.enqueue_next(scenes[s].clips[t]);
|
|
},
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
pub fn is_first_row (&self) -> bool {
|
|
let selected = self.selected;
|
|
selected.is_mix() || selected.is_track()
|
|
}
|
|
|
|
pub fn is_last_row (&self) -> bool {
|
|
let selected = self.selected;
|
|
(self.scenes().len() == 0 && (selected.is_mix() || selected.is_track())) || match selected {
|
|
ArrangerSelection::Scene(s) => s == self.scenes().len() - 1,
|
|
ArrangerSelection::Clip(_, s) => s == self.scenes().len() - 1,
|
|
_ => false
|
|
}
|
|
}
|
|
|
|
pub fn toggle_loop (&mut self) {
|
|
if let Some(phrase) = self.selected_phrase() {
|
|
phrase.write().unwrap().toggle_loop()
|
|
}
|
|
}
|
|
|
|
pub fn randomize_color (&mut self) {
|
|
match self.selected {
|
|
ArrangerSelection::Mix => {
|
|
self.color = ItemColor::random_dark()
|
|
},
|
|
ArrangerSelection::Track(t) => {
|
|
self.tracks_mut()[t].color = ItemColor::random()
|
|
},
|
|
ArrangerSelection::Scene(s) => {
|
|
self.scenes_mut()[s].color = ItemColor::random()
|
|
},
|
|
ArrangerSelection::Clip(t, s) => {
|
|
if let Some(phrase) = &self.scenes_mut()[s].clips[t] {
|
|
phrase.write().unwrap().color = ItemColorTriplet::random();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//pub fn track_next (&mut self, last_track: usize) {
|
|
//use ArrangerSelection::*;
|
|
//*self = match self {
|
|
//Mix => Track(0),
|
|
//Track(t) => Track(last_track.min(*t + 1)),
|
|
//Scene(s) => Clip(0, *s),
|
|
//Clip(t, s) => Clip(last_track.min(*t + 1), *s),
|
|
//}
|
|
//}
|
|
//pub fn track_prev (&mut self) {
|
|
//use ArrangerSelection::*;
|
|
//*self = match self {
|
|
//Mix => Mix,
|
|
//Scene(s) => Scene(*s),
|
|
//Track(t) => if *t == 0 { Mix } else { Track(*t - 1) },
|
|
//Clip(t, s) => if *t == 0 { Scene(*s) } else { Clip(t.saturating_sub(1), *s) }
|
|
//}
|
|
//}
|
|
//pub fn scene_next (&mut self, last_scene: usize) {
|
|
//use ArrangerSelection::*;
|
|
//*self = match self {
|
|
//Mix => Scene(0),
|
|
//Track(t) => Clip(*t, 0),
|
|
//Scene(s) => Scene(last_scene.min(*s + 1)),
|
|
//Clip(t, s) => Clip(*t, last_scene.min(*s + 1)),
|
|
//}
|
|
//}
|
|
//pub fn scene_prev (&mut self) {
|
|
//use ArrangerSelection::*;
|
|
//*self = match self {
|
|
//Mix => Mix,
|
|
//Track(t) => Track(*t),
|
|
//Scene(s) => if *s == 0 { Mix } else { Scene(*s - 1) },
|
|
//Clip(t, s) => if *s == 0 { Track(*t) } else { Clip(*t, s.saturating_sub(1)) }
|
|
//}
|
|
//}
|
|
|
|
//pub fn arranger_menu_bar () -> MenuBar {
|
|
//use ArrangerCommand as Cmd;
|
|
//use ArrangerCommand as Edit;
|
|
//use ArrangerSelection as Focus;
|
|
//use ArrangerTrackCommand as Track;
|
|
//use ArrangerClipCommand as Clip;
|
|
//use ArrangerSceneCommand as Scene;
|
|
//use TransportCommand as Transport;
|
|
//MenuBar::new()
|
|
//.add({
|
|
//use ArrangerCommand::*;
|
|
//Menu::new("File")
|
|
//.cmd("n", "New project", ArrangerViewCommand::Arranger(New))
|
|
//.cmd("l", "Load project", ArrangerViewCommand::Arranger(Load))
|
|
//.cmd("s", "Save project", ArrangerViewCommand::Arranger(Save))
|
|
//})
|
|
//.add({
|
|
//Menu::new("Transport")
|
|
//.cmd("p", "Play", TransportCommand::Transport(Play(None)))
|
|
//.cmd("P", "Play from start", TransportCommand::Transport(Play(Some(0))))
|
|
//.cmd("s", "Pause", TransportCommand::Transport(Stop(None)))
|
|
//.cmd("S", "Stop and rewind", TransportCommand::Transport(Stop(Some(0))))
|
|
//})
|
|
//.add({
|
|
//use ArrangerCommand::*;
|
|
//Menu::new("Track")
|
|
//.cmd("a", "Append new", ArrangerViewCommand::Arranger(AddTrack))
|
|
//.cmd("i", "Insert new", ArrangerViewCommand::Arranger(AddTrack))
|
|
//.cmd("n", "Rename", ArrangerViewCommand::Arranger(AddTrack))
|
|
//.cmd("d", "Delete", ArrangerViewCommand::Arranger(AddTrack))
|
|
//.cmd(">", "Move up", ArrangerViewCommand::Arranger(AddTrack))
|
|
//.cmd("<", "Move down", ArrangerViewCommand::Arranger(AddTrack))
|
|
//})
|
|
//.add({
|
|
//use ArrangerCommand::*;
|
|
//Menu::new("Scene")
|
|
//.cmd("a", "Append new", ArrangerViewCommand::Arranger(AddScene))
|
|
//.cmd("i", "Insert new", ArrangerViewCommand::Arranger(AddTrack))
|
|
//.cmd("n", "Rename", ArrangerViewCommand::Arranger(AddTrack))
|
|
//.cmd("d", "Delete", ArrangerViewCommand::Arranger(AddTrack))
|
|
//.cmd(">", "Move up", ArrangerViewCommand::Arranger(AddTrack))
|
|
//.cmd("<", "Move down", ArrangerViewCommand::Arranger(AddTrack))
|
|
//})
|
|
//.add({
|
|
//use PhraseRenameCommand as Rename;
|
|
//use PhraseLengthCommand as Length;
|
|
//Menu::new("Phrase")
|
|
//.cmd("a", "Append new", PhrasePoolCommand::Phrases(Append))
|
|
//.cmd("i", "Insert new", PhrasePoolCommand::Phrases(Insert))
|
|
//.cmd("n", "Rename", PhrasePoolCommand::Phrases(Rename(Rename::Begin)))
|
|
//.cmd("t", "Set length", PhrasePoolCommand::Phrases(Length(Length::Begin)))
|
|
//.cmd("d", "Delete", PhrasePoolCommand::Phrases(Delete))
|
|
//.cmd("l", "Load from MIDI...", PhrasePoolCommand::Phrases(Import))
|
|
//.cmd("s", "Save to MIDI...", PhrasePoolCommand::Phrases(Export))
|
|
//.cmd(">", "Move up", PhrasePoolCommand::Phrases(MoveUp))
|
|
//.cmd("<", "Move down", PhrasePoolCommand::Phrases(MoveDown))
|
|
//})
|
|
//}
|
|
|
|
//pub fn phrase_next (&mut self) {
|
|
//if let ArrangerSelection::Clip(track, scene) = self.selected {
|
|
//if let Some(ref mut phrase) = self.model.scenes[scene].clips[track] {
|
|
//let phrases = self.model.phrases.read().unwrap();
|
|
//let index = phrases.index_of(&*phrase.read().unwrap());
|
|
//if let Some(index) = index {
|
|
//if index < phrases.len().saturating_sub(1) {
|
|
//*phrase = phrases[index + 1].clone();
|
|
//}
|
|
//}
|
|
//}
|
|
//}
|
|
//}
|
|
//pub fn phrase_prev (&mut self) {
|
|
//if let ArrangerSelection::Clip(track, scene) = self.selected {
|
|
//if let Some(ref mut phrase) = self.model.scenes[scene].clips[track] {
|
|
//let phrases = self.model.phrases.read().unwrap();
|
|
//let index = phrases.index_of(&*phrase.read().unwrap());
|
|
//if let Some(index) = index {
|
|
//if index > 0 {
|
|
//*phrase = phrases[index - 1].clone();
|
|
//}
|
|
//}
|
|
//}
|
|
//}
|
|
//}
|
|
|
|
//pub fn phrase_get (&mut self) {
|
|
//if let ArrangerSelection::Clip(track, scene) = self.selected {
|
|
//if let Some(phrase) = &self.model.scenes[scene].clips[track] {
|
|
//let mut phrases = self.model.phrases.write().unwrap();
|
|
//if let Some(index) = &*phrases.index_of(&*phrase.read().unwrap()) {
|
|
//self.model.phrase = index;
|
|
//}
|
|
//}
|
|
//}
|
|
//}
|
|
|
|
///// Focus the editor with the current phrase
|
|
//pub fn edit_phrase (&mut self) {
|
|
//if self.arrangement.selected.is_clip() && self.arrangement.phrase().is_none() {
|
|
//self.phrases.append_new(None, Some(self.next_color().into()));
|
|
//self.arrangement.phrase_put();
|
|
//}
|
|
//self.show_phrase();
|
|
//self.focus(ArrangerFocus::PhraseEditor);
|
|
//self.editor.entered = true;
|
|
//}
|
|
|
|
//pub fn next_color (&self) -> ItemColor {
|
|
//if let ArrangerSelection::Clip(track, scene) = self.arrangement.selected {
|
|
//let track_color = self.arrangement.model.tracks[track].color;
|
|
//let scene_color = self.arrangement.model.scenes[scene].color;
|
|
//track_color.mix(scene_color, 0.5).mix(ItemColor::random(), 0.25)
|
|
//} else {
|
|
//panic!("could not compute next color")
|
|
//}
|
|
//}
|
|
//pub fn phrase_del (&mut self) {
|
|
//let track_index = self.selected.track();
|
|
//let scene_index = self.selected.scene();
|
|
//track_index
|
|
//.and_then(|index|self.model.tracks.get_mut(index).map(|track|(index, track)))
|
|
//.map(|(track_index, _)|scene_index
|
|
//.and_then(|index|self.model.scenes.get_mut(index))
|
|
//.map(|scene|scene.clips[track_index] = None));
|
|
//}
|
|
//pub fn phrase_put (&mut self) {
|
|
//if let ArrangerSelection::Clip(track, scene) = self.selected {
|
|
//self.model.scenes[scene].clips[track] = self.selected_phrase().clone();
|
|
//}
|
|
//}
|
|
//pub fn selected_scene (&self) -> Option<&ArrangerScene> {
|
|
//self.selected.scene().map(|s|self.model.scenes.get(s)).flatten()
|
|
//}
|
|
//pub fn selected_scene_mut (&mut self) -> Option<&mut ArrangerScene> {
|
|
//self.selected.scene().map(|s|self.model.scenes.get_mut(s)).flatten()
|
|
//}
|
|
//pub fn selected_phrase (&self) -> Option<Arc<RwLock<Phrase>>> {
|
|
//self.selected_scene()?.clips.get(self.selected.track()?)?.clone()
|
|
//}
|