mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 20:26:42 +01:00
216 lines
7.2 KiB
Rust
216 lines
7.2 KiB
Rust
use crate::*;
|
|
|
|
pub trait TransportControl: ClockApi {}
|
|
|
|
pub trait SequencerControl: TransportControl {}
|
|
|
|
pub trait ArrangerControl: TransportControl {
|
|
fn selected (&self) -> ArrangerSelection;
|
|
fn selected_mut (&mut self) -> &mut ArrangerSelection;
|
|
fn activate (&mut self);
|
|
fn selected_phrase (&self) -> Option<Arc<RwLock<Phrase>>>;
|
|
fn toggle_loop (&mut self);
|
|
fn randomize_color (&mut self);
|
|
}
|
|
|
|
pub trait PhrasesControl: HasPhrases {
|
|
fn phrase_index (&self) -> usize;
|
|
fn set_phrase_index (&self, index: usize);
|
|
fn phrases_mode (&self) -> &Option<PhrasesMode>;
|
|
fn phrases_mode_mut (&mut self) -> &mut Option<PhrasesMode>;
|
|
fn phrase_rename_begin (&mut self) {
|
|
let name = self.phrases()[self.phrase_index()].read().unwrap().name.clone();
|
|
*self.phrases_mode_mut() = Some(
|
|
PhrasesMode::Rename(self.phrase_index(), name)
|
|
)
|
|
}
|
|
fn phrase_length_begin (&mut self) {
|
|
let length = self.phrases()[self.phrase_index()].read().unwrap().length;
|
|
*self.phrases_mode_mut() = Some(
|
|
PhrasesMode::Length(self.phrase_index(), length, PhraseLengthFocus::Bar)
|
|
)
|
|
}
|
|
fn new_phrase (name: Option<&str>, color: Option<ItemColorTriplet>) -> Arc<RwLock<Phrase>> {
|
|
Arc::new(RwLock::new(Phrase::new(
|
|
String::from(name.unwrap_or("(new)")), true, 4 * PPQ, None, color
|
|
)))
|
|
}
|
|
fn index_of (&self, phrase: &Phrase) -> Option<usize> {
|
|
for i in 0..self.phrases().len() {
|
|
if *self.phrases()[i].read().unwrap() == *phrase { return Some(i) }
|
|
}
|
|
return None
|
|
}
|
|
fn insert_dup (&mut self) {
|
|
let mut phrase = self.phrases()[self.phrase_index()].read().unwrap().duplicate();
|
|
phrase.color = ItemColorTriplet::random_near(phrase.color, 0.25);
|
|
let index = self.phrase_index() + 1;
|
|
self.phrases_mut().insert(index, Arc::new(RwLock::new(phrase)));
|
|
self.set_phrase_index(index);
|
|
}
|
|
}
|
|
|
|
pub trait PhraseEditorControl {
|
|
fn edit_phrase (&self, phrase: &Option<Arc<RwLock<Phrase>>>);
|
|
fn editing_phrase (&self) -> &Option<Arc<RwLock<Phrase>>>;
|
|
fn phrase_editor_entered (&self) -> bool;
|
|
fn time_axis (&self) -> &RwLock<ScaledAxis<usize>>;
|
|
fn note_axis (&self) -> &RwLock<FixedAxis<usize>>;
|
|
fn note_len (&self) -> usize;
|
|
fn note_len_mut (&mut self) -> &mut usize;
|
|
fn put_note (&mut self);
|
|
fn time_cursor_advance (&self) {
|
|
let point = self.time_axis().read().unwrap().point;
|
|
let length = self.editing_phrase().as_ref().map(|p|p.read().unwrap().length).unwrap_or(1);
|
|
let forward = |time|(time + self.note_len()) % length;
|
|
self.time_axis().write().unwrap().point = point.map(forward);
|
|
}
|
|
}
|
|
|
|
impl TransportControl for TransportTui {}
|
|
|
|
impl TransportControl for SequencerTui {}
|
|
|
|
impl TransportControl for ArrangerTui {}
|
|
|
|
impl SequencerControl for SequencerTui {}
|
|
|
|
impl ArrangerControl for ArrangerTui {
|
|
fn selected (&self) -> ArrangerSelection {
|
|
self.selected
|
|
}
|
|
fn selected_mut (&mut self) -> &mut ArrangerSelection {
|
|
&mut self.selected
|
|
}
|
|
fn activate (&mut self) {
|
|
if let ArrangerSelection::Scene(s) = self.selected {
|
|
for (t, track) in self.tracks_mut().iter_mut().enumerate() {
|
|
let clip = self.scenes()[s].clips[t].as_ref();
|
|
if track.player.play_phrase.is_some() || clip.is_some() {
|
|
track.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()
|
|
//}
|
|
} else if let ArrangerSelection::Clip(t, s) = self.selected {
|
|
self.tracks_mut()[t].enqueue_next(self.scenes()[s].clips[t].as_ref());
|
|
};
|
|
}
|
|
fn selected_phrase (&self) -> Option<Arc<RwLock<Phrase>>> {
|
|
self.selected_scene()?.clips.get(self.selected.track()?)?.clone()
|
|
}
|
|
fn toggle_loop (&mut self) {
|
|
if let Some(phrase) = self.selected_phrase() {
|
|
phrase.write().unwrap().toggle_loop()
|
|
}
|
|
}
|
|
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();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl PhrasesControl for SequencerTui {
|
|
fn phrase_index (&self) -> usize {
|
|
self.phrases.phrase.load(Ordering::Relaxed)
|
|
}
|
|
fn set_phrase_index (&self, value: usize) {
|
|
self.phrases.phrase.store(value, Ordering::Relaxed);
|
|
}
|
|
fn phrases_mode (&self) -> &Option<PhrasesMode> {
|
|
&self.phrases.mode
|
|
}
|
|
fn phrases_mode_mut (&mut self) -> &mut Option<PhrasesMode> {
|
|
&mut self.phrases.mode
|
|
}
|
|
}
|
|
|
|
impl PhrasesControl for ArrangerTui {
|
|
fn phrase_index (&self) -> usize {
|
|
self.phrases.phrase.load(Ordering::Relaxed)
|
|
}
|
|
fn set_phrase_index (&self, value: usize) {
|
|
self.phrases.phrase.store(value, Ordering::Relaxed);
|
|
}
|
|
fn phrases_mode (&self) -> &Option<PhrasesMode> {
|
|
&self.phrases.mode
|
|
}
|
|
fn phrases_mode_mut (&mut self) -> &mut Option<PhrasesMode> {
|
|
&mut self.phrases.mode
|
|
}
|
|
}
|
|
|
|
impl PhraseEditorControl for SequencerTui {
|
|
fn edit_phrase (&self, phrase: &Option<Arc<RwLock<Phrase>>>) {
|
|
//self.editor.show(self.selected_phrase().as_ref());
|
|
//state.editor.phrase = phrase.clone();
|
|
//state.focus(ArrangerFocus::PhraseEditor);
|
|
//state.focus_enter();
|
|
todo!()
|
|
}
|
|
fn editing_phrase (&self) -> &Option<Arc<RwLock<Phrase>>> {
|
|
todo!()
|
|
}
|
|
fn phrase_editor_entered (&self) -> bool {
|
|
self.entered && self.focused() == SequencerFocus::PhraseEditor
|
|
}
|
|
fn time_axis (&self) -> &RwLock<ScaledAxis<usize>> {
|
|
todo!()
|
|
}
|
|
fn note_axis (&self) -> &RwLock<FixedAxis<usize>> {
|
|
todo!()
|
|
}
|
|
fn note_len (&self) -> usize {
|
|
todo!()
|
|
}
|
|
fn note_len_mut (&mut self) -> &mut usize {
|
|
todo!()
|
|
}
|
|
fn put_note (&mut self) {
|
|
todo!()
|
|
}
|
|
}
|
|
|
|
impl PhraseEditorControl for ArrangerTui {
|
|
fn edit_phrase (&self, phrase: &Option<Arc<RwLock<Phrase>>>) {
|
|
todo!()
|
|
}
|
|
fn editing_phrase (&self) -> &Option<Arc<RwLock<Phrase>>> {
|
|
todo!()
|
|
}
|
|
fn phrase_editor_entered (&self) -> bool {
|
|
self.entered && self.focused() == ArrangerFocus::PhraseEditor
|
|
}
|
|
fn time_axis (&self) -> &RwLock<ScaledAxis<usize>> {
|
|
todo!()
|
|
}
|
|
fn note_axis (&self) -> &RwLock<FixedAxis<usize>> {
|
|
todo!()
|
|
}
|
|
fn note_len (&self) -> usize {
|
|
todo!()
|
|
}
|
|
fn note_len_mut (&mut self) -> &mut usize {
|
|
todo!()
|
|
}
|
|
fn put_note (&mut self) {
|
|
todo!()
|
|
}
|
|
}
|