mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
comment out app-specific structs/impls. only monoapp remains
This commit is contained in:
parent
e73c31d494
commit
479988272e
6 changed files with 1080 additions and 1075 deletions
|
|
@ -1,7 +1,7 @@
|
|||
use crate::*;
|
||||
use ClockCommand::{Play, Pause};
|
||||
use self::ArrangerCommand as Cmd;
|
||||
|
||||
pub const TRACK_MIN_WIDTH: usize = 9;
|
||||
impl Arrangement for App {
|
||||
fn tracks (&self) -> &Vec<ArrangerTrack> { &self.tracks }
|
||||
fn tracks_mut (&mut self) -> &mut Vec<ArrangerTrack> { &mut self.tracks }
|
||||
|
|
@ -10,14 +10,14 @@ impl Arrangement for App {
|
|||
fn selected (&self) -> &ArrangerSelection { &self.selected }
|
||||
fn selected_mut (&mut self) -> &mut ArrangerSelection { &mut self.selected }
|
||||
}
|
||||
impl Arrangement for Arranger {
|
||||
fn tracks (&self) -> &Vec<ArrangerTrack> { &self.tracks }
|
||||
fn tracks_mut (&mut self) -> &mut Vec<ArrangerTrack> { &mut self.tracks }
|
||||
fn scenes (&self) -> &Vec<ArrangerScene> { &self.scenes }
|
||||
fn scenes_mut (&mut self) -> &mut Vec<ArrangerScene> { &mut self.scenes }
|
||||
fn selected (&self) -> &ArrangerSelection { &self.selected }
|
||||
fn selected_mut (&mut self) -> &mut ArrangerSelection { &mut self.selected }
|
||||
}
|
||||
//impl Arrangement for Arranger {
|
||||
//fn tracks (&self) -> &Vec<ArrangerTrack> { &self.tracks }
|
||||
//fn tracks_mut (&mut self) -> &mut Vec<ArrangerTrack> { &mut self.tracks }
|
||||
//fn scenes (&self) -> &Vec<ArrangerScene> { &self.scenes }
|
||||
//fn scenes_mut (&mut self) -> &mut Vec<ArrangerScene> { &mut self.scenes }
|
||||
//fn selected (&self) -> &ArrangerSelection { &self.selected }
|
||||
//fn selected_mut (&mut self) -> &mut ArrangerSelection { &mut self.selected }
|
||||
//}
|
||||
pub trait Arrangement: HasClock + HasJack {
|
||||
fn tracks (&self) -> &Vec<ArrangerTrack>;
|
||||
fn tracks_mut (&mut self) -> &mut Vec<ArrangerTrack>;
|
||||
|
|
@ -117,6 +117,49 @@ pub trait Arrangement: HasClock + HasJack {
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
fn activate (&mut self) -> Usually<()> {
|
||||
let selected = self.selected().clone();
|
||||
match selected {
|
||||
ArrangerSelection::Scene(s) => {
|
||||
let mut clips = vec![];
|
||||
for (t, _) in self.tracks().iter().enumerate() {
|
||||
clips.push(self.scenes()[s].clips[t].clone());
|
||||
}
|
||||
for (t, track) in self.tracks_mut().iter_mut().enumerate() {
|
||||
if track.player.play_clip.is_some() || clips[t].is_some() {
|
||||
track.player.enqueue_next(clips[t].as_ref());
|
||||
}
|
||||
}
|
||||
if self.clock().is_stopped() {
|
||||
self.clock().play_from(Some(0))?;
|
||||
}
|
||||
},
|
||||
ArrangerSelection::Clip(t, s) => {
|
||||
let clip = self.scenes()[s].clips[t].clone();
|
||||
self.tracks_mut()[t].player.enqueue_next(clip.as_ref());
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn clip (&self) -> Option<Arc<RwLock<MidiClip>>> {
|
||||
self.scene()?.clips.get(self.selected().track()?)?.clone()
|
||||
}
|
||||
fn toggle_loop (&mut self) {
|
||||
if let Some(clip) = self.clip() {
|
||||
clip.write().unwrap().toggle_loop()
|
||||
}
|
||||
}
|
||||
//fn randomize_color (&mut self) {
|
||||
//match self.selected {
|
||||
//ArrangerSelection::Mix => { self.color = ItemPalette::random() },
|
||||
//ArrangerSelection::Track(t) => { self.tracks[t].color = ItemPalette::random() },
|
||||
//ArrangerSelection::Scene(s) => { self.scenes[s].color = ItemPalette::random() },
|
||||
//ArrangerSelection::Clip(t, s) => if let Some(clip) = &self.scenes[s].clips[t] {
|
||||
//clip.write().unwrap().color = ItemPalette::random();
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -180,7 +223,7 @@ impl ArrangerTrack {
|
|||
self.width += 1;
|
||||
}
|
||||
fn width_dec (&mut self) {
|
||||
if self.width > Arranger::TRACK_MIN_WIDTH {
|
||||
if self.width > TRACK_MIN_WIDTH {
|
||||
self.width -= 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -240,40 +283,3 @@ impl ArrangerSelection {
|
|||
}).into()
|
||||
}
|
||||
}
|
||||
impl Arranger {
|
||||
pub fn activate (&mut self) -> Usually<()> {
|
||||
if let ArrangerSelection::Scene(s) = self.selected {
|
||||
for (t, track) in self.tracks.iter_mut().enumerate() {
|
||||
let clip = self.scenes[s].clips[t].clone();
|
||||
if track.player.play_clip.is_some() || clip.is_some() {
|
||||
track.player.enqueue_next(clip.as_ref());
|
||||
}
|
||||
}
|
||||
if self.clock().is_stopped() {
|
||||
self.clock().play_from(Some(0))?;
|
||||
}
|
||||
} else if let ArrangerSelection::Clip(t, s) = self.selected {
|
||||
let clip = self.scenes[s].clips[t].clone();
|
||||
self.tracks[t].player.enqueue_next(clip.as_ref());
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
pub fn clip (&self) -> Option<Arc<RwLock<MidiClip>>> {
|
||||
self.scene()?.clips.get(self.selected.track()?)?.clone()
|
||||
}
|
||||
pub fn toggle_loop (&mut self) {
|
||||
if let Some(clip) = self.clip() {
|
||||
clip.write().unwrap().toggle_loop()
|
||||
}
|
||||
}
|
||||
pub fn randomize_color (&mut self) {
|
||||
match self.selected {
|
||||
ArrangerSelection::Mix => { self.color = ItemPalette::random() },
|
||||
ArrangerSelection::Track(t) => { self.tracks[t].color = ItemPalette::random() },
|
||||
ArrangerSelection::Scene(s) => { self.scenes[s].color = ItemPalette::random() },
|
||||
ArrangerSelection::Clip(t, s) => if let Some(clip) = &self.scenes[s].clips[t] {
|
||||
clip.write().unwrap().color = ItemPalette::random();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
196
tek/src/audio.rs
196
tek/src/audio.rs
|
|
@ -2,9 +2,9 @@ use crate::*;
|
|||
impl HasJack for App {
|
||||
fn jack (&self) -> &Arc<RwLock<JackConnection>> { &self.jack }
|
||||
}
|
||||
impl HasJack for Arranger {
|
||||
fn jack (&self) -> &Arc<RwLock<JackConnection>> { &self.jack }
|
||||
}
|
||||
//impl HasJack for Arranger {
|
||||
//fn jack (&self) -> &Arc<RwLock<JackConnection>> { &self.jack }
|
||||
//}
|
||||
audio!(|self: App, client, scope|{
|
||||
// Start profiling cycle
|
||||
let t0 = self.perf.get_t0();
|
||||
|
|
@ -101,111 +101,111 @@ audio!(|self: App, client, scope|{
|
|||
Control::Continue
|
||||
});
|
||||
|
||||
audio!(|self: Sequencer, client, scope|{
|
||||
// Start profiling cycle
|
||||
let t0 = self.perf.get_t0();
|
||||
//audio!(|self: Sequencer, client, scope|{
|
||||
//// Start profiling cycle
|
||||
//let t0 = self.perf.get_t0();
|
||||
|
||||
// Update transport clock
|
||||
if Control::Quit == ClockAudio(self).process(client, scope) {
|
||||
return Control::Quit
|
||||
}
|
||||
// Update MIDI sequencer
|
||||
if Control::Quit == PlayerAudio(
|
||||
&mut self.player, &mut self.note_buf, &mut self.midi_buf
|
||||
).process(client, scope) {
|
||||
return Control::Quit
|
||||
}
|
||||
|
||||
// End profiling cycle
|
||||
self.perf.update(t0, scope);
|
||||
|
||||
Control::Continue
|
||||
});
|
||||
|
||||
audio!(|self: Groovebox, client, scope|{
|
||||
// Start profiling cycle
|
||||
let t0 = self.perf.get_t0();
|
||||
|
||||
// Update transport clock
|
||||
if Control::Quit == ClockAudio(&mut self.player).process(client, scope) {
|
||||
return Control::Quit
|
||||
}
|
||||
|
||||
// Update MIDI sequencer
|
||||
if Control::Quit == PlayerAudio(
|
||||
&mut self.player, &mut self.note_buf, &mut self.midi_buf
|
||||
).process(client, scope) {
|
||||
return Control::Quit
|
||||
}
|
||||
|
||||
// Update sampler
|
||||
if Control::Quit == SamplerAudio(&mut self.sampler).process(client, scope) {
|
||||
return Control::Quit
|
||||
}
|
||||
|
||||
// TODO move these to editor and sampler:
|
||||
for RawMidi { time, bytes } in self.player.midi_ins[0].port.iter(scope) {
|
||||
if let LiveEvent::Midi { message, .. } = LiveEvent::parse(bytes).unwrap() {
|
||||
match message {
|
||||
MidiMessage::NoteOn { ref key, .. } => {
|
||||
self.editor.set_note_point(key.as_int() as usize);
|
||||
},
|
||||
MidiMessage::Controller { controller, value } => {
|
||||
if let Some(sample) = &self.sampler.mapped[self.editor.note_point()] {
|
||||
sample.write().unwrap().handle_cc(controller, value)
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// End profiling cycle
|
||||
self.perf.update(t0, scope);
|
||||
|
||||
Control::Continue
|
||||
});
|
||||
|
||||
audio!(|self: Arranger, client, scope|{
|
||||
// Start profiling cycle
|
||||
let t0 = self.perf.get_t0();
|
||||
|
||||
// Update transport clock
|
||||
if Control::Quit == ClockAudio(self).process(client, scope) {
|
||||
return Control::Quit
|
||||
}
|
||||
|
||||
//// Update MIDI sequencers
|
||||
//let tracks = &mut self.tracks;
|
||||
//let note_buf = &mut self.note_buf;
|
||||
//let midi_buf = &mut self.midi_buf;
|
||||
//if Control::Quit == TracksAudio(tracks, note_buf, midi_buf).process(client, scope) {
|
||||
//// Update transport clock
|
||||
//if Control::Quit == ClockAudio(self).process(client, scope) {
|
||||
//return Control::Quit
|
||||
//}
|
||||
//// Update MIDI sequencer
|
||||
//if Control::Quit == PlayerAudio(
|
||||
//&mut self.player, &mut self.note_buf, &mut self.midi_buf
|
||||
//).process(client, scope) {
|
||||
//return Control::Quit
|
||||
//}
|
||||
|
||||
// FIXME: one of these per playing track
|
||||
//self.now.set(0.);
|
||||
//if let ArrangerSelection::Clip(t, s) = self.selected {
|
||||
//let clip = self.scenes.get(s).map(|scene|scene.clips.get(t));
|
||||
//if let Some(Some(Some(clip))) = clip {
|
||||
//if let Some(track) = self.tracks().get(t) {
|
||||
//if let Some((ref started_at, Some(ref playing))) = track.player.play_clip {
|
||||
//let clip = clip.read().unwrap();
|
||||
//if *playing.read().unwrap() == *clip {
|
||||
//let pulse = self.current().pulse.get();
|
||||
//let start = started_at.pulse.get();
|
||||
//let now = (pulse - start) % clip.length as f64;
|
||||
//self.now.set(now);
|
||||
//// End profiling cycle
|
||||
//self.perf.update(t0, scope);
|
||||
|
||||
//Control::Continue
|
||||
//});
|
||||
|
||||
//audio!(|self: Groovebox, client, scope|{
|
||||
//// Start profiling cycle
|
||||
//let t0 = self.perf.get_t0();
|
||||
|
||||
//// Update transport clock
|
||||
//if Control::Quit == ClockAudio(&mut self.player).process(client, scope) {
|
||||
//return Control::Quit
|
||||
//}
|
||||
|
||||
//// Update MIDI sequencer
|
||||
//if Control::Quit == PlayerAudio(
|
||||
//&mut self.player, &mut self.note_buf, &mut self.midi_buf
|
||||
//).process(client, scope) {
|
||||
//return Control::Quit
|
||||
//}
|
||||
|
||||
//// Update sampler
|
||||
//if Control::Quit == SamplerAudio(&mut self.sampler).process(client, scope) {
|
||||
//return Control::Quit
|
||||
//}
|
||||
|
||||
//// TODO move these to editor and sampler:
|
||||
//for RawMidi { time, bytes } in self.player.midi_ins[0].port.iter(scope) {
|
||||
//if let LiveEvent::Midi { message, .. } = LiveEvent::parse(bytes).unwrap() {
|
||||
//match message {
|
||||
//MidiMessage::NoteOn { ref key, .. } => {
|
||||
//self.editor.set_note_point(key.as_int() as usize);
|
||||
//},
|
||||
//MidiMessage::Controller { controller, value } => {
|
||||
//if let Some(sample) = &self.sampler.mapped[self.editor.note_point()] {
|
||||
//sample.write().unwrap().handle_cc(controller, value)
|
||||
//}
|
||||
//}
|
||||
//_ => {}
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
|
||||
// End profiling cycle
|
||||
self.perf.update(t0, scope);
|
||||
return Control::Continue
|
||||
});
|
||||
//// End profiling cycle
|
||||
//self.perf.update(t0, scope);
|
||||
|
||||
//Control::Continue
|
||||
//});
|
||||
|
||||
//audio!(|self: Arranger, client, scope|{
|
||||
//// Start profiling cycle
|
||||
//let t0 = self.perf.get_t0();
|
||||
|
||||
//// Update transport clock
|
||||
//if Control::Quit == ClockAudio(self).process(client, scope) {
|
||||
//return Control::Quit
|
||||
//}
|
||||
|
||||
////// Update MIDI sequencers
|
||||
////let tracks = &mut self.tracks;
|
||||
////let note_buf = &mut self.note_buf;
|
||||
////let midi_buf = &mut self.midi_buf;
|
||||
////if Control::Quit == TracksAudio(tracks, note_buf, midi_buf).process(client, scope) {
|
||||
////return Control::Quit
|
||||
////}
|
||||
|
||||
//// FIXME: one of these per playing track
|
||||
////self.now.set(0.);
|
||||
////if let ArrangerSelection::Clip(t, s) = self.selected {
|
||||
////let clip = self.scenes.get(s).map(|scene|scene.clips.get(t));
|
||||
////if let Some(Some(Some(clip))) = clip {
|
||||
////if let Some(track) = self.tracks().get(t) {
|
||||
////if let Some((ref started_at, Some(ref playing))) = track.player.play_clip {
|
||||
////let clip = clip.read().unwrap();
|
||||
////if *playing.read().unwrap() == *clip {
|
||||
////let pulse = self.current().pulse.get();
|
||||
////let start = started_at.pulse.get();
|
||||
////let now = (pulse - start) % clip.length as f64;
|
||||
////self.now.set(now);
|
||||
////}
|
||||
////}
|
||||
////}
|
||||
////}
|
||||
////}
|
||||
|
||||
//// End profiling cycle
|
||||
//self.perf.update(t0, scope);
|
||||
//return Control::Continue
|
||||
//});
|
||||
|
||||
/// Hosts the JACK callback for a collection of tracks
|
||||
pub struct TracksAudio<'a>(
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ use MidiEditCommand as EditCmd;
|
|||
use MidiPoolCommand as PoolCmd;
|
||||
|
||||
handle!(TuiIn: |self: App, input| Ok(None));
|
||||
handle!(TuiIn: |self: Sequencer, input|SequencerCommand::execute_with_state(self, input.event()));
|
||||
handle!(TuiIn: |self: Groovebox, input|GrooveboxCommand::execute_with_state(self, input.event()));
|
||||
handle!(TuiIn: |self: Arranger, input|ArrangerCommand::execute_with_state(self, input.event()));
|
||||
//handle!(TuiIn: |self: Sequencer, input|SequencerCommand::execute_with_state(self, input.event()));
|
||||
//handle!(TuiIn: |self: Groovebox, input|GrooveboxCommand::execute_with_state(self, input.event()));
|
||||
//handle!(TuiIn: |self: Arranger, input|ArrangerCommand::execute_with_state(self, input.event()));
|
||||
|
||||
#[derive(Clone, Debug)] pub enum AppCommand {
|
||||
Clear,
|
||||
|
|
@ -239,348 +239,348 @@ command!(|self: AppCommand, state: App|match self {
|
|||
},
|
||||
});
|
||||
|
||||
command!(|self: SequencerCommand, state: Sequencer|match self {
|
||||
Self::Clock(cmd) => cmd.delegate(state, Self::Clock)?,
|
||||
Self::Editor(cmd) => cmd.delegate(&mut state.editor, Self::Editor)?,
|
||||
Self::Enqueue(clip) => { state.player.enqueue_next(clip.as_ref()); None },
|
||||
Self::History(delta) => { todo!("undo/redo") },
|
||||
//command!(|self: SequencerCommand, state: Sequencer|match self {
|
||||
//Self::Clock(cmd) => cmd.delegate(state, Self::Clock)?,
|
||||
//Self::Editor(cmd) => cmd.delegate(&mut state.editor, Self::Editor)?,
|
||||
//Self::Enqueue(clip) => { state.player.enqueue_next(clip.as_ref()); None },
|
||||
//Self::History(delta) => { todo!("undo/redo") },
|
||||
|
||||
Self::Pool(cmd) => match cmd {
|
||||
// autoselect: automatically load selected clip in editor
|
||||
PoolCommand::Select(_) => {
|
||||
let undo = cmd.delegate(&mut state.pool, Self::Pool)?;
|
||||
state.editor.set_clip(state.pool.clip().as_ref());
|
||||
undo
|
||||
},
|
||||
// update color in all places simultaneously
|
||||
PoolCommand::Clip(PoolCmd::SetColor(index, _)) => {
|
||||
let undo = cmd.delegate(&mut state.pool, Self::Pool)?;
|
||||
state.editor.set_clip(state.pool.clip().as_ref());
|
||||
undo
|
||||
},
|
||||
_ => cmd.delegate(&mut state.pool, Self::Pool)?
|
||||
},
|
||||
Self::Compact(compact) => if state.compact != compact {
|
||||
state.compact = compact;
|
||||
Some(Self::Compact(!compact))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
});
|
||||
command!(|self: GrooveboxCommand, state: Groovebox|match self {
|
||||
Self::Clock(cmd) => cmd.delegate(state, Self::Clock)?,
|
||||
Self::Editor(cmd) => cmd.delegate(&mut state.editor, Self::Editor)?,
|
||||
Self::Enqueue(clip) => { state.player.enqueue_next(clip.as_ref()); None },
|
||||
Self::History(delta) => { todo!("undo/redo") },
|
||||
Self::Sampler(cmd) => cmd.delegate(&mut state.sampler, Self::Sampler)?,
|
||||
|
||||
Self::Pool(cmd) => match cmd {
|
||||
// autoselect: automatically load selected clip in editor
|
||||
PoolCommand::Select(_) => {
|
||||
let undo = cmd.delegate(&mut state.pool, Self::Pool)?;
|
||||
state.editor.set_clip(state.pool.clip().as_ref());
|
||||
undo
|
||||
},
|
||||
// update color in all places simultaneously
|
||||
PoolCommand::Clip(PoolCmd::SetColor(index, _)) => {
|
||||
let undo = cmd.delegate(&mut state.pool, Self::Pool)?;
|
||||
state.editor.set_clip(state.pool.clip().as_ref());
|
||||
undo
|
||||
},
|
||||
_ => cmd.delegate(&mut state.pool, Self::Pool)?
|
||||
},
|
||||
Self::Compact(compact) => if state.compact != compact {
|
||||
state.compact = compact;
|
||||
Some(Self::Compact(!compact))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
});
|
||||
command!(|self: ArrangerCommand, state: Arranger|match self {
|
||||
Self::Clear => { todo!() },
|
||||
Self::Clip(cmd) => cmd.delegate(state, Self::Clip)?,
|
||||
Self::Clock(cmd) => cmd.delegate(state, Self::Clock)?,
|
||||
Self::Editor(cmd) => cmd.delegate(&mut state.editor, Self::Editor)?,
|
||||
Self::History(_) => { todo!() },
|
||||
Self::Scene(cmd) => cmd.delegate(state, Self::Scene)?,
|
||||
Self::Select(s) => { state.selected = s; None },
|
||||
Self::Track(cmd) => cmd.delegate(state, Self::Track)?,
|
||||
Self::Zoom(_) => { todo!(); },
|
||||
|
||||
Self::StopAll => {
|
||||
for track in 0..state.tracks.len() { state.tracks[track].player.enqueue_next(None); }
|
||||
None
|
||||
},
|
||||
Self::Color(palette) => {
|
||||
let old = state.color;
|
||||
state.color = palette;
|
||||
Some(Self::Color(old))
|
||||
},
|
||||
Self::Pool(cmd) => {
|
||||
match cmd {
|
||||
// autoselect: automatically load selected clip in editor
|
||||
PoolCommand::Select(_) => {
|
||||
let undo = cmd.delegate(&mut state.pool, Self::Pool)?;
|
||||
state.editor.set_clip(state.pool.clip().as_ref());
|
||||
undo
|
||||
},
|
||||
// reload clip in editor to update color
|
||||
PoolCommand::Clip(MidiPoolCommand::SetColor(index, _)) => {
|
||||
let undo = cmd.delegate(&mut state.pool, Self::Pool)?;
|
||||
state.editor.set_clip(state.pool.clip().as_ref());
|
||||
undo
|
||||
},
|
||||
_ => cmd.delegate(&mut state.pool, Self::Pool)?
|
||||
}
|
||||
},
|
||||
});
|
||||
command!(|self: SceneCommand, state: Arranger|match self {
|
||||
Self::Add => { state.scene_add(None, None)?; None }
|
||||
Self::Del(index) => { state.scene_del(index); None },
|
||||
Self::SetColor(index, color) => {
|
||||
let old = state.scenes[index].color;
|
||||
state.scenes[index].color = color;
|
||||
Some(Self::SetColor(index, old))
|
||||
},
|
||||
Self::Enqueue(scene) => {
|
||||
for track in 0..state.tracks.len() {
|
||||
state.tracks[track].player.enqueue_next(state.scenes[scene].clips[track].as_ref());
|
||||
}
|
||||
None
|
||||
},
|
||||
_ => None
|
||||
});
|
||||
command!(|self: TrackCommand, state: Arranger|match self {
|
||||
Self::Add => { state.track_add(None, None)?; None },
|
||||
Self::Del(index) => { state.track_del(index); None },
|
||||
Self::Stop(track) => { state.tracks[track].player.enqueue_next(None); None },
|
||||
Self::SetColor(index, color) => {
|
||||
let old = state.tracks[index].color;
|
||||
state.tracks[index].color = color;
|
||||
Some(Self::SetColor(index, old))
|
||||
},
|
||||
_ => None
|
||||
});
|
||||
command!(|self: ClipCommand, state: Arranger|match self {
|
||||
Self::Get(track, scene) => { todo!() },
|
||||
Self::Put(track, scene, clip) => {
|
||||
let old = state.scenes[scene].clips[track].clone();
|
||||
state.scenes[scene].clips[track] = clip;
|
||||
Some(Self::Put(track, scene, old))
|
||||
},
|
||||
Self::Enqueue(track, scene) => {
|
||||
state.tracks[track].player.enqueue_next(state.scenes[scene].clips[track].as_ref());
|
||||
None
|
||||
},
|
||||
_ => None
|
||||
});
|
||||
keymap!(KEYS_SEQUENCER = |state: Sequencer, input: Event| SequencerCommand {
|
||||
// TODO: k: toggle on-screen keyboard
|
||||
ctrl(key(Char('k'))) => { todo!("keyboard") },
|
||||
// Transport: Play/pause
|
||||
key(Char(' ')) => SeqCmd::Clock(if state.clock().is_stopped() { Play(None) } else { Pause(None) }),
|
||||
// Transport: Play from start or rewind to start
|
||||
shift(key(Char(' '))) => SeqCmd::Clock(if state.clock().is_stopped() { Play(Some(0)) } else { Pause(Some(0)) }),
|
||||
// u: undo
|
||||
key(Char('u')) => SeqCmd::History(-1),
|
||||
// Shift-U: redo
|
||||
key(Char('U')) => SeqCmd::History( 1),
|
||||
// Tab: Toggle compact mode
|
||||
key(Tab) => SeqCmd::Compact(!state.compact),
|
||||
// q: Enqueue currently edited clip
|
||||
key(Char('q')) => SeqCmd::Enqueue(state.pool.clip().clone()),
|
||||
// 0: Enqueue clip 0 (stop all)
|
||||
key(Char('0')) => SeqCmd::Enqueue(Some(state.clips()[0].clone())),
|
||||
// e: Toggle between editing currently playing or other clip
|
||||
//key(Char('e')) => if let Some((_, Some(playing))) = state.player.play_clip() {
|
||||
//let editing = state.editor.clip().as_ref().map(|p|p.read().unwrap().clone());
|
||||
//let selected = state.pool.clip().clone();
|
||||
//SeqCmd::Editor(Show(Some(if Some(selected.read().unwrap().clone()) != editing {
|
||||
//selected
|
||||
//} else {
|
||||
//playing.clone()
|
||||
//})))
|
||||
//} else {
|
||||
//return None
|
||||
//}
|
||||
}, if let Some(command) = MidiEditCommand::input_to_command(&state.editor, input) {
|
||||
SeqCmd::Editor(command)
|
||||
} else if let Some(command) = PoolCommand::input_to_command(&state.pool, input) {
|
||||
SeqCmd::Pool(command)
|
||||
} else {
|
||||
return None
|
||||
});
|
||||
keymap!(<'a> KEYS_GROOVEBOX = |state: Groovebox, input: Event| GrooveboxCommand {
|
||||
// Tab: Toggle compact mode
|
||||
key(Tab) => GrvCmd::Compact(!state.compact),
|
||||
// q: Enqueue currently edited clip
|
||||
key(Char('q')) => GrvCmd::Enqueue(state.pool.clip().clone()),
|
||||
// 0: Enqueue clip 0 (stop all)
|
||||
key(Char('0')) => GrvCmd::Enqueue(Some(state.pool.clips()[0].clone())),
|
||||
// TODO: k: toggle on-screen keyboard
|
||||
ctrl(key(Char('k'))) => todo!("keyboard"),
|
||||
// Transport: Play from start or rewind to start
|
||||
ctrl(key(Char(' '))) => GrvCmd::Clock(
|
||||
if state.clock().is_stopped() { Play(Some(0)) } else { Pause(Some(0)) }
|
||||
),
|
||||
// Shift-R: toggle recording
|
||||
shift(key(Char('R'))) => GrvCmd::Sampler(if state.sampler.recording.is_some() {
|
||||
SmplCmd::RecordFinish
|
||||
} else {
|
||||
SmplCmd::RecordBegin(u7::from(state.editor.note_point() as u8))
|
||||
}),
|
||||
// Shift-Del: delete sample
|
||||
shift(key(Delete)) => GrvCmd::Sampler(
|
||||
SmplCmd::SetSample(u7::from(state.editor.note_point() as u8), None)
|
||||
),
|
||||
// e: Toggle between editing currently playing or other clip
|
||||
//shift(key(Char('e'))) => if let Some((_, Some(playing))) = state.player.play_clip() {
|
||||
//let editing = state.editor.clip().as_ref().map(|p|p.read().unwrap().clone());
|
||||
//let selected = state.pool.clip().clone().map(|s|s.read().unwrap().clone());
|
||||
//GrvCmd::Editor(Show(if selected != editing {
|
||||
//selected
|
||||
//} else {
|
||||
//Some(playing.clone())
|
||||
//}))
|
||||
//} else {
|
||||
//return None
|
||||
//Self::Pool(cmd) => match cmd {
|
||||
//// autoselect: automatically load selected clip in editor
|
||||
//PoolCommand::Select(_) => {
|
||||
//let undo = cmd.delegate(&mut state.pool, Self::Pool)?;
|
||||
//state.editor.set_clip(state.pool.clip().as_ref());
|
||||
//undo
|
||||
//},
|
||||
//// update color in all places simultaneously
|
||||
//PoolCommand::Clip(PoolCmd::SetColor(index, _)) => {
|
||||
//let undo = cmd.delegate(&mut state.pool, Self::Pool)?;
|
||||
//state.editor.set_clip(state.pool.clip().as_ref());
|
||||
//undo
|
||||
//},
|
||||
//_ => cmd.delegate(&mut state.pool, Self::Pool)?
|
||||
//},
|
||||
}, if let Some(command) = MidiEditCommand::input_to_command(&state.editor, input) {
|
||||
GrvCmd::Editor(command)
|
||||
} else if let Some(command) = PoolCommand::input_to_command(&state.pool, input) {
|
||||
GrvCmd::Pool(command)
|
||||
} else {
|
||||
return None
|
||||
});
|
||||
keymap!(KEYS_ARRANGER = |state: Arranger, input: Event| ArrangerCommand {
|
||||
key(Char('u')) => ArrCmd::History(-1),
|
||||
key(Char('U')) => ArrCmd::History(1),
|
||||
// TODO: k: toggle on-screen keyboard
|
||||
ctrl(key(Char('k'))) => { todo!("keyboard") },
|
||||
// Transport: Play/pause
|
||||
key(Char(' ')) => ArrCmd::Clock(if state.clock().is_stopped() { Play(None) } else { Pause(None) }),
|
||||
// Transport: Play from start or rewind to start
|
||||
shift(key(Char(' '))) => ArrCmd::Clock(if state.clock().is_stopped() { Play(Some(0)) } else { Pause(Some(0)) }),
|
||||
key(Char('e')) => ArrCmd::Editor(MidiEditCommand::Show(state.pool.clip().clone())),
|
||||
ctrl(key(Char('a'))) => ArrCmd::Scene(SceneCommand::Add),
|
||||
ctrl(key(Char('A'))) => return None,//ArrCmd::Scene(SceneCommand::Add),
|
||||
ctrl(key(Char('t'))) => ArrCmd::Track(TrackCommand::Add),
|
||||
// Tab: Toggle visibility of clip pool column
|
||||
key(Tab) => ArrCmd::Pool(PoolCommand::Show(!state.pool.visible)),
|
||||
}, {
|
||||
use ArrangerSelection as Selected;
|
||||
use SceneCommand as Scene;
|
||||
use TrackCommand as Track;
|
||||
use ClipCommand as Clip;
|
||||
let t_len = state.tracks.len();
|
||||
let s_len = state.scenes.len();
|
||||
match state.selected {
|
||||
Selected::Clip(t, s) => clip_keymap(state, input, t, s),
|
||||
Selected::Scene(s) => scene_keymap(state, input, s),
|
||||
Selected::Track(t) => track_keymap(state, input, t),
|
||||
Selected::Mix => match input {
|
||||
//Self::Compact(compact) => if state.compact != compact {
|
||||
//state.compact = compact;
|
||||
//Some(Self::Compact(!compact))
|
||||
//} else {
|
||||
//None
|
||||
//},
|
||||
//});
|
||||
//command!(|self: GrooveboxCommand, state: Groovebox|match self {
|
||||
//Self::Clock(cmd) => cmd.delegate(state, Self::Clock)?,
|
||||
//Self::Editor(cmd) => cmd.delegate(&mut state.editor, Self::Editor)?,
|
||||
//Self::Enqueue(clip) => { state.player.enqueue_next(clip.as_ref()); None },
|
||||
//Self::History(delta) => { todo!("undo/redo") },
|
||||
//Self::Sampler(cmd) => cmd.delegate(&mut state.sampler, Self::Sampler)?,
|
||||
|
||||
kpat!(Delete) => Some(ArrCmd::Clear),
|
||||
kpat!(Char('0')) => Some(ArrCmd::StopAll),
|
||||
kpat!(Char('c')) => Some(ArrCmd::Color(ItemPalette::random())),
|
||||
//Self::Pool(cmd) => match cmd {
|
||||
//// autoselect: automatically load selected clip in editor
|
||||
//PoolCommand::Select(_) => {
|
||||
//let undo = cmd.delegate(&mut state.pool, Self::Pool)?;
|
||||
//state.editor.set_clip(state.pool.clip().as_ref());
|
||||
//undo
|
||||
//},
|
||||
//// update color in all places simultaneously
|
||||
//PoolCommand::Clip(PoolCmd::SetColor(index, _)) => {
|
||||
//let undo = cmd.delegate(&mut state.pool, Self::Pool)?;
|
||||
//state.editor.set_clip(state.pool.clip().as_ref());
|
||||
//undo
|
||||
//},
|
||||
//_ => cmd.delegate(&mut state.pool, Self::Pool)?
|
||||
//},
|
||||
//Self::Compact(compact) => if state.compact != compact {
|
||||
//state.compact = compact;
|
||||
//Some(Self::Compact(!compact))
|
||||
//} else {
|
||||
//None
|
||||
//},
|
||||
//});
|
||||
//command!(|self: ArrangerCommand, state: Arranger|match self {
|
||||
//Self::Clear => { todo!() },
|
||||
//Self::Clip(cmd) => cmd.delegate(state, Self::Clip)?,
|
||||
//Self::Clock(cmd) => cmd.delegate(state, Self::Clock)?,
|
||||
//Self::Editor(cmd) => cmd.delegate(&mut state.editor, Self::Editor)?,
|
||||
//Self::History(_) => { todo!() },
|
||||
//Self::Scene(cmd) => cmd.delegate(state, Self::Scene)?,
|
||||
//Self::Select(s) => { state.selected = s; None },
|
||||
//Self::Track(cmd) => cmd.delegate(state, Self::Track)?,
|
||||
//Self::Zoom(_) => { todo!(); },
|
||||
|
||||
kpat!(Up) => return None,
|
||||
kpat!(Down) => Some(ArrCmd::Select(Selected::Scene(0))),
|
||||
kpat!(Left) => return None,
|
||||
kpat!(Right) => Some(ArrCmd::Select(Selected::Track(0))),
|
||||
//Self::StopAll => {
|
||||
//for track in 0..state.tracks.len() { state.tracks[track].player.enqueue_next(None); }
|
||||
//None
|
||||
//},
|
||||
//Self::Color(palette) => {
|
||||
//let old = state.color;
|
||||
//state.color = palette;
|
||||
//Some(Self::Color(old))
|
||||
//},
|
||||
//Self::Pool(cmd) => {
|
||||
//match cmd {
|
||||
//// autoselect: automatically load selected clip in editor
|
||||
//PoolCommand::Select(_) => {
|
||||
//let undo = cmd.delegate(&mut state.pool, Self::Pool)?;
|
||||
//state.editor.set_clip(state.pool.clip().as_ref());
|
||||
//undo
|
||||
//},
|
||||
//// reload clip in editor to update color
|
||||
//PoolCommand::Clip(MidiPoolCommand::SetColor(index, _)) => {
|
||||
//let undo = cmd.delegate(&mut state.pool, Self::Pool)?;
|
||||
//state.editor.set_clip(state.pool.clip().as_ref());
|
||||
//undo
|
||||
//},
|
||||
//_ => cmd.delegate(&mut state.pool, Self::Pool)?
|
||||
//}
|
||||
//},
|
||||
//});
|
||||
//command!(|self: SceneCommand, state: Arranger|match self {
|
||||
//Self::Add => { state.scene_add(None, None)?; None }
|
||||
//Self::Del(index) => { state.scene_del(index); None },
|
||||
//Self::SetColor(index, color) => {
|
||||
//let old = state.scenes[index].color;
|
||||
//state.scenes[index].color = color;
|
||||
//Some(Self::SetColor(index, old))
|
||||
//},
|
||||
//Self::Enqueue(scene) => {
|
||||
//for track in 0..state.tracks.len() {
|
||||
//state.tracks[track].player.enqueue_next(state.scenes[scene].clips[track].as_ref());
|
||||
//}
|
||||
//None
|
||||
//},
|
||||
//_ => None
|
||||
//});
|
||||
//command!(|self: TrackCommand, state: Arranger|match self {
|
||||
//Self::Add => { state.track_add(None, None)?; None },
|
||||
//Self::Del(index) => { state.track_del(index); None },
|
||||
//Self::Stop(track) => { state.tracks[track].player.enqueue_next(None); None },
|
||||
//Self::SetColor(index, color) => {
|
||||
//let old = state.tracks[index].color;
|
||||
//state.tracks[index].color = color;
|
||||
//Some(Self::SetColor(index, old))
|
||||
//},
|
||||
//_ => None
|
||||
//});
|
||||
//command!(|self: ClipCommand, state: Arranger|match self {
|
||||
//Self::Get(track, scene) => { todo!() },
|
||||
//Self::Put(track, scene, clip) => {
|
||||
//let old = state.scenes[scene].clips[track].clone();
|
||||
//state.scenes[scene].clips[track] = clip;
|
||||
//Some(Self::Put(track, scene, old))
|
||||
//},
|
||||
//Self::Enqueue(track, scene) => {
|
||||
//state.tracks[track].player.enqueue_next(state.scenes[scene].clips[track].as_ref());
|
||||
//None
|
||||
//},
|
||||
//_ => None
|
||||
//});
|
||||
//keymap!(KEYS_SEQUENCER = |state: Sequencer, input: Event| SequencerCommand {
|
||||
//// TODO: k: toggle on-screen keyboard
|
||||
//ctrl(key(Char('k'))) => { todo!("keyboard") },
|
||||
//// Transport: Play/pause
|
||||
//key(Char(' ')) => SeqCmd::Clock(if state.clock().is_stopped() { Play(None) } else { Pause(None) }),
|
||||
//// Transport: Play from start or rewind to start
|
||||
//shift(key(Char(' '))) => SeqCmd::Clock(if state.clock().is_stopped() { Play(Some(0)) } else { Pause(Some(0)) }),
|
||||
//// u: undo
|
||||
//key(Char('u')) => SeqCmd::History(-1),
|
||||
//// Shift-U: redo
|
||||
//key(Char('U')) => SeqCmd::History( 1),
|
||||
//// Tab: Toggle compact mode
|
||||
//key(Tab) => SeqCmd::Compact(!state.compact),
|
||||
//// q: Enqueue currently edited clip
|
||||
//key(Char('q')) => SeqCmd::Enqueue(state.pool.clip().clone()),
|
||||
//// 0: Enqueue clip 0 (stop all)
|
||||
//key(Char('0')) => SeqCmd::Enqueue(Some(state.clips()[0].clone())),
|
||||
//// e: Toggle between editing currently playing or other clip
|
||||
////key(Char('e')) => if let Some((_, Some(playing))) = state.player.play_clip() {
|
||||
////let editing = state.editor.clip().as_ref().map(|p|p.read().unwrap().clone());
|
||||
////let selected = state.pool.clip().clone();
|
||||
////SeqCmd::Editor(Show(Some(if Some(selected.read().unwrap().clone()) != editing {
|
||||
////selected
|
||||
////} else {
|
||||
////playing.clone()
|
||||
////})))
|
||||
////} else {
|
||||
////return None
|
||||
////}
|
||||
//}, if let Some(command) = MidiEditCommand::input_to_command(&state.editor, input) {
|
||||
//SeqCmd::Editor(command)
|
||||
//} else if let Some(command) = PoolCommand::input_to_command(&state.pool, input) {
|
||||
//SeqCmd::Pool(command)
|
||||
//} else {
|
||||
//return None
|
||||
//});
|
||||
//keymap!(<'a> KEYS_GROOVEBOX = |state: Groovebox, input: Event| GrooveboxCommand {
|
||||
//// Tab: Toggle compact mode
|
||||
//key(Tab) => GrvCmd::Compact(!state.compact),
|
||||
//// q: Enqueue currently edited clip
|
||||
//key(Char('q')) => GrvCmd::Enqueue(state.pool.clip().clone()),
|
||||
//// 0: Enqueue clip 0 (stop all)
|
||||
//key(Char('0')) => GrvCmd::Enqueue(Some(state.pool.clips()[0].clone())),
|
||||
//// TODO: k: toggle on-screen keyboard
|
||||
//ctrl(key(Char('k'))) => todo!("keyboard"),
|
||||
//// Transport: Play from start or rewind to start
|
||||
//ctrl(key(Char(' '))) => GrvCmd::Clock(
|
||||
//if state.clock().is_stopped() { Play(Some(0)) } else { Pause(Some(0)) }
|
||||
//),
|
||||
//// Shift-R: toggle recording
|
||||
//shift(key(Char('R'))) => GrvCmd::Sampler(if state.sampler.recording.is_some() {
|
||||
//SmplCmd::RecordFinish
|
||||
//} else {
|
||||
//SmplCmd::RecordBegin(u7::from(state.editor.note_point() as u8))
|
||||
//}),
|
||||
//// Shift-Del: delete sample
|
||||
//shift(key(Delete)) => GrvCmd::Sampler(
|
||||
//SmplCmd::SetSample(u7::from(state.editor.note_point() as u8), None)
|
||||
//),
|
||||
//// e: Toggle between editing currently playing or other clip
|
||||
////shift(key(Char('e'))) => if let Some((_, Some(playing))) = state.player.play_clip() {
|
||||
////let editing = state.editor.clip().as_ref().map(|p|p.read().unwrap().clone());
|
||||
////let selected = state.pool.clip().clone().map(|s|s.read().unwrap().clone());
|
||||
////GrvCmd::Editor(Show(if selected != editing {
|
||||
////selected
|
||||
////} else {
|
||||
////Some(playing.clone())
|
||||
////}))
|
||||
////} else {
|
||||
////return None
|
||||
////},
|
||||
//}, if let Some(command) = MidiEditCommand::input_to_command(&state.editor, input) {
|
||||
//GrvCmd::Editor(command)
|
||||
//} else if let Some(command) = PoolCommand::input_to_command(&state.pool, input) {
|
||||
//GrvCmd::Pool(command)
|
||||
//} else {
|
||||
//return None
|
||||
//});
|
||||
//keymap!(KEYS_ARRANGER = |state: Arranger, input: Event| ArrangerCommand {
|
||||
//key(Char('u')) => ArrCmd::History(-1),
|
||||
//key(Char('U')) => ArrCmd::History(1),
|
||||
//// TODO: k: toggle on-screen keyboard
|
||||
//ctrl(key(Char('k'))) => { todo!("keyboard") },
|
||||
//// Transport: Play/pause
|
||||
//key(Char(' ')) => ArrCmd::Clock(if state.clock().is_stopped() { Play(None) } else { Pause(None) }),
|
||||
//// Transport: Play from start or rewind to start
|
||||
//shift(key(Char(' '))) => ArrCmd::Clock(if state.clock().is_stopped() { Play(Some(0)) } else { Pause(Some(0)) }),
|
||||
//key(Char('e')) => ArrCmd::Editor(MidiEditCommand::Show(state.pool.clip().clone())),
|
||||
//ctrl(key(Char('a'))) => ArrCmd::Scene(SceneCommand::Add),
|
||||
//ctrl(key(Char('A'))) => return None,//ArrCmd::Scene(SceneCommand::Add),
|
||||
//ctrl(key(Char('t'))) => ArrCmd::Track(TrackCommand::Add),
|
||||
//// Tab: Toggle visibility of clip pool column
|
||||
//key(Tab) => ArrCmd::Pool(PoolCommand::Show(!state.pool.visible)),
|
||||
//}, {
|
||||
//use ArrangerSelection as Selected;
|
||||
//use SceneCommand as Scene;
|
||||
//use TrackCommand as Track;
|
||||
//use ClipCommand as Clip;
|
||||
//let t_len = state.tracks.len();
|
||||
//let s_len = state.scenes.len();
|
||||
//match state.selected {
|
||||
//Selected::Clip(t, s) => clip_keymap(state, input, t, s),
|
||||
//Selected::Scene(s) => scene_keymap(state, input, s),
|
||||
//Selected::Track(t) => track_keymap(state, input, t),
|
||||
//Selected::Mix => match input {
|
||||
|
||||
_ => None
|
||||
},
|
||||
}
|
||||
}.or_else(||if let Some(command) = MidiEditCommand::input_to_command(&state.editor, input) {
|
||||
Some(ArrCmd::Editor(command))
|
||||
} else if let Some(command) = PoolCommand::input_to_command(&state.pool, input) {
|
||||
Some(ArrCmd::Pool(command))
|
||||
} else {
|
||||
None
|
||||
})?);
|
||||
//kpat!(Delete) => Some(ArrCmd::Clear),
|
||||
//kpat!(Char('0')) => Some(ArrCmd::StopAll),
|
||||
//kpat!(Char('c')) => Some(ArrCmd::Color(ItemPalette::random())),
|
||||
|
||||
fn clip_keymap (state: &Arranger, input: &Event, t: usize, s: usize) -> Option<ArrangerCommand> {
|
||||
use ArrangerSelection as Selected;
|
||||
use SceneCommand as Scene;
|
||||
use TrackCommand as Track;
|
||||
use ClipCommand as Clip;
|
||||
let t_len = state.tracks.len();
|
||||
let s_len = state.scenes.len();
|
||||
Some(match input {
|
||||
//kpat!(Up) => return None,
|
||||
//kpat!(Down) => Some(ArrCmd::Select(Selected::Scene(0))),
|
||||
//kpat!(Left) => return None,
|
||||
//kpat!(Right) => Some(ArrCmd::Select(Selected::Track(0))),
|
||||
|
||||
kpat!(Char('g')) => ArrCmd::Pool(PoolCommand::Select(0)),
|
||||
kpat!(Char('q')) => ArrCmd::Clip(Clip::Enqueue(t, s)),
|
||||
kpat!(Char('l')) => ArrCmd::Clip(Clip::SetLoop(t, s, false)),
|
||||
//_ => None
|
||||
//},
|
||||
//}
|
||||
//}.or_else(||if let Some(command) = MidiEditCommand::input_to_command(&state.editor, input) {
|
||||
//Some(ArrCmd::Editor(command))
|
||||
//} else if let Some(command) = PoolCommand::input_to_command(&state.pool, input) {
|
||||
//Some(ArrCmd::Pool(command))
|
||||
//} else {
|
||||
//None
|
||||
//})?);
|
||||
|
||||
kpat!(Enter) => if state.scenes[s].clips[t].is_none() {
|
||||
// FIXME: get this clip from the pool (autoregister via intmut)
|
||||
let (_, clip) = state.add_clip();
|
||||
ArrCmd::Clip(Clip::Put(t, s, Some(clip)))
|
||||
} else {
|
||||
return None
|
||||
},
|
||||
kpat!(Delete) => ArrCmd::Clip(Clip::Put(t, s, None)),
|
||||
kpat!(Char('p')) => ArrCmd::Clip(Clip::Put(t, s, state.pool.clip().clone())),
|
||||
kpat!(Char(',')) => ArrCmd::Clip(Clip::Put(t, s, None)),
|
||||
kpat!(Char('.')) => ArrCmd::Clip(Clip::Put(t, s, None)),
|
||||
kpat!(Char('<')) => ArrCmd::Clip(Clip::Put(t, s, None)),
|
||||
kpat!(Char('>')) => ArrCmd::Clip(Clip::Put(t, s, None)),
|
||||
//fn clip_keymap (state: &Arranger, input: &Event, t: usize, s: usize) -> Option<ArrangerCommand> {
|
||||
//use ArrangerSelection as Selected;
|
||||
//use SceneCommand as Scene;
|
||||
//use TrackCommand as Track;
|
||||
//use ClipCommand as Clip;
|
||||
//let t_len = state.tracks.len();
|
||||
//let s_len = state.scenes.len();
|
||||
//Some(match input {
|
||||
|
||||
kpat!(Up) => ArrCmd::Select(if s > 0 { Selected::Clip(t, s - 1) } else { Selected::Track(t) }),
|
||||
kpat!(Down) => ArrCmd::Select(Selected::Clip(t, (s + 1).min(s_len.saturating_sub(1)))),
|
||||
kpat!(Left) => ArrCmd::Select(if t > 0 { Selected::Clip(t - 1, s) } else { Selected::Scene(s) }),
|
||||
kpat!(Right) => ArrCmd::Select(Selected::Clip((t + 1).min(t_len.saturating_sub(1)), s)),
|
||||
//kpat!(Char('g')) => ArrCmd::Pool(PoolCommand::Select(0)),
|
||||
//kpat!(Char('q')) => ArrCmd::Clip(Clip::Enqueue(t, s)),
|
||||
//kpat!(Char('l')) => ArrCmd::Clip(Clip::SetLoop(t, s, false)),
|
||||
|
||||
_ => return None
|
||||
})
|
||||
}
|
||||
fn scene_keymap (state: &Arranger, input: &Event, s: usize) -> Option<ArrangerCommand> {
|
||||
use ArrangerSelection as Selected;
|
||||
use SceneCommand as Scene;
|
||||
use TrackCommand as Track;
|
||||
use ClipCommand as Clip;
|
||||
let t_len = state.tracks.len();
|
||||
let s_len = state.scenes.len();
|
||||
Some(match input {
|
||||
//kpat!(Enter) => if state.scenes[s].clips[t].is_none() {
|
||||
//// FIXME: get this clip from the pool (autoregister via intmut)
|
||||
//let (_, clip) = state.add_clip();
|
||||
//ArrCmd::Clip(Clip::Put(t, s, Some(clip)))
|
||||
//} else {
|
||||
//return None
|
||||
//},
|
||||
//kpat!(Delete) => ArrCmd::Clip(Clip::Put(t, s, None)),
|
||||
//kpat!(Char('p')) => ArrCmd::Clip(Clip::Put(t, s, state.pool.clip().clone())),
|
||||
//kpat!(Char(',')) => ArrCmd::Clip(Clip::Put(t, s, None)),
|
||||
//kpat!(Char('.')) => ArrCmd::Clip(Clip::Put(t, s, None)),
|
||||
//kpat!(Char('<')) => ArrCmd::Clip(Clip::Put(t, s, None)),
|
||||
//kpat!(Char('>')) => ArrCmd::Clip(Clip::Put(t, s, None)),
|
||||
|
||||
kpat!(Char(',')) => ArrCmd::Scene(Scene::Swap(s, s - 1)),
|
||||
kpat!(Char('.')) => ArrCmd::Scene(Scene::Swap(s, s + 1)),
|
||||
kpat!(Char('<')) => ArrCmd::Scene(Scene::Swap(s, s - 1)),
|
||||
kpat!(Char('>')) => ArrCmd::Scene(Scene::Swap(s, s + 1)),
|
||||
kpat!(Char('q')) => ArrCmd::Scene(Scene::Enqueue(s)),
|
||||
kpat!(Delete) => ArrCmd::Scene(Scene::Del(s)),
|
||||
kpat!(Char('c')) => ArrCmd::Scene(Scene::SetColor(s, ItemPalette::random())),
|
||||
//kpat!(Up) => ArrCmd::Select(if s > 0 { Selected::Clip(t, s - 1) } else { Selected::Track(t) }),
|
||||
//kpat!(Down) => ArrCmd::Select(Selected::Clip(t, (s + 1).min(s_len.saturating_sub(1)))),
|
||||
//kpat!(Left) => ArrCmd::Select(if t > 0 { Selected::Clip(t - 1, s) } else { Selected::Scene(s) }),
|
||||
//kpat!(Right) => ArrCmd::Select(Selected::Clip((t + 1).min(t_len.saturating_sub(1)), s)),
|
||||
|
||||
kpat!(Up) => ArrCmd::Select(if s > 0 { Selected::Scene(s - 1) } else { Selected::Mix }),
|
||||
kpat!(Down) => ArrCmd::Select(Selected::Scene((s + 1).min(s_len.saturating_sub(1)))),
|
||||
kpat!(Left) => return None,
|
||||
kpat!(Right) => ArrCmd::Select(Selected::Clip(0, s)),
|
||||
//_ => return None
|
||||
//})
|
||||
//}
|
||||
//fn scene_keymap (state: &Arranger, input: &Event, s: usize) -> Option<ArrangerCommand> {
|
||||
//use ArrangerSelection as Selected;
|
||||
//use SceneCommand as Scene;
|
||||
//use TrackCommand as Track;
|
||||
//use ClipCommand as Clip;
|
||||
//let t_len = state.tracks.len();
|
||||
//let s_len = state.scenes.len();
|
||||
//Some(match input {
|
||||
|
||||
_ => return None
|
||||
})
|
||||
}
|
||||
fn track_keymap (state: &Arranger, input: &Event, t: usize) -> Option<ArrangerCommand> {
|
||||
use ArrangerSelection as Selected;
|
||||
use SceneCommand as Scene;
|
||||
use TrackCommand as Track;
|
||||
use ClipCommand as Clip;
|
||||
let t_len = state.tracks.len();
|
||||
let s_len = state.scenes.len();
|
||||
Some(match input {
|
||||
//kpat!(Char(',')) => ArrCmd::Scene(Scene::Swap(s, s - 1)),
|
||||
//kpat!(Char('.')) => ArrCmd::Scene(Scene::Swap(s, s + 1)),
|
||||
//kpat!(Char('<')) => ArrCmd::Scene(Scene::Swap(s, s - 1)),
|
||||
//kpat!(Char('>')) => ArrCmd::Scene(Scene::Swap(s, s + 1)),
|
||||
//kpat!(Char('q')) => ArrCmd::Scene(Scene::Enqueue(s)),
|
||||
//kpat!(Delete) => ArrCmd::Scene(Scene::Del(s)),
|
||||
//kpat!(Char('c')) => ArrCmd::Scene(Scene::SetColor(s, ItemPalette::random())),
|
||||
|
||||
kpat!(Char(',')) => ArrCmd::Track(Track::Swap(t, t - 1)),
|
||||
kpat!(Char('.')) => ArrCmd::Track(Track::Swap(t, t + 1)),
|
||||
kpat!(Char('<')) => ArrCmd::Track(Track::Swap(t, t - 1)),
|
||||
kpat!(Char('>')) => ArrCmd::Track(Track::Swap(t, t + 1)),
|
||||
kpat!(Delete) => ArrCmd::Track(Track::Del(t)),
|
||||
kpat!(Char('c')) => ArrCmd::Track(Track::SetColor(t, ItemPalette::random())),
|
||||
//kpat!(Up) => ArrCmd::Select(if s > 0 { Selected::Scene(s - 1) } else { Selected::Mix }),
|
||||
//kpat!(Down) => ArrCmd::Select(Selected::Scene((s + 1).min(s_len.saturating_sub(1)))),
|
||||
//kpat!(Left) => return None,
|
||||
//kpat!(Right) => ArrCmd::Select(Selected::Clip(0, s)),
|
||||
|
||||
kpat!(Up) => return None,
|
||||
kpat!(Down) => ArrCmd::Select(Selected::Clip(t, 0)),
|
||||
kpat!(Left) => ArrCmd::Select(if t > 0 { Selected::Track(t - 1) } else { Selected::Mix }),
|
||||
kpat!(Right) => ArrCmd::Select(Selected::Track((t + 1).min(t_len.saturating_sub(1)))),
|
||||
//_ => return None
|
||||
//})
|
||||
//}
|
||||
//fn track_keymap (state: &Arranger, input: &Event, t: usize) -> Option<ArrangerCommand> {
|
||||
//use ArrangerSelection as Selected;
|
||||
//use SceneCommand as Scene;
|
||||
//use TrackCommand as Track;
|
||||
//use ClipCommand as Clip;
|
||||
//let t_len = state.tracks.len();
|
||||
//let s_len = state.scenes.len();
|
||||
//Some(match input {
|
||||
|
||||
_ => return None
|
||||
})
|
||||
}
|
||||
//kpat!(Char(',')) => ArrCmd::Track(Track::Swap(t, t - 1)),
|
||||
//kpat!(Char('.')) => ArrCmd::Track(Track::Swap(t, t + 1)),
|
||||
//kpat!(Char('<')) => ArrCmd::Track(Track::Swap(t, t - 1)),
|
||||
//kpat!(Char('>')) => ArrCmd::Track(Track::Swap(t, t + 1)),
|
||||
//kpat!(Delete) => ArrCmd::Track(Track::Del(t)),
|
||||
//kpat!(Char('c')) => ArrCmd::Track(Track::SetColor(t, ItemPalette::random())),
|
||||
|
||||
//kpat!(Up) => return None,
|
||||
//kpat!(Down) => ArrCmd::Select(Selected::Clip(t, 0)),
|
||||
//kpat!(Left) => ArrCmd::Select(if t > 0 { Selected::Track(t - 1) } else { Selected::Mix }),
|
||||
//kpat!(Right) => ArrCmd::Select(Selected::Track((t + 1).min(t_len.saturating_sub(1)))),
|
||||
|
||||
//_ => return None
|
||||
//})
|
||||
//}
|
||||
|
|
|
|||
110
tek/src/model.rs
110
tek/src/model.rs
|
|
@ -92,60 +92,60 @@ has_clock!(|self: App|&self.clock);
|
|||
has_clips!(|self: App|self.pool.as_ref().expect("no clip pool").clips);
|
||||
has_editor!(|self: App|self.editor.as_ref().expect("no editor"));
|
||||
|
||||
#[derive(Default)] pub struct Sequencer {
|
||||
pub jack: Arc<RwLock<JackConnection>>,
|
||||
pub compact: bool,
|
||||
pub editor: MidiEditor,
|
||||
pub midi_buf: Vec<Vec<Vec<u8>>>,
|
||||
pub note_buf: Vec<u8>,
|
||||
pub perf: PerfModel,
|
||||
pub player: MidiPlayer,
|
||||
pub pool: PoolModel,
|
||||
pub selectors: bool,
|
||||
pub size: Measure<TuiOut>,
|
||||
pub status: bool,
|
||||
pub transport: bool,
|
||||
}
|
||||
has_size!(<TuiOut>|self:Sequencer|&self.size);
|
||||
has_clock!(|self:Sequencer|&self.player.clock);
|
||||
has_clips!(|self:Sequencer|self.pool.clips);
|
||||
has_editor!(|self:Sequencer|self.editor);
|
||||
has_player!(|self:Sequencer|self.player);
|
||||
//#[derive(Default)] pub struct Sequencer {
|
||||
//pub jack: Arc<RwLock<JackConnection>>,
|
||||
//pub compact: bool,
|
||||
//pub editor: MidiEditor,
|
||||
//pub midi_buf: Vec<Vec<Vec<u8>>>,
|
||||
//pub note_buf: Vec<u8>,
|
||||
//pub perf: PerfModel,
|
||||
//pub player: MidiPlayer,
|
||||
//pub pool: PoolModel,
|
||||
//pub selectors: bool,
|
||||
//pub size: Measure<TuiOut>,
|
||||
//pub status: bool,
|
||||
//pub transport: bool,
|
||||
//}
|
||||
//has_size!(<TuiOut>|self:Sequencer|&self.size);
|
||||
//has_clock!(|self:Sequencer|&self.player.clock);
|
||||
//has_clips!(|self:Sequencer|self.pool.clips);
|
||||
//has_editor!(|self:Sequencer|self.editor);
|
||||
//has_player!(|self:Sequencer|self.player);
|
||||
|
||||
#[derive(Default)] pub struct Groovebox {
|
||||
pub jack: Arc<RwLock<JackConnection>>,
|
||||
pub compact: bool,
|
||||
pub editor: MidiEditor,
|
||||
pub midi_buf: Vec<Vec<Vec<u8>>>,
|
||||
pub note_buf: Vec<u8>,
|
||||
pub perf: PerfModel,
|
||||
pub player: MidiPlayer,
|
||||
pub pool: PoolModel,
|
||||
pub sampler: Sampler,
|
||||
pub size: Measure<TuiOut>,
|
||||
pub status: bool,
|
||||
}
|
||||
has_clock!(|self: Groovebox|self.player.clock());
|
||||
//#[derive(Default)] pub struct Groovebox {
|
||||
//pub jack: Arc<RwLock<JackConnection>>,
|
||||
//pub compact: bool,
|
||||
//pub editor: MidiEditor,
|
||||
//pub midi_buf: Vec<Vec<Vec<u8>>>,
|
||||
//pub note_buf: Vec<u8>,
|
||||
//pub perf: PerfModel,
|
||||
//pub player: MidiPlayer,
|
||||
//pub pool: PoolModel,
|
||||
//pub sampler: Sampler,
|
||||
//pub size: Measure<TuiOut>,
|
||||
//pub status: bool,
|
||||
//}
|
||||
//has_clock!(|self: Groovebox|self.player.clock());
|
||||
|
||||
#[derive(Default)] pub struct Arranger {
|
||||
pub clock: Clock,
|
||||
pub color: ItemPalette,
|
||||
pub compact: bool,
|
||||
pub editing: AtomicBool,
|
||||
pub editor: MidiEditor,
|
||||
pub jack: Arc<RwLock<JackConnection>>,
|
||||
pub midi_buf: Vec<Vec<Vec<u8>>>,
|
||||
pub midi_ins: Vec<JackPort<MidiIn>>,
|
||||
pub midi_outs: Vec<JackPort<MidiOut>>,
|
||||
pub note_buf: Vec<u8>,
|
||||
pub perf: PerfModel,
|
||||
pub pool: PoolModel,
|
||||
pub scenes: Vec<ArrangerScene>,
|
||||
pub selected: ArrangerSelection,
|
||||
pub size: Measure<TuiOut>,
|
||||
pub splits: [u16;2],
|
||||
pub tracks: Vec<ArrangerTrack>,
|
||||
}
|
||||
has_clock!(|self: Arranger|&self.clock);
|
||||
has_clips!(|self: Arranger|self.pool.clips);
|
||||
has_editor!(|self: Arranger|self.editor);
|
||||
//#[derive(Default)] pub struct Arranger {
|
||||
//pub clock: Clock,
|
||||
//pub color: ItemPalette,
|
||||
//pub compact: bool,
|
||||
//pub editing: AtomicBool,
|
||||
//pub editor: MidiEditor,
|
||||
//pub jack: Arc<RwLock<JackConnection>>,
|
||||
//pub midi_buf: Vec<Vec<Vec<u8>>>,
|
||||
//pub midi_ins: Vec<JackPort<MidiIn>>,
|
||||
//pub midi_outs: Vec<JackPort<MidiOut>>,
|
||||
//pub note_buf: Vec<u8>,
|
||||
//pub perf: PerfModel,
|
||||
//pub pool: PoolModel,
|
||||
//pub scenes: Vec<ArrangerScene>,
|
||||
//pub selected: ArrangerSelection,
|
||||
//pub size: Measure<TuiOut>,
|
||||
//pub splits: [u16;2],
|
||||
//pub tracks: Vec<ArrangerTrack>,
|
||||
//}
|
||||
//has_clock!(|self: Arranger|&self.clock);
|
||||
//has_clips!(|self: Arranger|self.pool.clips);
|
||||
//has_editor!(|self: Arranger|self.editor);
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
use crate::*;
|
||||
1084
tek/src/view.rs
1084
tek/src/view.rs
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue