1use super::parse_error::*;
2use super::time_code::*;
3use super::util::*;
4use super::ReceiverContext;
5use alloc::vec::Vec;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum SystemCommonMsg {
11 TimeCodeQuarterFrame1(TimeCode),
18 TimeCodeQuarterFrame2(TimeCode),
19 TimeCodeQuarterFrame3(TimeCode),
20 TimeCodeQuarterFrame4(TimeCode),
21 TimeCodeQuarterFrame5(TimeCode),
22 TimeCodeQuarterFrame6(TimeCode),
23 TimeCodeQuarterFrame7(TimeCode),
24 TimeCodeQuarterFrame8(TimeCode),
25 SongPosition(u16),
27 SongSelect(u8),
29 TuneRequest,
31}
32
33impl SystemCommonMsg {
34 pub(crate) fn extend_midi(&self, v: &mut Vec<u8>) {
35 match self {
36 SystemCommonMsg::TimeCodeQuarterFrame1(qf) => {
37 v.push(0xF1);
38 v.push(qf.to_nibbles()[0]);
39 }
40 SystemCommonMsg::TimeCodeQuarterFrame2(qf) => {
41 v.push(0xF1);
42 v.push(qf.to_nibbles()[1]);
43 }
44 SystemCommonMsg::TimeCodeQuarterFrame3(qf) => {
45 v.push(0xF1);
46 v.push(qf.to_nibbles()[2]);
47 }
48 SystemCommonMsg::TimeCodeQuarterFrame4(qf) => {
49 v.push(0xF1);
50 v.push(qf.to_nibbles()[3]);
51 }
52 SystemCommonMsg::TimeCodeQuarterFrame5(qf) => {
53 v.push(0xF1);
54 v.push(qf.to_nibbles()[4]);
55 }
56 SystemCommonMsg::TimeCodeQuarterFrame6(qf) => {
57 v.push(0xF1);
58 v.push(qf.to_nibbles()[5]);
59 }
60 SystemCommonMsg::TimeCodeQuarterFrame7(qf) => {
61 v.push(0xF1);
62 v.push(qf.to_nibbles()[6]);
63 }
64 SystemCommonMsg::TimeCodeQuarterFrame8(qf) => {
65 v.push(0xF1);
66 v.push(qf.to_nibbles()[7]);
67 }
68 SystemCommonMsg::SongPosition(pos) => {
69 v.push(0xF2);
70 push_u14(*pos, v);
71 }
72 SystemCommonMsg::SongSelect(song) => {
73 v.push(0xF3);
74 v.push(to_u7(*song));
75 }
76 SystemCommonMsg::TuneRequest => v.push(0xF6),
77 }
78 }
79
80 pub(crate) fn from_midi(
81 m: &[u8],
82 ctx: &mut ReceiverContext,
83 ) -> Result<(Self, usize), ParseError> {
84 match m.first() {
85 Some(0xF1) => {
86 if let Some(b2) = m.get(1) {
87 if b2 > &127 {
88 Err(ParseError::ByteOverflow)
89 } else {
90 Ok((
91 match ctx.time_code.extend(*b2) {
92 0 => Self::TimeCodeQuarterFrame1(ctx.time_code),
93 1 => Self::TimeCodeQuarterFrame2(ctx.time_code),
94 2 => Self::TimeCodeQuarterFrame3(ctx.time_code),
95 3 => Self::TimeCodeQuarterFrame4(ctx.time_code),
96 4 => Self::TimeCodeQuarterFrame5(ctx.time_code),
97 5 => Self::TimeCodeQuarterFrame6(ctx.time_code),
98 6 => Self::TimeCodeQuarterFrame7(ctx.time_code),
99 7 => Self::TimeCodeQuarterFrame8(ctx.time_code),
100 _ => panic!("Should not be reachable"),
101 },
102 2,
103 ))
104 }
105 } else {
106 Err(ParseError::UnexpectedEnd)
107 }
108 }
109 Some(0xF2) => Ok((Self::SongPosition(u14_from_midi(&m[1..])?), 3)),
110 Some(0xF3) => Ok((Self::SongSelect(u7_from_midi(&m[1..])?), 2)),
111 Some(0xF6) => Ok((Self::TuneRequest, 1)),
112 Some(0xF7) => Err(ParseError::UnexpectedEndOfSystemExclusiveFlag),
113 Some(x) => Err(ParseError::UndefinedSystemCommonMessage(*x)),
114 _ => panic!("Should not be reachable"),
115 }
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use super::super::*;
122 extern crate std;
123 use std::vec;
124
125 #[test]
126 fn serialize_system_common_msg() {
127 assert_eq!(
128 MidiMsg::SystemCommon {
129 msg: SystemCommonMsg::TuneRequest
130 }
131 .to_midi(),
132 vec![0xF6]
133 );
134
135 assert_eq!(
136 MidiMsg::SystemCommon {
137 msg: SystemCommonMsg::SongSelect(69)
138 }
139 .to_midi(),
140 vec![0xF3, 69]
141 );
142
143 assert_eq!(
144 MidiMsg::SystemCommon {
145 msg: SystemCommonMsg::SongPosition(1000)
146 }
147 .to_midi(),
148 vec![0xF2, 0x68, 0x07]
149 );
150
151 let frame = TimeCode {
152 frames: 40, seconds: 58, minutes: 20, hours: 25, code_type: TimeCodeType::DF30, };
158
159 assert_eq!(
160 MidiMsg::SystemCommon {
161 msg: SystemCommonMsg::TimeCodeQuarterFrame1(frame)
162 }
163 .to_midi(),
164 vec![0xF1, 0b1101]
165 );
166 assert_eq!(
167 MidiMsg::SystemCommon {
168 msg: SystemCommonMsg::TimeCodeQuarterFrame2(frame)
169 }
170 .to_midi(),
171 vec![0xF1, 0b00010000 + 0b0001]
172 );
173 assert_eq!(
174 MidiMsg::SystemCommon {
175 msg: SystemCommonMsg::TimeCodeQuarterFrame3(frame)
176 }
177 .to_midi(),
178 vec![0xF1, 0b00100000 + 0b1010]
179 );
180 assert_eq!(
181 MidiMsg::SystemCommon {
182 msg: SystemCommonMsg::TimeCodeQuarterFrame4(frame)
183 }
184 .to_midi(),
185 vec![0xF1, 0b00110000 + 0b0011]
186 );
187 assert_eq!(
188 MidiMsg::SystemCommon {
189 msg: SystemCommonMsg::TimeCodeQuarterFrame5(frame)
190 }
191 .to_midi(),
192 vec![0xF1, 0b01000000 + 0b0100]
193 );
194 assert_eq!(
195 MidiMsg::SystemCommon {
196 msg: SystemCommonMsg::TimeCodeQuarterFrame6(frame)
197 }
198 .to_midi(),
199 vec![0xF1, 0b01010000 + 0b0001]
200 );
201 assert_eq!(
202 MidiMsg::SystemCommon {
203 msg: SystemCommonMsg::TimeCodeQuarterFrame7(frame)
204 }
205 .to_midi(),
206 vec![0xF1, 0b01100000 + 0b0111]
207 );
208 assert_eq!(
209 MidiMsg::SystemCommon {
210 msg: SystemCommonMsg::TimeCodeQuarterFrame8(frame)
211 }
212 .to_midi(),
213 vec![0xF1, 0b01110000 + 0b0101]
214 );
215 }
216
217 #[test]
218 fn deserialize_system_common_msg() {
219 let mut ctx = ReceiverContext::new();
220
221 test_serialization(
222 MidiMsg::SystemCommon {
223 msg: SystemCommonMsg::TuneRequest,
224 },
225 &mut ctx,
226 );
227
228 test_serialization(
229 MidiMsg::SystemCommon {
230 msg: SystemCommonMsg::SongPosition(1000),
231 },
232 &mut ctx,
233 );
234
235 MidiMsg::from_midi_with_context(&[0xF1, 0b1101], &mut ctx)
236 .expect("Expected a timecode, got an error");
237 MidiMsg::from_midi_with_context(&[0xF1, 0b00010000 + 0b0001], &mut ctx)
238 .expect("Expected a timecode, got an error");
239 MidiMsg::from_midi_with_context(&[0xF1, 0b00100000 + 0b1010], &mut ctx)
240 .expect("Expected a timecode, got an error");
241 MidiMsg::from_midi_with_context(&[0xF1, 0b00110000 + 0b0011], &mut ctx)
242 .expect("Expected a timecode, got an error");
243 MidiMsg::from_midi_with_context(&[0xF1, 0b01000000 + 0b0100], &mut ctx)
244 .expect("Expected a timecode, got an error");
245 MidiMsg::from_midi_with_context(&[0xF1, 0b01010000 + 0b0001], &mut ctx)
246 .expect("Expected a timecode, got an error");
247 MidiMsg::from_midi_with_context(&[0xF1, 0b01100000 + 0b0111], &mut ctx)
248 .expect("Expected a timecode, got an error");
249 MidiMsg::from_midi_with_context(&[0xF1, 0b01110000 + 0b0101], &mut ctx)
250 .expect("Expected a timecode, got an error");
251
252 assert_eq!(
253 ctx.time_code,
254 TimeCode {
255 frames: 29, seconds: 58, minutes: 20, hours: 23, code_type: TimeCodeType::DF30, }
261 );
262 }
263}