Skip to main content

midi_msg/
message.rs

1use alloc::vec;
2use alloc::vec::Vec;
3use core::convert::TryFrom;
4
5use super::{
6    ChannelModeMsg, ChannelVoiceMsg, ParseError, ReceiverContext, SystemCommonMsg,
7    SystemRealTimeMsg,
8};
9
10#[cfg(feature = "sysex")]
11use super::SystemExclusiveMsg;
12
13#[cfg(feature = "file")]
14use super::Meta;
15
16/// The primary interface of this library. Used to encode MIDI messages.
17#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
18#[derive(Debug, Clone, PartialEq)]
19pub enum MidiMsg {
20    /// Channel-level messages that act on a voice, such as turning notes on and off.
21    ChannelVoice {
22        channel: Channel,
23        msg: ChannelVoiceMsg,
24    },
25    /// Like `ChannelVoice`, but with the first "status" byte of the message omitted.
26    /// When these "running status" messages are sent, the receiver must treat them
27    /// as implicitly referring to the previous "status" received.
28    ///
29    /// For instance, if a `ChannelVoiceMsg::NoteOn` message is received, and then
30    /// the next message does not contain a status byte, it implicitly refers to a
31    /// `ChannelVoiceMsg::NoteOn`.
32    RunningChannelVoice {
33        channel: Channel,
34        msg: ChannelVoiceMsg,
35    },
36    /// Channel-level messages that should alter the mode of the receiver.
37    ChannelMode {
38        channel: Channel,
39        msg: ChannelModeMsg,
40    },
41    /// Like `RunningChannelVoice` but for `ChannelMode`
42    RunningChannelMode {
43        channel: Channel,
44        msg: ChannelModeMsg,
45    },
46    /// A fairly limited set of messages, generally for device synchronization.
47    SystemCommon { msg: SystemCommonMsg },
48    /// Another limited set of messages used for device synchronization.
49    SystemRealTime { msg: SystemRealTimeMsg },
50    /// The bulk of the MIDI spec lives here, in "Universal System Exclusive" messages.
51    /// Also the home of manufacturer-specific messages.
52    #[cfg(feature = "sysex")]
53    SystemExclusive { msg: SystemExclusiveMsg },
54
55    /// A Meta event, which occur within MIDI files.
56    #[cfg(feature = "file")]
57    Meta { msg: Meta },
58
59    /// A message that was invalid.
60    ///
61    /// These can only occur in MIDI files, since only in MIDI files do we know the
62    /// length of (some) messages before we parse them.
63    #[cfg(feature = "file")]
64    #[cfg_attr(feature = "serde", serde(skip))]
65    Invalid { bytes: Vec<u8>, error: ParseError },
66}
67
68impl MidiMsg {
69    /// Turn a `MidiMsg` into a series of bytes.
70    pub fn to_midi(&self) -> Vec<u8> {
71        let mut r: Vec<u8> = vec![];
72        self.extend_midi(&mut r);
73        r
74    }
75
76    /// Turn a series of bytes into a `MidiMsg`.
77    ///
78    /// Ok results return a MidiMsg and the number of bytes consumed from the input.
79    pub fn from_midi(m: &[u8]) -> Result<(Self, usize), ParseError> {
80        Self::from_midi_with_context(m, &mut ReceiverContext::default())
81    }
82
83    /// Turn a series of bytes into a `MidiMsg`, given a [`ReceiverContext`](crate::ReceiverContext).
84    ///
85    /// Consecutive messages that relate to each other will be collapsed into one
86    /// `MidiMsg`. E.g. a `ChannelVoiceMsg::ControlChange` where the CC is the MSB and LSB
87    /// of `ControlChange::Volume` will turn into a single `ControlChange::Volume` with both
88    /// bytes turned into one. Use [`MidiMsg::from_midi_with_context_no_extensions`] to disable this
89    /// behavior.
90    ///
91    /// The `ReceiverContext` is also used to track the current [`TimeCode`](crate::TimeCode)
92    /// as sent through [`SystemCommonMsg::TimeCodeQuarterFrame`](crate::SystemCommonMsg::TimeCodeQuarterFrame1)
93    /// messages, or [`UniversalRealTimeMsg::TimeCodeFull`](crate::UniversalRealTimeMsg::TimeCodeFull)
94    /// messages.
95    ///
96    /// Ok results return a MidiMsg and the number of bytes consumed from the input.
97    pub fn from_midi_with_context(
98        m: &[u8],
99        ctx: &mut ReceiverContext,
100    ) -> Result<(Self, usize), ParseError> {
101        Self::_from_midi_with_context(m, ctx, true)
102    }
103
104    /// Like [`MidiMsg::from_midi_with_context`] but does not turn multiple related consecutive messages
105    /// into one `MidiMsg`.
106    pub fn from_midi_with_context_no_extensions(
107        m: &[u8],
108        ctx: &mut ReceiverContext,
109    ) -> Result<(Self, usize), ParseError> {
110        Self::_from_midi_with_context(m, ctx, false)
111    }
112
113    fn _from_midi_with_context(
114        m: &[u8],
115        ctx: &mut ReceiverContext,
116        allow_extensions: bool,
117    ) -> Result<(Self, usize), ParseError> {
118        let (mut midi_msg, mut len) = match m.first() {
119            Some(b) => match b >> 4 {
120                0x8 | 0x9 | 0xA | 0xC | 0xD | 0xE => {
121                    let (msg, len) = ChannelVoiceMsg::from_midi(m, ctx)?;
122                    let channel = Channel::from_u8(b & 0x0F);
123                    let midi_msg = Self::ChannelVoice { channel, msg };
124
125                    ctx.previous_channel_message = Some(midi_msg.clone());
126                    Ok((midi_msg, len))
127                }
128                0xB => {
129                    // Could either be a Channel Mode or CC message
130                    let channel = Channel::from_u8(b & 0x0F);
131                    let (midi_msg, len) = if let Some(b2) = m.get(1) {
132                        if b2 >= &120 {
133                            let (msg, len) = ChannelModeMsg::from_midi(m)?;
134                            (Self::ChannelMode { channel, msg }, len)
135                        } else {
136                            let (mut msg, len) = ChannelVoiceMsg::from_midi(m, ctx)?;
137
138                            if allow_extensions {
139                                // If we can interpret this message as an extension to the previous
140                                // one, do it.
141                                if let Some(Self::ChannelVoice {
142                                    channel: prev_channel,
143                                    msg: prev_msg,
144                                }) = ctx.previous_channel_message
145                                {
146                                    if channel == prev_channel
147                                        && prev_msg.is_extensible()
148                                        && msg.is_extension()
149                                    {
150                                        if let Ok(updated_msg) = prev_msg.maybe_extend(&msg) {
151                                            msg = updated_msg;
152                                        }
153                                    }
154                                }
155                            }
156                            (Self::ChannelVoice { channel, msg }, len)
157                        }
158                    } else {
159                        return Err(ParseError::UnexpectedEnd);
160                    };
161
162                    ctx.previous_channel_message = Some(midi_msg.clone());
163                    Ok((midi_msg, len))
164                }
165                0xF => {
166                    if b & 0b00001111 == 0 {
167                        #[cfg(feature = "sysex")]
168                        {
169                            let (msg, len) = SystemExclusiveMsg::from_midi(m, ctx)?;
170                            return Ok((Self::SystemExclusive { msg }, len));
171                        }
172                        #[cfg(not(feature = "sysex"))]
173                        return Err(ParseError::SystemExclusiveDisabled);
174                    } else if b & 0b00001111 == 0xF && ctx.parsing_smf {
175                        #[cfg(feature = "file")]
176                        {
177                            let (msg, len) = Meta::from_midi(m)?;
178                            return Ok((Self::Meta { msg }, len));
179                        }
180                        #[cfg(not(feature = "file"))]
181                        return Err(ParseError::FileDisabled);
182                    } else if b & 0b00001000 == 0 {
183                        let (msg, len) = SystemCommonMsg::from_midi(m, ctx)?;
184                        Ok((Self::SystemCommon { msg }, len))
185                    } else {
186                        let (msg, len) = SystemRealTimeMsg::from_midi(m)?;
187                        Ok((Self::SystemRealTime { msg }, len))
188                    }
189                }
190                _ => {
191                    if let Some(p) = &ctx.previous_channel_message {
192                        match p {
193                            Self::ChannelVoice {
194                                channel,
195                                msg: prev_msg,
196                            } => {
197                                if m.len() < 2 {
198                                    return Err(ParseError::UnexpectedEnd);
199                                }
200                                match prev_msg {
201                                    // See A-2 of the MIDI spec
202                                    ChannelVoiceMsg::ControlChange { .. } => {
203                                        if m[0] >= 120 {
204                                            let (msg, len) = ChannelModeMsg::from_midi_running(m)?;
205                                            return Ok((
206                                                Self::ChannelMode {
207                                                    channel: *channel,
208                                                    msg,
209                                                },
210                                                len,
211                                            ));
212                                        }
213                                    }
214                                    _ => (),
215                                };
216                                let (mut msg, len) =
217                                    ChannelVoiceMsg::from_midi_running(m, prev_msg, ctx)?;
218
219                                if allow_extensions {
220                                    // If we can interpret this message as an extension to the previous
221                                    // one, do it.
222                                    if prev_msg.is_extensible() && msg.is_extension() {
223                                        if let Ok(updated_msg) = prev_msg.maybe_extend(&msg) {
224                                            msg = updated_msg;
225                                        }
226                                    }
227                                }
228                                Ok((
229                                    Self::ChannelVoice {
230                                        channel: *channel,
231                                        msg,
232                                    },
233                                    len,
234                                ))
235                            }
236
237                            Self::ChannelMode { channel, .. } => {
238                                if m.len() < 2 {
239                                    return Err(ParseError::UnexpectedEnd);
240                                }
241                                // See A-2 of the MIDI spec
242                                if m[0] >= 120 {
243                                    let (msg, len) = ChannelModeMsg::from_midi_running(m)?;
244                                    Ok((
245                                        Self::ChannelMode {
246                                            channel: *channel,
247                                            msg,
248                                        },
249                                        len,
250                                    ))
251                                } else {
252                                    let control = crate::ControlChange::from_midi(m, ctx)?;
253                                    Ok((
254                                        Self::ChannelVoice {
255                                            channel: *channel,
256                                            msg: ChannelVoiceMsg::ControlChange { control },
257                                        },
258                                        2,
259                                    ))
260                                }
261                            }
262                            _ => Err(ParseError::Invalid(
263                                "ReceiverContext::previous_channel_message may only be a ChannelMode or ChannelVoice message.",
264                            )),
265                        }
266                    } else {
267                        Err(ParseError::ContextlessRunningStatus)
268                    }
269                }
270            },
271            None => Err(ParseError::UnexpectedEnd),
272        }?;
273
274        if allow_extensions {
275            // TODO: this loop could be written as a `while let` loop
276            // for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#while_let_loop
277
278            // If this is an extensible message, try to extend it
279            loop {
280                if let Self::ChannelVoice { channel, msg } = midi_msg {
281                    if msg.is_extensible() {
282                        // Shadow the context;
283                        let mut ctx = ctx.clone();
284                        // Try to extend an extensible message
285                        match Self::_from_midi_with_context(&m[len..], &mut ctx, false) {
286                            Ok((
287                                Self::ChannelVoice {
288                                    channel: next_channel,
289                                    msg: next_msg,
290                                },
291                                next_len,
292                            )) => {
293                                if channel == next_channel && next_msg.is_extension() {
294                                    match msg.maybe_extend(&next_msg) {
295                                        Ok(updated_msg) => {
296                                            midi_msg = Self::ChannelVoice {
297                                                channel,
298                                                msg: updated_msg,
299                                            };
300                                            len += next_len;
301                                        }
302                                        _ => break,
303                                    }
304                                } else {
305                                    break;
306                                }
307                            }
308                            _ => break,
309                        }
310                    } else {
311                        break;
312                    }
313                } else {
314                    break;
315                }
316            }
317        }
318
319        Ok((midi_msg, len))
320    }
321
322    /// Turn a set of `MidiMsg`s into a series of bytes, with fewer allocations than
323    /// repeatedly concatenating the results of `to_midi`.
324    pub fn messages_to_midi(msgs: &[Self]) -> Vec<u8> {
325        let mut r: Vec<u8> = vec![];
326        for m in msgs.iter() {
327            m.extend_midi(&mut r);
328        }
329        r
330    }
331
332    /// Given a `Vec<u8>`, append this `MidiMsg` to it.
333    pub fn extend_midi(&self, v: &mut Vec<u8>) {
334        match self {
335            MidiMsg::ChannelVoice { channel, msg } => {
336                let p = v.len();
337                msg.extend_midi(v);
338                v[p] += *channel as u8;
339                match msg {
340                    ChannelVoiceMsg::HighResNoteOff { .. }
341                    | ChannelVoiceMsg::HighResNoteOn { .. } => {
342                        v[p + 3] += *channel as u8;
343                    }
344                    _ => (),
345                }
346            }
347            MidiMsg::RunningChannelVoice { msg, .. } => msg.extend_midi_running(v),
348            MidiMsg::ChannelMode { channel, msg } => {
349                let p = v.len();
350                msg.extend_midi(v);
351                v[p] += *channel as u8;
352            }
353            MidiMsg::RunningChannelMode { msg, .. } => msg.extend_midi_running(v),
354            MidiMsg::SystemCommon { msg } => msg.extend_midi(v),
355            MidiMsg::SystemRealTime { msg } => msg.extend_midi(v),
356            #[cfg(feature = "sysex")]
357            MidiMsg::SystemExclusive { msg } => msg.extend_midi(v, true),
358            #[cfg(feature = "file")]
359            MidiMsg::Meta { msg } => msg.extend_midi(v),
360            #[cfg(feature = "file")]
361            MidiMsg::Invalid { .. } => {
362                // Do nothing
363            }
364        }
365    }
366
367    /// Returns true if this message is a channel voice message.
368    pub fn is_channel_voice(&self) -> bool {
369        matches!(
370            self,
371            Self::ChannelVoice { .. } | Self::RunningChannelVoice { .. }
372        )
373    }
374
375    pub fn is_note_on(&self) -> bool {
376        matches!(
377            self,
378            Self::ChannelVoice {
379                msg: ChannelVoiceMsg::NoteOn { .. } | ChannelVoiceMsg::HighResNoteOn { .. },
380                ..
381            } | Self::RunningChannelVoice {
382                msg: ChannelVoiceMsg::NoteOn { .. } | ChannelVoiceMsg::HighResNoteOn { .. },
383                ..
384            }
385        )
386    }
387
388    pub fn is_note_off(&self) -> bool {
389        matches!(
390            self,
391            Self::ChannelVoice {
392                msg: ChannelVoiceMsg::NoteOff { .. } | ChannelVoiceMsg::HighResNoteOff { .. },
393                ..
394            } | Self::RunningChannelVoice {
395                msg: ChannelVoiceMsg::NoteOff { .. } | ChannelVoiceMsg::HighResNoteOff { .. },
396                ..
397            }
398        )
399    }
400
401    /// Returns true if this message is a note (on or off) message.
402    pub fn is_note(&self) -> bool {
403        matches!(
404            self,
405            Self::ChannelVoice {
406                msg: ChannelVoiceMsg::NoteOn { .. }
407                    | ChannelVoiceMsg::NoteOff { .. }
408                    | ChannelVoiceMsg::HighResNoteOn { .. }
409                    | ChannelVoiceMsg::HighResNoteOff { .. },
410                ..
411            } | Self::RunningChannelVoice {
412                msg: ChannelVoiceMsg::NoteOn { .. }
413                    | ChannelVoiceMsg::NoteOff { .. }
414                    | ChannelVoiceMsg::HighResNoteOn { .. }
415                    | ChannelVoiceMsg::HighResNoteOff { .. },
416                ..
417            }
418        )
419    }
420
421    /// Returns true if this message is a control change message.
422    pub fn is_cc(&self) -> bool {
423        matches!(
424            self,
425            Self::ChannelVoice {
426                msg: ChannelVoiceMsg::ControlChange { .. },
427                ..
428            } | Self::RunningChannelVoice {
429                msg: ChannelVoiceMsg::ControlChange { .. },
430                ..
431            }
432        )
433    }
434
435    /// Returns true if this message is a channel mode message.
436    pub fn is_channel_mode(&self) -> bool {
437        matches!(
438            self,
439            Self::ChannelMode { .. } | Self::RunningChannelMode { .. }
440        )
441    }
442
443    /// Returns true if this message is a system common message.
444    pub fn is_system_common(&self) -> bool {
445        matches!(self, Self::SystemCommon { .. })
446    }
447
448    /// Returns true if this message is a system real-time message.
449    pub fn is_system_real_time(&self) -> bool {
450        matches!(self, Self::SystemRealTime { .. })
451    }
452
453    #[cfg(feature = "sysex")]
454    /// Returns true if this message is a system exclusive message.
455    pub fn is_system_exclusive(&self) -> bool {
456        matches!(self, Self::SystemExclusive { .. })
457    }
458
459    #[cfg(feature = "file")]
460    /// Returns true if this message is a meta message.
461    pub fn is_meta(&self) -> bool {
462        matches!(self, Self::Meta { .. })
463    }
464
465    #[cfg(feature = "file")]
466    /// Returns true if this message is an invalid message.
467    pub fn is_invalid(&self) -> bool {
468        matches!(self, Self::Invalid { .. })
469    }
470}
471
472impl From<&MidiMsg> for Vec<u8> {
473    fn from(m: &MidiMsg) -> Vec<u8> {
474        m.to_midi()
475    }
476}
477
478/// Find the index of the next message in a MIDI byte sequence. This is useful for
479/// being able to skip over messages, which may be necessary when a message is
480/// unable to be deserialized.
481///
482/// This *will* skip any running status messages, since we're not parsing the byte stream,
483/// we're just looking for a "status byte" -- a byte with the upper bit set.
484pub fn next_message(m: &[u8]) -> Option<usize> {
485    if m.is_empty() {
486        return None;
487    }
488    // If the first byte has the upper bit set, it's the start of the message we're skipping over.
489    // If not, we're somewhere in the middle of a message, and we need to find the next one.
490    let start = if upper_bit_set(m[0]) { 1 } else { 0 };
491
492    (start..m.len()).find(|&i| upper_bit_set(m[i]))
493}
494
495fn upper_bit_set(x: u8) -> bool {
496    x & 0b10000000 != 0
497}
498
499#[cfg(feature = "std")]
500use strum::{EnumIter, EnumString};
501
502/// The MIDI channel, 1-16. Used by [`MidiMsg`] and elsewhere.
503#[cfg_attr(feature = "std", derive(EnumIter, EnumString))]
504#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
505#[derive(Debug, Clone, Copy, PartialEq, Eq)]
506#[repr(u8)]
507pub enum Channel {
508    Ch1,
509    Ch2,
510    Ch3,
511    Ch4,
512    Ch5,
513    Ch6,
514    Ch7,
515    Ch8,
516    Ch9,
517    Ch10,
518    Ch11,
519    Ch12,
520    Ch13,
521    Ch14,
522    Ch15,
523    Ch16,
524}
525
526impl core::fmt::Display for Channel {
527    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
528        write!(f, "Ch{}", *self as u8 + 1)
529    }
530}
531
532impl Channel {
533    pub fn from_u8(x: u8) -> Self {
534        match x {
535            0 => Self::Ch1,
536            1 => Self::Ch2,
537            2 => Self::Ch3,
538            3 => Self::Ch4,
539            4 => Self::Ch5,
540            5 => Self::Ch6,
541            6 => Self::Ch7,
542            7 => Self::Ch8,
543            8 => Self::Ch9,
544            9 => Self::Ch10,
545            10 => Self::Ch11,
546            11 => Self::Ch12,
547            12 => Self::Ch13,
548            13 => Self::Ch14,
549            14 => Self::Ch15,
550            _ => Self::Ch16,
551        }
552    }
553}
554
555impl TryFrom<u8> for Channel {
556    type Error = &'static str;
557
558    fn try_from(value: u8) -> Result<Self, Self::Error> {
559        if value > 15 {
560            return Err("Invalid channel value");
561        }
562        Ok(Self::from_u8(value))
563    }
564}
565
566#[cfg(test)]
567mod tests {
568    use super::*;
569    use crate::Channel::*;
570
571    #[test]
572    fn test_ch() {
573        assert_eq!(Ch1, Channel::from_u8(0));
574        assert_eq!(Ch2, Channel::from_u8(1));
575        assert_eq!(Ch16, Channel::from_u8(255));
576    }
577
578    #[test]
579    fn test_ch_try_from() {
580        assert_eq!(Ch1, Channel::try_from(0).unwrap());
581        assert_eq!(Ch2, Channel::try_from(1).unwrap());
582        assert_eq!(Ch16, Channel::try_from(15).unwrap());
583        assert!(Channel::try_from(16).is_err());
584    }
585
586    #[test]
587    fn test_running_status() {
588        let noteon = MidiMsg::ChannelVoice {
589            channel: Channel::Ch1,
590            msg: ChannelVoiceMsg::NoteOn {
591                note: 0x42,
592                velocity: 0x60,
593            },
594        };
595        let running_noteon = MidiMsg::RunningChannelVoice {
596            channel: Channel::Ch1,
597            msg: ChannelVoiceMsg::NoteOn {
598                note: 0x42,
599                velocity: 0x60,
600            },
601        };
602        let reset = MidiMsg::ChannelMode {
603            channel: Channel::Ch1,
604            msg: ChannelModeMsg::ResetAllControllers,
605        };
606        let running_reset = MidiMsg::RunningChannelMode {
607            channel: Channel::Ch1,
608            msg: ChannelModeMsg::ResetAllControllers,
609        };
610        let cc = MidiMsg::ChannelVoice {
611            channel: Channel::Ch1,
612            msg: ChannelVoiceMsg::ControlChange {
613                control: crate::ControlChange::Volume(0x7F),
614            },
615        };
616        let running_cc = MidiMsg::RunningChannelVoice {
617            channel: Channel::Ch1,
618            msg: ChannelVoiceMsg::ControlChange {
619                control: crate::ControlChange::Volume(0x7F),
620            },
621        };
622
623        // Push 10 messages
624        let mut midi = vec![];
625        noteon.extend_midi(&mut midi);
626        running_noteon.extend_midi(&mut midi);
627        // Ensure that channel mode messages can follow one another
628        reset.extend_midi(&mut midi);
629        running_reset.extend_midi(&mut midi);
630        // Ensure that control changes can follow one another
631        cc.extend_midi(&mut midi);
632        running_cc.extend_midi(&mut midi);
633        //   Ensure that control changes and channel mode messages can follow one another
634        reset.extend_midi(&mut midi);
635        running_cc.extend_midi(&mut midi);
636        cc.extend_midi(&mut midi);
637        running_reset.extend_midi(&mut midi);
638
639        // Read back ten messages
640        let mut offset = 0;
641        let mut ctx = ReceiverContext::new().complex_cc();
642        let (msg1, len) = MidiMsg::from_midi_with_context(&midi, &mut ctx).expect("Not an error");
643        offset += len;
644        let (msg2, len) =
645            MidiMsg::from_midi_with_context(&midi[offset..], &mut ctx).expect("Not an error");
646        offset += len;
647        let (msg3, len) =
648            MidiMsg::from_midi_with_context(&midi[offset..], &mut ctx).expect("Not an error");
649        offset += len;
650        let (msg4, len) =
651            MidiMsg::from_midi_with_context(&midi[offset..], &mut ctx).expect("Not an error");
652        offset += len;
653        let (msg5, len) =
654            MidiMsg::from_midi_with_context(&midi[offset..], &mut ctx).expect("Not an error");
655        offset += len;
656        let (msg6, len) =
657            MidiMsg::from_midi_with_context(&midi[offset..], &mut ctx).expect("Not an error");
658        offset += len;
659        let (msg7, len) =
660            MidiMsg::from_midi_with_context(&midi[offset..], &mut ctx).expect("Not an error");
661        offset += len;
662        let (msg8, len) =
663            MidiMsg::from_midi_with_context(&midi[offset..], &mut ctx).expect("Not an error");
664        offset += len;
665        let (msg9, len) =
666            MidiMsg::from_midi_with_context(&midi[offset..], &mut ctx).expect("Not an error");
667        offset += len;
668        let (msg10, _) =
669            MidiMsg::from_midi_with_context(&midi[offset..], &mut ctx).expect("Not an error");
670
671        // The expected messages are not running status messages, since we never deserialize into them
672        assert_eq!(msg1, noteon);
673        assert_eq!(msg2, noteon);
674        assert_eq!(msg3, reset);
675        assert_eq!(msg4, reset);
676        assert_eq!(msg5, cc);
677        assert_eq!(msg6, cc);
678        assert_eq!(msg7, reset);
679        assert_eq!(msg8, cc);
680        assert_eq!(msg9, cc);
681        assert_eq!(msg10, reset);
682    }
683
684    #[test]
685    fn test_simple_cc_running_status() {
686        let cc = MidiMsg::ChannelVoice {
687            channel: Channel::Ch1,
688            msg: ChannelVoiceMsg::ControlChange {
689                control: crate::ControlChange::Volume(0x7F),
690            },
691        };
692        let running_cc = MidiMsg::RunningChannelVoice {
693            channel: Channel::Ch1,
694            msg: ChannelVoiceMsg::ControlChange {
695                control: crate::ControlChange::Volume(0x7F),
696            },
697        };
698        let simple_cc_msb = MidiMsg::ChannelVoice {
699            channel: Channel::Ch1,
700            msg: ChannelVoiceMsg::ControlChange {
701                control: crate::ControlChange::CC {
702                    control: 7,
703                    value: 0,
704                },
705            },
706        };
707        let simple_cc_lsb = MidiMsg::ChannelVoice {
708            channel: Channel::Ch1,
709            msg: ChannelVoiceMsg::ControlChange {
710                control: crate::ControlChange::CC {
711                    control: 7 + 32,
712                    value: 0x7F,
713                },
714            },
715        };
716
717        // Push two messages
718        let mut midi = vec![];
719        cc.extend_midi(&mut midi);
720        running_cc.extend_midi(&mut midi);
721
722        // Read back 4 messages (two are running status messages)
723        let mut offset = 0;
724        let mut ctx = ReceiverContext::new();
725        let (msg1, len) = MidiMsg::from_midi_with_context(&midi, &mut ctx).expect("Not an error");
726        offset += len;
727        let (msg2, len) =
728            MidiMsg::from_midi_with_context(&midi[offset..], &mut ctx).expect("Not an error");
729        offset += len;
730        let (msg3, len) =
731            MidiMsg::from_midi_with_context(&midi[offset..], &mut ctx).expect("Not an error");
732        offset += len;
733        let (msg4, _) =
734            MidiMsg::from_midi_with_context(&midi[offset..], &mut ctx).expect("Not an error");
735
736        // The expected messages are not running status messages, since we never deserialize into them
737        assert_eq!(msg1, simple_cc_msb);
738        assert_eq!(msg2, simple_cc_lsb);
739        assert_eq!(msg3, simple_cc_msb);
740        assert_eq!(msg4, simple_cc_lsb);
741    }
742
743    #[test]
744    fn test_next_message() {
745        let mut midi = vec![];
746        MidiMsg::ChannelVoice {
747            channel: Channel::Ch1,
748            msg: ChannelVoiceMsg::NoteOn {
749                note: 0x42,
750                velocity: 0x60,
751            },
752        }
753        .extend_midi(&mut midi);
754        let first_message_len = midi.len();
755        MidiMsg::ChannelVoice {
756            channel: Channel::Ch1,
757            msg: ChannelVoiceMsg::NoteOn {
758                note: 0x42,
759                velocity: 0x60,
760            },
761        }
762        .extend_midi(&mut midi);
763
764        assert_eq!(next_message(&midi), Some(first_message_len));
765        // Offset by a byte, so we're in the middle of a message
766        assert_eq!(next_message(&midi[1..]), Some(first_message_len - 1));
767        assert_eq!(next_message(&midi[first_message_len..]), None);
768    }
769}