Skip to main content

midi_msg/
system_real_time.rs

1use super::parse_error::*;
2use alloc::vec::Vec;
3
4/// A fairly limited set of messages used for device synchronization.
5/// Used in [`MidiMsg`](crate::MidiMsg).
6#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum SystemRealTimeMsg {
9    /// Used to synchronize clocks. Sent at a rate of 24 per quarter note.
10    TimingClock,
11    /// Start at the beginning of the song or sequence.
12    Start,
13    /// Continue from the current location in the song or sequence.
14    Continue,
15    /// Stop playback.
16    Stop,
17    /// Sent every 300ms or less whenever other MIDI data is not sent.
18    /// Used to indicate that the given device is still connected.
19    ActiveSensing,
20    /// Request that all devices are reset to their power-up state.
21    ///
22    /// This is not a valid message in a MIDI file, since it overlaps
23    /// with the MIDI file's Meta messages. If you add this message to a
24    /// MIDI file, it will be ignored upon serialization.
25    SystemReset,
26}
27
28impl SystemRealTimeMsg {
29    pub(crate) fn extend_midi(&self, v: &mut Vec<u8>) {
30        match self {
31            Self::TimingClock => v.push(0xF8),
32            Self::Start => v.push(0xFA),
33            Self::Continue => v.push(0xFB),
34            Self::Stop => v.push(0xFC),
35            Self::ActiveSensing => v.push(0xFE),
36            Self::SystemReset => v.push(0xFF),
37        }
38    }
39
40    pub(crate) fn from_midi(m: &[u8]) -> Result<(Self, usize), ParseError> {
41        match m.first() {
42            Some(0xF8) => Ok((Self::TimingClock, 1)),
43            Some(0xFA) => Ok((Self::Start, 1)),
44            Some(0xFB) => Ok((Self::Continue, 1)),
45            Some(0xFC) => Ok((Self::Stop, 1)),
46            Some(0xFE) => Ok((Self::ActiveSensing, 1)),
47            Some(0xFF) => Ok((Self::SystemReset, 1)),
48            Some(x) => Err(ParseError::UndefinedSystemRealTimeMessage(*x)),
49            None => panic!("Should not be reachable"),
50        }
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use crate::*;
57    extern crate std;
58    use std::vec;
59
60    #[test]
61    fn serialize_system_real_time_msg() {
62        assert_eq!(
63            MidiMsg::SystemRealTime {
64                msg: SystemRealTimeMsg::TimingClock
65            }
66            .to_midi(),
67            vec![0xF8]
68        );
69    }
70
71    #[test]
72    fn deserialize_system_real_time_msg() {
73        let mut ctx = ReceiverContext::new();
74
75        test_serialization(
76            MidiMsg::SystemRealTime {
77                msg: SystemRealTimeMsg::TimingClock,
78            },
79            &mut ctx,
80        );
81    }
82
83    #[test]
84    fn serde_system_reset() {
85        let system_reset = MidiMsg::SystemRealTime {
86            msg: SystemRealTimeMsg::SystemReset,
87        };
88        assert_eq!(
89            MidiMsg::from_midi_with_context(&system_reset.to_midi(), &mut ReceiverContext::new()),
90            Ok((system_reset, 1)),
91        );
92    }
93}