I play guitar and I used to carry a clip-on tuner. Then I realized that my phone has a microphone, a fast processor, and a screen. Everything a tuner needs. The browser has the Web Audio API, which gives JavaScript direct access to the microphone and real-time audio analysis. Building a chromatic tuner is one of the most satisfying browser projects because the feedback loop is instant and physical.
How pitch detection works
A chromatic tuner does one thing: listen to a sound and determine its fundamental frequency in Hz. The mapping from frequency to note is:
A4 = 440 Hz
Each semitone up: frequency * 2^(1/12)
Each semitone down: frequency * 2^(-1/12)
Each octave up: frequency * 2
The 12th root of 2 (approximately 1.05946) is the frequency ratio between adjacent semitones in equal temperament tuning. This means:
A4 = 440.00 Hz
A#4 = 466.16 Hz
B4 = 493.88 Hz
C5 = 523.25 Hz
...
To determine which note a frequency corresponds to:
function frequencyToNote(freq) {
const semitones = 12 * Math.log2(freq / 440);
const nearestSemitone = Math.round(semitones);
const centsOff = (semitones - nearestSemitone) * 100;
const noteNames = ['A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#'];
const noteIndex = ((nearestSemitone % 12) + 12) % 12;
return { note: noteNames[noteIndex], cents: centsOff };
}
Cents measure how far off-pitch you are. 100 cents = 1 semitone. A value of +10 cents means slightly sharp. -10 cents means slightly flat. Most musicians can hear differences of about 5 cents.
The autocorrelation method
The hardest part of a tuner is not the note mapping. It is extracting the fundamental frequency from raw audio data. The standard approach is autocorrelation.
Autocorrelation compares a signal with a time-shifted copy of itself. When the shift equals one period of the fundamental frequency, the correlation peaks. By finding the first peak after the zero-lag peak, you determine the period, and from the period, the frequency.
function autoCorrelate(buffer, sampleRate) {
let bestOffset = -1;
let bestCorrelation = 0;
let foundGoodCorrelation = false;
for (let offset = 1; offset < buffer.length / 2; offset++) {
let correlation = 0;
for (let i = 0; i < buffer.length / 2; i++) {
correlation += buffer[i] * buffer[i + offset];
}
correlation /= buffer.length / 2;
if (correlation > 0.9 && correlation > bestCorrelation) {
bestCorrelation = correlation;
bestOffset = offset;
foundGoodCorrelation = true;
}
}
if (!foundGoodCorrelation) return -1;
return sampleRate / bestOffset;
}
This basic version works but lacks precision. Refinements include parabolic interpolation around the peak (to get sub-sample accuracy) and windowing the input buffer (to reduce spectral leakage).
The Web Audio API pipeline
const audioContext = new AudioContext();
const analyser = audioContext.createAnalyser();
analyser.fftSize = 4096;
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const source = audioContext.createMediaStreamSource(stream);
source.connect(analyser);
const buffer = new Float32Array(analyser.fftSize);
function detect() {
analyser.getFloatTimeDomainData(buffer);
const frequency = autoCorrelate(buffer, audioContext.sampleRate);
if (frequency > 0) {
const { note, cents } = frequencyToNote(frequency);
updateDisplay(note, cents);
}
requestAnimationFrame(detect);
}
detect();
The key settings: fftSize of 4096 at a 44.1kHz sample rate gives about 93ms of audio per frame. This is sufficient for detecting frequencies down to about 80Hz (low E on guitar is 82Hz). For bass instruments, increase the buffer size.
Why browser-based tuners work now
Five years ago, browser audio latency was too high for real-time tuning. The Web Audio API's AudioContext now runs on a separate thread with low-latency audio processing. On modern browsers, the latency from microphone input to visual feedback is under 50ms -- fast enough to feel instantaneous.
I built a chromatic tuner at zovo.one/free-tools/tuner that uses this exact pipeline. It detects pitch in real time, shows the nearest note, displays cents deviation, and provides a visual indicator for sharp/flat. Works with any instrument. No app download required.
I'm Michael Lip. I build free developer tools at zovo.one. 500+ tools, all private, all free.
Top comments (0)