From 0dfe89da0424de79c72c2e8d782e3ee3464ee67d Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Sun, 21 Mar 2021 22:25:09 +0100 Subject: [PATCH] Allow creating multiple MIDI in and out jacks --- src/midi_device.rs | 133 ++++++++++++++++++++++++++++----------------- 1 file changed, 84 insertions(+), 49 deletions(-) diff --git a/src/midi_device.rs b/src/midi_device.rs index 44d7536..4e551d4 100644 --- a/src/midi_device.rs +++ b/src/midi_device.rs @@ -16,7 +16,9 @@ pub struct MidiClass<'a,B: UsbBus> { standard_ac: InterfaceNumber, standard_mc: InterfaceNumber, 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 { @@ -24,15 +26,25 @@ pub enum MidiReadError { UsbError(UsbError) } +#[derive(Debug)] +pub struct InvalidArguments; + impl MidiClass<'_, B> { - /// Creates a new MidiClass with the provided UsbBus - pub fn new(alloc: &UsbBusAllocator) -> MidiClass<'_, B> { - MidiClass { + /// Creates a new MidiClass with the provided UsbBus and `n_in/out_jacks` embedded input/output jacks (or "cables", + /// depending on the terminology). + /// Note that a maximum of 16 in and 16 out jacks are supported. + pub fn new(alloc: &UsbBusAllocator, n_in_jacks: u8, n_out_jacks: u8) -> core::result::Result, InvalidArguments> { + if n_in_jacks >= 16 || n_out_jacks >= 16 { + return Err(InvalidArguments); + } + Ok(MidiClass { standard_ac: alloc.interface(), standard_mc: alloc.interface(), 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 { @@ -43,14 +55,21 @@ impl MidiClass<'_, B> { pub fn read(&mut self, buffer: &mut [u8]) -> Result { 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 UsbClass for MidiClass<'_, B> { fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> { - //AUDIO CONTROL STANDARD - writer.interface( self.standard_ac, USB_AUDIO_CLASS, @@ -79,64 +98,80 @@ impl UsbClass for MidiClass<'_, B> { 0, //no protocol )?; //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, &[ MS_HEADER_SUBTYPE, 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 + 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( - CS_INTERFACE, - &[ - MIDI_IN_JACK_SUBTYPE, - EMBEDDED, - 0x01, // id - 0x00 - ] - )?; + for i in 0..self.n_out_jacks { + writer.write ( // len = 9 = MIDI_OUT_SIZE + CS_INTERFACE, + &[ + MIDI_OUT_JACK_SUBTYPE, + EMBEDDED, + self.out_jack_id(i), //id + 0x01, // 1 pin + self.in_jack_id(i), // pin 1 + 0x01, //sorta vague source pin? + 0x00 + ] + )?; + } - writer.write ( - CS_INTERFACE, - &[ - MIDI_OUT_JACK_SUBTYPE, - EMBEDDED, - 0x01,//id - 0x01, // 1 pin - 0x01, // pin 1 - 0x01, //sorta vague source pin? - 0x00 - ] - )?; + let mut endpoint_data = [ + MS_GENERAL, + 0, // number of jacks. must be filled in! + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 // jack mappings. must be filled in and cropped. + ]; - 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, - &[ - MS_GENERAL, - 0x01, - 0x01 - ] + &endpoint_data[0..2+self.n_in_jacks as usize] )?; - writer.endpoint(&self.standard_bulkin)?; - - writer.write( + writer.endpoint(&self.standard_bulkin)?; // len = 7 + endpoint_data[1] = self.n_out_jacks; + 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, - &[ - MS_GENERAL, - 0x01, - 0x01 - ] + &endpoint_data[0..2+self.n_out_jacks as usize] )?; + + let midi_streaming_end_byte = writer.position(); + assert!(midi_streaming_end_byte - midi_streaming_start_byte == midi_streaming_total_length); + Ok(()) } -} \ No newline at end of file +}