Code and Life

Programming, electronics and other cool tech stuff

Supported by

Supported by Picotech

MIDI to USB Adapter with Teensy LC

Among my recent electronics purchase spree was the amazing Teensy LC from PJRC. It has a nice ARM Cortex-M0+ processor, real hardware USB, and what’s the nicest part, an Arduino add-on called Teensyduino which enables easy programming with Arduino, but with support for many of the hardware features.

Now I started playing piano a while ago, and just a few weeks ago bought a Pianoteq license to send notes via MIDI to my computer, and render high quality piano sound to speakers. However, it turns out my $8 USB-MIDI adapter from DealExtreme had a less than perfect implementation, essentially changing pedal events into “note on” events!

Thankfully, I had a MIDI connector and a high-speed optocoupler at hand, and with these I could implement a MIDI in rather easily. After some investigation with Arduino Uno, it seemed quite simple to receive the serial MIDI bytes and dump them over Arduino serial (I’ll write another post about this later).

However, Arduino cannot become a USB MIDI device very easily, so here comes the really nice part: Teensy LC can, and the Teensyduino add-on included a working USB MIDI and also serial MIDI libraries!

The Hardware

The Wikipedia page for MIDI essentially shows the required circuitry for receiving MIDI data – wire the DIN cable pins 4 and 5 through the receiving side of optocoupler and put a 200 ohm resistor in series with it. A diode is also suggested for reverse current (ESD) protection, but I skipped that. You can start with a LED instead of optocoupler to see it lights up if you’re unsure you have pins 4 and 5 the right way. Or just put the LED (with a resistor) on the other side of the optocoupler first.

The HCPL-2531 I had at hand requires an additional VCC connection on the sending side. After some experimentation, a 4k7 ohm pullup resistor between VCC and VO1 (NPN-transistor base?) gave the cleanest signal out. The wiring diagram (thanks Diptrace!) is shown below:

Teensy LC MIDI schematic

As you can see, only a Teensy LC, the optocoupler, two resistors (220 ohm for the MIDI side, 4k7 for the Teensy side transistor load resistor) and some wire is needed. Talk about simple! Below you can see a pictorial representation of the above diagram:

Teensy LC MIDI circuit

So essentially the circuit has (HCPL 2531 part on the left for reference):

HCPL 2531 pinout

  • Teensy LC “G” and “3V” pins wired to GND and VCC rails of the breadboard
  • Optocoupler pin 8 (VCC) to VCC rail
  • Optocoupler pin 7 (VO1) to VCC via 4k7 ohm resistor
  • Optocoupler pin 7 (VO1) also wired to Teensy LC pin “0” (serial RX)
  • Optocoupler pin 5 (GND) to GND rail
  • Optocoupler pin 1 (ANODE1) to PIN4 (I think) of the MIDI DIN connector
  • Optocoupler pin 2 (CATHODE1) to PIN5 (I think) of the MIDI DIN connector via 220 ohm resistor
  • USB cable to computer

That’s really it! Depending on the exact type and model of the optocoupler, the wiring may be a bit different, but not much. If you have a different model and are not sure how the pins work, I suggest first making some tests with LED’s on both sides and a multimeter (or oscilloscope preferably) to see how the signal is transmitting over the optocoupler.

The Code

Now comes the easy part. Just plug the Teensy into computer, run Arduino (with the Teensyduino add-on installed), change Teensy USB type to “MIDI” (see Teensyduino USB MIDI for examples which you can run first), and program the following sketch:


/* MIDI to USB adapter - for use with Teensy or boards where Serial is separate from MIDI
 * As MIDI messages arrive, they are sent as USB midi messages. Only transmits note on, 
 * off and pedal (control change) events.
 *
 * Note that this does not work on a regular Arduino boards (no separate USB and UART)!
 *
 * Based on Francois Best midi library example:
 * http://arduinomidilib.fortyseveneffects.com/
 * This example code is released into the public domain.
 */
 
#include <MIDI.h>

void myNoteOn(byte channel, byte note, byte velocity) {
  usbMIDI.sendNoteOn(note, velocity, channel);
}

void myNoteOff(byte channel, byte note, byte velocity) {
  usbMIDI.sendNoteOff(note, velocity, channel);
}

void myControlChange(byte channel, byte number, byte value) {
  usbMIDI.sendControlChange(number, value, channel);
}

void setup() {
  MIDI.setHandleNoteOn(myNoteOn);
  MIDI.setHandleNoteOff(myNoteOff);
  MIDI.setHandleControlChange(myControlChange);
  MIDI.begin(MIDI_CHANNEL_OMNI);
}

void loop() {
  MIDI.read();
}

That’s really it! With this sketch, I can just plug my MIDI keyboard into the DIN connector via cable, and plug the Teensy into my MacBook, and both my playing and pedal action get nicely transmitted to the computer. Not bad for $20 worth of components and some 20 lines of code!

