Introduction
This guide will show how to take a freshly installed Raspberry Pi and have it operate as an OS-discoverable MIDI I/O device. It will also provide some examples of using various Python libraries to get MIDI data into and out of the programming environment.
UPDATE – Jun 9, 2022.: This guide has been updated to fix some issues with the latest Raspberry Pi OS version. Added new examples. Big thanks to Marting Woolley for his contribution.
UPDATE – Aug 14, 2022.: Added old guide link and some community projects using MIDI board.
What we need
- Raspberry Pi A+/B+/2/3B/3B+/4B
- MIDI Board for Raspberry Pi
- A MicroSD Card
- Set of 4 Nylon M2.5 Screws
- Set of 4 Nylon M2.5*11mm Female to Female Standoffs
- Set of 4 Nylon M2.5*5mm Male to Female Standoffs
Assembly
Use the nylon screws and standoffs to assembly the Raspberry Pi together with the MIDI Board, as shown on the image below: 
First time setup
We tested all the examples in this document on a Pi 4B using Rasperry Pi OS, version April 2022). The first time, it is necessary to use a screen and keyboard to set the Pi up. Thereafter, use your method of choice to access the Pi’s OS. All steps are mandatory unless otherwise stated.
Installation
Update/Upgrade
Perform the update and upgrade as described here: https://www.raspberrypi.com/documentation/computers/os
Python Examples
The examples use the serial library to make it easier for everybody to test the board functionality.
MIDI in over Serial (example_1_midi_in.py)
This example shows how to:
- Lists some types of MIDI messages received in hex such as note on/note off of the MIDI device connected.
import serial
ser = serial.Serial('/dev/ttyAMA0', baudrate=31250)
message = [0, 0, 0]
while True:
i = 0
while i < 3:
data = ord(ser.read(1)) # read a byte
if data >> 7 != 0:
i = 0 # status byte! this is the beginning of a midi message!
message[i] = data
i += 1
if i == 2 and message[0] >> 4 == 12: # program change: don't wait for a
message[2] = 0 # third byte: it has only 2 bytes
i = 3
messagetype = message[0] >> 4
messagechannel = (message[0] & 15) + 1
note = message[1] if len(message) > 1 else None
velocity = message[2] if len(message) > 2 else None
if messagetype == 9: # Note on
print('Note on : 0x' + ''.join('{:02x}'.format(x) for x in message) + ' note=' + str(note) + ' on channel ' + str(messagechannel))
elif messagetype == 8: # Note off
print('Note off: 0x' + ''.join('{:02x}'.format(x) for x in message) + ' note=' + str(note) + ' on channel ' + str(messagechannel))
elif messagetype == 12: # Program change
print 'Program change'
MIDI out over Serial (example_1_midi_out.py)
This example shows how to:
- Play note C3 over and over again on a connected MIDI device.
import serial
import time
ser = serial.Serial('/dev/ttyAMA0', baudrate=31250)
channel = 2 # this represents channel 3
note = 60
velocity = 100
note_off = 8
note_on = 9
msg_note_on = bytearray([(note_on << 4) | channel, 60, 72])
msg_note_off = bytearray([(note_off << 4) | channel, 60, 72])
while True:
print(str(hex(msg_note_on[0]))+' '+str(msg_note_on[1])+' '+str(msg_note_on[2]))
ser.write(msg_note_on)
time.sleep(1)
ser.write(msg_note_off)
time.sleep(1)
Community Projects
Check out some of the projects that community is sharing with all of us using the OSA MIDI Board or similar:
- Octopy: https://github.com/dcooperdalrymple/octopy
- Bulky MIDI 32: https://github.com/tebl/BulkyMIDI-32
Old guide
If somebody finds usefull the old guide that was posted, please check it out HERE.


