wip: refactor pt.41 (57e) nice

This commit is contained in:
🪞👃🪞 2024-11-15 20:09:49 +01:00
parent c875d87c33
commit 8856353eab
32 changed files with 911 additions and 1019 deletions

View file

@ -1 +1,141 @@
use crate::*;
pub trait HasPhrases {
fn phrases (&self) -> &Vec<Arc<RwLock<Phrase>>>;
fn phrases_mut (&mut self) -> &mut Vec<Arc<RwLock<Phrase>>>;
}
#[derive(Clone, PartialEq)]
pub enum PhrasePoolCommand {
Add(usize),
Delete(usize),
Duplicate(usize),
Swap(usize, usize),
RandomColor(usize),
Import(usize, String),
Export(usize, String),
SetName(usize, String),
SetLength(usize, usize),
}
impl<T: HasPhrases> Command<T> for PhrasePoolCommand {
fn execute (self, model: &mut T) -> Perhaps<Self> {
match self {
Self::Add(index) => {
//Self::Append => { view.append_new(None, None) },
//Self::Insert => { view.insert_new(None, None) },
},
Self::Delete(index) => {
//if view.phrase > 0 {
//view.model.phrases.remove(view.phrase);
//view.phrase = view.phrase.min(view.model.phrases.len().saturating_sub(1));
//}
},
Self::Duplicate(index) => {
//let mut phrase = view.phrase().read().unwrap().duplicate();
//phrase.color = ItemColorTriplet::random_near(phrase.color, 0.25);
//view.phrases.insert(view.phrase + 1, Arc::new(RwLock::new(phrase)));
//view.phrase += 1;
},
Self::Swap(index, other) => {
//Self::MoveUp => { view.move_up() },
//Self::MoveDown => { view.move_down() },
},
Self::RandomColor(index) => {
//view.phrase().write().unwrap().color = ItemColorTriplet::random();
},
Self::Import(index, path) => {
},
Self::Export(index, path) => {
},
Self::SetName(index, name) => {
},
Self::SetLength(index, length) => {
},
}
Ok(None)
}
}
/// A MIDI sequence.
#[derive(Debug, Clone)]
pub struct Phrase {
pub uuid: uuid::Uuid,
/// Name of phrase
pub name: String,
/// Temporal resolution in pulses per quarter note
pub ppq: usize,
/// Length of phrase in pulses
pub length: usize,
/// Notes in phrase
pub notes: PhraseData,
/// Whether to loop the phrase or play it once
pub loop_on: 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: ItemColorTriplet,
}
/// MIDI message structural
pub type PhraseData = Vec<Vec<MidiMessage>>;
impl Phrase {
pub fn new (
name: impl AsRef<str>,
loop_on: bool,
length: usize,
notes: Option<PhraseData>,
color: Option<ItemColorTriplet>,
) -> Self {
Self {
uuid: uuid::Uuid::new_v4(),
name: name.as_ref().to_string(),
ppq: PPQ,
length,
notes: notes.unwrap_or(vec![Vec::with_capacity(16);length]),
loop_on,
loop_start: 0,
loop_length: length,
percussive: true,
color: color.unwrap_or_else(ItemColorTriplet::random)
}
}
pub fn duplicate (&self) -> Self {
let mut clone = self.clone();
clone.uuid = uuid::Uuid::new_v4();
clone
}
pub fn toggle_loop (&mut self) { self.loop_on = !self.loop_on; }
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 {
//panic!("{:?} {start} {end}", &self);
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 } }
}
}
return false
}
}
impl Default for Phrase {
fn default () -> Self {
Self::new("(empty)", false, 0, None, Some(ItemColor::from(Color::Rgb(0, 0, 0)).into()))
}
}
impl PartialEq for Phrase {
fn eq (&self, other: &Self) -> bool {
self.uuid == other.uuid
}
}
impl Eq for Phrase {}