remove old input macros

This commit is contained in:
🪞👃🪞 2025-01-14 20:17:17 +01:00
parent 6fd87ce4ed
commit ca1fb3c414
11 changed files with 218 additions and 247 deletions

View file

@ -1,7 +1,8 @@
use tek::*;
use clap::{self, Parser, Subcommand};
#[derive(Debug, Parser)]
#[command(version, about, long_about = None)]
#[derive(Debug, Parser)] pub struct TekCli {
pub struct TekCli {
/// Which app to initialize
#[command(subcommand)] mode: TekMode,
/// Name of JACK client
@ -60,7 +61,7 @@ use clap::{self, Parser, Subcommand};
pub fn main () -> Usually<()> {
let cli = TekCli::parse();
let name = cli.name.as_ref().map_or("tek", |x|x.as_str());
let color = ItemPalette::random();
//let color = ItemPalette::random();
let jack = JackConnection::new(name)?;
let engine = Tui::new()?;
let empty = &[] as &[&str];
@ -73,20 +74,6 @@ pub fn main () -> Usually<()> {
let audio_froms = &[left_froms.as_slice(), right_froms.as_slice()];
let audio_tos = &[left_tos.as_slice(), right_tos.as_slice() ];
Ok(match cli.mode {
TekMode::Sampler => engine.run(&jack.activate_with(|jack|Ok(
SamplerTui {
cursor: (0, 0),
editing: None,
mode: None,
note_lo: 36.into(),
note_pt: 36.into(),
size: Measure::new(),
state: Sampler::new(jack, &"sampler", &midi_froms,
&[&left_froms, &right_froms],
&[&left_tos, &right_tos])?,
color,
}
))?)?,
TekMode::Clock =>
engine.run(&jack.activate_with(|jack|App::clock(
jack, cli.bpm))?)?,
@ -101,6 +88,20 @@ pub fn main () -> Usually<()> {
jack, cli.bpm, &midi_froms, &midi_tos, &audio_froms, &audio_tos,
scenes, tracks, track_width,
))?)?,
//TekMode::Sampler => engine.run(&jack.activate_with(|jack|Ok(
//SamplerTui {
//cursor: (0, 0),
//editing: None,
//mode: None,
//note_lo: 36.into(),
//note_pt: 36.into(),
//size: Measure::new(),
//state: Sampler::new(jack, &"sampler", &midi_froms,
//&[&left_froms, &right_froms],
//&[&left_tos, &right_tos])?,
//color,
//}
//))?)?,
_ => todo!()
})
}

View file

@ -0,0 +1,6 @@
(@up inc)
(@down dec)
(@right next)
(@left prev)
(@return set :length)
(@escape cancel)

View file

@ -0,0 +1,4 @@
(:char append :char)
(@backspace delete :last)
(@return confirm)
(@escape cancel)

View file

@ -1,12 +1,12 @@
(:n rename/begin)
(:t length/begin)
(:m import/begin)
(:x export/begin)
(:c clip/color :current :random-color)
(:openbracket select :previous)
(:closebracket select :next)
(:lt swap :current :previous)
(:gt swap :current :next)
(:delete clip/delete :current)
(:shift-A clip/add :after :new-clip)
(:shift-D clip/add :after :cloned-clip)
(@n rename/begin)
(@t length/begin)
(@m import/begin)
(@x export/begin)
(@c clip/color :current :random-color)
(@openbracket select :previous)
(@closebracket select :next)
(@lt swap :current :previous)
(@gt swap :current :next)
(@delete clip/delete :current)
(@shift-A clip/add :after :new-clip)
(@shift-D clip/add :after :cloned-clip)

View file

@ -0,0 +1,8 @@
(@up select :prev)
(@down select :next)
(@right chdir :selected)
(@left chdir :parent)
(@return confirm)
(@escape cancel)
(:char append :char)
(@backspace delete :last)

View file

