1use crate::consts::system_event;
9use crate::message::{SysExEvent, SysExType};
10use crate::MidiMessage;
11
12#[derive(Clone, Copy, Debug, Eq, PartialEq)]
17pub enum ManufacturerId {
18 Id(u8),
19 ExtId(u8, u8),
20}
21
22impl ManufacturerId {
23 pub fn from_raw(raw: &[u8]) -> Option<ManufacturerId> {
27 if raw[0] != 0 {
28 Some(ManufacturerId::Id(raw[0]))
29 } else if raw.len() < 3 {
30 None
31 } else {
32 Some(ManufacturerId::ExtId(raw[1], raw[2]))
33 }
34 }
35
36 pub fn raw_len(self) -> usize {
38 match self {
39 ManufacturerId::Id(_) => 1,
40 ManufacturerId::ExtId(_, _) => 3,
41 }
42 }
43
44 pub fn push_to(self, vec: &mut Vec<u8>) {
47 match self {
48 ManufacturerId::Id(m) => vec.push(m),
49 ManufacturerId::ExtId(m1, m2) => {
50 vec.push(system_event::sysex::ID_EXTENSION);
51 vec.push(m1);
52 vec.push(m2);
53 }
54 }
55 }
56}
57
58pub struct SysExDecoder<'a>(&'a SysExEvent);
61
62impl SysExDecoder<'_> {
63 pub fn decode(msg: &MidiMessage) -> Option<SysExDecoder> {
68 if let MidiMessage::SysEx(ref e) = msg {
69 Some(SysExDecoder(e))
70 } else {
71 None
72 }
73 }
74
75 pub fn is_universal_sysex(&self) -> bool {
77 matches!(
78 self.0.get_type(),
79 SysExType::NonRealTime(_, _) | SysExType::RealTime(_, _)
80 )
81 }
82}
83
84pub struct USysExDecoder<'a>(&'a SysExEvent);
86
87impl USysExDecoder<'_> {
88 pub fn decode(msg: &MidiMessage) -> Option<USysExDecoder> {
92 if let MidiMessage::SysEx(ref e) = msg {
94 match e.get_type() {
95 SysExType::NonRealTime(_, _) | SysExType::RealTime(_, _) => {
96 return Some(USysExDecoder(e))
97 }
98 _ => {}
99 }
100 }
101 None
102 }
103
104 pub fn is_non_realtime(&self) -> bool {
106 matches!(self.0.get_type(), SysExType::NonRealTime(_, _))
107 }
108
109 pub fn target_device(&self) -> u8 {
114 match self.0.get_type() {
115 SysExType::NonRealTime(d, _) | SysExType::RealTime(d, _) => *d,
116 _ => unreachable!(),
117 }
118 }
119
120 pub fn subid(&self) -> [u8; 2] {
125 match self.0.get_type() {
126 SysExType::NonRealTime(_, subid) | SysExType::RealTime(_, subid) => *subid,
127 _ => unreachable!(),
128 }
129 }
130
131 pub fn general_info_reply_manufacturer_id(&self) -> Option<ManufacturerId> {
136 if self.is_non_realtime() && self.subid() == [6, 2] {
137 let data = self.0.get_data();
138 if data.len() >= 8 {
139 return ManufacturerId::from_raw(data);
140 }
141 }
142 None
143 }
144
145 pub fn general_info_reply_family(&self) -> Option<([u8; 2], [u8; 2])> {
150 if self.is_non_realtime() && self.subid() == [6, 2] {
151 let data = self.0.get_data();
152 if data.len() >= 8 {
153 return Some(([data[3], data[4]], [data[5], data[6]]));
154 }
155 }
156 None
157 }
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163
164 #[test]
165 pub fn test_sysex_decoder() {
166 let msg = MidiMessage::SysEx(SysExEvent::new_non_realtime(
168 0,
169 [6, 2],
170 &[0, 32, 107, 2, 0, 4, 2, 67, 7, 0, 1, 247],
171 ));
172 let decoder = SysExDecoder::decode(&msg);
173 assert!(decoder.is_some());
174 let decoder = decoder.unwrap();
175 assert!(decoder.is_universal_sysex());
176
177 let decoder = USysExDecoder::decode(&msg);
179 assert!(decoder.is_some());
180 let decoder = decoder.unwrap();
181 assert!(decoder.is_non_realtime());
182 assert_eq!(decoder.target_device(), 0);
183 assert_eq!(decoder.subid(), [6, 2]);
184 assert_eq!(
185 decoder.general_info_reply_manufacturer_id(),
186 Some(ManufacturerId::ExtId(32, 107))
187 );
188 assert_eq!(decoder.general_info_reply_family(), Some(([2, 0], [4, 2])));
189 }
190}