Skip to content

Commit b8d29ba

Browse files
committed
add stub MIDIUSB library
only a proof of concept for PluggableUSB module
1 parent a260377 commit b8d29ba

File tree

2 files changed

+370
-0
lines changed

2 files changed

+370
-0
lines changed

Diff for: libraries/MIDIUSB/MIDIUSB.cpp

+215
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
// Copyright (c) 2015, Gary Grewal
2+
/*
3+
** Permission to use, copy, modify, and/or distribute this software for
4+
** any purpose with or without fee is hereby granted, provided that the
5+
** above copyright notice and this permission notice appear in all copies.
6+
**
7+
** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
8+
** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
9+
** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
10+
** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
11+
** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
12+
** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
13+
** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
14+
** SOFTWARE.
15+
*/
16+
#include "PluggableUSB.h"
17+
#include "MIDIUSB.h"
18+
19+
#define MIDI_BUFFER_SIZE 128
20+
21+
22+
static u8 MIDI_AC_INTERFACE; // MIDI AC Interface
23+
static u8 MIDI_INTERFACE;
24+
static u8 MIDI_FIRST_ENDPOINT;
25+
static u8 MIDI_ENDPOINT_OUT;
26+
static u8 MIDI_ENDPOINT_IN;
27+
28+
#define MIDI_RX MIDI_ENDPOINT_OUT
29+
#define MIDI_TX MIDI_ENDPOINT_IN
30+
31+
struct ring_bufferMIDI
32+
{
33+
midiEventPacket_t midiEvent[MIDI_BUFFER_SIZE];
34+
volatile uint32_t head;
35+
volatile uint32_t tail;
36+
};
37+
38+
ring_bufferMIDI midi_rx_buffer = {{0,0,0,0 }, 0, 0};
39+
40+
static MIDIDescriptor _midiInterface;
41+
42+
void WEAK setupUSB() {
43+
MidiUSB.begin();
44+
}
45+
46+
int8_t WEAK MIDI_GetInterface(uint8_t* interfaceNum)
47+
{
48+
interfaceNum[0] += 2; // uses 2
49+
return USB_SendControl(0,&_midiInterface,sizeof(_midiInterface));
50+
}
51+
bool WEAK MIDI_Setup(Setup& setup, u8 i)
52+
{
53+
//Support requests here if needed. Typically these are optional
54+
return false;
55+
}
56+
57+
int8_t WEAK MIDI_GetDescriptor(int8_t t)
58+
{
59+
return 0;
60+
}
61+
62+
void MIDI_::accept(void)
63+
{
64+
// static uint32_t mguard = 0;
65+
66+
// // synchronized access to guard
67+
// do {
68+
// if (__LDREXW(&mguard) != 0) {
69+
// __CLREX();
70+
// return; // busy
71+
// }
72+
// } while (__STREXW(1, &mguard) != 0); // retry until write succeed
73+
74+
// ring_bufferMIDI *buffer = &midi_rx_buffer;
75+
// uint32_t i = (uint32_t)(buffer->head+1) % MIDI_BUFFER_SIZE;
76+
77+
// // if we should be storing the received character into the location
78+
// // just before the tail (meaning that the head would advance to the
79+
// // current location of the tail), we're about to overflow the buffer
80+
// // and so we don't write the character or advance the head.
81+
// while (i != buffer->tail) {
82+
// int c;
83+
// midiEventPacket_t event;
84+
// if (!USB_Available(MIDI_RX)) {
85+
// udd_ack_fifocon(MIDI_RX);
86+
// break;
87+
// }
88+
// c = USB_Recv(MIDI_RX, &event, sizeof(event) );
89+
90+
// //MIDI paacket has to be 4 bytes
91+
// if(c < 4)
92+
// return;
93+
// buffer->midiEvent[buffer->head] = event;
94+
// buffer->head = i;
95+
96+
// i = (i + 1) % MIDI_BUFFER_SIZE;
97+
// }
98+
99+
// // release the guard
100+
// mguard = 0;
101+
}
102+
103+
uint32_t MIDI_::available(void)
104+
{
105+
106+
ring_bufferMIDI *buffer = &midi_rx_buffer;
107+
return (uint32_t)(MIDI_BUFFER_SIZE + buffer->head - buffer->tail) % MIDI_BUFFER_SIZE;
108+
}
109+
110+
111+
midiEventPacket_t MIDI_::read(void)
112+
{
113+
ring_bufferMIDI *buffer = &midi_rx_buffer;
114+
midiEventPacket_t c = buffer->midiEvent[buffer->tail];
115+
c.header = 0;
116+
c.byte1 = 0;
117+
c.byte2 = 0;
118+
c.byte3 = 0;
119+
120+
// if the head isn't ahead of the tail, we don't have any characters
121+
if (buffer->head == buffer->tail)
122+
{
123+
return c;
124+
}
125+
else
126+
{
127+
midiEventPacket_t c = buffer->midiEvent[buffer->tail];
128+
buffer->tail = (uint32_t)(buffer->tail + 1) % MIDI_BUFFER_SIZE;
129+
if (USB_Available(MIDI_RX))
130+
accept();
131+
return c;
132+
}
133+
}
134+
135+
void MIDI_::flush(void)
136+
{
137+
USB_Flush(MIDI_TX);
138+
}
139+
140+
size_t MIDI_::write(const uint8_t *buffer, size_t size)
141+
{
142+
/* only try to send bytes if the high-level MIDI connection itself
143+
is open (not just the pipe) - the OS should set lineState when the port
144+
is opened and clear lineState when the port is closed.
145+
bytes sent before the user opens the connection or after
146+
the connection is closed are lost - just like with a UART. */
147+
148+
// TODO - ZE - check behavior on different OSes and test what happens if an
149+
// open connection isn't broken cleanly (cable is yanked out, host dies
150+
// or locks up, or host virtual serial port hangs)
151+
152+
int r = USB_Send(MIDI_TX, buffer, size);
153+
154+
if (r > 0)
155+
{
156+
return r;
157+
} else
158+
{
159+
return 0;
160+
}
161+
return 0;
162+
}
163+
164+
void MIDI_::sendMIDI(midiEventPacket_t event)
165+
{
166+
uint8_t data[4];
167+
data[0] = event.header;
168+
data[1] = event.byte1;
169+
data[2] = event.byte2;
170+
data[3] = event.byte3;
171+
write(data, 4);
172+
}
173+
174+
int8_t MIDI_plug(void)
175+
{
176+
PUSBCallbacks cb;
177+
178+
cb.setup = &MIDI_Setup;
179+
cb.getInterface = &MIDI_GetInterface;
180+
cb.getDescriptor = &MIDI_GetDescriptor;
181+
cb.numEndpoints = 2;
182+
cb.endpointType[0] = EP_TYPE_BULK_OUT_MIDI; // MIDI_ENDPOINT_OUT
183+
cb.endpointType[1] = EP_TYPE_BULK_IN_MIDI; // MIDI_ENDPOINT_IN
184+
185+
MIDI_ENDPOINT_OUT = PUSB_AddFunction(&cb, &MIDI_AC_INTERFACE);
186+
MIDI_ENDPOINT_IN = MIDI_ENDPOINT_OUT + 1;
187+
MIDI_INTERFACE = MIDI_AC_INTERFACE + 1;
188+
189+
_midiInterface =
190+
{
191+
D_IAD(MIDI_AC_INTERFACE, 2, MIDI_AUDIO, MIDI_AUDIO_CONTROL, 0),
192+
D_INTERFACE(MIDI_AC_INTERFACE,0,MIDI_AUDIO,MIDI_AUDIO_CONTROL,0),
193+
D_AC_INTERFACE(0x1, MIDI_INTERFACE),
194+
D_INTERFACE(MIDI_INTERFACE,2, MIDI_AUDIO,MIDI_STREAMING,0),
195+
D_AS_INTERFACE,
196+
D_MIDI_INJACK(MIDI_JACK_EMD, 0x1),
197+
D_MIDI_INJACK(MIDI_JACK_EXT, 0x2),
198+
D_MIDI_OUTJACK(MIDI_JACK_EMD, 0x3, 1, 2, 1),
199+
D_MIDI_OUTJACK(MIDI_JACK_EXT, 0x4, 1, 1, 1),
200+
D_MIDI_JACK_EP(USB_ENDPOINT_OUT(MIDI_ENDPOINT_OUT),USB_ENDPOINT_TYPE_BULK,512),
201+
D_MIDI_AC_JACK_EP(1, 1),
202+
D_MIDI_JACK_EP(USB_ENDPOINT_IN(MIDI_ENDPOINT_IN),USB_ENDPOINT_TYPE_BULK,512),
203+
D_MIDI_AC_JACK_EP (1, 3)
204+
};
205+
206+
return MIDI_ENDPOINT_IN;
207+
}
208+
209+
int8_t MIDI_::begin()
210+
{
211+
return MIDI_plug();
212+
}
213+
214+
215+
MIDI_ MidiUSB;

Diff for: libraries/MIDIUSB/MIDIUSB.h

+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
//================================================================================
2+
//================================================================================
3+
// MIDI USB class
4+
5+
#ifndef MIDIUSB_h
6+
#define MIDIUSB_h
7+
8+
#include <stdint.h>
9+
#include <Arduino.h>
10+
11+
#if defined(USBCON)
12+
13+
typedef struct
14+
{
15+
uint8_t header;
16+
uint8_t byte1;
17+
uint8_t byte2;
18+
uint8_t byte3;
19+
}midiEventPacket_t;
20+
21+
#define EP_TYPE_BULK_OUT_MIDI EP_TYPE_BULK_OUT
22+
#define EP_TYPE_BULK_IN_MIDI EP_TYPE_BULK_IN
23+
24+
class MIDI_
25+
{
26+
// private:
27+
// RingBuffer *_midi_rx_buffer;
28+
public:
29+
int8_t begin();
30+
31+
virtual uint32_t available(void);
32+
virtual void accept(void);
33+
virtual midiEventPacket_t read(void);
34+
virtual void flush(void);
35+
virtual void sendMIDI(midiEventPacket_t event);
36+
virtual size_t write(const uint8_t *buffer, size_t size);
37+
operator bool();
38+
};
39+
extern MIDI_ MidiUSB;
40+
41+
#define MIDI_AUDIO 0x01
42+
#define MIDI_AUDIO_CONTROL 0x01
43+
#define MIDI_CS_INTERFACE 0x24
44+
#define MIDI_CS_ENDPOINT 0x25
45+
#define MIDI_STREAMING 0x3
46+
#define MIDI_JACK_EMD 0x01
47+
#define MIDI_JACK_EXT 0X02
48+
49+
typedef struct
50+
{
51+
uint8_t len; // 9
52+
uint8_t dtype; // 4
53+
uint8_t dsubType;
54+
uint16_t bcdADc;
55+
uint16_t wTotalLength;
56+
uint8_t bInCollection;
57+
uint8_t interfaceNumbers;
58+
} MIDI_ACInterfaceDescriptor;
59+
60+
typedef struct
61+
{
62+
uint8_t len; // 9
63+
uint8_t dtype; // 4
64+
uint8_t dsubType;
65+
uint8_t jackType;
66+
uint8_t jackID;
67+
uint8_t jackStrIndex;
68+
} MIDIJackinDescriptor;
69+
70+
typedef struct
71+
{
72+
uint8_t len; // 9
73+
uint8_t dtype; // 4
74+
uint8_t dsubType;
75+
uint8_t jackType;
76+
uint8_t jackID;
77+
uint8_t nPins;
78+
uint8_t srcJackID;
79+
uint8_t srcPinID;
80+
uint8_t jackStrIndex;
81+
} MIDIJackOutDescriptor;
82+
83+
typedef struct
84+
{
85+
EndpointDescriptor len; // 9
86+
uint8_t refresh; // 4
87+
uint8_t sync;
88+
} MIDI_EPDescriptor;
89+
90+
typedef struct
91+
{
92+
uint8_t len; // 5
93+
uint8_t dtype; // 0x24
94+
uint8_t subtype;
95+
uint8_t embJacks;
96+
uint8_t jackID;
97+
} MIDI_EP_ACDescriptor;
98+
99+
typedef struct
100+
{
101+
uint8_t len; // 9
102+
uint8_t dtype; // 4
103+
uint8_t dsubType;
104+
uint16_t bcdADc;
105+
uint16_t wTotalLength;
106+
} MIDI_ASInterfaceDescriptor;
107+
108+
typedef struct
109+
{
110+
// IAD
111+
IADDescriptor iad;
112+
// MIDI Audio Control Interface
113+
InterfaceDescriptor Audio_ControlInterface;
114+
MIDI_ACInterfaceDescriptor Audio_ControlInterface_SPC;
115+
116+
// MIDI Audio Streaming Interface
117+
InterfaceDescriptor Audio_StreamInterface;
118+
MIDI_ASInterfaceDescriptor Audio_StreamInterface_SPC;
119+
120+
MIDIJackinDescriptor MIDI_In_Jack_Emb;
121+
MIDIJackinDescriptor MIDI_In_Jack_Ext;
122+
MIDIJackOutDescriptor MIDI_Out_Jack_Emb;
123+
MIDIJackOutDescriptor MIDI_Out_Jack_Ext;
124+
125+
MIDI_EPDescriptor MIDI_In_Jack_Endpoint;
126+
MIDI_EP_ACDescriptor MIDI_In_Jack_Endpoint_SPC;
127+
MIDI_EPDescriptor MIDI_Out_Jack_Endpoint;
128+
MIDI_EP_ACDescriptor MIDI_Out_Jack_Endpoint_SPC;
129+
} MIDIDescriptor;
130+
131+
#define D_AC_INTERFACE(_streamingInterfaces, _MIDIInterface) \
132+
{ 9, MIDI_CS_INTERFACE, 0x1, 0x0100, 0x0009, _streamingInterfaces, _MIDIInterface }
133+
134+
#define D_AS_INTERFACE \
135+
{ 0x7, MIDI_CS_INTERFACE, 0x01,0x0100, 0x0041}
136+
137+
#define D_MIDI_INJACK(jackProp, _jackID) \
138+
{ 0x06, MIDI_CS_INTERFACE, 0x02, jackProp, _jackID, 0 }
139+
140+
#define D_MIDI_OUTJACK(jackProp, _jackID, _nPins, _srcID, _srcPin) \
141+
{ 0x09, MIDI_CS_INTERFACE, 0x3, jackProp, _jackID, _nPins, _srcID, _srcPin, 0 }
142+
143+
#define D_MIDI_JACK_EP(_addr,_attr,_packetSize) \
144+
{ 9, 5, _addr,_attr,_packetSize, 0, 0, 0}
145+
146+
#define D_MIDI_AC_JACK_EP(_nMIDI, _iDMIDI) \
147+
{ 5, MIDI_CS_ENDPOINT, 0x1, _nMIDI, _iDMIDI}
148+
149+
#define D_CDCCS(_subtype,_d0,_d1) { 5, 0x24, _subtype, _d0, _d1 }
150+
#define D_CDCCS4(_subtype,_d0) { 4, 0x24, _subtype, _d0 }
151+
152+
#define WEAK __attribute__ ((weak))
153+
154+
#endif
155+
#endif

0 commit comments

Comments
 (0)