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]
embedded-hal = "0.2.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'
//note the flat versions are associated constants
//but can be referenced like Note::Bb3
/// A simple enum type that represents all the midi 'notes'
/// note the flat versions are associated constants
/// but can be referenced like Note::Bb3
/// C1m is the C-1
#[derive(Debug)]
#[repr(u8)]
pub enum Note {
A0 = 21,
As0,
B0,
C1,
Cs1,
D1,
Ds1,
E1,
F1,
Fs1,
G1,
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
C1m, Cs1m, D1m, Ds1m, E1m, F1m, Fs1m, G1m, Gs1m, A1m, As1m, B1m,
C0 , Cs0 , D0 , Ds0 , E0 , F0 , Fs0 , G0 , Gs0 , A0 , As0 , B0 ,
C1 , Cs1 , D1 , Ds1 , E1 , F1 , Fs1 , G1 , 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 {
#[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 Eb1 : Note = Note::Ds1;
#[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
//(as the same number) correctly.
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_cs1: (Note::Cs1,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]
mod usb_constants;
mod midi_device;
mod notes;
pub use usb_device::{Result,UsbError};
pub use crate::usb_constants::USB_CLASS_NONE;
pub use crate::midi_device::*;
pub use crate::notes::Note;
mod util;
pub mod data;
pub mod midi_device;

View file

@ -1,7 +1,8 @@
use usb_device::class_prelude::*;
use usb_device::Result;
use crate::notes::Note;
use crate::usb_constants::*;
use crate::data::midi::notes::Note;
use crate::data::usb::constants::*;
use crate::data::usb_midi::usb_midi_event_packet::UsbMidiEventPacket;
//const MIDI_IN_SIZE: u8 = 0x06;
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> {
let note = note as u8;
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>;
}