Interactive Musical Board

by hwangjin in Circuits > Raspberry Pi

362 Views, 3 Favorites, 0 Comments

Interactive Musical Board

IMG_0752.jpeg

The Interactive Musical Game Board is an assistive technology device designed for students with physical and cognitive disabilities at the Campus School to enjoy music by pressing buttons.

The board features 9 100mm arcade buttons (8 blue and 1 red) each triggering colorful NeoPixel LED light feedback and cheerful audio playback through a speaker when pressed.

The device operates in two modes toggled by the red button:

  1. Mode A (Melody Mode): Each blue button plays a unique cheerful song — Baby Shark, Happy Birthday, Twinkle Twinkle, and more
  2. Mode B (Scale Mode): The same buttons play individual Do Re Mi musical notes, each with a unique rainbow color on the NeoPixel strip

This project was built using a Raspberry Pi Pico 2W running CircuitPython, with MP3 audio handled through the PWM audio output, a 132-LED NeoPixel strip for colorful light feedback, and 4× 16×16 LED panels driven by a Pixelblaze controller for ambient background effects. The laser-cut enclosure is assembled with hot glue.

Supplies

Electronics

  1. Raspberry Pi Pico 2W (x1) https://www.adafruit.com/product/6315
  2. Massive Arcade Button with LED - 100mm (x8 blue, x1 red) https://www.adafruit.com/product/1189
  3. Adafruit NeoPixel Digital RGBW LED Strip - Black PCB 60 LED/m 1m (x1) https://www.adafruit.com/product/2841
  4. Mono Enclosed Speaker - 3W 4Ohm (x1) https://www.adafruit.com/product/3351
  5. Pixelblaze V3 controller (x1) https://shop.electromage.com/products/pixelblaze-v3-standard-wifi-led-controller
  6. 16×16 WS2812B LED panels (x4) https://www.amazon.com/WESIRI-WS2812B-Flexible-Individually-Addressable/dp/B07PB2P81N?th=1
  7. 5V 5A power supply (for Pixelblaze + panels) (x1) https://www.amazon.com/5V-Power-Supply-Adapter-Converter/dp/B07H9W6MCH
  8. Dupont jumper wires (many) https://www.amazon.com/Elegoo-EL-CP-004-Multicolored-Breadboard/dp/B01EV70C78

Materials:

  1. 2x Baltic Birch 1/8" for laser cutting components
  2. Hot glue gun + sticks

Laser Cut the Enclosure & Assemble With Hot Glue

IMG_0620.jpeg
IMG_0621.jpeg

Design the enclosure using makercase and export it as an SVG file. Add 9 cutouts for the arcade buttons (100mm diameter each) before cutting. Take the SVG file to the laser cutter and cut all panels.

Assemble the enclosure using a hot glue gun. Apply hot glue to each joint and hold firmly until set. Hot glue works well here because it's fast, strong enough for a display project, and easy to adjust if you need to reposition a panel.

Assemble Buttons & Wiring

IMG_0742.jpeg

Connects wires onto each of the 9 buttons. For each button, one wire connects to ground and one wire connects to the signal GPIO pin. You only need 2 wires per button — the SW (NO) and SW (COM) terminals. If you want the buttons to light on when pressed, you can connect other 2 wires to 5V and GND and write a code for that.

Once connected, push each button through its hole on the enclosure from the inside and secure it with the plastic locking ring that comes with the button.

Connect Speaker, NeoPixel, and Buttons to Pico 2W

Screen Shot 2026-04-29 at 23.35.04.png

NeoPixel strip (132 LEDs):

Signal → GP15

Power → VBUS (5V)

GND → GND

Speaker:

Signal→ GP14

GND → GND

Power → 3.3V


Prepare Audio Files Using Audacity

Download Audacity (audacityteam.org) — it's free. Use it to prepare all your MP3 files for the project.

For each audio file:

  1. Open the file in Audacity
  2. Select the desired part
  3. Modify the volume — Mono, 16 bits, sample rate = 22050
  4. Export as MP3 — go to File → Export → Export as MP3 (mp3 has smaller size than wav)
  5. Name the file exactly as referenced in your code (e.g. baby-shark.mp3)

Create a folder named "sound" on your CIRCUITPY drive and copy all MP3 files into it.

Melody files (Mode A): baby-shark.mp3, birthday.mp3, cpk.mp3, dance-monkey.mp3, old-mac.mp3, shake-it-off.mp3, TT-star.mp3, wheel-on-bus.mp3

Scale note files (Mode B): do.mp3, re.mp3, mi.mp3, fa.mp3, sol.mp3, la.mp3, ti.mp3, do1.mp3

Test LED Animations Using Pixelblaze (2× 16×16 Panels)

Screen Shot 2026-04-29 at 23.54.21.png

I tested animations using Pixelblaze with 2× 16×16 WS2812B LED panels. Power the Pixelblaze via USB and daisy chain the panels. Connect to the WiFi network named pixelblaze_XXXXXX from the laptop. Open a browser to http://192.168.4.1, set pixel count to 512 (2 × 16x16), and pick a pattern like Rainbow or Sparks.

Switch HUB75 for 2 Additional 16×16 Panels

