p5.js Beginner Article 7

Sound Basics

Load and play audio files, synthesise tones, and react to microphone input with the p5.sound library.

⏱ 20 min read sound audio p5.sound microphone synthesis

Setting up p5.sound

p5.sound is an official add-on library. Include it alongside p5.js:

<script src="https://cdn.jsdelivr.net/npm/p5@1.11.0/lib/p5.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/p5@1.11.0/lib/addons/p5.sound.min.js"></script>

In the p5.js web editor, p5.sound is already included by default.

Browser autoplay policy: Browsers require a user interaction (click, key press) before audio can start. Always begin audio in a click handler, not in setup().

Loading and playing a sound file

let synth;

function preload() {
  synth = loadSound('bass.mp3');
}

function setup() {
  createCanvas(400, 200);
  background(20);
  fill(255);
  textAlign(CENTER, CENTER);
  text('Click to play', width / 2, height / 2);
}

function mouseClicked() {
  if (synth.isPlaying()) {
    synth.stop();
  } else {
    synth.play();
  }
}

Sound file controls

synth.play();           // play from current position
synth.stop();           // stop and reset to start
synth.pause();          // pause at current position
synth.loop();           // loop indefinitely
synth.setLoop(true);    // set loop mode
synth.isPlaying();      // returns true/false
synth.setVolume(0.5);   // 0 (silent) to 1 (full)
synth.rate(1.5);        // playback speed (1 = normal, 0.5 = half speed)
synth.pan(-1);          // -1 = left, 0 = centre, 1 = right
synth.jump(2.5);        // jump to 2.5 seconds
synth.duration();       // total length in seconds
synth.currentTime();    // current playback position

Sound amplitude (volume analysis)

p5.Amplitude measures the average volume of a sound:

let sound, amp;

function preload() {
  sound = loadSound('music.mp3');
}

function setup() {
  createCanvas(600, 400);
  sound.loop();
  amp = new p5.Amplitude();
  amp.setInput(sound);
}

function draw() {
  background(20);

  let level = amp.getLevel();  // 0 to ~1 (peaks may exceed 1)
  let size  = map(level, 0, 0.5, 20, height * 0.9);

  colorMode(HSB, 360, 100, 100);
  fill(map(level, 0, 0.5, 200, 360), 80, 90);
  noStroke();
  circle(width / 2, height / 2, size);
}

FFT — frequency analysis

p5.FFT splits the audio into frequency bands, enabling spectrum visualisers:

let sound, fft;

function preload() {
  sound = loadSound('music.mp3');
}

function setup() {
  createCanvas(700, 400);
  sound.loop();
  fft = new p5.FFT(0.8, 256);  // smoothing (0-1), number of bins
}

function draw() {
  background(15);

  let spectrum = fft.analyze();  // array of 256 amplitude values (0-255)

  noStroke();
  for (let i = 0; i < spectrum.length; i++) {
    let x = map(i, 0, spectrum.length, 0, width);
    let h = map(spectrum[i], 0, 255, 0, height);

    colorMode(HSB, 360, 100, 100);
    fill(map(i, 0, spectrum.length, 200, 360), 80, 90);
    rect(x, height - h, width / spectrum.length, h);
  }
}

Waveform display

let waveform = fft.waveform();  // returns 1024 values from -1 to 1

stroke(100, 200, 255);
strokeWeight(1.5);
noFill();
beginShape();
for (let i = 0; i < waveform.length; i++) {
  let x = map(i, 0, waveform.length, 0, width);
  let y = map(waveform[i], -1, 1, height, 0);
  vertex(x, y);
}
endShape();

Microphone input

let mic, amp;

function setup() {
  createCanvas(600, 200);
  mic = new p5.AudioIn();
  mic.start();
  amp = new p5.Amplitude();
  amp.setInput(mic);
}

function draw() {
  background(20);
  let level = amp.getLevel();
  let w     = map(level, 0, 0.5, 0, width);

  fill(100, 200, 255);
  noStroke();
  rect(0, height / 2 - 20, w, 40, 0, 8, 8, 0);
}

Microphone access requires HTTPS (or localhost). The browser will show a permission prompt.

Synthesis with p5.Oscillator

Generate tones without audio files:

let osc;

function setup() {
  createCanvas(400, 200);
  osc = new p5.Oscillator('sine');  // 'sine', 'square', 'triangle', 'sawtooth'
  osc.amp(0.5);
  osc.freq(440);   // Hz
}

function mouseClicked() {
  if (osc.started) {
    osc.stop();
  } else {
    osc.start();
  }
}

function draw() {
  background(20);
  // Map mouse position to frequency
  let freq = map(mouseX, 0, width, 100, 1000);
  osc.freq(freq);
}

Theremin-style instrument

let osc, env;

function setup() {
  createCanvas(600, 400);
  osc = new p5.Oscillator('sine');
  env = new p5.Envelope();
  env.setADSR(0.05, 0.1, 0.7, 0.3);
  env.setRange(0.8, 0);
  osc.amp(env);
  osc.start();
}

function draw() {
  background(15);
  let freq = map(mouseX, 0, width, 80, 880);
  osc.freq(freq);

  colorMode(HSB, 360, 100, 100);
  fill(map(mouseX, 0, width, 180, 360), 80, mouseIsPressed ? 90 : 30);
  noStroke();
  circle(width / 2, height / 2, map(mouseY, 0, height, 200, 20));
}

function mousePressed() { env.play(); }
function mouseReleased() { env.stop(); }

Key takeaways

  • Include p5.sound via CDN; audio must start from a user interaction
  • loadSound() in preload() loads files; .play(), .stop(), .loop() control playback
  • p5.Amplitude measures volume level; p5.FFT provides spectrum data
  • p5.AudioIn captures microphone input
  • p5.Oscillator generates tones; p5.Envelope shapes the amplitude over time
  • Map audio levels to visual properties (size, colour, position) for reactive visuals