Skip to main content

midi_toolkit/io/
track_parser.rs

1use crate::{events::*, sequence::event::Delta};
2
3use super::{errors::MIDIParseError, readers::TrackReader};
4
5pub struct TrackParser<T: TrackReader> {
6    reader: T,
7    pushback: i16,
8    prev_command: u8,
9    errored: bool,
10}
11
12pub struct ParserCheckpoint {
13    pushback: i16,
14    prev_command: u8,
15    reader_pos: u64,
16    ended: bool,
17}
18
19impl ParserCheckpoint {
20    pub fn reader_pos(&self) -> u64 {
21        self.reader_pos
22    }
23}
24
25impl<T: TrackReader> TrackParser<T> {
26    pub fn from_checkpoint(reader: T, checkpoint: ParserCheckpoint) -> Self {
27        assert_eq!(
28            checkpoint.reader_pos,
29            reader.pos(),
30            "Checkpoint reader pos does not match reader pos"
31        );
32
33        Self {
34            reader,
35            pushback: checkpoint.pushback,
36            prev_command: checkpoint.prev_command,
37            errored: checkpoint.ended,
38        }
39    }
40
41    pub fn new(reader: T) -> Self {
42        Self {
43            reader,
44            pushback: -1,
45            prev_command: 0,
46            errored: false,
47        }
48    }
49
50    fn read(&mut self) -> Result<u8, MIDIParseError> {
51        if self.pushback != -1 {
52            let p: u8 = self.pushback as u8;
53            self.pushback = -1;
54            return Ok(p);
55        }
56        self.reader.read()
57    }
58
59    fn read_fast(&mut self) -> Result<u8, MIDIParseError> {
60        self.reader.read()
61    }
62
63    fn read_var_length(&mut self) -> Result<u64, MIDIParseError> {
64        let mut n: u64 = 0;
65        loop {
66            let byte = self.read()?;
67            n = (n << 7) | (byte & 0x7F) as u64;
68            if (byte & 0x80) == 0 {
69                break;
70            }
71        }
72        Ok(n)
73    }
74
75    fn try_parse_next_event(&mut self) -> Result<Option<Delta<u64, Event>>, MIDIParseError> {
76        macro_rules! ret {
77            ($val:expr) => {
78                Ok(Some($val))
79            };
80        }
81
82        macro_rules! assert_len {
83            ($size:expr) => {
84                if self.read_fast()? != $size {
85                    return Err(MIDIParseError::CorruptEvent {
86                        track_number: self.reader.track_number(),
87                        position: self.reader.pos(),
88                    });
89                }
90            };
91        }
92
93        let delta = self.read_var_length()?;
94        let mut command = self.read()?;
95        if command < 0x80 {
96            self.pushback = command as i16;
97            command = self.prev_command;
98        }
99        self.prev_command = command;
100        let comm = command & 0xF0;
101        match comm {
102            0x80 => {
103                let channel = command & 0x0F;
104                let key = self.read()?;
105                let _vel = self.read_fast()?;
106                ret!(Event::new_delta_note_off_event(delta, channel, key))
107            }
108            0x90 => {
109                let channel = command & 0x0F;
110                let key = self.read()?;
111                let vel = self.read_fast()?;
112                if vel == 0 {
113                    ret!(Event::new_delta_note_off_event(delta, channel, key))
114                } else {
115                    ret!(Event::new_delta_note_on_event(delta, channel, key, vel))
116                }
117            }
118            0xA0 => {
119                let channel = command & 0x0F;
120                let key = self.read()?;
121                let vel = self.read_fast()?;
122                ret!(Event::new_delta_polyphonic_key_pressure_event(
123                    delta, channel, key, vel
124                ))
125            }
126            0xB0 => {
127                let channel = command & 0x0F;
128                let controller = self.read()?;
129                let value = self.read_fast()?;
130                ret!(Event::new_delta_control_change_event(
131                    delta, channel, controller, value
132                ))
133            }
134            0xC0 => {
135                let channel = command & 0x0F;
136                let program = self.read()?;
137                ret!(Event::new_delta_program_change_event(
138                    delta, channel, program
139                ))
140            }
141            0xD0 => {
142                let channel = command & 0x0F;
143                let pressure = self.read()?;
144                ret!(Event::new_delta_channel_pressure_event(
145                    delta, channel, pressure
146                ))
147            }
148            0xE0 => {
149                let channel = command & 0x0F;
150                let var1 = self.read()?;
151                let var2 = self.read_fast()?;
152                ret!(Event::new_delta_pitch_wheel_change_event(
153                    delta,
154                    channel,
155                    (((var2 as i16) << 7) | var1 as i16) - 8192
156                ))
157            }
158            _ => match command {
159                0xF0 => {
160                    let size = self.read_var_length()?;
161                    let mut data = Vec::new();
162                    for _ in 0..size {
163                        data.push(self.read_fast()?);
164                    }
165                    data.shrink_to_fit();
166                    ret!(Event::new_delta_system_exclusive_message_event(delta, data))
167                }
168                0xF2 => {
169                    let var1 = self.read()?;
170                    let var2 = self.read_fast()?;
171                    ret!(Event::new_delta_song_position_pointer_event(
172                        delta,
173                        ((var2 as u16) << 7) | var1 as u16
174                    ))
175                }
176                0xF3 => {
177                    let pos = self.read()?;
178                    ret!(Event::new_delta_song_select_event(delta, pos))
179                }
180                0xF6 => {
181                    ret!(Event::new_delta_tune_request_event(delta))
182                }
183                0xF7 => {
184                    ret!(Event::new_delta_end_of_exclusive_event(delta))
185                }
186                0xF8 => {
187                    ret!(Event::new_delta_end_of_exclusive_event(delta))
188                }
189                0xFF => {
190                    let command = self.read()?;
191                    match command {
192                        0x00 => {
193                            assert_len!(2);
194                            self.read_fast()?;
195                            self.read_fast()?;
196                            ret!(Event::new_delta_track_start_event(delta))
197                        }
198                        0x01..=0x0A | 0xF7 => {
199                            let size = self.read_var_length()?;
200                            let mut data = Vec::new();
201                            for _ in 0..size {
202                                data.push(self.read_fast()?);
203                            }
204                            data.shrink_to_fit();
205
206                            ret!(Event::new_delta_text_event(
207                                delta,
208                                TextEventKind::from_val(command),
209                                data
210                            ))
211                        }
212                        0x20 => {
213                            assert_len!(1);
214                            let prefix = self.read_fast()?;
215                            ret!(Event::new_delta_channel_prefix_event(delta, prefix))
216                        }
217                        0x21 => {
218                            assert_len!(1);
219                            let port = self.read_fast()?;
220                            ret!(Event::new_delta_midi_port_event(delta, port))
221                        }
222                        0x2F => {
223                            assert_len!(0);
224                            // Skip this event
225                            Ok(None)
226                        }
227                        0x51 => {
228                            assert_len!(3);
229                            let mut tempo: u32 = 0;
230                            for _ in 0..3 {
231                                tempo = (tempo << 8) | self.read_fast()? as u32;
232                            }
233                            ret!(Event::new_delta_tempo_event(delta, tempo))
234                        }
235                        0x54 => {
236                            assert_len!(5);
237                            let hr = self.read_fast()?;
238                            let mn = self.read_fast()?;
239                            let se = self.read_fast()?;
240                            let fr = self.read_fast()?;
241                            let ff = self.read_fast()?;
242                            ret!(Event::new_delta_smpte_offset_event(
243                                delta, hr, mn, se, fr, ff
244                            ))
245                        }
246                        0x58 => {
247                            assert_len!(4);
248                            let nn = self.read_fast()?;
249                            let dd = self.read_fast()?;
250                            let cc = self.read_fast()?;
251                            let bb = self.read_fast()?;
252                            ret!(Event::new_delta_time_signature_event(delta, nn, dd, cc, bb))
253                        }
254                        0x59 => {
255                            assert_len!(2);
256                            let sf = self.read_fast()?;
257                            let mi = self.read_fast()?;
258                            ret!(Event::new_delta_key_signature_event(delta, sf, mi))
259                        }
260                        _ => {
261                            let size = self.read_var_length()?;
262                            let mut data = Vec::new();
263                            for _ in 0..size {
264                                data.push(self.read_fast()?);
265                            }
266                            data.shrink_to_fit();
267
268                            ret!(Event::new_delta_unknown_meta_event(delta, command, data))
269                        }
270                    }
271                }
272                _ => ret!(Event::new_delta_undefined_event(delta, command)),
273            },
274        }
275    }
276}
277
278impl<T: TrackReader> Iterator for TrackParser<T> {
279    type Item = Result<Delta<u64, Event>, MIDIParseError>;
280
281    fn next(&mut self) -> Option<Self::Item> {
282        loop {
283            if self.errored || self.reader.is_at_end() {
284                return None;
285            }
286
287            let next_event = self.try_parse_next_event();
288            match next_event {
289                Ok(Some(event)) => return Some(Ok(event)),
290                Ok(None) => {
291                    // We skip some events such as track end events,
292                    // so we just loop again to get the next one
293                    continue;
294                }
295                Err(e) => {
296                    self.errored = true;
297                    return Some(Err(e));
298                }
299            }
300        }
301    }
302}
303
304#[cfg(test)]
305mod tests {
306    use super::TrackParser;
307    use crate::{
308        events::{Event, NoteOnEvent},
309        io::FullRamTrackReader,
310    };
311
312    #[test]
313    fn track_start_consumes_its_payload_bytes() {
314        let reader = FullRamTrackReader::new_from_vec(
315            None,
316            vec![0x00, 0xFF, 0x00, 0x02, 0x12, 0x34, 0x00, 0x90, 0x3C, 0x40],
317        );
318        let mut parser = TrackParser::new(reader);
319
320        let track_start = parser.next().unwrap().unwrap();
321        assert!(matches!(track_start.event, Event::TrackStart(_)));
322
323        let note_on = parser.next().unwrap().unwrap();
324        assert!(matches!(
325            note_on.event,
326            Event::NoteOn(NoteOnEvent {
327                channel: 0,
328                key: 0x3C,
329                velocity: 0x40,
330            })
331        ));
332
333        assert!(parser.next().is_none());
334    }
335}