mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +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::*;
|
||||
|
||||
mod audio_in;
|
||||
|
||||
mod audio_out;
|
||||
|
||||
mod sampler;
|
||||
pub(crate) use self::sampler::*;
|
||||
pub use self::sampler::{Sampler, Sample, Voice};
|
||||
|
|
|
|||
|
|
@ -1,14 +1,36 @@
|
|||
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_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_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.
|
||||
pub fn all_notes_off (output: &mut [Vec<Vec<u8>>]) {
|
||||
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::*;
|
||||
|
||||
pub struct Note;
|
||||
|
||||
impl Note {
|
||||
/// (pulses, name), assuming 96 PPQ
|
||||
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));
|
||||
|
||||
input_to_command!(GrooveboxCommand: <Tui>|state: GrooveboxTui,input|match input.event() {
|
||||
key_pat!(Up) |
|
||||
key_pat!(Down) |
|
||||
key_pat!(Left) |
|
||||
key_pat!(Right) =>
|
||||
GrooveboxCommand::Sampler(SamplerCommand::input_to_command(&state.sampler, input)?),
|
||||
key_pat!(Up) | key_pat!(Down) | key_pat!(Left) | key_pat!(Right) |
|
||||
key_pat!(Shift-Char('L')) =>
|
||||
SamplerCommand::input_to_command(&state.sampler, input).map(Self::Sampler)?,
|
||||
_ =>
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -62,27 +62,25 @@ render!(<Tui>|self: SamplerTui|{
|
|||
let fg = self.color.base.rgb;
|
||||
let bg = self.color.darkest.rgb;
|
||||
let border = Fill::wh(Outer(Style::default().fg(fg).bg(bg)));
|
||||
let inset = 0;
|
||||
let with_border = |x|lay!([border, Tui::inset_xy(inset, inset, Fill::wh(&x))]);
|
||||
let with_border = |x|lay!([border, Fill::wh(&x)]);
|
||||
let with_size = |x|lay!([self.size, x]);
|
||||
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(
|
||||
Fixed::w(keys_width, keys()),
|
||||
Fill::wh(render(|to: &mut TuiOutput|Ok({
|
||||
let x = to.area.x() + 1;
|
||||
let rows = self.size.h() as u16;
|
||||
let x = to.area.x();
|
||||
let bg_base = self.color.darkest.rgb;
|
||||
let bg_selected = self.color.darker.rgb;
|
||||
let style_empty = Style::default().fg(self.color.base.rgb);
|
||||
let style_full = Style::default().fg(self.color.lighter.rgb);
|
||||
let note_hi = self.note_hi();
|
||||
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 bg = if note == note_pt { bg_selected } else { bg_base };
|
||||
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() {
|
||||
// load sample
|
||||
key_pat!(Char('l')) => Self::Import(FileBrowserCommand::Begin),
|
||||
key_pat!(Shift-Char('L')) => {
|
||||
Self::Import(FileBrowserCommand::Begin)
|
||||
},
|
||||
key_pat!(KeyCode::Up) => {
|
||||
Self::SelectNote(state.note_point().overflowing_add(1).0.min(127))
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue