A four-operator FM synth whose sidebands land exactly where Bessel functions say.
Four sine operators are wired by one of eight classic algorithms: modulators add their output to another operator's phase, carriers are heard, and operator 1 can feed back into itself. For a carrier with one sine modulator, sin(wc t + I sin(wm t)) expands into sidebands at fc + n fm with heights J_n(I), so every frame the demo renders the patch's real output, takes a Blackman-Harris windowed FFT and marks where the Bessel series says each line belongs, with negative frequencies folded back by their sign. The spectra stack into a 3D waterfall as envelopes sweep the index, a chart of J_0 to J_6 follows the live index (watch the carrier vanish at I = 2.405), and every operator node shows its own waveform. After a click the same voices run in the audio callback, so what you see is what you hear.
Try it. Play the keyboard with the mouse or with keys Z to M and Q to U. Pick a preset (Bell, Sweep, E. Piano, Brass, Clarinet, Gong, Bass, Organ) or an algorithm (keys 1 to 8), and drag any operator node up and down to set its index or sideways to set its frequency ratio (hold shift for free ratios). The selected node's ratio, index, decay and release have sliders, - and = set feedback, and A toggles the autopilot.
Paste this into Claude Code, Codex or any coding agent to get a simple version running, then take it wherever you like.
Build an FM synthesizer you can see and hear, with JavaScript, the HTML canvas element and Web Audio. Put everything in a single index.html file with no libraries or build step, so I can open it directly in a browser.
Start simple:
- Make a canvas that fills the window, stays sharp on high-DPI screens (scale by devicePixelRatio), and resizes with the window. Use a dark background.
- Write a two-operator FM voice by hand: a carrier at frequency fc and a modulator at fm = ratio * fc, with output sin(2 pi fc t + I sin(2 pi fm t)), where I is the modulation index. Give each operator a simple attack and exponential decay envelope.
- Every frame, render 4096 samples of the current voice into an array, apply a Blackman-Harris window, take an FFT you write yourself, and draw the magnitude spectrum in dB with a linear frequency axis.
- Draw a one-octave keyboard at the bottom. Only after the first click, create an AudioContext and play notes through a ScriptProcessorNode that runs the same voice code, so the sound matches the picture.
- Add sliders for the ratio and the index.
Once that works, make it beautiful:
- Compute Bessel functions J_n(I) with their power series and mark where theory says each sideband should sit: at fc + n fm with height J_n(I), folding negative frequencies back with a sign flip. The marks should land on the measured peaks.
- Draw a small chart of J_0 to J_6 against the index with a moving line at the current index, and notice the carrier vanish at I = 2.405.
- Keep the last 50 spectra and draw them as a 3D waterfall, each older line shifted up and to the right and filled with the background so it hides the ones behind.
Explain the key ideas in short code comments. When you're done, tell me how to open it and suggest three directions I could take it next, such as four operators with switchable algorithms, operator feedback, or presets for a bell, an electric piano and brass.