mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
This commit is contained in:
parent
2c3bfe4ebb
commit
ef81b085a0
106 changed files with 6866 additions and 7106 deletions
23
engine/note/note_pitch.rs
Normal file
23
engine/note/note_pitch.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
pub struct Note;
|
||||
|
||||
impl Note {
|
||||
pub const NAMES: [&str; 128] = [
|
||||
"C0", "C#0", "D0", "D#0", "E0", "F0", "F#0", "G0", "G#0", "A0", "A#0", "B0",
|
||||
"C1", "C#1", "D1", "D#1", "E1", "F1", "F#1", "G1", "G#1", "A1", "A#1", "B1",
|
||||
"C2", "C#2", "D2", "D#2", "E2", "F2", "F#2", "G2", "G#2", "A2", "A#2", "B2",
|
||||
"C3", "C#3", "D3", "D#3", "E3", "F3", "F#3", "G3", "G#3", "A3", "A#3", "B3",
|
||||
"C4", "C#4", "D4", "D#4", "E4", "F4", "F#4", "G4", "G#4", "A4", "A#4", "B4",
|
||||
"C5", "C#5", "D5", "D#5", "E5", "F5", "F#5", "G5", "G#5", "A5", "A#5", "B5",
|
||||
"C6", "C#6", "D6", "D#6", "E6", "F6", "F#6", "G6", "G#6", "A6", "A#6", "B6",
|
||||
"C7", "C#7", "D7", "D#7", "E7", "F7", "F#7", "G7", "G#7", "A7", "A#7", "B7",
|
||||
"C8", "C#8", "D8", "D#8", "E8", "F8", "F#8", "G8", "G#8", "A8", "A#8", "B8",
|
||||
"C9", "C#9", "D9", "D#9", "E9", "F9", "F#9", "G9", "G#9", "A9", "A#9", "B9",
|
||||
"C10", "C#10", "D10", "D#10", "E10", "F10", "F#10", "G10",
|
||||
];
|
||||
pub fn pitch_to_name (n: usize) -> &'static str {
|
||||
if n > 127 {
|
||||
panic!("to_note_name({n}): must be 0-127");
|
||||
}
|
||||
Self::NAMES[n]
|
||||
}
|
||||
}
|
||||
79
engine/note/note_point.rs
Normal file
79
engine/note/note_point.rs
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
use crate::*;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MidiPointModel {
|
||||
/// Time coordinate of cursor
|
||||
pub time_pos: Arc<AtomicUsize>,
|
||||
/// Note coordinate of cursor
|
||||
pub note_pos: 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_pos: Arc::new(0.into()),
|
||||
note_pos: Arc::new(36.into()),
|
||||
note_len: Arc::new(24.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NotePoint for MidiPointModel {
|
||||
fn note_len (&self) -> &AtomicUsize {
|
||||
&self.note_len
|
||||
}
|
||||
fn note_pos (&self) -> &AtomicUsize {
|
||||
&self.note_pos
|
||||
}
|
||||
}
|
||||
|
||||
impl TimePoint for MidiPointModel {
|
||||
fn time_pos (&self) -> &AtomicUsize {
|
||||
self.time_pos.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait NotePoint {
|
||||
fn note_len (&self) -> &AtomicUsize;
|
||||
/// Get the current length of the note cursor.
|
||||
fn get_note_len (&self) -> usize {
|
||||
self.note_len().load(Relaxed)
|
||||
}
|
||||
/// Set the length of the note cursor, returning the previous value.
|
||||
fn set_note_len (&self, x: usize) -> usize {
|
||||
self.note_len().swap(x, Relaxed)
|
||||
}
|
||||
|
||||
fn note_pos (&self) -> &AtomicUsize;
|
||||
/// Get the current pitch of the note cursor.
|
||||
fn get_note_pos (&self) -> usize {
|
||||
self.note_pos().load(Relaxed).min(127)
|
||||
}
|
||||
/// Set the current pitch fo the note cursor, returning the previous value.
|
||||
fn set_note_pos (&self, x: usize) -> usize {
|
||||
self.note_pos().swap(x.min(127), Relaxed)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TimePoint {
|
||||
fn time_pos (&self) -> &AtomicUsize;
|
||||
/// Get the current time position of the note cursor.
|
||||
fn get_time_pos (&self) -> usize {
|
||||
self.time_pos().load(Relaxed)
|
||||
}
|
||||
/// Set the current time position of the note cursor, returning the previous value.
|
||||
fn set_time_pos (&self, x: usize) -> usize {
|
||||
self.time_pos().swap(x, Relaxed)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MidiPoint: NotePoint + TimePoint {
|
||||
/// Get the current end of the note cursor.
|
||||
fn get_note_end (&self) -> usize {
|
||||
self.get_time_pos() + self.get_note_len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: NotePoint + TimePoint> MidiPoint for T {}
|
||||
98
engine/note/note_range.rs
Normal file
98
engine/note/note_range.rs
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
use crate::*;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
#[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 get_time_len (&self) -> usize {
|
||||
self.time_len().load(Ordering::Relaxed)
|
||||
}
|
||||
fn time_zoom (&self) -> &AtomicUsize;
|
||||
fn get_time_zoom (&self) -> usize {
|
||||
self.time_zoom().load(Ordering::Relaxed)
|
||||
}
|
||||
fn set_time_zoom (&self, value: usize) -> usize {
|
||||
self.time_zoom().swap(value, Ordering::Relaxed)
|
||||
}
|
||||
fn time_lock (&self) -> &AtomicBool;
|
||||
fn get_time_lock (&self) -> bool {
|
||||
self.time_lock().load(Ordering::Relaxed)
|
||||
}
|
||||
fn set_time_lock (&self, value: bool) -> bool {
|
||||
self.time_lock().swap(value, Ordering::Relaxed)
|
||||
}
|
||||
fn time_start (&self) -> &AtomicUsize;
|
||||
fn get_time_start (&self) -> usize {
|
||||
self.time_start().load(Ordering::Relaxed)
|
||||
}
|
||||
fn set_time_start (&self, value: usize) -> usize {
|
||||
self.time_start().swap(value, Ordering::Relaxed)
|
||||
}
|
||||
fn time_axis (&self) -> &AtomicUsize;
|
||||
fn get_time_axis (&self) -> usize {
|
||||
self.time_axis().load(Ordering::Relaxed)
|
||||
}
|
||||
fn get_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 get_note_lo (&self) -> usize {
|
||||
self.note_lo().load(Ordering::Relaxed)
|
||||
}
|
||||
fn set_note_lo (&self, x: usize) -> usize {
|
||||
self.note_lo().swap(x, Ordering::Relaxed)
|
||||
}
|
||||
fn note_axis (&self) -> &AtomicUsize;
|
||||
fn get_note_axis (&self) -> usize {
|
||||
self.note_axis().load(Ordering::Relaxed)
|
||||
}
|
||||
fn get_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 }
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue