How Remove Silence is built
These are the engineering notes for Remove Silence: the technologies it is built on, what each one is, and how it is used in the tool.
Tech used
Decoding with the Web Audio API
The Web Audio API is the browser’s built-in audio engine. Its AudioContext.decodeAudioData(arrayBuffer) acts as a universal decoder: hand it the bytes of an MP3, WAV, M4A/AAC, OGG, or FLAC and it returns an AudioBuffer of raw PCM samples, using the browser’s own codecs. The tool reads the file with file.arrayBuffer(), decodes it, then closes the context.
PCM samples and the downmix to mono
An AudioBuffer exposes each channel as a Float32Array of samples in the range −1…1, via getChannelData(). The tool averages the channels into a single mono Float32Array — both to simplify detection and because the output is mono.
Amplitude-threshold silence detection
Detection is deliberately simple: a sample counts as “loud” when its absolute amplitude exceeds a threshold. Runs of loud samples are kept; a quiet stretch only becomes a cut once it lasts longer than a minimum-silence duration (so natural micro-pauses aren’t chopped), and each kept region is padded by ~50 ms on both sides to avoid clicks at the splice. The result is a list of sample-index regions to keep. This is a peak threshold, not an RMS/dBFS measure — a loud transient inside an otherwise “silent” gap will defeat it.
Re-encoding to MP3 with lamejs
The kept samples are concatenated and quantized from Float32 to 16-bit integers, then encoded with lamejs (@breezystack/lamejs), a pure-JavaScript port of the LAME MP3 encoder. An Mp3Encoder (mono, the source sample rate, 128 kbps) consumes the samples in 1152-sample blocks — the MPEG frame size — and a final flush() emits the last frame; the chunks become a single audio/mpeg Blob.
Shell
Same static Astro + Preact island and Service-Worker PWA shell as the other tools (see the HEIC notes). Everything runs on the main thread — no Web Worker, no OfflineAudioContext, and no ffmpeg: the job is light enough to run inline with a pure-JS encoder.
Implementation & operational notes
Output is mono 128 kbps MP3. Channels are averaged to mono before detection and encoding, so even stereo input comes out mono — a real fidelity trade-off. The sample rate is preserved (no resampling).
Detection parameters. The amplitude threshold and the minimum-silence duration are exposed as sliders; the anti-click pad is fixed at 50 ms. A clip that is silent throughout has nothing to keep and is reported as such.
In memory, on the main thread. The decoded mono samples, the kept-sample buffer, and all MP3 chunks are held at once and processed synchronously, so a long recording uses a lot of memory and blocks the UI thread while it runs.
Try it / source
- Tool: Remove Silence
- Source: github.com/GeppettoAndRomero