mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-08 12:46:42 +01:00
wip: modularize once again
This commit is contained in:
parent
e08c9d1790
commit
3b6ff81dad
44 changed files with 984 additions and 913 deletions
|
|
@ -1,109 +0,0 @@
|
|||
use crate::*;
|
||||
|
||||
pub trait HasMidiClip {
|
||||
fn phrase (&self) -> &Arc<RwLock<MidiClip>>;
|
||||
}
|
||||
|
||||
#[macro_export] macro_rules! has_phrase {
|
||||
(|$self:ident:$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)?|$cb:expr) => {
|
||||
impl $(<$($L),*$($T $(: $U)?),*>)? HasMidiClip for $Struct $(<$($L),*$($T),*>)? {
|
||||
fn phrase (&$self) -> &Arc<RwLock<MidiClip>> { &$cb }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A MIDI sequence.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MidiClip {
|
||||
pub uuid: uuid::Uuid,
|
||||
/// Name of phrase
|
||||
pub name: Arc<str>,
|
||||
/// Temporal resolution in pulses per quarter note
|
||||
pub ppq: usize,
|
||||
/// Length of phrase in pulses
|
||||
pub length: usize,
|
||||
/// Notes in phrase
|
||||
pub notes: MidiData,
|
||||
/// Whether to loop the phrase or play it once
|
||||
pub looped: bool,
|
||||
/// Start of loop
|
||||
pub loop_start: usize,
|
||||
/// Length of loop
|
||||
pub loop_length: usize,
|
||||
/// All notes are displayed with minimum length
|
||||
pub percussive: bool,
|
||||
/// Identifying color of phrase
|
||||
pub color: ItemPalette,
|
||||
}
|
||||
|
||||
/// MIDI message structural
|
||||
pub type MidiData = Vec<Vec<MidiMessage>>;
|
||||
|
||||
impl MidiClip {
|
||||
pub fn new (
|
||||
name: impl AsRef<str>,
|
||||
looped: bool,
|
||||
length: usize,
|
||||
notes: Option<MidiData>,
|
||||
color: Option<ItemPalette>,
|
||||
) -> Self {
|
||||
Self {
|
||||
uuid: uuid::Uuid::new_v4(),
|
||||
name: name.as_ref().into(),
|
||||
ppq: PPQ,
|
||||
length,
|
||||
notes: notes.unwrap_or(vec![Vec::with_capacity(16);length]),
|
||||
looped,
|
||||
loop_start: 0,
|
||||
loop_length: length,
|
||||
percussive: true,
|
||||
color: color.unwrap_or_else(ItemPalette::random)
|
||||
}
|
||||
}
|
||||
pub fn set_length (&mut self, length: usize) {
|
||||
self.length = length;
|
||||
self.notes = vec![Vec::with_capacity(16);length];
|
||||
}
|
||||
pub fn duplicate (&self) -> Self {
|
||||
let mut clone = self.clone();
|
||||
clone.uuid = uuid::Uuid::new_v4();
|
||||
clone
|
||||
}
|
||||
pub fn toggle_loop (&mut self) { self.looped = !self.looped; }
|
||||
pub fn record_event (&mut self, pulse: usize, message: MidiMessage) {
|
||||
if pulse >= self.length { panic!("extend phrase first") }
|
||||
self.notes[pulse].push(message);
|
||||
}
|
||||
/// Check if a range `start..end` contains MIDI Note On `k`
|
||||
pub fn contains_note_on (&self, k: u7, start: usize, end: usize) -> bool {
|
||||
for events in self.notes[start.max(0)..end.min(self.notes.len())].iter() {
|
||||
for event in events.iter() {
|
||||
if let MidiMessage::NoteOn {key,..} = event { if *key == k { return true } }
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MidiClip {
|
||||
fn default () -> Self {
|
||||
Self::new(
|
||||
"Stop",
|
||||
false,
|
||||
1,
|
||||
Some(vec![vec![MidiMessage::Controller {
|
||||
controller: 123.into(),
|
||||
value: 0.into()
|
||||
}]]),
|
||||
Some(ItemColor::from(Color::Rgb(32, 32, 32)).into())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for MidiClip {
|
||||
fn eq (&self, other: &Self) -> bool {
|
||||
self.uuid == other.uuid
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for MidiClip {}
|
||||
Loading…
Add table
Add a link
Reference in a new issue