Skip to content

Commit bda1f2c

Browse files
committed
initial commit, TX only supported
0 parents  commit bda1f2c

File tree

6 files changed

+485
-0
lines changed

6 files changed

+485
-0
lines changed

README.adoc

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
= MIDIUSB Library for Arduino =
2+
3+
This library allows an Arduino board with USB capabilites to act as a MIDI instrument over USB.
4+
5+
For more information about this library please visit us at
6+
http://www.arduino.cc/en/Reference/MIDIUSB
7+
8+
== License ==
9+
10+
Copyright (c) 2015, Arduino LLC. All right reserved.
11+
Copyright (c) 2015, Gary Grewal
12+
13+
This library is free software; you can redistribute it and/or
14+
modify it under the terms of the GNU Lesser General Public
15+
License as published by the Free Software Foundation; either
16+
version 2.1 of the License, or (at your option) any later version.
17+
18+
This library is distributed in the hope that it will be useful,
19+
but WITHOUT ANY WARRANTY; without even the implied warranty of
20+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21+
Lesser General Public License for more details.
22+
23+
You should have received a copy of the GNU Lesser General Public
24+
License along with this library; if not, write to the Free Software
25+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* MIDIUSB_test.ino
3+
*
4+
* Created: 4/6/2015 10:47:08 AM
5+
* Author: gurbrinder grewal
6+
* Modified by Arduino LLC (2015)
7+
*/
8+
9+
#include "MIDIUSB.h"
10+
11+
// First parameter is the event type (0x09 = note on, 0x08 = note off).
12+
// Second parameter is note-on/note-off, combined with the channel.
13+
// Channel can be anything between 0-15. Typically reported to the user as 1-16.
14+
// Third parameter is the note number (48 = middle C).
15+
// Fourth parameter is the velocity (64 = normal, 127 = fastest).
16+
17+
void noteOn(byte channel, byte pitch, byte velocity) {
18+
midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity};
19+
MidiUSB.sendMIDI(noteOn);
20+
}
21+
22+
void noteOff(byte channel, byte pitch, byte velocity) {
23+
midiEventPacket_t noteOff = {0x08, 0x80 | channel, pitch, velocity};
24+
MidiUSB.sendMIDI(noteOff);
25+
}
26+
27+
void setup() {
28+
29+
}
30+
31+
// First parameter is the event type (0x0B = control change).
32+
// Second parameter is the event type, combined with the channel.
33+
// Third parameter is the control number number (0-119).
34+
// Fourth parameter is the control value (0-127).
35+
36+
void controlChange(byte channel, byte control, byte value) {
37+
midiEventPacket_t event = {0x0B, 0xB0 | channel, control, value};
38+
MidiUSB.sendMIDI(event);
39+
}
40+
41+
void loop() {
42+
Serial.println("Sending note on");
43+
noteOn(0, 48, 64); // Channel 0, middle C, normal velocity
44+
MidiUSB.flush();
45+
delay(500);
46+
Serial.println("Sending note off");
47+
noteOff(0, 48, 64); // Channel 0, middle C, normal velocity
48+
MidiUSB.flush();
49+
delay(1500);
50+
51+
// controlChange(0, 10, 65); // Set the value of controller 10 on channel 0 to 65
52+
}

keywords.txt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#######################################
2+
# Syntax Coloring Map For Keyboard
3+
#######################################
4+
5+
#######################################
6+
# Datatypes (KEYWORD1)
7+
#######################################
8+
9+
MidiUSB KEYWORD1
10+
11+
#######################################
12+
# Methods and Functions (KEYWORD2)
13+
#######################################
14+
15+
begin KEYWORD2
16+
available KEYWORD2
17+
accept KEYWORD2
18+
read KEYWORD2
19+
flush KEYWORD2
20+
sendMIDI KEYWORD2
21+
write KEYWORD2
22+
23+
#######################################
24+
# Constants (LITERAL1)
25+
#######################################
26+

library.properties

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
name=MIDIUSB
2+
version=1.0.0
3+
author=Gary Grewal, Arduino
4+
maintainer=Arduino <[email protected]>
5+
sentence=Allows an Arduino board with USB capabilites to act as a MIDI instrument over USB. For Leonardo/Micro only
6+
paragraph=
7+
category=USB
8+
url=http://www.arduino.cc/en/Reference/MIDIUSB
9+
architectures=*

src/MIDIUSB.cpp

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

0 commit comments

Comments
 (0)