A library to send and receive MIDI messages over USB using the default USB-MIDI drivers on Win/Mac

Dependents:   USBMIDI_HelloWorld USBMIDI_DrumExample USBMIDI_MonoSynth MIDI_Interface_ver_1 ... more

Files at this revision

API Documentation at this revision

Comitter:
simon
Date:
Sun Feb 20 13:10:05 2011 +0000
Parent:
0:56b095524cf2
Child:
2:10d694d6ccdc
Commit message:
First version, supporting most USB MIDI functionality

Changed in this revision

MIDIMessage.h Show annotated file Show diff for this revision Revisions of this file
USBMIDI.cpp Show annotated file Show diff for this revision Revisions of this file
USBMIDI.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show diff for this revision Revisions of this file
mbed.bld Show diff for this revision Revisions of this file
usbcore.c Show annotated file Show diff for this revision Revisions of this file
usbcore.h Show annotated file Show diff for this revision Revisions of this file
usbdevice.c Show annotated file Show diff for this revision Revisions of this file
--- a/MIDIMessage.h	Sun Feb 06 17:26:29 2011 +0000
+++ b/MIDIMessage.h	Sun Feb 20 13:10:05 2011 +0000
@@ -1,161 +1,254 @@
-/* MIDI Message Format
- * 
- * [ msg(4) | channel(4) ] [ 0 | n(7) ] [ 0 | m(7) ]
- *
- * MIDI Data Messages (Channel Specific)
+/** @license The MIT License
+ * Copyright (c) 2011 mux, simon
  *
- * Message               msg n    m
- * ---------------------------------------------
- * Note Off	             0x8 Key        Velocity
- * Note On	             0x9 Key        Velocity
- * Polyphonic Aftertouch 0xA Key        Pressure
- * Control Change        0xB Controller Value
- * Program Change        0xC Program    -
- * Channel Aftertouch    0xD Pressure   -
- * Pitch Wheel           0xE LSB        MSB
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *  
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *  
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
  */
 
-
 #ifndef MBED_MIDIMESSAGE_H
 #define MBED_MIDIMESSAGE_H
 
+#include "mbed.h"
+
+// MIDI Message Format
+// 
+// [ msg(4) | channel(4) ] [ 0 | n(7) ] [ 0 | m(7) ]
+//
+// MIDI Data Messages (Channel Specific)
+//
+// Message               msg n          m
+// ---------------------------------------------
+// Note Off              0x8 Key        Velocity
+// Note On               0x9 Key        Velocity
+// Polyphonic Aftertouch 0xA Key        Pressure
+// Control Change        0xB Controller Value
+// Program Change        0xC Program    -
+// Channel Aftertouch    0xD Pressure   -
+// Pitch Wheel           0xE LSB        MSB
+
+#define CABLE_NUM (0<<4)
+
+/** A MIDI message container */
 class MIDIMessage {
 public:
-	
-	// create messages
-	
-	static MIDIMessage NoteOff(int key, int velocity = 127, int channel = 0) {
-		MIDIMessage msg;
-		msg.data[0] = 0x80 | (channel & 0x0F);
-		msg.data[1] = key & 0x7F;
-		msg.data[2] = velocity & 0x7F; 
-		return msg;
-	}
-	
-	static MIDIMessage NoteOn(int key, int velocity = 127, int channel = 0) {
-		MIDIMessage msg;
-		msg.data[0] = 0x90 | (channel & 0x0F);
-		msg.data[1] = key & 0x7F;
-		msg.data[2] = velocity & 0x7F; 				
-		return msg;
-	}
-	
-	static MIDIMessage PolyphonicAftertouch(int key, int pressure, int channel = 0) {
-		MIDIMessage msg;
-		msg.data[0] = 0xA0 | (channel & 0x0F);
-		msg.data[1] = key & 0x7F;
-		msg.data[2] = pressure & 0x7F; 		
-		return msg;
-	}
-	
-	static MIDIMessage ControlChange(int control, int value, int channel = 0) {
-		MIDIMessage msg;
-		msg.data[0] = 0xB0 | (channel & 0x0F);
-		msg.data[1] = control & 0x7F;
-		msg.data[2] = value & 0x7F; 		
-		return msg;
-	}
-	
-	static MIDIMessage ProgramChange(int program, int channel = 0) {
-		MIDIMessage msg;
-		msg.data[0] = 0xC0 | (channel & 0x0F);
-		msg.data[1] = program & 0x7F;
-		msg.data[2] = 0x00; 		
-		return msg;
-	}
-	
-	static MIDIMessage ChannelAftertouch(int pressure, int channel = 0) {
-		MIDIMessage msg;
-		msg.data[0] = 0xD0 | (channel & 0x0F);
-		msg.data[1] = pressure & 0x7F;
-		msg.data[2] = 0x00; 		
-		return msg;
-	}
-	
-	static MIDIMessage PitchWheel(int pitch = 0, int channel = 0) {
-		MIDIMessage msg;
-		int p = pitch + 8192;	// 0 - 16383, 8192 is center
-		msg.data[0] = 0xE0 | (channel & 0x0F);
-		msg.data[1] = p & 0x7F;
-		msg.data[2] = (p >> 7) & 0x7F; 				
-		return msg;
-	}
-	
-	static MIDIMessage AllNotesOff(int channel = 0) {
-		return ControlChange(123, 0, channel);
-	}
-	
-	// decode messages
-	enum MIDIMessageType {
-		ErrorType,
-		NoteOffType,
-		NoteOnType,
-		PolyphonicAftertouchType,
-		ControlChangeType,
-		ProgramChangeType,
-		ChannelAftertouchType,
-		PitchWheelType,
-		AllNotesOffType
-	};
-	
-	MIDIMessageType type() {
-		switch((data[0] >> 4) & 0xF) {
-			case 0x8: return NoteOffType;
-			case 0x9: return NoteOnType;
-			case 0xA: return PolyphonicAftertouchType;
-			case 0xB: 
-				if(controller() < 120) { // standard controllers
-					return ControlChangeType;
-				} else if(controller() == 123) {
-					return AllNotesOffType;
-				} else {
-					return ErrorType; // unsupported atm
-				}
-			case 0xC: return ProgramChangeType;
-			case 0xD: return ChannelAftertouchType;
-			case 0xE: return PitchWheelType;
-			default: return ErrorType;
-		}
-	}
-	
-	int channel() {
-		return (data[0] & 0x0F);
-	}
-	
-	int key() {
-		return (data[1] & 0x7F);		
-	}
-	
-	int velocity() {
-		return (data[2] & 0x7F);		
-	}
+    MIDIMessage() {}
+    
+    MIDIMessage(uint8_t *buf) {
+        *((uint32_t *)data) = *((uint32_t *)buf);
+    }
+    
+    // create messages
+    
+    /** Create a NoteOff message 
+     * @param key Key ID
+     * @param velocity Key velocity (0-127, default = 127)
+     * @param channel Key channel (0-15, default 0)
+     * @returns A MIDIMessage
+     */
+    static MIDIMessage NoteOff(int key, int velocity = 127, int channel = 0) {
+        MIDIMessage msg;
+        msg.data[0] = CABLE_NUM | 0x08;
+        msg.data[1] = 0x80 | (channel & 0x0F);
+        msg.data[2] = key & 0x7F;
+        msg.data[3] = velocity & 0x7F; 
+        return msg;
+    }
+    
+    /** Create a NoteOn message 
+     * @param key Key ID
+     * @param velocity Key velocity (0-127, default = 127)
+     * @param channel Key channel (0-15, default 0)
+     * @returns A MIDIMessage
+     */
+    static MIDIMessage NoteOn(int key, int velocity = 127, int channel = 0) {
+        MIDIMessage msg;
+        msg.data[0] = CABLE_NUM | 0x09;
+        msg.data[1] = 0x90 | (channel & 0x0F);
+        msg.data[2] = key & 0x7F;
+        msg.data[3] = velocity & 0x7F;                 
+        return msg;
+    }
+    
+    /** Create a PolyPhonic Aftertouch message 
+     * @param key Key ID
+     * @param pressure Aftertouch pressure (0-127)
+     * @param channel Key channel (0-15, default 0)
+     * @returns A MIDIMessage
+     */    
+    static MIDIMessage PolyphonicAftertouch(int key, int pressure, int channel = 0) {
+        MIDIMessage msg;
+        msg.data[0] = CABLE_NUM | 0x0A;
+        msg.data[1] = 0xA0 | (channel & 0x0F);
+        msg.data[2] = key & 0x7F;
+        msg.data[3] = pressure & 0x7F;         
+        return msg;
+    }
+    
+    /** Create a Control Change message 
+     * @param control Controller ID
+     * @param value Controller value (0-127)
+     * @param channel Controller channel (0-15, default 0)
+     * @returns A MIDIMessage
+     */
+    static MIDIMessage ControlChange(int control, int value, int channel = 0) {
+        MIDIMessage msg;
+        msg.data[0] = CABLE_NUM | 0x0B;
+        msg.data[1] = 0xB0 | (channel & 0x0F);
+        msg.data[2] = control & 0x7F;
+        msg.data[3] = value & 0x7F;         
+        return msg;
+    }
+    
+    /** Create a Program Change message 
+     * @param program Program ID
+     * @param channel Channel (0-15, default 0)
+     * @returns A MIDIMessage
+     */    
+    static MIDIMessage ProgramChange(int program, int channel = 0) {
+        MIDIMessage msg;
+        msg.data[0] = CABLE_NUM | 0x0C;
+        msg.data[1] = 0xC0 | (channel & 0x0F);
+        msg.data[2] = program & 0x7F;
+        msg.data[3] = 0x00;         
+        return msg;
+    }
+    
+    /** Create a Channel Aftertouch message 
+     * @param pressure Pressure 
+     * @param channel Key channel (0-15, default 0)
+     * @returns A MIDIMessage
+     */    
+    static MIDIMessage ChannelAftertouch(int pressure, int channel = 0) {
+        MIDIMessage msg;
+        msg.data[0] = CABLE_NUM | 0x0D;
+        msg.data[1] = 0xD0 | (channel & 0x0F);
+        msg.data[2] = pressure & 0x7F;
+        msg.data[3] = 0x00;         
+        return msg;
+    }
+    
+    /** Create a Pitch Wheel message 
+     * @param pitch Pitch (-8192 - 8191, default = 0)
+     * @param channel Channel (0-15, default 0)
+     * @returns A MIDIMessage
+     */    
+    static MIDIMessage PitchWheel(int pitch = 0, int channel = 0) {
+        MIDIMessage msg;
+        int p = pitch + 8192;    // 0 - 16383, 8192 is center
+        msg.data[0] = CABLE_NUM | 0x0E;
+        msg.data[1] = 0xE0 | (channel & 0x0F);
+        msg.data[2] = p & 0x7F;
+        msg.data[3] = (p >> 7) & 0x7F;                 
+        return msg;
+    }
+    
+    /** Create an All Notes Off message 
+     * @param channel Channel (0-15, default 0)
+     * @returns A MIDIMessage
+     */    
+    static MIDIMessage AllNotesOff(int channel = 0) {
+        return ControlChange(123, 0, channel);
+    }
+    
+    // decode messages
+    
+    /** MIDI Message Types */
+    enum MIDIMessageType {
+        ErrorType,
+        NoteOffType,
+        NoteOnType,
+        PolyphonicAftertouchType,
+        ControlChangeType,
+        ProgramChangeType,
+        ChannelAftertouchType,
+        PitchWheelType,
+        AllNotesOffType
+    };
+    
+    /** Read the message type
+     * @returns MIDIMessageType
+     */    
+    MIDIMessageType type() {
+        switch((data[1] >> 4) & 0xF) {
+            case 0x8: return NoteOffType;
+            case 0x9: return NoteOnType;
+            case 0xA: return PolyphonicAftertouchType;
+            case 0xB: 
+                if(controller() < 120) { // standard controllers
+                    return ControlChangeType;
+                } else if(controller() == 123) {
+                    return AllNotesOffType;
+                } else {
+                    return ErrorType; // unsupported atm
+                }
+            case 0xC: return ProgramChangeType;
+            case 0xD: return ChannelAftertouchType;
+            case 0xE: return PitchWheelType;
+            default: return ErrorType;
+        }
+    }
 
-	int value() {
-		return (data[2] & 0x7F);		
-	}
-	
-	int pressure() {
-		if(type() == PolyphonicAftertouchType) {
-			return (data[2] & 0x7F);		
-		} else {
-			return (data[1] & 0x7F);		
-		}
-	}
+    /** Read the channel number */    
+    int channel() {
+        return (data[1] & 0x0F);
+    }
+    
+    /** Read the key ID */    
+    int key() {
+        return (data[2] & 0x7F);        
+    }
+        
+    /** Read the velocity */    
+    int velocity() {
+        return (data[3] & 0x7F);        
+    }
 
-	int controller() {
-		return (data[1] & 0x7F);		
-	}
+    /** Read the controller value */    
+    int value() {
+        return (data[3] & 0x7F);        
+    }
+    
+    /** Read the aftertouch pressure */        
+    int pressure() {
+        if(type() == PolyphonicAftertouchType) {
+            return (data[3] & 0x7F);        
+        } else {
+            return (data[2] & 0x7F);        
+        }
+    }
 
-	int program() {
-		return (data[1] & 0x7F);		
-	}
-	
-	int pitch() {
-		int p = ((data[2] & 0x7F) << 7) | (data[1] & 0x7F);
-		return p - 8192; // 0 - 16383, 8192 is center
-	}
-	
-	uint8_t data[3];
-};	
+    /** Read the controller number */    
+    int controller() {
+        return (data[2] & 0x7F);        
+    }
+
+    /** Read the program number */    
+    int program() {
+        return (data[2] & 0x7F);        
+    }
+    
+    /** Read the pitch value */        
+    int pitch() {
+        int p = ((data[3] & 0x7F) << 7) | (data[2] & 0x7F);
+        return p - 8192; // 0 - 16383, 8192 is center
+    }
+    
+    uint8_t data[4];
+};    
 
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBMIDI.cpp	Sun Feb 20 13:10:05 2011 +0000
@@ -0,0 +1,60 @@
+/** @license The MIT License
+ * Copyright (c) 2011 mux, simon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *  
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *  
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "USBMIDI.h"
+
+#include "mbed.h"
+#include "usbcore.h"
+
+static void (*midi_evt)(MIDIMessage) = NULL;
+
+USBMIDI::USBMIDI() {
+    usb_init();
+    usb_connect();
+    while (!usb_configured());  
+}
+
+void USBMIDI::write(MIDIMessage m) {
+    while (!writeable());
+    ep_write(EP5, m.data, 4);
+}
+
+bool USBMIDI::writeable() {
+    return (bool)ep_writable(EP5);
+}
+
+void USBMIDI::attach(void (*fptr)(MIDIMessage)) {
+    midi_evt = fptr;
+}
+
+void ep2_in() {}
+
+void ep2_out() {    
+    uint8_t buf[MAX_EPn_PSIZE];
+    int len = ep_read(EP4, buf);
+    
+    if (midi_evt != NULL) {
+        for(int i=0; i<len; i+=4){
+            midi_evt(MIDIMessage(buf+i));
+        }
+    }
+}
--- a/USBMIDI.h	Sun Feb 06 17:26:29 2011 +0000
+++ b/USBMIDI.h	Sun Feb 20 13:10:05 2011 +0000
@@ -1,26 +1,50 @@
+/** @license The MIT License
+ * Copyright (c) 2011 mux, simon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *  
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *  
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
 #ifndef MBED_USBMIDI_H
 #define MBED_USBMIDI_H
 
 #include "MIDIMessage.h"
 
+/** USBMIDI interface class for sending and receiving MIDI messages over USB */ 
 class USBMIDI {
 public:
-	USBMIDI() {}
-	~USBMIDI() {}
-		
-	// write messages
-	void write(MIDIMessage m) {}
-	int writeable() { return 0; }
-		
-	// read messages
-	MIDIMessage read() { return MIDIMessage::NoteOn(0); }
-	int readable() { return 0; }
-		
-	// notification of incoming message
-	void attach(void (*fptr)(void)) {}
-	
-	template <class T>
-	void attach(T *tptr, void (T::*mptr)(void)) {}
+
+    /** Create the USBMIDI interface */
+    USBMIDI();
+    
+    /** Send a MIDIMessage
+     * @param m The MIDIMessage to send
+     */    
+    void write(MIDIMessage m);
+        
+    /** Check if it possible to send a MIDIMessage
+     * @returns True if there's an empty buffer for sending a MIDIMessage, otherwise False
+     */                
+    bool writeable();
+
+    /** Attach a callback for when a MIDIEvent is received */
+    void attach(void (*fptr)(MIDIMessage));
+    
 }; 
 
 #endif
