Further cleanup of types

I should write better messages, but this shifts the cable
number to follow the numbering usually present in devices (0 is 1 etc).

Also implements some other missing types
This commit is contained in:
beau trepp 2019-12-12 20:17:24 +08:00
parent a11b695c5e
commit e4e16bcbcd
8 changed files with 110 additions and 46 deletions

View file

@ -2,20 +2,20 @@ use crate::util::try_from::{TryFrom};
/// The MidiChannel is a value ranging from 0x0 to 0xF /// The MidiChannel is a value ranging from 0x0 to 0xF
/// This is a standard midi concept /// This is a standard midi concept
/// Note Channel1 = 0 on the wire
#[derive(Debug)] #[derive(Debug)]
#[repr(u8)] #[repr(u8)]
pub enum MidiChannel { pub enum MidiChannel {
Channel0 = 0x0, Channel1 = 0x1, Channel2 = 0x2, Channel3 = 0x3, Channel1 = 0x0, Channel2 = 0x1, Channel3 = 0x2, Channel4 = 0x3,
Channel4 = 0x4, Channel5 = 0x5, Channel6 = 0x6, Channel7 = 0x7, Channel5 = 0x4, Channel6 = 0x5, Channel7 = 0x6, Channel8 = 0x7,
Channel8 = 0x8, Channel9 = 0x9, Channel10 = 0xA, Channel11 = 0xB, Channel9 = 0x8, Channel10 = 0x9, Channel11 = 0xA, Channel12 = 0xB,
Channel12 = 0xC, Channel13 = 0xD, Channel14 = 0xE, Channel15 = 0xF Channel13 = 0xC, Channel14 = 0xD, Channel15 = 0xE, Channel16 = 0xF
} }
impl TryFrom<u8> for MidiChannel { impl TryFrom<u8> for MidiChannel {
fn try_from(value:u8) -> Option<Self> { fn try_from(value:u8) -> Option<Self> {
match value { match value {
x if x == MidiChannel::Channel0 as u8 => Some(MidiChannel::Channel0),
x if x == MidiChannel::Channel1 as u8 => Some(MidiChannel::Channel1), x if x == MidiChannel::Channel1 as u8 => Some(MidiChannel::Channel1),
x if x == MidiChannel::Channel2 as u8 => Some(MidiChannel::Channel2), x if x == MidiChannel::Channel2 as u8 => Some(MidiChannel::Channel2),
x if x == MidiChannel::Channel3 as u8 => Some(MidiChannel::Channel3), x if x == MidiChannel::Channel3 as u8 => Some(MidiChannel::Channel3),
@ -31,6 +31,7 @@ impl TryFrom<u8> for MidiChannel {
x if x == MidiChannel::Channel13 as u8 => Some(MidiChannel::Channel13), x if x == MidiChannel::Channel13 as u8 => Some(MidiChannel::Channel13),
x if x == MidiChannel::Channel14 as u8 => Some(MidiChannel::Channel14), x if x == MidiChannel::Channel14 as u8 => Some(MidiChannel::Channel14),
x if x == MidiChannel::Channel15 as u8 => Some(MidiChannel::Channel15), x if x == MidiChannel::Channel15 as u8 => Some(MidiChannel::Channel15),
x if x == MidiChannel::Channel16 as u8 => Some(MidiChannel::Channel16),
_ => None _ => None
} }
} }
@ -60,21 +61,21 @@ mod tests {
} }
channel_test! { channel_test! {
cable_0: (MidiChannel::Channel0,0), channel_1: (MidiChannel::Channel1,0),
cable_1: (MidiChannel::Channel1,1), channel_2: (MidiChannel::Channel2,1),
cable_2: (MidiChannel::Channel2,2), channel_3: (MidiChannel::Channel3,2),
cable_3: (MidiChannel::Channel3,3), channel_4: (MidiChannel::Channel4,3),
cable_4: (MidiChannel::Channel4,4), channel_5: (MidiChannel::Channel5,4),
cable_5: (MidiChannel::Channel5,5), channel_6: (MidiChannel::Channel6,5),
cable_6: (MidiChannel::Channel6,6), channel_7: (MidiChannel::Channel7,6),
cable_7: (MidiChannel::Channel7,7), channel_8: (MidiChannel::Channel8,7),
cable_8: (MidiChannel::Channel8,8), channel_9: (MidiChannel::Channel9,8),
cable_9: (MidiChannel::Channel9,9), channel_10: (MidiChannel::Channel10,9),
cable_10: (MidiChannel::Channel10,10), channel_11: (MidiChannel::Channel11,10),
cable_11: (MidiChannel::Channel11,11), channel_12: (MidiChannel::Channel12,11),
cable_12: (MidiChannel::Channel12,12), channel_13: (MidiChannel::Channel13,12),
cable_13: (MidiChannel::Channel13,13), channel_14: (MidiChannel::Channel14,13),
cable_14: (MidiChannel::Channel14,14), channel_15: (MidiChannel::Channel15,14),
cable_15: (MidiChannel::Channel15,15), channel_16: (MidiChannel::Channel16,15),
} }
} }

View file

