Reverbs · Play track

LFOs &
modulation

Put one wobble in charge of another. Slow, you hear movement — a singer's vibrato, a pulsing pad. Speed it up and something uncanny happens: the movement vanishes and a whole new tone takes its place. That doorway is FM synthesis. Let's walk through it.

Scroll to begin
00 a second wobble

One oscillator steering another.

In How Synths Make Sound you built a single oscillator — a thing that wobbles a number up and down very fast, and that wobble, pushed into the air, is a note. One oscillator gives you a steady, dead-still tone. Beautiful, but lifeless.

Real instruments are never still. A violinist's finger trembles and the pitch shivers with it. A tremolo guitar pedal makes the volume pulse. The trick behind both is the same, and it is almost embarrassingly simple: take a second, much slower oscillator and let it nudge a setting of the first one.

That slow second oscillator has a name: a Low-Frequency Oscillator, or LFO. "Low-frequency" because it wobbles only a few times per second — far below the ~20 Hz floor of human hearing, so you never hear the LFO itself. You hear only its effect on the note: the pitch sliding, the volume breathing.

The LFO doesn't make sound. It makes change. Whatever knob you point it at, it grabs that knob and turns it back and forth, gently, over and over.

what this lesson covers

Vibrato (an LFO on pitch) and tremolo (an LFO on volume); the modulation-index idea; the single reveal that slow modulation is behavior and fast modulation is timbre; the product-to-sum identity that explains why new frequencies — sidebands — appear; a worked example at 440 Hz; the same thing in JavaScript and in NumPy; and a playable pad where you drag rate and depth and watch the sidebands bloom in a live spectrum.

01 vibrato

Point the wobble at pitch.

Start with the most musical target: pitch. We let the LFO add a small, swinging amount to the carrier's frequency. "Carrier" is just the name for the oscillator carrying the note you actually hear; the LFO is the modulator.

If the carrier wants to sit at frequency f_c, and the LFO swings up and down f_lfo times a second with a peak swing of A hertz, then the carrier's instantaneous frequency at time t is no longer a constant — it breathes:

f(t) = fc + A · sin(2π · flfo · t) the carrier's frequency is its rest value f_c plus a swing of ±A, oscillating f_lfo times a second

Read it slowly. f_c is where the pitch lives at rest. The sin(2π·f_lfo·t) rides between −1 and +1, so the term A·sin(…) rides between −A and +A. The whole frequency therefore wanders between f_c − A at the bottom of each swing and f_c + A at the top. That gentle up-and-down of pitch is exactly what your ear calls vibrato.

Two knobs, two feelings. f_lfo — the rate — is how fast the pitch wavers: a lazy 4 Hz sigh or a nervous 8 Hz flutter. A — the depth — is how far the pitch swings: a few cents of shimmer or a wide, seasick wobble.

Let's make it concrete with a hand-worked example before you touch anything.

Carrier at f_c = 440 Hz (the note A4). LFO rate f_lfo = 5 Hz, depth A = 10 Hz. So the pitch will breathe five times a second, between 440 − 10 = 430 Hz and 440 + 10 = 450 Hz.
At t = 0: sin(0) = 0, so f(0) = 440 + 10·0 = 440 Hz — passing through rest.
A quarter of an LFO cycle later, at t = 0.05 s (one quarter of 1/5 s): sin(2π·5·0.05) = sin(π/2) = 1, so f = 440 + 10·1 = 450 Hz — the top of the swing.
Three quarters in, at t = 0.15 s: sin(2π·5·0.15) = sin(3π/2) = −1, so f = 440 − 10 = 430 Hz — the bottom. Then it climbs back. That ±10 Hz dance, five times a second, is the vibrato you'll hear.
one object, three languages

Mathematician: we have made the argument of a sine itself time-varying — f is now a function of t, the seed of frequency modulation. Musician: that wandering frequency is vibrato, the single most human gesture a held note can make. Artist: on a scope the wave stops being a rigid grid and starts to shiver — it breathes in and out as the cycles squeeze and stretch. Same equation, three ways of knowing it.

Below is that pad. Press it to start the note, then drag: left ↔ right is the LFO rate, up ↕ down is the depth. Keep it on the left half for now — slow rates — and feel the pitch sway. We'll cross the line on the right in Chapter 3.

← slow rate~20 Hz boundaryfast rate →
↑ deeper swing · ↓ no modulation
rate depth

The top trace is the live carrier waveform; the bottom strip is its live spectrum — the same DFT you met in the Signal track, running 60 times a second. Keep an eye on it as you drag right later.

02 tremolo

Now point it at loudness.

Move the LFO from the pitch knob to the volume knob and you get the other classic gesture: tremolo — the throbbing pulse of a Rhodes piano or a surf-rock guitar. Same modulator, different target.

