fix editor behaviors

This commit is contained in:
🪞👃🪞 2025-01-16 16:22:16 +01:00
parent 6408cd26b8
commit 968441850f
8 changed files with 151 additions and 148 deletions

View file

@ -1,6 +1,4 @@
use crate::*;
use self::MidiEditCommand::*;
use KeyCode::*;
pub trait HasEditor {
fn editor (&self) -> &Option<MidiEditor>;
fn editor_mut (&mut self) -> &Option<MidiEditor>;
@ -52,21 +50,33 @@ from!(|clip: Option<Arc<RwLock<MidiClip>>>|MidiEditor = {
model
});
edn_provide!(bool: |self: MidiEditor| {
":true" => true,
":false" => false
":true" => true,
":false" => false,
":time-lock" => self.time_lock().get(),
":time-lock-toggle" => !self.time_lock().get(),
});
edn_provide!(usize: |self: MidiEditor| {
":note-length" => self.note_len(),
":note-length" => self.note_len(),
":note-pos" => self.note_point(),
":note-pos-next" => self.note_point() + 1,
":note-pos-prev" => self.note_point().saturating_sub(1),
":note-pos" => self.note_pos(),
":note-pos-next" => self.note_pos() + 1,
":note-pos-prev" => self.note_pos().saturating_sub(1),
":time-pos" => self.time_point(),
":time-pos-next" => self.time_point() + self.time_zoom().get(),
":time-pos-prev" => self.time_point().saturating_sub(self.time_zoom().get()),
":note-len" => self.note_len(),
":note-len-next" => self.note_len() + 1,
":note-len-prev" => self.note_len().saturating_sub(1),
":note-range" => self.note_axis().get(),
":note-range-prev" => self.note_axis().get() + 1,
":note-range-next" => self.note_axis().get().saturating_sub(1),
":time-pos" => self.time_pos(),
":time-pos-next" => self.time_pos() + self.time_zoom().get(),
":time-pos-prev" => self.time_pos().saturating_sub(self.time_zoom().get()),
":time-zoom" => self.time_zoom().get(),
":time-zoom-next" => self.time_zoom().get() + 1,
":time-zoom-prev" => self.time_zoom().get().saturating_sub(1).max(1),
});
impl std::fmt::Debug for MidiEditor {
fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
@ -91,12 +101,12 @@ impl MidiEditor {
pub fn put_note (&mut self, advance: bool) {
let mut redraw = false;
if let Some(clip) = self.clip() {
let mut clip = clip.write().unwrap();
let note_start = self.time_point();
let note_point = self.note_point();
let mut clip = clip.write().unwrap();
let note_start = self.time_pos();
let note_pos = self.note_pos();
let note_len = self.note_len();
let note_end = note_start + (note_len.saturating_sub(1));
let key: u7 = u7::from(note_point as u8);
let key: u7 = u7::from(note_pos as u8);
let vel: u7 = 100.into();
let length = clip.length;
let note_end = note_end % length;
@ -109,7 +119,7 @@ impl MidiEditor {
clip.notes[note_end].push(note_off);
}
if advance {
self.set_time_point(note_end);
self.set_time_pos(note_end);
}
redraw = true;
}
@ -119,25 +129,25 @@ impl MidiEditor {
}
}
impl TimeRange for MidiEditor {
fn time_len (&self) -> &AtomicUsize { self.mode.time_len() }
fn time_zoom (&self) -> &AtomicUsize { self.mode.time_zoom() }
fn time_lock (&self) -> &AtomicBool { self.mode.time_lock() }
fn time_len (&self) -> &AtomicUsize { self.mode.time_len() }
fn time_zoom (&self) -> &AtomicUsize { self.mode.time_zoom() }
fn time_lock (&self) -> &AtomicBool { self.mode.time_lock() }
fn time_start (&self) -> &AtomicUsize { self.mode.time_start() }
fn time_axis (&self) -> &AtomicUsize { self.mode.time_axis() }
fn time_axis (&self) -> &AtomicUsize { self.mode.time_axis() }
}
impl NoteRange for MidiEditor {
fn note_lo (&self) -> &AtomicUsize { self.mode.note_lo() }
fn note_axis (&self) -> &AtomicUsize { self.mode.note_axis() }
fn note_lo (&self) -> &AtomicUsize { self.mode.note_lo() }
fn note_axis (&self) -> &AtomicUsize { self.mode.note_axis() }
}
impl NotePoint for MidiEditor {
fn note_len (&self) -> usize { self.mode.note_len() }
fn set_note_len (&self, x: usize) { self.mode.set_note_len(x) }
fn note_point (&self) -> usize { self.mode.note_point() }
fn set_note_point (&self, x: usize) { self.mode.set_note_point(x) }
fn note_len (&self) -> usize { self.mode.note_len() }
fn set_note_len (&self, x: usize) { self.mode.set_note_len(x) }
fn note_pos (&self) -> usize { self.mode.note_pos() }
fn set_note_pos (&self, x: usize) { self.mode.set_note_pos(x) }
}
impl TimePoint for MidiEditor {
fn time_point (&self) -> usize { self.mode.time_point() }
fn set_time_point (&self, x: usize) { self.mode.set_time_point(x) }
fn time_pos (&self) -> usize { self.mode.time_pos() }
fn set_time_pos (&self, x: usize) { self.mode.set_time_pos(x) }
}
impl MidiViewer for MidiEditor {
fn buffer_size (&self, clip: &MidiClip) -> (usize, usize) { self.mode.buffer_size(clip) }
@ -164,15 +174,15 @@ impl MidiEditor {
} else {
(ItemPalette::from(TuiTheme::g(64)), 0)
};
let time_point = self.time_point();
let time_pos = self.time_pos();
let time_zoom = self.time_zoom().get();
let time_lock = if self.time_lock().get() { "[lock]" } else { " " };
let note_point = format!("{:>3}", self.note_point());
let note_name = format!("{:4}", Note::pitch_to_name(self.note_point()));
let note_pos = format!("{:>3}", self.note_pos());
let note_name = format!("{:4}", Note::pitch_to_name(self.note_pos()));
let note_len = format!("{:>4}", self.note_len());
Bsp::e(
FieldV(color, "Time", format!("{length}/{time_zoom}+{time_point} {time_lock}")),
FieldV(color, "Note", format!("{note_name} {note_point} {note_len}")),
FieldV(color, "Time", format!("{length}/{time_zoom}+{time_pos} {time_lock}")),
FieldV(color, "Note", format!("{note_name} {note_pos} {note_len}")),
)
}
}
@ -184,23 +194,8 @@ edn_command!(MidiEditCommand: |state: MidiEditor| {
("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()))
});
//impl EdnCommand<MidiEditor> for MidiEditCommand {
//fn from_edn <'a> (state: &MidiEditor, head: &EdnItem<&str>, tail: &'a [EdnItem<String>]) -> 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,
@ -241,27 +236,54 @@ handle!(TuiIn: |self: MidiEditor, input|{
None
})
});
impl Command<MidiEditor> for MidiEditCommand {
fn execute (self, state: &mut MidiEditor) -> Perhaps<Self> {
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) => {
let note_len = state.note_len();
let time_zoom = state.time_zoom().get();
state.set_note_len(x);
if note_len / time_zoom != x / time_zoom {
state.redraw();
}
},
SetTimeCursor(x) => { state.set_time_pos(x); },
SetNoteCursor(note) => { state.set_note_pos(note.min(127)); },
//_ => todo!("{:?}", self)
}
Ok(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()),
//key(Up) => SetNoteCursor(s.note_pos() + 1),
//key(Char('w')) => SetNoteCursor(s.note_pos() + 1),
//key(Down) => SetNoteCursor(s.note_pos().saturating_sub(1)),
//key(Char('s')) => SetNoteCursor(s.note_pos().saturating_sub(1)),
//key(Left) => SetTimeCursor(s.time_pos().saturating_sub(s.note_len())),
//key(Char('a')) => SetTimeCursor(s.time_pos().saturating_sub(s.note_len())),
//key(Right) => SetTimeCursor((s.time_pos() + s.note_len()) % s.clip_length()),
//ctrl(alt(key(Up))) => SetNoteScroll(s.note_pos() + 3),
//ctrl(alt(key(Down))) => SetNoteScroll(s.note_pos().saturating_sub(3)),
//ctrl(alt(key(Left))) => SetTimeScroll(s.time_pos().saturating_sub(s.time_zoom().get())),
//ctrl(alt(key(Right))) => SetTimeScroll((s.time_pos() + 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()),
//alt(key(Up)) => SetNoteCursor(s.note_pos() + 3),
//alt(key(Down)) => SetNoteCursor(s.note_pos().saturating_sub(3)),
//alt(key(Left)) => SetTimeCursor(s.time_pos().saturating_sub(s.time_zoom().get())),
//alt(key(Right)) => SetTimeCursor((s.time_pos() + s.time_zoom().get()) % s.clip_length()),
//key(Char('d')) => SetTimeCursor((s.time_pos() + 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()) }),
@ -276,22 +298,3 @@ handle!(TuiIn: |self: MidiEditor, input|{
////// 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::*;
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)
}
}