mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 04:06:45 +01:00
enable adding midi ins and outs
This commit is contained in:
parent
76cefdca61
commit
5d6592bbdf
12 changed files with 171 additions and 165 deletions
|
|
@ -70,7 +70,7 @@ pub const fn peek_src <'a> (source: &'a str) -> Option<Token<'a>> {
|
||||||
_ => token.error(Unexpected(c))
|
_ => token.error(Unexpected(c))
|
||||||
},
|
},
|
||||||
Sym(_) => match c {
|
Sym(_) => match c {
|
||||||
'a'..='z'|'0'..='9'|'-' => token.grow_sym(),
|
'a'..='z'|'A'..='Z'|'0'..='9'|'-' => token.grow_sym(),
|
||||||
' '|'\n'|'\r'|'\t'|')' => return Some(token),
|
' '|'\n'|'\r'|'\t'|')' => return Some(token),
|
||||||
_ => token.error(Unexpected(c))
|
_ => token.error(Unexpected(c))
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -16,3 +16,13 @@ pub trait Command<S>: Send + Sync + Sized {
|
||||||
Ok(self.execute(state)?.map(wrap))
|
Ok(self.execute(state)?.map(wrap))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<S, T: Command<S>> Command<S> for Option<T> {
|
||||||
|
fn execute (self, _: &mut S) -> Perhaps<Self> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
fn delegate <U> (self, _: &mut S, _: impl Fn(Self)->U) -> Perhaps<U>
|
||||||
|
where Self: Sized
|
||||||
|
{
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ impl<'a, C, T: TryFromAtom<'a, C> + Command<C>> AtomCommand<'a, C> for T {}
|
||||||
$(let $arg: Option<$type> = Context::<$type>::get($state, &$arg.value);)?
|
$(let $arg: Option<$type> = Context::<$type>::get($state, &$arg.value);)?
|
||||||
)*
|
)*
|
||||||
$(let $rest = iter.clone();)?
|
$(let $rest = iter.clone();)?
|
||||||
return Some($command)
|
return $command
|
||||||
},)*
|
},)*
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
|
|
@ -142,7 +142,7 @@ impl<'a, C, T: TryFromAtom<'a, C> + Command<C>> AtomCommand<'a, C> for T {}
|
||||||
$(let $arg: Option<$type> = Context::<$type>::get($state, &$arg.value);)?
|
$(let $arg: Option<$type> = Context::<$type>::get($state, &$arg.value);)?
|
||||||
)*
|
)*
|
||||||
$(let $rest = iter.clone();)?
|
$(let $rest = iter.clone();)?
|
||||||
return Some($command)
|
return $command
|
||||||
}),*
|
}),*
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -184,15 +184,15 @@ impl MidiViewer for MidiEditor {
|
||||||
fn set_clip (&mut self, p: Option<&Arc<RwLock<MidiClip>>>) { self.mode.set_clip(p) }
|
fn set_clip (&mut self, p: Option<&Arc<RwLock<MidiClip>>>) { self.mode.set_clip(p) }
|
||||||
}
|
}
|
||||||
atom_command!(MidiEditCommand: |state: MidiEditor| {
|
atom_command!(MidiEditCommand: |state: MidiEditor| {
|
||||||
("note/append" [] Self::AppendNote)
|
("note/append" [] Some(Self::AppendNote))
|
||||||
("note/put" [] Self::PutNote)
|
("note/put" [] Some(Self::PutNote))
|
||||||
("note/del" [] Self::DelNote)
|
("note/del" [] Some(Self::DelNote))
|
||||||
("note/pos" [a: usize] Self::SetNoteCursor(a.expect("no note cursor")))
|
("note/pos" [a: usize] Some(Self::SetNoteCursor(a.expect("no note cursor"))))
|
||||||
("note/len" [a: usize] Self::SetNoteLength(a.expect("no note length")))
|
("note/len" [a: usize] Some(Self::SetNoteLength(a.expect("no note length"))))
|
||||||
("time/pos" [a: usize] Self::SetTimeCursor(a.expect("no time cursor")))
|
("time/pos" [a: usize] Some(Self::SetTimeCursor(a.expect("no time cursor"))))
|
||||||
("time/zoom" [a: usize] Self::SetTimeZoom(a.expect("no time zoom")))
|
("time/zoom" [a: usize] Some(Self::SetTimeZoom(a.expect("no time zoom"))))
|
||||||
("time/lock" [a: bool] Self::SetTimeLock(a.expect("no time lock")))
|
("time/lock" [a: bool] Some(Self::SetTimeLock(a.expect("no time lock"))))
|
||||||
("time/lock" [] Self::SetTimeLock(!state.time_lock().get()))
|
("time/lock" [] Some(Self::SetTimeLock(!state.time_lock().get())))
|
||||||
});
|
});
|
||||||
#[derive(Clone, Debug)] pub enum MidiEditCommand {
|
#[derive(Clone, Debug)] pub enum MidiEditCommand {
|
||||||
// TODO: 1-9 seek markers that by default start every 8th of the clip
|
// TODO: 1-9 seek markers that by default start every 8th of the clip
|
||||||
|
|
|
||||||
|
|
@ -265,13 +265,13 @@ provide!(ItemColor: |self: MidiPool| {
|
||||||
Clip(PoolClipCommand),
|
Clip(PoolClipCommand),
|
||||||
}
|
}
|
||||||
atom_command!(PoolCommand: |state: MidiPool| {
|
atom_command!(PoolCommand: |state: MidiPool| {
|
||||||
("show" [a: bool] Self::Show(a.expect("no flag")))
|
("show" [a: bool] Some(Self::Show(a.expect("no flag"))))
|
||||||
("select" [i: usize] Self::Select(i.expect("no index")))
|
("select" [i: usize] Some(Self::Select(i.expect("no index"))))
|
||||||
("rename" [,..a] ClipRenameCommand::try_from_expr(state, a).map(Self::Rename).expect("invalid command"))
|
("rename" [,..a] ClipRenameCommand::try_from_expr(state, a).map(Self::Rename))
|
||||||
("length" [,..a] ClipLengthCommand::try_from_expr(state, a).map(Self::Length).expect("invalid command"))
|
("length" [,..a] ClipLengthCommand::try_from_expr(state, a).map(Self::Length))
|
||||||
("import" [,..a] FileBrowserCommand::try_from_expr(state, a).map(Self::Import).expect("invalid command"))
|
("import" [,..a] FileBrowserCommand::try_from_expr(state, a).map(Self::Import))
|
||||||
("export" [,..a] FileBrowserCommand::try_from_expr(state, a).map(Self::Export).expect("invalid command"))
|
("export" [,..a] FileBrowserCommand::try_from_expr(state, a).map(Self::Export))
|
||||||
("clip" [,..a] PoolClipCommand::try_from_expr(state, a).map(Self::Clip).expect("invalid command"))
|
("clip" [,..a] PoolClipCommand::try_from_expr(state, a).map(Self::Clip))
|
||||||
});
|
});
|
||||||
command!(|self: PoolCommand, state: MidiPool|{
|
command!(|self: PoolCommand, state: MidiPool|{
|
||||||
use PoolCommand::*;
|
use PoolCommand::*;
|
||||||
|
|
@ -300,14 +300,22 @@ command!(|self: PoolCommand, state: MidiPool|{
|
||||||
SetColor(usize, ItemColor),
|
SetColor(usize, ItemColor),
|
||||||
}
|
}
|
||||||
atom_command!(PoolClipCommand: |state: MidiPool| {
|
atom_command!(PoolClipCommand: |state: MidiPool| {
|
||||||
("add" [i: usize, c: MidiClip] Self::Add(i.expect("no index"), c.expect("no clip")))
|
("add" [i: usize, c: MidiClip]
|
||||||
("delete" [i: usize] Self::Delete(i.expect("no index")))
|
Some(Self::Add(i.expect("no index"), c.expect("no clip"))))
|
||||||
("swap" [a: usize, b: usize] Self::Swap(a.expect("no index"), b.expect("no index")))
|
("delete" [i: usize]
|
||||||
("import" [i: usize, p: PathBuf] Self::Import(i.expect("no index"), p.expect("no path")))
|
Some(Self::Delete(i.expect("no index"))))
|
||||||
("export" [i: usize, p: PathBuf] Self::Export(i.expect("no index"), p.expect("no path")))
|
("swap" [a: usize, b: usize]
|
||||||
("set-name" [i: usize, n: Arc<str>] Self::SetName(i.expect("no index"), n.expect("no name")))
|
Some(Self::Swap(a.expect("no index"), b.expect("no index"))))
|
||||||
("set-length" [i: usize, l: usize] Self::SetLength(i.expect("no index"), l.expect("no length")))
|
("import" [i: usize, p: PathBuf]
|
||||||
("set-color" [i: usize, c: ItemColor] Self::SetColor(i.expect("no index"), c.expect("no color")))
|
Some(Self::Import(i.expect("no index"), p.expect("no path"))))
|
||||||
|
("export" [i: usize, p: PathBuf]
|
||||||
|
Some(Self::Export(i.expect("no index"), p.expect("no path"))))
|
||||||
|
("set-name" [i: usize, n: Arc<str>]
|
||||||
|
Some(Self::SetName(i.expect("no index"), n.expect("no name"))))
|
||||||
|
("set-length" [i: usize, l: usize]
|
||||||
|
Some(Self::SetLength(i.expect("no index"), l.expect("no length"))))
|
||||||
|
("set-color" [i: usize, c: ItemColor]
|
||||||
|
Some(Self::SetColor(i.expect("no index"), c.expect("no color"))))
|
||||||
});
|
});
|
||||||
impl<T: HasClips> Command<T> for PoolClipCommand {
|
impl<T: HasClips> Command<T> for PoolClipCommand {
|
||||||
fn execute (self, model: &mut T) -> Perhaps<Self> {
|
fn execute (self, model: &mut T) -> Perhaps<Self> {
|
||||||
|
|
@ -381,10 +389,10 @@ impl<T: HasClips> Command<T> for PoolClipCommand {
|
||||||
Set(Arc<str>),
|
Set(Arc<str>),
|
||||||
}
|
}
|
||||||
atom_command!(ClipRenameCommand: |state: MidiPool| {
|
atom_command!(ClipRenameCommand: |state: MidiPool| {
|
||||||
("begin" [] Self::Begin)
|
("begin" [] Some(Self::Begin))
|
||||||
("cancel" [] Self::Cancel)
|
("cancel" [] Some(Self::Cancel))
|
||||||
("confirm" [] Self::Confirm)
|
("confirm" [] Some(Self::Confirm))
|
||||||
("set" [n: Arc<str>] Self::Set(n.expect("no name")))
|
("set" [n: Arc<str>] Some(Self::Set(n.expect("no name"))))
|
||||||
});
|
});
|
||||||
command!(|self: ClipRenameCommand, state: MidiPool|{
|
command!(|self: ClipRenameCommand, state: MidiPool|{
|
||||||
use ClipRenameCommand::*;
|
use ClipRenameCommand::*;
|
||||||
|
|
@ -421,13 +429,13 @@ command!(|self: ClipRenameCommand, state: MidiPool|{
|
||||||
Dec,
|
Dec,
|
||||||
}
|
}
|
||||||
atom_command!(ClipLengthCommand: |state: MidiPool| {
|
atom_command!(ClipLengthCommand: |state: MidiPool| {
|
||||||
("begin" [] Self::Begin)
|
("begin" [] Some(Self::Begin))
|
||||||
("cancel" [] Self::Cancel)
|
("cancel" [] Some(Self::Cancel))
|
||||||
("next" [] Self::Next)
|
("next" [] Some(Self::Next))
|
||||||
("prev" [] Self::Prev)
|
("prev" [] Some(Self::Prev))
|
||||||
("inc" [] Self::Inc)
|
("inc" [] Some(Self::Inc))
|
||||||
("dec" [] Self::Dec)
|
("dec" [] Some(Self::Dec))
|
||||||
("set" [l: usize] Self::Set(l.expect("no length")))
|
("set" [l: usize] Some(Self::Set(l.expect("no length"))))
|
||||||
});
|
});
|
||||||
command!(|self: ClipLengthCommand, state: MidiPool|{
|
command!(|self: ClipLengthCommand, state: MidiPool|{
|
||||||
use ClipLengthCommand::*;
|
use ClipLengthCommand::*;
|
||||||
|
|
@ -467,12 +475,12 @@ command!(|self: ClipLengthCommand, state: MidiPool|{
|
||||||
None
|
None
|
||||||
});
|
});
|
||||||
atom_command!(FileBrowserCommand: |state: MidiPool| {
|
atom_command!(FileBrowserCommand: |state: MidiPool| {
|
||||||
("begin" [] Self::Begin)
|
("begin" [] Some(Self::Begin))
|
||||||
("cancel" [] Self::Cancel)
|
("cancel" [] Some(Self::Cancel))
|
||||||
("confirm" [] Self::Confirm)
|
("confirm" [] Some(Self::Confirm))
|
||||||
("select" [i: usize] Self::Select(i.expect("no index")))
|
("select" [i: usize] Some(Self::Select(i.expect("no index"))))
|
||||||
("chdir" [p: PathBuf] Self::Chdir(p.expect("no path")))
|
("chdir" [p: PathBuf] Some(Self::Chdir(p.expect("no path"))))
|
||||||
("filter" [f: Arc<str>] Self::Filter(f.expect("no filter")))
|
("filter" [f: Arc<str>] Some(Self::Filter(f.expect("no filter"))))
|
||||||
});
|
});
|
||||||
command!(|self: FileBrowserCommand, state: MidiPool|{
|
command!(|self: FileBrowserCommand, state: MidiPool|{
|
||||||
use PoolMode::*;
|
use PoolMode::*;
|
||||||
|
|
|
||||||
|
|
@ -662,28 +662,19 @@ pub enum SamplerMode {
|
||||||
Sample(SamplerCommand),
|
Sample(SamplerCommand),
|
||||||
}
|
}
|
||||||
atom_command!(SamplerTuiCommand: |state: SamplerTui| {
|
atom_command!(SamplerTuiCommand: |state: SamplerTui| {
|
||||||
("select" [i: usize] Self::Select(i.expect("no index")))
|
("select" [i: usize] Some(Self::Select(i.expect("no index"))))
|
||||||
("import" [,..a] if let Some(command) = FileBrowserCommand::try_from_expr(state, a) {
|
("import" [,..a] FileBrowserCommand::try_from_expr(state, a).map(Self::Import))
|
||||||
Self::Import(command)
|
("sample" [,..a] SamplerCommand::try_from_expr(&state.state, a).map(Self::Sample)) });
|
||||||
} else {
|
|
||||||
return None
|
|
||||||
})
|
|
||||||
("sample" [,..a] if let Some(command) = SamplerCommand::try_from_expr(&state.state, a) {
|
|
||||||
Self::Sample(command)
|
|
||||||
} else {
|
|
||||||
return None
|
|
||||||
})
|
|
||||||
});
|
|
||||||
provide!(usize: |self: SamplerTui| {});
|
provide!(usize: |self: SamplerTui| {});
|
||||||
provide!(PathBuf: |self: SamplerTui| {});
|
provide!(PathBuf: |self: SamplerTui| {});
|
||||||
provide!(Arc<str>: |self: SamplerTui| {});
|
provide!(Arc<str>: |self: SamplerTui| {});
|
||||||
atom_command!(FileBrowserCommand: |state: SamplerTui| {
|
atom_command!(FileBrowserCommand: |state: SamplerTui| {
|
||||||
("begin" [] Self::Begin)
|
("begin" [] Some(Self::Begin))
|
||||||
("cancel" [] Self::Cancel)
|
("cancel" [] Some(Self::Cancel))
|
||||||
("confirm" [] Self::Confirm)
|
("confirm" [] Some(Self::Confirm))
|
||||||
("select" [i: usize] Self::Select(i.expect("no index")))
|
("select" [i: usize] Some(Self::Select(i.expect("no index"))))
|
||||||
("chdir" [p: PathBuf] Self::Chdir(p.expect("no path")))
|
("chdir" [p: PathBuf] Some(Self::Chdir(p.expect("no path"))))
|
||||||
("filter" [f: Arc<str>] Self::Filter(f.expect("no filter")))
|
("filter" [f: Arc<str>] Some(Self::Filter(f.expect("no filter"))))
|
||||||
});
|
});
|
||||||
#[derive(Clone, Debug)] pub enum SamplerCommand {
|
#[derive(Clone, Debug)] pub enum SamplerCommand {
|
||||||
RecordBegin(u7),
|
RecordBegin(u7),
|
||||||
|
|
@ -697,21 +688,21 @@ atom_command!(FileBrowserCommand: |state: SamplerTui| {
|
||||||
}
|
}
|
||||||
atom_command!(SamplerCommand: |state: Sampler| {
|
atom_command!(SamplerCommand: |state: Sampler| {
|
||||||
("record/begin" [i: u7]
|
("record/begin" [i: u7]
|
||||||
Self::RecordBegin(i.expect("no index")))
|
Some(Self::RecordBegin(i.expect("no index"))))
|
||||||
("record/cancel" []
|
("record/cancel" []
|
||||||
Self::RecordCancel)
|
Some(Self::RecordCancel))
|
||||||
("record/finish" []
|
("record/finish" []
|
||||||
Self::RecordFinish)
|
Some(Self::RecordFinish))
|
||||||
("set/sample" [i: u7, s: Option<Arc<RwLock<Sample>>>]
|
("set/sample" [i: u7, s: Option<Arc<RwLock<Sample>>>]
|
||||||
Self::SetSample(i.expect("no index"), s.expect("no sampler")))
|
Some(Self::SetSample(i.expect("no index"), s.expect("no sampler"))))
|
||||||
("set/start" [i: u7, s: usize]
|
("set/start" [i: u7, s: usize]
|
||||||
Self::SetStart(i.expect("no index"), s.expect("no start")))
|
Some(Self::SetStart(i.expect("no index"), s.expect("no start"))))
|
||||||
("set/gain" [i: u7, g: f32]
|
("set/gain" [i: u7, g: f32]
|
||||||
Self::SetGain(i.expect("no index"), g.expect("no garin")))
|
Some(Self::SetGain(i.expect("no index"), g.expect("no garin"))))
|
||||||
("note/on" [p: u7, v: u7]
|
("note/on" [p: u7, v: u7]
|
||||||
Self::NoteOn(p.expect("no pitch"), v.expect("no velocity")))
|
Some(Self::NoteOn(p.expect("no pitch"), v.expect("no velocity"))))
|
||||||
("note/off" [p: u7]
|
("note/off" [p: u7]
|
||||||
Self::NoteOff(p.expect("no pitch")))
|
Some(Self::NoteOff(p.expect("no pitch"))))
|
||||||
});
|
});
|
||||||
provide!(u7: |self: Sampler| {});
|
provide!(u7: |self: Sampler| {});
|
||||||
provide!(Option<Arc<RwLock<Sample>>>: |self: Sampler| {});
|
provide!(Option<Arc<RwLock<Sample>>>: |self: Sampler| {});
|
||||||
|
|
|
||||||
|
|
@ -7,3 +7,5 @@
|
||||||
(@t select :track 0)
|
(@t select :track 0)
|
||||||
(@tab edit :clip)
|
(@tab edit :clip)
|
||||||
(@c color)
|
(@c color)
|
||||||
|
(@shift-I input add)
|
||||||
|
(@shift-O output add)
|
||||||
|
|
|
||||||
127
tek/src/keys.rs
127
tek/src/keys.rs
|
|
@ -38,6 +38,8 @@ handle!(TuiIn: |self: Tek, input|Ok({
|
||||||
Editor(MidiEditCommand),
|
Editor(MidiEditCommand),
|
||||||
Enqueue(Option<Arc<RwLock<MidiClip>>>),
|
Enqueue(Option<Arc<RwLock<MidiClip>>>),
|
||||||
History(isize),
|
History(isize),
|
||||||
|
Input(InputCommand),
|
||||||
|
Output(OutputCommand),
|
||||||
Pool(PoolCommand),
|
Pool(PoolCommand),
|
||||||
Sampler(SamplerCommand),
|
Sampler(SamplerCommand),
|
||||||
Scene(SceneCommand),
|
Scene(SceneCommand),
|
||||||
|
|
@ -47,34 +49,29 @@ handle!(TuiIn: |self: Tek, input|Ok({
|
||||||
Zoom(Option<usize>),
|
Zoom(Option<usize>),
|
||||||
}
|
}
|
||||||
atom_command!(TekCommand: |app: Tek| {
|
atom_command!(TekCommand: |app: Tek| {
|
||||||
("stop" [] Self::StopAll)
|
("stop" [] Some(Self::StopAll))
|
||||||
("undo" [d: usize] Self::History(-(d.unwrap_or(0)as isize)))
|
("undo" [d: usize] Some(Self::History(-(d.unwrap_or(0)as isize))))
|
||||||
("redo" [d: usize] Self::History(d.unwrap_or(0) as isize))
|
("redo" [d: usize] Some(Self::History(d.unwrap_or(0) as isize)))
|
||||||
("zoom" [z: usize] Self::Zoom(z))
|
("zoom" [z: usize] Some(Self::Zoom(z)))
|
||||||
("edit" [] Self::Edit(None))
|
("edit" [] Some(Self::Edit(None)))
|
||||||
("edit" [c: bool] Self::Edit(c))
|
("edit" [c: bool] Some(Self::Edit(c)))
|
||||||
("color" [c: Color] Self::Color(c.map(ItemPalette::from).unwrap_or_default()))
|
("color" [c: Color] Some(Self::Color(c.map(ItemPalette::from).unwrap_or_default())))
|
||||||
("enqueue" [c: Arc<RwLock<MidiClip>>] Self::Enqueue(c))
|
("enqueue" [c: Arc<RwLock<MidiClip>>] Some(Self::Enqueue(c)))
|
||||||
("select" [t: usize, s: usize] match (t.expect("no track"), s.expect("no scene")) {
|
("clip" [,..a] ClipCommand::try_from_expr(app, a).map(Self::Clip))
|
||||||
|
("clock" [,..a] ClockCommand::try_from_expr(app.clock(), a).map(Self::Clock))
|
||||||
|
("editor" [,..a] MidiEditCommand::try_from_expr(app.editor.as_ref().expect("no editor"), a).map(Self::Editor))
|
||||||
|
("pool" [,..a] PoolCommand::try_from_expr(app.pool.as_ref().expect("no pool"), a).map(Self::Pool))
|
||||||
|
//("sampler" [,..a] Self::Sampler( //SamplerCommand::try_from_expr(app.sampler().as_ref().expect("no sampler"), a).expect("invalid command")))
|
||||||
|
("scene" [,..a] SceneCommand::try_from_expr(app, a).map(Self::Scene))
|
||||||
|
("track" [,..a] TrackCommand::try_from_expr(app, a).map(Self::Track))
|
||||||
|
("input" [,..a] InputCommand::try_from_expr(app, a).map(Self::Input))
|
||||||
|
("output" [,..a] OutputCommand::try_from_expr(app, a).map(Self::Output))
|
||||||
|
("select" [t: usize, s: usize] Some(match (t.expect("no track"), s.expect("no scene")) {
|
||||||
(0, 0) => Self::Select(Selection::Mix),
|
(0, 0) => Self::Select(Selection::Mix),
|
||||||
(t, 0) => Self::Select(Selection::Track(t)),
|
(t, 0) => Self::Select(Selection::Track(t)),
|
||||||
(0, s) => Self::Select(Selection::Scene(s)),
|
(0, s) => Self::Select(Selection::Scene(s)),
|
||||||
(t, s) => Self::Select(Selection::Clip(t, s)),
|
(t, s) => Self::Select(Selection::Clip(t, s)),
|
||||||
})
|
}))
|
||||||
("clip" [,..a] Self::Clip(
|
|
||||||
ClipCommand::try_from_expr(app, a).expect("invalid command: {a:?}")))
|
|
||||||
("clock" [,..a] Self::Clock(
|
|
||||||
ClockCommand::try_from_expr(app.clock(), a).expect("invalid command")))
|
|
||||||
("editor" [,..a] Self::Editor(
|
|
||||||
MidiEditCommand::try_from_expr(app.editor.as_ref().expect("no editor"), a).expect("invalid command")))
|
|
||||||
("pool" [,..a] Self::Pool(
|
|
||||||
PoolCommand::try_from_expr(app.pool.as_ref().expect("no pool"), a).expect("invalid command")))
|
|
||||||
//("sampler" [,..a] Self::Sampler(
|
|
||||||
//SamplerCommand::try_from_expr(app.sampler().as_ref().expect("no sampler"), a).expect("invalid command")))
|
|
||||||
("scene" [,..a] Self::Scene(
|
|
||||||
SceneCommand::try_from_expr(app, a).expect("invalid command")))
|
|
||||||
("track" [,..a] Self::Track(
|
|
||||||
TrackCommand::try_from_expr(app, a).expect("invalid command")))
|
|
||||||
});
|
});
|
||||||
command!(|self: TekCommand, app: Tek|match self {
|
command!(|self: TekCommand, app: Tek|match self {
|
||||||
Self::Zoom(_) => { println!("\n\rtodo: global zoom"); None },
|
Self::Zoom(_) => { println!("\n\rtodo: global zoom"); None },
|
||||||
|
|
@ -127,10 +124,12 @@ command!(|self: TekCommand, app: Tek|match self {
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
Self::Clock(cmd) => cmd.delegate(app, Self::Clock)?,
|
Self::Clock(cmd) => cmd.delegate(app, Self::Clock)?,
|
||||||
Self::Scene(cmd) => cmd.delegate(app, Self::Scene)?,
|
Self::Scene(cmd) => cmd.delegate(app, Self::Scene)?,
|
||||||
Self::Track(cmd) => cmd.delegate(app, Self::Track)?,
|
Self::Track(cmd) => cmd.delegate(app, Self::Track)?,
|
||||||
Self::Clip(cmd) => cmd.delegate(app, Self::Clip)?,
|
Self::Input(cmd) => cmd.delegate(app, Self::Input)?,
|
||||||
|
Self::Output(cmd) => cmd.delegate(app, Self::Output)?,
|
||||||
|
Self::Clip(cmd) => cmd.delegate(app, Self::Clip)?,
|
||||||
Self::Editor(cmd) => app.editor.as_mut()
|
Self::Editor(cmd) => app.editor.as_mut()
|
||||||
.map(|editor|cmd.delegate(editor, Self::Editor)).transpose()?.flatten(),
|
.map(|editor|cmd.delegate(editor, Self::Editor)).transpose()?.flatten(),
|
||||||
//Self::Sampler(cmd) => app.sampler.as_mut()
|
//Self::Sampler(cmd) => app.sampler.as_mut()
|
||||||
|
|
@ -192,6 +191,26 @@ command!(|self: TekCommand, app: Tek|match self {
|
||||||
},
|
},
|
||||||
_ => todo!("{self:?}")
|
_ => todo!("{self:?}")
|
||||||
});
|
});
|
||||||
|
#[derive(Clone, Debug)] pub enum InputCommand { Add }
|
||||||
|
atom_command!(InputCommand: |app: Tek| {
|
||||||
|
("add" [] Some(Self::Add))
|
||||||
|
});
|
||||||
|
command!(|self: InputCommand, app: Tek|match self {
|
||||||
|
Self::Add => {
|
||||||
|
app.midi_ins.push(JackMidiIn::new(&app.jack, &format!("M/{}", app.midi_ins.len()), &[])?);
|
||||||
|
None
|
||||||
|
},
|
||||||
|
});
|
||||||
|
#[derive(Clone, Debug)] pub enum OutputCommand { Add }
|
||||||
|
atom_command!(OutputCommand: |app: Tek| {
|
||||||
|
("add" [] Some(Self::Add))
|
||||||
|
});
|
||||||
|
command!(|self: OutputCommand, app: Tek|match self {
|
||||||
|
Self::Add => {
|
||||||
|
app.midi_outs.push(JackMidiOut::new(&app.jack, &format!("{}/M", app.midi_outs.len()), &[])?);
|
||||||
|
None
|
||||||
|
},
|
||||||
|
});
|
||||||
#[derive(Clone, Debug)] pub enum TrackCommand {
|
#[derive(Clone, Debug)] pub enum TrackCommand {
|
||||||
Add,
|
Add,
|
||||||
Del(usize),
|
Del(usize),
|
||||||
|
|
@ -206,17 +225,17 @@ command!(|self: TekCommand, app: Tek|match self {
|
||||||
ToggleMonitor,
|
ToggleMonitor,
|
||||||
}
|
}
|
||||||
atom_command!(TrackCommand: |app: Tek| {
|
atom_command!(TrackCommand: |app: Tek| {
|
||||||
("add" [] Self::Add)
|
("add" [] Some(Self::Add))
|
||||||
("size" [a: usize] Self::SetSize(a.unwrap()))
|
("size" [a: usize] Some(Self::SetSize(a.unwrap())))
|
||||||
("zoom" [a: usize] Self::SetZoom(a.unwrap()))
|
("zoom" [a: usize] Some(Self::SetZoom(a.unwrap())))
|
||||||
("color" [a: usize] Self::SetColor(a.unwrap().saturating_sub(1), ItemPalette::random()))
|
("color" [a: usize] Some(Self::SetColor(a.unwrap().saturating_sub(1), ItemPalette::random())))
|
||||||
("del" [a: usize] Self::Del(a.unwrap().saturating_sub(1)))
|
("del" [a: usize] Some(Self::Del(a.unwrap().saturating_sub(1))))
|
||||||
("stop" [a: usize] Self::Stop(a.unwrap().saturating_sub(1)))
|
("stop" [a: usize] Some(Self::Stop(a.unwrap().saturating_sub(1))))
|
||||||
("swap" [a: usize, b: usize] Self::Swap(a.unwrap(), b.unwrap()))
|
("swap" [a: usize, b: usize] Some(Self::Swap(a.unwrap(), b.unwrap())))
|
||||||
("play" [] Self::TogglePlay)
|
("play" [] Some(Self::TogglePlay))
|
||||||
("solo" [] Self::ToggleSolo)
|
("solo" [] Some(Self::ToggleSolo))
|
||||||
("rec" [] Self::ToggleRecord)
|
("rec" [] Some(Self::ToggleRecord))
|
||||||
("mon" [] Self::ToggleMonitor)
|
("mon" [] Some(Self::ToggleMonitor))
|
||||||
});
|
});
|
||||||
command!(|self: TrackCommand, app: Tek|match self {
|
command!(|self: TrackCommand, app: Tek|match self {
|
||||||
Self::Add => {
|
Self::Add => {
|
||||||
|
|
@ -266,12 +285,12 @@ command!(|self: TrackCommand, app: Tek|match self {
|
||||||
Enqueue(usize),
|
Enqueue(usize),
|
||||||
}
|
}
|
||||||
atom_command!(SceneCommand: |app: Tek| {
|
atom_command!(SceneCommand: |app: Tek| {
|
||||||
("add" [] Self::Add)
|
("add" [] Some(Self::Add))
|
||||||
("del" [a: usize] Self::Del(0))
|
("del" [a: usize] Some(Self::Del(0)))
|
||||||
("zoom" [a: usize] Self::SetZoom(a.unwrap()))
|
("zoom" [a: usize] Some(Self::SetZoom(a.unwrap())))
|
||||||
("color" [a: usize] Self::SetColor(a.unwrap().saturating_sub(1), ItemPalette::random()))
|
("color" [a: usize] Some(Self::SetColor(a.unwrap().saturating_sub(1), ItemPalette::random())))
|
||||||
("enqueue" [a: usize] Self::Enqueue(a.unwrap().saturating_sub(1)))
|
("enqueue" [a: usize] Some(Self::Enqueue(a.unwrap().saturating_sub(1))))
|
||||||
("swap" [a: usize, b: usize] Self::Swap(a.unwrap(), b.unwrap()))
|
("swap" [a: usize, b: usize] Some(Self::Swap(a.unwrap(), b.unwrap())))
|
||||||
});
|
});
|
||||||
command!(|self: SceneCommand, app: Tek|match self {
|
command!(|self: SceneCommand, app: Tek|match self {
|
||||||
Self::Add => {
|
Self::Add => {
|
||||||
|
|
@ -307,18 +326,12 @@ command!(|self: SceneCommand, app: Tek|match self {
|
||||||
SetColor(usize, usize, ItemPalette),
|
SetColor(usize, usize, ItemPalette),
|
||||||
}
|
}
|
||||||
atom_command!(ClipCommand: |app: Tek| {
|
atom_command!(ClipCommand: |app: Tek| {
|
||||||
("get" [a: usize ,b: usize]
|
("get" [a: usize ,b: usize] Some(Self::Get(a.unwrap().saturating_sub(1), b.unwrap().saturating_sub(1))))
|
||||||
Self::Get(a.unwrap().saturating_sub(1), b.unwrap().saturating_sub(1)))
|
("put" [a: usize, b: usize, c: Option<Arc<RwLock<MidiClip>>>] Some(Self::Put(a.unwrap().saturating_sub(1), b.unwrap().saturating_sub(1), c.unwrap())))
|
||||||
("put" [a: usize, b: usize, c: Option<Arc<RwLock<MidiClip>>>]
|
("enqueue" [a: usize, b: usize] Some(Self::Enqueue(a.unwrap().saturating_sub(1), b.unwrap().saturating_sub(1))))
|
||||||
Self::Put(a.unwrap().saturating_sub(1), b.unwrap().saturating_sub(1), c.unwrap()))
|
("edit" [a: Option<Arc<RwLock<MidiClip>>>] Some(Self::Edit(a.unwrap())))
|
||||||
("enqueue" [a: usize, b: usize]
|
("loop" [a: usize, b: usize, c: bool] Some(Self::SetLoop(a.unwrap().saturating_sub(1), b.unwrap().saturating_sub(1), c.unwrap())))
|
||||||
Self::Enqueue(a.unwrap().saturating_sub(1), b.unwrap().saturating_sub(1)))
|
("color" [a: usize, b: usize] Some(Self::SetColor(a.unwrap().saturating_sub(1), b.unwrap().saturating_sub(1), ItemPalette::random())))
|
||||||
("edit" [a: Option<Arc<RwLock<MidiClip>>>]
|
|
||||||
Self::Edit(a.unwrap()))
|
|
||||||
("loop" [a: usize, b: usize, c: bool]
|
|
||||||
Self::SetLoop(a.unwrap().saturating_sub(1), b.unwrap().saturating_sub(1), c.unwrap()))
|
|
||||||
("color" [a: usize, b: usize]
|
|
||||||
Self::SetColor(a.unwrap().saturating_sub(1), b.unwrap().saturating_sub(1), ItemPalette::random()))
|
|
||||||
});
|
});
|
||||||
command!(|self: ClipCommand, app: Tek|match self {
|
command!(|self: ClipCommand, app: Tek|match self {
|
||||||
Self::Get(track, scene) => { todo!() },
|
Self::Get(track, scene) => { todo!() },
|
||||||
|
|
|
||||||
|
|
@ -128,15 +128,6 @@ impl Tek {
|
||||||
name,
|
name,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
//let midi_in = JackMidiIn::new(&self.jack, &format!("{}I", &track.name), midi_from)?;
|
|
||||||
//midi_in.connect_to_matching()?;
|
|
||||||
//track.player.midi_ins.push(midi_in);
|
|
||||||
|
|
||||||
//let midi_out = JackMidiOut::new(&self.jack, &format!("{}O", &track.name), midi_to)?;
|
|
||||||
//midi_out.connect_to_matching()?;
|
|
||||||
//track.player.midi_outs.push(midi_out);
|
|
||||||
|
|
||||||
self.tracks_mut().push(track);
|
self.tracks_mut().push(track);
|
||||||
let len = self.tracks().len();
|
let len = self.tracks().len();
|
||||||
let index = len - 1;
|
let index = len - 1;
|
||||||
|
|
|
||||||
|
|
@ -197,15 +197,10 @@ impl Tek {
|
||||||
let conn = move|conn: &PortConnect|{
|
let conn = move|conn: &PortConnect|{
|
||||||
Fill::x(Align::w(Tui::bold(false, Tui::fg_bg(fg, bg, conn.info()))))
|
Fill::x(Align::w(Tui::bold(false, Tui::fg_bg(fg, bg, conn.info()))))
|
||||||
};
|
};
|
||||||
let header: ThunkBox<_> = io_header!(
|
let header: ThunkBox<_> = io_header!(self, " I ", " midi ins", self.midi_ins.len(),
|
||||||
self,
|
Map::new(||self.midi_ins.iter(), move|input, index|map_south(index as u16, 1u16, Bsp::s(
|
||||||
" I ",
|
|
||||||
" midi ins",
|
|
||||||
self.midi_ins.len(),
|
|
||||||
self.midi_ins().get(0).map(move|input: &JackMidiIn|Bsp::s(
|
|
||||||
Fill::x(Tui::bold(true, Tui::fg_bg(fg, bg, Align::w(input.name())))),
|
Fill::x(Tui::bold(true, Tui::fg_bg(fg, bg, Align::w(input.name())))),
|
||||||
input.conn().get(0).map(conn)
|
input.conn().get(0).map(conn)))));
|
||||||
)));
|
|
||||||
let cells: ThunkBox<_> = per_track!(self.size.w();|self, track, t|{
|
let cells: ThunkBox<_> = per_track!(self.size.w();|self, track, t|{
|
||||||
let rec = track.player.recording;
|
let rec = track.player.recording;
|
||||||
let mon = track.player.monitoring;
|
let mon = track.player.monitoring;
|
||||||
|
|
@ -229,15 +224,11 @@ impl Tek {
|
||||||
let bg = Tui::g(64);
|
let bg = Tui::g(64);
|
||||||
let mut h = 2.max(1 + self.midi_outs.len());
|
let mut h = 2.max(1 + self.midi_outs.len());
|
||||||
for midi_out in self.midi_outs.iter() { h += midi_out.conn().len() }
|
for midi_out in self.midi_outs.iter() { h += midi_out.conn().len() }
|
||||||
let header: ThunkBox<_> = io_header!(
|
let header: ThunkBox<_> = io_header!(self, " O ", " midi outs", self.midi_outs.len(),
|
||||||
self,
|
Map::new(||self.midi_outs.iter(), move|output, index|map_south(index as u16, 1u16, Bsp::s(
|
||||||
" O ",
|
|
||||||
" midi outs",
|
|
||||||
self.midi_outs.len(),
|
|
||||||
self.midi_outs().get(0).map(move|output: &JackMidiOut|Bsp::s(
|
|
||||||
Fill::x(Tui::bold(true, Tui::fg_bg(fg, bg, Align::w(output.name())))),
|
Fill::x(Tui::bold(true, Tui::fg_bg(fg, bg, Align::w(output.name())))),
|
||||||
output.conn().get(0).map(|connect|Fill::x(Align::w(Tui::bold(false,
|
output.conn().get(0).map(|connect|Fill::x(Align::w(Tui::bold(false,
|
||||||
Tui::fg_bg(fg, bg, connect.info()))))))));
|
Tui::fg_bg(fg, bg, connect.info())))))))));
|
||||||
let mute = false;
|
let mute = false;
|
||||||
let solo = false;
|
let solo = false;
|
||||||
let cells: ThunkBox<_> = per_track!(self.size.w();|self, track, t|{
|
let cells: ThunkBox<_> = per_track!(self.size.w();|self, track, t|{
|
||||||
|
|
|
||||||
|
|
@ -25,18 +25,18 @@ pub enum ClockCommand {
|
||||||
provide_num!(u32: |self: Clock| {});
|
provide_num!(u32: |self: Clock| {});
|
||||||
provide!(f64: |self: Clock| {});
|
provide!(f64: |self: Clock| {});
|
||||||
atom_command!(ClockCommand: |state: Clock| {
|
atom_command!(ClockCommand: |state: Clock| {
|
||||||
("play" [] Self::Play(None))
|
("play" [] Some(Self::Play(None)))
|
||||||
("play" [t: u32] Self::Play(t))
|
("play" [t: u32] Some(Self::Play(t)))
|
||||||
("pause" [] Self::Pause(None))
|
("pause" [] Some(Self::Pause(None)))
|
||||||
("pause" [t: u32] Self::Pause(t))
|
("pause" [t: u32] Some(Self::Pause(t)))
|
||||||
("toggle" [] if state.is_rolling() { Self::Pause(None) } else { Self::Play(None) })
|
("toggle" [] Some(if state.is_rolling() { Self::Pause(None) } else { Self::Play(None) }))
|
||||||
("toggle" [t: u32] if state.is_rolling() { Self::Pause(t) } else { Self::Play(t) })
|
("toggle" [t: u32] Some(if state.is_rolling() { Self::Pause(t) } else { Self::Play(t) }))
|
||||||
("seek/usec" [t: f64] Self::SeekUsec(t.expect("no usec")))
|
("seek/usec" [t: f64] Some(Self::SeekUsec(t.expect("no usec"))))
|
||||||
("seek/pulse" [t: f64] Self::SeekPulse(t.expect("no pulse")))
|
("seek/pulse" [t: f64] Some(Self::SeekPulse(t.expect("no pulse"))))
|
||||||
("seek/sample" [t: f64] Self::SeekSample(t.expect("no sample")))
|
("seek/sample" [t: f64] Some(Self::SeekSample(t.expect("no sample"))))
|
||||||
("set/bpm" [t: f64] Self::SetBpm(t.expect("no bpm")))
|
("set/bpm" [t: f64] Some(Self::SetBpm(t.expect("no bpm"))))
|
||||||
("set/sync" [t: f64] Self::SetSync(t.expect("no sync")))
|
("set/sync" [t: f64] Some(Self::SetSync(t.expect("no sync"))))
|
||||||
("set/quant" [t: f64] Self::SetQuant(t.expect("no quant")))
|
("set/quant" [t: f64] Some(Self::SetQuant(t.expect("no quant"))))
|
||||||
});
|
});
|
||||||
impl<T: HasClock> Command<T> for ClockCommand {
|
impl<T: HasClock> Command<T> for ClockCommand {
|
||||||
fn execute (self, state: &mut T) -> Perhaps<Self> {
|
fn execute (self, state: &mut T) -> Perhaps<Self> {
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ handle!(TuiIn: |self: Example, input|{
|
||||||
});
|
});
|
||||||
enum ExampleCommand { Next, Previous }
|
enum ExampleCommand { Next, Previous }
|
||||||
atom_command!(ExampleCommand: |app: Example| {
|
atom_command!(ExampleCommand: |app: Example| {
|
||||||
(":prev" [] Self::Previous)
|
(":prev" [] Some(Self::Previous))
|
||||||
(":next" [] Self::Next)
|
(":next" [] Some(Self::Next))
|
||||||
});
|
});
|
||||||
command!(|self: ExampleCommand, state: Example|match self {
|
command!(|self: ExampleCommand, state: Example|match self {
|
||||||
Self::Next =>
|
Self::Next =>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue