use crate::prelude::*;
use std::hash::Hash;
#[cfg(feature = "midly")]
use midly::num::{u4, u7};
#[derive(Clone, Copy, Debug)]
pub enum NoteEvent<K: Eq + Hash + Clone, D> {
Add { key: K, data: D },
Stop { key: K },
Skip,
}
#[derive(Clone, Copy)]
pub struct Note<D: Clone> {
pub start: unt::Time,
pub length: Option<unt::Time>,
pub data: D,
}
impl<D: Clone> Note<D> {
pub const fn new_raw(start: unt::Time, length: Option<unt::Time>, data: D) -> Self {
Self {
start,
length,
data,
}
}
pub const fn new(start: unt::Time, length: unt::Time, data: D) -> Self {
Self::new_raw(start, Some(length), data)
}
pub const fn new_trailing(start: unt::Time, data: D) -> Self {
Self::new_raw(start, None, data)
}
pub fn end(&self) -> Option<unt::Time> {
self.length.map(|t| t + self.start)
}
pub fn map_data<E: Clone, F: FnOnce(D) -> E>(self, func: F) -> Note<E> {
Note::new_raw(self.start, self.length, func(self.data))
}
pub fn start_event<K: Eq + Hash + Clone>(&self, key: K) -> (unt::Time, NoteEvent<K, D>) {
(
self.start,
NoteEvent::Add {
key,
data: self.data.clone(),
},
)
}
pub fn end_event<K: Eq + Hash + Clone>(&self, key: K) -> Option<(unt::Time, NoteEvent<K, D>)> {
self.end().map(|end| (end, NoteEvent::Stop { key }))
}
}
#[derive(Clone, Copy, Debug)]
#[cfg(feature = "midly")]
pub struct MidiNoteData {
pub channel: u4,
pub key: u7,
pub vel: u7,
}
#[cfg(feature = "midly")]
impl MidiNoteData {
#[must_use]
pub const fn new(channel: u4, key: u7, vel: u7) -> Self {
Self { channel, key, vel }
}
}
#[derive(Clone, Debug)]
pub struct NoteReader<K: Eq + Hash + Clone, D: Clone, F: Map<Input = D>>
where
F::Output: Frequency + Stop + Done,
{
pub events: Vec<NoteEvent<K, D>>,
pub index: usize,
pub func: F,
}
impl<K: Eq + Hash + Clone, D: Clone, F: Map<Input = D>> NoteReader<K, D, F>
where
F::Output: Frequency + Stop + Done,
{
#[must_use]
pub const fn new(events: Vec<NoteEvent<K, D>>, func: F) -> Self {
Self {
events,
index: 0,
func,
}
}
#[must_use]
pub fn current(&self) -> &NoteEvent<K, D> {
&self.events[self.index]
}
#[must_use]
pub fn len(&self) -> usize {
self.events.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.events.is_empty()
}
}
impl<K: Eq + Hash + Clone, D: Clone, F: Map<Input = D>> map::Mut<gen::Polyphony<K, F::Output>>
for NoteReader<K, D, F>
where
F::Output: Frequency + Stop + Done,
{
fn modify(&mut self, sgn: &mut gen::Polyphony<K, F::Output>) {
match self.current() {
NoteEvent::Add { key, data } => sgn.add(key.clone(), self.func.eval(data.clone())),
NoteEvent::Stop { key } => {
sgn.stop(key);
}
NoteEvent::Skip => {}
}
crate::mod_inc(self.len(), &mut self.index);
}
}
pub type MelSeq<K, D, F> = ctr::Seq<gen::Polyphony<K, <F as Map>::Output>, NoteReader<K, D, F>>;
pub type MelLoop<K, D, F> = ctr::Loop<gen::Polyphony<K, <F as Map>::Output>, NoteReader<K, D, F>>;
#[derive(Clone, Debug)]
pub struct Melody<K: Eq + Hash + Clone, D: Clone> {
pub times: Vec<unt::Time>,
pub events: Vec<NoteEvent<K, D>>,
}
impl<K: Eq + Hash + Clone, D: Clone> Melody<K, D> {
#[must_use]
pub const fn new(times: Vec<unt::Time>, events: Vec<NoteEvent<K, D>>) -> Self {
Self { times, events }
}
pub fn piano_roll<N: IntoIterator<Item = Note<D>>, G: FnMut(usize) -> K>(
notes: N,
mut idx_cast: G,
) -> Self {
let notes = notes.into_iter();
let event_len = 2 * notes.size_hint().0;
let mut time_events = Vec::with_capacity(event_len);
for (idx, note) in notes.enumerate() {
let note_idx = idx_cast(idx);
time_events.push(note.start_event(note_idx.clone()));
if let Some(end_event) = note.end_event(note_idx) {
time_events.push(end_event);
}
}
time_events.sort_by_key(|(time, _)| *time);
let mut last_time = unt::Time::ZERO;
let mut times = Vec::with_capacity(event_len);
let mut events = Vec::with_capacity(event_len);
for (time, event) in time_events {
times.push(time - last_time);
last_time = time;
events.push(event);
}
Self::new(times, events)
}
pub fn piano_roll_loop<N: IntoIterator<Item = Note<D>>, G: FnMut(usize) -> K>(
notes: N,
length: unt::Time,
mut idx_cast: G,
) -> Self {
let notes = notes.into_iter();
let event_len = 2 * notes.size_hint().0;
let mut time_events = Vec::with_capacity(event_len);
for (idx, note) in notes.enumerate() {
let note_idx = idx_cast(idx);
time_events.push(note.start_event(note_idx.clone()));
if let Some((time, event)) = note.end_event(note_idx) {
time_events.push((time % length, event));
}
}
time_events.sort_by_key(|(time, _)| *time);
let last_time = time_events.last().expect("notes can't be empty").0;
let mut prev_time = unt::Time::ZERO;
let mut times = Vec::with_capacity(event_len + 1);
let mut events = Vec::with_capacity(event_len + 1);
for (time, event) in time_events {
times.push(time - prev_time);
prev_time = time;
events.push(event);
}
times.push(length - last_time);
events.push(NoteEvent::Skip);
Self::new(times, events)
}
}
#[cfg(feature = "midly")]
impl<K: Eq + Hash + Clone> Melody<K, MidiNoteData> {
pub fn from_midi<G: FnMut(usize) -> K>(
event_iter: midly::EventIter,
tick_time: unt::Time,
mut idx_cast: G,
) -> midly::Result<Self> {
let mut times = Vec::new();
let mut events = Vec::new();
let mut latest = [usize::MAX; 128 * 16];
let mut idx = 0;
let mut since_last = 0;
for event in event_iter {
let event = event?;
since_last += event.delta.as_int();
if let midly::TrackEventKind::Midi { channel, message } = event.kind {
let index = |key: u7| 128 * (channel.as_int() as usize) + key.as_int() as usize;
let mut stop = |key: u7| {
events.push(NoteEvent::Stop {
key: idx_cast(latest[index(key)]),
});
times.push(since_last * tick_time);
since_last = 0;
};
match message {
midly::MidiMessage::NoteOn { key, vel } => {
stop(key);
if vel != u7::new(0) {
events.push(NoteEvent::Add {
key: idx_cast(idx),
data: MidiNoteData::new(channel, key, vel),
});
times.push(unt::Time::ZERO);
latest[index(key)] = idx;
idx += 1;
}
}
midly::MidiMessage::NoteOff { key, vel: _ } => {
stop(key);
}
_ => {}
}
}
}
Ok(Self::new(times, events))
}
pub fn from_midi_loop<G: FnMut(usize) -> K>(
event_iter: midly::EventIter,
length: unt::Time,
tick_time: unt::Time,
idx_cast: G,
) -> midly::Result<Self> {
let mut melody = Self::from_midi(event_iter, tick_time, idx_cast)?;
let last_time = melody.times.iter().copied().sum();
melody.times.push(length - last_time);
melody.events.push(NoteEvent::Skip);
Ok(melody)
}
}
impl<K: Eq + Hash + Clone, D: Clone, F: Map<Input = D>> MelSeq<K, D, F>
where
F::Output: Frequency + Stop + Done,
{
pub fn new_note_reader(times: Vec<unt::Time>, note_reader: NoteReader<K, D, F>) -> Self {
Self::new(times, gen::Polyphony::new(), note_reader)
}
pub fn new_melody(melody: Melody<K, D>, func: F) -> Self {
Self::new_note_reader(melody.times, NoteReader::new(melody.events, func))
}
pub const fn note_reader(&self) -> &NoteReader<K, D, F> {
self.func()
}
pub fn note_reader_mut(&mut self) -> &mut NoteReader<K, D, F> {
self.func_mut()
}
}
impl<K: Eq + Hash + Clone, D: Clone, F: Map<Input = D>> MelLoop<K, D, F>
where
F::Output: Frequency + Stop + Done,
{
pub fn new_note_reader(times: Vec<unt::Time>, note_reader: NoteReader<K, D, F>) -> Self {
Self::new(times, gen::Polyphony::new(), note_reader)
}
pub fn new_melody(melody: Melody<K, D>, func: F) -> Self {
Self::new_note_reader(melody.times, NoteReader::new(melody.events, func))
}
pub const fn note_reader(&self) -> &NoteReader<K, D, F> {
self.func()
}
pub fn note_reader_mut(&mut self) -> &mut NoteReader<K, D, F> {
self.func_mut()
}
}