mirror of
https://github.com/italicsjenga/usbd-midi.git
synced 2024-12-23 12:21:30 +11:00
Allow creating multiple MIDI in and out jacks
This commit is contained in:
parent
49484f0b15
commit
0dfe89da04
|
@ -16,7 +16,9 @@ pub struct MidiClass<'a,B: UsbBus> {
|
||||||
standard_ac: InterfaceNumber,
|
standard_ac: InterfaceNumber,
|
||||||
standard_mc: InterfaceNumber,
|
standard_mc: InterfaceNumber,
|
||||||
standard_bulkout: EndpointOut<'a, B>,
|
standard_bulkout: EndpointOut<'a, B>,
|
||||||
standard_bulkin: EndpointIn<'a,B>
|
standard_bulkin: EndpointIn<'a,B>,
|
||||||
|
n_in_jacks: u8,
|
||||||
|
n_out_jacks: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum MidiReadError {
|
pub enum MidiReadError {
|
||||||
|
@ -24,15 +26,25 @@ pub enum MidiReadError {
|
||||||
UsbError(UsbError)
|
UsbError(UsbError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct InvalidArguments;
|
||||||
|
|
||||||
impl<B: UsbBus> MidiClass<'_, B> {
|
impl<B: UsbBus> MidiClass<'_, B> {
|
||||||
/// Creates a new MidiClass with the provided UsbBus
|
/// Creates a new MidiClass with the provided UsbBus and `n_in/out_jacks` embedded input/output jacks (or "cables",
|
||||||
pub fn new(alloc: &UsbBusAllocator<B>) -> MidiClass<'_, B> {
|
/// depending on the terminology).
|
||||||
MidiClass {
|
/// Note that a maximum of 16 in and 16 out jacks are supported.
|
||||||
|
pub fn new(alloc: &UsbBusAllocator<B>, n_in_jacks: u8, n_out_jacks: u8) -> core::result::Result<MidiClass<'_, B>, InvalidArguments> {
|
||||||
|
if n_in_jacks >= 16 || n_out_jacks >= 16 {
|
||||||
|
return Err(InvalidArguments);
|
||||||
|
}
|
||||||
|
Ok(MidiClass {
|
||||||
standard_ac: alloc.interface(),
|
standard_ac: alloc.interface(),
|
||||||
standard_mc: alloc.interface(),
|
standard_mc: alloc.interface(),
|
||||||
standard_bulkout : alloc.bulk(MAX_PACKET_SIZE as u16),
|
standard_bulkout : alloc.bulk(MAX_PACKET_SIZE as u16),
|
||||||
standard_bulkin: alloc.bulk(MAX_PACKET_SIZE as u16)
|
standard_bulkin: alloc.bulk(MAX_PACKET_SIZE as u16),
|
||||||
}
|
n_in_jacks,
|
||||||
|
n_out_jacks
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_message(&mut self, usb_midi:UsbMidiEventPacket) -> Result<usize> {
|
pub fn send_message(&mut self, usb_midi:UsbMidiEventPacket) -> Result<usize> {
|
||||||
|
@ -43,14 +55,21 @@ impl<B: UsbBus> MidiClass<'_, B> {
|
||||||
pub fn read(&mut self, buffer: &mut [u8]) -> Result<usize> {
|
pub fn read(&mut self, buffer: &mut [u8]) -> Result<usize> {
|
||||||
self.standard_bulkout.read(buffer)
|
self.standard_bulkout.read(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// calculates the index'th midi in jack id
|
||||||
|
fn in_jack_id(&self, index: u8) -> u8 {
|
||||||
|
return index + 1;
|
||||||
|
}
|
||||||
|
/// calculates the index'th midi in jack id
|
||||||
|
fn out_jack_id(&self, index: u8) -> u8 {
|
||||||
|
return self.n_in_jacks + index + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: UsbBus> UsbClass<B> for MidiClass<'_, B> {
|
impl<B: UsbBus> UsbClass<B> for MidiClass<'_, B> {
|
||||||
|
|
||||||
fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> {
|
fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> {
|
||||||
|
|
||||||
//AUDIO CONTROL STANDARD
|
//AUDIO CONTROL STANDARD
|
||||||
|
|
||||||
writer.interface(
|
writer.interface(
|
||||||
self.standard_ac,
|
self.standard_ac,
|
||||||
USB_AUDIO_CLASS,
|
USB_AUDIO_CLASS,
|
||||||
|
@ -79,64 +98,80 @@ impl<B: UsbBus> UsbClass<B> for MidiClass<'_, B> {
|
||||||
0, //no protocol
|
0, //no protocol
|
||||||
)?; //Num endpoints?
|
)?; //Num endpoints?
|
||||||
|
|
||||||
//Streaming extra info
|
let midi_streaming_start_byte = writer.position();
|
||||||
|
let midi_streaming_total_length =
|
||||||
|
7 + self.n_in_jacks as usize * MIDI_IN_SIZE as usize + self.n_out_jacks as usize * MIDI_OUT_SIZE as usize
|
||||||
|
+ 7 + (4+self.n_in_jacks as usize) + 7 + (4+self.n_out_jacks as usize);
|
||||||
|
|
||||||
writer.write(
|
//Streaming extra info
|
||||||
|
writer.write( // len = 7
|
||||||
CS_INTERFACE,
|
CS_INTERFACE,
|
||||||
&[
|
&[
|
||||||
MS_HEADER_SUBTYPE,
|
MS_HEADER_SUBTYPE,
|
||||||
0x00,0x01, //REVISION
|
0x00,0x01, //REVISION
|
||||||
(0x07 + MIDI_OUT_SIZE),0x00 //Total size of class specific descriptors? (little endian?)
|
(midi_streaming_total_length & 0xFF) as u8, ((midi_streaming_total_length >> 8) & 0xFF) as u8
|
||||||
]
|
]
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
//JACKS
|
//JACKS
|
||||||
|
for i in 0..self.n_in_jacks {
|
||||||
|
writer.write( // len = 6 = MIDI_IN_SIZE
|
||||||
|
CS_INTERFACE,
|
||||||
|
&[
|
||||||
|
MIDI_IN_JACK_SUBTYPE,
|
||||||
|
EMBEDDED,
|
||||||
|
self.in_jack_id(i), // id
|
||||||
|
0x00
|
||||||
|
]
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
writer.write(
|
for i in 0..self.n_out_jacks {
|
||||||
CS_INTERFACE,
|
writer.write ( // len = 9 = MIDI_OUT_SIZE
|
||||||
&[
|
CS_INTERFACE,
|
||||||
MIDI_IN_JACK_SUBTYPE,
|
&[
|
||||||
EMBEDDED,
|
MIDI_OUT_JACK_SUBTYPE,
|
||||||
0x01, // id
|
EMBEDDED,
|
||||||
0x00
|
self.out_jack_id(i), //id
|
||||||
]
|
0x01, // 1 pin
|
||||||
)?;
|
self.in_jack_id(i), // pin 1
|
||||||
|
0x01, //sorta vague source pin?
|
||||||
|
0x00
|
||||||
|
]
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
writer.write (
|
let mut endpoint_data = [
|
||||||
CS_INTERFACE,
|
MS_GENERAL,
|
||||||
&[
|
0, // number of jacks. must be filled in!
|
||||||
MIDI_OUT_JACK_SUBTYPE,
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 // jack mappings. must be filled in and cropped.
|
||||||
EMBEDDED,
|
];
|
||||||
0x01,//id
|
|
||||||
0x01, // 1 pin
|
|
||||||
0x01, // pin 1
|
|
||||||
0x01, //sorta vague source pin?
|
|
||||||
0x00
|
|
||||||
]
|
|
||||||
)?;
|
|
||||||
|
|
||||||
writer.endpoint(&self.standard_bulkout)?;
|
writer.endpoint(&self.standard_bulkout)?; // len = 7
|
||||||
|
|
||||||
writer.write(
|
endpoint_data[1] = self.n_in_jacks;
|
||||||
|
for i in 0..self.n_in_jacks {
|
||||||
|
endpoint_data[2 + i as usize] = self.in_jack_id(i);
|
||||||
|
}
|
||||||
|
writer.write( // len = 4 + self.n_in_jacks
|
||||||
CS_ENDPOINT,
|
CS_ENDPOINT,
|
||||||
&[
|
&endpoint_data[0..2+self.n_in_jacks as usize]
|
||||||
MS_GENERAL,
|
|
||||||
0x01,
|
|
||||||
0x01
|
|
||||||
]
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
writer.endpoint(&self.standard_bulkin)?;
|
writer.endpoint(&self.standard_bulkin)?; // len = 7
|
||||||
|
endpoint_data[1] = self.n_out_jacks;
|
||||||
writer.write(
|
for i in 0..self.n_out_jacks {
|
||||||
|
endpoint_data[2 + i as usize] = self.out_jack_id(i);
|
||||||
|
}
|
||||||
|
writer.write( // len = 4 + self.n_out_jacks
|
||||||
CS_ENDPOINT,
|
CS_ENDPOINT,
|
||||||
&[
|
&endpoint_data[0..2+self.n_out_jacks as usize]
|
||||||
MS_GENERAL,
|
|
||||||
0x01,
|
|
||||||
0x01
|
|
||||||
]
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
let midi_streaming_end_byte = writer.position();
|
||||||
|
assert!(midi_streaming_end_byte - midi_streaming_start_byte == midi_streaming_total_length);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue