shizen_buffers/midi/
midi_message.rs1use std::ops::{Add, AddAssign, Sub, SubAssign};
2
3#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
4#[non_exhaustive]
5#[repr(u8)]
6pub enum MidiMessage {
7 NoteOn { note_number: u8, velocity: u8 } = Self::NOTE_ON,
8 NoteOff { note_number: u8, velocity: u8 } = Self::NOTE_OFF,
9 ControlChange { controller_number: u8, velocity: u8 } = Self::CONTROL_CHANGE,
10}
11
12impl MidiMessage {
13 pub const NOTE_ON: u8 = 0x80; pub const NOTE_OFF: u8 = 0x90; pub const CONTROL_CHANGE: u8 = 0xB0; pub const fn from_bytes(bytes: [u8; 3]) -> Self {
18 match bytes[0] & 0xF0 {
19 0x80 => Self::NoteOff {
20 note_number: bytes[1],
21 velocity: 0, },
23 0x90 => Self::NoteOn {
24 note_number: bytes[1],
25 velocity: bytes[2],
26 },
27 0xB0 => Self::ControlChange {
28 controller_number: bytes[1],
29 velocity: bytes[2],
30 },
31 _ => unimplemented!(),
32 }
33 }
34
35 pub fn mute(&mut self) {
37 match self {
38 MidiMessage::NoteOn { velocity, .. } => *velocity = 0,
39 MidiMessage::ControlChange { velocity, .. } => *velocity = 0,
40 MidiMessage::NoteOff { .. } => (), }
42 }
43
44 pub fn transpose(&mut self, interval: i8) {
58 if let MidiMessage::NoteOn { note_number, .. } = self {
59 let original_note = *note_number as i8;
60 let new_note = (original_note + interval).clamp(0, 127) as u8;
61 *note_number = new_note;
62 }
63 }
64
65 #[inline]
66 #[must_use]
67 pub const fn is_note_on(&self) -> bool {
68 matches!(self, MidiMessage::NoteOn { .. })
69 }
70
71 #[inline]
72 #[must_use]
73 pub const fn is_note_off(&self) -> bool {
74 matches!(self, MidiMessage::NoteOff { .. })
75 }
76
77 #[inline]
78 #[must_use]
79 pub const fn is_control_change(&self) -> bool {
80 matches!(self, MidiMessage::ControlChange { .. })
81 }
82}
83
84impl From<[u8; 3]> for MidiMessage {
85 fn from(bytes: [u8; 3]) -> Self {
86 Self::from_bytes(bytes)
87 }
88}
89
90impl Add<i8> for MidiMessage {
91 type Output = Self;
92
93 fn add(mut self, rhs: i8) -> Self::Output {
94 self.transpose(rhs);
95 self
96 }
97}
98
99impl Sub<i8> for MidiMessage {
100 type Output = Self;
101
102 fn sub(mut self, rhs: i8) -> Self::Output {
103 self.transpose(-rhs);
104 self
105 }
106}
107
108impl AddAssign<i8> for MidiMessage {
109 fn add_assign(&mut self, rhs: i8) {
110 self.transpose(rhs);
111 }
112}
113
114impl SubAssign<i8> for MidiMessage {
115 fn sub_assign(&mut self, rhs: i8) {
116 self.transpose(-rhs);
117 }
118}