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]
|
[dependencies]
|
||||||
embedded-hal = "0.2.2"
|
embedded-hal = "0.2.2"
|
||||||
nb = "0.1.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 u7;
|
||||||
pub mod u4;
|
pub mod u4;
|
||||||
|
pub mod from_traits;
|
|
@ -26,7 +26,7 @@ impl From<U4> for u8 {
|
||||||
|
|
||||||
impl U4 {
|
impl U4 {
|
||||||
pub const MAX: U4= U4(0x0F);
|
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
|
/// Combines two nibbles (u4) eg half byte
|
||||||
/// result will be a full byte
|
/// result will be a full byte
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
|
use crate::data::byte::from_traits::{FromOverFlow,FromClamped};
|
||||||
|
|
||||||
/// A primitive value that can be from 0-0x7F
|
/// A primitive value that can be from 0-0x7F
|
||||||
pub struct U7(u8);
|
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 {
|
impl U7 {
|
||||||
pub const MAX: U7= U7(0x7F);
|
pub const MAX: U7= U7(0x7F);
|
||||||
pub const MIN: U7 = U7(0);
|
pub const MIN: U7 = U7(0);
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,10 +1,11 @@
|
||||||
|
|
||||||
use crate::data::midi::channel::Channel;
|
use crate::data::midi::channel::Channel;
|
||||||
use crate::data::midi::velocity::Velocity;
|
|
||||||
use crate::data::midi::notes::Note;
|
use crate::data::midi::notes::Note;
|
||||||
use crate::data::byte::u7::U7;
|
use crate::data::byte::u7::U7;
|
||||||
use crate::data::midi::message::raw::{Raw,Payload};
|
use crate::data::midi::message::raw::{Raw,Payload};
|
||||||
|
|
||||||
|
type Velocity = U7;
|
||||||
|
|
||||||
/// Represents midi messages
|
/// Represents midi messages
|
||||||
/// Note: not current exhaustive and SysEx messages end up
|
/// Note: not current exhaustive and SysEx messages end up
|
||||||
/// being a confusing case. So are currently note implemented
|
/// being a confusing case. So are currently note implemented
|
||||||
|
@ -29,32 +30,32 @@ impl From<Message> for Raw {
|
||||||
fn from(value:Message) -> Raw {
|
fn from(value:Message) -> Raw {
|
||||||
match value {
|
match value {
|
||||||
Message::NoteOn(chan,note,vel) => {
|
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);
|
let status = NOTE_ON_MASK | u8::from(chan);
|
||||||
Raw { status, payload }
|
Raw { status, payload }
|
||||||
},
|
},
|
||||||
Message::NoteOff(chan,note,vel) => {
|
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);
|
let status = NOTE_OFF_MASK | u8::from(chan);
|
||||||
Raw {status, payload}
|
Raw {status, payload}
|
||||||
},
|
},
|
||||||
Message::PolyphonicAftertouch(chan,note,pressure) => {
|
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);
|
let status = POLYPHONIC_MASK | u8::from(chan);
|
||||||
Raw {status, payload}
|
Raw {status, payload}
|
||||||
},
|
},
|
||||||
Message::ProgramChange(chan,program) => {
|
Message::ProgramChange(chan,program) => {
|
||||||
let payload = Payload::SingleByte(u8::from(program));
|
let payload = Payload::SingleByte(program);
|
||||||
let status = PROGRAM_MASK | u8::from(chan);
|
let status = PROGRAM_MASK | u8::from(chan);
|
||||||
Raw {status, payload}
|
Raw {status, payload}
|
||||||
},
|
},
|
||||||
Message::ChannelAftertouch(chan,pressure) => {
|
Message::ChannelAftertouch(chan,pressure) => {
|
||||||
let payload = Payload::SingleByte(u8::from(pressure));
|
let payload = Payload::SingleByte(pressure);
|
||||||
let status = CHANNEL_AFTERTOUCH_MASK | u8::from(chan);
|
let status = CHANNEL_AFTERTOUCH_MASK | u8::from(chan);
|
||||||
Raw {status, payload}
|
Raw {status, payload}
|
||||||
},
|
},
|
||||||
Message::PitchWheelChange(chan,lsb,msb) => {
|
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);
|
let status = PITCH_BEND_MASK | u8::from(chan);
|
||||||
Raw {status , payload}
|
Raw {status , payload}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
pub mod voice;
|
|
||||||
pub mod message;
|
pub mod message;
|
||||||
pub mod raw;
|
pub mod raw;
|
||||||
pub use crate::data::midi::message::message::{Message};
|
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
|
/// Represents the payloads that the midi message may contain
|
||||||
pub enum Payload {
|
pub enum Payload {
|
||||||
Empty,
|
Empty,
|
||||||
SingleByte(u8),
|
SingleByte(U7),
|
||||||
DoubleByte(u8,u8)
|
DoubleByte(U7,U7)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A struct that captures the valid states
|
/// A struct that captures the valid states
|
||||||
|
@ -13,4 +15,4 @@ pub enum Payload {
|
||||||
pub struct Raw {
|
pub struct Raw {
|
||||||
pub status: u8,
|
pub status: u8,
|
||||||
pub payload: Payload
|
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 notes;
|
||||||
pub mod channel;
|
pub mod channel;
|
||||||
pub mod message;
|
pub mod message;
|
||||||
pub mod velocity;
|
|
|
@ -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'
|
/// A simple enum type that represents all the midi 'notes'
|
||||||
/// note the flat versions are associated constants
|
/// note the flat versions are associated constants
|
||||||
/// but can be referenced like Note::Bb3
|
/// 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 {
|
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;
|
||||||
|
|
|
@ -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 {
|
match raw_midi.payload {
|
||||||
Payload::Empty => [header,status,0,0],
|
Payload::Empty => [header,status,0,0],
|
||||||
Payload::SingleByte(byte) => [header,status,byte,0],
|
Payload::SingleByte(byte) =>
|
||||||
Payload::DoubleByte(byte1,byte2) => [header,status,byte1,byte2]
|
[header,status,byte.into(),0],
|
||||||
|
Payload::DoubleByte(byte1,byte2) =>
|
||||||
|
[header,status,byte1.into(),byte2.into()]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue