Loading & Playing Sounds

iHearYouCanCode — by David Stein
Load audio files, play them on click, and control volume and speed
↗ SoundFile Docs
Haven't set things up yet? Do Getting Started first — it shows you how to add p5.js, p5.sound, and ProControls.

1. Load a sound file

A p5.SoundFile holds audio loaded from a file — like an MP3 or WAV. Loading takes time, so use preload() to fetch the file before setup() runs. Call loadSound() with a path or URL. Click the canvas to play it.

The examples below use an audio file stored in the project's /assets folder. When you build your own sketch, put audio files in your project folder and use a path like 'sounds/beat.mp3'.

Try editing the code — the preview updates as you type

Loading takes time

Audio files don't appear instantly — loadSound() fetches the file in the background. The code checks isPlaying() to decide whether to play or stop, but it's also common to guard with isLoaded() to make sure the file is ready before you call play(). If you try to play too early, nothing happens.

2. Control volume and playback speed

Use amp() to change the volume and rate() to change how fast the sound plays. Here an IconButton from ProControls toggles the song on and off, and a MultiSlider gives you two knobs — one for volume, one for speed. Drag a slider while the song is playing to hear the difference in real time.

Try editing the code — the preview updates as you type

Handy SoundFile methods

When you host your own files, you can pass several formats in an array — loadSound(['beat.mp3', 'beat.ogg']) — and the browser picks one that works. See the p5.SoundFile reference.

3. Build a sample pad

A sample pad is a set of buttons — press one and it immediately plays a sound, like the pads on a real drum machine. Each button is wired to one audio file, so you can tap out patterns in real time. This example uses GridPad from ProControls with mode:"button", which means pads fire when you press them but don't stay lit up — perfect for a performance-style pad.

Try editing the code — the preview updates as you type

Loading the sounds

The samples array holds the file path for each drum sound. Inside preload(), a loop calls loadSound() on every path and pushes the result into the drums array. By the time setup() runs, all eight sounds are loaded and ready to go.

The pad — mode:"button"

new GridPad({rows:2, cols:4, cellSize:60, mode:"button"}) draws a 2×4 grid of eight pads. mode:"button" is the key difference from the sequencer below — pressing a pad triggers it once and it immediately goes dark again, just like a real drum pad. There's no on/off toggle; every press is a fresh hit.

Reacting to a press — onChange

Every time you press a pad, onChange fires and receives an object with three things: data1.r (which row, 0 or 1), data1.c (which column, 0–3), and data1.state ("on" when the pad is first pressed). The line let index = data1.r * 4 + data1.c converts that row and column into a single number between 0 and 7 — the position of the right sound in the drums array. When state is "on", drums[index].play() fires the sound.

Want to loop sounds instead of playing them once? Replace gridChanged with this version and change mode from "button" to "toggle" — pressing a pad starts the loop, pressing it again stops it:
function gridChanged(data1, data2) {
  let index = data1.r * 4 + data1.c;
  if (data1.value == 1) {
    drums[index].loop();
  } else if (data1.value == 0) {
    drums[index].stop();
  }
}

4. Build a drum machine with GridPad

A step sequencer is basically a drum machine. Imagine a grid where each row is a different drum sound and each column is a moment in time. Click a cell to switch it on — when the sequencer reaches that column, that drum plays. Click it again to switch it off.

GridPad from ProControls draws the whole grid for you and handles all the clicking. You just tell it how many rows and columns you want. The preview on the right shows a finished sequencer — try clicking the cells to build a beat.

Try editing the code — the preview updates as you type

The grid — GridPad

new GridPad({rows:8, cols:16, mode:"toggle"}) creates an 8×16 button grid. mode:"toggle" means every click flips a cell between on (lit) and off (dark). hGroup:4 draws faint divider lines every 4 columns so you can count beats easily. You don't write any drawing code — GridPad handles all of it automatically.

The timer — setInterval

setInterval(() => { ... }, 250) runs a chunk of code every 250 milliseconds — that's four times per second, which feels like a steady beat at 60 BPM. Each time it fires it calls nextBeat() to move the playhead one step to the right, then playBeat() to check which drums should play on that step. Want it faster? Lower the number. Slower? Raise it.

There's one small catch: the timer starts the moment the page loads, but the grid doesn't exist yet — it only gets created inside setup(), which runs after all the samples have finished downloading. The line if (!myGrid) return; inside the timer is a safety check: if the grid isn't ready yet, just skip this tick and wait until it is.

Reading the grid — getValue

myGrid.getValue(row, col) returns 1 if that cell is lit up, or 0 if it's dark. playBeat() loops through every row and plays the drum sound for that row only when the value is 1. That's the whole playback engine — just a loop and a number check.

Moving the playhead — highlightCol

myGrid.highlightCol(col, true) draws a glowing outline around that column so you can see where the sequencer is. nextBeat() turns the highlight off on the old column, adds one to beatCounter (wrapping back to 0 after column 15), then turns the highlight on for the new column.

Key GridPad options