diff --git a/midi/src/keys_edit.edn b/midi/src/keys_edit.edn index 599f17a6..71395856 100644 --- a/midi/src/keys_edit.edn +++ b/midi/src/keys_edit.edn @@ -1,12 +1,12 @@ (@up note/pos :note-pos-next) (@down note/pos :note-pos-prev) -(@comma note/len :note-length-prev) -(@period note/len :note-length-next) +(@comma note/len :note-len-prev) +(@period note/len :note-len-next) (@plus note/range :note-range-next-) (@underscore note/range :note-range-prev-) -(@left time/pos :time-pos-next) -(@right time/pos :time-pos-prev) +(@left time/pos :time-pos-prev) +(@right time/pos :time-pos-next) (@equal time/zoom :time-zoom-prev) (@minus time/zoom :time-zoom-next) (@z time/lock) diff --git a/midi/src/midi_edit.rs b/midi/src/midi_edit.rs index 7de89d96..b8ed17ef 100644 --- a/midi/src/midi_edit.rs +++ b/midi/src/midi_edit.rs @@ -1,6 +1,4 @@ use crate::*; -use self::MidiEditCommand::*; -use KeyCode::*; pub trait HasEditor { fn editor (&self) -> &Option; fn editor_mut (&mut self) -> &Option; @@ -52,21 +50,33 @@ from!(|clip: Option>>|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 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, @@ -241,27 +236,54 @@ handle!(TuiIn: |self: MidiEditor, input|{ None }) }); +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) => { + 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 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) - } -} diff --git a/midi/src/midi_point.rs b/midi/src/midi_point.rs index bc85de88..a7b05332 100644 --- a/midi/src/midi_point.rs +++ b/midi/src/midi_point.rs @@ -3,9 +3,9 @@ use crate::*; #[derive(Debug, Clone)] pub struct MidiPointModel { /// Time coordinate of cursor - pub time_point: Arc, + pub time_pos: Arc, /// Note coordinate of cursor - pub note_point: Arc, + pub note_pos: Arc, /// Length of note that will be inserted, in pulses pub note_len: Arc, } @@ -13,8 +13,8 @@ pub struct MidiPointModel { impl Default for MidiPointModel { fn default () -> Self { Self { - time_point: Arc::new(0.into()), - note_point: Arc::new(36.into()), + time_pos: Arc::new(0.into()), + note_pos: Arc::new(36.into()), note_len: Arc::new(24.into()), } } @@ -23,14 +23,14 @@ impl Default for MidiPointModel { pub trait NotePoint { fn note_len (&self) -> usize; fn set_note_len (&self, x: usize); - fn note_point (&self) -> usize; - fn set_note_point (&self, x: usize); - fn note_end (&self) -> usize { self.note_point() + self.note_len() } + fn note_pos (&self) -> usize; + fn set_note_pos (&self, x: usize); + fn note_end (&self) -> usize { self.note_pos() + self.note_len() } } pub trait TimePoint { - fn time_point (&self) -> usize; - fn set_time_point (&self, x: usize); + fn time_pos (&self) -> usize; + fn set_time_pos (&self, x: usize); } pub trait MidiPoint: NotePoint + TimePoint {} @@ -40,11 +40,11 @@ impl MidiPoint for T {} impl NotePoint for MidiPointModel { fn note_len (&self) -> usize { self.note_len.load(Relaxed)} fn set_note_len (&self, x: usize) { self.note_len.store(x, Relaxed) } - fn note_point (&self) -> usize { self.note_point.load(Relaxed).min(127) } - fn set_note_point (&self, x: usize) { self.note_point.store(x.min(127), Relaxed) } + fn note_pos (&self) -> usize { self.note_pos.load(Relaxed).min(127) } + fn set_note_pos (&self, x: usize) { self.note_pos.store(x.min(127), Relaxed) } } impl TimePoint for MidiPointModel { - fn time_point (&self) -> usize { self.time_point.load(Relaxed) } - fn set_time_point (&self, x: usize) { self.time_point.store(x, Relaxed) } + fn time_pos (&self) -> usize { self.time_pos.load(Relaxed) } + fn set_time_pos (&self, x: usize) { self.time_pos.store(x, Relaxed) } } diff --git a/midi/src/midi_view.rs b/midi/src/midi_view.rs index 24357631..ae6440b3 100644 --- a/midi/src/midi_view.rs +++ b/midi/src/midi_view.rs @@ -11,13 +11,13 @@ pub trait MidiViewer: HasSize + MidiRange + MidiPoint + Debug + Send + S } /// Make sure cursor is within note range fn autoscroll (&self) { - let note_point = self.note_point().min(127); + let note_pos = self.note_pos().min(127); let note_lo = self.note_lo().get(); let note_hi = self.note_hi(); - if note_point < note_lo { - self.note_lo().set(note_point); - } else if note_point > note_hi { - self.note_lo().set((note_lo + note_point).saturating_sub(note_hi)); + if note_pos < note_lo { + self.note_lo().set(note_pos); + } else if note_pos > note_hi { + self.note_lo().set((note_lo + note_pos).saturating_sub(note_hi)); } } /// Make sure time range is within display diff --git a/midi/src/piano_h.rs b/midi/src/piano_h.rs index cdce1830..bb6438c9 100644 --- a/midi/src/piano_h.rs +++ b/midi/src/piano_h.rs @@ -1,5 +1,4 @@ use crate::*; -use super::*; /// A clip, rendered as a horizontal piano roll. pub struct PianoHorizontal { pub clip: Option>>, @@ -83,7 +82,7 @@ impl PianoHorizontal { let style = Style::default().fg(clip.color.base.rgb);//.bg(Color::Rgb(0, 0, 0)); let mut notes_on = [false;128]; for (x, time_start) in (0..clip.length).step_by(zoom).enumerate() { - for (y, note) in (0..=127).rev().enumerate() { + for (_y, note) in (0..=127).rev().enumerate() { if let Some(cell) = buf.get_mut(x, note) { if notes_on[note] { cell.set_char('▂'); @@ -114,19 +113,17 @@ impl PianoHorizontal { } fn notes (&self) -> impl Content { let time_start = self.time_start().get(); - let note_axis = self.note_axis().get(); let note_lo = self.note_lo().get(); let note_hi = self.note_hi(); - let note_point = self.note_point(); let buffer = self.buffer.clone(); RenderThunk::new(move|to: &mut TuiOut|{ let source = buffer.read().unwrap(); - let [x0, y0, w, h] = to.area().xywh(); + let [x0, y0, w, _h] = to.area().xywh(); //if h as usize != note_axis { //panic!("area height mismatch: {h} <> {note_axis}"); //} for (area_x, screen_x) in (x0..x0+w).enumerate() { - for (area_y, screen_y, note) in note_y_iter(note_lo, note_hi, y0) { + for (area_y, screen_y, _note) in note_y_iter(note_lo, note_hi, y0) { let source_x = time_start + area_x; let source_y = note_hi - area_y; // TODO: enable loop rollover: @@ -150,19 +147,19 @@ impl PianoHorizontal { let note_hi = self.note_hi(); let note_len = self.note_len(); let note_lo = self.note_lo().get(); - let note_point = self.note_point(); - let time_point = self.time_point(); + let note_pos = self.note_pos(); + let time_pos = self.time_pos(); let time_start = self.time_start().get(); let time_zoom = self.time_zoom().get(); RenderThunk::new(move|to: &mut TuiOut|{ let [x0, y0, w, _] = to.area().xywh(); for (_area_y, screen_y, note) in note_y_iter(note_lo, note_hi, y0) { - if note == note_point { + if note == note_pos { for x in 0..w { let screen_x = x0 + x; let time_1 = time_start + x as usize * time_zoom; let time_2 = time_1 + time_zoom; - if time_1 <= time_point && time_point < time_2 { + if time_1 <= time_pos && time_pos < time_2 { to.blit(&"█", screen_x, screen_y, style); let tail = note_len as u16 / time_zoom as u16; for x_tail in (screen_x + 1)..(screen_x + tail) { @@ -181,18 +178,18 @@ impl PianoHorizontal { let color = state.color; let note_lo = state.note_lo().get(); let note_hi = state.note_hi(); - let note_point = state.note_point(); + let note_pos = state.note_pos(); let key_style = Some(Style::default().fg(Color::Rgb(192, 192, 192)).bg(Color::Rgb(0, 0, 0))); let off_style = Some(Style::default().fg(TuiTheme::g(160))); let on_style = Some(Style::default().fg(TuiTheme::g(255)).bg(color.base.rgb).bold()); Fill::y(Fixed::x(self.keys_width, RenderThunk::new(move|to: &mut TuiOut|{ - let [x, y0, w, h] = to.area().xywh(); - for (area_y, screen_y, note) in note_y_iter(note_lo, note_hi, y0) { + let [x, y0, _w, _h] = to.area().xywh(); + for (_area_y, screen_y, note) in note_y_iter(note_lo, note_hi, y0) { to.blit(&to_key(note), x, screen_y, key_style); if note > 127 { continue } - if note == note_point { + if note == note_pos { to.blit(&format!("{:<5}", Note::pitch_to_name(note)), x, screen_y, on_style) } else { to.blit(&Note::pitch_to_name(note), x, screen_y, off_style) @@ -202,7 +199,7 @@ impl PianoHorizontal { } fn timeline (&self) -> impl Content + '_ { Fill::x(Fixed::y(1, RenderThunk::new(move|to: &mut TuiOut|{ - let [x, y, w, h] = to.area(); + let [x, y, w, _h] = to.area(); let style = Some(Style::default().dim()); let length = self.clip.as_ref().map(|p|p.read().unwrap().length).unwrap_or(1); for (area_x, screen_x) in (0..w).map(|d|(d, d+x)) { @@ -231,12 +228,12 @@ impl NoteRange for PianoHorizontal { impl NotePoint for PianoHorizontal { fn note_len (&self) -> usize { self.point.note_len() } fn set_note_len (&self, x: usize) { self.point.set_note_len(x) } - fn note_point (&self) -> usize { self.point.note_point() } - fn set_note_point (&self, x: usize) { self.point.set_note_point(x) } + fn note_pos (&self) -> usize { self.point.note_pos() } + fn set_note_pos (&self, x: usize) { self.point.set_note_pos(x) } } impl TimePoint for PianoHorizontal { - fn time_point (&self) -> usize { self.point.time_point() } - fn set_time_point (&self, x: usize) { self.point.set_time_point(x) } + fn time_pos (&self) -> usize { self.point.time_pos() } + fn set_time_pos (&self, x: usize) { self.point.set_time_pos(x) } } impl MidiViewer for PianoHorizontal { fn clip (&self) -> &Option>> { diff --git a/sampler/src/sampler_cmd.rs b/sampler/src/sampler_cmd.rs index eb13da39..f403da63 100644 --- a/sampler/src/sampler_cmd.rs +++ b/sampler/src/sampler_cmd.rs @@ -44,8 +44,8 @@ command!(|self:FileBrowserCommand,state:SamplerTui|match self { //_ => 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)), + //kpat!(KeyCode::Up) => Self::Select(state.note_pos().overflowing_add(1).0.min(127)), + //kpat!(KeyCode::Down) => Self::Select(state.note_pos().overflowing_sub(1).0.min(127)), //_ => return None //} //}); @@ -58,8 +58,8 @@ command!(|self: SamplerTuiCommand, state: SamplerTui|match self { None }, Self::Select(index) => { - let old = state.note_point(); - state.set_note_point(index); + let old = state.note_pos(); + state.set_note_pos(index); Some(Self::Select(old)) }, Self::Sample(cmd) => cmd.execute(&mut state.state)?.map(Self::Sample), diff --git a/sampler/src/sampler_tui.rs b/sampler/src/sampler_tui.rs index 5b0c7639..9f97b8c3 100644 --- a/sampler/src/sampler_tui.rs +++ b/sampler/src/sampler_tui.rs @@ -42,7 +42,7 @@ content!(TuiOut: |self: SamplerTui| { Fill::xy(SamplesTui { color: self.color, note_hi: self.note_hi(), - note_pt: self.note_point(), + note_pt: self.note_pos(), height: self.size.h(), }), ))), @@ -74,14 +74,14 @@ impl NoteRange for SamplerTui { impl NotePoint for SamplerTui { fn note_len (&self) -> usize {0/*TODO*/} fn set_note_len (&self, x: usize) {} - fn note_point (&self) -> usize { self.note_pt.load(Relaxed) } - fn set_note_point (&self, x: usize) { self.note_pt.store(x, Relaxed); } + fn note_pos (&self) -> usize { self.note_pt.load(Relaxed) } + fn set_note_pos (&self, x: usize) { self.note_pt.store(x, Relaxed); } } impl Sampler { const EMPTY: &[(f64, f64)] = &[(0., 0.), (1., 1.), (2., 2.), (0., 2.), (2., 0.)]; pub fn list <'a> (&'a self, compact: bool, editor: &MidiEditor) -> impl Content + 'a { let note_lo = editor.note_lo().load(Relaxed); - let note_pt = editor.note_point(); + let note_pt = editor.note_pos(); let note_hi = editor.note_hi(); Outer(Style::default().fg(TuiTheme::g(96))).enclose(Map::new(move||(note_lo..=note_hi).rev(), move|note, i| { let offset = |a|Push::y(i as u16, Align::n(Fixed::y(1, Fill::x(a)))); diff --git a/tek/src/lib.rs b/tek/src/lib.rs index ebe58ef1..ece29809 100644 --- a/tek/src/lib.rs +++ b/tek/src/lib.rs @@ -144,7 +144,7 @@ has_clips!(|self: Tek|self.pool.as_ref().expect("no clip pool").clips); has_jack!(|self: Tek|&self.jack); has_sampler!(|self: Tek|{ sampler = self.sampler; - index = self.editor.as_ref().map(|e|e.note_point()).unwrap_or(0); }); + index = self.editor.as_ref().map(|e|e.note_pos()).unwrap_or(0); }); has_editor!(|self: Tek|{ editor = self.editor; editor_w = { @@ -502,20 +502,23 @@ impl Tek { } else { ("⏹ ".to_string(), TuiTheme::g(64), TuiTheme::g(32)) }; + let selected = selected_scene == Some(s) && selected_track == Some(t); + let active = editing && selected; + let label = move||Tui::fg(fg, Push::x(1, Tui::bold(true, name.to_string()))); + let neighbor = selected_track == Some(t) && selected_scene.map(|s|s+1) == Some(s); map_south(y1 as u16, h, Push::y(1, Fixed::y(h, Either::new( - editing && selected_scene == Some(s) && selected_track == Some(t), + active, Thunk::new(||self.editor()), - Thunk::new(move||phat_sel_3( - selected_track == Some(t) && selected_scene == Some(s), - Tui::fg(fg, Push::x(1, Tui::bold(true, name.to_string()))), - Tui::fg(fg, Push::x(1, Tui::bold(true, name.to_string()))), - if selected_track == Some(t) && selected_scene.map(|s|s+1) == Some(s) { - None - } else { - Some(bg.into()) - }, - bg.into(), - bg.into(), + Thunk::new(move||Bsp::a( + When::new(selected, Fill::y(Align::n(button(" Tab ".into(), "edit".into())))), + phat_sel_3( + selected, + label(), + label(), + if neighbor { None } else { Some(bg.into()) }, + bg.into(), + bg.into(), + ) )), )))) }))).boxed() @@ -1108,14 +1111,14 @@ audio!(|self: Tek, client, scope|{ match event { (time, Ok(LiveEvent::Midi {message, ..})) => match message { MidiMessage::NoteOn {ref key, ..} if let Some(editor) = self.editor.as_ref() => { - editor.set_note_point(key.as_int() as usize); + editor.set_note_pos(key.as_int() as usize); }, MidiMessage::Controller {controller, value} if let (Some(editor), Some(sampler)) = ( self.editor.as_ref(), self.sampler.as_ref(), ) => { // TODO: give sampler its own cursor - if let Some(sample) = &sampler.mapped[editor.note_point()] { + if let Some(sample) = &sampler.mapped[editor.note_pos()] { sample.write().unwrap().handle_cc(*controller, *value) } }