midi_msg/system_exclusive/
notation.rs1use crate::parse_error::*;
2use crate::util::*;
3use alloc::vec;
4use alloc::vec::Vec;
5
6#[derive(Debug, Copy, Clone, PartialEq, Eq)]
10pub enum BarMarker {
11 NotRunning,
13 CountIn(u16), Number(u16),
17 RunningUnknown,
19}
20
21impl BarMarker {
22 pub(crate) fn extend_midi(&self, v: &mut Vec<u8>) {
23 match *self {
24 Self::NotRunning => {
25 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 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#[derive(Debug, Clone, PartialEq, Eq)]
52pub struct TimeSignature {
53 pub signature: Signature,
55 pub midi_clocks_in_metronome_click: u8,
58 pub thirty_second_notes_in_midi_quarter_note: u8,
61 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, thirty_second_notes_in_midi_quarter_note: 8, 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); 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#[derive(Debug, Copy, Clone, PartialEq, Eq)]
98pub struct Signature {
99 pub beats: u8,
101 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#[derive(Debug, Copy, Clone, PartialEq, Eq)]
128pub enum BeatValue {
129 Whole,
130 Half,
131 Quarter,
132 Eighth,
133 Sixteenth,
134 ThirtySecond,
135 SixtyFourth,
136 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 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}