M0UNTAIN 0F C0DE

📻 Rendering Audio Waveforms

PHP audio

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.