Spoilers ahead! A similar MIDI to USB adapter can be implemented with Arduino and some additional software on computer side (serial to MIDI bridge). And as of today, I have also managed to achieve native USB MIDI with ATmega328p and V-USB library, which means you could reprogram any small Arduino-compatible device (including Pro Trinket from Adafruit). Stay tuned for additional posts detailing these hacks. :)

8 comments

Karg:

Well done! I like your writing style :)
Yes pin 4 and 5 on the DIN are correct. A tip to secure your circuit and to comply to the MIDI standard, just add a small diode between your optocouplers pin 1 and 2. In case polarity is swapped (i.e. DIN pin 4 and 5), the diode protects the optocoupler.

I did it very similarly, but with an 6N137, and with clock support and several filtering options: http://karg-music.blogspot.de/p/multi-duty-midi-aid.html

Joonas Pihlajamaa:

Thanks for great comment and your kind words! I know about the diode, actually mentioned about it in hardware section, I suspected the optocoupler diode could handle a few volts of reverse current (most diodes do), but electrostatic discharge could exceed that so the diode definitely would be useful. Despite that, I thought better careless and lucky. :)

Realizing my “lying around” optocoupler is actually $6 high-end one, I’ve ordered a bunch of inexpensive ones including 6N137 and 6N138. I’m going to see which work well, and probaly stock up on those for future projects, in case I fry one…

Your project looked nice. Maybe you should add a schematic PNG and a picture of the hardware to your page, I don’t have Eagle installed and usually give up when there’s no easy-to-view schematic on a project page. Your MDMA thing looks like it deserver further investigation!

Akos:

Great Project!
I am planning a USB-MIDI interface, but instead of UART-MIDI input, I want to convert my old keyboard with scanning all the keys.
Can you estimate / measure how heavy is the CPU load with your code when you play fast notes? I have no idea how well the Teensy-LC handles the USB traffic, if it is struggling with it I’d rather develop my interface for the faster Teensy 3.2.

Thanks!

Joonas Pihlajamaa:

Hmm, if you have PS/2 keyboard (or use a PS/2 “adapter”, I have a theory that most USB keyboards recognize the adapter being used and fall back to PS/2 over USB wires), I think it should be quite straightforward to receive PS/2 data with Teensy.

Teensy has native USB and PS/2 scanning should not overburden the processor at all, I think the main delay will be how fast your keyboard sends PS/2 data, the delay caused by Teensy processor will be in order of microseconds at most.

Akos:

Hello!
I did not mean PC keyboard. I want to scan old E-piano keyboards (all the keys directly, or in 8×8 matrices), in fact more, with a single teensy, and use them as MIDI keyboards :)
What I do not know is how heavy the task would be for a Teensy LC.
(USB MIDI messaging + scanning 256 inputs with a target latency of 2-3ms)
Sorry for my unclear definition.

Joonas Pihlajamaa:

I think you could think it this way: Was 2-3 ms delay possible in the 80s electronics? The Teensy LC ARM processor is about 40x faster than state-of-the art embedded processors back then, so my gut instinct is that as long as USB MIDI latency stays at 1-2 ms, the 1 ms should easily be achievable with right kind of architecture.

256 inputs is quite a lot, but if you take 48 MHz processor, you have about 48 000 cycles to spare in a millisecond. If we assume overhead takes a half, you still have 24 000 cycles, i.e. 100 cycles per input. Teensy doesn’t have 256 pins, but something like 8×8 matrix with relatively fast transistors should be a piece of cake.

Hoang Nguyen:

Hi Joonas, I’m looking for an DIY midi to usb interface like that, as the chinese interface i bought with $5 send note on message on pedal, also with incorrect note on off signal :(. Unfortunately, I have very very very little knowledge about schematic and coding, i can buy and solder thing myself with an instruction (much like tutorial) from you, please tell me how to do it, as the Roland Um one at $40 is so expensive to afford. My email is hoangcosmic@gmail.com, thank you very much

Joonas Pihlajamaa:

Hi Hoang,

This article is basically a tutorial to do just that, you should be able to follow the connection instructions and sample image I gave. If it is too advanced, I unfortunately cannot offer any additional help. You can get the Teensy LC for $12,90 and rest of the components cost a few dollars.

HOWEVER, if you are not interested in building this to learn electronics and google around on how to program the Teensy LC (it’s not hard but requires some learning if you’re not familiar with Arduinos for example), I would STRONGLY suggest you just try to source a less expensive, but working MIDI adapter. I have this one:

https://www.thomann.de/fi/miditech_midiface_ii_thru.htm (29€)

There are two with high ratings and similar price point to Teensy LC, I would assume they work with pedal:

https://www.thomann.de/fi/miditech_midilinkmini.htm (15€, it’s the same brand as mine so I’d be surprised if it doesn’t work)
https://www.thomann.de/fi/thomann_midi_usb_1x1.htm (15€, looks very much like the unworking one I bought from DX.com that had the same issue as you, but has good reviews so who knows?)

Really cheap option would be to use a $4 atmega32u4 devboard, but it’s still a 5 hour project, I would value my free time over the $2 hourly salary and just save to get a ready-made adapter, unless I had all components readily in hand and the desire to do it just to tinker around.