Here the LFO multiplies the carrier's amplitude. We don't want the volume to go negative (that would just flip the wave's phase, which sounds odd), so we center the LFO around 1 and let it swing by a depth m between 0 and 1:

a(t) = ( 1 + m · sin(2π · flfo · t) ) the amplitude multiplier rides between 1−m and 1+m; m is the tremolo depth

The actual sound is this multiplier times the carrier wave:

x(t) = ( 1 + m · sin(2π flfo t) ) · sin(2π fc t) amplitude-modulated tone: a steady carrier whose loudness is pumped by the LFO

m is the modulation depth. At m = 0 the multiplier is a flat 1 — no tremolo, dead-steady volume. At m = 1 the multiplier swings all the way from 0 (total silence) up to 2 (double loud) — a dramatic, fully-pumping throb. Work the corners:

Depth m = 0.5, top of the swing (sin = +1): multiplier = 1 + 0.5·1 = 1.5 — 50% louder than rest.
Same depth, bottom of the swing (sin = −1): multiplier = 1 − 0.5 = 0.5 — half as loud. So the sound pulses between 50% and 150% loudness.
Full depth m = 1, bottom (sin = −1): multiplier = 1 − 1 = 0 — the note momentarily disappears. That's the chop of hard tremolo.

Here is the crucial difference from vibrato, and it is the hinge of the whole lesson. Vibrato bent the argument of the carrier's sine — it changed how fast the wave goes. Tremolo instead multiplies two waves together — the slow LFO times the fast carrier. And a product of two sines is not just "a louder sine." It is, secretly, a sum of different frequencies. Hold that thought; in Chapter 4 we'll pull it apart algebraically and watch new tones fall out.

03 the boundary

Speed it up until movement becomes tone.

Go back to the pad and do one experiment slowly, by hand, with your ear. Start the note. Put the LFO at a few hertz. You hear obvious vibrato — the pitch visibly, audibly swaying. Now drag right: 8 Hz, a nervous flutter. 12 Hz, a buzz you can almost count. 16 Hz, a blur. And then — somewhere around 20 Hz — something tips over.

The wobble stops being a wobble. You no longer hear pitch moving. Instead the sound takes on a hard, metallic, hollow new color. The vibrato has become a timbre.

Why exactly there? Because ~20 Hz is the floor of human pitch perception. Below it, your auditory system tracks each individual swing as an event in time — it hears movement. Above it, the swings come too fast to follow one by one, so your brain stops hearing "change" and starts fusing the whole thing into a single steady sound with a richer spectrum. The modulation didn't change its math. Your ear changed its mind.

the one sentence to remember

Slow modulation is heard as behavior; fast modulation is heard as timbre. A 5 Hz pitch-wobble is vibrato you can feel; the same mechanism at 200 Hz is a new instrument's voice. Crossing ~20 Hz is the doorway from "an effect on a note" to "a way of inventing tones" — the doorway into FM and AM synthesis.

below ~20 Hz · behavior

You count the swings. Pitch slides; volume pulses. This is the Play world of vibrato, tremolo, slow filter sweeps. The spectrum looks like one note jittering.

above ~20 Hz · timbre

The swings fuse. A bright, bell-like, sometimes clangorous tone appears. The spectrum sprouts new fixed peaks — sidebands — that weren't in either oscillator alone. This is synthesis.

Scroll up to the pad and try it for real: drag from the left edge to the right, slowly, listening for the moment it flips. Watch the dashed teal line marked ~20 Hz — that's the boundary. On the right, watch the spectrum: where there was one peak, several appear. Those new peaks have a name, and a beautifully simple cause.

04 sidebands

Where the new frequencies come from.

Let's prove the magic. We'll take the simplest fast-modulation case — amplitude modulation, where the math is exact and clean — and watch new frequencies fall out of pure algebra. Strip the tremolo expression down to its heart: a modulator sine times a carrier sine.

product = sin(2π fc t) · sin(2π fm t) the carrier wave multiplied by the (now audio-rate) modulator wave

It looks like one tangled wave. But there is a centuries-old trigonometric identity — the product-to-sum formula — that says a product of two sines is exactly equal to a difference of two cosines at the sum and difference frequencies:

sin(2π fc t) · sin(2π fm t) = ½[ cos(2π(fc−fm) t) − cos(2π(fc+fm) t) ] the heart of AM: one product becomes two new pure tones, at f_c−f_m and f_c+f_m

This is the most important equation in the lesson, so let's derive it, not just assert it. Start from the two angle-addition formulas for cosine, which you can take as known:

Write the two cosine identities, with α = 2πf_c t and β = 2πf_m t:
cos(α − β) = cos α cos β + sin α sin β
cos(α + β) = cos α cos β − sin α sin β
Subtract the second from the first. The cos α cos β terms cancel, and the two sin α sin β terms add:
cos(α − β) − cos(α + β) = 2 · sin α sin β
Divide both sides by 2 and read it backwards — that is the product:
sin α sin β = ½[ cos(α − β) − cos(α + β) ]
Substitute the angles back. α − β = 2π(f_c − f_m)t and α + β = 2π(f_c + f_m)t. Done — the product of two sines is two cosines, one at the difference frequency f_c − f_m and one at the sum frequency f_c + f_m.

The original carrier frequency f_c has vanished from the product entirely; in its place sit two brand-new tones flanking it. These two new tones are the sidebands. (Tremolo's full formula, (1 + m·sin)·sin(f_c), keeps the carrier too — the 1·sin(f_c) term — so AM gives you three peaks: the carrier in the middle, a sideband on each side.)

Now nail it with numbers. The lesson's worked case:

Carrier f_c = 440 Hz. Modulator f_m = 110 Hz — well above the 20 Hz boundary, so this is timbre, not vibrato.
Lower sideband, the difference: f_c − f_m = 440 − 110 = 330 Hz.
Upper sideband, the sum: f_c + f_m = 440 + 110 = 550 Hz.
So multiplying a 440 Hz carrier by a 110 Hz modulator produces energy at 330 Hz and 550 Hz (and, with the full tremolo formula, the original 440 Hz between them). Three sine waves where you started with two — and not one of the three is at the modulator's own 110 Hz. New tone, from a product.
see it on the pad

Scroll to the pad, drag the rate above 20 Hz, and watch the spectrum: the dashed teal markers labelled f_c−f and f_c+f show exactly where the math says the sidebands must land, and the live DFT bars grow up to meet them. The equation you just derived is drawing itself in real time.

That was amplitude modulation: a clean product, exactly two sidebands. Frequency modulation — the vibrato of Chapter 1 pushed past 20 Hz — is richer. Instead of two sidebands, FM produces a whole stack of them, spaced evenly at f_c ± f_m, f_c ± 2f_m, f_c ± 3f_m, …, with heights given by Bessel functions of the modulation index β = A / f_m (peak frequency swing over modulator rate). We won't grind the Bessel math here — that's a lesson of its own — but the intuition is everything you need:

β = A / fm modulation index: how many sideband pairs are loud — small β ≈ two sidebands (≈ AM), large β = a dense bright stack

When β is tiny, only the first pair of sidebands matters and FM looks almost like AM. As you crank the depth (raising β), more and more sideband pairs light up and the tone gets brighter and more complex — which is precisely what made the Yamaha DX7's FM presets sound so glassy and metallic. On the pad, the vertical axis (depth) is your β control: drag up, at a fast rate, and watch the stack thicken.

05 now make the machine

Modulation in two languages.

The beautiful thing about Web Audio is that an AudioParam — like an oscillator's frequency or a gain's gain — can itself be the destination of another node. Connect a second oscillator into the carrier's frequency and you have built f(t) = f_c + A·sin(2π f_lfo t) in hardware-accelerated audio, with no per-sample loop of your own. This is exactly what the pad above does:

JavaScript · Web Audio · vibrato → FM
const ctx = new AudioContext();

// the carrier — the note you hear
const carrier = ctx.createOscillator();
carrier.frequency.value = 440;        // f_c

// the LFO / modulator — a second oscillator
const lfo = ctx.createOscillator();
lfo.frequency.value = 5;             // f_lfo: 5 Hz = vibrato. Push to 110 = FM.

// the "depth" gain scales the unit LFO (±1) into Hz of swing (±A)
const depth = ctx.createGain();
depth.gain.value = 10;              // A = ±10 Hz of pitch swing

// LFO → depth → the carrier's FREQUENCY param. This IS f_c + A·sin(2π f_lfo t)
lfo.connect(depth);
depth.connect(carrier.frequency);

carrier.connect(ctx.destination);
carrier.start(); lfo.start();
// raise lfo.frequency past 20 → vibrato becomes timbre; sidebands appear.

For tremolo (amplitude modulation) the wiring is the same shape, but the LFO drives a gain instead of a frequency. We bias the gain to sit at 1 and let the LFO swing it by the depth m:

JavaScript · Web Audio · tremolo → AM
const amp = ctx.createGain();
amp.gain.value = 1;                 // the bias: the "1 +" in (1 + m·sin)

const lfo = ctx.createOscillator();
lfo.frequency.value = 6;             // 6 Hz tremolo; past 20 → AM sidebands
const m = ctx.createGain();
m.gain.value = 0.5;                // modulation depth m

lfo.connect(m);
m.connect(amp.gain);             // gain(t) = 1 + 0.5·sin(2π·6·t)

carrier.connect(amp);
amp.connect(ctx.destination);
carrier.start(); lfo.start();

And here is the same idea at the sample level in NumPy, where the formulas from Chapters 1, 2 and 4 become literal array arithmetic. Synthesize, then run an FFT and you will find the sidebands at 330 and 550 Hz exactly where the algebra predicted:

Python · NumPy · build the modulated samples
import numpy as np

fs  = 44100
t   = np.arange(fs) / fs          # 1 second of time, sample by sample
f_c = 440.0                        # carrier

# ── VIBRATO / FM: a time-varying frequency. We integrate the frequency to
# get phase, because phase is the running total of frequency over time. ──
def fm(f_lfo, A):
    inst_freq = f_c + A * np.sin(2*np.pi*f_lfo*t)   # f(t) = f_c + A·sin(…)
    phase     = 2*np.pi * np.cumsum(inst_freq) / fs   # ∫ f dt, discretely
    return np.sin(phase)

vibrato = fm(5,   10)    # 5 Hz, ±10 Hz  → you HEAR it move (behavior)
fm_tone = fm(110, 220)   # 110 Hz, deep   → a bright FM timbre (sidebands)

# ── TREMOLO / AM: literally  (1 + m·sin) · carrier ──
def am(f_lfo, m):
    return (1 + m*np.sin(2*np.pi*f_lfo*t)) * np.sin(2*np.pi*f_c*t)

am_tone = am(110, 1.0)   # carrier 440, modulator 110

# prove the sidebands: peaks at 330 and 550 Hz (and 440 in the middle)
X    = np.fft.rfft(am_tone)
freq = np.fft.rfftfreq(len(am_tone), 1/fs)
peaks = freq[np.argsort(np.abs(X))[-3:]]   # ≈ [330., 440., 550.]
why FM needs phase, not frequency

Notice the NumPy FM trick: we couldn't just write sin(2π·f(t)·t) — that's wrong, because frequency is the rate of change of phase, not phase itself. The honest move is to build the instantaneous frequency, then accumulate it (cumsum, a discrete integral) into phase, then take the sine of that. Web Audio's node graph does this integration for you internally — which is why the JS version is so short.

play it

Drag the doorway open.

Everything is in one gesture now. The pad you've been visiting is the whole lesson as an instrument: horizontal is the LFO rate, vertical is the depth. Start on the far left, deep, and you have lush vibrato — pure Play-track behavior, the singer's quiver. Drag steadily right and cross the dashed ~20 Hz line: the wobble dissolves and a bright synthetic tone takes its place, with sidebands the live spectrum draws for you. Drag up while you're over there and watch the sideband stack thicken — that's the modulation index β climbing.

You didn't switch instruments. You didn't add an effect. You took one slow oscillator steering another and simply sped it up. The same three numbers — carrier, rate, depth — that made vibrato made an entire new voice. That is the secret the Yamaha DX7 sold a hundred thousand copies of.

this is the merge — sound, math, art as one

Music (Ableton): you steer rate and depth by hand and hear vibrato melt into timbre. Math (Stanford): the bright new tone is literally the sidebands of ½[cos(f_c−f_m) − cos(f_c+f_m)] you derived — and the spectrum strip is a live DFT pulling them straight back out of the air. Art (Nature of Code): the carrier waveform shivers and the spectrum blooms; the picture is the equation is the sound. Cross 20 Hz and you can watch all three change their minds at once.

Scroll back up to the pad to keep playing — it's the same live instrument. When you're ready, two threads lead onward.

Open the full Reverbs index →

The same wobble, sped up past hearing, stops being movement and becomes a voice.

where this goes
next on the Play track · Envelopes

An LFO modulates a parameter forever, periodically. An envelope modulates it once, in a shape — attack, decay, sustain, release. Same idea (a controller steering a knob over time), but one-shot instead of cyclic. That's how a note is born and dies.

back to the Signal track · the DFT

Every sideband you watched bloom is a peak the Discrete Fourier Transform reads. Fast modulation literally writes the spectra the DFT decodes — synthesis and analysis, the two directions of one machine, meeting here.

Sources go deeper

Xavier Serra et al., Audio Signal Processing for Music Applications — modulation, sinusoidal models & the spectrum (Stanford / UPF). · Ableton, Learning Synths — the LFO & the behavior→timbre reveal as interaction. · John Chowning, "The Synthesis of Complex Audio Spectra by Means of Frequency Modulation" (1973) — the paper that turned vibrato into FM synthesis. · MDN, Web Audio API — connecting a node to an AudioParam, the engine under the pad.

← Back to Reverbs