Micro Music Keyboard With Effects

by wzimeng in Circuits > Electronics

49 Views, 1 Favorites, 0 Comments

Micro Music Keyboard With Effects

IMG_1824.jpg
IMG_1753.jpg

This is a one octave arduino microcontroller piano keyboard that plays music and generate visual effects. The project was created to combine an interest in electronics with music and an exploration of coding and AI using the Raspberry Pi.

Supplies

Display:

  1. raspberry pi 5 (optional, only required for LCD board)
  2. LCD board (optional)
  3. computer

Keyboard:

  1. 2x raspberry pi pico
  2. self-designed pcb board
  3. 42x mechanical tactile switches
  4. 42x key caps
  5. 2x USB to micro cable

Keys:

  1. 3D printer
  2. pla filament

Other necessities:

  1. soldering materials

Design PCB Board

IMG_1800.jpg

For this project, I used two 3x7 pcb boards for the full octave using a reference from another project. It is possible to design it as one pcb board but since the pico only has 26 usable pins and this requires 39 pins for direct wiring, it would have to be done through a key matrix.

Solder and Key Cap

IMG_1798.jpg
IMG_1797.jpg

With the pcb boards, solder each switch as well as the raspberry pi pico. Use any online tutorial for help with soldering.

After soldering, attach the key caps. The key caps can either be bought or 3D printed.

Code

Use the following guide and download the necessary bundle.

Use the following code for the first pcb board and upload it using a notepage as a code.py file.

# SPDX-FileCopyrightText: 2021 John Park for Adafruit Industries
# SPDX-License-Identifier: MIT

# Pico RP2040 MIDI Keyboard - Columns play same note
# 7 columns x 3 rows = 21 keys
# Each column plays the same note: C, C#, D, D#, E, F, F#

import time
import board
from digitalio import DigitalInOut, Direction, Pull
import usb_midi
import adafruit_midi
from adafruit_midi.note_on import NoteOn
from adafruit_midi.note_off import NoteOff

print("---Pico MIDI Keyboard---")

MIDI_CHANNEL = 1
midi = adafruit_midi.MIDI(midi_out=usb_midi.ports[1], out_channel=MIDI_CHANNEL - 1)

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

# All 21 pins in order (GP0 to GP21, skipping GP15)
pins = (
board.GP0, board.GP1, board.GP2, board.GP3, board.GP4,
board.GP5, board.GP6, board.GP7, board.GP8, board.GP9,
board.GP10, board.GP11, board.GP12, board.GP13, board.GP14,
board.GP16, board.GP17, board.GP18, board.GP19, board.GP20,
board.GP21,
)

switches = []
for pin in pins:
switch = DigitalInOut(pin)
switch.direction = Direction.INPUT
switch.pull = Pull.UP
switches.append(switch)

switch_state = [0] * 21

# 7 columns, 3 rows
# Keys are wired left-to-right, top-to-bottom:
# Row 0 (top): keys 0-6 → GP0-GP6
# Row 1 (middle): keys 7-13 → GP7-GP13
# Row 2 (bottom): keys 14-20 → GP14,GP16-GP21

# One note per column: C4, C#4, D4, D#4, E4, F4, F#4
COLUMN_NOTES = [60, 61, 62, 63, 64, 65, 66]

# Map each key index (0-20) to its column (0-6)
def key_to_note(key_index):
col = key_index % 7
return COLUMN_NOTES[col]

led.value = False
print("Ready, set, play!")

while True:
for i in range(21):
note = key_to_note(i)

if switch_state[i] == 0:
if not switches[i].value:
midi.send(NoteOn(note, 120))
print(f"NoteOn: key {i} → MIDI {note}")
switch_state[i] = 1

if switch_state[i] == 1:
if switches[i].value:
midi.send(NoteOff(note, 0))
print(f"NoteOff: key {i} → MIDI {note}")
switch_state[i] = 0

time.sleep(0.01)

Second code:

# SPDX-FileCopyrightText: 2021 John Park for Adafruit Industries
# SPDX-License-Identifier: MIT

# Pico RP2040 MIDI Keyboard - Board 2
# 7 columns x 3 rows = 21 keys
# Columns play: G, G#, A, A#, B, C, C

import time
import board
from digitalio import DigitalInOut, Direction, Pull
import usb_midi
import adafruit_midi
from adafruit_midi.note_on import NoteOn
from adafruit_midi.note_off import NoteOff

print("---Pico MIDI Keyboard Board 2---")

MIDI_CHANNEL = 1
midi = adafruit_midi.MIDI(midi_out=usb_midi.ports[1], out_channel=MIDI_CHANNEL - 1)

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

# All 21 pins in order (GP0 to GP21, skipping GP15)
pins = (
board.GP0, board.GP1, board.GP2, board.GP3, board.GP4,
board.GP5, board.GP6, board.GP7, board.GP8, board.GP9,
board.GP10, board.GP11, board.GP12, board.GP13, board.GP14,
board.GP16, board.GP17, board.GP18, board.GP19, board.GP20,
board.GP21,
)

switches = []
for pin in pins:
switch = DigitalInOut(pin)
switch.direction = Direction.INPUT
switch.pull = Pull.UP
switches.append(switch)

switch_state = [0] * 21

# G4, G#4, A4, A#4, B4, C5, C5
# Last column repeats C5 since we only have 6 new notes but 7 columns
COLUMN_NOTES = [67, 68, 69, 70, 71, 72, 72]

def key_to_note(key_index):
col = key_index % 7
return COLUMN_NOTES[col]

led.value = False
print("Ready, set, play!")

while True:
for i in range(21):
note = key_to_note(i)

if switch_state[i] == 0:
if not switches[i].value:
midi.send(NoteOn(note, 120))
print(f"NoteOn: key {i} → MIDI {note}")
switch_state[i] = 1

if switch_state[i] == 1:
if switches[i].value:
midi.send(NoteOff(note, 0))
print(f"NoteOff: key {i} → MIDI {note}")
switch_state[i] = 0

time.sleep(0.01)

*** For the second code, switch the order of the keys so that the raspberry pi pico can lay on the outside for both of the boards

Test the pcb boards by plugging in the USB cable to the computer.

All three keys in each column should play the exact same note.

To play, use any online MIDI keyboard. I personally used midi.city but any other free platforms work just as well.

3D Print Keys

IMG_1641.jpg

Utilized a reference for standard sized keys from another project. The 8 white keys are different for each key. Additionally print 5 identical black keys.

To attach the keys, use strong tape to attach each key to three of the keycaps.

Effects

The keyboard playing can be played with effects and different sounds using a variety of platforms.

For varying keyboard sounds try virtualpiano.eu.