How Machines Hear Pitch

Five methods and the sounds that expose their differences.

When you drop a sample into Scala Creator, an algorithm has to answer a deceptively hard question: what note is this? This page walks through the five methods we evaluated — no math required, though it's hiding under the hood if you want it. Every demo makes sound, so headphones on.

Chapter 1

What is pitch, anyway?

🎧 Think of: a plucked guitar string

Almost every pitched sound in the natural world is a stack of pure tones called partials, all sounding at once. A guitar string is the kind of sound most pitch algorithms were built around: its partials sit at neat whole-number multiples of the lowest one — 1×, 2×, 3×, 4×. Stacks like that are called harmonic, and they add up to a waveform that repeats over and over, like a loop.

The lowest partial is the fundamentalf₀. Think of the partials as singers holding one chord. The others sing at exact multiples of the lowest voice's speed, so they all draw breath at the same instant. That shared breath is the waveform's repeat.

Pitch is not one of the singers. It's the name you'd give what you heard — one note, not seven. Your ear does the blending for free, and for harmonic sounds it always names the lowest voice. Which is why the two words get used as if they were one.

A struck bronze bar — a saron in a Javanese gamelan — follows different physics. Its partials can sit at ratios like 1 : 2.76 : 5.40. Nothing lines up, so the waveform never repeats — and standard assumptions in the math behind a particular algorithm can fall apart. Thusly, some methods will reliably find the pitch of 'smoother' sounding harmonic instruments, while others will do better on 'metallic', inharmonic ones.

Partial mixer — build a sound, watch its waveform

Spectrum view: each spike is one partial. The faint grid lines mark perfect whole-number multiples — in harmonic mode the spikes sit on them; in saron mode they land in between.

Under the hood: partials, harmonics & inharmonicity

A harmonic sound has partials at frequencies fk = k·f0 for k = 1, 2, 3… The common period is 1/f0, so the waveform is periodic and the ear (and most algorithms) reads f0 as the pitch.

A free bar vibrating transversely (the saron model) has mode frequencies scaling roughly with the square of odd integers, giving ratios near:

f₁ : f₂ : f₃ : f₄ ≈ 1.00 : 2.76 : 5.40 : 8.93

Those figures come from Jim Woodhouse's Euphonics §3.2, which lists the free–free bending modes as 1.00, 2.76, 5.40, 8.93, 13.34 and notes that "none of the ratios are very close to whole numbers."

No common divisor → no period → the sum of these sines is quasi-periodic at best. Research on gamelan instruments (McLachlan, Marco & Wilson 2013, Frontiers in Psychology 4:768) shows makers tune the lowest partial precisely — sister instruments within about 2 Hz of each other, while upper partials vary widely — and listeners' perceived pitch tracks it. The upper partials are timbre, not pitch.

Chapter 2 · Family one: time-domain

"Does the wave repeat?"

🎧 Think of: tracing a wallpaper pattern to find where it starts over

The first family of methods never looks at frequencies at all. It takes the waveform, slides a copy of it forward in time, and asks: how far do I have to slide before it lines up with itself again? That slide distance is the period, and one-over-the-period is the pitch.

Try it yourself. Drag the slider to slide the ghost copy. On the harmonic sound you'll find spots where the match score jumps toward 100% — that's the wave repeating. Then switch to the saron bar and try to find one.

Slide-to-match — you are the algorithm
0%

Method 1 · NSDF / McLeod time-domain

Computes that match score at every lag automatically (the curve above), then picks a peak. Scala Creator's current engine. It picks the tallest peak, because on rich metallic gamelan sounds the true note reliably wins — a deliberate tweak to the textbook recipe. Accurate to about 1 cent on clean tones, cheap enough to run live in the browser.

Method 2 · YIN & pYIN time-domain

The same core idea, measured as mismatch instead of match: it looks for the first lag where the difference dips near zero. pYIN adds a probabilistic layer that smooths a melody over time — great for singing, not much help for one struck note. Both inherit the family weakness: no repetition, nothing to find.

Under the hood: autocorrelation, NSDF & YIN

Autocorrelation multiplies the signal by a delayed copy of itself and sums:

r(τ) = Σ x(t) · x(t + τ)

NSDF (the McLeod Pitch Method, from McLeod & Wyvill 2005) normalizes it so the score always lives between −1 and +1 regardless of loudness:

n(τ) = 2·Σ x(t)·x(t+τ)  /  Σ [x(t)² + x(t+τ)²]

The peak height doubles as a clarity measure — how tone-like the sound is. Canonical MPM picks the first major peak; Scala Creator picks the global maximum, which avoids spurious low-frequency candidates on metallic timbres but is riskier on other material.

YIN (de Cheveigné & Kawahara 2002) instead computes a difference function d(τ), normalizes it cumulatively, and takes the first dip below a threshold (≈0.15). pYIN (Mauch & Dixon 2014) runs it across a distribution of thresholds and Viterbi-decodes the candidates into a smooth track. Published accuracy for both is ±1–2 cents — on harmonic test sets. On inharmonic sounds, the failure isn't precision, it's picking the wrong partial entirely.

Chapter 3 · Family two: frequency-domain

"Where is the energy?"

🎧 Think of: an EQ analyzer bouncing in your DAW

The second family gives up on repetition entirely. It runs the sound through a Fourier transform — the same math behind every EQ display — and simply reads where the spectral peaks are. No repeating waveform required. For a gamelan bar, the lowest strong peak is the pitch the maker tuned and the ear hears.

Explore the spectra below. Hover or tap the peaks. Notice the bell: its perceived note (the "strike note") sits where there's no peak at all — your brain invents it from the partials above. That's why no naive rule survives every instrument.

