diff --git a/edn/src/iter.rs b/edn/src/iter.rs index 4c792ddd..ac634a91 100644 --- a/edn/src/iter.rs +++ b/edn/src/iter.rs @@ -70,7 +70,7 @@ pub const fn peek_src <'a> (source: &'a str) -> Option> { _ => token.error(Unexpected(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), _ => token.error(Unexpected(c)) }, diff --git a/input/src/command.rs b/input/src/command.rs index dc53c637..23b24640 100644 --- a/input/src/command.rs +++ b/input/src/command.rs @@ -16,3 +16,13 @@ pub trait Command: Send + Sync + Sized { Ok(self.execute(state)?.map(wrap)) } } +impl> Command for Option { + fn execute (self, _: &mut S) -> Perhaps { + Ok(None) + } + fn delegate (self, _: &mut S, _: impl Fn(Self)->U) -> Perhaps + where Self: Sized + { + Ok(None) + } +} diff --git a/input/src/keymap.rs b/input/src/keymap.rs index fca114b9..73b063ea 100644 --- a/input/src/keymap.rs +++ b/input/src/keymap.rs @@ -100,7 +100,7 @@ impl<'a, C, T: TryFromAtom<'a, C> + Command> AtomCommand<'a, C> for T {} $(let $arg: Option<$type> = Context::<$type>::get($state, &$arg.value);)? )* $(let $rest = iter.clone();)? - return Some($command) + return $command },)* _ => None } @@ -142,7 +142,7 @@ impl<'a, C, T: TryFromAtom<'a, C> + Command> AtomCommand<'a, C> for T {} $(let $arg: Option<$type> = Context::<$type>::get($state, &$arg.value);)? )* $(let $rest = iter.clone();)? - return Some($command) + return $command }),* _ => None } diff --git a/midi/src/midi_edit.rs b/midi/src/midi_edit.rs index 5f5a7239..5e3b6679 100644 --- a/midi/src/midi_edit.rs +++ b/midi/src/midi_edit.rs @@ -184,15 +184,15 @@ impl MidiViewer for MidiEditor { fn set_clip (&mut self, p: Option<&Arc>>) { self.mode.set_clip(p) } } atom_command!(MidiEditCommand: |state: MidiEditor| { - ("note/append" [] Self::AppendNote) - ("note/put" [] Self::PutNote) - ("note/del" [] Self::DelNote) - ("note/pos" [a: usize] Self::SetNoteCursor(a.expect("no note cursor"))) - ("note/len" [a: usize] Self::SetNoteLength(a.expect("no note length"))) - ("time/pos" [a: usize] Self::SetTimeCursor(a.expect("no time cursor"))) - ("time/zoom" [a: usize] Self::SetTimeZoom(a.expect("no time zoom"))) - ("time/lock" [a: bool] Self::SetTimeLock(a.expect("no time lock"))) - ("time/lock" [] Self::SetTimeLock(!state.time_lock().get())) + ("note/append" [] Some(Self::AppendNote)) + ("note/put" [] Some(Self::PutNote)) + ("note/del" [] Some(Self::DelNote)) + ("note/pos" [a: usize] Some(Self::SetNoteCursor(a.expect("no note cursor")))) + ("note/len" [a: usize] Some(Self::SetNoteLength(a.expect("no note length")))) + ("time/pos" [a: usize] Some(Self::SetTimeCursor(a.expect("no time cursor")))) + ("time/zoom" [a: usize] Some(Self::SetTimeZoom(a.expect("no time zoom")))) + ("time/lock" [a: bool] Some(Self::SetTimeLock(a.expect("no time lock")))) + ("time/lock" [] Some(Self::SetTimeLock(!state.time_lock().get()))) }); #[derive(Clone, Debug)] pub enum MidiEditCommand { // TODO: 1-9 seek markers that by default start every 8th of the clip diff --git a/midi/src/midi_pool.rs b/midi/src/midi_pool.rs index eae4101c..959b94c2 100644 --- a/midi/src/midi_pool.rs +++ b/midi/src/midi_pool.rs @@ -265,13 +265,13 @@ provide!(ItemColor: |self: MidiPool| { Clip(PoolClipCommand), } atom_command!(PoolCommand: |state: MidiPool| { - ("show" [a: bool] Self::Show(a.expect("no flag"))) - ("select" [i: usize] Self::Select(i.expect("no index"))) - ("rename" [,..a] ClipRenameCommand::try_from_expr(state, a).map(Self::Rename).expect("invalid command")) - ("length" [,..a] ClipLengthCommand::try_from_expr(state, a).map(Self::Length).expect("invalid command")) - ("import" [,..a] FileBrowserCommand::try_from_expr(state, a).map(Self::Import).expect("invalid command")) - ("export" [,..a] FileBrowserCommand::try_from_expr(state, a).map(Self::Export).expect("invalid command")) - ("clip" [,..a] PoolClipCommand::try_from_expr(state, a).map(Self::Clip).expect("invalid command")) + ("show" [a: bool] Some(Self::Show(a.expect("no flag")))) + ("select" [i: usize] Some(Self::Select(i.expect("no index")))) + ("rename" [,..a] ClipRenameCommand::try_from_expr(state, a).map(Self::Rename)) + ("length" [,..a] ClipLengthCommand::try_from_expr(state, a).map(Self::Length)) + ("import" [,..a] FileBrowserCommand::try_from_expr(state, a).map(Self::Import)) + ("export" [,..a] FileBrowserCommand::try_from_expr(state, a).map(Self::Export)) + ("clip" [,..a] PoolClipCommand::try_from_expr(state, a).map(Self::Clip)) }); command!(|self: PoolCommand, state: MidiPool|{ use PoolCommand::*; @@ -300,14 +300,22 @@ command!(|self: PoolCommand, state: MidiPool|{ SetColor(usize, ItemColor), } atom_command!(PoolClipCommand: |state: MidiPool| { - ("add" [i: usize, c: MidiClip] Self::Add(i.expect("no index"), c.expect("no clip"))) - ("delete" [i: usize] Self::Delete(i.expect("no index"))) - ("swap" [a: usize, b: usize] Self::Swap(a.expect("no index"), b.expect("no index"))) - ("import" [i: usize, p: PathBuf] Self::Import(i.expect("no index"), p.expect("no path"))) - ("export" [i: usize, p: PathBuf] Self::Export(i.expect("no index"), p.expect("no path"))) - ("set-name" [i: usize, n: Arc] Self::SetName(i.expect("no index"), n.expect("no name"))) - ("set-length" [i: usize, l: usize] Self::SetLength(i.expect("no index"), l.expect("no length"))) - ("set-color" [i: usize, c: ItemColor] Self::SetColor(i.expect("no index"), c.expect("no color"))) + ("add" [i: usize, c: MidiClip] + Some(Self::Add(i.expect("no index"), c.expect("no clip")))) + ("delete" [i: usize] + Some(Self::Delete(i.expect("no index")))) + ("swap" [a: usize, b: usize] + Some(Self::Swap(a.expect("no index"), b.expect("no index")))) + ("import" [i: usize, p: PathBuf] + 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] + 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 Command for PoolClipCommand { fn execute (self, model: &mut T) -> Perhaps { @@ -381,10 +389,10 @@ impl Command for PoolClipCommand { Set(Arc), } atom_command!(ClipRenameCommand: |state: MidiPool| { - ("begin" [] Self::Begin) - ("cancel" [] Self::Cancel) - ("confirm" [] Self::Confirm) - ("set" [n: Arc] Self::Set(n.expect("no name"))) + ("begin" [] Some(Self::Begin)) + ("cancel" [] Some(Self::Cancel)) + ("confirm" [] Some(Self::Confirm)) + ("set" [n: Arc] Some(Self::Set(n.expect("no name")))) }); command!(|self: ClipRenameCommand, state: MidiPool|{ use ClipRenameCommand::*; @@ -421,13 +429,13 @@ command!(|self: ClipRenameCommand, state: MidiPool|{ Dec, } atom_command!(ClipLengthCommand: |state: MidiPool| { - ("begin" [] Self::Begin) - ("cancel" [] Self::Cancel) - ("next" [] Self::Next) - ("prev" [] Self::Prev) - ("inc" [] Self::Inc) - ("dec" [] Self::Dec) - ("set" [l: usize] Self::Set(l.expect("no length"))) + ("begin" [] Some(Self::Begin)) + ("cancel" [] Some(Self::Cancel)) + ("next" [] Some(Self::Next)) + ("prev" [] Some(Self::Prev)) + ("inc" [] Some(Self::Inc)) + ("dec" [] Some(Self::Dec)) + ("set" [l: usize] Some(Self::Set(l.expect("no length")))) }); command!(|self: ClipLengthCommand, state: MidiPool|{ use ClipLengthCommand::*; @@ -467,12 +475,12 @@ command!(|self: ClipLengthCommand, state: MidiPool|{ None }); atom_command!(FileBrowserCommand: |state: MidiPool| { - ("begin" [] Self::Begin) - ("cancel" [] Self::Cancel) - ("confirm" [] Self::Confirm) - ("select" [i: usize] Self::Select(i.expect("no index"))) - ("chdir" [p: PathBuf] Self::Chdir(p.expect("no path"))) - ("filter" [f: Arc] Self::Filter(f.expect("no filter"))) + ("begin" [] Some(Self::Begin)) + ("cancel" [] Some(Self::Cancel)) + ("confirm" [] Some(Self::Confirm)) + ("select" [i: usize] Some(Self::Select(i.expect("no index")))) + ("chdir" [p: PathBuf] Some(Self::Chdir(p.expect("no path")))) + ("filter" [f: Arc] Some(Self::Filter(f.expect("no filter")))) }); command!(|self: FileBrowserCommand, state: MidiPool|{ use PoolMode::*; diff --git a/sampler/src/sampler.rs b/sampler/src/sampler.rs index c0933191..b37853a7 100644 --- a/sampler/src/sampler.rs +++ b/sampler/src/sampler.rs @@ -662,28 +662,19 @@ pub enum SamplerMode { Sample(SamplerCommand), } atom_command!(SamplerTuiCommand: |state: SamplerTui| { - ("select" [i: usize] Self::Select(i.expect("no index"))) - ("import" [,..a] if let Some(command) = FileBrowserCommand::try_from_expr(state, a) { - Self::Import(command) - } else { - return None - }) - ("sample" [,..a] if let Some(command) = SamplerCommand::try_from_expr(&state.state, a) { - Self::Sample(command) - } else { - return None - }) -}); + ("select" [i: usize] Some(Self::Select(i.expect("no index")))) + ("import" [,..a] FileBrowserCommand::try_from_expr(state, a).map(Self::Import)) + ("sample" [,..a] SamplerCommand::try_from_expr(&state.state, a).map(Self::Sample)) }); provide!(usize: |self: SamplerTui| {}); provide!(PathBuf: |self: SamplerTui| {}); provide!(Arc: |self: SamplerTui| {}); atom_command!(FileBrowserCommand: |state: SamplerTui| { - ("begin" [] Self::Begin) - ("cancel" [] Self::Cancel) - ("confirm" [] Self::Confirm) - ("select" [i: usize] Self::Select(i.expect("no index"))) - ("chdir" [p: PathBuf] Self::Chdir(p.expect("no path"))) - ("filter" [f: Arc] Self::Filter(f.expect("no filter"))) + ("begin" [] Some(Self::Begin)) + ("cancel" [] Some(Self::Cancel)) + ("confirm" [] Some(Self::Confirm)) + ("select" [i: usize] Some(Self::Select(i.expect("no index")))) + ("chdir" [p: PathBuf] Some(Self::Chdir(p.expect("no path")))) + ("filter" [f: Arc] Some(Self::Filter(f.expect("no filter")))) }); #[derive(Clone, Debug)] pub enum SamplerCommand { RecordBegin(u7), @@ -697,21 +688,21 @@ atom_command!(FileBrowserCommand: |state: SamplerTui| { } atom_command!(SamplerCommand: |state: Sampler| { ("record/begin" [i: u7] - Self::RecordBegin(i.expect("no index"))) + Some(Self::RecordBegin(i.expect("no index")))) ("record/cancel" [] - Self::RecordCancel) + Some(Self::RecordCancel)) ("record/finish" [] - Self::RecordFinish) + Some(Self::RecordFinish)) ("set/sample" [i: u7, s: Option>>] - 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] - 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] - 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] - 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] - Self::NoteOff(p.expect("no pitch"))) + Some(Self::NoteOff(p.expect("no pitch")))) }); provide!(u7: |self: Sampler| {}); provide!(Option>>: |self: Sampler| {}); diff --git a/tek/src/keys.edn b/tek/src/keys.edn index 8c2a9924..11065f76 100644 --- a/tek/src/keys.edn +++ b/tek/src/keys.edn @@ -7,3 +7,5 @@ (@t select :track 0) (@tab edit :clip) (@c color) +(@shift-I input add) +(@shift-O output add) diff --git a/tek/src/keys.rs b/tek/src/keys.rs index b7c17942..956c3a55 100644 --- a/tek/src/keys.rs +++ b/tek/src/keys.rs @@ -38,6 +38,8 @@ handle!(TuiIn: |self: Tek, input|Ok({ Editor(MidiEditCommand), Enqueue(Option>>), History(isize), + Input(InputCommand), + Output(OutputCommand), Pool(PoolCommand), Sampler(SamplerCommand), Scene(SceneCommand), @@ -47,34 +49,29 @@ handle!(TuiIn: |self: Tek, input|Ok({ Zoom(Option), } atom_command!(TekCommand: |app: Tek| { - ("stop" [] Self::StopAll) - ("undo" [d: usize] Self::History(-(d.unwrap_or(0)as isize))) - ("redo" [d: usize] Self::History(d.unwrap_or(0) as isize)) - ("zoom" [z: usize] Self::Zoom(z)) - ("edit" [] Self::Edit(None)) - ("edit" [c: bool] Self::Edit(c)) - ("color" [c: Color] Self::Color(c.map(ItemPalette::from).unwrap_or_default())) - ("enqueue" [c: Arc>] Self::Enqueue(c)) - ("select" [t: usize, s: usize] match (t.expect("no track"), s.expect("no scene")) { + ("stop" [] Some(Self::StopAll)) + ("undo" [d: usize] Some(Self::History(-(d.unwrap_or(0)as isize)))) + ("redo" [d: usize] Some(Self::History(d.unwrap_or(0) as isize))) + ("zoom" [z: usize] Some(Self::Zoom(z))) + ("edit" [] Some(Self::Edit(None))) + ("edit" [c: bool] Some(Self::Edit(c))) + ("color" [c: Color] Some(Self::Color(c.map(ItemPalette::from).unwrap_or_default()))) + ("enqueue" [c: Arc>] Some(Self::Enqueue(c))) + ("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), (t, 0) => Self::Select(Selection::Track(t)), (0, s) => Self::Select(Selection::Scene(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 { Self::Zoom(_) => { println!("\n\rtodo: global zoom"); None }, @@ -127,10 +124,12 @@ command!(|self: TekCommand, app: Tek|match self { } None }, - Self::Clock(cmd) => cmd.delegate(app, Self::Clock)?, - Self::Scene(cmd) => cmd.delegate(app, Self::Scene)?, - Self::Track(cmd) => cmd.delegate(app, Self::Track)?, - Self::Clip(cmd) => cmd.delegate(app, Self::Clip)?, + Self::Clock(cmd) => cmd.delegate(app, Self::Clock)?, + Self::Scene(cmd) => cmd.delegate(app, Self::Scene)?, + Self::Track(cmd) => cmd.delegate(app, Self::Track)?, + 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() .map(|editor|cmd.delegate(editor, Self::Editor)).transpose()?.flatten(), //Self::Sampler(cmd) => app.sampler.as_mut() @@ -192,6 +191,26 @@ command!(|self: TekCommand, app: Tek|match 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 { Add, Del(usize), @@ -206,17 +225,17 @@ command!(|self: TekCommand, app: Tek|match self { ToggleMonitor, } atom_command!(TrackCommand: |app: Tek| { - ("add" [] Self::Add) - ("size" [a: usize] Self::SetSize(a.unwrap())) - ("zoom" [a: usize] Self::SetZoom(a.unwrap())) - ("color" [a: usize] Self::SetColor(a.unwrap().saturating_sub(1), ItemPalette::random())) - ("del" [a: usize] Self::Del(a.unwrap().saturating_sub(1))) - ("stop" [a: usize] Self::Stop(a.unwrap().saturating_sub(1))) - ("swap" [a: usize, b: usize] Self::Swap(a.unwrap(), b.unwrap())) - ("play" [] Self::TogglePlay) - ("solo" [] Self::ToggleSolo) - ("rec" [] Self::ToggleRecord) - ("mon" [] Self::ToggleMonitor) + ("add" [] Some(Self::Add)) + ("size" [a: usize] Some(Self::SetSize(a.unwrap()))) + ("zoom" [a: usize] Some(Self::SetZoom(a.unwrap()))) + ("color" [a: usize] Some(Self::SetColor(a.unwrap().saturating_sub(1), ItemPalette::random()))) + ("del" [a: usize] Some(Self::Del(a.unwrap().saturating_sub(1)))) + ("stop" [a: usize] Some(Self::Stop(a.unwrap().saturating_sub(1)))) + ("swap" [a: usize, b: usize] Some(Self::Swap(a.unwrap(), b.unwrap()))) + ("play" [] Some(Self::TogglePlay)) + ("solo" [] Some(Self::ToggleSolo)) + ("rec" [] Some(Self::ToggleRecord)) + ("mon" [] Some(Self::ToggleMonitor)) }); command!(|self: TrackCommand, app: Tek|match self { Self::Add => { @@ -266,12 +285,12 @@ command!(|self: TrackCommand, app: Tek|match self { Enqueue(usize), } atom_command!(SceneCommand: |app: Tek| { - ("add" [] Self::Add) - ("del" [a: usize] Self::Del(0)) - ("zoom" [a: usize] Self::SetZoom(a.unwrap())) - ("color" [a: usize] Self::SetColor(a.unwrap().saturating_sub(1), ItemPalette::random())) - ("enqueue" [a: usize] Self::Enqueue(a.unwrap().saturating_sub(1))) - ("swap" [a: usize, b: usize] Self::Swap(a.unwrap(), b.unwrap())) + ("add" [] Some(Self::Add)) + ("del" [a: usize] Some(Self::Del(0))) + ("zoom" [a: usize] Some(Self::SetZoom(a.unwrap()))) + ("color" [a: usize] Some(Self::SetColor(a.unwrap().saturating_sub(1), ItemPalette::random()))) + ("enqueue" [a: usize] Some(Self::Enqueue(a.unwrap().saturating_sub(1)))) + ("swap" [a: usize, b: usize] Some(Self::Swap(a.unwrap(), b.unwrap()))) }); command!(|self: SceneCommand, app: Tek|match self { Self::Add => { @@ -307,18 +326,12 @@ command!(|self: SceneCommand, app: Tek|match self { SetColor(usize, usize, ItemPalette), } atom_command!(ClipCommand: |app: Tek| { - ("get" [a: usize ,b: usize] - Self::Get(a.unwrap().saturating_sub(1), b.unwrap().saturating_sub(1))) - ("put" [a: usize, b: usize, c: Option>>] - Self::Put(a.unwrap().saturating_sub(1), b.unwrap().saturating_sub(1), c.unwrap())) - ("enqueue" [a: usize, b: usize] - Self::Enqueue(a.unwrap().saturating_sub(1), b.unwrap().saturating_sub(1))) - ("edit" [a: Option>>] - 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())) + ("get" [a: usize ,b: usize] Some(Self::Get(a.unwrap().saturating_sub(1), b.unwrap().saturating_sub(1)))) + ("put" [a: usize, b: usize, c: Option>>] Some(Self::Put(a.unwrap().saturating_sub(1), b.unwrap().saturating_sub(1), c.unwrap()))) + ("enqueue" [a: usize, b: usize] Some(Self::Enqueue(a.unwrap().saturating_sub(1), b.unwrap().saturating_sub(1)))) + ("edit" [a: Option>>] Some(Self::Edit(a.unwrap()))) + ("loop" [a: usize, b: usize, c: bool] Some(Self::SetLoop(a.unwrap().saturating_sub(1), b.unwrap().saturating_sub(1), c.unwrap()))) + ("color" [a: usize, b: usize] Some(Self::SetColor(a.unwrap().saturating_sub(1), b.unwrap().saturating_sub(1), ItemPalette::random()))) }); command!(|self: ClipCommand, app: Tek|match self { Self::Get(track, scene) => { todo!() }, diff --git a/tek/src/model.rs b/tek/src/model.rs index 8affcf3a..1015f0c2 100644 --- a/tek/src/model.rs +++ b/tek/src/model.rs @@ -128,15 +128,6 @@ impl Tek { name, ..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); let len = self.tracks().len(); let index = len - 1; diff --git a/tek/src/view.rs b/tek/src/view.rs index 8ec348ef..270a4858 100644 --- a/tek/src/view.rs +++ b/tek/src/view.rs @@ -197,15 +197,10 @@ impl Tek { let conn = move|conn: &PortConnect|{ Fill::x(Align::w(Tui::bold(false, Tui::fg_bg(fg, bg, conn.info())))) }; - let header: ThunkBox<_> = io_header!( - self, - " I ", - " midi ins", - self.midi_ins.len(), - self.midi_ins().get(0).map(move|input: &JackMidiIn|Bsp::s( + let header: ThunkBox<_> = io_header!(self, " I ", " midi ins", self.midi_ins.len(), + Map::new(||self.midi_ins.iter(), move|input, index|map_south(index as u16, 1u16, Bsp::s( 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 rec = track.player.recording; let mon = track.player.monitoring; @@ -229,15 +224,11 @@ impl Tek { let bg = Tui::g(64); let mut h = 2.max(1 + self.midi_outs.len()); for midi_out in self.midi_outs.iter() { h += midi_out.conn().len() } - let header: ThunkBox<_> = io_header!( - self, - " O ", - " midi outs", - self.midi_outs.len(), - self.midi_outs().get(0).map(move|output: &JackMidiOut|Bsp::s( + let header: ThunkBox<_> = io_header!(self, " O ", " midi outs", self.midi_outs.len(), + Map::new(||self.midi_outs.iter(), move|output, index|map_south(index as u16, 1u16, Bsp::s( 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, - Tui::fg_bg(fg, bg, connect.info())))))))); + Tui::fg_bg(fg, bg, connect.info()))))))))); let mute = false; let solo = false; let cells: ThunkBox<_> = per_track!(self.size.w();|self, track, t|{ diff --git a/time/src/clock.rs b/time/src/clock.rs index ed877852..ab33fe34 100644 --- a/time/src/clock.rs +++ b/time/src/clock.rs @@ -25,18 +25,18 @@ pub enum ClockCommand { provide_num!(u32: |self: Clock| {}); provide!(f64: |self: Clock| {}); atom_command!(ClockCommand: |state: Clock| { - ("play" [] Self::Play(None)) - ("play" [t: u32] Self::Play(t)) - ("pause" [] Self::Pause(None)) - ("pause" [t: u32] Self::Pause(t)) - ("toggle" [] 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) }) - ("seek/usec" [t: f64] Self::SeekUsec(t.expect("no usec"))) - ("seek/pulse" [t: f64] Self::SeekPulse(t.expect("no pulse"))) - ("seek/sample" [t: f64] Self::SeekSample(t.expect("no sample"))) - ("set/bpm" [t: f64] Self::SetBpm(t.expect("no bpm"))) - ("set/sync" [t: f64] Self::SetSync(t.expect("no sync"))) - ("set/quant" [t: f64] Self::SetQuant(t.expect("no quant"))) + ("play" [] Some(Self::Play(None))) + ("play" [t: u32] Some(Self::Play(t))) + ("pause" [] Some(Self::Pause(None))) + ("pause" [t: u32] Some(Self::Pause(t))) + ("toggle" [] Some(if state.is_rolling() { Self::Pause(None) } else { Self::Play(None) })) + ("toggle" [t: u32] Some(if state.is_rolling() { Self::Pause(t) } else { Self::Play(t) })) + ("seek/usec" [t: f64] Some(Self::SeekUsec(t.expect("no usec")))) + ("seek/pulse" [t: f64] Some(Self::SeekPulse(t.expect("no pulse")))) + ("seek/sample" [t: f64] Some(Self::SeekSample(t.expect("no sample")))) + ("set/bpm" [t: f64] Some(Self::SetBpm(t.expect("no bpm")))) + ("set/sync" [t: f64] Some(Self::SetSync(t.expect("no sync")))) + ("set/quant" [t: f64] Some(Self::SetQuant(t.expect("no quant")))) }); impl Command for ClockCommand { fn execute (self, state: &mut T) -> Perhaps { diff --git a/tui/examples/tui.rs b/tui/examples/tui.rs index 411647e0..37fd116e 100644 --- a/tui/examples/tui.rs +++ b/tui/examples/tui.rs @@ -21,8 +21,8 @@ handle!(TuiIn: |self: Example, input|{ }); enum ExampleCommand { Next, Previous } atom_command!(ExampleCommand: |app: Example| { - (":prev" [] Self::Previous) - (":next" [] Self::Next) + (":prev" [] Some(Self::Previous)) + (":next" [] Some(Self::Next)) }); command!(|self: ExampleCommand, state: Example|match self { Self::Next =>