Reverbs · Play track · Ableton Learning Synths

Envelopes
giving a note life

One oscillator. One pitch. Yet it can be a harpsichord pluck, a bowed string, or a swelling pad — and the only thing that changed is how its loudness moves over time. That motion is the envelope. Let's draw one and hear it.

Scroll to begin
00 same oscillator, a new instrument

A note is not a switch.

In How Synths Make Sound you built an oscillator and a pitch and a timbre. But every note you played snapped on and snapped off — a fog-horn. Real instruments don't do that.

Strike a piano key and the sound leaps to its loudest in a few milliseconds, then sags to a held level, then — when you lift the key — fades away. Bow a cello and the sound swells in slowly. Same air, same room; utterly different gestures. The gesture is the loudness changing over time.

That time-varying loudness is called the amplitude envelope. It is the difference between a pluck and a pad, between a stab and a swell. And here is the surprising part: none of it touches the oscillator. The pitch and the harmonics stay exactly as you left them. The envelope only turns a volume knob — very precisely, very fast.

what this lesson covers

The envelope as a multiplier a(t) on the oscillator; exponential decay and its time constant τ; why good fades are exponential, not linear (your ear hears loudness logarithmically); the four phases A·D·S·R defined precisely; a complete envelope worked out by hand; the code in Web Audio and NumPy; and a draggable ADSR editor where you sculpt the shape and immediately hear the same oscillator wear it.

01 the envelope is a multiplier

One curve riding on top of the wave.

The oscillator produces a fast wobble — for a pure tone, sin(2πft), racing along at hundreds of cycles a second. The envelope is a slow curve, a(t), that rises and falls over a fraction of a second to a few seconds. The sound you actually hear is simply the two multiplied together:

output(t) = a(t) · sin(2πf·t) the slow envelope a(t) scales the fast carrier sin(2πft) sample by sample

Read it carefully. The sin(2πft) part decides the pitch and timbre — what note, what character. The a(t) part decides the shape of the gesture — how it begins, holds, and ends. They are independent. Change a(t) and the same note becomes a different instrument; change f and the same gesture plays a different note.

You can see it as one curve modulating another. Below, the loud envelope is the smooth hull; the busy wave packed inside it is the carrier, squeezed and stretched in loudness so it exactly fits under a(t):

|output(t)| ≤ a(t)   for all t the envelope is the ceiling the waveform can never exceed — it traces the peaks
one idea, three languages

Mathematician: the envelope is amplitude modulation — a slow function a(t) multiplying a fast carrier, a(t)·sin(2πft). Musician: it's the difference between plucked, bowed, and swelled — the articulation, the feel of the note under your fingers. Artist: it's the hull, the silhouette the sound is poured into; draw the silhouette and you've drawn the gesture. Hold all three and the next time you hear a sound start, you'll see its envelope.

