@audio/pitch [](https://github.com/audiojs/pitch/actions/workflows/test.yml) [](https://www.npmjs.com/package/@audio/pitch) [](https://github.com/krishnized/license)

July 10, 2026 · View on GitHub

Pitch detection (F0 estimation). YIN, McLeod, pYIN, autocorrelation, AMDF, HPS, cepstrum, SWIPE.

Time-domain

YIN — cumulative mean normalized difference
McLeod — normalized square difference (MPM)
pYIN — probabilistic YIN with Beta prior
Autocorrelation — normalized autocorrelation
AMDF — average magnitude difference

Spectral

HPS — harmonic product spectrum
Cepstrum — real cepstrum peak picking
SWIPE — sawtooth waveform inspired estimator

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 Float32Array samples.

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 Hz
  • clarity — 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 })
ParamDefault
fs44100Sample rate (Hz)
threshold0.15CMND 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(N2/4)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 })
ParamDefault
fs44100Sample rate (Hz)
threshold0.9Peak 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(N2/4)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 }, ...] }
ParamDefault
fs44100Sample rate (Hz)
minFreq50Minimum detectable frequency (Hz)
maxFreq2000Maximum 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 })
ParamDefault
fs44100Sample rate (Hz)
threshold0.5Minimum 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(N2/4)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 })
ParamDefault
fs44100Sample rate (Hz)
minFreq50Minimum detectable frequency (Hz)
maxFreq2000Maximum detectable frequency (Hz)
threshold0.3Normalized 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(N2/4)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 })
ParamDefault
fs44100Sample rate (Hz)
harmonics5Number of harmonic products
minFreq50Minimum detectable frequency (Hz)
maxFreq4000Maximum detectable frequency (Hz)
cents10Candidate spacing in cents
threshold0.1Minimum 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(τ)=IFFT(logFFT(x))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 })
ParamDefault
fs44100Sample rate (Hz)
minFreq50Minimum detectable frequency (Hz)
maxFreq2000Maximum detectable frequency (Hz)
threshold0.3Minimum 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 })
ParamDefault
fs44100Sample rate (Hz)
minFreq60Minimum detectable frequency (Hz)
maxFreq4000Maximum detectable frequency (Hz)
cents10Candidate spacing in cents
threshold0.15Minimum 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

YINMcLeodpYINAMDFHPSCepstrumSWIPE
Domaintimetimetimetimespectralspectralspectral
Accuracy★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
Noise robustness★★★★★★★★★★★★★★★★★★★★★★★★★★★
Octave errorsrarerarerarecommonrareoccasionalrare
Missing fundamentalnonononoyesyesyes
Min window~4 periods~2 periods~4 periods~4 periodspower of 2power of 2power of 2
Best forgeneralvibratoambiguousembeddedharmonic-richpedagogicalstudio

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