DEV Community

Cover image for I Built a Binaural Beat Generator — Then Proved It With a Live FFT Spectrum Analyzer
Serenesynth Team
Serenesynth Team

Posted on AI-assisted

I Built a Binaural Beat Generator — Then Proved It With a Live FFT Spectrum Analyzer

The "frequency healing" corner of the internet runs on faith. Apps ship MP3s labeled "40Hz gamma" and ask you to believe it. I'm a life scientist who builds web tools, and I couldn't ship that. So I built SereneSynth, a browser-based binaural beat and noise generator — and then I built a live spectrum analyzer into the page so anyone can audit the output in their own browser.

This is the engineering write-up: the Web Audio graph, the FFT gotcha that almost made me publish wrong numbers, and how I cross-verified everything in Audacity.

The honesty constraint first

A binaural beat is not a tone in the air. Play 200 Hz into the left ear and 240 Hz into the right, and the listener's superior olivary complex computes the 40 Hz difference. A microphone — or a mono spectrum analyzer — will never show a 40 Hz peak. So the only honest thing a generator can prove is its carriers and its spectral slope. That is exactly what we measure.

The synthesis graph

Two sine oscillators, hard-panned with StereoPannerNode, summed into a master GainNode, tapped by an AnalyserNode before the destination — the analyzer observes exactly what the headphones receive. Settings that matter: fftSize 16384, smoothingTimeConstant 0.8.

The FFT gotcha that almost made me ship garbage

My first version used fftSize 1024: one fat bump near 220 Hz instead of two peaks. Bin width = 44100 / 1024 ≈ 43 Hz, and my carriers are 40 Hz apart — same bin, merged. At fftSize 16384 the bin width drops to ≈ 2.7 Hz and the carriers resolve as razor-sharp spikes at 200.0 and 240.0 Hz. Lesson: FFT size is the magnifying glass. If a "frequency proof" doesn't state its FFT size, ask.

The widget renders a log axis (20–1000 Hz) because a linear axis wastes 90% of the canvas, and peak detection labels the top bins in the 100–500 Hz range live.

Bit-exact, downloadable verification

The page also renders 10-second stereo WAVs via Offline Audio Context (16-bit PCM, 44.1 kHz): same graph, offline render, RIFF encode. No lossy compression between the engine and the evidence.

Cross-check: two instruments, same answer

Opened the exported WAVs in Audacity (Analyze → Plot Spectrum, FFT 16,384, Hann window):

  • 40 Hz preset: two spikes at 200.0 / 240.0 Hz
  • 432 Hz preset: single spike at 432.0 Hz, no harmonics
  • Brown noise: continuous ≈ -6 dB/octave rolloff on a log axis

Browser analyzer and desktop DAW agree. The proof is re-runnable, not rhetorical.

Audit it yourself

Live analyzer + WAV downloads: serenesynth.com/proof-lab

The generator: serenesynth.com/binaural-beat-generator

Methodology + figures: GitHub repo

No mysticism. Just math.

Top comments (0)