Skip to content

Commit 4cb88ec

Browse files
committed
Create Midi.cpp
1 parent f155601 commit 4cb88ec

File tree

1 file changed

+183
-0
lines changed
  • hardware/arduino/sam/cores/arduino/USB

1 file changed

+183
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
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 "Arduino.h"
17+
#include "USBAPI.h"
18+
#include "Reset.h"
19+
20+
#ifdef MIDI_ENABLED
21+
22+
#define MIDI_BUFFER_SIZE 128
23+
24+
struct ring_bufferMIDI
25+
{
26+
midiEventPacket_t midiEvent[MIDI_BUFFER_SIZE];
27+
volatile uint32_t head;
28+
volatile uint32_t tail;
29+
};
30+
31+
ring_bufferMIDI midi_rx_buffer = {{0,0,0,0 }, 0, 0};
32+
33+
_Pragma("pack(1)")
34+
static const MIDIDescriptor _midiInterface =
35+
{
36+
#ifdef CDC_ENABLED
37+
D_IAD(MIDI_AC_INTERFACE,MIDI_INTERFACE_COUNT, MIDI_AUDIO, MIDI_AUDIO_CONTROL, 0),
38+
#endif
39+
D_INTERFACE(MIDI_AC_INTERFACE,0,MIDI_AUDIO,MIDI_AUDIO_CONTROL,0),
40+
D_AC_INTERFACE(0x1, MIDI_INTERFACE),
41+
D_INTERFACE(MIDI_INTERFACE,2, MIDI_AUDIO,MIDI_STREAMING,0),
42+
D_AS_INTERFACE,
43+
D_MIDI_INJACK(MIDI_JACK_EMD, 0x1),
44+
D_MIDI_INJACK(MIDI_JACK_EXT, 0x2),
45+
D_MIDI_OUTJACK(MIDI_JACK_EMD, 0x3, 1, 2, 1),
46+
D_MIDI_OUTJACK(MIDI_JACK_EXT, 0x4, 1, 1, 1),
47+
D_MIDI_JACK_EP(USB_ENDPOINT_OUT(MIDI_ENDPOINT_OUT),USB_ENDPOINT_TYPE_BULK,0x0040),
48+
D_MIDI_AC_JACK_EP(1, 1),
49+
D_MIDI_JACK_EP(USB_ENDPOINT_IN(MIDI_ENDPOINT_IN),USB_ENDPOINT_TYPE_BULK,0x0040),
50+
D_MIDI_AC_JACK_EP (1, 3)
51+
};
52+
_Pragma("pack()")
53+
54+
int WEAK MIDI_GetInterface(uint8_t* interfaceNum)
55+
{
56+
interfaceNum[0] += 2; // uses 2
57+
return USBD_SendControl(0,&_midiInterface,sizeof(_midiInterface));
58+
}
59+
bool WEAK MIDI_Setup(Setup& setup)
60+
{
61+
//Support requests here if needed. Typically these are optional
62+
return false;
63+
}
64+
65+
void MIDI_::begin()
66+
{
67+
//Nothing to do
68+
}
69+
70+
void MIDI_::accept(void)
71+
{
72+
static uint32_t mguard = 0;
73+
74+
// synchronized access to guard
75+
do {
76+
if (__LDREXW(&mguard) != 0) {
77+
__CLREX();
78+
return; // busy
79+
}
80+
} while (__STREXW(1, &mguard) != 0); // retry until write succeed
81+
82+
ring_bufferMIDI *buffer = &midi_rx_buffer;
83+
uint32_t i = (uint32_t)(buffer->head+1) % MIDI_BUFFER_SIZE;
84+
85+
// if we should be storing the received character into the location
86+
// just before the tail (meaning that the head would advance to the
87+
// current location of the tail), we're about to overflow the buffer
88+
// and so we don't write the character or advance the head.
89+
while (i != buffer->tail) {
90+
int c;
91+
midiEventPacket_t event;
92+
if (!USBD_Available(MIDI_RX)) {
93+
udd_ack_fifocon(MIDI_RX);
94+
break;
95+
}
96+
c = USBD_Recv(MIDI_RX, &event, sizeof(event) );
97+
98+
//MIDI paacket has to be 4 bytes
99+
if(c < 4)
100+
return;
101+
buffer->midiEvent[buffer->head] = event;
102+
buffer->head = i;
103+
104+
i = (i + 1) % MIDI_BUFFER_SIZE;
105+
}
106+
107+
// release the guard
108+
mguard = 0;
109+
}
110+
111+
uint32_t MIDI_::available(void)
112+
{
113+
114+
ring_bufferMIDI *buffer = &midi_rx_buffer;
115+
return (uint32_t)(MIDI_BUFFER_SIZE + buffer->head - buffer->tail) % MIDI_BUFFER_SIZE;
116+
}
117+
118+
119+
midiEventPacket_t MIDI_::read(void)
120+
{
121+
ring_bufferMIDI *buffer = &midi_rx_buffer;
122+
midiEventPacket_t c = buffer->midiEvent[buffer->tail];
123+
c.header = 0;
124+
c.byte1 = 0;
125+
c.byte2 = 0;
126+
c.byte3 = 0;
127+
128+
// if the head isn't ahead of the tail, we don't have any characters
129+
if (buffer->head == buffer->tail)
130+
{
131+
return c;
132+
}
133+
else
134+
{
135+
midiEventPacket_t c = buffer->midiEvent[buffer->tail];
136+
buffer->tail = (uint32_t)(buffer->tail + 1) % MIDI_BUFFER_SIZE;
137+
if (USBD_Available(MIDI_RX))
138+
accept();
139+
return c;
140+
}
141+
}
142+
143+
void MIDI_::flush(void)
144+
{
145+
USBD_Flush(MIDI_TX);
146+
}
147+
148+
size_t MIDI_::write(const uint8_t *buffer, size_t size)
149+
{
150+
/* only try to send bytes if the high-level MIDI connection itself
151+
is open (not just the pipe) - the OS should set lineState when the port
152+
is opened and clear lineState when the port is closed.
153+
bytes sent before the user opens the connection or after
154+
the connection is closed are lost - just like with a UART. */
155+
156+
// TODO - ZE - check behavior on different OSes and test what happens if an
157+
// open connection isn't broken cleanly (cable is yanked out, host dies
158+
// or locks up, or host virtual serial port hangs)
159+
160+
int r = USBD_Send(MIDI_TX, buffer, size);
161+
162+
if (r > 0)
163+
{
164+
return r;
165+
} else
166+
{
167+
return 0;
168+
}
169+
return 0;
170+
}
171+
172+
void MIDI_::sendMIDI(midiEventPacket_t event)
173+
{
174+
uint8_t data[4];
175+
data[0] = event.header;
176+
data[1] = event.byte1;
177+
data[2] = event.byte2;
178+
data[3] = event.byte3;
179+
write(data, 4);
180+
}
181+
182+
MIDI_ MidiUSB;
183+
#endif

0 commit comments

Comments
 (0)