@audio/pitch

Pitch detection (F0 estimation). YIN, McLeod, pYIN, autocorrelation, AMDF, HPS, cepstrum, SWIPE.
Time-domainYIN — cumulative mean normalized difference | SpectralHPS — harmonic product spectrum |
Chroma, chord and key detection moved to @audio/mir (
mir-chroma,mir-chord,mir-key).
Install
npm install @audio/pitch
Usage
import { yin, mcleod } from '@audio/pitch'
let fs = 44100
let frame = new Float32Array(2048) // fill from your audio source
let result = yin(frame, { fs })
// → { freq: 440.1, clarity: 0.97 } or null
Works in Node.js and browser. No Web Audio API needed — operates on raw
Float32Arraysamples.
Sliding windows — call repeatedly as new samples arrive:
let hop = 512
for (let i = 0; i + 2048 <= samples.length; i += hop) {
let frame = samples.subarray(i, i + 2048)
let result = yin(frame, { fs })
if (result) console.log(i / fs, result.freq.toFixed(1))
}
Harmony pipeline — chroma → chord → key lives in @audio/mir:
import { chroma, chord, smoothChords, key } from '@audio/mir'
let frames = []
for (let i = 0; i + 4096 <= samples.length; i += 2048) {
frames.push(chroma(samples.subarray(i, i + 4096), { fs, method: 'nnls' }))
}
let chords = smoothChords(frames, { selfProb: 0.5 })
let k = key(frames)
API
All pitch algorithms return { freq, clarity } | null:
freq— fundamental frequency in Hzclarity— algorithm-specific confidence in[0, 1]null— no periodic structure found (silence, noise, polyphony)
Time-domain algorithms (YIN, McLeod, pYIN, autocorrelation, AMDF) accept any buffer length. Spectral algorithms (HPS, cepstrum, SWIPE) require power-of-2 length.
Each algorithm is also installable standalone: npm install @audio/pitch-yin etc.
YIN
de Cheveigné & Kawahara, 2002. The reference algorithm for monophonic pitch estimation. Most cited, most tested, most robust.
import yin from '@audio/pitch-yin'
let result = yin(samples, { fs: 44100 })
| Param | Default | |
|---|---|---|
fs |
44100 |
Sample rate (Hz) |
threshold |
0.15 |
CMND threshold — lower = stricter, fewer detections |
Use when: General-purpose monophonic pitch tracking — speech, singing, solo instruments. The most reliable choice when in doubt.
Not for: Polyphonic audio (returns dominant or null), real-time with hard latency budgets (needs full window).
Ref: de Cheveigné & Kawahara, "YIN, a fundamental frequency estimator for speech and music", JASA 2002.
Complexity: $O(N^2/4)$ — two nested passes over half the window.
McLeod
McLeod & Wyvill, 2005. Normalized square difference with smarter peak picking. Handles smaller windows — good for vibrato and fast pitch changes.
import mcleod from '@audio/pitch-mcleod'
let result = mcleod(samples, { fs: 44100 })
| Param | Default | |
|---|---|---|
fs |
44100 |
Sample rate (Hz) |
threshold |
0.9 |
Peak selection threshold as fraction of global max |
Use when: Vibrato tracking, small hop sizes, singing voice where YIN occasionally double-triggers.
Not for: Highly noisy signals (NSDF is less thresholded than YIN's CMND).
Ref: McLeod & Wyvill, "A smarter way to find pitch", ICMC 2005.
Complexity: $O(N^2/4)$ — same asymptotic cost as YIN.
pYIN
Mauch & Dixon, 2014. Probabilistic YIN — runs YIN at multiple thresholds weighted by a Beta(2, 18) prior, producing a distribution over candidate pitches instead of a single hard pick. More robust than YIN on ambiguous frames.
import pyin from '@audio/pitch-pyin'
let result = pyin(samples, { fs: 44100 })
// → { freq: 440.1, clarity: 0.92, candidates: [{ freq: 440.1, prob: 0.85 }, ...] }
| Param | Default | |
|---|---|---|
fs |
44100 |
Sample rate (Hz) |
minFreq |
50 |
Minimum detectable frequency (Hz) |
maxFreq |
2000 |
Maximum detectable frequency (Hz) |
Use when: Ambiguous pitched content — breathy vocals, noisy recordings, or when you need a pitch posterior for downstream HMM tracking.
Not for: Clean signals where YIN already works well (pYIN is ~10× slower due to multi-threshold sweep).
Ref: Mauch & Dixon, "pYIN: A Fundamental Frequency Estimator Using Probabilistic Threshold Distributions", ICASSP 2014.
Autocorrelation
Normalized autocorrelation — the simplest pitch estimator. Educational baseline.
import autocorrelation from '@audio/pitch-autocorrelation'
let result = autocorrelation(samples, { fs: 44100 })
| Param | Default | |
|---|---|---|
fs |
44100 |
Sample rate (Hz) |
threshold |
0.5 |
Minimum normalized autocorrelation value to accept |
Use when: Learning, quick prototypes, signals with strong dominant periodicity and low noise.
Not for: Production — octave errors are common without additional heuristics.
Ref: Rabiner, "Use of autocorrelation analysis for pitch detection", IEEE TASSP 1977.
Complexity: $O(N^2/4)$.
AMDF
Ross et al., 1974. Average Magnitude Difference Function — the classical predecessor to YIN. Measures average absolute difference between a signal and its delayed copy; minima indicate periodicity.
import amdf from '@audio/pitch-amdf'
let result = amdf(samples, { fs: 44100 })
| Param | Default | |
|---|---|---|
fs |
44100 |
Sample rate (Hz) |
minFreq |
50 |
Minimum detectable frequency (Hz) |
maxFreq |
2000 |
Maximum detectable frequency (Hz) |
threshold |
0.3 |
Normalized AMDF dip threshold |
Use when: Low-complexity environments, embedded systems. Simpler and cheaper than YIN (no squaring, no cumulative normalization).
Not for: Noisy signals — lacks YIN's cumulative normalization that suppresses octave errors.
Ref: Ross et al., "Average magnitude difference function pitch extractor", IEEE TASSP 1974.
Complexity: $O(N^2/4)$.
HPS
Schroeder, 1968. Harmonic Product Spectrum — multiplies the spectrum by its downsampled copies so that harmonic peaks align at the fundamental. Robust to the missing-fundamental problem.
import hps from '@audio/pitch-hps'
let result = hps(samples, { fs: 44100 })
| Param | Default | |
|---|---|---|
fs |
44100 |
Sample rate (Hz) |
harmonics |
5 |
Number of harmonic products |
minFreq |
50 |
Minimum detectable frequency (Hz) |
maxFreq |
4000 |
Maximum detectable frequency (Hz) |
cents |
10 |
Candidate spacing in cents |
threshold |
0.1 |
Minimum clarity to accept |
Use when: Harmonic-rich signals (guitar, piano, brass). Naturally handles missing fundamentals.
Not for: Pure sinusoids (only one harmonic), very noisy signals.
Ref: Schroeder, "Period histogram and product spectrum", JASA 1968.
Requires: Power-of-2 window length.
Cepstrum
Noll, 1967. Real cepstrum — $c(\tau) = \text{IFFT}(\log |\text{FFT}(x)|)$. A peak at quefrency $\tau$ corresponds to period $\tau$ in the time domain.
import cepstrum from '@audio/pitch-cepstrum'
let result = cepstrum(samples, { fs: 44100 })
| Param | Default | |
|---|---|---|
fs |
44100 |
Sample rate (Hz) |
minFreq |
50 |
Minimum detectable frequency (Hz) |
maxFreq |
2000 |
Maximum detectable frequency (Hz) |
threshold |
0.3 |
Minimum clarity to accept |
Use when: Harmonic signals where you want a clean spectral-domain method. Good pedagogical complement to time-domain algorithms.
Not for: Low-pitched signals (quefrency resolution is limited by window length).
Ref: Noll, "Cepstrum pitch determination", JASA 1967.
Requires: Power-of-2 window length.
SWIPE
Camacho & Harris, 2008. SWIPE' (Sawtooth Waveform Inspired Pitch Estimator, prime harmonics). Measures spectral similarity between the window and a sawtooth template whose lobes sit at prime harmonics. More accurate than HPS on clean instrumental signals; robust against octave errors because only prime harmonics contribute.
Simplified single-window form: uses one FFT instead of the multi-resolution loudness pyramid of the original paper — sufficient for stationary windows.
import swipe from '@audio/pitch-swipe'
let result = swipe(samples, { fs: 44100 })
| Param | Default | |
|---|---|---|
fs |
44100 |
Sample rate (Hz) |
minFreq |
60 |
Minimum detectable frequency (Hz) |
maxFreq |
4000 |
Maximum detectable frequency (Hz) |
cents |
10 |
Candidate spacing in cents |
threshold |
0.15 |
Minimum clarity to accept |
Use when: Clean instrumental signals, studio recordings, where sub-Hz accuracy matters.
Not for: Very noisy or reverberant signals (single-window form lacks multi-resolution robustness of the full SWIPE').
Ref: Camacho & Harris, "A sawtooth waveform inspired pitch estimator for speech and music", JASA 2008.
Requires: Power-of-2 window length.
Comparison
Pitch algorithms
| YIN | McLeod | pYIN | AMDF | HPS | Cepstrum | SWIPE | |
|---|---|---|---|---|---|---|---|
| Domain | time | time | time | time | spectral | spectral | spectral |
| Accuracy | ★★★★★ | ★★★★ | ★★★★★ | ★★★ | ★★★★ | ★★★ | ★★★★★ |
| Noise robustness | ★★★★★ | ★★★★ | ★★★★★ | ★★★ | ★★★ | ★★★ | ★★★★ |
| Octave errors | rare | rare | rare | common | rare | occasional | rare |
| Missing fundamental | no | no | no | no | yes | yes | yes |
| Min window | ~4 periods | ~2 periods | ~4 periods | ~4 periods | power of 2 | power of 2 | power of 2 |
| Best for | general | vibrato | ambiguous | embedded | harmonic-rich | pedagogical | studio |
See also
- fourier-transform — FFT used by spectral algorithms
- mir — chroma, chord, key, melody, structure, fingerprint
- beat — onset detection, tempo estimation, beat tracking
- digital-filter — filter design and processing
- stretch — time stretching and pitch shifting
- shift — pitch shifting algorithms