Spectrum explorer — tap a peak to hear & inspect it
Hover a peak…

The zoom trick — finding a peak between the pixels

An FFT chops the frequency axis into bins, like pixels. A real partial usually lands between two bins — and for tuning files we need cents-level precision, far finer than the bins. The fix is lovely: fit a curve (a parabola) through the tallest bin and its two neighbours, and read the curve's tip. Drag the slider to move the true frequency around and watch the estimate follow it.

Method 3 · Interpolated FFT frequency-domain

The two panels above, combined: find the lowest strong spectral peak, refine it with the parabola trick. Accuracy well under 1 cent, and it doesn't care whether the sound is harmonic. This is the recommended future engine for Scala Creator's inharmonic uploads. Its one weakness — grabbing an upper partial by mistake — is fenced off with a frequency-range control.

Method 4 · Cepstrum frequency-domain

A clever speech-processing trick: it measures the spacing between spectral peaks. Brilliant when peaks are evenly spaced — which is exactly what harmonic sounds have and gamelan sounds don't. The instructive part is that it doesn't fall silent on a saron: it averages spacings that were never equal and hands back a confident spike at a period no partial has. Included here as the wrong tool, and as a lesson in output that looks like an answer.

Method 4 in action — cepstrum of the guitar-like tone

The cepstrum doesn't look for peaks — it looks for the rhythm of the peaks. Evenly spaced partials make the spectrum ripple, and that ripple shows up here as one tall spike whose position is the period of the note. Switch instruments and watch what happens to the spike. The dashed line marks where it should land if the lowest partial is the pitch.

shares the selection with the spectrum explorer above

Under the hood: QIFFT & the cepstrum

The quadratically-interpolated FFT is set out in Julius O. Smith III's Spectral Audio Signal Processing (CCRMA, Stanford). With the peak bin k and its neighbours' dB magnitudes y₋₁, y₀, y₊₁, the parabolic offset from the bin centre is:

δ = ½ · (y₋₁ − y₊₁) / (y₋₁ − 2y₀ + y₊₁),   f ≈ (k + δ) · sampleRate / N

With zero-padding, error drops below 0.1% of frequency — sub-cent for a clean partial. One practical note: the Web Audio AnalyserNode's default FFT is far too coarse for this; a custom zero-padded FFT is required.

The cepstrum is the inverse FFT of the log-magnitude spectrum. Evenly spaced harmonics create a ripple in the log spectrum whose "frequency" (called quefrency) equals the pitch period — it shows up as one sharp cepstral peak. Uneven inharmonic partials produce no coherent ripple — but note what that does not mean. The transform still returns something: a peak at whatever period best fits mutually incompatible spacings, or, where partials are near-integer multiples, a peak at a genuine periodicity that isn’t the perceived pitch. Absence of structure produces a wrong reading, not a blank one, which is why the panel above is worth switching through.

Chapter 4 · The outsider

Method 5 · CREPE, the neural network

🎧 Think of: a session musician with perfect pitch — trained only on pop records

CREPE belongs to neither family. It's a deep neural network that was shown millions of examples of pitched audio with known answers, and learned to guess. For each slice of sound it lights up a row of 360 pitch "bins", each 20 cents wide — its confidence for every possible note.

What CREPE's output looks like

Why it's tempting data-driven

State-of-the-art accuracy on voices and harmonic instruments — 99.5% of frames within 10 cents on its RWC-Synth benchmark (Kim, Salamon, Li & Bello 2018). Astonishing on the material it was trained on.

Why it's not the engine data-driven

It never studied for this exam: the training data contains essentially no inharmonic idiophones, and its own authors note "noisy results for uncommon instruments." Its bins are 20 cents wide — coarse for tuning work — and the full model is ~89 MB, heavy for a browser. Verdict in the notes: an optional, clearly-labelled cross-check. Never the source of truth for a tuning file.

Chapter 5 · The payoff

The showdown: five methods, four instruments

🎧 Think of: five friends guessing the note of a gong — and arguing

Pick an instrument, listen to it, then reveal how each method fares. The verdicts below are a scripted illustration — a summary of the research and testing behind Scala Creator, not a live computation — but every sound you hear is really synthesized from the physics ratios of that instrument.

MethodVerdictWhy
Under the hood: where the verdicts come from

Saron bars, genders and slenthems vibrate like free bars (modal ratios ≈ 1 : 2.76 : 5.40 : 8.93, per Woodhouse, Euphonics §3.2); McLachlan, Marco & Wilson (2013) show makers tune the lowest partial to within ~2 Hz across an ensemble while upper partials vary widely — so "lowest strong partial" is the physically and perceptually correct target.

A bossed gong's central boss forces two principal modes into a near-2:1 relationship (Rossing & Shepherd, "Acoustics of gamelan instruments," Percussive Notes 1982), and on some gongs the pitch-bearing partial is the 2nd or 3rd — which is why the spectral method needs a frequency-range fence rather than a blind "lowest peak" rule.

A bell's strike note is a virtual pitch: the ear constructs it from the nominal, superquint and octave-nominal partials, landing near nominal ÷ 2 — a frequency where there may be no partial at all. Bill Hibbert's The Sound of Bells documents the effect and the measurements behind it. Every naive method misses it; handling bells needs a dedicated strike-note mode.

The spectral-matching alternative to all of this is SWIPE (Camacho & Harris 2008), which fits a sawtooth template to the spectrum — a reasonable middle ground, though still harmonic-template-based and so not ideal for strongly inharmonic material.

Full citations and the complete engineering plan live in PITCH_DETECTION_NOTES.md.