midi_toolkit/sequence/note/
merge_notes.rs

1use crate::gen_iter::GenIter;
2
3use crate::{
4    notes::MIDINote,
5    num::MIDINum,
6    sequence::{grouped_multithreaded_merge, MergableStreams},
7    unwrap, yield_error,
8};
9
10struct SeqTime<T: MIDINum, N: MIDINote<T>, Err, I: Iterator<Item = Result<N, Err>> + Sized> {
11    iter: I,
12    time: T,
13    next: Option<N>,
14}
15
16/// Merge an array of note iterators together into one iterator.
17pub fn merge_notes_array<
18    T: MIDINum,
19    N: MIDINote<T>,
20    Err,
21    I: Iterator<Item = Result<N, Err>> + Sized,
22>(
23    array: Vec<I>,
24) -> impl Iterator<Item = Result<N, Err>> {
25    GenIter(
26        #[coroutine]
27        move || {
28            let mut sequences = Vec::new();
29            for mut seq in array.into_iter() {
30                let first = seq.next();
31                match first {
32                    None => continue,
33                    Some(e) => match e {
34                        Err(e) => yield_error!(Err(e)),
35                        Ok(e) => {
36                            let s = SeqTime {
37                                time: e.start(),
38                                next: Some(e),
39                                iter: seq,
40                            };
41                            sequences.push(s);
42                        }
43                    },
44                }
45            }
46
47            while !sequences.is_empty() {
48                let mut smallest_index = 0;
49                let mut smallest_time = sequences[0].time;
50                for (i, next) in sequences.iter().enumerate() {
51                    if next.time < smallest_time {
52                        smallest_time = next.time;
53                        smallest_index = i;
54                    }
55                }
56                loop {
57                    let (note, next) = {
58                        let smallest = &mut sequences[smallest_index];
59
60                        let note = smallest.next.take().unwrap();
61
62                        (note, smallest.iter.next())
63                    };
64                    yield Ok(note);
65                    match next {
66                        None => {
67                            sequences.remove(smallest_index);
68                            break;
69                        }
70                        Some(next) => {
71                            let next = unwrap!(next);
72                            let smallest = &mut sequences[smallest_index];
73                            smallest.time = next.start();
74                            smallest.next = Some(next);
75                        }
76                    }
77                    if sequences[smallest_index].time != smallest_time {
78                        break;
79                    }
80                }
81            }
82        },
83    )
84}
85
86/// Merge a pair of two different event iterators together into one iterator.
87pub fn merge_notes<
88    T: MIDINum,
89    N: MIDINote<T>,
90    Err: 'static,
91    I1: Iterator<Item = Result<N, Err>> + Sized,
92    I2: Iterator<Item = Result<N, Err>> + Sized,
93>(
94    iter1: I1,
95    iter2: I2,
96) -> impl Iterator<Item = Result<N, Err>> {
97    fn seq_from_iter<
98        T: MIDINum,
99        N: MIDINote<T>,
100        Err,
101        I: Iterator<Item = Result<N, Err>> + Sized,
102    >(
103        mut iter: I,
104    ) -> Result<SeqTime<T, N, Err, I>, Err> {
105        let first = iter.next();
106        match first {
107            None => Ok(SeqTime {
108                iter,
109                time: T::zero(),
110                next: None,
111            }),
112            Some(e) => match e {
113                Err(e) => Err(e),
114                Ok(e) => Ok(SeqTime {
115                    iter,
116                    time: e.start(),
117                    next: Some(e),
118                }),
119            },
120        }
121    }
122
123    fn move_next<T: MIDINum, N: MIDINote<T>, Err, I: Iterator<Item = Result<N, Err>> + Sized>(
124        seq: &mut SeqTime<T, N, Err, I>,
125    ) -> Result<(), Err> {
126        let next = seq.iter.next();
127        let next = match next {
128            None => None,
129            Some(e) => match e {
130                Err(e) => return Err(e),
131                Ok(e) => {
132                    seq.time = e.start();
133                    Some(e)
134                }
135            },
136        };
137        seq.next = next;
138        Ok(())
139    }
140
141    GenIter(
142        #[coroutine]
143        move || {
144            let mut seq1 = unwrap!(seq_from_iter(iter1));
145            let mut seq2 = unwrap!(seq_from_iter(iter2));
146
147            macro_rules! flush_seq_and_return {
148                ($seq:ident) => {
149                    while let Some(ev) = $seq.next.take() {
150                        yield Ok(ev);
151                        unwrap!(move_next(&mut $seq));
152                    }
153                    return;
154                };
155            }
156
157            loop {
158                if seq1.next.is_none() {
159                    if seq2.next.is_none() {
160                        break;
161                    } else {
162                        flush_seq_and_return!(seq2);
163                    }
164                }
165                if seq2.next.is_none() {
166                    flush_seq_and_return!(seq1);
167                }
168
169                if seq1.time < seq2.time {
170                    let ev = seq1.next.take().unwrap();
171                    yield Ok(ev);
172                    unwrap!(move_next(&mut seq1));
173                } else {
174                    let ev = seq2.next.take().unwrap();
175                    yield Ok(ev);
176                    unwrap!(move_next(&mut seq2));
177                }
178            }
179        },
180    )
181}
182
183struct EventMerger<D: 'static + MIDINum, N: 'static + MIDINote<D> + Send, Err: 'static + Send> {
184    _phantom: std::marker::PhantomData<(D, N, Err)>,
185}
186impl<D: 'static + MIDINum, N: 'static + MIDINote<D> + Send, Err: 'static + Send> MergableStreams
187    for EventMerger<D, N, Err>
188{
189    type Item = Result<N, Err>;
190
191    fn merge_two(
192        iter1: impl Iterator<Item = Self::Item> + Send + 'static,
193        iter2: impl Iterator<Item = Self::Item> + Send + 'static,
194    ) -> impl Iterator<Item = Self::Item> + Send + 'static {
195        merge_notes(iter1, iter2)
196    }
197
198    fn merge_array(
199        array: Vec<impl Iterator<Item = Self::Item> + Send + 'static>,
200    ) -> impl Iterator<Item = Self::Item> + Send + 'static {
201        merge_notes_array(array)
202    }
203}
204
205/// Group tracks into separate threads and merge them together
206pub fn grouped_multithreaded_merge_note_arrays<
207    T: 'static + MIDINum,
208    N: 'static + MIDINote<T> + Send,
209    Err: 'static + Send,
210    I: 'static + Iterator<Item = Result<N, Err>> + Sized + Send,
211>(
212    array: Vec<I>,
213) -> impl Iterator<Item = Result<N, Err>> {
214    grouped_multithreaded_merge::<EventMerger<T, N, Err>>(array)
215}