📻 Rendering Audio Waveforms
For an upcoming post I wanted to include some audio, easy enough, just drop in an <audio> tag, job done. Nah,
this sounds like a great oppurtunity for some overengineering!
I wanted to an audio visualiser, no not that kind, just a simple waveform visualisation which follows along with the audio. I wanted it to be an enhancement to the native player rather than take over and end up being a rebuild of the perfectly good native player.
Attempt One: JS + OfflineAudioContext
My first attempt leveraged JS APIs provided by the browser to analyse the wav file, render the waveform to a canvas and keep track of the current playback position:
It worked, but I wasn't happy with it. It was visually a bit much, and it felt rude to ask each visitor to do a bunch of audio analysis just to render a totally unnecessary image, especially given that the image won't ever change. Also I didn't want to deal with browser compatibility.
Attempt Two: PHP + ffmpeg + GD
This moves all the work to the server and leverages the excellent ffmpeg to do the audio processing:
ffmpeg -i sound.mp3
-ac 1 // mono (1 channel)
-filter:a aresample=8000 // resample to 8 kHz — reduces data volume
-map 0:a // select audio stream from input 0
-c:a pcm_s16le // encode as 16-bit signed little-endian Pulse Code Modulation
-f data // raw output format (no container)
This converts the audio file into raw amplitude values, these values are output in a binary format and can be converted
into an array of integers in PHP by calling unpack('v*', $binaryOutput). It's a small jump then to plot these
values to a simple PNG:
The native audio player is then layered on top (it hides when de-focused) with a little CSS and the whole thing is
packaged up into an <x-audio/> webcomponent.
The soruce code for the webcomponent and image generation are, naturally, opensource.