1use crate::consts;
10use crate::note::MidiNote;
11use crate::sysex;
12
13#[derive(Clone, Copy, Debug, Eq, PartialEq)]
15#[repr(u8)]
16pub enum Channel {
17 Ch1,
18 Ch2,
19 Ch3,
20 Ch4,
21 Ch5,
22 Ch6,
23 Ch7,
24 Ch8,
25 Ch9,
26 Ch10,
27 Ch11,
28 Ch12,
29 Ch13,
30 Ch14,
31 Ch15,
32 Ch16,
33 Invalid,
34}
35
36impl Channel {
37 pub fn from_midi_cmd(v: u8) -> Channel {
39 Self::from(v & consts::MIDI_CHANNEL_MASK)
40 }
41}
42
43impl From<u8> for Channel {
44 fn from(v: u8) -> Channel {
48 use Channel::*;
49 match v {
50 0 => Ch1,
51 1 => Ch2,
52 2 => Ch3,
53 3 => Ch4,
54 4 => Ch5,
55 5 => Ch6,
56 6 => Ch7,
57 7 => Ch8,
58 8 => Ch9,
59 9 => Ch10,
60 10 => Ch11,
61 11 => Ch12,
62 12 => Ch13,
63 13 => Ch14,
64 14 => Ch15,
65 15 => Ch16,
66 _ => Invalid,
67 }
68 }
69}
70
71#[derive(Clone, Debug, Eq, PartialEq)]
76pub struct KeyEvent {
77 pub key: MidiNote,
79 pub value: u8,
81}
82
83#[derive(Debug, Eq, PartialEq)]
85pub struct ControlEvent {
86 pub control: u8,
88 pub value: u8,
90}
91
92#[derive(Debug, Eq, PartialEq)]
94pub enum SysExType {
95 Manufacturer(sysex::ManufacturerId),
97 NonRealTime(u8, [u8; 2]),
100 RealTime(u8, [u8; 2]),
103}
104
105#[derive(Debug, Eq, PartialEq)]
107pub struct SysExEvent {
108 pub r#type: SysExType,
110 pub data: Vec<u8>,
112}
113
114impl SysExEvent {
115 pub fn new_manufacturer(manufacturer: sysex::ManufacturerId, data: &[u8]) -> SysExEvent {
118 SysExEvent {
119 r#type: SysExType::Manufacturer(manufacturer),
120 data: Vec::from(data),
121 }
122 }
123
124 pub fn new_non_realtime(device: u8, subids: [u8; 2], data: &[u8]) -> SysExEvent {
129 SysExEvent {
130 r#type: SysExType::NonRealTime(device, subids),
131 data: Vec::from(data),
132 }
133 }
134
135 pub fn new_realtime(device: u8, subids: [u8; 2], data: &[u8]) -> SysExEvent {
140 SysExEvent {
141 r#type: SysExType::RealTime(device, subids),
142 data: Vec::from(data),
143 }
144 }
145
146 pub fn get_type(&self) -> &SysExType {
148 &self.r#type
149 }
150
151 pub fn get_data(&self) -> &Vec<u8> {
153 &self.data
154 }
155}
156
157#[derive(Debug, Eq, PartialEq)]
160pub enum MidiMessage {
161 Invalid,
163 NoteOn(Channel, KeyEvent),
165 NoteOff(Channel, KeyEvent),
167 PolyKeyPressure(Channel, KeyEvent),
169 ControlChange(Channel, ControlEvent),
171 ProgramChange(Channel, u8),
173 ChannelPressure(Channel, u8),
175 PitchBend(Channel, u8, u8),
177 SysEx(SysExEvent),
179}
180
181impl MidiMessage {
182 pub fn get_channel(&self) -> Channel {
186 use MidiMessage::*;
187 match *self {
188 Invalid | SysEx(_) => Channel::Invalid,
189 NoteOn(ch, _)
190 | NoteOff(ch, _)
191 | PolyKeyPressure(ch, _)
192 | ControlChange(ch, _)
193 | ProgramChange(ch, _)
194 | ChannelPressure(ch, _)
195 | PitchBend(ch, _, _) => ch,
196 }
197 }
198
199 fn sysex_message_from(data: &[u8]) -> MidiMessage {
203 use consts::system_event::sysex::*;
204
205 if data[0] != consts::SYSEX {
206 return MidiMessage::Invalid;
207 }
208
209 let idx;
210 let manufacturer = data[1];
211 let r#type = match manufacturer {
212 NON_REAL_TIME => {
213 idx = 5;
214 SysExType::NonRealTime(data[2], [data[3], data[4]])
215 }
216 REAL_TIME => {
217 idx = 5;
218 SysExType::RealTime(data[2], [data[3], data[4]])
219 }
220 _ => {
221 let (_, d) = data.split_at(1);
222 let manufacturer = sysex::ManufacturerId::from_raw(d).unwrap();
223 idx = 1 + manufacturer.raw_len();
224 SysExType::Manufacturer(manufacturer)
225 }
226 };
227 MidiMessage::SysEx(SysExEvent {
228 r#type,
229 data: data.split_at(idx).1.to_vec(),
230 })
231 }
232}
233
234impl From<MidiMessage> for Vec<u8> {
235 fn from(message: MidiMessage) -> Vec<u8> {
239 use MidiMessage::*;
240 match message {
241 NoteOff(ch, e) => vec![consts::NOTE_OFF | ch as u8, e.key, e.value],
242 NoteOn(ch, e) => vec![consts::NOTE_ON | ch as u8, e.key, e.value],
243 PolyKeyPressure(ch, e) => {
244 vec![consts::POLYPHONIC_KEY_PRESSURE | ch as u8, e.key, e.value]
245 }
246 ControlChange(ch, e) => vec![consts::CONTROL_CHANGE | ch as u8, e.control, e.value],
247 ProgramChange(ch, p) => vec![consts::PROGRAM_CHANGE | ch as u8, p, 0],
248 ChannelPressure(ch, p) => vec![consts::CHANNEL_KEY_PRESSURE | ch as u8, p, 0],
249 PitchBend(ch, lsb, msb) => vec![consts::PITCH_BEND_CHANGE | ch as u8, lsb, msb],
250 SysEx(ref e) => {
251 let out_size = match e.r#type {
252 SysExType::Manufacturer(m) => 1 + m.raw_len() + e.data.len(),
253 SysExType::NonRealTime(_, _) | SysExType::RealTime(_, _) => 5 + e.data.len(),
254 };
255 let mut vec = Vec::with_capacity(out_size);
256 vec.push(consts::SYSEX);
257 use SysExType::*;
258 match e.r#type {
259 Manufacturer(ref b) => b.push_to(&mut vec),
260 NonRealTime(d, id) => {
261 vec.push(consts::system_event::sysex::NON_REAL_TIME);
262 vec.push(d);
263 vec.extend_from_slice(&id);
264 }
265 RealTime(d, id) => {
266 vec.push(consts::system_event::sysex::REAL_TIME);
267 vec.push(d);
268 vec.extend_from_slice(&id);
269 }
270 }
271 vec.extend_from_slice(&e.data);
272 vec
273 }
274 Invalid => vec![],
275 }
276 }
277}
278
279impl From<&[u8]> for MidiMessage {
280 fn from(data: &[u8]) -> MidiMessage {
282 if data.len() < 3 {
283 MidiMessage::Invalid
284 } else {
285 let (event, channel) = if data[0] < consts::SYSEX {
286 (
287 data[0] & consts::EVENT_TYPE_MASK,
288 data[0] & consts::MIDI_CHANNEL_MASK,
289 )
290 } else {
291 (data[0], 0u8)
292 };
293 match event {
294 consts::NOTE_OFF => {
295 MidiMessage::NoteOff(
297 Channel::from(channel),
298 KeyEvent {
299 key: data[1],
300 value: data[2],
301 },
302 )
303 }
304 consts::NOTE_ON => {
305 MidiMessage::NoteOn(
307 Channel::from(channel),
308 KeyEvent {
309 key: data[1],
310 value: data[2],
311 },
312 )
313 }
314 consts::POLYPHONIC_KEY_PRESSURE => MidiMessage::PolyKeyPressure(
315 Channel::from(channel),
316 KeyEvent {
317 key: data[1],
318 value: data[2],
319 },
320 ),
321 consts::CONTROL_CHANGE => MidiMessage::ControlChange(
322 Channel::from(channel),
323 ControlEvent {
324 control: data[1],
325 value: data[2],
326 },
327 ),
328 consts::PROGRAM_CHANGE => {
329 MidiMessage::ProgramChange(Channel::from(channel), data[1])
330 }
331 consts::CHANNEL_KEY_PRESSURE => {
332 MidiMessage::ChannelPressure(Channel::from(channel), data[1])
333 }
334 consts::PITCH_BEND_CHANGE => {
335 MidiMessage::PitchBend(Channel::from(channel), data[1], data[2])
336 }
337 consts::SYSEX => MidiMessage::sysex_message_from(data),
338 _ => MidiMessage::Invalid,
340 }
341 }
342 }
343}
344
345#[cfg(test)]
346mod tests {
347 use super::*;
348
349 #[test]
350 pub fn test_midi_channel() {
351 let ch = Channel::from_midi_cmd(128);
352 assert_eq!(ch, Channel::Ch1);
353
354 let ch = Channel::from_midi_cmd(137);
355 assert_eq!(ch, Channel::Ch10);
356 }
357
358 #[test]
359 pub fn test_midi_from_to_raw() {
360 let raw = vec![0u8];
362 let msg = MidiMessage::Invalid;
363 assert_eq!(MidiMessage::from(raw.as_slice()), msg);
364 let out: Vec<u8> = msg.into();
365 assert!(out.len() == 0);
366
367 let raw = vec![144u8, 59u8, 88u8];
369 let msg = MidiMessage::NoteOn(Channel::Ch1, KeyEvent { key: 59, value: 88 });
370 assert_eq!(MidiMessage::from(raw.as_slice()), msg);
371 let out: Vec<u8> = msg.into();
372 assert_eq!(out, raw);
373
374 let raw = vec![128u8, 60u8, 0u8];
376 let msg = MidiMessage::NoteOff(Channel::Ch1, KeyEvent { key: 60, value: 0 });
377 assert_eq!(MidiMessage::from(raw.as_slice()), msg);
378 let out: Vec<u8> = msg.into();
379 assert_eq!(out, raw);
380
381 let raw = vec![176, 114, 65];
383 let msg = MidiMessage::ControlChange(
384 Channel::Ch1,
385 ControlEvent {
386 control: 114,
387 value: 65,
388 },
389 );
390 assert_eq!(MidiMessage::from(raw.as_slice()), msg);
391 let out: Vec<u8> = msg.into();
392 assert_eq!(out, raw);
393
394 let raw = vec![224, 0, 76];
396 let msg = MidiMessage::PitchBend(Channel::Ch1, 0, 76);
397 assert_eq!(MidiMessage::from(raw.as_slice()), msg);
398 let out: Vec<u8> = msg.into();
399 assert_eq!(out, raw);
400
401 let raw = vec![240, 30, 127, 66, 2, 0, 0, 16, 127, 247];
403 let msg = MidiMessage::SysEx(SysExEvent::new_manufacturer(
404 sysex::ManufacturerId::Id(30),
405 &[127, 66, 2, 0, 0, 16, 127, 247],
406 ));
407 assert_eq!(MidiMessage::from(raw.as_slice()), msg);
408 let out: Vec<u8> = msg.into();
409 assert_eq!(out, raw);
410
411 let raw = vec![240, 0, 32, 107, 127, 66, 2, 0, 0, 16, 127, 247];
412 let msg = MidiMessage::SysEx(SysExEvent::new_manufacturer(
413 sysex::ManufacturerId::ExtId(32, 107),
414 &[127, 66, 2, 0, 0, 16, 127, 247],
415 ));
416 assert_eq!(MidiMessage::from(raw.as_slice()), msg);
417 let out: Vec<u8> = msg.into();
418 assert_eq!(out, raw);
419
420 let raw = vec![240, 126, 0, 6, 2, 0, 32, 107, 2, 0, 4, 2, 67, 7, 0, 1, 247];
422 let msg = MidiMessage::SysEx(SysExEvent::new_non_realtime(
423 0,
424 [6, 2],
425 &[0, 32, 107, 2, 0, 4, 2, 67, 7, 0, 1, 247],
426 ));
427 assert_eq!(MidiMessage::from(raw.as_slice()), msg);
428 let out: Vec<u8> = msg.into();
429 assert_eq!(out, raw);
430 }
431}