Back to Projects

Adafruit MIDI Controller

CircuitPython code for Raspberry Pi Pico MIDI controller with keyboard matrix scanning

midi-controller.py
CircuitPython
import time
import board
import digitalio
import usb_midi
from adafruit_midi import MIDI
from adafruit_midi.note_on import NoteOn
from adafruit_midi.note_off import NoteOff

# Update these lists if you wired differently
ROWS = [board.GP2, board.GP3, board.GP4, board.GP5, board.GP6, board.GP7, board.GP8, board.GP9]
COLS = [board.GP10, board.GP11, board.GP12, board.GP13, board.GP14, board.GP15, board.GP16, board.GP17]

FIRST_NOTE = 36       # MIDI note number for the leftmost key; adjust for your keyboard
DEBOUNCE_DELAY = 0

row_pins = []
for p in ROWS:
    d = digitalio.DigitalInOut(p)
    d.direction = digitalio.Direction.OUTPUT
    d.value = False
    row_pins.append(d)

col_pins = []
for p in COLS:
    d = digitalio.DigitalInOut(p)
    d.direction = digitalio.Direction.INPUT
    d.pull = digitalio.Pull.DOWN
    col_pins.append(d)

midi = MIDI(midi_out=usb_midi.ports[1], out_channel=0)
key_states = [False] * (8 * 8)

def scan_matrix():
    pressed = []
    for r, row in enumerate(row_pins):
        row.value = True
        time.sleep(0.0001)
        for c, col in enumerate(col_pins):
            if col.value:
                pressed.append(r * 8 + c)
        row.value = False
    return pressed

print("MIDI matrix ready")

while True:
    current = scan_matrix()
    for i in range(64):
        note = FIRST_NOTE + i
        now = (i in current)
        prev = key_states[i]
        if now and not prev:
            midi.send(NoteOn(note, 100))
            key_states[i] = True
        elif not now and prev:
            midi.send(NoteOff(note, 0))
            key_states[i] = False
    time.sleep(DEBOUNCE_DELAY)

Configuration

  • ROWS: GPIO pins 2-9 (outputs for row selection)
  • COLS: GPIO pins 10-17 (inputs for column detection)
  • FIRST_NOTE: MIDI note 36 (C2) - adjust as needed
  • Key Matrix: 8x8 = 64 keys maximum