Compiles, untested EventIterator

This commit is contained in:
Denis Redozubov 2023-05-15 19:45:36 +04:00
parent c582fa08a3
commit f5be68d0d5
4 changed files with 192 additions and 59 deletions

7
Cargo.lock generated
View file

@ -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",
] ]

View file

@ -14,3 +14,4 @@ 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"

View file

@ -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,

View file

@ -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]
} // }