--- a/main.cpp	Sun Feb 06 17:26:29 2011 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-#include "mbed.h"
-#include "USBMIDI.h"
-
-USBMIDI midi;
-
-int main() {
-    // send some notes
-	for(int i=0; i<127; i++) {
-		midi.write(MIDIMessage::NoteOn(i));
-		wait(0.25);
-		midi.write(MIDIMessage::NoteOff(i));
-		wait(0.5);
-	}
-
-    // recieve notes
-	while(1) {
-		if(midi.readable()) {
-			MIDIMessage msg = midi.read();
-			switch(msg.type()) {
-				case MIDIMessage::NoteOnType:
-				    printf("NoteOn key:%d, velocity: %d, channel: %d\n", msg.key(), msg.velocity(), msg.channel());
-				    break;
-				case MIDIMessage::NoteOffType:
-				    printf("NoteOff key:%d, velocity: %d, channel: %d\n", msg.key(), msg.velocity(), msg.channel());
-				    break;
-				case MIDIMessage::ControlChangeType:	
-				    printf("ControlChange controller: %d, data: %d\n", msg.controller(), msg.value());
-				    break;
-				case MIDIMessage::PitchWheelType:
-				    printf("PitchWheel channel: %d, pitch: %d\n", msg.channel(), msg.pitch());
-				    break;
-				default:
-				    printf("Another message\n");
-				
-			}
-		}
-	}
-}
--- a/mbed.bld	Sun Feb 06 17:26:29 2011 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-http://mbed.org/users/mbed_official/code/mbed/builds/9a9732ce53a1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usbcore.c	Sun Feb 20 13:10:05 2011 +0000
@@ -0,0 +1,278 @@
+/** @license The MIT License
+ * Copyright (c) 2011 mux, simon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *  
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *  
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "usbcore.h"
+
+#include "mbed.h"
+
+// Serial Interface Engine
+#define SIE_SET_ADDR    (0xD0)
+#define SIE_SET_STATUS  (0xFE)
+#define SIE_GET_STATUS  (0xFE)
+#define SIE_SET_MODE    (0xF3)
+#define SIE_CLR_BUFFER  (0xF2)
+#define SIE_VAL_BUFFER  (0xFA)
+#define SIE_SEL_EP      (0x00)
+#define SIE_SEL_CLR_EP  (0x28)
+#define SIE_SET_EP_STAT (0x40)
+#define SIE_READ_ERROR  (0xFB)
+#define SIE_CONFIG_DEVICE (0xD8)
+
+// EP status
+#define EP_FE           (1<<0) // Full/Empty
+#define EP_ST           (1<<1) // Stalled endpoint
+#define EP_STP          (1<<2) // Setup packet
+#define EP_PO           (1<<3) // packet overwritten
+#define EP_EPN          (1<<4) // EP NAKed
+#define B_1_FULL        (1<<5) // buffer 1 status
+#define B_2_FULL        (1<<6) // buffer 2 status
+
+// USB device interrupts
+#define DEV_FRAME       (1<<0)
+#define EP_FAST         (1<<1)
+#define EP_SLOW         (1<<2)
+#define DEV_STAT        (1<<3)
+#define RxENDPKT        (1<<6)
+#define TxENDPKT        (1<<7)
+#define EP_RLZED        (1<<8)
+#define CCEMPTY         (0x10)
+#define CDFULL          (0x20)
+
+// USB device status bits
+#define STAT_CON        (1<<0)
+#define STAT_CON_CH     (1<<1)
+#define STAT_SUS        (1<<2)
+#define STAT_SUS_CH     (1<<3)
+#define STAT_RST        (1<<4)
+
+// end points interrupts
+#define EP0RX_INT       (1<<0)
+#define EP0TX_INT       (1<<1)
+#define EP1RX_INT       (1<<2)
+#define EP1TX_INT       (1<<3)
+#define EP2RX_INT       (1<<4)
+#define EP2TX_INT       (1<<5)
+
+// USB control register
+#define RD_EN           (1<<0)
+#define WR_EN           (1<<1)
+#define PKT_RDY         (1<<11)
+#define LOG_ENDPOINT(ep) ((ep>>1)<<2)
+
+// configure state
+static int configured = 0;
+
+// USB interrupt handler
+void USB_IRQHandler(void);
+
+// Serial Interface Engine functions
+void sie_command(uint32_t code) {
+    LPC_USB->USBDevIntClr = CCEMPTY;                // clear CCEMPTY     
+    LPC_USB->USBCmdCode   = ((code<<16)|(0x05<<8)); // CMD_PHASE=Command 
+    while (!(LPC_USB->USBDevIntSt & CCEMPTY));      // wait for CCEMPTY 
+}
+
+void sie_write(uint32_t data) {
+    LPC_USB->USBDevIntClr = CCEMPTY;                // clear CCEMPTY     
+    LPC_USB->USBCmdCode   = ((data<<16)|(0x01<<8)); // CMD_PHASE=Write   
+    while (!(LPC_USB->USBDevIntSt & CCEMPTY));      // wait for CCEMPTY  
+}
+
+uint8_t sie_read(uint32_t code) {
+    LPC_USB->USBDevIntClr = CDFULL;                 // clear CCEMPTY     
+    LPC_USB->USBCmdCode   = ((code<<16)|(0x02<<8)); // CMD_PHASE=Read    
+    while (!(LPC_USB->USBDevIntSt & CDFULL));       // wait for CDFULL   
+    return (uint8_t) LPC_USB->USBCmdData;
+
+}
+
+// end point functions
+void ep_realize(uint8_t ep, uint32_t size) {
+    LPC_USB->USBDevIntClr = EP_RLZED;           // clear EP_RLZED
+    LPC_USB->USBReEp    |= (1<<ep);
+    LPC_USB->USBEpInd    = ep;                  // set USBEpIn
+    LPC_USB->USBMaxPSize = size;                // writing to EPn pointed to by USBEpInd
+    while (!(LPC_USB->USBDevIntSt & EP_RLZED)); // wait for EP_RLZED
+    LPC_USB->USBDevIntClr = EP_RLZED;           // clear EP_RLZED
+}
+
+void ep_stall(uint8_t ep) {
+    sie_command(SIE_SET_EP_STAT+ep);
+    sie_write(1);
+}
+
+void ep_unstall(uint8_t ep) {
+    sie_command(SIE_SET_EP_STAT+ep);
+    sie_write(0);
+}
+
+// initializes a pointer to the endpoint buffer
+uint8_t ep_select(uint8_t ep) {
+    sie_command(SIE_SEL_EP+ep);
+    return sie_read(SIE_SEL_EP+ep);
+}
+
+uint8_t ep_select_clear(uint8_t ep) {
+    LPC_USB->USBEpIntClr |= ep;                 // clear ep interrupt   
+    while (!(LPC_USB->USBDevIntSt & CDFULL));   // wait for cmd finish 
+    return LPC_USB->USBCmdData;
+}
+
+int ep_readable(uint8_t ep) {
+    uint8_t st = ep_select(ep);
+    return (st & EP_FE);
+}
+
+int ep_writable(uint8_t ep) {
+    uint8_t st = ep_select(ep);
+    return !(st & EP_FE);
+}
+
+int ep_read(uint8_t ep, uint8_t *tbuf) {
+    uint32_t *buf = (uint32_t*) tbuf;
+    LPC_USB->USBCtrl = LOG_ENDPOINT(ep)|RD_EN;  // RD_EN bit and LOG_ENDPOINT   
+    while (!(LPC_USB->USBRxPLen & PKT_RDY));    // wait for packet to be fetched
+    int len = LPC_USB->USBRxPLen & 0x3FF;       // read and mask packet length  
+    while (!(LPC_USB->USBDevIntSt & RxENDPKT)) {
+        *buf++ = LPC_USB->USBRxData;
+    }
+    LPC_USB->USBCtrl = 0;
+    LPC_USB->USBDevIntClr |= RxENDPKT;
+    sie_command(SIE_SEL_EP+ep);     // select endpoint   
+    sie_command(SIE_CLR_BUFFER);    // clear RX buffer   
+    return len;
+}
+
+void ep_write(uint8_t ep, uint8_t *tbuf, uint32_t len) {
+    uint32_t *buf = (uint32_t*) tbuf;
+    LPC_USB->USBCtrl   = LOG_ENDPOINT(ep)|WR_EN; // RD_EN bit and LOG_ENDPOINT  
+    LPC_USB->USBTxPLen |= (len & 0x3FF);         // write and mask packet length
+    while (!(LPC_USB->USBDevIntSt & TxENDPKT)) {
+        LPC_USB->USBTxData = *buf++;
+    }
+    LPC_USB->USBCtrl = 0;
+    LPC_USB->USBDevIntClr |= TxENDPKT;
+    sie_command(SIE_SEL_EP+ep);     // select endpoint   
+    sie_command(SIE_VAL_BUFFER);    // validate TX buffer
+}
+
+// USB device controller initialization
+void usb_init() {
+    // USB D+/D- pinsel functions
+    LPC_PINCON->PINSEL1 &=   0xC3FFFFFF;
+    LPC_PINCON->PINSEL1 |=   0x14000000;
+
+#if USB_UP_DEBUG
+    // USB_UP_LED pinsel function
+    LPC_PINCON->PINSEL3 &=   0xFFFFFFCF;
+    LPC_PINCON->PINSEL3 |=   0x00000010;
+#endif    
+
+    // USB connect pinsel function
+    LPC_PINCON->PINSEL4 &=   0xFFFCFFFF;
+    LPC_PINCON->PINSEL4 |=   0x00040000;
+    LPC_SC->PCONP       |=   (1UL<<31);         // enable the USB controller
+    LPC_USB->USBClkCtrl |=   ((1<<1)|(1<<4));   // enable the AHB and DEV clocks
+    while ((LPC_USB->USBClkSt & 0x12) != 0x12); // wait for the clocks to init
+
+    NVIC_SetVector(USB_IRQn, (uint32_t)&USB_IRQHandler);
+    NVIC_EnableIRQ(USB_IRQn);    // enable USB interrupts
+
+    usb_reset();
+    usb_set_address(0);          // default address
+}
+
+void usb_reset() {
+    ep_realize(EP0, MAX_EP0_PSIZE);
+    ep_realize(EP1, MAX_EP0_PSIZE);
+    LPC_USB->USBEpIntClr  = 0xFFFFFFFF;         // clear end points interrupts
+    LPC_USB->USBEpIntEn   = 0xFFFFFFFF;         // enable end points interrupts
+    LPC_USB->USBEpIntPri  = 0x0;                // route to EP_SLOW
+    LPC_USB->USBDevIntClr = 0xFFFFFFFF;         // clear USB device interrupts 
+    LPC_USB->USBDevIntEn  = (EP_SLOW|DEV_STAT); // enable USB device interrupts
+}
+
+void usb_configure(uint8_t conf) {
+    sie_command(SIE_CONFIG_DEVICE);
+    sie_write(conf);
+    configured = 1;
+}
+
+int usb_configured() {
+    return configured;
+}
+
+void usb_set_address(uint8_t addr) {
+    sie_command(SIE_SET_ADDR);
+    sie_write(addr|0x80);       // DEV_EN = 1
+}
+
+uint8_t usb_get_status() {
+    sie_command(SIE_GET_STATUS);
+    return sie_read(SIE_GET_STATUS);
+}
+
+void usb_connect() {
+    sie_command(SIE_GET_STATUS); // read current status
+    uint8_t st = sie_read(SIE_GET_STATUS);
+
+    sie_command(SIE_SET_STATUS); // set STAT_CON bit
+    sie_write(st|STAT_CON);
+}
+
+void USB_IRQHandler(void) {
+    if (LPC_USB->USBDevIntSt & DEV_STAT) { // DEV_STAT interrupt
+        LPC_USB->USBDevIntClr |= DEV_STAT;
+        if (usb_get_status() & STAT_RST) { // bus reset
+            usb_reset();
+        }
+        return;
+    }
+
+    if (LPC_USB->USBDevIntSt & EP_SLOW) {  // EP_SLOW interrupt
+        if (LPC_USB->USBEpIntSt & EP0RX_INT) {
+            if (ep_select_clear(EP0RX_INT) & EP_STP) { // setup transfer
+                ep0_setup();
+            } else {
+                ep0_out();
+            }
+        }
+
+        if (LPC_USB->USBEpIntSt & EP0TX_INT) {
+            ep_select_clear(EP0TX_INT);
+            ep0_in();
+        }
+
+        if (LPC_USB->USBEpIntSt & EP2RX_INT) {
+            ep_select_clear(EP2TX_INT);
+            ep2_out();
+        }
+
+        if (LPC_USB->USBEpIntSt & EP2TX_INT) {
+            ep_select_clear(EP2TX_INT);
+            ep2_in();
+        }
+
+        // EP_SLOW should be cleared after clearing EPs interrupts
+        LPC_USB->USBDevIntClr |= EP_SLOW;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usbcore.h	Sun Feb 20 13:10:05 2011 +0000
@@ -0,0 +1,56 @@
+/** @license The MIT License
+ * Copyright (c) 2011 mux, simon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *  
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *  
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef USB_CORE_H
+#define USB_CORE_H
+
+#include "mbed.h"
+
+#define MAX_EP0_PSIZE   (8)
+#define MAX_EPn_PSIZE   (64)
+
+// physical endpoint numbers
+#define EP0             (0)
+#define EP1             (1)
+#define EP2             (2)
+#define EP3             (3)
+#define EP4             (4)
+#define EP5             (5)
+
+void usb_init();
+void usb_reset();
+void usb_connect();
+void usb_set_address(uint8_t);
+void usb_configure(uint8_t);
+int usb_configured();
+void ep_realize(uint8_t ep, uint32_t psize);
+int  ep_read(uint8_t ep, uint8_t *buf);
+void ep_write(uint8_t ep, uint8_t *buf, uint32_t len);
+int ep_readable(uint8_t ep);
+int ep_writable(uint8_t ep);
+void ep0_setup();
+void ep0_in();
+void ep0_out();
+void ep2_in();
+void ep2_out();
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usbdevice.c	Sun Feb 20 13:10:05 2011 +0000
@@ -0,0 +1,181 @@
+/** @license The MIT License
+ * Copyright (c) 2011 mux, simon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *  
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *  
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "usbcore.h"
+#include "mbed.h"
+
+#define STANDARD_DEVICE_REQUEST     (0x00)
+#define STANDARD_INTERFACE_REQUEST  (0x01)
+#define STANDARD_ENDPOINT_REQUEST   (0x02)
+#define CLASS_DEVICE_REQUEST        (0x20)
+#define CLASS_INTERFACE_REQUEST     (0x21)
+#define CLASS_ENDPOINT_REQUEST      (0x22)
+#define VENDOR_DEVICE_REQUEST       (0x40)
+#define VENDOR_INTERFACE_REQUEST    (0x41)
+#define VENDOR_ENDPOINT_REQUEST     (0x42)
+#define GET_STATUS                  (0x00)
+#define CLEAR_FEATURE               (0x01)
+#define SET_FEATURE                 (0x03)
+#define SET_ADDRESS                 (0x05)
+#define GET_DESCRIPTOR              (0x06)
+#define SET_DESCRIPTOR              (0x07)
+#define GET_CONFIGURATION           (0x08)
+#define SET_CONFIGURATION           (0x09)
+#define DEVICE_DESCRIPTOR           (0x01)
+#define CONFIG_DESCRIPTOR           (0x02)
+#define STRING_DESCRIPTOR           (0x03)
+#define INTERFACE_DESCRIPTOR        (0x04)
+#define ENDPOINT_DESCRIPTOR         (0x05)
+#define QUALIFIER_DESCRIPTOR        (0x06)
+#define unpack(x) (x & 0xFF),((x >> 8) & 0xFF)
+
+// setup packet
+struct {
+    uint8_t   bmRequestType;
+    uint8_t   bRequest;
+    uint16_t  wValue;
+    uint16_t  wIndex;
+    uint16_t  wLength;
+} __attribute__((packed)) setup = {0};
+
+// data packet
+struct { 
+    uint8_t *data;
+    uint8_t size;
+    uint8_t sent;
+} transfer = {0};
+
+uint8_t device_descriptor[] = {
+    0x12,                       // Descriptor size in bytes (12h)                  
+    DEVICE_DESCRIPTOR,          // The constant DEVICE (01h)                       
+    unpack(0x0200),             // US2B specification release number (BCD)         
+    0x00,                       // Class code                                      
+    0x00,                       // Subclass code                                   
+    0x00,                       // Protocol Code                                   
+    MAX_EP0_PSIZE,              // Maximum packet size for endpoint zero           
+    unpack(0x0763),             // Vendor ID                                       
+    unpack(0x0198),             // Product ID                                      
+    unpack(0x0001),             // Device release number (BCD)                     
+    0x00,                       // Index of string descriptor for the manufacturer 
+    0x00,                       // Index of string descriptor for the product      
+    0x00,                       // Index of string descriptor for the serial number
+    0x01,                       // Number of possible configurations               
+};
+
+uint8_t config_descriptor[]={
+    0x09, 0x02, 0x65, 0x00, 0x02, 0x01, 0x00, 0xc0, 0x50, // configuration descriptor
+    // The Audio Interface Collection
+    0x09, 0x04, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, // Standard AC Interface Descriptor
+    0x09, 0x24, 0x01, 0x00, 0x01, 0x09, 0x00, 0x01, 0x01, // Class-specific AC Interface Descriptor
+    0x09, 0x04, 0x01, 0x00, 0x02, 0x01, 0x03, 0x00, 0x00, // MIDIStreaming Interface Descriptors
+    0x07, 0x24, 0x01, 0x00, 0x01, 0x41, 0x00,             // Class-Specific MS Interface Header Descriptor
+
+    // MIDI IN JACKS
+    0x06, 0x24, 0x02, 0x01, 0x01, 0x00,
+    0x06, 0x24, 0x02, 0x02, 0x02, 0x00,
+
+    // MIDI OUT JACKS
+    0x09, 0x24, 0x03, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00,
+    0x09, 0x24, 0x03, 0x02, 0x06, 0x01, 0x01, 0x01, 0x00,
+
+    // OUT endpoint descriptor
+    0x09, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
+    0x05, 0x25, 0x01, 0x01, 0x01,
+
+    // IN endpoint descriptor
+    0x09, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
+    0x05, 0x25, 0x01, 0x01, 0x03,
+};
+
+void ep0_in();
+
+void data_in_stage(uint8_t *desc, uint8_t length) {
+    transfer.sent = 0;
+    transfer.data = desc;
+    transfer.size = length;
+    ep0_in();
+}
+
+void status_in_stage() {
+    ep_write(EP1, 0, 0); // ZLEP for status stage
+}
+
+void ep0_setup() {
+    ep_read(EP0,(uint8_t*) &setup);
+
+    switch (setup.bmRequestType & 0x7f) { // mask direction
+        case STANDARD_DEVICE_REQUEST:
+            switch (setup.bRequest) {
+                case GET_DESCRIPTOR:
+                    switch ((setup.wValue>>8)) {
+                        case DEVICE_DESCRIPTOR:     // device descriptor request
+                        case QUALIFIER_DESCRIPTOR:  // device qualifier descriptor
+                            data_in_stage(device_descriptor, sizeof(device_descriptor));
+                            break;
+                        case CONFIG_DESCRIPTOR:     // configuration descriptor
+                            data_in_stage(config_descriptor, setup.wLength);
+                            break;
+                        case STRING_DESCRIPTOR:
+                            break;
+                        default:
+                            break;
+                    }
+                    break;
+                case SET_ADDRESS:
+                    usb_set_address((uint8_t) (setup.wValue & 0xFF));
+                    status_in_stage();
+                    break;
+                case SET_CONFIGURATION:
+                    if (!setup.wValue) {
+                        break;
+                    }
+                    ep_realize(EP4, MAX_EPn_PSIZE);
+                    ep_realize(EP5, MAX_EPn_PSIZE);
+                    status_in_stage();
+                    usb_configure(1);
+                    break;
+                default:
+                    break;
+            }
+            break;
+        default:
+            break;
+    }
+}
+
+void ep0_in() {
+    if ((setup.bmRequestType & 0x80) && transfer.size) { // device to host
+        if (transfer.size > MAX_EP0_PSIZE) {
+            transfer.sent = MAX_EP0_PSIZE;
+        } else {
+            transfer.sent = transfer.size;
+        }
+        ep_write(EP1, transfer.data, transfer.sent);
+        transfer.data += transfer.sent;
+        transfer.size -= transfer.sent;
+    }
+}
+
+void ep0_out() {
+    uint8_t buf[64];
+    ep_read(EP0, buf);
+}