1use crate::packet::UsbMidiEventPacketError;
4
5#[derive(Debug, Clone, Copy, Eq, PartialEq)]
9#[repr(u8)]
10pub enum CodeIndexNumber {
11 MiscFunction = 0x00,
13 CableEvents = 0x1,
15 SystemCommon2Bytes = 0x2,
17 SystemCommon3Bytes = 0x3,
19 SysexStartsOrContinues = 0x4,
21 SystemCommon1Byte = 0x5,
23 SysexEnds2Bytes = 0x6,
25 SysexEnds3Bytes = 0x7,
27 NoteOff = 0x8,
29 NoteOn = 0x9,
31 PolyKeyPress = 0xA,
33 ControlChange = 0xB,
35 ProgramChange = 0xC,
37 ChannelPressure = 0xD,
39 PitchBendChange = 0xE,
41 SingleByte = 0xF,
43}
44
45impl TryFrom<u8> for CodeIndexNumber {
46 type Error = UsbMidiEventPacketError;
47
48 fn try_from(value: u8) -> Result<Self, Self::Error> {
49 match value {
50 x if x == CodeIndexNumber::MiscFunction as u8 => Ok(CodeIndexNumber::MiscFunction),
51 x if x == CodeIndexNumber::CableEvents as u8 => Ok(CodeIndexNumber::CableEvents),
52 x if x == CodeIndexNumber::SystemCommon2Bytes as u8 => {
53 Ok(CodeIndexNumber::SystemCommon2Bytes)
54 }
55 x if x == CodeIndexNumber::SystemCommon3Bytes as u8 => {
56 Ok(CodeIndexNumber::SystemCommon3Bytes)
57 }
58 x if x == CodeIndexNumber::SysexStartsOrContinues as u8 => {
59 Ok(CodeIndexNumber::SysexStartsOrContinues)
60 }
61 x if x == CodeIndexNumber::SystemCommon1Byte as u8 => {
62 Ok(CodeIndexNumber::SystemCommon1Byte)
63 }
64 x if x == CodeIndexNumber::SysexEnds2Bytes as u8 => {
65 Ok(CodeIndexNumber::SysexEnds2Bytes)
66 }
67 x if x == CodeIndexNumber::SysexEnds3Bytes as u8 => {
68 Ok(CodeIndexNumber::SysexEnds3Bytes)
69 }
70 x if x == CodeIndexNumber::NoteOff as u8 => Ok(CodeIndexNumber::NoteOff),
71 x if x == CodeIndexNumber::NoteOn as u8 => Ok(CodeIndexNumber::NoteOn),
72 x if x == CodeIndexNumber::PolyKeyPress as u8 => Ok(CodeIndexNumber::PolyKeyPress),
73 x if x == CodeIndexNumber::ControlChange as u8 => Ok(CodeIndexNumber::ControlChange),
74 x if x == CodeIndexNumber::ProgramChange as u8 => Ok(CodeIndexNumber::ProgramChange),
75 x if x == CodeIndexNumber::ChannelPressure as u8 => {
76 Ok(CodeIndexNumber::ChannelPressure)
77 }
78 x if x == CodeIndexNumber::PitchBendChange as u8 => {
79 Ok(CodeIndexNumber::PitchBendChange)
80 }
81 x if x == CodeIndexNumber::SingleByte as u8 => Ok(CodeIndexNumber::SingleByte),
82 _ => Err(UsbMidiEventPacketError::InvalidCodeIndexNumber(value)),
83 }
84 }
85}
86
87impl CodeIndexNumber {
88 pub fn try_from_payload(payload: &[u8]) -> Result<Self, UsbMidiEventPacketError> {
92 let Some(status) = payload.first() else {
93 return Err(UsbMidiEventPacketError::EmptyPayload);
94 };
95
96 if *status < 0xF0 {
97 match status & 0xF0 {
98 0x80 => Ok(Self::NoteOff),
99 0x90 => Ok(Self::NoteOn),
100 0xA0 => Ok(Self::PolyKeyPress),
101 0xB0 => Ok(Self::ControlChange),
102 0xC0 => Ok(Self::ProgramChange),
103 0xD0 => Ok(Self::ChannelPressure),
104 0xE0 => Ok(Self::PitchBendChange),
105 _ => {
106 if payload.len() > 1 && payload[1] == 0xF7 {
107 Ok(Self::SysexEnds2Bytes)
108 } else if payload.len() > 2 && payload[2] == 0xF7 {
109 Ok(Self::SysexEnds3Bytes)
110 } else if payload.len() == 1 {
111 Ok(Self::SingleByte)
112 } else if payload.len() > 2 {
113 Ok(Self::SysexStartsOrContinues)
114 } else {
115 Err(UsbMidiEventPacketError::InvalidPayloadSize)
116 }
117 }
118 }
119 } else {
120 match status {
121 0xF0 => {
122 if payload.len() > 1 && payload[1] == 0xF7 {
123 Ok(Self::SysexEnds2Bytes)
124 } else if payload.len() > 2 && payload[2] == 0xF7 {
125 Ok(Self::SysexEnds3Bytes)
126 } else if payload.len() > 2 {
127 Ok(Self::SysexStartsOrContinues)
128 } else {
129 Err(UsbMidiEventPacketError::InvalidPayloadSize)
130 }
131 }
132 0xF1 | 0xF3 => Ok(Self::SystemCommon2Bytes),
133 0xF2 => Ok(Self::SystemCommon3Bytes),
134 0xF6 | 0xF7 => Ok(Self::SystemCommon1Byte),
135 0xF8 | 0xF9 | 0xFA | 0xFB | 0xFC | 0xFE | 0xFF => Ok(Self::SingleByte),
136 _ => Err(UsbMidiEventPacketError::InvalidPayloadStatus),
137 }
138 }
139 }
140
141 pub fn payload_size(&self) -> usize {
143 match self {
144 Self::SystemCommon1Byte | Self::SingleByte => 1,
145 Self::SystemCommon2Bytes
146 | Self::SysexEnds2Bytes
147 | Self::ProgramChange
148 | Self::ChannelPressure => 2,
149 Self::SystemCommon3Bytes
150 | Self::SysexEnds3Bytes
151 | Self::SysexStartsOrContinues
152 | Self::NoteOff
153 | Self::NoteOn
154 | Self::PolyKeyPress
155 | Self::ControlChange
156 | Self::PitchBendChange => 3,
157
158 Self::MiscFunction | Self::CableEvents => 3,
161 }
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168
169 macro_rules! encode_payload_test {
170 ($($id:ident: $value:expr,)*) => {
171 $(
172 #[test]
173 fn $id() {
174 let (payload, expected) = $value;
175 let cin = CodeIndexNumber::try_from_payload(&payload);
176 assert_eq!(cin, expected);
177 }
178 )*
179 }
180 }
181
182 encode_payload_test! {
183 note_off: ([0x80, 60, 64], Ok(CodeIndexNumber::NoteOff)),
184 note_on: ([0x90, 60, 64], Ok(CodeIndexNumber::NoteOn)),
185 poly_key_press: ([0xA0, 48, 32], Ok(CodeIndexNumber::PolyKeyPress)),
186 control_change: ([0xB0, 10, 127], Ok(CodeIndexNumber::ControlChange)),
187 program_change: ([0xC0, 5], Ok(CodeIndexNumber::ProgramChange)),
188 channel_pressure: ([0xD0, 54], Ok(CodeIndexNumber::ChannelPressure)),
189 pitch_bend: ([0xE0, 32, 96], Ok(CodeIndexNumber::PitchBendChange)),
190 mtc_quarter_frame: ([0xF1, 12], Ok(CodeIndexNumber::SystemCommon2Bytes)),
191 song_position_pointer: ([0xF2, 3, 8], Ok(CodeIndexNumber::SystemCommon3Bytes)),
192 song_select: ([0xF3, 15], Ok(CodeIndexNumber::SystemCommon2Bytes)),
193 tune_request: ([0xF6], Ok(CodeIndexNumber::SystemCommon1Byte)),
194 timing_clock: ([0xF8], Ok(CodeIndexNumber::SingleByte)),
195 tick: ([0xF9], Ok(CodeIndexNumber::SingleByte)),
196 start: ([0xFA], Ok(CodeIndexNumber::SingleByte)),
197 continue_: ([0xFB], Ok(CodeIndexNumber::SingleByte)),
198 stop: ([0xFC], Ok(CodeIndexNumber::SingleByte)),
199 active_sensing: ([0xFE], Ok(CodeIndexNumber::SingleByte)),
200 system_reset: ([0xFF], Ok(CodeIndexNumber::SingleByte)),
201 sysex_starts: ([0xF0, 1, 2], Ok(CodeIndexNumber::SysexStartsOrContinues)),
202 sysex_starts_1byte: ([0xF0], Err(UsbMidiEventPacketError::InvalidPayloadSize)),
203 sysex_starts_2bytes: ([0xF0, 1], Err(UsbMidiEventPacketError::InvalidPayloadSize)),
204 sysex_continues_1byte: ([1], Ok(CodeIndexNumber::SingleByte)),
205 sysex_continues_2bytes: ([1, 2], Err(UsbMidiEventPacketError::InvalidPayloadSize)),
206 sysex_continues_3bytes: ([1, 2, 3], Ok(CodeIndexNumber::SysexStartsOrContinues)),
207 sysex_ends_1byte: ([0xF7], Ok(CodeIndexNumber::SystemCommon1Byte)),
208 sysex_ends_2bytes: ([1, 0xF7], Ok(CodeIndexNumber::SysexEnds2Bytes)),
209 sysex_ends_3bytes: ([1, 2, 0xF7], Ok(CodeIndexNumber::SysexEnds3Bytes)),
210 sysex_2bytes: ([0xF0, 0xF7], Ok(CodeIndexNumber::SysexEnds2Bytes)),
211 sysex_3bytes: ([0xF0, 1, 0xF7], Ok(CodeIndexNumber::SysexEnds3Bytes)),
212 undefined_f4: ([0xF4], Err(UsbMidiEventPacketError::InvalidPayloadStatus)),
213 undefined_f5: ([0xF5], Err(UsbMidiEventPacketError::InvalidPayloadStatus)),
214 empty: ([], Err(UsbMidiEventPacketError::EmptyPayload)),
215 }
216}