@ -1,4 +1,28 @@
use crate::data::midi::midi_channel::MidiChannel;
use crate::data::midi::notes::Note;
use crate::data::midi::midi_velocity::MidiVelocity;
pub struct MidiMessage { pub struct MidiMessage {
payload: [u8;3] payload: [u8;3]
} }
impl MidiMessage {
pub fn note_on(channel:MidiChannel, note:Note, velocity:MidiVelocity)
-> MidiMessage{
let channel : u8 = channel.into();
let note : u8 = note.into();
let velocity : u8 = velocity.into();
MidiMessage {
payload: [channel,note,velocity]
}
}
}
impl Into<[u8;3]> for MidiMessage {
/// Converts the midi packet into a byte array
/// suitable for transfer via usb
fn into(self) -> [u8;3] {
self.payload
}
}

View file

@ -0,0 +1,31 @@
use crate::util::try_from::TryFrom;
pub struct MidiVelocity(u8);
impl From<u8> for MidiVelocity{
fn from(value:u8) -> MidiVelocity{
let masked = value & 0x7F;
MidiVelocity(masked)
}
}
impl Into<u8> for MidiVelocity{
fn into(self) -> u8 {
self.0
}
}
impl TryFrom<u8> for MidiVelocity{
fn try_from(value:u8) -> Option<MidiVelocity> {
if value > 0x7F {
None
} else {
Some(MidiVelocity(value))
}
}
}
impl MidiVelocity {
pub const MAX: MidiVelocity= MidiVelocity(0x7F);
pub const MIN: MidiVelocity = MidiVelocity(0);
}

View file

@ -2,3 +2,4 @@ pub mod notes;
pub mod code_index_number; pub mod code_index_number;
pub mod midi_channel; pub mod midi_channel;
pub mod midi_message; pub mod midi_message;
pub mod midi_velocity;

View file

@ -19,6 +19,13 @@ pub enum Note {
C9 , Cs9 , D9 , Ds9 , E9 , F9 , Fs9 , G9 , Gs9 C9 , Cs9 , D9 , Ds9 , E9 , F9 , Fs9 , G9 , Gs9
} }
impl Into<u8> for Note {
fn into(self) -> u8 {
self as u8
}
}
impl Note { impl Note {
#[allow(non_upper_case_globals)] pub const Db1m : Note = Note::Cs1m; #[allow(non_upper_case_globals)] pub const Db1m : Note = Note::Cs1m;
#[allow(non_upper_case_globals)] pub const Eb1m : Note = Note::Ds1m; #[allow(non_upper_case_globals)] pub const Eb1m : Note = Note::Ds1m;

View file

@ -3,6 +3,8 @@ use crate::data::midi::code_index_number::CodeIndexNumber;
use crate::data::midi::notes::Note; use crate::data::midi::notes::Note;
use crate::data::midi::midi_channel::MidiChannel; use crate::data::midi::midi_channel::MidiChannel;
use crate::data::midi::midi_message::MidiMessage; use crate::data::midi::midi_message::MidiMessage;
use crate::data::midi::midi_velocity::MidiVelocity;
use crate::util::nibble::{combine_nibble};
/// A packet that communicates with the host /// A packet that communicates with the host
/// Note that the payload seems fairly 'open' /// Note that the payload seems fairly 'open'
@ -11,34 +13,20 @@ use crate::data::midi::midi_message::MidiMessage;
pub struct UsbMidiEventPacket { pub struct UsbMidiEventPacket {
cable_number : CableNumber, cable_number : CableNumber,
code_index_number: CodeIndexNumber, code_index_number: CodeIndexNumber,
payload: [u8;3] message: MidiMessage
}
/// Combines two nibbles.
/// Note that the upper will overflow if greater than 0xF
/// The lower will be clamped to the range 0-0xF
fn combine_nibble(upper:u8,lower:u8) -> u8 {
let upper = upper.overflowing_shl(8).0;
let lower = lower & 0xF;
upper | lower
} }
/// Constructs a note-on midi message given the cable, note and velocity /// Constructs a note-on midi message given the cable, note and velocity
pub fn note_on( cable:CableNumber, pub fn note_on( cable:CableNumber,
channel: MidiChannel, channel: MidiChannel,
note:Note, note:Note,
velocity: u8) -> UsbMidiEventPacket { velocity: MidiVelocity) -> UsbMidiEventPacket {
let message = MidiMessage::note_on(channel,note,velocity);
let code :u8 = CodeIndexNumber::NOTE_ON.into();
let channel : u8 = channel.into();
UsbMidiEventPacket{ UsbMidiEventPacket{
cable_number : cable, cable_number : cable,
code_index_number : CodeIndexNumber::NOTE_ON, code_index_number : CodeIndexNumber::NOTE_ON,
payload : [ code & channel, message : message
note as u8,
velocity
]
} }
} }
impl Into<[u8;4]> for UsbMidiEventPacket { impl Into<[u8;4]> for UsbMidiEventPacket {
@ -48,10 +36,11 @@ impl Into<[u8;4]> for UsbMidiEventPacket {
let cable_number : u8 = self.cable_number.into(); let cable_number : u8 = self.cable_number.into();
let index_number : u8 = self.code_index_number.into(); let index_number : u8 = self.code_index_number.into();
let header = combine_nibble(cable_number,index_number); let header = combine_nibble(cable_number,index_number);
let payload : [u8;3]= self.message.into();
[ header, [ header,
self.payload[0], payload[0],
self.payload[1], payload[1],
self.payload[2] payload[2]
] ]
} }
} }

View file

@ -1 +1,2 @@
pub mod try_from; pub mod try_from;
pub mod nibble;

10
src/util/nibble.rs Normal file
View file

@ -0,0 +1,10 @@
/// 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
}