mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
142 lines
4.5 KiB
Rust
142 lines
4.5 KiB
Rust
use crate::*;
|
|
|
|
/// Contains state for viewing and editing a clip
|
|
pub struct MidiEditor {
|
|
/// Size of editor on screen
|
|
pub size: Measure<TuiOut>,
|
|
/// View mode and state of editor
|
|
pub mode: PianoHorizontal,
|
|
}
|
|
|
|
has!(Measure<TuiOut>: |self: MidiEditor|self.size);
|
|
|
|
impl std::fmt::Debug for MidiEditor {
|
|
fn fmt (&self, f: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
|
|
f.debug_struct("MidiEditor")
|
|
.field("mode", &self.mode)
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
impl Default for MidiEditor {
|
|
fn default () -> Self {
|
|
Self {
|
|
size: Measure::new(),
|
|
mode: PianoHorizontal::new(None),
|
|
}
|
|
}
|
|
}
|
|
|
|
from!(|clip: &Arc<RwLock<MidiClip>>|MidiEditor = {
|
|
let model = Self::from(Some(clip.clone()));
|
|
model.redraw();
|
|
model
|
|
});
|
|
|
|
from!(|clip: Option<Arc<RwLock<MidiClip>>>|MidiEditor = {
|
|
let mut model = Self::default();
|
|
*model.clip_mut() = clip;
|
|
model.redraw();
|
|
model
|
|
});
|
|
|
|
impl MidiEditor {
|
|
/// Put note at current position
|
|
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.get_time_pos();
|
|
let note_pos = self.get_note_pos();
|
|
let note_len = self.get_note_len();
|
|
let note_end = note_start + (note_len.saturating_sub(1));
|
|
let key: u7 = u7::from(note_pos as u8);
|
|
let vel: u7 = 100.into();
|
|
let length = clip.length;
|
|
let note_end = note_end % length;
|
|
let note_on = MidiMessage::NoteOn { key, vel };
|
|
if !clip.notes[note_start].iter().any(|msg|*msg == note_on) {
|
|
clip.notes[note_start].push(note_on);
|
|
}
|
|
let note_off = MidiMessage::NoteOff { key, vel };
|
|
if !clip.notes[note_end].iter().any(|msg|*msg == note_off) {
|
|
clip.notes[note_end].push(note_off);
|
|
}
|
|
if advance {
|
|
self.set_time_pos((note_end + 1) % clip.length);
|
|
}
|
|
redraw = true;
|
|
}
|
|
if redraw {
|
|
self.mode.redraw();
|
|
}
|
|
}
|
|
}
|
|
|
|
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_start (&self) -> &AtomicUsize { self.mode.time_start() }
|
|
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() }
|
|
}
|
|
|
|
impl NotePoint for MidiEditor {
|
|
fn note_len (&self) -> &AtomicUsize { self.mode.note_len() }
|
|
fn note_pos (&self) -> &AtomicUsize { self.mode.note_pos() }
|
|
}
|
|
|
|
impl TimePoint for MidiEditor {
|
|
fn time_pos (&self) -> &AtomicUsize { self.mode.time_pos() }
|
|
}
|
|
|
|
impl MidiViewer for MidiEditor {
|
|
fn buffer_size (&self, clip: &MidiClip) -> (usize, usize) { self.mode.buffer_size(clip) }
|
|
fn redraw (&self) { self.mode.redraw() }
|
|
fn clip (&self) -> &Option<Arc<RwLock<MidiClip>>> { self.mode.clip() }
|
|
fn clip_mut (&mut self) -> &mut Option<Arc<RwLock<MidiClip>>> { self.mode.clip_mut() }
|
|
fn set_clip (&mut self, p: Option<&Arc<RwLock<MidiClip>>>) { self.mode.set_clip(p) }
|
|
}
|
|
|
|
impl<T: Has<Option<MidiEditor>>> HasEditor for T {}
|
|
|
|
pub trait HasEditor: Has<Option<MidiEditor>> {
|
|
fn editor (&self) -> Option<&MidiEditor> {
|
|
self.get().as_ref()
|
|
}
|
|
fn editor_mut (&mut self) -> Option<&mut MidiEditor> {
|
|
self.get_mut().as_mut()
|
|
}
|
|
fn is_editing (&self) -> bool {
|
|
self.editor().is_some()
|
|
}
|
|
fn editor_w (&self) -> usize {
|
|
self.editor().map(|e|e.size.w()).unwrap_or(0)
|
|
}
|
|
fn editor_h (&self) -> usize {
|
|
self.editor().map(|e|e.size.h()).unwrap_or(0)
|
|
}
|
|
}
|
|
|
|
#[macro_export] macro_rules! has_editor {
|
|
(|$self:ident: $Struct:ident|{
|
|
editor = $e0:expr;
|
|
editor_w = $e1:expr;
|
|
editor_h = $e2:expr;
|
|
is_editing = $e3:expr;
|
|
}) => {
|
|
impl HasEditor for $Struct {
|
|
fn editor (&$self) -> Option<&MidiEditor> { $e0.as_ref() }
|
|
fn editor_mut (&mut $self) -> Option<&mut MidiEditor> { $e0.as_mut() }
|
|
fn editor_w (&$self) -> usize { $e1 }
|
|
fn editor_h (&$self) -> usize { $e2 }
|
|
fn is_editing (&$self) -> bool { $e3 }
|
|
}
|
|
};
|
|
}
|
|
|