From 55d94f7024100f008ffcae15b3f5cc3b25752a5d Mon Sep 17 00:00:00 2001 From: beau trepp Date: Tue, 17 Dec 2019 19:19:27 +0800 Subject: [PATCH] Simplifies more midi domain types The usb interface now only allows you to send midi messages, created via fairly restrictive structs It should be very difficult to create an invalid midi message now. --- src/data/byte/mod.rs | 3 +- src/data/byte/u4.rs | 46 ++++++++++++++ src/data/midi/mod.rs | 1 - src/data/usb_midi/cable_number.rs | 15 +++-- .../{midi => usb_midi}/code_index_number.rs | 20 +++++- src/data/usb_midi/mod.rs | 3 +- src/data/usb_midi/usb_midi_event_packet.rs | 61 +++++++------------ src/midi_device.rs | 23 ------- src/util/mod.rs | 1 - src/util/nibble.rs | 10 --- 10 files changed, 101 insertions(+), 82 deletions(-) create mode 100644 src/data/byte/u4.rs rename src/data/{midi => usb_midi}/code_index_number.rs (76%) delete mode 100644 src/util/nibble.rs diff --git a/src/data/byte/mod.rs b/src/data/byte/mod.rs index ff07688..34200f4 100644 --- a/src/data/byte/mod.rs +++ b/src/data/byte/mod.rs @@ -1 +1,2 @@ -pub mod u7; \ No newline at end of file +pub mod u7; +pub mod u4; \ No newline at end of file diff --git a/src/data/byte/u4.rs b/src/data/byte/u4.rs new file mode 100644 index 0000000..5cd40b7 --- /dev/null +++ b/src/data/byte/u4.rs @@ -0,0 +1,46 @@ +use core::convert::TryFrom; + +/// A primitive value that can be from 0-0x7F +pub struct U4(u8); + +/// Error representing that this value is not a valid u4 +pub struct InvalidU4(u8); + +impl TryFrom for U4{ + type Error = InvalidU4; + + fn try_from(value:u8) -> Result { + if value > U4::MAX.0 { + Err(InvalidU4(value)) + } else { + Ok(U4(value)) + } + } +} + +impl From for u8 { + fn from(value:U4) -> u8 { + value.0 + } +} + +impl U4 { + pub const MAX: U4= U4(0x0F); + pub const MIN: U4 = U4(0); + + /// Combines two nibbles (u4) eg half byte + /// result will be a full byte + pub fn combine(upper:U4,lower:U4) -> u8 { + let upper = upper.0.overflowing_shl(8).0; + let lower = lower.0 & U4::MAX.0; + upper | lower + } + + /// Constructs a U4 from a u8. + /// Note this clamps off the upper portions + pub fn from_overflowing_u8(value:u8) -> U4 { + const MASK :u8 = 0b0000_1111; + let number = MASK & value; + U4(number) + } +} diff --git a/src/data/midi/mod.rs b/src/data/midi/mod.rs index 6eeac55..710965d 100644 --- a/src/data/midi/mod.rs +++ b/src/data/midi/mod.rs @@ -1,5 +1,4 @@ pub mod notes; -pub mod code_index_number; pub mod channel; pub mod message; pub mod velocity; \ No newline at end of file diff --git a/src/data/usb_midi/cable_number.rs b/src/data/usb_midi/cable_number.rs index 0743c2d..3be05f2 100644 --- a/src/data/usb_midi/cable_number.rs +++ b/src/data/usb_midi/cable_number.rs @@ -1,4 +1,5 @@ use core::convert::TryFrom; +use crate::data::byte::u4::U4; /// The Cable Number (CN) is a value ranging from 0x0 to 0xF /// indicating the number assignment of the Embedded MIDI Jack associated @@ -39,9 +40,15 @@ impl TryFrom for CableNumber { } -impl Into for CableNumber { - fn into(self) -> u8 { - self as u8 +impl From for u8{ + fn from(value:CableNumber) -> u8 { + value as u8 + } +} + +impl From for U4{ + fn from(value:CableNumber) -> U4 { + U4::from_overflowing_u8(u8::from(value)) } } @@ -55,7 +62,7 @@ mod tests { #[test] fn $id() { let (input,expected) = $value; - assert_eq!(input as u8, expected); + assert_eq!(u8::from(input), expected); } )* } diff --git a/src/data/midi/code_index_number.rs b/src/data/usb_midi/code_index_number.rs similarity index 76% rename from src/data/midi/code_index_number.rs rename to src/data/usb_midi/code_index_number.rs index 71d34b9..221699a 100644 --- a/src/data/midi/code_index_number.rs +++ b/src/data/usb_midi/code_index_number.rs @@ -1,4 +1,6 @@ use core::convert::TryFrom; +use crate::data::midi::message::Message; +use crate::data::byte::u4::U4; /// The Code Index Number(CIN) indicates the classification /// of the bytes in the MIDI_x fields @@ -16,12 +18,14 @@ impl TryFrom for CodeIndexNumber { } } -impl Into for CodeIndexNumber { - fn into(self) -> u8 { - self.0 +impl From for U4{ + fn from(value:CodeIndexNumber) -> U4{ + U4::from_overflowing_u8(value.0) } } + + impl CodeIndexNumber { /// Miscellaneous function codes. Reserved for future extensions @@ -60,4 +64,14 @@ impl CodeIndexNumber { /// Single Byte pub const SINGLE_BYTE : CodeIndexNumber= CodeIndexNumber(0xF); + pub fn find_from_message(value:&Message) -> CodeIndexNumber{ + match value { + Message::NoteOn(_,_,_) => CodeIndexNumber::NOTE_ON, + Message::NoteOff(_,_,_) => CodeIndexNumber::NOTE_OFF, + Message::ChannelAftertouch(_,_) => CodeIndexNumber::CHANNEL_PRESSURE, + Message::PitchWheelChange(_,_,_) => CodeIndexNumber::PITCHBEND_CHANGE, + Message::PolyphonicAftertouch(_,_,_) => CodeIndexNumber::POLY_KEYPRESS, + Message::ProgramChange(_,_) => CodeIndexNumber::PROGRAM_CHANGE + } + } } diff --git a/src/data/usb_midi/mod.rs b/src/data/usb_midi/mod.rs index 82ed118..eabf2cb 100644 --- a/src/data/usb_midi/mod.rs +++ b/src/data/usb_midi/mod.rs @@ -1,2 +1,3 @@ pub mod usb_midi_event_packet; -pub mod cable_number; \ No newline at end of file +pub mod cable_number; +pub mod code_index_number; \ No newline at end of file diff --git a/src/data/usb_midi/usb_midi_event_packet.rs b/src/data/usb_midi/usb_midi_event_packet.rs index 6487f0f..da3abff 100644 --- a/src/data/usb_midi/usb_midi_event_packet.rs +++ b/src/data/usb_midi/usb_midi_event_packet.rs @@ -1,50 +1,35 @@ use crate::data::usb_midi::cable_number::CableNumber; -use crate::data::midi::code_index_number::CodeIndexNumber; -use crate::data::midi::notes::Note; -use crate::data::midi::channel::Channel; +use crate::data::usb_midi::code_index_number::CodeIndexNumber; use crate::data::midi::message::Message; -use crate::data::midi::velocity::Velocity; -use crate::util::nibble::{combine_nibble}; -use crate::data::midi::message::raw::Raw; +use crate::data::byte::u4::U4; +use crate::data::midi::message::raw::{Payload,Raw}; /// A packet that communicates with the host -/// Note that the payload seems fairly 'open' -/// It's contents can depend on the cable/code index number -/// but may not!? +/// Currently supported is sending the specified normal midi +/// message over the supplied cable number pub struct UsbMidiEventPacket { cable_number : CableNumber, - code_index_number: CodeIndexNumber, //Is this strictly necessary - //if can be built from the midi message? message: Message } -/// Constructs a note-on midi message given the cable, note and velocity -pub fn note_on( cable:CableNumber, - channel: Channel, - note:Note, - velocity: Velocity) -> UsbMidiEventPacket { +impl From for [u8;4] { + fn from(value:UsbMidiEventPacket) -> [u8;4] { + let message= value.message; + let cable_number = U4::from(value.cable_number); + let index_number = { + let code_index = + CodeIndexNumber::find_from_message(&message); + U4::from(code_index) + }; + let header = U4::combine(cable_number,index_number); + let raw_midi = Raw::from(message); + let status = raw_midi.status; - let message = Message::NoteOn(channel,note,velocity); - - UsbMidiEventPacket{ - cable_number : cable, - code_index_number : CodeIndexNumber::NOTE_ON, - message : message + match raw_midi.payload { + Payload::Empty => [header,status,0,0], + Payload::SingleByte(byte) => [header,status,byte,0], + Payload::DoubleByte(byte1,byte2) => [header,status,byte1,byte2] + } } -} -impl Into<[u8;4]> for UsbMidiEventPacket { - /// Converts the midi packet into a byte array - /// suitable for transfer via usbgit - fn into(self) -> [u8;4] { - let cable_number : u8 = self.cable_number.into(); - let index_number : u8 = self.code_index_number.into(); - let header = combine_nibble(cable_number,index_number); - - let raw : Raw = self.message.into(); - let status : u8 = raw.status.into(); - - panic!() - } -} - +} \ No newline at end of file diff --git a/src/midi_device.rs b/src/midi_device.rs index 44d8431..9693508 100644 --- a/src/midi_device.rs +++ b/src/midi_device.rs @@ -1,6 +1,5 @@ use usb_device::class_prelude::*; use usb_device::Result; -use crate::data::midi::notes::Note; use crate::data::usb::constants::*; use crate::data::usb_midi::usb_midi_event_packet::UsbMidiEventPacket; @@ -34,28 +33,6 @@ impl MidiClass<'_, B> { self.standard_bulkin.write(&bytes) } - pub fn note_on(&mut self, chan: u8, note: Note, vel : u8) -> Result { - let note = note as u8; - self.standard_bulkin.write( - &[ - 0x09,//Note-on message (usb-midi) - 0x90 | (chan & 0x0f),// (note-on, normal midi) - note & 0x7f, //note - vel & 0x7f //vel - ]) - } - - pub fn note_off(&mut self, chan: u8, note: Note, vel : u8) -> Result { - let note = note as u8; - self.standard_bulkin.write( - &[ - 0x08,//Note-on message (usb-midi) - 0x80 | (chan & 0x0f),// (note-on, normal midi) - note & 0x7f, //note - vel & 0x7f //vel - ]) - } - } impl UsbClass for MidiClass<'_, B> { diff --git a/src/util/mod.rs b/src/util/mod.rs index 8d6cac7..e69de29 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1 +0,0 @@ -pub mod nibble; \ No newline at end of file diff --git a/src/util/nibble.rs b/src/util/nibble.rs deleted file mode 100644 index 5f8015f..0000000 --- a/src/util/nibble.rs +++ /dev/null @@ -1,10 +0,0 @@ - - -/// Combines two nibbles. -/// Note that the upper will overflow if greater than 0xF -/// The lower will be clamped to the range 0-0xF -pub fn combine_nibble(upper:u8,lower:u8) -> u8 { - let upper = upper.overflowing_shl(8).0; - let lower = lower & 0xF; - upper | lower -} \ No newline at end of file