midi_toolkit/sequence/conversion/
notes_to_events.rs1use std::collections::BinaryHeap;
2
3use crate::gen_iter::GenIter;
4
5use crate::{
6 events::{Event, NoteOffEvent},
7 notes::MIDINote,
8 num::MIDINum,
9 sequence::event::Delta,
10 unwrap,
11};
12
13struct NoteOffHolder<D: MIDINum>(Delta<D, NoteOffEvent>);
15
16impl<D: MIDINum> NoteOffHolder<D> {
17 fn new(delta: D, event: NoteOffEvent) -> Self {
18 Self(Delta::new(delta, event))
19 }
20
21 fn into_event(self) -> Delta<D, Event> {
22 Delta::new(self.0.delta, Event::NoteOff(self.0.event))
23 }
24}
25
26impl<D: MIDINum> PartialEq for NoteOffHolder<D> {
27 fn eq(&self, other: &Self) -> bool {
28 self.0.delta == other.0.delta
29 }
30}
31impl<D: MIDINum> Eq for NoteOffHolder<D> {}
32
33impl<D: MIDINum> Ord for NoteOffHolder<D> {
34 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
35 self.0
36 .delta
37 .partial_cmp(&other.0.delta)
38 .unwrap_or(std::cmp::Ordering::Equal)
39 .reverse()
40 }
41}
42
43impl<D: MIDINum> PartialOrd for NoteOffHolder<D> {
44 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
45 Some(self.cmp(other))
46 }
47}
48
49pub fn notes_to_events<D: MIDINum, N: MIDINote<D>, Err>(
52 iter: impl Iterator<Item = Result<N, Err>> + Sized,
53) -> impl Iterator<Item = Result<Delta<D, Event>, Err>> {
54 GenIter(
55 #[coroutine]
56 move || {
57 let mut note_offs = BinaryHeap::<NoteOffHolder<D>>::new();
58
59 let mut prev_time = D::zero();
60
61 for note in iter {
62 let note = unwrap!(note);
63
64 while let Some(e) = note_offs.peek() {
65 if e.0.delta <= note.start() {
66 let holder = note_offs.pop().unwrap();
67 let mut e = holder.into_event();
68 let time = e.delta;
69 e.delta -= prev_time;
70 prev_time = time;
71 yield Ok(e);
72 } else {
73 break;
74 }
75 }
76
77 yield Ok(Event::new_delta_note_on_event(
78 note.start() - prev_time,
79 note.channel(),
80 note.key(),
81 note.velocity(),
82 ));
83
84 prev_time = note.start();
85
86 let time = note.end();
87 let off = NoteOffEvent::new(note.channel(), note.key());
88 let holder = NoteOffHolder::new(time, off);
89
90 note_offs.push(holder);
91 }
92
93 while let Some(holder) = note_offs.pop() {
94 let mut e = holder.into_event();
95 let time = e.delta;
96 e.delta -= prev_time;
97 prev_time = time;
98 yield Ok(e);
99 }
100 },
101 )
102}
103
104#[cfg(test)]
105mod tests {
106 use crate::{
107 events::Event,
108 notes::Note,
109 pipe,
110 sequence::{conversion::notes_to_events, to_vec_result, wrap_ok},
111 };
112
113 #[test]
114 fn convert_notes_to_events() {
115 let events = vec![
116 Note {
117 start: 100.0f64,
118 channel: 0,
119 key: 64,
120 velocity: 127,
121 len: 80.0,
122 },
123 Note {
124 start: 130.0,
125 channel: 0,
126 key: 64,
127 velocity: 127,
128 len: 130.0,
129 },
130 Note {
131 start: 260.0,
132 channel: 1,
133 key: 64,
134 velocity: 127,
135 len: 80.0,
136 },
137 ];
138
139 let changed = pipe! {
140 events.into_iter()
141 |>wrap_ok()
142 |>notes_to_events()
143 |>to_vec_result().unwrap()
144 };
145
146 let expected = vec![
147 Event::new_delta_note_on_event(100.0f64, 0, 64, 127),
148 Event::new_delta_note_on_event(30.0f64, 0, 64, 127),
149 Event::new_delta_note_off_event(50.0f64, 0, 64),
150 Event::new_delta_note_off_event(80.0f64, 0, 64),
151 Event::new_delta_note_on_event(0.0f64, 1, 64, 127),
152 Event::new_delta_note_off_event(80.0f64, 1, 64),
153 ];
154
155 assert_eq!(changed, expected);
156 }
157}