Refactoring

Swaps a few things around, and adds some better types
This commit is contained in:
beau trepp 2019-12-12 19:11:55 +08:00
parent 273f897ea5
commit dd37e5efcc
16 changed files with 256 additions and 121 deletions

View file

@ -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", path = "../usb-device" } usb-device = {version = "0.2.3"}

View file

@ -0,0 +1,63 @@
use crate::util::try_from::{TryFrom};
/// The Code Index Number(CIN) indicates the classification
/// of the bytes in the MIDI_x fields
pub struct CodeIndexNumber(u8);
impl TryFrom<u8> for CodeIndexNumber {
fn try_from(value:u8) -> Option<Self> {
if value > 0xF {
None
} else {
Some(CodeIndexNumber(value))
}
}
}
impl Into<u8> for CodeIndexNumber {
fn into(self) -> u8 {
self.0
}
}
impl CodeIndexNumber {
/// Miscellaneous function codes. Reserved for future extensions
pub const MISC_FUNCTION : CodeIndexNumber = CodeIndexNumber(0x00);
/// Cable events. Reserved for future expansion.
pub const CABLE_EVENTS : CodeIndexNumber = CodeIndexNumber(0x1);
/// Two-byte System Common messages like MTC, SongSelect, etc.
pub const SYSTEM_COMMON_LEN2 :CodeIndexNumber = CodeIndexNumber(0x2);
/// Three-byte System Common messages like SPP, etc.
pub const SYSTEM_COMMON_LEN3 :CodeIndexNumber = CodeIndexNumber(0x3);
/// SysEx starts or continues
pub const SYSEX_STARTS : CodeIndexNumber = CodeIndexNumber(0x4);
pub const SYSEX_CONTINUES : CodeIndexNumber = CodeIndexNumber::SYSEX_STARTS;
/// Single-byte System Common Message or SysEx ends with following single byte.
pub const SYSTEM_COMMON_LEN1 : CodeIndexNumber= CodeIndexNumber(0x5);
/// SysEx ends with the following byte
pub const SYSEX_ENDS_NEXT1 :CodeIndexNumber = CodeIndexNumber::SYSTEM_COMMON_LEN1;
/// SysEx ends with following two bytes
pub const SYSEX_ENDS_NEXT2 : CodeIndexNumber = CodeIndexNumber(0x6);
/// SysEx ends with following three bytes
pub const SYSEX_ENDS_NEXT3 : CodeIndexNumber = CodeIndexNumber(0x7);
/// Note - Off
pub const NOTE_OFF : CodeIndexNumber = CodeIndexNumber(0x8);
/// Note - On
pub const NOTE_ON : CodeIndexNumber = CodeIndexNumber(0x9);
/// Poly-KeyPress
pub const POLY_KEYPRESS : CodeIndexNumber = CodeIndexNumber(0xA);
/// Control Change
pub const CONTROL_CHANGE : CodeIndexNumber = CodeIndexNumber(0xB);
/// Program Change
pub const PROGRAM_CHANGE : CodeIndexNumber = CodeIndexNumber(0xC);
/// Channel Pressure
pub const CHANNEL_PRESSURE : CodeIndexNumber = CodeIndexNumber(0xD);
/// Pitch Bend Change
pub const PITCHBEND_CHANGE : CodeIndexNumber = CodeIndexNumber(0xE);
/// Single Byte
pub const SINGLE_BYTE : CodeIndexNumber= CodeIndexNumber(0xF);
}

View file

@ -0,0 +1,25 @@
use crate::util::try_from::{TryFrom};
/// The MidiChannel is a value ranging from 0x0 to 0xF
/// This is a standard midi concept
pub struct MidiChannel(u8);
impl TryFrom<u8> for MidiChannel {
fn try_from(value:u8) -> Option<MidiChannel> {
if value > 0xF {
None
} else {
Some(MidiChannel(value))
}
}
}
impl Into<u8> for MidiChannel {
fn into(self) -> u8 {
self.0
}
}

View file

3
src/data/midi/mod.rs Normal file
View file

@ -0,0 +1,3 @@
pub mod notes;
pub mod code_index_number;
pub mod midi_channel;

View file

@ -1,121 +1,35 @@
//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
/// C1m is the C-1
#[derive(Debug)] #[derive(Debug)]
#[repr(u8)] #[repr(u8)]
pub enum Note { pub enum Note {
A0 = 21, C1m, Cs1m, D1m, Ds1m, E1m, F1m, Fs1m, G1m, Gs1m, A1m, As1m, B1m,
As0, C0 , Cs0 , D0 , Ds0 , E0 , F0 , Fs0 , G0 , Gs0 , A0 , As0 , B0 ,
B0, C1 , Cs1 , D1 , Ds1 , E1 , F1 , Fs1 , G1 , Gs1 , A1 , As1 , B1 ,
C1, C2 , Cs2 , D2 , Ds2 , E2 , F2 , Fs2 , G2 , Gs2 , A2 , As2 , B2 ,
Cs1, C3 , Cs3 , D3 , Ds3 , E3 , F3 , Fs3 , G3 , Gs3 , A3 , As3 , B3 ,
D1, C4 , Cs4 , D4 , Ds4 , E4 , F4 , Fs4 , G4 , Gs4 , A4 , As4 , B4 ,
Ds1, C5 , Cs5 , D5 , Ds5 , E5 , F5 , Fs5 , G5 , Gs5 , A5 , As5 , B5 ,
E1, C6 , Cs6 , D6 , Ds6 , E6 , F6 , Fs6 , G6 , Gs6 , A6 , As6 , B6 ,
F1, C7 , Cs7 , D7 , Ds7 , E7 , F7 , Fs7 , G7 , Gs7 , A7 , As7 , B7 ,
Fs1, C8 , Cs8 , D8 , Ds8 , E8 , F8 , Fs8 , G8 , Gs8 , A8 , As8 , B8 ,
G1, C9 , Cs9 , D9 , Ds9 , E9 , F9 , Fs9 , G9 , Gs9
Gs1,
A1,
As1,
B1,
C2,
Cs2,
D2,
Ds2,
E2,
F2,
Fs2,
G2,
Gs2,
A2,
As2,
B2,
C3,
Cs3,
D3,
Ds3,
E3,
F3,
Fs3,
G3,
Gs3,
A3,
As3,
B3,
C4,
Cs4,
D4,
Ds4,
E4,
F4,
Fs4,
G4,
Gs4,
A4,
As4,
B4,
C5,
Cs5,
D5,
Ds5,
E5,
F5,
Fs5,
G5,
Gs5,
A5,
As5,
B5,
C6,
Cs6,
D6,
Ds6,
E6,
F6,
Fs6,
G6,
Gs6,
A6,
As6,
B6,
C7,
Cs7,
D7,
Ds7,
E7,
F7,
Fs7,
G7,
Gs7,
A7,
As7,
B7,
C8,
Cs8,
D8,
Ds8,
E8,
F8,
Fs8,
G8,
Gs8,
A8,
As8,
B8,
C9,
Cs9,
D9,
Ds9,
E9,
F9,
Fs9,
G9,
Gs9
} }
impl Note { impl Note {
#[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 Gb1m : Note = Note::Fs1m;
#[allow(non_upper_case_globals)] pub const Ab1m : Note = Note::Gs1m;
#[allow(non_upper_case_globals)] pub const Bb1m : Note = Note::As1m;
#[allow(non_upper_case_globals)] pub const Db0 : Note = Note::Cs0;
#[allow(non_upper_case_globals)] pub const Eb0 : Note = Note::Ds0;
#[allow(non_upper_case_globals)] pub const Gb0 : Note = Note::Fs0;
#[allow(non_upper_case_globals)] pub const Ab0 : Note = Note::Gs0;
#[allow(non_upper_case_globals)] pub const Bb0 : Note = Note::As0;
#[allow(non_upper_case_globals)] pub const Db1 : Note = Note::Cs1; #[allow(non_upper_case_globals)] pub const Db1 : Note = Note::Cs1;
#[allow(non_upper_case_globals)] pub const Eb1 : Note = Note::Ds1; #[allow(non_upper_case_globals)] pub const Eb1 : Note = Note::Ds1;
#[allow(non_upper_case_globals)] pub const Gb1 : Note = Note::Fs1; #[allow(non_upper_case_globals)] pub const Gb1 : Note = Note::Fs1;
@ -182,6 +96,40 @@ mod tests {
//These test mainly prove we are generating all the sharps/flats //These test mainly prove we are generating all the sharps/flats
//(as the same number) correctly. //(as the same number) correctly.
note_test! { note_test! {
note_c1m: (Note::C1m,0),
note_cs1m: (Note::Cs1m,1),
note_db1m: (Note::Db1m,1),
note_d1m: (Note::D1m,2),
note_ds1m: (Note::Ds1m,3),
note_eb1m: (Note::Eb1m,3),
note_e1m: (Note::E1m,4),
note_f1m: (Note::F1m,5),
note_fs1m: (Note::Fs1m,6),
note_gb1m: (Note::Gb1m,6),
note_g1m: (Note::G1m,7),
note_gs1m: (Note::Gs1m,8),
note_ab1m: (Note::Ab1m,8),
note_a1m: (Note::A1m,9),
note_as1m: (Note::As1m,10),
note_bb1m: (Note::Bb1m,10),
note_b1m: (Note::B1m,11),
note_c0: (Note::C0,12),
note_cs0: (Note::Cs0,13),
note_db0: (Note::Db0,13),
note_d0: (Note::D0,14),
note_ds0: (Note::Ds0,15),
note_eb0: (Note::Eb0,15),
note_e0: (Note::E0,16),
note_f0: (Note::F0,17),
note_fs0: (Note::Fs0,18),
note_gb0: (Note::Gb0,18),
note_g0: (Note::G0,19),
note_gs0: (Note::Gs0,20),
note_ab0: (Note::Ab0,20),
note_a0: (Note::A0,21),
note_as0: (Note::As0,22),
note_bb0: (Note::Bb0,22),
note_b0: (Note::B0,23),
note_c1: (Note::C1,24), note_c1: (Note::C1,24),
note_cs1: (Note::Cs1,25), note_cs1: (Note::Cs1,25),
note_db1: (Note::Db1,25), note_db1: (Note::Db1,25),

3
src/data/mod.rs Normal file
View file

@ -0,0 +1,3 @@
pub mod midi;
pub mod usb;
pub mod usb_midi;

1
src/data/usb/mod.rs Normal file
View file

@ -0,0 +1 @@
pub mod constants;

View file

@ -0,0 +1,23 @@
use crate::util::try_from::{TryFrom};
/// The Cable Number (CN) is a value ranging from 0x0 to 0xF
/// indicating the number assignment of the Embedded MIDI Jack associated
/// with the endpoint that is transferring the data
pub struct CableNumber(u8);
impl TryFrom<u8> for CableNumber {
fn try_from(value:u8) -> Option<Self> {
if value > 0xF {
None
} else {
Some(CableNumber(value))
}
}
}
impl Into<u8> for CableNumber {
fn into(self) -> u8 {
self.0
}
}

2
src/data/usb_midi/mod.rs Normal file
View file

@ -0,0 +1,2 @@
pub mod usb_midi_event_packet;
pub mod cable_number;

View file

@ -0,0 +1,57 @@
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::midi_channel::MidiChannel;
/// 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!?
pub struct UsbMidiEventPacket {
cable_number : CableNumber,
code_index_number: CodeIndexNumber,
payload: [u8;3]
}
/// 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
pub fn note_on( cable:CableNumber,
channel: MidiChannel,
note:Note,
velocity: u8) -> UsbMidiEventPacket {
let code :u8 = CodeIndexNumber::NOTE_ON.into();
let channel : u8 = channel.into();
UsbMidiEventPacket{
cable_number : cable,
code_index_number : CodeIndexNumber::NOTE_ON,
payload : [ code & channel,
note as u8,
velocity
]
}
}
impl Into<[u8;4]> for UsbMidiEventPacket {
/// Converts the midi packet into a byte array
/// suitable for transfer via usb
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);
[ header,
self.payload[0],
self.payload[1],
self.payload[2]
]
}
}

View file

@ -1,9 +1,6 @@
#![no_std] #![no_std]
mod usb_constants;
mod midi_device;
mod notes;
pub use usb_device::{Result,UsbError}; mod util;
pub use crate::usb_constants::USB_CLASS_NONE; pub mod data;
pub use crate::midi_device::*; pub mod midi_device;
pub use crate::notes::Note;

View file

@ -1,7 +1,8 @@
use usb_device::class_prelude::*; use usb_device::class_prelude::*;
use usb_device::Result; use usb_device::Result;
use crate::notes::Note; use crate::data::midi::notes::Note;
use crate::usb_constants::*; use crate::data::usb::constants::*;
use crate::data::usb_midi::usb_midi_event_packet::UsbMidiEventPacket;
//const MIDI_IN_SIZE: u8 = 0x06; //const MIDI_IN_SIZE: u8 = 0x06;
const MIDI_OUT_SIZE: u8 = 0x09; const MIDI_OUT_SIZE: u8 = 0x09;
@ -28,6 +29,11 @@ impl<B: UsbBus> MidiClass<'_, B> {
} }
} }
pub fn send_message(&mut self, usb_midi:UsbMidiEventPacket) -> Result<usize> {
let bytes : [u8;4] = usb_midi.into();
self.standard_bulkin.write(&bytes)
}
pub fn note_on(&mut self, chan: u8, note: Note, vel : u8) -> Result<usize> { pub fn note_on(&mut self, chan: u8, note: Note, vel : u8) -> Result<usize> {
let note = note as u8; let note = note as u8;
self.standard_bulkin.write( self.standard_bulkin.write(

1
src/util/mod.rs Normal file
View file

@ -0,0 +1 @@
pub mod try_from;

6
src/util/try_from.rs Normal file
View file

@ -0,0 +1,6 @@
/// A version of try from that works on options
/// useful for the bounded ints
pub trait TryFrom<T> : Sized{
fn try_from(value:T) -> Option<Self>;
}