mirror of
https://github.com/italicsjenga/usbd-midi.git
synced 2024-12-23 12:21:30 +11:00
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:
parent
a11b695c5e
commit
e4e16bcbcd
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
31
src/data/midi/midi_velocity.rs
Normal file
31
src/data/midi/midi_velocity.rs
Normal 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);
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
pub mod notes;
|
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;
|
|
@ -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;
|
||||||
|
|
|
@ -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]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
pub mod try_from;
|
pub mod try_from;
|
||||||
|
pub mod nibble;
|
10
src/util/nibble.rs
Normal file
10
src/util/nibble.rs
Normal 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
|
||||||
|
}
|
Loading…
Reference in a new issue