1use crate::Note;
4
5#[derive(Debug, PartialEq, Clone, Copy, Eq)]
7#[cfg_attr(feature = "defmt", derive(defmt::Format))]
8pub enum MidiMessage {
9 NoteOff(Channel, Note, Value7),
12
13 NoteOn(Channel, Note, Value7),
15
16 KeyPressure(Channel, Note, Value7),
18
19 ControlChange(Channel, Control, Value7),
21
22 ProgramChange(Channel, Program),
24
25 ChannelPressure(Channel, Value7),
27
28 PitchBendChange(Channel, Value14),
30
31 QuarterFrame(QuarterFrame),
45
46 SongPositionPointer(Value14),
48
49 SongSelect(Value7),
51
52 TuneRequest,
54
55 TimingClock,
58
59 Start,
61
62 Continue,
64
65 Stop,
67
68 ActiveSensing,
70
71 Reset,
73}
74
75impl MidiMessage {
76 #[allow(clippy::len_without_is_empty)]
78 #[must_use]
79 pub const fn len(&self) -> usize {
80 match self {
81 Self::NoteOff(..)
82 | Self::NoteOn(..)
83 | Self::KeyPressure(..)
84 | Self::ControlChange(..)
85 | Self::PitchBendChange(..)
86 | Self::SongPositionPointer(..) => 3,
87 Self::ProgramChange(..)
88 | Self::ChannelPressure(..)
89 | Self::QuarterFrame(..)
90 | Self::SongSelect(..) => 2,
91 Self::TuneRequest
92 | Self::TimingClock
93 | Self::Start
94 | Self::Continue
95 | Self::Stop
96 | Self::ActiveSensing
97 | Self::Reset => 1,
98 }
99 }
100}
101
102#[allow(missing_docs)]
103pub mod status {
105 pub const NOTE_OFF: u8 = 0x80;
106 pub const NOTE_ON: u8 = 0x90;
107 pub const KEY_PRESSURE: u8 = 0xA0;
108 pub const CONTROL_CHANGE: u8 = 0xB0;
109 pub const PITCH_BEND_CHANGE: u8 = 0xE0;
110 pub const SONG_POSITION_POINTER: u8 = 0xF2;
111 pub const PROGRAM_CHANGE: u8 = 0xC0;
112 pub const CHANNEL_PRESSURE: u8 = 0xD0;
113 pub const QUARTER_FRAME: u8 = 0xF1;
114 pub const SONG_SELECT: u8 = 0xF3;
115 pub const TUNE_REQUEST: u8 = 0xF6;
116 pub const TIMING_CLOCK: u8 = 0xF8;
117 pub const START: u8 = 0xFA;
118 pub const CONTINUE: u8 = 0xFB;
119 pub const STOP: u8 = 0xFC;
120 pub const ACTIVE_SENSING: u8 = 0xFE;
121 pub const RESET: u8 = 0xFF;
122
123 pub const SYSEX_START: u8 = 0xF0;
124 pub const SYSEX_END: u8 = 0xF7;
125}
126
127#[derive(Debug, PartialEq, Eq, Copy, Clone)]
130#[cfg_attr(feature = "defmt", derive(defmt::Format))]
131pub struct Channel(u8);
132
133impl Channel {
134 #[must_use]
142 pub const fn new(channel: u8) -> Self {
143 debug_assert!(channel <= 15, "Channel exceeds valid range");
144 Self(if channel > 15 { 15 } else { channel })
145 }
146
147 pub const C1: Self = Self::new(0);
149 pub const C2: Self = Self::new(1);
151 pub const C3: Self = Self::new(2);
153 pub const C4: Self = Self::new(3);
155 pub const C5: Self = Self::new(4);
157 pub const C6: Self = Self::new(5);
159 pub const C7: Self = Self::new(6);
161 pub const C8: Self = Self::new(7);
163 pub const C9: Self = Self::new(8);
165 pub const C10: Self = Self::new(9);
167 pub const C11: Self = Self::new(10);
169 pub const C12: Self = Self::new(11);
171 pub const C13: Self = Self::new(12);
173 pub const C14: Self = Self::new(13);
175 pub const C15: Self = Self::new(14);
177 pub const C16: Self = Self::new(15);
179
180 pub const MIN: Self = Self::C1;
182 pub const MAX: Self = Self::C16;
184}
185
186impl From<u8> for Channel {
187 fn from(channel: u8) -> Self {
188 Self::new(channel)
189 }
190}
191
192impl From<Channel> for u8 {
193 fn from(channel: Channel) -> Self {
194 channel.0
195 }
196}
197
198#[derive(Debug, PartialEq, Eq, Copy, Clone)]
200#[cfg_attr(feature = "defmt", derive(defmt::Format))]
201pub struct Control(u8);
202
203impl Control {
204 #[must_use]
212 pub const fn new(control: u8) -> Self {
213 debug_assert!(control < 127, "Control exceeds valid range");
214 Self(if control > 127 { 127 } else { control })
215 }
216}
217
218impl From<u8> for Control {
219 fn from(control: u8) -> Self {
220 Self::new(control)
221 }
222}
223
224impl From<Control> for u8 {
225 fn from(control: Control) -> Self {
226 control.0
227 }
228}
229
230#[derive(Debug, PartialEq, Eq, Copy, Clone)]
232#[cfg_attr(feature = "defmt", derive(defmt::Format))]
233pub struct Program(u8);
234
235impl Program {
236 #[must_use]
244 pub const fn new(program: u8) -> Self {
245 debug_assert!(program < 127, "Program exceeds valid range");
246 Self(if program > 127 { 127 } else { program })
247 }
248}
249
250impl From<u8> for Program {
251 fn from(program: u8) -> Self {
252 Self::new(program)
253 }
254}
255
256impl From<Program> for u8 {
257 fn from(program: Program) -> Self {
258 program.0
259 }
260}
261
262#[derive(Debug, PartialEq, Eq, Copy, Clone)]
264#[cfg_attr(feature = "defmt", derive(defmt::Format))]
265pub struct Value7(u8);
266
267impl Value7 {
268 #[must_use]
276 pub const fn new(value: u8) -> Self {
277 debug_assert!(value <= 127, "Value7 exceeds valid range");
278 Self(if value > 127 { 127 } else { value })
279 }
280}
281
282impl From<u8> for Value7 {
283 fn from(value: u8) -> Self {
284 Self::new(value)
285 }
286}
287
288impl From<Value7> for u8 {
289 fn from(value: Value7) -> Self {
290 value.0
291 }
292}
293
294#[derive(Debug, PartialEq, Eq, Copy, Clone)]
297#[cfg_attr(feature = "defmt", derive(defmt::Format))]
298pub struct Value14(u8, u8);
299
300impl Value14 {
301 #[must_use]
309 pub const fn new(msb: u8, lsb: u8) -> Self {
310 debug_assert!(msb <= 127, "Value14 msb exceeds valid range");
311 debug_assert!(lsb <= 127, "Value14 lsb exceeds valid range");
312 Self(
313 if msb >= 127 { 127 } else { msb },
314 if lsb >= 127 { 127 } else { lsb },
315 )
316 }
317}
318
319impl From<(u8, u8)> for Value14 {
320 fn from(value: (u8, u8)) -> Self {
321 Self::new(value.0, value.1)
322 }
323}
324
325impl From<Value14> for (u8, u8) {
326 fn from(value: Value14) -> (u8, u8) {
327 (value.0, value.1)
328 }
329}
330
331impl From<u16> for Value14 {
332 fn from(value: u16) -> Self {
333 debug_assert!(value <= 16383, "Value14 exceeds valid range");
334 let value = if value > 16383 { 16383 } else { value };
335 Self(((value & 0x3f80) >> 7) as u8, (value & 0x007f) as u8)
336 }
337}
338
339impl From<Value14> for u16 {
340 fn from(value: Value14) -> Self {
341 (Self::from(value.0) << 7) + Self::from(value.1)
342 }
343}
344
345impl From<i16> for Value14 {
347 #[allow(clippy::cast_sign_loss)]
348 fn from(value: i16) -> Self {
349 debug_assert!(value >= -8192, "Value14 exceeds valid range");
350 debug_assert!(value <= 8191, "Value14 exceeds valid range");
351 let value = value.clamp(-8192, 8191) + 8192;
352 Self::new(((value & 0x3f80) >> 7) as u8, (value & 0x007f) as u8)
353 }
354}
355
356impl From<Value14> for i16 {
358 #[allow(clippy::cast_possible_wrap)]
359 fn from(value: Value14) -> Self {
360 let v: u16 = value.into();
361 (v as Self) - 8192
362 }
363}
364
365impl From<f32> for Value14 {
367 #[allow(clippy::cast_possible_truncation)]
368 fn from(value: f32) -> Self {
369 Self::from((value * if value > 0.0 { 8191.0 } else { 8192.0 }) as i16)
370 }
371}
372
373impl From<Value14> for f32 {
375 fn from(value: Value14) -> Self {
376 let v: i16 = value.into();
377 let v = Self::from(v) / if v > 0 { 8191.0 } else { 8192.0 };
378 v.clamp(-1.0, 1.0)
379 }
380}
381
382#[derive(Debug, PartialEq, Eq, Copy, Clone)]
434#[cfg_attr(feature = "defmt", derive(defmt::Format))]
435pub struct QuarterFrame(u8);
436
437impl QuarterFrame {
438 #[must_use]
446 pub const fn new(frame: u8) -> Self {
447 debug_assert!(frame <= 127, "QuarterFrame exceeds valid range");
448 Self(if frame > 127 { 127 } else { frame })
449 }
450}
451
452impl From<u8> for QuarterFrame {
469 fn from(frame: u8) -> Self {
470 Self::new(frame)
471 }
472}
473
474impl From<QuarterFrame> for u8 {
475 fn from(value: QuarterFrame) -> Self {
476 value.0
477 }
478}
479
480#[cfg(test)]
481mod test {
482 use super::*;
483
484 #[test]
485 fn should_combine_7_bit_vals_into_14() {
486 let val = Value14::new(0b01010101u8, 0b01010111u8);
487 assert_eq!(0b0010101011010111u16, val.into());
488 assert_eq!((0b01010101u8, 0b01010111u8), val.into())
489 }
490
491 #[test]
492 fn conversion_u16_14() {
493 let val: Value14 = Value14::from(16383u16);
494 assert_eq!((127, 127), val.into());
495 assert_eq!(16383u16, val.into());
496
497 let val: Value14 = Value14::from(16256u16);
498 assert_eq!((127, 0), val.into());
499 assert_eq!(16256u16, val.into());
500
501 let val: Value14 = Value14::from(127u16);
502 assert_eq!((0, 127), val.into());
503 assert_eq!(127u16, val.into());
504
505 let val: Value14 = Value14::from(0u16);
506 assert_eq!((0, 0), val.into());
507 assert_eq!(0u16, val.into());
508 }
509
510 #[test]
511 fn conversion_i16_14() {
512 let val: Value14 = Value14::from(8191i16);
513 assert_eq!((127, 127), val.into());
514 assert_eq!(8191i16, val.into());
515 assert_eq!(val, Value14::new(127, 127));
516
517 let val: Value14 = Value14::from(8190i16);
518 assert_eq!((127, 126), val.into());
519 assert_eq!(8190i16, val.into());
520
521 let val: Value14 = Value14::from(-8192i16);
522 assert_eq!((0, 0), val.into());
523 assert_eq!(-8192i16, val.into());
524
525 let val: Value14 = Value14::from(0i16);
526 assert_eq!((64, 0), val.into());
527 assert_eq!(0i16, val.into());
528
529 let val: Value14 = Value14::from(1i16);
530 assert_eq!((64, 1), val.into());
531 assert_eq!(1i16, val.into());
532 }
533
534 #[test]
535 fn conversion_f32_14() {
536 let val: Value14 = Value14::from(0.0f32);
537 assert_eq!((64, 0), val.into());
538 assert_eq!(0.0f32, val.into());
539
540 let val: Value14 = Value14::from(1.0f32);
541 assert_eq!((127, 127), val.into());
542 assert_eq!(1.0f32, val.into());
543
544 let val: Value14 = Value14::from(-1.0f32);
545 assert_eq!((0, 0), val.into());
546 assert_eq!(-1.0f32, val.into());
547 }
548}