mirror of
https://github.com/italicsjenga/usbd-midi.git
synced 2024-12-23 12:21:30 +11:00
Strengthens raw midi packet.
It now very strongly depends on U7s when appropriate
This commit is contained in:
parent
55d94f7024
commit
d151a05787
|
@ -9,4 +9,4 @@ edition = "2018"
|
|||
[dependencies]
|
||||
embedded-hal = "0.2.2"
|
||||
nb = "0.1.2"
|
||||
usb-device = {version = "0.2.3"}
|
||||
usb-device = {version = "0.2.3"}
|
12
src/data/byte/from_traits.rs
Normal file
12
src/data/byte/from_traits.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
|
||||
|
||||
/// Like from, but will conceptually overflow if the value is too big
|
||||
/// this is useful from going from higher ranges to lower ranges
|
||||
pub trait FromOverFlow<T>:Sized {
|
||||
fn from_overflow(_:T) -> Self;
|
||||
}
|
||||
|
||||
/// Like from, but will clamp the value to a maximum value
|
||||
pub trait FromClamped<T>:Sized{
|
||||
fn from_clamped(_:T) -> Self;
|
||||
}
|
|
@ -1,2 +1,3 @@
|
|||
pub mod u7;
|
||||
pub mod u4;
|
||||
pub mod u4;
|
||||
pub mod from_traits;
|
|
@ -26,7 +26,7 @@ impl From<U4> for u8 {
|
|||
|
||||
impl U4 {
|
||||
pub const MAX: U4= U4(0x0F);
|
||||
pub const MIN: U4 = U4(0);
|
||||
pub const MIN: U4= U4(0);
|
||||
|
||||
/// Combines two nibbles (u4) eg half byte
|
||||
/// result will be a full byte
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use core::convert::TryFrom;
|
||||
use crate::data::byte::from_traits::{FromOverFlow,FromClamped};
|
||||
|
||||
/// A primitive value that can be from 0-0x7F
|
||||
pub struct U7(u8);
|
||||
|
@ -24,7 +25,25 @@ impl From<U7> for u8 {
|
|||
}
|
||||
}
|
||||
|
||||
impl FromOverFlow<u8> for U7 {
|
||||
fn from_overflow(value:u8) -> U7 {
|
||||
const MASK :u8 = 0b0111_1111;
|
||||
let value = MASK & value;
|
||||
U7(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromClamped<u8> for U7{
|
||||
fn from_clamped(value:u8) -> U7{
|
||||
match U7::try_from(value) {
|
||||
Ok(x) => x,
|
||||
_ => U7::MAX
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl U7 {
|
||||
pub const MAX: U7= U7(0x7F);
|
||||
pub const MIN: U7 = U7(0);
|
||||
|
||||
}
|
|
@ -1,10 +1,11 @@
|
|||
|
||||
use crate::data::midi::channel::Channel;
|
||||
use crate::data::midi::velocity::Velocity;
|
||||
use crate::data::midi::notes::Note;
|
||||
use crate::data::byte::u7::U7;
|
||||
use crate::data::midi::message::raw::{Raw,Payload};
|
||||
|
||||
type Velocity = U7;
|
||||
|
||||
/// Represents midi messages
|
||||
/// Note: not current exhaustive and SysEx messages end up
|
||||
/// being a confusing case. So are currently note implemented
|
||||
|
@ -29,32 +30,32 @@ impl From<Message> for Raw {
|
|||
fn from(value:Message) -> Raw {
|
||||
match value {
|
||||
Message::NoteOn(chan,note,vel) => {
|
||||
let payload = Payload::DoubleByte(note.into(),vel.into());
|
||||
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.into());
|
||||
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.into());
|
||||
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(u8::from(program));
|
||||
let payload = Payload::SingleByte(program);
|
||||
let status = PROGRAM_MASK | u8::from(chan);
|
||||
Raw {status, payload}
|
||||
},
|
||||
Message::ChannelAftertouch(chan,pressure) => {
|
||||
let payload = Payload::SingleByte(u8::from(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(u8::from(lsb),u8::from(msb));
|
||||
let payload = Payload::DoubleByte(lsb,msb);
|
||||
let status = PITCH_BEND_MASK | u8::from(chan);
|
||||
Raw {status , payload}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
pub mod voice;
|
||||
pub mod message;
|
||||
pub mod raw;
|
||||
pub use crate::data::midi::message::message::{Message};
|
|
@ -1,8 +1,10 @@
|
|||
use crate::data::byte::u7::U7;
|
||||
|
||||
/// Represents the payloads that the midi message may contain
|
||||
pub enum Payload {
|
||||
Empty,
|
||||
SingleByte(u8),
|
||||
DoubleByte(u8,u8)
|
||||
SingleByte(U7),
|
||||
DoubleByte(U7,U7)
|
||||
}
|
||||
|
||||
/// A struct that captures the valid states
|
||||
|
@ -13,4 +15,4 @@ pub enum Payload {
|
|||
pub struct Raw {
|
||||
pub status: u8,
|
||||
pub payload: Payload
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
|
||||
pub use crate::data::midi::channel::Channel;
|
||||
pub use crate::data::midi::notes::Note;
|
||||
pub use crate::data::midi::velocity::Velocity;
|
||||
|
||||
pub enum Voice {
|
||||
NoteOff(Channel,Note,Velocity),
|
||||
NoteOn(Channel,Note,Velocity),
|
||||
PolyPressure(Channel)
|
||||
}
|
||||
|
||||
|
||||
impl Voice {
|
||||
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
pub mod notes;
|
||||
pub mod channel;
|
||||
pub mod message;
|
||||
pub mod velocity;
|
||||
pub mod message;
|
|
@ -1,4 +1,5 @@
|
|||
|
||||
use crate::data::byte::u7::U7;
|
||||
use crate::data::byte::from_traits::FromOverFlow;
|
||||
/// A simple enum type that represents all the midi 'notes'
|
||||
/// note the flat versions are associated constants
|
||||
/// but can be referenced like Note::Bb3
|
||||
|
@ -26,6 +27,14 @@ impl Into<u8> for Note {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Note> for U7 {
|
||||
fn from(value:Note) -> U7{
|
||||
let byte = value as u8;
|
||||
U7::from_overflow(byte)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Note {
|
||||
#[allow(non_upper_case_globals)] pub const Db1m : Note = Note::Cs1m;
|
||||
#[allow(non_upper_case_globals)] pub const Eb1m : Note = Note::Ds1m;
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
use core::convert::TryFrom;
|
||||
|
||||
pub struct Velocity(u8);
|
||||
|
||||
pub struct InvalidVelocity(u8);
|
||||
|
||||
impl TryFrom<u8> for Velocity{
|
||||
type Error = InvalidVelocity;
|
||||
|
||||
fn try_from(value:u8) -> Result<Self,Self::Error> {
|
||||
if value > 0x7F {
|
||||
Err(InvalidVelocity(value))
|
||||
} else {
|
||||
Ok(Velocity(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for Velocity {
|
||||
fn into(self) -> u8 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Velocity {
|
||||
pub const MAX: Velocity= Velocity(0x7F);
|
||||
pub const MIN: Velocity = Velocity(0);
|
||||
}
|
|
@ -28,8 +28,10 @@ impl From<UsbMidiEventPacket> for [u8;4] {
|
|||
|
||||
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]
|
||||
Payload::SingleByte(byte) =>
|
||||
[header,status,byte.into(),0],
|
||||
Payload::DoubleByte(byte1,byte2) =>
|
||||
[header,status,byte1.into(),byte2.into()]
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue