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