I hope this is useful – I pulled together the steps I used (including the video above) to run TTYMIDI as a service so it is always available for sequencers, synthesizers, etc.
https://aidanblack.github.io/RPiMIDI.html
Hello All, i fought for many months to make it work and i have finally been able to use it ! You need to change the uart config and switch the Bluetooth uart to somewhere else ! Follow the tuto here !
Hi Oriol, I am trying to revisit this the last time I was not successful, can you confirm where is the latest guide? Or please email it to me. Thank you.
Hi Oriol,
I have been struggling to get the board working with my Pi2 running the latests (as of january 2023) version of the OS.
Most example I found on the internet are for Pi3, or are made for earlier version of the OS.
But I finally got it working perfectly, and I wanted to share what I did, it case it can help other users of the board.
So here is my “tutorial” to get MIDI working on a Raspberry Pi 2 Model B Rev 1.1 running Linux raspberrypi 5.15.84-v7+ and Python 3.9.2
by the way, here are the commands to know Pi model, OS an Python versions
cat /sys/firmware/devicetree/base/model
uname -a
python –version
So here is how I proceeded:
STEP 1:
Edit the config:
sudo nano /boot/config.txt
At the end of the file add
enable_uart=1
dtoverlay=midi-uart0
IMPORTANT NOTE: This will automatically switch the serial baud rate to 31250 when using 38400, so in the python script the baudrate MUST be set to 38400. Using 31250 will not work
NOTE FOR PI3 users: The bluetooth has to be moved to another serial port by adding this line:
dtoverlay=pi3-miniuart-bt
(I do not have a PI3 to test that, so there is no guarantee it will work)
STEP 2:
Edit the cmdline:
sudo nano /boot/cmdline.txt
Original file should be like this:
console=serial0,115200 console=tty1 root=PARTUUID=2867c77f-02 rootfstype=ext4 fsck.repair=yes rootwait quiet splash plymouth.ignore-seria-consoles
Remove the
console=serial0,115200
and
console=tty1
which are at the beginning of the commande line.
This will remove the consol text that will pollute the serial port input
Modified file should be like:
root=PARTUUID=2867c77f-02 rootfstype=ext4 fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles
STEP 3:
Reboot the pi
sudo reboot
STEP 4:
Create an example file:
nano midi.py
and paste the following code:
This is the example code you provided, modified to work with python 3 and the “correct” baudrate in our config.
It also shows velocity for notes on, and program number for program changes.
import serial
ser = serial.Serial(‘/dev/ttyAMA0’, baudrate=38400)
message = [0, 0, 0]
while True:
i = 0
while i > 7 != 0:
i = 0 # status byte! this is the beginning of a midi message!
message[i] = data
i += 1
if i == 2 and message[0] >> 4 == 12: # program change: don’t wait for a
message[2] = 0 # third byte: it has only 2 bytes
i = 3
messagetype = message[0] >> 4
messagechannel = (message[0] & 15) + 1
# second byte is not for note on/note off messages and program number for program change messages
note = message[1] if len(message) > 1 else None
# programe changes are in the 0-127 while usually numbered 1-128 in keyboards
programNumber = note + 1
# third byte is the velocity (for note on/off only)
velocity = message[2] if len(message) > 2 else None
if messagetype == 9: # Note on
print(‘Note on : 0x’ + ”.join(‘{:02x}’.format(x) for x in message) + ‘ note=’ + str(note) + ‘ at velocity ‘ + str(velocity) + ‘ on c>
elif messagetype == 8: # Note off
print(‘Note off: 0x’ + ”.join(‘{:02x}’.format(x) for x in message) + ‘ note=’ + str(note) + ‘ on channel ‘ + str(messagechannel))
elif messagetype == 12: # Program change
print (‘Program change ‘ + str(programNumber) + ‘ on channel ‘ + str(messagechannel))
STEP 5:
Run the example file in sudo
sudo python midi.py
Here is the output I get when
– playing C4 and releasing it
– playing (and kept sustained) C4, D4, E4 and releasing them all at the same time
– changing program to 8, 7 and 6
Note on : 0x903c4b note=60 at velocity 75 on channel 1
Note off: 0x803c4b note=60 on channel 1
Note on : 0x903c64 note=60 at velocity 100 on channel 1
Note on : 0x903e70 note=62 at velocity 112 on channel 1
Note on : 0x90407f note=64 at velocity 127 on channel 1
Note off: 0x803c7f note=60 on channel 1
Note off: 0x803e7f note=62 on channel 1
Note off: 0x80407f note=64 on channel 1
Program change 8 on channel 1
Program change 7 on channel 1
Program change 6 on channel 1
Hi Oriol,
I trust you are well and continue to be keeping safe.
I have revisited this again after a hiatus.
Could you point me to the latest install instructions?
W/o updated instructions I can see, I went ahead and try again:
Steps;
1) Use an fresh RPI ( sudo apt full-upgrade done and rebooted)
2) I place the OSA Midi Board onto the RPI
3) Put power
4) Immediately, the TX light turns on and never turns off ( same as my observation the first time I asked for your help 5) On OSA Midi Board connect MIDI out to MIDI IN of my groovebox
6) Ensure I am setup to receive MIDI IN of my groovebox from Channel 3
7) Run the latest example you have posted – “MIDI out over Serial (example_1_midi_out.py)”
6) No sound coming from the python script, TX light forever ON.
7) 🙁
( My unit is Raspberry Pi 3 Model B v1.2 )
Can you help me in trouble shoot? Or could it be that I have a faulty Midi board?
Thanks Again, Joseph
Joseph,
By default the Raspberry Pi assigns the GPIO serial channel used for MIDI to Bluetooth. Check out Section 3 of this guide: https://www.samplerbox.org/article/midiinwithrpi
You may also need to disable shell communication over GPIO in raspi-config, otherwise your MIDI messages will be garbled.
Hey Oriol,
I think you are using the wrong baudrate in the two python scripts above. I was not able to get it working until I changed the baudrate to the MIDI baudrate of 31250 (http://www.gweep.net/~prefect/eng/reference/protocol/midispec.html). Now its working well.
Just wanted to mention it in case anyone faces the same problem. However thanks a lot for the tutorial 🙂
Best, Florian
Thank you very much Florian! You are right, so just changed that!
Best,
Oriol.