CircuitPython USB to Serial MIDI Router

I’ve indirectly used USB and Serial MIDI with CircuitPython a few times now, but haven’t explicitly shown how to use it as a simple USB (device) to serial MIDI converter.  This project shows how to do that.  Any CircuitPython device should be usable like this, but I’ve used this as an excuse to do something with the Seeedstudio Seeeduino XIAO board.

IMG_6117

Warning! I strongly recommend using old or second hand equipment for your experiments.  I am not responsible for any damage to expensive instruments!

These are the key tutorials for the main concepts used in this project:

If you are new to microcontrollers, see the Getting Started pages.

Parts list

The Circuit

If you are using a Raspberry Pi then the circuit is one I’ve used several times already.  Connect up your 3V3 compatible MIDI module to GND, 3V3, RX and TX.

If you are using a Trinket M0 then there is a really good learning guide on the Adafruit site that will get you going – again you’ll need the same GND, 3V3, RX and TX pins.

In my case, I wanted an excuse to do something with a Seeedstudio Seeeduino XIAO module.  This is a SAMD21G based module with a USB-C connector, and would need to be connected up as follows.

XIAO MIDI_bb

The general idea is that the CircuitPython device will connect to a PC (or other USB host) as a USB MIDI device and forward any MIDI traffic between the USB MIDI link and a connected serial MIDI module.

The Code

The basic idea is relatively straightforward once your device is up and running with Circuitpython itself (see the Adafruit guides for help to get this far!):

Set up the USB MIDI device
Set up the serial MIDI device

while:
    IF there is a USB MIDI IN message THEN
        Send it out on the serial MIDI OUT port
    IF there is a serial MIDI IN message THEN
        Send it out on the USB MIDI OUT port

The only slight quirk is that I try to filter out unrecognised MIDI messages to limit the forwarded traffic, but if you haven’t imported the adafruit_midi representation of a MIDI message, then the code will not recognise it!  So I need to pull in the various MIDI message representations at the start of the file.

Not being a python person myself really, I may well be missing something and there might be a more elegant way to do this, but I have to say I’m not really a fan of how MIDI is implemented in CircuitPython as it feels too hidden away behind “clever layers” for my liking.  But having said that, there really is no easier way (at present) for making a USB MIDI device than CircuitPython.

The code also supports flashing an LED on reception of a MIDI event.  For the XIAO this looks like the following:

led = digitalio.DigitalInOut(board.D13)
led.direction = digitalio.Direction.OUTPUT
led.value = True

def ledOn():
    led.value = False

def ledOff():
    led.value = True

With the XIAO the LED is on when led.value = False.  For the Raspberry Pi Pico, it would be different again, something like the following (untested, but pasted in from my other code):

led = digitalio.DigitalInOut(board.GP25)
led.direction = digitalio.Direction.OUTPUT

def ledOn():
    led.value = True

def ledOff():
    led.value = False

Some boards support the Python/CircuitPython “built in LED” identifier – you might be able to get away with using board.LED above, but the True/False logic still needs setting up correctly for your board.  Some boards are now using board.LED_INVERTED too, so just see what works.

One way to see what is supported is to do the following in the REPL shell when connected to the board:

>>> import board
>>> dir (board)

Also, whilst the XIAO and other boards have board.TX and board.RX defined for the default serial port, the Raspberry Pi Pico does not, so the code to initialise the serial MIDI will also have to be changed to look more like the following for the Pico (this is to use UART 0 on GP0 and GP1).

uart = busio.UART(tx=board.GP0, rx=board.GP1, baudrate=31250, timeout=0.001)

The original was:

uart = busio.UART(tx=board.TX, rx=board.RX, baudrate=31250, timeout=0.001)

Find the XIAO version on GitHub here.

Closing Thoughts

As always, I continue my love/hate relationship with CircuitPython (and Python more generally), but I can’t deny, this is still probably the easiest way to get a USB MIDI device to serial MIDI converter up and running!

Now USB MIDI Host… well that is another story…

Kevin

2 thoughts on “CircuitPython USB to Serial MIDI Router

  1. Hmm, interesting. Gotta say, I got so discouraged by the disastrous Adafruit MIDI dox, my big organ-pedal/MIDI-merger project is on hold till I regain my composure.

    > this is still probably the easiest way to get a USB MIDI device to serial MIDI converter up and running!

    Oh? Is there a problem doing it in Arduino? Even if I get a Python version working, I may have to port it to Arduino for speed… Or just raw C. Sigh.

    >

    Like

    1. > Oh? Is there a problem doing it in Arduino?

      Not in the slightest! See: https://diyelectromusic.wordpress.com/2022/03/22/arduino-and-usb-midi/ 🙂

      But getting USB on an Arduino isn’t particularly easy for those starting out in this area, especially the whole “press reset until the right mode happens” thing with the Pro Micro! But if CP is doing what one needs it to, it can be a lot easier “out of the box” as it were. But I too prefer to do things in C for pretty much all circumstances rather than adding software layers.

      Kevin

      Like

Leave a reply to nslcwatch Cancel reply