mirror of
https://github.com/dredozubov/polyrhythmix.git
synced 2024-11-22 11:57:43 +00:00
EventIterator in progress
This commit is contained in:
parent
f5be68d0d5
commit
a94a2d331a
1 changed files with 296 additions and 102 deletions
398
src/midi/core.rs
398
src/midi/core.rs
|
@ -52,6 +52,15 @@ pub enum EventType {
|
||||||
NoteOff(Part),
|
NoteOff(Part),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl EventType {
|
||||||
|
fn is_note_on(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
EventType::NoteOn(_) => true,
|
||||||
|
EventType::NoteOff(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct TimeSignature {
|
pub struct TimeSignature {
|
||||||
pub numerator: u8,
|
pub numerator: u8,
|
||||||
|
@ -643,42 +652,27 @@ fn flatten_groups(part: Part, groups: &Vec<Group>) -> EventGrid<Tick> {
|
||||||
grid
|
grid
|
||||||
}
|
}
|
||||||
|
|
||||||
// Combines a vector of sorted EventGrid<Tick> into a single `EventGrid<Tick>`
|
pub struct EventIterator {
|
||||||
fn merge_event_grids(mut eg: Vec<EventGrid<Tick>>) -> EventGrid<Tick> {
|
kick: Peekable<Cycle<std::vec::IntoIter<Event<Tick>>>>,
|
||||||
let first = eg.pop().unwrap();
|
snare: Peekable<Cycle<std::vec::IntoIter<Event<Tick>>>>,
|
||||||
eg.iter().fold(first, |mut acc, next| {
|
hihat: Peekable<Cycle<std::vec::IntoIter<Event<Tick>>>>,
|
||||||
acc = acc * (*next).clone();
|
crash: Peekable<Cycle<std::vec::IntoIter<Event<Tick>>>>,
|
||||||
acc
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct EventIterator<T>
|
|
||||||
where
|
|
||||||
T:Clone
|
|
||||||
{
|
|
||||||
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,
|
kick_length: Tick,
|
||||||
snare_length: Tick,
|
snare_length: Tick,
|
||||||
hihat_length: Tick,
|
hihat_length: Tick,
|
||||||
crash_length: Tick,
|
crash_length: Tick,
|
||||||
limit: Tick,
|
limit: Tick,
|
||||||
time: Tick
|
time: Tick,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> EventIterator<T>
|
impl EventIterator {
|
||||||
where
|
|
||||||
T: Clone
|
|
||||||
{
|
|
||||||
fn new(
|
fn new(
|
||||||
kick_grid: EventGrid<T>,
|
kick_grid: EventGrid<Tick>,
|
||||||
snare_grid: EventGrid<T>,
|
snare_grid: EventGrid<Tick>,
|
||||||
hihat_grid: EventGrid<T>,
|
hihat_grid: EventGrid<Tick>,
|
||||||
crash_grid: EventGrid<T>,
|
crash_grid: EventGrid<Tick>,
|
||||||
limit_value: Tick,
|
limit_value: Tick,
|
||||||
) -> EventIterator<T> {
|
) -> EventIterator {
|
||||||
let event_iterator = EventIterator {
|
let event_iterator = EventIterator {
|
||||||
kick_length: kick_grid.length.clone(),
|
kick_length: kick_grid.length.clone(),
|
||||||
snare_length: snare_grid.length.clone(),
|
snare_length: snare_grid.length.clone(),
|
||||||
|
@ -689,81 +683,262 @@ where
|
||||||
hihat: hihat_grid.into_iter().cycle().peekable(),
|
hihat: hihat_grid.into_iter().cycle().peekable(),
|
||||||
crash: crash_grid.into_iter().cycle().peekable(),
|
crash: crash_grid.into_iter().cycle().peekable(),
|
||||||
limit: limit_value,
|
limit: limit_value,
|
||||||
time: Tick(0)
|
time: Tick(0),
|
||||||
};
|
};
|
||||||
event_iterator
|
event_iterator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Iterator for EventIterator<Tick> {
|
impl Iterator for EventIterator {
|
||||||
type Item = Event<Tick>;
|
type Item = (Event<Tick>, Tick);
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
println!("============");
|
||||||
|
println!("self.time: {}", self.time);
|
||||||
let mut min_part = Part::KickDrum;
|
let mut min_part = Part::KickDrum;
|
||||||
let mut min_tick = self.limit;
|
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_event: Event<Tick> = Event {
|
||||||
let mut min_group_length: Tick;
|
tick: Tick(0),
|
||||||
|
event_type: EventType::NoteOn(Part::KickDrum),
|
||||||
|
};
|
||||||
|
|
||||||
let candidates = vec![
|
let candidates = vec![
|
||||||
(self.kick.peek().unwrap(), Part::KickDrum),
|
(self.kick.peek(), Part::KickDrum),
|
||||||
(self.snare.peek().unwrap(), Part::SnareDrum),
|
(self.snare.peek(), Part::SnareDrum),
|
||||||
(self.hihat.peek().unwrap(), Part::HiHat),
|
(self.hihat.peek(), Part::HiHat),
|
||||||
(self.crash.peek().unwrap(), Part::CrashCymbal),
|
(self.crash.peek(), Part::CrashCymbal),
|
||||||
];
|
];
|
||||||
|
|
||||||
for (&e, p) in candidates {
|
println!("candidates: {:?}", candidates);
|
||||||
if e.tick <= min_tick {
|
|
||||||
min_part = p;
|
for (o, p) in candidates {
|
||||||
min_tick = e.tick;
|
match o {
|
||||||
min_event = e;
|
Some(e) => {
|
||||||
} else {
|
println!("{:?}", e);
|
||||||
continue;
|
|
||||||
|
// FIXME
|
||||||
|
// fails with:
|
||||||
|
//
|
||||||
|
// self.time: 96
|
||||||
|
// Event { tick: Tick(0), event_type: NoteOn(KickDrum) }
|
||||||
|
// e.tick <= min_tick
|
||||||
|
// Event { tick: Tick(96), event_type: NoteOff(SnareDrum) }
|
||||||
|
// continue
|
||||||
|
// Kick
|
||||||
|
// group_length: 96
|
||||||
|
// self.time = group_length
|
||||||
|
// updated self.time: 96
|
||||||
|
// self.time = self.limit
|
||||||
|
if e.tick == self.time {
|
||||||
|
println!("e.tick = self.time");
|
||||||
|
min_part = p;
|
||||||
|
min_tick = e.tick;
|
||||||
|
min_event = *e;
|
||||||
|
continue;
|
||||||
|
} else if e.tick <= min_tick {
|
||||||
|
println!("e.tick <= min_tick");
|
||||||
|
min_part = p;
|
||||||
|
min_tick = e.tick;
|
||||||
|
min_event = *e;
|
||||||
|
} else {
|
||||||
|
println!("continue");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => continue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut group_length: Tick;
|
||||||
|
|
||||||
match min_part {
|
match min_part {
|
||||||
Part::KickDrum => {
|
Part::KickDrum => {
|
||||||
|
println!("Kick");
|
||||||
self.kick.next();
|
self.kick.next();
|
||||||
min_group_length = self.kick_length;
|
group_length = self.kick_length;
|
||||||
},
|
}
|
||||||
Part::SnareDrum => {
|
Part::SnareDrum => {
|
||||||
|
println!("Snare");
|
||||||
self.snare.next();
|
self.snare.next();
|
||||||
min_group_length = self.snare_length;
|
group_length = self.snare_length;
|
||||||
},
|
}
|
||||||
Part::HiHat => {
|
Part::HiHat => {
|
||||||
self.hihat.next();
|
self.hihat.next();
|
||||||
min_group_length = self.hihat_length;
|
group_length = self.hihat_length;
|
||||||
},
|
}
|
||||||
Part::CrashCymbal => {
|
Part::CrashCymbal => {
|
||||||
self.crash.next();
|
self.crash.next();
|
||||||
min_group_length = self.crash_length;
|
group_length = self.crash_length;
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if min_event.tick < self.limit {
|
println!("group_length: {}", group_length);
|
||||||
self.time = self.time + min_event.tick;
|
self.time = match self.time.cmp(&group_length) {
|
||||||
if self.time > min_group_length {
|
Ordering::Less => {
|
||||||
let remainder = Tick(self.time.0 % min_group_length.0);
|
println!("self.time < group_length");
|
||||||
min_event.tick = self.time + remainder;
|
if min_event.tick == self.time {
|
||||||
Some(min_event)
|
println!(
|
||||||
} else {
|
"min_event.tick ({}) = self.time ({})",
|
||||||
Some(min_event)
|
min_event.tick, self.time
|
||||||
|
);
|
||||||
|
Tick(self.time.0 + min_event.tick.0)
|
||||||
|
} else {
|
||||||
|
println!(
|
||||||
|
"min_event.tick ({}) <> self.time ({})",
|
||||||
|
min_event.tick, self.time
|
||||||
|
);
|
||||||
|
Tick(self.time.0 + (self.time.0 % group_length.0) + min_event.tick.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ordering::Equal => {
|
||||||
|
println!("self.time = group_length ({})", self.time);
|
||||||
|
if self.time == min_event.tick {
|
||||||
|
self.time
|
||||||
|
} else {
|
||||||
|
self.time + min_event.tick
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
Ordering::Greater => {
|
||||||
|
println!("self.time ({}) > group_length ({})", self.time, group_length);
|
||||||
|
Tick(self.time.0 + (group_length.0 % self.time.0) + min_event.tick.0)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("updated self.time: {}", self.time);
|
||||||
|
|
||||||
|
match self.time.cmp(&self.limit) {
|
||||||
|
Ordering::Less => {
|
||||||
|
println!("self.time < self.limit");
|
||||||
|
min_event.tick = self.time;
|
||||||
|
Some((min_event, self.time))
|
||||||
|
}
|
||||||
|
Ordering::Equal => {
|
||||||
|
println!("self.time = self.limit");
|
||||||
|
if min_event.event_type.is_note_on() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
min_event.tick = self.time;
|
||||||
|
Some((min_event, self.time))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ordering::Greater => {
|
||||||
|
println!("self.time > self.limit");
|
||||||
|
None
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_event_iterator_impl() {
|
||||||
|
let empty = EventGrid::new();
|
||||||
|
let flat_kick = flatten_group(
|
||||||
|
&group_or_delimited_group("(4x-)").unwrap().1,
|
||||||
|
Part::KickDrum,
|
||||||
|
&mut Tick(0),
|
||||||
|
);
|
||||||
|
let snare = flatten_group(
|
||||||
|
&group_or_delimited_group("4-x").unwrap().1,
|
||||||
|
Part::SnareDrum,
|
||||||
|
&mut Tick(0),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
EventIterator::new(
|
||||||
|
flat_kick.clone(),
|
||||||
|
snare.clone(),
|
||||||
|
empty.clone(),
|
||||||
|
empty.clone(),
|
||||||
|
Tick(96)
|
||||||
|
)
|
||||||
|
.into_iter()
|
||||||
|
.map(|x| { x.0 })
|
||||||
|
.collect::<Vec<Event<Tick>>>(),
|
||||||
|
vec![
|
||||||
|
Event {
|
||||||
|
tick: Tick(0),
|
||||||
|
event_type: EventType::NoteOn(Part::KickDrum)
|
||||||
|
},
|
||||||
|
Event {
|
||||||
|
tick: Tick(48),
|
||||||
|
event_type: EventType::NoteOn(Part::SnareDrum)
|
||||||
|
},
|
||||||
|
Event {
|
||||||
|
tick: Tick(96),
|
||||||
|
event_type: EventType::NoteOff(Part::KickDrum)
|
||||||
|
},
|
||||||
|
Event {
|
||||||
|
tick: Tick(96),
|
||||||
|
event_type: EventType::NoteOff(Part::SnareDrum)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
EventIterator::new(
|
||||||
|
flat_kick.clone(),
|
||||||
|
empty.clone(),
|
||||||
|
empty.clone(),
|
||||||
|
empty.clone(),
|
||||||
|
Tick(96)
|
||||||
|
)
|
||||||
|
.into_iter()
|
||||||
|
.map(|x| { x.0 })
|
||||||
|
.collect::<Vec<Event<Tick>>>(),
|
||||||
|
[
|
||||||
|
Event {
|
||||||
|
tick: Tick(0),
|
||||||
|
event_type: EventType::NoteOn(Part::KickDrum)
|
||||||
|
},
|
||||||
|
Event {
|
||||||
|
tick: Tick(48),
|
||||||
|
event_type: EventType::NoteOff(Part::KickDrum)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
EventIterator::new(
|
||||||
|
flat_kick.clone(),
|
||||||
|
empty.clone(),
|
||||||
|
empty.clone(),
|
||||||
|
empty.clone(),
|
||||||
|
Tick(144)
|
||||||
|
)
|
||||||
|
.into_iter()
|
||||||
|
.map(|x| { x.0 })
|
||||||
|
.collect::<Vec<Event<Tick>>>(),
|
||||||
|
[
|
||||||
|
Event {
|
||||||
|
tick: Tick(0),
|
||||||
|
event_type: EventType::NoteOn(Part::KickDrum)
|
||||||
|
},
|
||||||
|
Event {
|
||||||
|
tick: Tick(48),
|
||||||
|
event_type: EventType::NoteOff(Part::KickDrum)
|
||||||
|
},
|
||||||
|
Event {
|
||||||
|
tick: Tick(96),
|
||||||
|
event_type: EventType::NoteOn(Part::KickDrum)
|
||||||
|
},
|
||||||
|
Event {
|
||||||
|
tick: Tick(144),
|
||||||
|
event_type: EventType::NoteOff(Part::KickDrum)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Returns time as a number of ticks from beginning, has to be turned into the midi delta-time.
|
// Returns time as a number of ticks from beginning, has to be turned into the midi delta-time.
|
||||||
fn flatten_and_merge<'a>(
|
fn flatten_and_merge(
|
||||||
mut groups: HashMap<Part, Vec<Group>>,
|
mut groups: HashMap<Part, Vec<Group>>,
|
||||||
time_signature: TimeSignature,
|
time_signature: TimeSignature,
|
||||||
) -> EventIterator<Tick> {
|
) -> EventIterator {
|
||||||
let f = |p| {
|
let f = |p| {
|
||||||
groups
|
groups
|
||||||
.get(&p)
|
.get(&p)
|
||||||
.map(|g| flatten_groups(p, g))
|
.map(|g| flatten_groups(p, g))
|
||||||
.unwrap_or(EventGrid::new())
|
.unwrap_or(EventGrid::new())
|
||||||
};
|
};
|
||||||
let kick = f(Part::KickDrum);
|
let kick = f(Part::KickDrum);
|
||||||
let snare = f(Part::SnareDrum);
|
let snare = f(Part::SnareDrum);
|
||||||
|
@ -774,10 +949,10 @@ fn flatten_and_merge<'a>(
|
||||||
|
|
||||||
// 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 = vec![] ; // 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.
|
||||||
let metrical = midly::Timing::Metrical(u15::new(TICKS_PER_QUARTER_NOTE));
|
let metrical = midly::Timing::Metrical(u15::new(TICKS_PER_QUARTER_NOTE));
|
||||||
Smf {
|
Smf {
|
||||||
header: Header {
|
header: Header {
|
||||||
|
@ -788,36 +963,55 @@ 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>>> {
|
||||||
// //FIXME: unhardcode time signature
|
//FIXME: unhardcode time signature
|
||||||
// let event_grid = flatten_and_merge(parts_and_groups, TimeSignature { numerator: 4, denominator: BasicLength::Fourth );
|
let events_iter = flatten_and_merge(
|
||||||
// let mut drums = Vec::new();
|
parts_and_groups,
|
||||||
// // let midi_tempo = MidiTempo::from_tempo(Tempo(130)).0;
|
TimeSignature {
|
||||||
// // drums.push(TrackEvent { delta: u28::from(0), kind: TrackEventKind::Meta(MetaMessage::Tempo(midi_tempo)) });
|
numerator: 4,
|
||||||
// // drums.push(TrackEvent { delta: u28::from(0), kind: TrackEventKind::Meta(MetaMessage::TimeSignature(4, 4, MIDI_CLOCKS_PER_CLICK.clone(), 8))});
|
denominator: BasicLength::Fourth,
|
||||||
// for event in event_grid.events {
|
},
|
||||||
// let midi_message = match event.event_type {
|
);
|
||||||
// EventType::NoteOn(part) => MidiMessage::NoteOn {
|
let event_pairs: Vec<(Event<Tick>, Tick)> = events_iter.collect();
|
||||||
// key: part.to_midi_key(),
|
let events = event_pairs.iter().map(|x| x.0).collect();
|
||||||
// vel: u7::from(120),
|
let time = match event_pairs.last() {
|
||||||
// },
|
Some((_, time)) => time,
|
||||||
// EventType::NoteOff(part) => MidiMessage::NoteOff {
|
None => {
|
||||||
// key: part.to_midi_key(),
|
panic!("Result has no midi notes")
|
||||||
// vel: u7::from(0),
|
}
|
||||||
// },
|
};
|
||||||
// };
|
let event_grid = EventGrid {
|
||||||
// drums.push(TrackEvent {
|
events,
|
||||||
// delta: u28::from(event.tick.0 as u32),
|
length: *time,
|
||||||
// kind: TrackEventKind::Midi {
|
}
|
||||||
// channel: u4::from(10),
|
.to_delta();
|
||||||
// message: midi_message,
|
let mut drums = Vec::new();
|
||||||
// },
|
// let midi_tempo = MidiTempo::from_tempo(Tempo(130)).0;
|
||||||
// })
|
// drums.push(TrackEvent { delta: u28::from(0), kind: TrackEventKind::Meta(MetaMessage::Tempo(midi_tempo)) });
|
||||||
// }
|
// drums.push(TrackEvent { delta: u28::from(0), kind: TrackEventKind::Meta(MetaMessage::TimeSignature(4, 4, MIDI_CLOCKS_PER_CLICK.clone(), 8))});
|
||||||
|
for event in event_grid.events {
|
||||||
|
let midi_message = match event.event_type {
|
||||||
|
EventType::NoteOn(part) => MidiMessage::NoteOn {
|
||||||
|
key: part.to_midi_key(),
|
||||||
|
vel: u7::from(120),
|
||||||
|
},
|
||||||
|
EventType::NoteOff(part) => MidiMessage::NoteOff {
|
||||||
|
key: part.to_midi_key(),
|
||||||
|
vel: u7::from(0),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
drums.push(TrackEvent {
|
||||||
|
delta: u28::from(event.tick.0 as u32),
|
||||||
|
kind: TrackEventKind::Midi {
|
||||||
|
channel: u4::from(10),
|
||||||
|
message: midi_message,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// vec![drums]
|
vec![drums]
|
||||||
// }
|
}
|
||||||
|
|
Loading…
Reference in a new issue