use crate::*; use self::MidiEditCommand::*; use KeyCode::*; 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) ("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"))) }); //impl EdnCommand for MidiEditCommand { //fn from_edn <'a> (state: &MidiEditor, head: &EdnItem<&str>, tail: &'a [EdnItem]) -> Self { //use EdnItem::*; //match (head, tail) { //(Key("note/put"), [a]) => Self::PutNote, //(Key("note/del"), [a]) => Self::AppendNote, //(Key("note/dur"), [a]) => Self::AppendNote, //(Key("note/range"), [a]) => Self::AppendNote, //(Key("note/pos"), [a]) => Self::AppendNote, //(Key("time/pos"), [a]) => Self::AppendNote, //(Key("time/zoom"), [a]) => Self::AppendNote, //(Key("time/lock"), [a]) => Self::AppendNote, //_ => todo!() //} //} //} #[derive(Clone, Debug)] pub enum MidiEditCommand { // TODO: 1-9 seek markers that by default start every 8th of the clip AppendNote, PutNote, SetNoteCursor(usize), SetNoteLength(usize), SetNoteScroll(usize), SetTimeCursor(usize), SetTimeScroll(usize), SetTimeZoom(usize), SetTimeLock(bool), Show(Option>>), } 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 Command for MidiEditCommand { fn execute (self, state: &mut MidiEditor) -> Perhaps { use MidiEditCommand::*; match self { Show(clip) => { state.set_clip(clip.as_ref()); }, PutNote => { state.put_note(false); }, AppendNote => { state.put_note(true); }, SetTimeZoom(x) => { state.time_zoom().set(x); state.redraw(); }, SetTimeLock(x) => { state.time_lock().set(x); }, SetTimeScroll(x) => { state.time_start().set(x); }, SetNoteScroll(x) => { state.note_lo().set(x.min(127)); }, SetNoteLength(x) => { state.set_note_len(x); }, SetTimeCursor(x) => { state.set_time_point(x); }, SetNoteCursor(note) => { state.set_note_point(note.min(127)); }, _ => todo!("{:?}", self) } Ok(None) } }