mirror of
https://github.com/dredozubov/polyrhythmix.git
synced 2024-11-22 03:47:43 +00:00
Compiles, untested EventIterator
This commit is contained in:
parent
c582fa08a3
commit
f5be68d0d5
4 changed files with 192 additions and 59 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -185,6 +185,12 @@ dependencies = [
|
||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dyn-clone"
|
||||||
|
version = "1.0.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.8.1"
|
version = "1.8.1"
|
||||||
|
@ -330,6 +336,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
|
"dyn-clone",
|
||||||
"midly",
|
"midly",
|
||||||
"nom",
|
"nom",
|
||||||
]
|
]
|
||||||
|
|
|
@ -13,4 +13,5 @@ path = "src/bin/main.rs"
|
||||||
nom = "*"
|
nom = "*"
|
||||||
midly = "0.5.3"
|
midly = "0.5.3"
|
||||||
derive_more = "*"
|
derive_more = "*"
|
||||||
clap = { version = "4.2.7", features = ["derive"] }
|
clap = { version = "4.2.7", features = ["derive"] }
|
||||||
|
dyn-clone = "1.0.11"
|
|
@ -1,6 +1,6 @@
|
||||||
use std::str;
|
use std::str;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
use std::ops::{Add, Mul};
|
use std::ops::{Add};
|
||||||
|
|
||||||
pub use nom::character::complete::{char, digit1};
|
pub use nom::character::complete::{char, digit1};
|
||||||
use nom::multi::many1;
|
use nom::multi::many1;
|
||||||
|
@ -110,20 +110,6 @@ pub enum Length {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
impl Add<Length> for Length {
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn add(self, rhs: Length) -> Length {
|
|
||||||
match self {
|
|
||||||
Length::Simple(mlen) => todo!(),
|
|
||||||
Length::Tied(_, _) => todo!(),
|
|
||||||
Length::Triplet(_) => todo!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum Note {
|
pub enum Note {
|
||||||
Hit,
|
Hit,
|
||||||
|
|
225
src/midi/core.rs
225
src/midi/core.rs
|
@ -1,12 +1,15 @@
|
||||||
extern crate derive_more;
|
extern crate derive_more;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::iter::Cycle;
|
||||||
|
use std::iter::Peekable;
|
||||||
use std::ops::{Add, Mul};
|
use std::ops::{Add, Mul};
|
||||||
|
use std::path::Iter;
|
||||||
|
|
||||||
use midly::{
|
use midly::{
|
||||||
num::u15, num::u24, num::u28, num::u4, num::u7, Header, MidiMessage, Smf, Track, TrackEventKind,
|
num::u15, num::u24, num::u28, num::u4, num::u7, Header, MidiMessage, Smf, Track, TrackEventKind,
|
||||||
};
|
};
|
||||||
use midly::{MetaMessage, TrackEvent};
|
use midly::{EventIter, MetaMessage, TrackEvent};
|
||||||
|
|
||||||
use crate::dsl::dsl::{
|
use crate::dsl::dsl::{
|
||||||
group_or_delimited_group, groups, BasicLength, Group, GroupOrNote, Length, ModdedLength, Note,
|
group_or_delimited_group, groups, BasicLength, Group, GroupOrNote, Length, ModdedLength, Note,
|
||||||
|
@ -25,6 +28,7 @@ use crate::dsl::dsl::{
|
||||||
derive_more::Add,
|
derive_more::Add,
|
||||||
derive_more::Sub,
|
derive_more::Sub,
|
||||||
derive_more::Mul,
|
derive_more::Mul,
|
||||||
|
derive_more::Rem,
|
||||||
derive_more::Display,
|
derive_more::Display,
|
||||||
)]
|
)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
|
@ -181,7 +185,7 @@ fn test_converges() {
|
||||||
denominator: BasicLength::Fourth,
|
denominator: BasicLength::Fourth,
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
three_sixteenth.converges(vec![four_fourth, three_fourth]),
|
three_sixteenth.converges(vec![four_fourth, three_fourth, four_fourth]),
|
||||||
Ok((3, four_fourth))
|
Ok((3, four_fourth))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -219,6 +223,30 @@ pub struct EventGrid<T> {
|
||||||
length: Tick,
|
length: Tick,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> IntoIterator for EventGrid<T> {
|
||||||
|
type Item = Event<T>;
|
||||||
|
type IntoIter = std::vec::IntoIter<Event<T>>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.events.into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> EventGrid<T> {
|
||||||
|
pub fn iter(&self) -> std::slice::Iter<'_, Event<T>> {
|
||||||
|
self.events.iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl <T> Iterator for EventGrid<T> {
|
||||||
|
// type Item = Event<T>;
|
||||||
|
|
||||||
|
// fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
// let e = self.events.iter().next();
|
||||||
|
// e.map(|x| *x )
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
impl<T: Add<Tick, Output = T> + Clone + Ord> Add for EventGrid<T> {
|
impl<T: Add<Tick, Output = T> + Clone + Ord> Add for EventGrid<T> {
|
||||||
type Output = EventGrid<T>;
|
type Output = EventGrid<T>;
|
||||||
|
|
||||||
|
@ -606,7 +634,7 @@ fn test_cycle_grid() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flatten_groups(part: Part, groups: Vec<Group>) -> EventGrid<Tick> {
|
fn flatten_groups(part: Part, groups: &Vec<Group>) -> EventGrid<Tick> {
|
||||||
let mut time: Tick = Tick(0);
|
let mut time: Tick = Tick(0);
|
||||||
let mut grid: EventGrid<Tick> = EventGrid::new();
|
let mut grid: EventGrid<Tick> = EventGrid::new();
|
||||||
groups.iter().for_each(|group| {
|
groups.iter().for_each(|group| {
|
||||||
|
@ -616,8 +644,7 @@ fn flatten_groups(part: Part, groups: Vec<Group>) -> EventGrid<Tick> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Combines a vector of sorted EventGrid<Tick> into a single `EventGrid<Tick>`
|
// Combines a vector of sorted EventGrid<Tick> into a single `EventGrid<Tick>`
|
||||||
fn merge_event_grids(mut eg: Vec<EventGrid<Tick>>) -> EventGrid<Tick>
|
fn merge_event_grids(mut eg: Vec<EventGrid<Tick>>) -> EventGrid<Tick> {
|
||||||
{
|
|
||||||
let first = eg.pop().unwrap();
|
let first = eg.pop().unwrap();
|
||||||
eg.iter().fold(first, |mut acc, next| {
|
eg.iter().fold(first, |mut acc, next| {
|
||||||
acc = acc * (*next).clone();
|
acc = acc * (*next).clone();
|
||||||
|
@ -625,18 +652,129 @@ fn merge_event_grids(mut eg: Vec<EventGrid<Tick>>) -> EventGrid<Tick>
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns time as a number of ticks from beginning, has to be turned into the midi delta-time.
|
pub struct EventIterator<T>
|
||||||
fn flatten_and_merge(groups: HashMap<Part, Vec<Group>>) -> EventGrid<Tick> {
|
where
|
||||||
let mut eg = Vec::new();
|
T:Clone
|
||||||
for (part, group) in groups {
|
{
|
||||||
eg.push(flatten_groups(part, group))
|
kick: Peekable<Cycle<std::vec::IntoIter<Event<T>>>>,
|
||||||
|
snare: Peekable<Cycle<std::vec::IntoIter<Event<T>>>>,
|
||||||
|
hihat: Peekable<Cycle<std::vec::IntoIter<Event<T>>>>,
|
||||||
|
crash: Peekable<Cycle<std::vec::IntoIter<Event<T>>>>,
|
||||||
|
kick_length: Tick,
|
||||||
|
snare_length: Tick,
|
||||||
|
hihat_length: Tick,
|
||||||
|
crash_length: Tick,
|
||||||
|
limit: Tick,
|
||||||
|
time: Tick
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> EventIterator<T>
|
||||||
|
where
|
||||||
|
T: Clone
|
||||||
|
{
|
||||||
|
fn new(
|
||||||
|
kick_grid: EventGrid<T>,
|
||||||
|
snare_grid: EventGrid<T>,
|
||||||
|
hihat_grid: EventGrid<T>,
|
||||||
|
crash_grid: EventGrid<T>,
|
||||||
|
limit_value: Tick,
|
||||||
|
) -> EventIterator<T> {
|
||||||
|
let event_iterator = EventIterator {
|
||||||
|
kick_length: kick_grid.length.clone(),
|
||||||
|
snare_length: snare_grid.length.clone(),
|
||||||
|
hihat_length: hihat_grid.length.clone(),
|
||||||
|
crash_length: crash_grid.length.clone(),
|
||||||
|
kick: kick_grid.into_iter().cycle().peekable(),
|
||||||
|
snare: snare_grid.into_iter().cycle().peekable(),
|
||||||
|
hihat: hihat_grid.into_iter().cycle().peekable(),
|
||||||
|
crash: crash_grid.into_iter().cycle().peekable(),
|
||||||
|
limit: limit_value,
|
||||||
|
time: Tick(0)
|
||||||
|
};
|
||||||
|
event_iterator
|
||||||
}
|
}
|
||||||
merge_event_grids(eg)
|
}
|
||||||
|
|
||||||
|
impl Iterator for EventIterator<Tick> {
|
||||||
|
type Item = Event<Tick>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let mut min_part = Part::KickDrum;
|
||||||
|
let mut min_tick = self.limit;
|
||||||
|
let mut min_event: Event<Tick> = Event { tick: Tick(0), event_type: EventType::NoteOn(Part::KickDrum) };
|
||||||
|
let mut min_group_length: Tick;
|
||||||
|
let candidates = vec![
|
||||||
|
(self.kick.peek().unwrap(), Part::KickDrum),
|
||||||
|
(self.snare.peek().unwrap(), Part::SnareDrum),
|
||||||
|
(self.hihat.peek().unwrap(), Part::HiHat),
|
||||||
|
(self.crash.peek().unwrap(), Part::CrashCymbal),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (&e, p) in candidates {
|
||||||
|
if e.tick <= min_tick {
|
||||||
|
min_part = p;
|
||||||
|
min_tick = e.tick;
|
||||||
|
min_event = e;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match min_part {
|
||||||
|
Part::KickDrum => {
|
||||||
|
self.kick.next();
|
||||||
|
min_group_length = self.kick_length;
|
||||||
|
},
|
||||||
|
Part::SnareDrum => {
|
||||||
|
self.snare.next();
|
||||||
|
min_group_length = self.snare_length;
|
||||||
|
},
|
||||||
|
Part::HiHat => {
|
||||||
|
self.hihat.next();
|
||||||
|
min_group_length = self.hihat_length;
|
||||||
|
},
|
||||||
|
Part::CrashCymbal => {
|
||||||
|
self.crash.next();
|
||||||
|
min_group_length = self.crash_length;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if min_event.tick < self.limit {
|
||||||
|
self.time = self.time + min_event.tick;
|
||||||
|
if self.time > min_group_length {
|
||||||
|
let remainder = Tick(self.time.0 % min_group_length.0);
|
||||||
|
min_event.tick = self.time + remainder;
|
||||||
|
Some(min_event)
|
||||||
|
} else {
|
||||||
|
Some(min_event)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns time as a number of ticks from beginning, has to be turned into the midi delta-time.
|
||||||
|
fn flatten_and_merge<'a>(
|
||||||
|
mut groups: HashMap<Part, Vec<Group>>,
|
||||||
|
time_signature: TimeSignature,
|
||||||
|
) -> EventIterator<Tick> {
|
||||||
|
let f = |p| {
|
||||||
|
groups
|
||||||
|
.get(&p)
|
||||||
|
.map(|g| flatten_groups(p, g))
|
||||||
|
.unwrap_or(EventGrid::new())
|
||||||
|
};
|
||||||
|
let kick = f(Part::KickDrum);
|
||||||
|
let snare = f(Part::SnareDrum);
|
||||||
|
let hihat = f(Part::HiHat);
|
||||||
|
let crash = f(Part::CrashCymbal);
|
||||||
|
EventIterator::new(kick, snare, hihat, crash, Tick(1000000))
|
||||||
}
|
}
|
||||||
|
|
||||||
// The length of a beat is not standard, so in order to fully describe the length of a MIDI tick the MetaMessage::Tempo event should be present.
|
// The length of a beat is not standard, so in order to fully describe the length of a MIDI tick the MetaMessage::Tempo event should be present.
|
||||||
pub fn create_smf<'a>(groups: HashMap<Part, Vec<Group>>, time_signature: TimeSignature) -> Smf<'a> {
|
pub fn create_smf<'a>(groups: HashMap<Part, Vec<Group>>, time_signature: TimeSignature) -> Smf<'a> {
|
||||||
let tracks = create_tracks(groups, time_signature); // FIXME
|
let tracks = vec![] ; // create_tracks(groups, time_signature); // FIXME
|
||||||
// https://majicdesigns.github.io/MD_MIDIFile/page_timing.html
|
// https://majicdesigns.github.io/MD_MIDIFile/page_timing.html
|
||||||
// says " If it is not specified the MIDI default is 48 ticks per quarter note."
|
// says " If it is not specified the MIDI default is 48 ticks per quarter note."
|
||||||
// As it's required in `Header`, let's use the same value.
|
// As it's required in `Header`, let's use the same value.
|
||||||
|
@ -650,35 +788,36 @@ pub fn create_smf<'a>(groups: HashMap<Part, Vec<Group>>, time_signature: TimeSig
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Translates drum parts to a single MIDI track.
|
// /// Translates drum parts to a single MIDI track.
|
||||||
fn create_tracks<'a>(
|
// fn create_tracks<'a>(
|
||||||
parts_and_groups: HashMap<Part, Vec<Group>>,
|
// parts_and_groups: HashMap<Part, Vec<Group>>,
|
||||||
time_signature: TimeSignature, // tempo: u32
|
// time_signature: TimeSignature, // tempo: u32
|
||||||
) -> Vec<Vec<midly::TrackEvent<'a>>> {
|
// ) -> Vec<Vec<midly::TrackEvent<'a>>> {
|
||||||
let event_grid = flatten_and_merge(parts_and_groups).to_delta();
|
// //FIXME: unhardcode time signature
|
||||||
let mut drums = Vec::new();
|
// let event_grid = flatten_and_merge(parts_and_groups, TimeSignature { numerator: 4, denominator: BasicLength::Fourth );
|
||||||
// let midi_tempo = MidiTempo::from_tempo(Tempo(130)).0;
|
// let mut drums = Vec::new();
|
||||||
// drums.push(TrackEvent { delta: u28::from(0), kind: TrackEventKind::Meta(MetaMessage::Tempo(midi_tempo)) });
|
// // let midi_tempo = MidiTempo::from_tempo(Tempo(130)).0;
|
||||||
// drums.push(TrackEvent { delta: u28::from(0), kind: TrackEventKind::Meta(MetaMessage::TimeSignature(4, 4, MIDI_CLOCKS_PER_CLICK.clone(), 8))});
|
// // drums.push(TrackEvent { delta: u28::from(0), kind: TrackEventKind::Meta(MetaMessage::Tempo(midi_tempo)) });
|
||||||
for event in event_grid.events {
|
// // drums.push(TrackEvent { delta: u28::from(0), kind: TrackEventKind::Meta(MetaMessage::TimeSignature(4, 4, MIDI_CLOCKS_PER_CLICK.clone(), 8))});
|
||||||
let midi_message = match event.event_type {
|
// for event in event_grid.events {
|
||||||
EventType::NoteOn(part) => MidiMessage::NoteOn {
|
// let midi_message = match event.event_type {
|
||||||
key: part.to_midi_key(),
|
// EventType::NoteOn(part) => MidiMessage::NoteOn {
|
||||||
vel: u7::from(120),
|
// key: part.to_midi_key(),
|
||||||
},
|
// vel: u7::from(120),
|
||||||
EventType::NoteOff(part) => MidiMessage::NoteOff {
|
// },
|
||||||
key: part.to_midi_key(),
|
// EventType::NoteOff(part) => MidiMessage::NoteOff {
|
||||||
vel: u7::from(0),
|
// key: part.to_midi_key(),
|
||||||
},
|
// vel: u7::from(0),
|
||||||
};
|
// },
|
||||||
drums.push(TrackEvent {
|
// };
|
||||||
delta: u28::from(event.tick.0 as u32),
|
// drums.push(TrackEvent {
|
||||||
kind: TrackEventKind::Midi {
|
// delta: u28::from(event.tick.0 as u32),
|
||||||
channel: u4::from(10),
|
// kind: TrackEventKind::Midi {
|
||||||
message: midi_message,
|
// channel: u4::from(10),
|
||||||
},
|
// message: midi_message,
|
||||||
})
|
// },
|
||||||
}
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
vec![drums]
|
// vec![drums]
|
||||||
}
|
// }
|
||||||
|
|
Loading…
Reference in a new issue