EventIterator in progress

This commit is contained in:
Denis Redozubov 2023-05-16 16:31:57 +04:00
parent f5be68d0d5
commit a94a2d331a

View file

@ -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,76 +683,257 @@ 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 {
for (o, p) in candidates {
match o {
Some(e) => {
println!("{:?}", e);
// 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_part = p;
min_tick = e.tick; min_tick = e.tick;
min_event = e; 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 { } else {
println!("continue");
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!(
"min_event.tick ({}) = self.time ({})",
min_event.tick, self.time
);
Tick(self.time.0 + min_event.tick.0)
} else { } else {
Some(min_event) 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 { } 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 None
} else {
min_event.tick = self.time;
Some((min_event, self.time))
}
}
Ordering::Greater => {
println!("self.time > self.limit");
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)
@ -774,7 +949,7 @@ 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.
@ -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]
// } }