@ -30,6 +30,12 @@ pub(crate) use std::fmt::Debug;
pub use ::midly; pub(crate) use ::midly::{*, num::*, live::*};
pub(crate) const KEYS_EDIT: &str = include_str!("keys_edit.edn");
pub(crate) const KEYS_POOL: &str = include_str!("keys_pool.edn");
pub(crate) const KEYS_FILE: &str = include_str!("keys_pool_file.edn");
pub(crate) const KEYS_LENGTH: &str = include_str!("keys_clip_length.edn");
pub(crate) const KEYS_RENAME: &str = include_str!("keys_clip_rename.edn");
/// Add "all notes off" to the start of a buffer.
pub fn all_notes_off (output: &mut [Vec<Vec<u8>>]) {
let mut buf = vec![];

View file

@ -34,6 +34,33 @@ pub struct MidiEditor {
pub mode: PianoHorizontal,
pub size: Measure<TuiOut>,
}
has_size!(<TuiOut>|self: MidiEditor|&self.size);
content!(TuiOut: |self: MidiEditor| {
self.autoscroll();
//self.autozoom();
self.size.of(&self.mode)
});
from!(|clip: &Arc<RwLock<MidiClip>>|MidiEditor = {
let model = Self::from(Some(clip.clone()));
model.redraw();
model
});
from!(|clip: Option<Arc<RwLock<MidiClip>>>|MidiEditor = {
let mut model = Self::default();
*model.clip_mut() = clip;
model.redraw();
model
});
edn_provide!(bool: |self: MidiEditor| {
":true" => true,
":false" => false
});
edn_provide!(usize: |self: MidiEditor| {
":note-length" => self.note_len(),
":note-point" => self.note_point(),
":time-point" => self.time_point(),
":time-zoom" => self.time_zoom().get(),
});
impl std::fmt::Debug for MidiEditor {
fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
f.debug_struct("MidiEditor")
@ -84,17 +111,6 @@ impl MidiEditor {
}
}
}
from!(|clip: &Arc<RwLock<MidiClip>>|MidiEditor = {
let model = Self::from(Some(clip.clone()));
model.redraw();
model
});
from!(|clip: Option<Arc<RwLock<MidiClip>>>|MidiEditor = {
let mut model = Self::default();
*model.clip_mut() = clip;
model.redraw();
model
});
impl TimeRange for MidiEditor {
fn time_len (&self) -> &AtomicUsize { self.mode.time_len() }
fn time_zoom (&self) -> &AtomicUsize { self.mode.time_zoom() }
@ -123,12 +139,6 @@ impl MidiViewer for MidiEditor {
fn clip_mut (&mut self) -> &mut Option<Arc<RwLock<MidiClip>>> { self.mode.clip_mut() }
fn set_clip (&mut self, p: Option<&Arc<RwLock<MidiClip>>>) { self.mode.set_clip(p) }
}
has_size!(<TuiOut>|self: MidiEditor|&self.size);
content!(TuiOut: |self: MidiEditor| {
self.autoscroll();
//self.autozoom();
self.size.of(&self.mode)
});
impl MidiEditor {
pub fn clip_status (&self) -> impl Content<TuiOut> + '_ {
let (color, name, length, looped) = if let Some(clip) = self.clip().as_ref().map(|p|p.read().unwrap()) {
@ -159,16 +169,6 @@ impl MidiEditor {
)
}
}
edn_provide!(bool: |self: MidiEditor|{
":true" => true,
":false" => false
});
edn_provide!(usize: |self: MidiEditor|{
":note-length" => self.note_len(),
":note-point" => self.note_point(),
":time-point" => self.time_point(),
":time-zoom" => self.time_zoom().get(),
});
edn_command!(MidiEditCommand: |state: MidiEditor| {
("note/put" [a: bool] Self::PutNote)
("note/del" [a: bool] Self::PutNote)
@ -207,42 +207,68 @@ edn_command!(MidiEditCommand: |state: MidiEditor| {
SetTimeLock(bool),
Show(Option<Arc<RwLock<MidiClip>>>),
}
handle!(TuiIn: |self: MidiEditor, input|MidiEditCommand::execute_with_state(self, input.event()));
keymap!(KEYS_MIDI_EDITOR = |s: MidiEditor, _input: Event| MidiEditCommand {
key(Up) => SetNoteCursor(s.note_point() + 1),
key(Char('w')) => SetNoteCursor(s.note_point() + 1),
key(Down) => SetNoteCursor(s.note_point().saturating_sub(1)),
key(Char('s')) => SetNoteCursor(s.note_point().saturating_sub(1)),
key(Left) => SetTimeCursor(s.time_point().saturating_sub(s.note_len())),
key(Char('a')) => SetTimeCursor(s.time_point().saturating_sub(s.note_len())),
key(Right) => SetTimeCursor((s.time_point() + s.note_len()) % s.clip_length()),
ctrl(alt(key(Up))) => SetNoteScroll(s.note_point() + 3),
ctrl(alt(key(Down))) => SetNoteScroll(s.note_point().saturating_sub(3)),
ctrl(alt(key(Left))) => SetTimeScroll(s.time_point().saturating_sub(s.time_zoom().get())),
ctrl(alt(key(Right))) => SetTimeScroll((s.time_point() + s.time_zoom().get()) % s.clip_length()),
ctrl(key(Up)) => SetNoteScroll(s.note_lo().get() + 1),
ctrl(key(Down)) => SetNoteScroll(s.note_lo().get().saturating_sub(1)),
ctrl(key(Left)) => SetTimeScroll(s.time_start().get().saturating_sub(s.note_len())),
ctrl(key(Right)) => SetTimeScroll(s.time_start().get() + s.note_len()),
alt(key(Up)) => SetNoteCursor(s.note_point() + 3),
alt(key(Down)) => SetNoteCursor(s.note_point().saturating_sub(3)),
alt(key(Left)) => SetTimeCursor(s.time_point().saturating_sub(s.time_zoom().get())),
alt(key(Right)) => SetTimeCursor((s.time_point() + s.time_zoom().get()) % s.clip_length()),
key(Char('d')) => SetTimeCursor((s.time_point() + s.note_len()) % s.clip_length()),
key(Char('z')) => SetTimeLock(!s.time_lock().get()),
key(Char('-')) => SetTimeZoom(if s.time_lock().get() { s.time_zoom().get() } else { NoteDuration::next(s.time_zoom().get()) }),
key(Char('_')) => SetTimeZoom(if s.time_lock().get() { s.time_zoom().get() } else { NoteDuration::next(s.time_zoom().get()) }),
key(Char('=')) => SetTimeZoom(if s.time_lock().get() { s.time_zoom().get() } else { NoteDuration::prev(s.time_zoom().get()) }),
key(Char('+')) => SetTimeZoom(if s.time_lock().get() { s.time_zoom().get() } else { NoteDuration::prev(s.time_zoom().get()) }),
key(Enter) => PutNote,
ctrl(key(Enter)) => AppendNote,
key(Char(',')) => SetNoteLength(NoteDuration::prev(s.note_len())),
key(Char('.')) => SetNoteLength(NoteDuration::next(s.note_len())),
key(Char('<')) => SetNoteLength(NoteDuration::prev(s.note_len())),
key(Char('>')) => SetNoteLength(NoteDuration::next(s.note_len())),
//// TODO: kpat!(Char('/')) => // toggle 3plet
//// TODO: kpat!(Char('?')) => // toggle dotted
impl MidiEditCommand {
pub fn from_tui_event (state: &MidiEditor, input: &impl EdnInput) -> Usually<Option<Self>> {
use EdnItem::*;
let edns = EdnItem::<&str>::read_all(KEYS_EDIT)?;
for item in edns.iter() {
if let Exp(e) = item {
match e.as_slice() {
[Sym(key), command, args @ ..] if input.matches_edn(key) => {
return Ok(MidiEditCommand::from_edn(state, command, args))
}
_ => {}
}
} else {
panic!("invalid config")
}
}
Ok(None)
}
}
handle!(TuiIn: |self: MidiEditor, input|{
Ok(if let Some(command) = MidiEditCommand::from_tui_event(self, input)? {
let _undo = command.execute(self)?;
Some(true)
} else {
None
})
});
//keymap!(KEYS_MIDI_EDITOR = |s: MidiEditor, _input: Event| MidiEditCommand {
//key(Up) => SetNoteCursor(s.note_point() + 1),
//key(Char('w')) => SetNoteCursor(s.note_point() + 1),
//key(Down) => SetNoteCursor(s.note_point().saturating_sub(1)),
//key(Char('s')) => SetNoteCursor(s.note_point().saturating_sub(1)),
//key(Left) => SetTimeCursor(s.time_point().saturating_sub(s.note_len())),
//key(Char('a')) => SetTimeCursor(s.time_point().saturating_sub(s.note_len())),
//key(Right) => SetTimeCursor((s.time_point() + s.note_len()) % s.clip_length()),
//ctrl(alt(key(Up))) => SetNoteScroll(s.note_point() + 3),
//ctrl(alt(key(Down))) => SetNoteScroll(s.note_point().saturating_sub(3)),
//ctrl(alt(key(Left))) => SetTimeScroll(s.time_point().saturating_sub(s.time_zoom().get())),
//ctrl(alt(key(Right))) => SetTimeScroll((s.time_point() + s.time_zoom().get()) % s.clip_length()),
//ctrl(key(Up)) => SetNoteScroll(s.note_lo().get() + 1),
//ctrl(key(Down)) => SetNoteScroll(s.note_lo().get().saturating_sub(1)),
//ctrl(key(Left)) => SetTimeScroll(s.time_start().get().saturating_sub(s.note_len())),
//ctrl(key(Right)) => SetTimeScroll(s.time_start().get() + s.note_len()),
//alt(key(Up)) => SetNoteCursor(s.note_point() + 3),
//alt(key(Down)) => SetNoteCursor(s.note_point().saturating_sub(3)),
//alt(key(Left)) => SetTimeCursor(s.time_point().saturating_sub(s.time_zoom().get())),
//alt(key(Right)) => SetTimeCursor((s.time_point() + s.time_zoom().get()) % s.clip_length()),
//key(Char('d')) => SetTimeCursor((s.time_point() + s.note_len()) % s.clip_length()),
//key(Char('z')) => SetTimeLock(!s.time_lock().get()),
//key(Char('-')) => SetTimeZoom(if s.time_lock().get() { s.time_zoom().get() } else { NoteDuration::next(s.time_zoom().get()) }),
//key(Char('_')) => SetTimeZoom(if s.time_lock().get() { s.time_zoom().get() } else { NoteDuration::next(s.time_zoom().get()) }),
//key(Char('=')) => SetTimeZoom(if s.time_lock().get() { s.time_zoom().get() } else { NoteDuration::prev(s.time_zoom().get()) }),
//key(Char('+')) => SetTimeZoom(if s.time_lock().get() { s.time_zoom().get() } else { NoteDuration::prev(s.time_zoom().get()) }),
//key(Enter) => PutNote,
//ctrl(key(Enter)) => AppendNote,
//key(Char(',')) => SetNoteLength(NoteDuration::prev(s.note_len())),
//key(Char('.')) => SetNoteLength(NoteDuration::next(s.note_len())),
//key(Char('<')) => SetNoteLength(NoteDuration::prev(s.note_len())),
//key(Char('>')) => SetNoteLength(NoteDuration::next(s.note_len())),
////// TODO: kpat!(Char('/')) => // toggle 3plet
////// TODO: kpat!(Char('?')) => // toggle dotted
//});
impl Command<MidiEditor> for MidiEditCommand {
fn execute (self, state: &mut MidiEditor) -> Perhaps<Self> {
use MidiEditCommand::*;

View file

@ -206,17 +206,13 @@ content!(TuiOut: |self: ClipLength| {
}
});
impl PoolCommand {
const KEYS_POOL: &str = include_str!("keys_pool.edn");
const KEYS_FILE: &str = include_str!("keys_pool_file.edn");
const KEYS_LENGTH: &str = include_str!("keys_clip_length.edn");
const KEYS_RENAME: &str = include_str!("keys_clip_rename.edn");
pub fn from_tui_event (state: &MidiPool, input: &impl EdnInput) -> Usually<Option<Self>> {
use EdnItem::*;
let edns: Vec<EdnItem<&str>> = EdnItem::read_all(match state.mode() {
Some(PoolMode::Rename(..)) => Self::KEYS_RENAME,
Some(PoolMode::Length(..)) => Self::KEYS_LENGTH,
Some(PoolMode::Import(..)) | Some(PoolMode::Export(..)) => Self::KEYS_FILE,
_ => Self::KEYS_POOL
Some(PoolMode::Rename(..)) => KEYS_RENAME,
Some(PoolMode::Length(..)) => KEYS_LENGTH,
Some(PoolMode::Import(..)) | Some(PoolMode::Export(..)) => KEYS_FILE,
_ => KEYS_POOL
})?;
for item in edns {
match item {
@ -519,82 +515,6 @@ command!(|self: FileBrowserCommand, state: MidiPool|{
None
});
///////////////////////////////////////////////////////////////////////////////////////////////////
input_to_command!(FileBrowserCommand: |state: MidiPool, input: Event|{
use FileBrowserCommand::*;
use KeyCode::{Up, Down, Left, Right, Enter, Esc, Backspace, Char};
if let Some(PoolMode::Import(_index, browser)) = &state.mode {
match input {
kpat!(Up) => Select(browser.index.overflowing_sub(1).0.min(browser.len().saturating_sub(1))),
kpat!(Down) => Select(browser.index.saturating_add(1)% browser.len()),
kpat!(Right) => Chdir(browser.cwd.clone()),
kpat!(Left) => Chdir(browser.cwd.clone()),
kpat!(Enter) => Confirm,
kpat!(Char(_)) => { todo!() },
kpat!(Backspace) => { todo!() },
kpat!(Esc) => Cancel,
_ => return None
}
} else if let Some(PoolMode::Export(_index, browser)) = &state.mode {
match input {
kpat!(Up) => Select(browser.index.overflowing_sub(1).0.min(browser.len())),
kpat!(Down) => Select(browser.index.saturating_add(1) % browser.len()),
kpat!(Right) => Chdir(browser.cwd.clone()),
kpat!(Left) => Chdir(browser.cwd.clone()),
kpat!(Enter) => Confirm,
kpat!(Char(_)) => { todo!() },
kpat!(Backspace) => { todo!() },
kpat!(Esc) => Cancel,
_ => return None
}
} else {
unreachable!()
}
});
///////////////////////////////////////////////////////////////////////////////////////////////////
input_to_command!(ClipLengthCommand: |state: MidiPool, input: Event|{
if let Some(PoolMode::Length(_, length, _)) = state.mode() {
match input {
kpat!(Up) => Self::Inc,
kpat!(Down) => Self::Dec,
kpat!(Right) => Self::Next,
kpat!(Left) => Self::Prev,
kpat!(Enter) => Self::Set(*length),
kpat!(Esc) => Self::Cancel,
_ => return None
}
} else {
unreachable!()
}
});
///////////////////////////////////////////////////////////////////////////////////////////////////
impl InputToCommand<Event, MidiPool> for ClipRenameCommand {
fn input_to_command (state: &MidiPool, input: &Event) -> Option<Self> {
use KeyCode::{Char, Backspace, Enter, Esc};
if let Some(PoolMode::Rename(_, ref old_name)) = state.mode() {
Some(match input {
kpat!(Char(c)) => {
let mut new_name = old_name.clone().to_string();
new_name.push(*c);
Self::Set(new_name.into())
},
kpat!(Backspace) => {
let mut new_name = old_name.clone().to_string();
new_name.pop();
Self::Set(new_name.into())
},
kpat!(Enter) => Self::Confirm,
kpat!(Esc) => Self::Cancel,
_ => return None
})
} else {
unreachable!()
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
//fn to_clips_command (state: &MidiPool, input: &Event) -> Option<PoolCommand> {
//use KeyCode::{Up, Down, Delete, Char};
//use PoolCommand as Cmd;

View file

@ -195,67 +195,67 @@ fn draw_header (state: &Plugin, to: &mut TuiOut, x: u16, y: u16, w: u16) {
//Ok(Rect { x, y, width: w, height: 1 })
}
handle!(TuiIn: |self:Plugin, from|{
match from.event() {
kpat!(KeyCode::Up) => {
self.selected = self.selected.saturating_sub(1);
Ok(Some(true))
},
kpat!(KeyCode::Down) => {
self.selected = (self.selected + 1).min(match &self.plugin {
Some(PluginKind::LV2(LV2Plugin { port_list, .. })) => port_list.len() - 1,
_ => unimplemented!()
});
Ok(Some(true))
},
kpat!(KeyCode::PageUp) => {
self.selected = self.selected.saturating_sub(8);
Ok(Some(true))
},
kpat!(KeyCode::PageDown) => {
self.selected = (self.selected + 10).min(match &self.plugin {
Some(PluginKind::LV2(LV2Plugin { port_list, .. })) => port_list.len() - 1,
_ => unimplemented!()
});
Ok(Some(true))
},
kpat!(KeyCode::Char(',')) => {
match self.plugin.as_mut() {
Some(PluginKind::LV2(LV2Plugin { port_list, ref mut instance, .. })) => {
let index = port_list[self.selected].index;
if let Some(value) = instance.control_input(index) {
instance.set_control_input(index, value - 0.01);
}
},
_ => {}
}
Ok(Some(true))
},
kpat!(KeyCode::Char('.')) => {
match self.plugin.as_mut() {
Some(PluginKind::LV2(LV2Plugin { port_list, ref mut instance, .. })) => {
let index = port_list[self.selected].index;
if let Some(value) = instance.control_input(index) {
instance.set_control_input(index, value + 0.01);
}
},
_ => {}
}
Ok(Some(true))
},
kpat!(KeyCode::Char('g')) => {
match self.plugin {
//Some(PluginKind::LV2(ref mut plugin)) => {
//plugin.ui_thread = Some(run_lv2_ui(LV2PluginUI::new()?)?);
//handle!(TuiIn: |self:Plugin, from|{
//match from.event() {
//kpat!(KeyCode::Up) => {
//self.selected = self.selected.saturating_sub(1);
//Ok(Some(true))
//},
//kpat!(KeyCode::Down) => {
//self.selected = (self.selected + 1).min(match &self.plugin {
//Some(PluginKind::LV2(LV2Plugin { port_list, .. })) => port_list.len() - 1,
//_ => unimplemented!()
//});
//Ok(Some(true))
//},
//kpat!(KeyCode::PageUp) => {
//self.selected = self.selected.saturating_sub(8);
//Ok(Some(true))
//},
//kpat!(KeyCode::PageDown) => {
//self.selected = (self.selected + 10).min(match &self.plugin {
//Some(PluginKind::LV2(LV2Plugin { port_list, .. })) => port_list.len() - 1,
//_ => unimplemented!()
//});
//Ok(Some(true))
//},
//kpat!(KeyCode::Char(',')) => {
//match self.plugin.as_mut() {
//Some(PluginKind::LV2(LV2Plugin { port_list, ref mut instance, .. })) => {
//let index = port_list[self.selected].index;
//if let Some(value) = instance.control_input(index) {
//instance.set_control_input(index, value - 0.01);
//}
//},
Some(_) => unreachable!(),
None => {}
}
Ok(Some(true))
},
_ => Ok(None)
}
});
//_ => {}
//}
//Ok(Some(true))
//},
//kpat!(KeyCode::Char('.')) => {
//match self.plugin.as_mut() {
//Some(PluginKind::LV2(LV2Plugin { port_list, ref mut instance, .. })) => {
//let index = port_list[self.selected].index;
//if let Some(value) = instance.control_input(index) {
//instance.set_control_input(index, value + 0.01);
//}
//},
//_ => {}
//}
//Ok(Some(true))
//},
//kpat!(KeyCode::Char('g')) => {
//match self.plugin {
////Some(PluginKind::LV2(ref mut plugin)) => {
////plugin.ui_thread = Some(run_lv2_ui(LV2PluginUI::new()?)?);
////},
//Some(_) => unreachable!(),
//None => {}
//}
//Ok(Some(true))
//},
//_ => Ok(None)
//}
//});
from_edn!("plugin/lv2" => |jack: &Arc<RwLock<JackConnection>>, args| -> Plugin {
let mut name = String::new();

View file

@ -1,6 +1,6 @@
use crate::*;
handle!(TuiIn: |self: SamplerTui, input|SamplerTuiCommand::execute_with_state(self, input.event()));
//handle!(TuiIn: |self: SamplerTui, input|SamplerTuiCommand::execute_with_state(self, input.event()));
#[derive(Clone, Debug)] pub enum SamplerTuiCommand {
Import(FileBrowserCommand),
@ -37,18 +37,18 @@ command!(|self:FileBrowserCommand,state:SamplerTui|match self {
_ => todo!()
});
input_to_command!(SamplerTuiCommand: |state: SamplerTui, input: Event|match state.mode{
Some(SamplerMode::Import(..)) => Self::Import(
FileBrowserCommand::input_to_command(state, input)?
),
_ => match input {
// load sample
kpat!(Shift-Char('L')) => Self::Import(FileBrowserCommand::Begin),
kpat!(KeyCode::Up) => Self::Select(state.note_point().overflowing_add(1).0.min(127)),
kpat!(KeyCode::Down) => Self::Select(state.note_point().overflowing_sub(1).0.min(127)),
_ => return None
}
});
//input_to_command!(SamplerTuiCommand: |state: SamplerTui, input: Event|match state.mode{
//Some(SamplerMode::Import(..)) => Self::Import(
//FileBrowserCommand::input_to_command(state, input)?
//),
//_ => match input {
//// load sample
//kpat!(Shift-Char('L')) => Self::Import(FileBrowserCommand::Begin),
//kpat!(KeyCode::Up) => Self::Select(state.note_point().overflowing_add(1).0.min(127)),
//kpat!(KeyCode::Down) => Self::Select(state.note_point().overflowing_sub(1).0.min(127)),
//_ => return None
//}
//});
command!(|self: SamplerTuiCommand, state: SamplerTui|match self {
Self::Import(FileBrowserCommand::Begin) => {