Music Devices — IM-UH 3116 / NYU Abu Dhabi
Four small browser pages showing how to read MIDI in the browser with WebMIDI.js and visualize it with p5.js. Built alongside the class hardware kit (ESP32-S3 Reverse TFT Feather + NeoKey 1x4 + NeoSlider) but any MIDI controller will work.
Use Chrome or Edge — they have built-in Web MIDI support. Firefox needs the Jazz plugin.
All four examples are built from the same ingredients:
The pattern shared by every example: MIDI events update state; the render loop reads state. MIDI messages arrive at unpredictable times, but p5 draws on a fixed tick. Keeping the two decoupled is the single most important idea — it’s what stops the canvas from flashing, stuttering, or missing events when your controller gets chatty.
List all connected MIDI devices and watch a live log of every incoming message — notes, velocity, CC values. A useful debugging tool when building your own controllers.
Before you build any visualiser, you need to see what your controller is actually sending. Half the bugs in a later example are really surprises in the MIDI stream — a duplicated note-on, a CC on channel 2 when you expected channel 1. This page is your oscilloscope.
Press the four NeoKey buttons to spawn colorful ripples on a p5.js canvas. Each button maps to a position and color; velocity controls the ring size.
The temptation with a “four-button visualiser” is to hard-code four positions. Resist it. If the same code handles 1 note or 20 with no config, you can reuse it with a keyboard, a drum pad, or a wind controller — whatever happens to be plugged in.
Move the NeoSlider to see a live dial and scrolling waveform in p5.js. Shows how to read Control Change messages and map them to visual parameters.
Controllers rarely send a single CC. A synth knob bank, a mod wheel, a foot pedal, and a breath controller all at once is normal. A visualiser that assumes one-CC-at-a-time breaks the moment you plug in real gear. Build for many from the start.
Press keys to spawn glowing particle bursts; move the slider to change gravity. Notes and CC are both auto-detected. Demonstrates using NoteOn/Off events alongside a continuous CC value to control physics in real time.
Pairs with CircuitPython/midi_particles.py — the hardware sends the same
notes (E minor pentatonic) and CC number, with button colours matching the on-screen particle hues.
These pages must be served over HTTP, not opened as a file. From inside the
docs/ directory:
cd docs && python3 -m http.server 8000
Then open http://localhost:8000/p5examples.html.
These examples were built with Claude as a pair-programmer. The advice below is useful whether you start from scratch or copy one of these and diff your way to something new.
CircuitPython/spritekeys.py”
(or whichever file matches your rig). It will read it, pick up the NeoKey / NeoSlider
init code, and match the firmware you already have working — no guessing about
which addresses or which notes.
Math.pow(2, (note - 69) / 12) or an
hsvToRgb function and you’re not sure what those do, ask.
“Explain this line” or “why did you choose this formula” is a
legitimate prompt — you’ll learn the technique and be able to modify it yourself
next time. Shipping code you can’t read means you’re stuck the moment it breaks.
WebMidi.enable() succeeds and the listener fires — the bug is
in the render path” saves five rounds of diagnostic suggestions.