And one more thing the math quietly allows: nothing says a(t) may only steer loudness. The very same curve can be wired to steer a filter's cutoff, or the pitch, or the harmonic mix — a filter envelope that makes a sound open bright and then close dark. We'll keep to amplitude here, but remember: an envelope is just a controllable curve over time, and you can point it at any knob. (That's the bridge to the next lesson.)

02 the shape of a fade

Why a good fade is exponential.

What curve should the fade-out actually be? The honest answer comes from physics. A struck string, a plucked note, a ringing bell — they all lose energy at a rate proportional to how much energy they still have. That rule, "the more you have, the faster you lose it," produces one shape and only one: the exponential decay.

a(t) = e−t/τ τ (tau) is the time constant — how long the decay "takes" to fall by a factor of e ≈ 2.718

The single number that controls this curve is the time constant τ. It is the time it takes the amplitude to fall to 1/e ≈ 0.368 of where it started — about 37%. Small τ = a snappy, percussive fall. Large τ = a long, lingering tail. Let's read the curve at a few moments for τ = 0.1 s:

At t = 0: a = e0 = 1.00 — full amplitude, the moment of attack.
At t = τ = 0.1 s: a = e−1 ≈ 0.368. After exactly one time constant, ~37% remains. This is the definition of τ.
At t = 0.2 s (two τ): a = e−2 ≈ 0.135 — ~13.5% left.
At t = 0.3 s (three τ): a = e−3 ≈ 0.050 — only ~5% left; the note is practically gone.

Notice the rhythm: every step of τ multiplies the amplitude by the same factor (1/e). That equal-ratio-per-equal-time behaviour is the fingerprint of exponential decay — and it is exactly the behaviour your ear wants. Here is why.

Recall from the synth lesson that loudness is not perceived linearly. Your ear hears ratios, on a logarithmic scale measured in decibels:

L = 20 · log₁₀( A / Aref ) perceived level in dB — a logarithm of the amplitude ratio, not the amplitude itself

Now feed an exponential amplitude A = e−t/τ into that dB formula and watch what happens to the perceived level:

L(t) = 20·log₁₀(e−t/τ) = 20·(−t/τ)·log₁₀(e) = −(8.686/τ)·t.
That is a straight line in time. An exponential fade in amplitude is a linear fade in decibels — so the ear hears it dropping at a perfectly steady rate. That is what sounds natural.
By contrast, a linear amplitude fade (A = 1 − t/T) plummets in dB at the start, then crawls forever near the end. It sounds like the note "drops fast, then refuses to die" — the classic amateur fade.
the takeaway

Use exponential ramps for decay and release, not linear ones. An exponential curve falls steadily to the ear; a linear curve fools your eye but sounds like it lingers. This is exactly why Web Audio gives you exponentialRampToValueAtTime — and why the attack, a quick snap your ear barely time-resolves, can stay linear.

03 four phases

A·D·S·R, defined precisely.

A bare exponential decay is enough for a pluck, but real notes are richer: they need to hold while a key is pressed, and to let go when released. The classic four-phase envelope handles all of it. It splits the gesture into Attack, Decay, Sustain, Release.

Three of the four are durations (in seconds); one is a level (a gain between 0 and 1). Here they are exactly:

A
Attack · duration

Time from note-on for the gain to rise from 0 to its peak (1.0). Short = percussive snap; long = a swell.

D
Decay · duration

Time for the gain to fall from the peak down to the sustain level. This is where the body of a struck note settles.

S
Sustain · level (0–1)

The held gain while the key stays down. The one parameter that is a level, not a time. S = 0 gives a pure pluck.

R
Release · duration

Time from note-off for the gain to fall from the sustain level back to silence. The tail of the note.

So the whole envelope is a path: rise over A → fall to S over D → hold at S for as long as the key is down → fall to zero over R. Two synths sound nothing alike not because their oscillators differ, but because their A/D/S/R differ. A pluck is fast A, short D, S ≈ 0, short R. A pad is slow A, gentle D, high S, long R. Same oscillator, opposite souls.

a(t) = { t/A · peak,   0 ≤ t < A } · { peak → S exp,   A ≤ t < A+D } · { S,   held } · { S → 0 exp,   release } attack linear; decay & release exponential; sustain a flat hold — the piecewise envelope
04 the whole envelope, by hand

Read the gain at every moment.

Let's grind one out so the numbers are real. Take a snappy synth-string envelope:

A = 5 ms  ·  D = 150 ms to S = 0.3  ·  R = 400 ms

Say the key is held down for 200 ms after the attack+decay finish, then released. We'll compute the gain at chosen timestamps. Attack is linear; decay and release are exponential.

Attack phase (linear from 0 to 1 over 5 ms):

At t = 0 ms: gain = 0 — silence, the instant before the note.
At t = 2.5 ms (halfway through attack): gain = 2.5/5 = 0.50.
At t = 5 ms: gain = 1.00 — peak reached. Attack done.

Decay phase — exponential from peak 1.0 down to S = 0.3 over D = 150 ms. We model it as gain(t') = 1.0 · (0.3/1.0)t'/D, where t' is time since decay began. (Equivalently, an exponential whose time constant is set so it lands on 0.3 exactly at the end of D.)

At decay start (t = 5 ms, t' = 0): gain = 1.0 · 0.30 = 1.00.
Halfway through decay (t' = 75 ms): gain = 0.30.5 = √0.3 ≈ 0.548. Already past halfway down — exponentials fall fast at first.
End of decay (t = 155 ms, t' = 150 ms): gain = 0.31 = 0.300 — the sustain level, reached.

Sustain phase — flat hold while the key is down. From t = 155 ms to t = 355 ms (our 200 ms hold), the gain sits at 0.300, unchanging. Then the key is released.

Release phase — exponential from S = 0.3 down toward 0 over R = 400 ms. We aim it at a tiny floor (say 0.001, since a true exponential never hits zero): gain(t″) = 0.3 · (0.001/0.3)t″/R, t″ = time since release.

At release start (t = 355 ms, t″ = 0): gain = 0.300.
Halfway through release (t″ = 200 ms): gain = 0.3 · (0.00333)0.5 ≈ 0.3 · 0.0577 ≈ 0.0173 — already very quiet, but audible as a tail.
End of release (t = 755 ms, t″ = 400 ms): gain ≈ 0.001 — effectively silent. The note is finished.
what the numbers tell you

The whole note lived for ~755 ms, but it reached full volume in just 5 ms. That tiny, sharp attack is precisely what your ear reads as "plucked / struck." Stretch the attack to 900 ms instead and the identical oscillator becomes a bowed pad — the table of numbers would simply ramp up slowly instead of snapping. Go draw exactly that in the editor below.

05 make the machine

The same shape, in two languages.

In the browser, you don't compute the envelope sample by sample — you schedule it. Web Audio's AudioParam lets you queue ramps on the gain node, and the audio engine renders them for you with sample-accurate timing. Each ADSR phase is one scheduled ramp:

JavaScript · Web Audio · scheduling an ADSR on a gain node
function playADSR(osc, gain, ctx, { A, D, S, R, hold, peak = 1 }) {
  const now = ctx.currentTime, g = gain.gain;
  const floor = 0.001;                 // exp ramps can't reach exactly 0
  g.cancelScheduledValues(now);
  g.setValueAtTime(floor, now);

  // A — attack: linear snap up to peak (ear can't resolve the shape here)
  g.linearRampToValueAtTime(peak, now + A);

  // D — decay: EXPONENTIAL fall to the sustain level (sounds steady in dB)
  g.exponentialRampToValueAtTime(Math.max(floor, S), now + A + D);

  // S — sustain: hold the level while the key is down
  g.setValueAtTime(Math.max(floor, S), now + A + D + hold);

  // R — release: EXPONENTIAL tail to silence
  g.exponentialRampToValueAtTime(floor, now + A + D + hold + R);
}

// a pluck: A=4ms, D=180ms, S=0, R=220ms  ·  a pad: A=900ms, S=0.7, R=1400ms

Offline — in NumPy, say, building a sound file — you instead generate the envelope as an array and multiply it sample-for-sample into the carrier. Same shape; you just realize it as numbers. This makes the multiplier idea a(t)·sin(2πft) literal:

Python · NumPy · build the envelope array, multiply the wave
import numpy as np

def adsr(A, D, S, R, hold, fs=44100, peak=1.0):
    # build each phase, then concatenate into one envelope array
    a = np.linspace(0, peak, int(fs * A))                # attack: linear
    d = peak * (S / peak) ** np.linspace(0, 1, int(fs * D))   # decay: exp peak→S
    s = np.full(int(fs * hold), S)                          # sustain: flat hold
    r = S * (1e-3 / S) ** np.linspace(0, 1, int(fs * R))   # release: exp S→0
    return np.concatenate([a, d, s, r])

# a struck synth string at 196 Hz (G3)
fs   = 44100
env  = adsr(A=0.005, D=0.15, S=0.3, R=0.4, hold=0.2)
t    = np.arange(len(env)) / fs
osc  = np.sin(2 * np.pi * 196 * t)              # the carrier
note = env * osc                                  # a(t) · sin(2πft) — the envelope IS a multiply
Python · NumPy · the simplest envelope of all — pure exponential decay
def pluck_env(n, tau=0.12, fs=44100):
    t = np.arange(n) / fs
    return np.exp(-t / tau)        # a(t) = e^(−t/τ): falls to 1/e at t=τ

# τ = 0.12 → after 0.12 s amplitude ≈ 0.37, after 0.36 s ≈ 0.05 (worked above)
draw a note, hear a note

Sculpt the shape. Play it.

Here is everything at once, in your hands. The curve below is a live ADSR envelope, and the four glowing handles let you sculpt it directly: drag the first handle to set the attack time, the second for decay (its height is the sustain level), the teal one to fine-tune sustain, and the last for release.

Underneath the curve you can watch the actual amplitude-modulated waveform — the carrier sin(2πft) squeezed under your envelope a(t). Press play note and the very same oscillator plays through the shape you drew. Drag it into a pluck, then into a pad, and hear how a single oscillator becomes two instruments.

presets →
this is a shaped note
A = D = S = R =
attack handle ⟶ time to peak decay handle ⟶ time & sustain height sustain handle ⟶ held level release handle ⟶ tail length

The dashed outline on the lower waveform is your envelope, traced as the ceiling the wave can't cross — that's |output| ≤ a(t) made visible.

this is the merge — one signal, three arts

Music (Ableton): you draw the articulation by hand and feel a pluck become a pad. Math (Stanford): the curve is literally a(t) in a(t)·sin(2πft), scheduled as linear and exponential ramps with the time constants you computed. Art (Nature of Code): the envelope is the hull the sound is poured into, and the playhead is a point riding that hull in real time. The shape you see is the loudness you hear.

And this is exactly what brought the synth lesson's tone to life. Back there, every note snapped on and off. Wrap that same oscillator in an envelope and it breathes — it plucks, it bows, it swells. The oscillator was the voice; the envelope is the phrasing.

One question remains. The envelope shaped how much sound came through over time — but it never changed the sound's color. Real instruments get brighter as they're struck and darker as they fade. To do that, you point an envelope at a filter instead of the volume — a filter envelope. That's the next lesson, and you already hold the key idea: an envelope is just a controllable curve over time, and you can aim it at any knob.

See the Play track → (filters next)

The oscillator gives a note its pitch. The envelope gives it its life.

Sources go deeper

Xavier Serra et al., Audio Signal Processing for Music Applications (Stanford / UPF, Coursera) — amplitude, envelopes, and the dB scale. · Ableton, Learning Synths — the ADSR interaction grammar. · MDN, AudioParamlinearRampToValueAtTime & exponentialRampToValueAtTime, the ramps behind every panel.

← Back to Reverbs