Skip to content

adafruit_midi

Works with

Any board with native USB (for USB MIDI) or a hardware UART (for traditional 5-pin DIN MIDI). Native USB boards include most SAMD21/SAMD51, RP2040, and ESP32-S2/S3 based boards.

What it does

Sends and receives MIDI messages over USB MIDI or UART serial. The library abstracts MIDI's binary protocol into Python objects — NoteOn, NoteOff, ControlChange, PitchBend, and others — so you work with readable class instances rather than raw bytes. It handles both the USB MIDI stack (via the built-in usb_midi module) and traditional 5-pin DIN MIDI (via busio.UART), making the same application code usable on either transport.

Installing the library

Copy the adafruit_midi/ folder from the bundle's lib/ folder to your board's lib/ folder.

Quick start

import usb_midi
import adafruit_midi
from adafruit_midi.note_on import NoteOn
from adafruit_midi.note_off import NoteOff
from adafruit_midi.control_change import ControlChange

# Channel numbers are 1-based in the constructor
midi = adafruit_midi.MIDI(
    midi_in=usb_midi.ports[0],
    in_channel=0,       # 0-based internally (channel 1)
    midi_out=usb_midi.ports[1],
    out_channel=0,
)

# Send a note
midi.send(NoteOn(60, 100))   # middle C, velocity 100
# ... do something ...
midi.send(NoteOff(60, 0))

# Receive messages (non-blocking)
msg = midi.receive()
if isinstance(msg, NoteOn):
    print("Note on:", msg.note, "velocity:", msg.velocity)
elif isinstance(msg, ControlChange):
    print("CC:", msg.control, "value:", msg.value)

Key things you can do

What you want How to do it
Send a note midi.send(NoteOn(note, velocity)) then NoteOff
Receive any message msg = midi.receive() — returns None if nothing waiting
Send a control change midi.send(ControlChange(control_number, value))
Change program/patch midi.send(ProgramChange(patch_number))
Send pitch bend midi.send(PitchBend(value)) — value is -8192 to 8191
Use UART MIDI busio.UART(tx, rx, baudrate=31250) as transport instead of usb_midi
Send on a specific channel Pass channel=N to individual message constructors
Middle C MIDI note number 60

Reading the official docs

https://docs.circuitpython.org/projects/midi/en/latest/

The API reference lists every message class and its attributes — useful when you need msg.note, msg.velocity, msg.control, or msg.value from a received message. The MIDI constructor reference explains in_channel / out_channel (which accept integers or tuples of integers for omni-channel reception) and the debug parameter for troubleshooting message parsing.

Projects using this library

  • Grand Central USB MIDI Controller in CircuitPython — Builds a multi-button USB MIDI controller with velocity sensitivity. Credit: Adafruit Learning System
  • MIDI Foot Pedal — Uses adafruit_midi to send program change and control change messages from a stomp switch. Credit: Adafruit Learning System
  • MIDI Keyset — Builds a small USB MIDI keyboard with CircuitPython and adafruit_midi. Credit: Adafruit Learning System