diff --git a/src/data/midi/message/message.rs b/src/data/midi/message/message.rs deleted file mode 100644 index a9726fc..0000000 --- a/src/data/midi/message/message.rs +++ /dev/null @@ -1,141 +0,0 @@ -use crate::data::byte::from_traits::FromClamped; -use crate::data::byte::u7::U7; -use crate::data::midi::channel::Channel; -use crate::data::midi::message::control_function::ControlFunction; -use crate::data::midi::message::raw::{Payload, Raw}; -use crate::data::midi::notes::Note; -use crate::data::usb_midi::usb_midi_event_packet::MidiPacketParsingError; -use core::convert::TryFrom; - -type Velocity = U7; - -/// Represents midi messages -/// Note: not current exhaustive and SysEx messages end up -/// being a confusing case. So are currently note implemented -/// they are sort-of unbounded -#[derive(Debug, Eq, PartialEq)] -pub enum Message { - NoteOff(Channel, Note, Velocity), - NoteOn(Channel, Note, Velocity), - PolyphonicAftertouch(Channel, Note, U7), - ProgramChange(Channel, U7), - ChannelAftertouch(Channel, U7), - PitchWheelChange(Channel, U7, U7), - ControlChange(Channel, ControlFunction, U7), -} - -const NOTE_OFF_MASK: u8 = 0b1000_0000; -const NOTE_ON_MASK: u8 = 0b1001_0000; -const POLYPHONIC_MASK: u8 = 0b1010_0000; -const PROGRAM_MASK: u8 = 0b1100_0000; -const CHANNEL_AFTERTOUCH_MASK: u8 = 0b1101_0000; -const PITCH_BEND_MASK: u8 = 0b1110_0000; -const CONTROL_CHANGE_MASK: u8 = 0b1011_0000; - -impl From for Raw { - fn from(value: Message) -> Raw { - match value { - Message::NoteOn(chan, note, vel) => { - let payload = Payload::DoubleByte(note.into(), vel); - let status = NOTE_ON_MASK | u8::from(chan); - Raw { status, payload } - } - Message::NoteOff(chan, note, vel) => { - let payload = Payload::DoubleByte(note.into(), vel); - let status = NOTE_OFF_MASK | u8::from(chan); - Raw { status, payload } - } - Message::PolyphonicAftertouch(chan, note, pressure) => { - let payload = Payload::DoubleByte(note.into(), pressure); - let status = POLYPHONIC_MASK | u8::from(chan); - Raw { status, payload } - } - Message::ProgramChange(chan, program) => { - let payload = Payload::SingleByte(program); - let status = PROGRAM_MASK | u8::from(chan); - Raw { status, payload } - } - Message::ChannelAftertouch(chan, pressure) => { - let payload = Payload::SingleByte(pressure); - let status = CHANNEL_AFTERTOUCH_MASK | u8::from(chan); - Raw { status, payload } - } - Message::PitchWheelChange(chan, lsb, msb) => { - let payload = Payload::DoubleByte(lsb, msb); - let status = PITCH_BEND_MASK | u8::from(chan); - Raw { status, payload } - } - Message::ControlChange(chan, control_function, value) => { - let payload = Payload::DoubleByte(control_function.0, value); - let status = CONTROL_CHANGE_MASK | u8::from(chan); - Raw { status, payload } - } - } - } -} - -impl<'a> TryFrom<&'a [u8]> for Message { - type Error = MidiPacketParsingError; - fn try_from(data: &[u8]) -> Result { - let status_byte = match data.get(0) { - Some(byte) => byte, - None => return Err(MidiPacketParsingError::MissingDataPacket), - }; - - let event_type = status_byte & 0b1111_0000; - let channel_bytes = (status_byte) & 0b0000_1111; - - let channel = Channel::try_from(channel_bytes).ok().unwrap(); - - match event_type { - NOTE_ON_MASK => Ok(Message::NoteOn( - channel, - get_note(data)?, - get_u7_at(data, 2)?, - )), - NOTE_OFF_MASK => Ok(Message::NoteOff( - channel, - get_note(data)?, - get_u7_at(data, 2)?, - )), - POLYPHONIC_MASK => Ok(Message::PolyphonicAftertouch( - channel, - get_note(data)?, - get_u7_at(data, 2)?, - )), - PROGRAM_MASK => Ok(Message::ProgramChange(channel, get_u7_at(data, 1)?)), - CHANNEL_AFTERTOUCH_MASK => Ok(Message::ChannelAftertouch(channel, get_u7_at(data, 1)?)), - PITCH_BEND_MASK => Ok(Message::PitchWheelChange( - channel, - get_u7_at(data, 1)?, - get_u7_at(data, 2)?, - )), - CONTROL_CHANGE_MASK => Ok(Message::ControlChange( - channel, - ControlFunction(get_u7_at(data, 1)?), - get_u7_at(data, 2)?, - )), - _ => Err(MidiPacketParsingError::InvalidEventType(event_type)), - } - } -} - -fn get_note(data: &[u8]) -> Result { - let note_byte = get_byte_at_position(data, 1)?; - match Note::try_from(note_byte) { - Ok(note) => Ok(note), - Err(_) => Err(MidiPacketParsingError::InvalidNote(note_byte)), - } -} - -fn get_u7_at(data: &[u8], index: usize) -> Result { - let data_byte = get_byte_at_position(data, index)?; - Ok(U7::from_clamped(data_byte)) -} - -fn get_byte_at_position(data: &[u8], index: usize) -> Result { - match data.get(index) { - Some(byte) => Ok(*byte), - None => Err(MidiPacketParsingError::MissingDataPacket), - } -} diff --git a/src/data/midi/message/mod.rs b/src/data/midi/message/mod.rs index bf4bdd4..1262fd0 100644 --- a/src/data/midi/message/mod.rs +++ b/src/data/midi/message/mod.rs @@ -1,4 +1,144 @@ -pub mod message; -pub mod raw; -pub use crate::data::midi::message::message::Message; pub mod control_function; +pub mod raw; + +use crate::data::byte::from_traits::FromClamped; +use crate::data::byte::u7::U7; +use crate::data::midi::channel::Channel; +use crate::data::midi::message::control_function::ControlFunction; +use crate::data::midi::message::raw::{Payload, Raw}; +use crate::data::midi::notes::Note; +use crate::data::usb_midi::usb_midi_event_packet::MidiPacketParsingError; +use core::convert::TryFrom; + +type Velocity = U7; + +/// Represents midi messages +/// Note: not current exhaustive and SysEx messages end up +/// being a confusing case. So are currently note implemented +/// they are sort-of unbounded +#[derive(Debug, Eq, PartialEq)] +pub enum Message { + NoteOff(Channel, Note, Velocity), + NoteOn(Channel, Note, Velocity), + PolyphonicAftertouch(Channel, Note, U7), + ProgramChange(Channel, U7), + ChannelAftertouch(Channel, U7), + PitchWheelChange(Channel, U7, U7), + ControlChange(Channel, ControlFunction, U7), +} + +const NOTE_OFF_MASK: u8 = 0b1000_0000; +const NOTE_ON_MASK: u8 = 0b1001_0000; +const POLYPHONIC_MASK: u8 = 0b1010_0000; +const PROGRAM_MASK: u8 = 0b1100_0000; +const CHANNEL_AFTERTOUCH_MASK: u8 = 0b1101_0000; +const PITCH_BEND_MASK: u8 = 0b1110_0000; +const CONTROL_CHANGE_MASK: u8 = 0b1011_0000; + +impl From for Raw { + fn from(value: Message) -> Raw { + match value { + Message::NoteOn(chan, note, vel) => { + let payload = Payload::DoubleByte(note.into(), vel); + let status = NOTE_ON_MASK | u8::from(chan); + Raw { status, payload } + } + Message::NoteOff(chan, note, vel) => { + let payload = Payload::DoubleByte(note.into(), vel); + let status = NOTE_OFF_MASK | u8::from(chan); + Raw { status, payload } + } + Message::PolyphonicAftertouch(chan, note, pressure) => { + let payload = Payload::DoubleByte(note.into(), pressure); + let status = POLYPHONIC_MASK | u8::from(chan); + Raw { status, payload } + } + Message::ProgramChange(chan, program) => { + let payload = Payload::SingleByte(program); + let status = PROGRAM_MASK | u8::from(chan); + Raw { status, payload } + } + Message::ChannelAftertouch(chan, pressure) => { + let payload = Payload::SingleByte(pressure); + let status = CHANNEL_AFTERTOUCH_MASK | u8::from(chan); + Raw { status, payload } + } + Message::PitchWheelChange(chan, lsb, msb) => { + let payload = Payload::DoubleByte(lsb, msb); + let status = PITCH_BEND_MASK | u8::from(chan); + Raw { status, payload } + } + Message::ControlChange(chan, control_function, value) => { + let payload = Payload::DoubleByte(control_function.0, value); + let status = CONTROL_CHANGE_MASK | u8::from(chan); + Raw { status, payload } + } + } + } +} + +impl<'a> TryFrom<&'a [u8]> for Message { + type Error = MidiPacketParsingError; + fn try_from(data: &[u8]) -> Result { + let status_byte = match data.first() { + Some(byte) => byte, + None => return Err(MidiPacketParsingError::MissingDataPacket), + }; + + let event_type = status_byte & 0b1111_0000; + let channel_bytes = (status_byte) & 0b0000_1111; + + let channel = Channel::try_from(channel_bytes).ok().unwrap(); + + match event_type { + NOTE_ON_MASK => Ok(Message::NoteOn( + channel, + get_note(data)?, + get_u7_at(data, 2)?, + )), + NOTE_OFF_MASK => Ok(Message::NoteOff( + channel, + get_note(data)?, + get_u7_at(data, 2)?, + )), + POLYPHONIC_MASK => Ok(Message::PolyphonicAftertouch( + channel, + get_note(data)?, + get_u7_at(data, 2)?, + )), + PROGRAM_MASK => Ok(Message::ProgramChange(channel, get_u7_at(data, 1)?)), + CHANNEL_AFTERTOUCH_MASK => Ok(Message::ChannelAftertouch(channel, get_u7_at(data, 1)?)), + PITCH_BEND_MASK => Ok(Message::PitchWheelChange( + channel, + get_u7_at(data, 1)?, + get_u7_at(data, 2)?, + )), + CONTROL_CHANGE_MASK => Ok(Message::ControlChange( + channel, + ControlFunction(get_u7_at(data, 1)?), + get_u7_at(data, 2)?, + )), + _ => Err(MidiPacketParsingError::InvalidEventType(event_type)), + } + } +} + +fn get_note(data: &[u8]) -> Result { + let note_byte = get_byte_at_position(data, 1)?; + match Note::try_from(note_byte) { + Ok(note) => Ok(note), + Err(_) => Err(MidiPacketParsingError::InvalidNote(note_byte)), + } +} + +fn get_u7_at(data: &[u8], index: usize) -> Result { + let data_byte = get_byte_at_position(data, index)?; + Ok(U7::from_clamped(data_byte)) +} + +fn get_byte_at_position(data: &[u8], index: usize) -> Result { + match data.get(index) { + Some(byte) => Ok(*byte), + None => Err(MidiPacketParsingError::MissingDataPacket), + } +} diff --git a/src/data/midi/notes.rs b/src/data/midi/notes.rs index 89b238f..677e241 100644 --- a/src/data/midi/notes.rs +++ b/src/data/midi/notes.rs @@ -139,9 +139,9 @@ pub enum Note { Gs9, } -impl Into for Note { - fn into(self) -> u8 { - self as u8 +impl From for u8 { + fn from(val: Note) -> Self { + val as u8 } } diff --git a/src/data/usb_midi/midi_packet_reader.rs b/src/data/usb_midi/midi_packet_reader.rs index f0b191d..9a3927d 100644 --- a/src/data/usb_midi/midi_packet_reader.rs +++ b/src/data/usb_midi/midi_packet_reader.rs @@ -23,13 +23,10 @@ impl<'a> Iterator for MidiPacketBufferReader<'a> { fn next(&mut self) -> Option { if self.position <= MAX_PACKET_SIZE && self.position < self.raw_bytes_received { - let packet = match self + let packet = self .buffer .get(self.position..(self.position + MIDI_PACKET_SIZE)) - { - Some(packet) => Some(UsbMidiEventPacket::try_from(packet)), - None => None, - }; + .map(UsbMidiEventPacket::try_from); self.position += MIDI_PACKET_SIZE; return packet; diff --git a/src/data/usb_midi/usb_midi_event_packet.rs b/src/data/usb_midi/usb_midi_event_packet.rs index 03f001f..9c3a2fe 100644 --- a/src/data/usb_midi/usb_midi_event_packet.rs +++ b/src/data/usb_midi/usb_midi_event_packet.rs @@ -47,12 +47,12 @@ impl TryFrom<&[u8]> for UsbMidiEventPacket { type Error = MidiPacketParsingError; fn try_from(value: &[u8]) -> Result { - let raw_cable_number = match value.get(0) { + let raw_cable_number = match value.first() { Some(byte) => *byte >> 4, None => return Err(MidiPacketParsingError::MissingDataPacket), }; - let cable_number = match CableNumber::try_from(u8::from(raw_cable_number)) { + let cable_number = match CableNumber::try_from(raw_cable_number) { Ok(val) => val, _ => return Err(MidiPacketParsingError::InvalidCableNumber(raw_cable_number)), }; diff --git a/src/midi_device.rs b/src/midi_device.rs index 597455e..9e0ba73 100644 --- a/src/midi_device.rs +++ b/src/midi_device.rs @@ -66,23 +66,23 @@ impl MidiClass<'_, B> { /// calculates the index'th external midi in jack id fn in_jack_id_ext(&self, index: u8) -> u8 { debug_assert!(index < self.n_in_jacks); - return 2 * index + 1; + 2 * index + 1 } /// calculates the index'th embedded midi out jack id fn out_jack_id_emb(&self, index: u8) -> u8 { debug_assert!(index < self.n_in_jacks); - return 2 * index + 2; + 2 * index + 2 } /// calculates the index'th external midi out jack id fn out_jack_id_ext(&self, index: u8) -> u8 { debug_assert!(index < self.n_out_jacks); - return 2 * self.n_in_jacks + 2 * index + 1; + 2 * self.n_in_jacks + 2 * index + 1 } /// calculates the index'th embedded midi in jack id fn in_jack_id_emb(&self, index: u8) -> u8 { debug_assert!(index < self.n_out_jacks); - return 2 * self.n_in_jacks + 2 * index + 2; + 2 * self.n_in_jacks + 2 * index + 2 } }