comment out app-specific structs/impls. only monoapp remains

This commit is contained in:
🪞👃🪞 2025-01-12 00:52:42 +01:00
parent e73c31d494
commit 479988272e
6 changed files with 1080 additions and 1075 deletions

View file

@ -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();
}
}
}
}

View file

@ -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>(

View file

@ -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
//})
//}

View file

@ -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);

View file

@ -1 +0,0 @@
use crate::*;

File diff suppressed because it is too large Load diff