IMG_0745.jpeg

I originally planned to use a HUB75 LED matrix connected directly to the Pico 2W for the main display. However, even with correct wiring the HUB75 did not work reliably — the high-speed data signal was too sensitive to the jumper wire connections.

Since the HUB75 matrix didn't work reliably with the Pico 2W, I replaced it with 2 more 16×16 WS2812B LED panels — giving me 4 panels driven by a Pixelblaze. (update the Pixelblaze pixel count to 1024)

Power all 4 panels from a dedicated 5V 5A power supply — not the Pico VBUS.

Final Assembly & Code

Place the Pico 2W and all wiring inside the enclosure. Route the NeoPixel strip along the inside edges and secure with hot glue. Mount the 4 LED panels on the outside of the enclosure or behind a display frame.

Copy the final code.py and the sound/ folder to your CIRCUITPY drive. Open the serial monitor in PyCharm using Tio to confirm the board prints:

"Music board ready!"

Press each of the 9 buttons to confirm:

  1. Correct melody or scale note plays
  2. NeoPixel strip lights the correct color
  3. Red button toggles between Mode A and Mode B
import board, time, digitalio, neopixel, audiomixer
from audiopwmio import PWMAudioOut as AudioOut
from audiomp3 import MP3Decoder
from adafruit_led_animation.color import BLACK, RED, BLUE, GREEN, \
YELLOW, PURPLE, CYAN, ORANGE, WHITE

BUTTON_PINS = [
board.GP11, board.GP12, board.GP4, board.GP5,
board.GP6, board.GP7, board.GP8, board.GP9,
board.GP10,
]

BUTTON_COLORS = [BLUE, GREEN, YELLOW, PURPLE, CYAN, ORANGE, WHITE, RED, RED]

SCALE_COLORS = [
(255, 0, 0), (255, 60, 0), (255, 200, 0), (0, 200, 0),
(0, 180, 180), (0, 80, 200), (120, 0, 180), (255, 0, 0),
]

SCALE_NAMES = ["Do", "Re", "Mi", "Fa", "Sol", "La", "Ti", "Do"]

path = "sound/"
audio = AudioOut(board.GP14)
mixer = audiomixer.Mixer(voice_count=1, sample_rate=22050,
channel_count=1, bits_per_sample=16, samples_signed=True)
audio.play(mixer)
mixer.voice[0].level = 0.3

mp3_file = open(path + "baby-shark.mp3", "rb")
decoder = MP3Decoder(mp3_file)

melody_mp3 = ["baby-shark.mp3", "birthday.mp3", "cpk.mp3", "dance-monkey.mp3",
"old-mac.mp3", "shake-it-off.mp3", "TT-star.mp3", "wheel-on-bus.mp3"]

piano_mp3 = ["do.mp3", "re.mp3", "mi.mp3", "fa.mp3",
"sol.mp3", "la.mp3", "ti.mp3", "do1.mp3"]

pixels = neopixel.NeoPixel(board.GP15, 132, brightness=0.4)

buttons = []
for pin in BUTTON_PINS:
b = digitalio.DigitalInOut(pin)
b.switch_to_input(pull=digitalio.Pull.UP)
buttons.append(b)

def play_mp3(filename):
decoder.file = open(path + filename, "rb")
mixer.voice[0].play(decoder)
while mixer.voice[0].playing:
pass

def light_strip(color):
pixels.fill(color)

def clear_strip():
pixels.fill(BLACK)

def flash_mode(color):
for _ in range(2):
pixels.fill(color)
time.sleep(0.2)
pixels.fill(BLACK)
time.sleep(0.1)

def read_button():
for i, b in enumerate(buttons):
if b.value == False:
return i
return None

MODE_MELODY, MODE_SCALE = 0, 1
mode = MODE_MELODY
clear_strip()
print("Music board ready!")

while True:
pressed = read_button()
if pressed is not None:
time.sleep(0.05)
if read_button() != pressed:
continue
if pressed == 8:
mode = MODE_SCALE if mode == MODE_MELODY else MODE_MELODY
flash_mode(RED if mode == MODE_SCALE else GREEN)
else:
if mode == MODE_MELODY:
light_strip(BUTTON_COLORS[pressed])
play_mp3(melody_mp3[pressed])
else:
light_strip(SCALE_COLORS[pressed])
play_mp3(piano_mp3[pressed])
clear_strip()
time.sleep(0.2)
time.sleep(0.03)

Downloads

Troubleshooting

Button not responding:

  1. External buttons use Pull.UP — reads False when pressed, not True
  2. Check SW (NO) → GPIO and SW (COM) → GND (mostly wiring issue)
  3. Run a quick test: print(button.value) in a loop to see readings

No sound:

  1. Check speaker + and − connections to GP14 and GND
  2. Make sure all MP3 files are in the sound/ folder with exact filenames
  3. Check for missing commas in your MP3 file lists in the code

HUB75 matrix not working:

  1. This is a known issue with direct Pico 2W + HUB75 connections using jumper wires
  2. The high-speed clock signal is sensitive to long or low-quality wires
  3. I switched to 4× 16×16 WS2812B panels driven by Pixelblaze as a reliable alternative