mirror of
https://github.com/italicsjenga/usbd-midi.git
synced 2024-12-23 12:21:30 +11:00
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.
This commit is contained in:
parent
6b7f71f7bd
commit
55d94f7024
|
@ -1 +1,2 @@
|
|||
pub mod u7;
|
||||
pub mod u7;
|
||||
pub mod u4;
|
46
src/data/byte/u4.rs
Normal file
46
src/data/byte/u4.rs
Normal file
|
@ -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<u8> for U4{
|
||||
type Error = InvalidU4;
|
||||
|
||||
fn try_from(value:u8) -> Result<Self,Self::Error> {
|
||||
if value > U4::MAX.0 {
|
||||
Err(InvalidU4(value))
|
||||
} else {
|
||||
Ok(U4(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<U4> 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)
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
pub mod notes;
|
||||
pub mod code_index_number;
|
||||
pub mod channel;
|
||||
pub mod message;
|
||||
pub mod velocity;
|
|
@ -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<u8> for CableNumber {
|
|||
|
||||
}
|
||||
|
||||
impl Into<u8> for CableNumber {
|
||||
fn into(self) -> u8 {
|
||||
self as u8
|
||||
impl From<CableNumber> for u8{
|
||||
fn from(value:CableNumber) -> u8 {
|
||||
value as u8
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CableNumber> 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);
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
|
|
@ -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<u8> for CodeIndexNumber {
|
|||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for CodeIndexNumber {
|
||||
fn into(self) -> u8 {
|
||||
self.0
|
||||
impl From<CodeIndexNumber> 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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,2 +1,3 @@
|
|||
pub mod usb_midi_event_packet;
|
||||
pub mod cable_number;
|
||||
pub mod cable_number;
|
||||
pub mod code_index_number;
|
|
@ -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<UsbMidiEventPacket> 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!()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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<B: UsbBus> MidiClass<'_, B> {
|
|||
self.standard_bulkin.write(&bytes)
|
||||
}
|
||||
|
||||
pub fn note_on(&mut self, chan: u8, note: Note, vel : u8) -> Result<usize> {
|
||||
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<usize> {
|
||||
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<B: UsbBus> UsbClass<B> for MidiClass<'_, B> {
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
pub mod nibble;
|
|
@ -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
|
||||
}
|
Loading…
Reference in a new issue