# AudioViz

*A dead TV, a lockdown and an obsession with the Fourier transform, turned into 26 real-time audio visualizations.*

- Year: 2024
- Built with: Vue.js, Vite, Canvas, Web Audio API, Pinia, Tailwind
- Updated: 2026-09-07T20:55:52.359Z
- live: https://audioviz.abchaudary.me
- repo: https://github.com/abdullahchaudary/audioviz

> AudioViz turns live audio into 26 real-time visual effects plus a waveform generator, built in Vue with plain JavaScript underneath, no Three.js, no Tone.js.

## What it is

AudioViz turns live audio, from a microphone or a file, into real-time visuals: 26 distinct modes, a randomizer that cycles between them, and a separate waveform and frequency generator for tuning speakers by ear. Vue wraps the app; the actual signal analysis is plain JavaScript underneath, built directly on the Web Audio API's `AnalyserNode`, not a visualization library.

## The room this was built for (origin story)

During lockdown I was rebuilding my home office: a triple-monitor setup for myself, and next to it a dual-monitor gaming setup for my younger brother, dense with RGB. Around the same time we replaced a failing TV in the lounge, which left the old one spare. I mounted the RGB strips through a custom ESP32 and WLED controller wired into my Home Assistant server, synced to whatever music was playing, a lightshow separate from anything in this repository. The spare TV was a different problem: it had gone patchy, with dark spots in the corners, and had no real use left. I decided to put something on it that would loop and add to the room rather than sit blank, which is the entire reason AudioViz exists.

With time to fill under lockdown, a simple music visualizer turned into a study of the Fast Fourier Transform: how to take a signal and break it into the frequency components that make it up, in real time, cheaply enough to redraw sixty times a second. I built the frontend in Vue and kept going, with one detour along the way: a mid-search for FFT libraries triggered an invitation to Google's Foobar recruiting challenge, which cost the project a day (the first of its five levels, text-to-Braille conversion under a fixed complexity budget, took under an hour) before I came back to finish what I'd been building in the first place.

## Twenty-six ways to watch a sound

`Visualizer.vue` lists 26 numbered modes in its mode selector, each a different way of drawing the same `AnalyserNode` output: bars, radial forms, particle fields, waveform traces. The FFT size is fixed at 512 samples, the resolution that held up in testing as a real-time frame budget on ordinary hardware. A randomizer cycles through all 26 on a 20-second timer, which turned out to be its own small problem: naively, `setTimeout` calls stack up every time the mode changes, and a stale one firing after a manual switch resets the mode a user just picked. The fix is a tracked array of every timeout ID currently scheduled, cleared in full the moment a mode is chosen by hand, so exactly one loop is ever running.

## Fixing the frequencies the mic hides

A lot of microphones apply their own noise suppression before the browser ever sees the signal, quietly flattening certain frequency ranges to cut background hiss. Rendered straight, those bands read as visually dead even when they aren't. The visualizer has a Boost control that multiplies the render amplitude on top of what the signal actually carries, which does nothing to the audio itself, only to how honestly the visualization represents what a listener's ear can still hear underneath the suppression.

## What audio processing actually costs

None of this looks expensive. A canvas redrawing bars in time with a beat looks like the easiest kind of animation there is. It isn't: an `AnalyserNode` running every frame, 26 draw routines, and a randomizer's timers all compete for the same main thread a browser also uses for everything else on the page, and a careless implementation here is a straightforward way to put real load on a machine that looks idle. Keeping the frame budget inside 512-sample FFT windows, and making sure exactly one timer loop is ever alive, is what keeps this running smoothly enough to leave on a TV for hours.

## From wall filler to tuning tool

A waveform generator was added later: sine, square, sawtooth or triangle, a frequency slider from 1Hz to 24kHz, and a gain control, driven by an `OscillatorNode` and a real `GainNode` rather than a canvas trick, unlike the visualizer's own Boost control above.

## Stack

Vue 3, Vite, Pinia and vue-router handle routing, state and bundling. Every part of this that actually processes audio (the FFT analysis, the oscillator, the gain stage) is packaged as plain JavaScript underneath the Vue layer, not tied to it, which is also why none of it depends on Three.js or Tone.js despite what a visualizer like this might suggest. It's built as a PWA (`vite-plugin-pwa`), so it installs straight from the browser onto a TV, a phone or a desktop without going through an app store.

## Outcome

Five commits across four days is the most any of [the five browser experiments](/projects) on this domain received, for a project that started as a fix for a dead TV. What has stuck longer than the commit history is the waveform generator: it's still how I set crossovers on my own speakers, and I've shared it with enough people since, friends, a few of them teachers, working musicians, even some of my own former teachers, that it's become a small, plain tool for hearing what a frequency actually sounds like rather than reading a number off a spec sheet. That's the part of this I'm most proud of, more than the 26 modes: it turned into something people learn from.

## Links

Live: [audioviz.abchaudary.me](https://audioviz.abchaudary.me). Source: [github.com/abdullahchaudary/audioviz](https://github.com/abdullahchaudary/audioviz). Built around the same time as [Emotions AI](/projects/emotions-ai), the other project on this domain that turned a stretch of forced time at home into something real.
