mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 04:06:45 +01:00
refactor midi_note and remove audio_in/out empty mods
This commit is contained in:
parent
e69cf6d9cb
commit
cb7ba855ab
12 changed files with 182 additions and 174 deletions
|
|
@ -1,9 +1,5 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
mod audio_in;
|
|
||||||
|
|
||||||
mod audio_out;
|
|
||||||
|
|
||||||
mod sampler;
|
mod sampler;
|
||||||
pub(crate) use self::sampler::*;
|
pub(crate) use self::sampler::*;
|
||||||
pub use self::sampler::{Sampler, Sample, Voice};
|
pub use self::sampler::{Sampler, Sample, Voice};
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,36 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
pub(crate) mod midi_in; pub(crate) use midi_in::*;
|
|
||||||
pub(crate) mod midi_launch; pub(crate) use midi_launch::*;
|
|
||||||
pub(crate) mod midi_note; pub(crate) use midi_note::*;
|
|
||||||
pub(crate) mod midi_out; pub(crate) use midi_out::*;
|
|
||||||
pub(crate) mod midi_clip; pub(crate) use midi_clip::*;
|
|
||||||
pub(crate) mod midi_play; pub(crate) use midi_play::*;
|
|
||||||
pub(crate) mod midi_pool; pub(crate) use midi_pool::*;
|
pub(crate) mod midi_pool; pub(crate) use midi_pool::*;
|
||||||
|
pub(crate) mod midi_clip; pub(crate) use midi_clip::*;
|
||||||
|
pub(crate) mod midi_launch; pub(crate) use midi_launch::*;
|
||||||
|
pub(crate) mod midi_play; pub(crate) use midi_play::*;
|
||||||
pub(crate) mod midi_rec; pub(crate) use midi_rec::*;
|
pub(crate) mod midi_rec; pub(crate) use midi_rec::*;
|
||||||
|
|
||||||
|
pub(crate) mod midi_note; pub(crate) use midi_note::*;
|
||||||
|
pub(crate) mod midi_range; pub(crate) use midi_range::*;
|
||||||
|
pub(crate) mod midi_point; pub(crate) use midi_point::*;
|
||||||
|
pub(crate) mod midi_view; pub(crate) use midi_view::*;
|
||||||
|
|
||||||
|
/// Trait for thing that may receive MIDI.
|
||||||
|
pub trait HasMidiIns {
|
||||||
|
fn midi_ins (&self) -> &Vec<Port<MidiIn>>;
|
||||||
|
fn midi_ins_mut (&mut self) -> &mut Vec<Port<MidiIn>>;
|
||||||
|
fn has_midi_ins (&self) -> bool {
|
||||||
|
!self.midi_ins().is_empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait for thing that may output MIDI.
|
||||||
|
pub trait HasMidiOuts {
|
||||||
|
fn midi_outs (&self) -> &Vec<Port<MidiOut>>;
|
||||||
|
fn midi_outs_mut (&mut self) -> &mut Vec<Port<MidiOut>>;
|
||||||
|
fn has_midi_outs (&self) -> bool {
|
||||||
|
!self.midi_outs().is_empty()
|
||||||
|
}
|
||||||
|
/// Buffer for serializing a MIDI event. FIXME rename
|
||||||
|
fn midi_note (&mut self) -> &mut Vec<u8>;
|
||||||
|
}
|
||||||
|
|
||||||
/// Add "all notes off" to the start of a buffer.
|
/// Add "all notes off" to the start of a buffer.
|
||||||
pub fn all_notes_off (output: &mut [Vec<Vec<u8>>]) {
|
pub fn all_notes_off (output: &mut [Vec<Vec<u8>>]) {
|
||||||
let mut buf = vec![];
|
let mut buf = vec![];
|
||||||
|
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
|
|
||||||
/// Trait for thing that may receive MIDI.
|
|
||||||
pub trait HasMidiIns {
|
|
||||||
fn midi_ins (&self) -> &Vec<Port<MidiIn>>;
|
|
||||||
fn midi_ins_mut (&mut self) -> &mut Vec<Port<MidiIn>>;
|
|
||||||
fn has_midi_ins (&self) -> bool {
|
|
||||||
!self.midi_ins().is_empty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
pub struct Note;
|
pub struct Note;
|
||||||
|
|
||||||
impl Note {
|
impl Note {
|
||||||
/// (pulses, name), assuming 96 PPQ
|
/// (pulses, name), assuming 96 PPQ
|
||||||
pub const DURATIONS: [(usize, &str);26] = [
|
pub const DURATIONS: [(usize, &str);26] = [
|
||||||
|
|
@ -32,131 +34,3 @@ impl Note {
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub trait MidiView<E: Engine>: MidiRange + MidiPoint + HasSize<E> {
|
|
||||||
/// Make sure cursor is within range
|
|
||||||
fn autoscroll (&self) {
|
|
||||||
let note_point = self.note_point().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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Make sure range is within display
|
|
||||||
fn autozoom (&self) {
|
|
||||||
let time_len = self.time_len().get();
|
|
||||||
let time_axis = self.time_axis().get();
|
|
||||||
let time_zoom = self.time_zoom().get();
|
|
||||||
//while time_len.div_ceil(time_zoom) > time_axis {
|
|
||||||
//println!("\r{time_len} {time_zoom} {time_axis}");
|
|
||||||
//time_zoom = Note::next(time_zoom);
|
|
||||||
//}
|
|
||||||
//self.time_zoom().set(time_zoom);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct MidiRangeModel {
|
|
||||||
pub time_len: Arc<AtomicUsize>,
|
|
||||||
/// Length of visible time axis
|
|
||||||
pub time_axis: Arc<AtomicUsize>,
|
|
||||||
/// Earliest time displayed
|
|
||||||
pub time_start: Arc<AtomicUsize>,
|
|
||||||
/// Time step
|
|
||||||
pub time_zoom: Arc<AtomicUsize>,
|
|
||||||
/// Auto rezoom to fit in time axis
|
|
||||||
pub time_lock: Arc<AtomicBool>,
|
|
||||||
/// Length of visible note axis
|
|
||||||
pub note_axis: Arc<AtomicUsize>,
|
|
||||||
// Lowest note displayed
|
|
||||||
pub note_lo: Arc<AtomicUsize>,
|
|
||||||
}
|
|
||||||
from!(|data:(usize, bool)|MidiRangeModel = Self {
|
|
||||||
time_len: Arc::new(0.into()),
|
|
||||||
note_axis: Arc::new(0.into()),
|
|
||||||
note_lo: Arc::new(0.into()),
|
|
||||||
time_axis: Arc::new(0.into()),
|
|
||||||
time_start: Arc::new(0.into()),
|
|
||||||
time_zoom: Arc::new(data.0.into()),
|
|
||||||
time_lock: Arc::new(data.1.into()),
|
|
||||||
});
|
|
||||||
pub trait TimeRange {
|
|
||||||
fn time_len (&self) -> &AtomicUsize;
|
|
||||||
fn time_zoom (&self) -> &AtomicUsize;
|
|
||||||
fn time_lock (&self) -> &AtomicBool;
|
|
||||||
fn time_start (&self) -> &AtomicUsize;
|
|
||||||
fn time_axis (&self) -> &AtomicUsize;
|
|
||||||
fn time_end (&self) -> usize {
|
|
||||||
self.time_start().get() + self.time_axis().get() * self.time_zoom().get()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub trait NoteRange {
|
|
||||||
fn note_lo (&self) -> &AtomicUsize;
|
|
||||||
fn note_axis (&self) -> &AtomicUsize;
|
|
||||||
fn note_hi (&self) -> usize {
|
|
||||||
(self.note_lo().get() + self.note_axis().get().saturating_sub(1)).min(127)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub trait MidiRange: TimeRange + NoteRange {}
|
|
||||||
impl<T: TimeRange + NoteRange> MidiRange for T {}
|
|
||||||
impl TimeRange for MidiRangeModel {
|
|
||||||
fn time_len (&self) -> &AtomicUsize { &self.time_len }
|
|
||||||
fn time_zoom (&self) -> &AtomicUsize { &self.time_zoom }
|
|
||||||
fn time_lock (&self) -> &AtomicBool { &self.time_lock }
|
|
||||||
fn time_start (&self) -> &AtomicUsize { &self.time_start }
|
|
||||||
fn time_axis (&self) -> &AtomicUsize { &self.time_axis }
|
|
||||||
}
|
|
||||||
impl NoteRange for MidiRangeModel {
|
|
||||||
fn note_lo (&self) -> &AtomicUsize { &self.note_lo }
|
|
||||||
fn note_axis (&self) -> &AtomicUsize { &self.note_axis }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct MidiPointModel {
|
|
||||||
/// Time coordinate of cursor
|
|
||||||
pub time_point: Arc<AtomicUsize>,
|
|
||||||
/// Note coordinate of cursor
|
|
||||||
pub note_point: Arc<AtomicUsize>,
|
|
||||||
/// Length of note that will be inserted, in pulses
|
|
||||||
pub note_len: Arc<AtomicUsize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for MidiPointModel {
|
|
||||||
fn default () -> Self {
|
|
||||||
Self {
|
|
||||||
time_point: Arc::new(0.into()),
|
|
||||||
note_point: Arc::new(36.into()),
|
|
||||||
note_len: Arc::new(24.into()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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() }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait TimePoint {
|
|
||||||
fn time_point (&self) -> usize;
|
|
||||||
fn set_time_point (&self, x: usize);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait MidiPoint: NotePoint + TimePoint {}
|
|
||||||
|
|
||||||
impl<T: NotePoint + TimePoint> 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) }
|
|
||||||
}
|
|
||||||
|
|
||||||
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) }
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
|
|
||||||
/// Trait for thing that may output MIDI.
|
|
||||||
pub trait HasMidiOuts {
|
|
||||||
fn midi_outs (&self) -> &Vec<Port<MidiOut>>;
|
|
||||||
fn midi_outs_mut (&mut self) -> &mut Vec<Port<MidiOut>>;
|
|
||||||
fn has_midi_outs (&self) -> bool {
|
|
||||||
!self.midi_outs().is_empty()
|
|
||||||
}
|
|
||||||
/// Buffer for serializing a MIDI event. FIXME rename
|
|
||||||
fn midi_note (&mut self) -> &mut Vec<u8>;
|
|
||||||
}
|
|
||||||
50
crates/tek/src/midi/midi_point.rs
Normal file
50
crates/tek/src/midi/midi_point.rs
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct MidiPointModel {
|
||||||
|
/// Time coordinate of cursor
|
||||||
|
pub time_point: Arc<AtomicUsize>,
|
||||||
|
/// Note coordinate of cursor
|
||||||
|
pub note_point: Arc<AtomicUsize>,
|
||||||
|
/// Length of note that will be inserted, in pulses
|
||||||
|
pub note_len: Arc<AtomicUsize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MidiPointModel {
|
||||||
|
fn default () -> Self {
|
||||||
|
Self {
|
||||||
|
time_point: Arc::new(0.into()),
|
||||||
|
note_point: Arc::new(36.into()),
|
||||||
|
note_len: Arc::new(24.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait TimePoint {
|
||||||
|
fn time_point (&self) -> usize;
|
||||||
|
fn set_time_point (&self, x: usize);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait MidiPoint: NotePoint + TimePoint {}
|
||||||
|
|
||||||
|
impl<T: NotePoint + TimePoint> 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) }
|
||||||
|
}
|
||||||
|
|
||||||
|
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) }
|
||||||
|
}
|
||||||
64
crates/tek/src/midi/midi_range.rs
Normal file
64
crates/tek/src/midi/midi_range.rs
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct MidiRangeModel {
|
||||||
|
pub time_len: Arc<AtomicUsize>,
|
||||||
|
/// Length of visible time axis
|
||||||
|
pub time_axis: Arc<AtomicUsize>,
|
||||||
|
/// Earliest time displayed
|
||||||
|
pub time_start: Arc<AtomicUsize>,
|
||||||
|
/// Time step
|
||||||
|
pub time_zoom: Arc<AtomicUsize>,
|
||||||
|
/// Auto rezoom to fit in time axis
|
||||||
|
pub time_lock: Arc<AtomicBool>,
|
||||||
|
/// Length of visible note axis
|
||||||
|
pub note_axis: Arc<AtomicUsize>,
|
||||||
|
// Lowest note displayed
|
||||||
|
pub note_lo: Arc<AtomicUsize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
from!(|data:(usize, bool)|MidiRangeModel = Self {
|
||||||
|
time_len: Arc::new(0.into()),
|
||||||
|
note_axis: Arc::new(0.into()),
|
||||||
|
note_lo: Arc::new(0.into()),
|
||||||
|
time_axis: Arc::new(0.into()),
|
||||||
|
time_start: Arc::new(0.into()),
|
||||||
|
time_zoom: Arc::new(data.0.into()),
|
||||||
|
time_lock: Arc::new(data.1.into()),
|
||||||
|
});
|
||||||
|
|
||||||
|
pub trait TimeRange {
|
||||||
|
fn time_len (&self) -> &AtomicUsize;
|
||||||
|
fn time_zoom (&self) -> &AtomicUsize;
|
||||||
|
fn time_lock (&self) -> &AtomicBool;
|
||||||
|
fn time_start (&self) -> &AtomicUsize;
|
||||||
|
fn time_axis (&self) -> &AtomicUsize;
|
||||||
|
fn time_end (&self) -> usize {
|
||||||
|
self.time_start().get() + self.time_axis().get() * self.time_zoom().get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait NoteRange {
|
||||||
|
fn note_lo (&self) -> &AtomicUsize;
|
||||||
|
fn note_axis (&self) -> &AtomicUsize;
|
||||||
|
fn note_hi (&self) -> usize {
|
||||||
|
(self.note_lo().get() + self.note_axis().get().saturating_sub(1)).min(127)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait MidiRange: TimeRange + NoteRange {}
|
||||||
|
|
||||||
|
impl<T: TimeRange + NoteRange> MidiRange for T {}
|
||||||
|
|
||||||
|
impl TimeRange for MidiRangeModel {
|
||||||
|
fn time_len (&self) -> &AtomicUsize { &self.time_len }
|
||||||
|
fn time_zoom (&self) -> &AtomicUsize { &self.time_zoom }
|
||||||
|
fn time_lock (&self) -> &AtomicBool { &self.time_lock }
|
||||||
|
fn time_start (&self) -> &AtomicUsize { &self.time_start }
|
||||||
|
fn time_axis (&self) -> &AtomicUsize { &self.time_axis }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NoteRange for MidiRangeModel {
|
||||||
|
fn note_lo (&self) -> &AtomicUsize { &self.note_lo }
|
||||||
|
fn note_axis (&self) -> &AtomicUsize { &self.note_axis }
|
||||||
|
}
|
||||||
26
crates/tek/src/midi/midi_view.rs
Normal file
26
crates/tek/src/midi/midi_view.rs
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
pub trait MidiView<E: Engine>: MidiRange + MidiPoint + HasSize<E> {
|
||||||
|
/// Make sure cursor is within range
|
||||||
|
fn autoscroll (&self) {
|
||||||
|
let note_point = self.note_point().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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Make sure range is within display
|
||||||
|
fn autozoom (&self) {
|
||||||
|
let time_len = self.time_len().get();
|
||||||
|
let time_axis = self.time_axis().get();
|
||||||
|
let time_zoom = self.time_zoom().get();
|
||||||
|
//while time_len.div_ceil(time_zoom) > time_axis {
|
||||||
|
//println!("\r{time_len} {time_zoom} {time_axis}");
|
||||||
|
//time_zoom = Note::next(time_zoom);
|
||||||
|
//}
|
||||||
|
//self.time_zoom().set(time_zoom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -55,13 +55,11 @@ pub enum GrooveboxCommand {
|
||||||
handle!(<Tui>|self: GrooveboxTui, input|GrooveboxCommand::execute_with_state(self, input));
|
handle!(<Tui>|self: GrooveboxTui, input|GrooveboxCommand::execute_with_state(self, input));
|
||||||
|
|
||||||
input_to_command!(GrooveboxCommand: <Tui>|state: GrooveboxTui,input|match input.event() {
|
input_to_command!(GrooveboxCommand: <Tui>|state: GrooveboxTui,input|match input.event() {
|
||||||
key_pat!(Up) |
|
key_pat!(Up) | key_pat!(Down) | key_pat!(Left) | key_pat!(Right) |
|
||||||
key_pat!(Down) |
|
key_pat!(Shift-Char('L')) =>
|
||||||
key_pat!(Left) |
|
SamplerCommand::input_to_command(&state.sampler, input).map(Self::Sampler)?,
|
||||||
key_pat!(Right) =>
|
|
||||||
GrooveboxCommand::Sampler(SamplerCommand::input_to_command(&state.sampler, input)?),
|
|
||||||
_ =>
|
_ =>
|
||||||
GrooveboxCommand::Sequencer(SequencerCommand::input_to_command(&state.sequencer, input)?),
|
SequencerCommand::input_to_command(&state.sequencer, input).map(Self::Sequencer)?,
|
||||||
});
|
});
|
||||||
|
|
||||||
command!(|self:GrooveboxCommand,state:GrooveboxTui|match self {
|
command!(|self:GrooveboxCommand,state:GrooveboxTui|match self {
|
||||||
|
|
|
||||||
|
|
@ -62,27 +62,25 @@ render!(<Tui>|self: SamplerTui|{
|
||||||
let fg = self.color.base.rgb;
|
let fg = self.color.base.rgb;
|
||||||
let bg = self.color.darkest.rgb;
|
let bg = self.color.darkest.rgb;
|
||||||
let border = Fill::wh(Outer(Style::default().fg(fg).bg(bg)));
|
let border = Fill::wh(Outer(Style::default().fg(fg).bg(bg)));
|
||||||
let inset = 0;
|
let with_border = |x|lay!([border, Fill::wh(&x)]);
|
||||||
let with_border = |x|lay!([border, Tui::inset_xy(inset, inset, Fill::wh(&x))]);
|
|
||||||
let with_size = |x|lay!([self.size, x]);
|
let with_size = |x|lay!([self.size, x]);
|
||||||
Tui::bg(bg, Fill::wh(with_border(Bsp::s(
|
Tui::bg(bg, Fill::wh(with_border(Bsp::s(
|
||||||
Tui::push_x(1, Tui::fg(self.color.light.rgb, Tui::bold(true, "Sampler"))),
|
Tui::fg(self.color.light.rgb, Tui::bold(true, "Sampler")),
|
||||||
with_size(Tui::shrink_y(1, Bsp::e(
|
with_size(Tui::shrink_y(1, Bsp::e(
|
||||||
Fixed::w(keys_width, keys()),
|
Fixed::w(keys_width, keys()),
|
||||||
Fill::wh(render(|to: &mut TuiOutput|Ok({
|
Fill::wh(render(|to: &mut TuiOutput|Ok({
|
||||||
let x = to.area.x() + 1;
|
let x = to.area.x();
|
||||||
let rows = self.size.h() as u16;
|
|
||||||
let bg_base = self.color.darkest.rgb;
|
let bg_base = self.color.darkest.rgb;
|
||||||
let bg_selected = self.color.darker.rgb;
|
let bg_selected = self.color.darker.rgb;
|
||||||
let style_empty = Style::default().fg(self.color.base.rgb);
|
let style_empty = Style::default().fg(self.color.base.rgb);
|
||||||
let style_full = Style::default().fg(self.color.lighter.rgb);
|
let style_full = Style::default().fg(self.color.lighter.rgb);
|
||||||
let note_hi = self.note_hi();
|
let note_hi = self.note_hi();
|
||||||
let note_pt = self.note_point();
|
let note_pt = self.note_point();
|
||||||
for y in 0..rows {
|
for y in 0..self.size.h() {
|
||||||
let note = note_hi - y as usize;
|
let note = note_hi - y as usize;
|
||||||
let bg = if note == note_pt { bg_selected } else { bg_base };
|
let bg = if note == note_pt { bg_selected } else { bg_base };
|
||||||
let style = Some(style_empty.bg(bg));
|
let style = Some(style_empty.bg(bg));
|
||||||
to.blit(&" (no sample) ", x, to.area.y() + y, style)
|
to.blit(&" (no sample) ", x, to.area.y() + y as u16, style)
|
||||||
}
|
}
|
||||||
})))
|
})))
|
||||||
))),
|
))),
|
||||||
|
|
@ -135,7 +133,9 @@ input_to_command!(SamplerCommand: <Tui>|state: SamplerTui, input|match state.mod
|
||||||
),
|
),
|
||||||
_ => match input.event() {
|
_ => match input.event() {
|
||||||
// load sample
|
// load sample
|
||||||
key_pat!(Char('l')) => Self::Import(FileBrowserCommand::Begin),
|
key_pat!(Shift-Char('L')) => {
|
||||||
|
Self::Import(FileBrowserCommand::Begin)
|
||||||
|
},
|
||||||
key_pat!(KeyCode::Up) => {
|
key_pat!(KeyCode::Up) => {
|
||||||
Self::SelectNote(state.note_point().overflowing_add(1).0.min(127))
|
Self::SelectNote(state.note_point().overflowing_add(1).0.min(127))
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue