Skip to main content

midi_toolkit/sequence/event/
batched.rs

1use crate::gen_iter::GenIter;
2
3use crate::{
4    events::{BatchTempo, MIDIDelta, MIDIEvent, MIDIEventEnum},
5    num::MIDINum,
6    unwrap,
7};
8
9use super::{Delta, Track};
10
11#[derive(Debug)]
12pub struct EventBatch<T> {
13    events: Vec<T>,
14}
15
16impl<T> EventBatch<T> {
17    fn new(events: Vec<T>) -> Self {
18        Self { events }
19    }
20
21    pub fn into_iter_inner(self) -> impl Iterator<Item = T> {
22        self.events.into_iter()
23    }
24
25    pub fn iter_inner(&self) -> impl Iterator<Item = &T> {
26        self.events.iter()
27    }
28
29    pub fn count(&self) -> usize {
30        self.events.len()
31    }
32}
33
34impl<D: MIDINum, T> Delta<D, EventBatch<T>> {
35    pub fn into_iter_events(self) -> impl Iterator<Item = Delta<D, T>> {
36        let mut delta = self.delta;
37        self.event.into_iter_inner().map(move |event| {
38            let event = Delta::new(delta, event);
39            delta = D::zero();
40            event
41        })
42    }
43
44    pub fn iter_events(&self) -> impl Iterator<Item = Delta<D, &T>> {
45        let mut delta = self.delta;
46        self.event.iter_inner().map(move |event| {
47            let event = Delta::new(delta, event);
48            delta = D::zero();
49            event
50        })
51    }
52}
53
54impl<D: MIDINum, T> Delta<D, Track<EventBatch<T>>> {
55    pub fn iter_events(&self) -> impl Iterator<Item = Delta<D, Track<&T>>> {
56        let mut delta = self.delta;
57        let track = self.event.track;
58        self.event.event.iter_inner().map(move |event| {
59            let event = Delta::new(delta, Track::new(event, track));
60            delta = D::zero();
61            event
62        })
63    }
64}
65
66impl<D: MIDINum, T> IntoIterator for Delta<D, Track<EventBatch<T>>> {
67    type Item = Delta<D, Track<T>>;
68    type IntoIter = impl Iterator<Item = Delta<D, Track<T>>>;
69
70    fn into_iter(self) -> Self::IntoIter {
71        let mut delta = self.delta;
72        let track = self.event.track;
73        self.event
74            .inner_event()
75            .into_iter_inner()
76            .map(move |event| {
77                let event = Delta::new(delta, Track::new(event, track));
78                delta = D::zero();
79                event
80            })
81    }
82}
83
84impl<E: MIDIEventEnum> BatchTempo for EventBatch<E> {
85    fn inner_tempo(&self) -> Option<u32> {
86        for e in self.events.iter().rev() {
87            if let Some(t) = e.as_event().inner_tempo() {
88                return Some(t);
89            }
90        }
91        None
92    }
93
94    fn without_tempo(self) -> Option<Self> {
95        let new = self
96            .events
97            .into_iter()
98            .filter(|e| e.as_event().inner_tempo().is_none())
99            .collect::<Vec<_>>();
100
101        if new.is_empty() {
102            None
103        } else {
104            Some(Self::new(new))
105        }
106    }
107}
108
109pub fn convert_events_into_batches<D: MIDINum, E, Err>(
110    iter: impl Iterator<Item = Result<Delta<D, E>, Err>>,
111) -> impl Iterator<Item = Result<Delta<D, EventBatch<E>>, Err>> {
112    GenIter(
113        #[coroutine]
114        move || {
115            let mut next_batch = Delta::new(D::zero(), EventBatch::new(Vec::new()));
116            for e in iter {
117                let e = unwrap!(e);
118                if e.delta() > D::zero() {
119                    if !next_batch.events.is_empty() {
120                        yield Ok(next_batch);
121                    }
122                    next_batch = Delta::new(e.delta(), EventBatch::new(Vec::new()));
123                }
124                next_batch.events.push(e.event);
125            }
126            if !next_batch.events.is_empty() {
127                yield Ok(next_batch);
128            }
129        },
130    )
131}
132
133pub fn flatten_batches_to_events<D: MIDINum, E: MIDIEvent, Err>(
134    iter: impl Iterator<Item = Result<Delta<D, EventBatch<E>>, Err>>,
135) -> impl Iterator<Item = Result<Delta<D, E>, Err>> {
136    GenIter(
137        #[coroutine]
138        move || {
139            for batch in iter {
140                let batch = unwrap!(batch);
141                let mut delta = batch.delta;
142                for event in batch.event.into_iter_inner() {
143                    yield Ok(Delta::new(delta, event));
144                    delta = D::zero();
145                }
146            }
147        },
148    )
149}
150
151pub fn flatten_track_batches_to_events<D: MIDINum, E: MIDIEvent, Err>(
152    iter: impl Iterator<Item = Result<Delta<D, Track<EventBatch<E>>>, Err>>,
153) -> impl Iterator<Item = Result<Delta<D, Track<E>>, Err>> {
154    GenIter(
155        #[coroutine]
156        move || {
157            for batch in iter {
158                let batch = unwrap!(batch);
159                let track = batch.event.track;
160                let mut delta = batch.delta;
161                for event in batch.event.inner_event().into_iter_inner() {
162                    yield Ok(Delta::new(delta, Track::new(event, track)));
163                    delta = D::zero();
164                }
165            }
166        },
167    )
168}
169
170#[cfg(test)]
171mod tests {
172    use super::EventBatch;
173    use crate::events::{BatchTempo, Event, NoteOnEvent, TempoEvent};
174
175    #[test]
176    fn without_tempo_keeps_non_tempo_events() {
177        let batch = EventBatch::new(vec![
178            Event::Tempo(Box::new(TempoEvent { tempo: 500000 })),
179            Event::NoteOn(NoteOnEvent {
180                channel: 0,
181                key: 64,
182                velocity: 127,
183            }),
184        ]);
185
186        let filtered = batch.without_tempo().unwrap();
187        assert_eq!(filtered.count(), 1);
188        assert!(matches!(
189            filtered.into_iter_inner().next(),
190            Some(Event::NoteOn(NoteOnEvent {
191                channel: 0,
192                key: 64,
193                velocity: 127,
194            }))
195        ));
196    }
197}