midi_msg/system_exclusive/
notation.rs

1use crate::parse_error::*;
2use crate::util::*;
3use alloc::vec;
4use alloc::vec::Vec;
5
6/// Indicates that the next MIDI clock message is the first clock of a new measure. Which bar
7/// is optionally indicated by this message.
8/// Used by [`UniversalRealTimeMsg::BarMarker`](crate::UniversalRealTimeMsg::BarMarker).
9#[derive(Debug, Copy, Clone, PartialEq, Eq)]
10pub enum BarMarker {
11    /// "Actually, we're not running right now, so there is no bar." Don't know why this is used.
12    NotRunning,
13    /// The bar is a count-in and are thus negative numbers from 8191-0.
14    CountIn(u16), // ?
15    /// A regular bar numbered 1-8191.
16    Number(u16),
17    /// Next clock message will be a new bar, but it's not known what its number is.
18    RunningUnknown,
19}
20
21impl BarMarker {
22    pub(crate) fn extend_midi(&self, v: &mut Vec<u8>) {
23        match *self {
24            Self::NotRunning => {
25                // Most negative number
26                v.push(0x00);
27                v.push(0x40);
28            }
29            Self::CountIn(x) => {
30                push_i14(-(x.min(8191) as i16), v);
31            }
32            Self::Number(x) => {
33                push_i14(x.min(8191) as i16, v);
34            }
35            Self::RunningUnknown => {
36                // Most positive number
37                v.push(0x7F);
38                v.push(0x3F);
39            }
40        }
41    }
42
43    #[allow(dead_code)]
44    pub(crate) fn from_midi(_m: &[u8]) -> Result<(Self, usize), ParseError> {
45        Err(ParseError::NotImplemented("BarMarker"))
46    }
47}
48
49/// Used to communicate a new time signature to the receiver.
50/// Used by [`UniversalRealTimeMsg`](crate::UniversalRealTimeMsg).
51#[derive(Debug, Clone, PartialEq, Eq)]
52pub struct TimeSignature {
53    /// The base time signature.
54    pub signature: Signature,
55    /// How many MIDI clock events per metronome click.
56    /// 24 indicates one click per quarter note (unless specified otherwise by `thirty_second_notes_in_midi_quarter_note`)
57    pub midi_clocks_in_metronome_click: u8,
58    /// Number of notated 32nd notes in a MIDI quarter note.
59    /// 8 is the normal value (e.g. a midi quarter note is a quarter note)
60    pub thirty_second_notes_in_midi_quarter_note: u8,
61    /// At most 61 (!) additional times signatures for compound time definitions
62    pub compound: Vec<Signature>,
63}
64
65impl Default for TimeSignature {
66    fn default() -> Self {
67        Self {
68            signature: Default::default(),
69            midi_clocks_in_metronome_click: 24, // one click per quarter note
70            thirty_second_notes_in_midi_quarter_note: 8, // Midi quarter note is a quarter note
71            compound: vec![],
72        }
73    }
74}
75
76impl TimeSignature {
77    pub(crate) fn extend_midi(&self, v: &mut Vec<u8>) {
78        v.push((4 + (self.compound.len() * 2)).min(126) as u8); // Bytes to follow
79        self.signature.extend_midi(v);
80        v.push(to_u7(self.midi_clocks_in_metronome_click));
81        v.push(to_u7(self.thirty_second_notes_in_midi_quarter_note));
82        for (i, s) in self.compound.iter().enumerate() {
83            if i >= 61 {
84                break;
85            }
86            s.extend_midi(v);
87        }
88    }
89
90    #[allow(dead_code)]
91    pub(crate) fn from_midi(_m: &[u8]) -> Result<(Self, usize), ParseError> {
92        Err(ParseError::NotImplemented("TimeSignature"))
93    }
94}
95
96/// A [time signature](https://en.wikipedia.org/wiki/Time_signature). Used by [`TimeSignature`].
97#[derive(Debug, Copy, Clone, PartialEq, Eq)]
98pub struct Signature {
99    /// Number of beats in a bar.
100    pub beats: u8,
101    /// The note value for each beat.
102    pub beat_value: BeatValue,
103}
104
105impl Signature {
106    fn extend_midi(&self, v: &mut Vec<u8>) {
107        v.push(to_u7(self.beats));
108        v.push(self.beat_value.to_u8());
109    }
110
111    #[allow(dead_code)]
112    pub(crate) fn from_midi(_m: &[u8]) -> Result<(Self, usize), ParseError> {
113        Err(ParseError::NotImplemented("Signature"))
114    }
115}
116
117impl Default for Signature {
118    fn default() -> Self {
119        Self {
120            beats: 4,
121            beat_value: BeatValue::Quarter,
122        }
123    }
124}
125
126/// The note value of a beat, used by [`Signature`].
127#[derive(Debug, Copy, Clone, PartialEq, Eq)]
128pub enum BeatValue {
129    Whole,
130    Half,
131    Quarter,
132    Eighth,
133    Sixteenth,
134    ThirtySecond,
135    SixtyFourth,
136    /// Any other value interpreted as 2^x.
137    /// The spec does not limit this value, so the maximum is a crazy 2^127
138    Other(u8),
139}
140
141impl BeatValue {
142    fn to_u8(self) -> u8 {
143        match self {
144            Self::Whole => 0,
145            Self::Half => 1,
146            Self::Quarter => 2,
147            Self::Eighth => 3,
148            Self::Sixteenth => 4,
149            Self::ThirtySecond => 5,
150            Self::SixtyFourth => 6,
151            Self::Other(x) => to_u7(x),
152        }
153    }
154
155    #[allow(dead_code)]
156    fn from_byte(_m: u8) -> Self {
157        // TODO
158        Self::Quarter
159    }
160}
161
162#[cfg(test)]
163mod tests {
164    use crate::*;
165    use alloc::vec;
166
167    #[test]
168    fn serialize_bar_marker() {
169        assert_eq!(
170            MidiMsg::SystemExclusive {
171                msg: SystemExclusiveMsg::UniversalRealTime {
172                    device: DeviceID::AllCall,
173                    msg: UniversalRealTimeMsg::BarMarker(BarMarker::NotRunning),
174                },
175            }
176            .to_midi(),
177            vec![0xF0, 0x7F, 0x7f, 0x3, 0x1, 0x00, 0x40, 0xF7]
178        );
179
180        assert_eq!(
181            MidiMsg::SystemExclusive {
182                msg: SystemExclusiveMsg::UniversalRealTime {
183                    device: DeviceID::AllCall,
184                    msg: UniversalRealTimeMsg::BarMarker(BarMarker::CountIn(1)),
185                },
186            }
187            .to_midi(),
188            vec![0xF0, 0x7F, 0x7f, 0x3, 0x1, 0x7f, 0x7f, 0xF7]
189        );
190
191        assert_eq!(
192            MidiMsg::SystemExclusive {
193                msg: SystemExclusiveMsg::UniversalRealTime {
194                    device: DeviceID::AllCall,
195                    msg: UniversalRealTimeMsg::BarMarker(BarMarker::Number(1)),
196                },
197            }
198            .to_midi(),
199            vec![0xF0, 0x7F, 0x7f, 0x3, 0x1, 0x01, 0x00, 0xF7]
200        );
201
202        assert_eq!(
203            MidiMsg::SystemExclusive {
204                msg: SystemExclusiveMsg::UniversalRealTime {
205                    device: DeviceID::AllCall,
206                    msg: UniversalRealTimeMsg::BarMarker(BarMarker::RunningUnknown),
207                },
208            }
209            .to_midi(),
210            vec![0xF0, 0x7F, 0x7f, 0x3, 0x1, 0x7f, 0x3f, 0xF7]
211        );
212    }
213
214    #[test]
215    fn serialize_time_signature() {
216        assert_eq!(
217            MidiMsg::SystemExclusive {
218                msg: SystemExclusiveMsg::UniversalRealTime {
219                    device: DeviceID::AllCall,
220                    msg: UniversalRealTimeMsg::TimeSignatureDelayed(TimeSignature::default()),
221                },
222            }
223            .to_midi(),
224            vec![0xF0, 0x7F, 0x7f, 0x3, 0x42, 4, 4, 2, 24, 8, 0xF7]
225        );
226
227        assert_eq!(
228            MidiMsg::SystemExclusive {
229                msg: SystemExclusiveMsg::UniversalRealTime {
230                    device: DeviceID::AllCall,
231                    msg: UniversalRealTimeMsg::TimeSignature(TimeSignature {
232                        compound: vec! {Signature {
233                            beats: 3,
234                            beat_value: BeatValue::Eighth,
235                        }},
236                        ..Default::default()
237                    }),
238                },
239            }
240            .to_midi(),
241            vec![0xF0, 0x7F, 0x7f, 0x3, 0x02, 6, 4, 2, 24, 8, 3, 3, 0xF7]
242        );
243    }
244}