Charlie KrugThe Build Log

← All posts

A hand-rolled FFT turns your audio into a heatmap, in the tab

Cathode draws a waveform and spectrogram, trims to the sample, and exports MP3/AAC/WAV, all in the browser. The spectrogram runs on a from-scratch radix-2 FFT, and your file never uploads.

Drop a voice memo onto the page and a heatmap blooms under the waveform: a low hum as bands near the bottom, the hiss of breath smeared across the top, every hard consonant a bright vertical spike. That picture is thousands of small math problems stacked side by side, one per column of pixels, and every one of them runs on your own machine. Nothing about the file leaves the tab.

What it is

Cathode is a single-page tool to see, trim, and convert a short audio clip in the browser. Drop in a file and it draws an interactive waveform and a spectrogram, lets you drag in/out handles to cut a selection to the exact sample, and exports the result to MP3, AAC, or WAV. No account, no queue, no upload.

Almost every "convert my audio" site on the web is a form that ships your file to a server, waits in a queue, and hands back a download. That is a privacy problem for anything sensitive (voice memos, demos, field recordings, a therapy note) and a latency problem for everything else. The browser has quietly grown everything you need to skip the server entirely: the Web Audio API decodes common formats natively, WebAssembly can run a full ffmpeg build for the rest, and <canvas> can push tens of thousands of samples at 60fps. Cathode is those three wired into one pipeline.

The spectrogram is a from-scratch FFT

Here is the part worth stealing. A spectrogram is a picture of which frequencies are present at each moment in time. To build one column of it, you take a short window of the raw samples, maybe 1024 of them, and ask: how much of each frequency is in this slice? The tool that answers is the Fast Fourier Transform, and Cathode implements it by hand rather than pulling in an audio library.

Two steps matter. First, the window gets multiplied by a Hann window, a smooth bell curve that tapers the slice to zero at both ends. Skip this and the abrupt cut at the window's edges leaks fake energy across the whole spectrum, smearing your clean tones into mush. Then a radix-2 Cooley-Tukey FFT turns those 1024 samples into 1024 frequency bins in a few thousand operations instead of the million a naive transform would cost. The magnitude of each bin becomes the brightness of one pixel, the column is drawn, the window slides forward, and repeat. A charting dependency would hide exactly the interesting part, so src/lib writes the windowing and the butterfly passes out longhand, unit-tested against transforms with known answers.

There is a second design decision hiding in the pipeline: ffmpeg does the encoding, not the decoding. The Web Audio API's decodeAudioData handles MP3, WAV, AAC, and OGG fast and natively, so ffmpeg.wasm only steps in as a fallback for exotic containers, and always for export, because browser MediaRecorder encoding is maddeningly inconsistent for MP3 and AAC. Use the right engine for each direction.

The 30MB you don't pay for until you need it

The ffmpeg.wasm core is about 30MB, which would be a rude thing to download just to look at a waveform. So Cathode does not fetch it on page load. It waits until you actually hit export, then pulls the core once, and the browser caches it for every export after. The page stays light for the common case of "I just want to see this sound," and the heavy engine only arrives when it has a job.

Trimming is instant for the same reason nothing re-encodes early: the in/out handles operate on the decoded PCM buffer in memory, not on the compressed file. Cutting is sample-accurate and free, and preview playback of just the selection is one AudioBufferSourceNode. The one re-encode happens at export, and only then. Honest limits: your first export makes you wait out that one-time core download, and because the whole clip lives in RAM, this is built for short recordings, not a three-hour podcast. That is the trade for never touching a server.

Try it

Open it, drop in any audio file, and watch the waveform and spectrogram render. Drag the trim handles to a phrase you want, hit loop to preview just that slice, then export it to MP3 and download. The first export fetches the ffmpeg core once; every one after is immediate, and at no point does the file go anywhere but your own browser.

Cathode is live. Free, in your browser, no signup.

This post is part of the build log: every app my automated factory ships gets written up here, honestly. Browse everything at apps.charliekrug.com. Comments are open below.

Comments

Loading comments…