An oscillator is something that moves back and forth in a regular, repeating pattern — like a pendulum or a guitar string vibrating. In audio, an oscillator generates a waveform: a signal that rises and falls at a set speed (its frequency, measured in Hz) and height (amplitude, which we hear as volume). That repeating wave is what travels through your speakers and becomes sound.
Oscillators are the fundamental building blocks of sound synthesis. Even complex, rich sounds — a violin, a human voice, a distorted guitar — can be understood as a combination of many simple oscillators layered together at different frequencies and volumes.
This idea goes back to the mathematician Joseph Fourier, who showed in the early 1800s that any repeating waveform can be broken down into a sum of simple sine waves. That means a square wave, a sawtooth, or a harsh buzzing sound is really just a pile of smooth, pure sine waves added together at precise ratios. Flip it around and you can build complex sounds by stacking simple ones — which is exactly what a synthesizer does.
This sketch makes a tone you turn on and off by clicking the canvas.
On the first click, call userStartAudio() so the browser allows sound.
Then use osc.start() to play and osc.stop() to stop.
Try editing the code below — the preview updates as you type.
Browsers won't play sound until you click something — it's a safety rule.
userStartAudio() in mousePressed() turns sound on.
osc.started tells you if the tone is playing: true means on, false means off.
Now your mouse controls the sound while it's playing.
Move left and right to change pitch (how high or low).
Move up and down to change volume (how loud).
map() turns mouse position into numbers the oscillator can use.
Click still turns the sound on and off.
Swap the mouse for ProControls — knobs and pads on the screen.
The XYPad works the same way: drag to change pitch and volume.
The Selector lets you pick the wave shape — sine (smooth), square (buzzy),
sawtooth (harsh), or triangle (soft).
Set ControlStyle before you create controls (this picks how they look).
Call proControlBackground() in draw().
In each control's onChange, call userStartAudio().
So far, your oscillator is either on or off — like flipping a light switch.
A p5.Envelope makes volume change over time: fade in, hold, fade out.
That's how real instruments sound — a piano note doesn't pop on and off instantly.
An envelope doesn't make sound by itself. You connect it to something that does — usually
an oscillator's volume with osc.amp(env). The envelope then acts like an automatic
volume knob that moves through four stages called ADSR
(Attack, Decay, Sustain, Release). You'll tweak those numbers in the next section.
Create an envelope, set its shape with setADSR(), set how loud it gets with
setRange(), then plug it into the oscillator:
var osc, env;
env = new p5.Envelope();
env.setADSR(0.1, 0.2, 0.5, 0.3); // attack, decay, sustain, release (seconds / level)
env.setRange(0.8, 0); // attack level (loudest), release level (silent)
osc = new p5.Oscillator('sine');
osc.freq(440);
osc.start(); // oscillator runs; envelope controls its volume
osc.amp(env); // route volume through the envelope
setRange(attackLevel, releaseLevel) sets the loudest and quietest points.
The first number is how loud the note gets at its peak; the second is where it fades to when released.
Usually that's setRange(0.8, 0) — loud attack, silent release. Stay below 1 to protect your ears.
The third argument to setADSR() is the sustain level (0 to 1),
not a time — it's how loud the note holds while you're "holding the key."
There is no env.start() — envelopes use different methods depending on how you
want the note to behave:
env.play(osc, startTime, sustainTime) — plays a complete note
in one call. It runs attack → decay → sustain for sustainTime seconds → then
release automatically. Good for a quick click where you don't need to hold anything down.
// One-shot note: wait 0 seconds, hold sustain for 0.5 seconds, then release
env.play(osc, 0, 0.5);
env.triggerAttack(osc) and
env.triggerRelease(osc) — split the note into two steps, like a
piano key. triggerAttack() runs attack and decay, then holds at the sustain level
until you call triggerRelease(), which runs the release fade. Use these when the
player holds a mouse button, key, or pad — you decide how long the note lasts.
function mousePressed() {
userStartAudio();
env.triggerAttack(); // no osc needed — already wired in setup
}
function mouseReleased() {
env.triggerRelease();
}
play() for tap-to-play notes (drums, plucks).
Use triggerAttack() / triggerRelease() when the player holds a control
and you want the note to last exactly as long as they hold it.
These come up often once you start building instruments:
env.setInput(osc) — another way to wire up in setup() (like osc.amp(env))env.setExp(true) — use exponential curves instead of linear ones (often sounds more natural for volume)env.ramp(osc, level, startTime, duration) — a quick volume bump using the attack and decay timesosc.freq(env) — an envelope can control pitch or other parameters, not just volumeattackTime, decayTime, releaseTime, attackLevel, sustainLevel, releaseLevelSee the full API in the p5.Envelope reference.
Try it below — hold the mouse button down to play a note, let go to release it.
Now put it all together with ProControls so you can see and tweak the envelope shape live.
ADSR stands for Attack (how fast the note fades in),
Decay (how fast it drops after the attack),
Sustain (how loud it holds), and
Release (how long it fades out).
The MultiSlider controls change volume, pitch, and ADSR values.
The ADSRDisplay draws the shape on screen.
Click the canvas to fire a one-shot note with env.play(osc).