midi_stream_parser/
lib.rs

1#![doc = include_str!("../README.md")]
2#![cfg_attr(not(test), no_std)]
3
4/// Parser type with internal states.
5/// Owns a buffer of `SYSEX_MAX_LEN` bytes for constructing SysEx messages.
6#[derive(Debug)]
7pub struct MidiStreamParser<const SYSEX_MAX_LEN: usize> {
8    /// Buffer for message to be created.
9    message: [u8; 3],
10
11    /// Length of message in buffer.
12    message_length: usize,
13
14    /// Single byte realtime message buffer.
15    realtime_message: [u8; 1],
16
17    /// State of SysEx parsing.
18    sysex_running: bool,
19
20    /// SysEx message buffer.
21    sysex_message: [u8; SYSEX_MAX_LEN],
22
23    /// SysEx message length.
24    sysex_message_length: usize,
25}
26
27/// Error variants.
28#[derive(Debug)]
29pub enum ParserError {
30    /// No valid status byte.
31    InvalidStatus,
32
33    /// SysEx message longer than SYSEX_MAX_LEN bytes.
34    SysexOverflow,
35}
36
37impl<const SYSEX_MAX_LEN: usize> Default for MidiStreamParser<SYSEX_MAX_LEN> {
38    /// Returns a new parser with default values.
39    fn default() -> Self {
40        Self::new()
41    }
42}
43
44impl<const SYSEX_MAX_LEN: usize> MidiStreamParser<SYSEX_MAX_LEN> {
45    /// Returns a new parser.
46    pub fn new() -> Self {
47        Self {
48            message: [0; 3],
49            message_length: 0,
50            realtime_message: [0; 1],
51            sysex_running: false,
52            sysex_message: [0; SYSEX_MAX_LEN],
53            sysex_message_length: 0,
54        }
55    }
56
57    /// Feed a byte into the parser and return result.
58    /// The `Ok` variant is an option that contains either the constructed message or `None`
59    /// in case the message is not ready yet.
60    pub fn parse(&mut self, byte: u8) -> Result<Option<&[u8]>, ParserError> {
61        match byte {
62            0x00..=0x7F => {
63                // Data byte
64                if self.sysex_running {
65                    if self.sysex_message_length >= SYSEX_MAX_LEN {
66                        return Err(ParserError::SysexOverflow);
67                    }
68                    self.sysex_message[self.sysex_message_length] = byte;
69                    self.sysex_message_length += 1;
70                } else {
71                    if self.message_length == 0 {
72                        // No valid status byte found.
73                        return Err(ParserError::InvalidStatus);
74                    }
75                    self.message[self.message_length] = byte;
76                    self.message_length += 1;
77                    if self.message_length == 3 {
78                        // 3-byte message ready, keep first byte for running status
79                        self.message_length = 1;
80                        return Ok(Some(&self.message));
81                    } else if matches!(self.message[0] & 0xF0, 0xC0 | 0xD0)
82                        || matches!(self.message[0], 0xF1 | 0xF3)
83                    {
84                        // 2-byte message ready, keep first byte for running status
85                        self.message_length = 1;
86                        return Ok(Some(&self.message[0..2]));
87                    }
88                }
89            }
90            0x80..=0xEF => {
91                // Status byte for channel voice message.
92                self.message[0] = byte;
93                self.message_length = 1;
94            }
95            0xF0..=0xF7 => {
96                // Status byte for system common message.
97                match byte {
98                    0xF0 => {
99                        // Start of SysEx.
100                        self.message[0] = 0;
101                        self.message_length = 0;
102                        self.sysex_running = true;
103                        self.sysex_message[0] = byte;
104                        self.sysex_message_length = 1;
105                    }
106                    0xF7 => {
107                        // End of SysEx.
108                        self.sysex_running = false;
109                        if self.sysex_message_length >= SYSEX_MAX_LEN {
110                            return Err(ParserError::SysexOverflow);
111                        }
112                        self.sysex_message[self.sysex_message_length] = byte;
113                        self.sysex_message_length += 1;
114                        return Ok(Some(&self.sysex_message[0..self.sysex_message_length]));
115                    }
116                    _ => {
117                        self.message[0] = byte;
118                        self.message_length = 1;
119                    }
120                }
121            }
122            0xF8..=0xFF => {
123                // Status byte for system realtime message.
124                self.realtime_message[0] = byte;
125                return Ok(Some(&self.realtime_message));
126            }
127        }
128
129        Ok(None)
130    }
131}
132
133#[cfg(test)]
134mod tests;