When want to display audio waveform from audio file, you can find browser libraries like WavesurferJs, Squiggl, or whatever, everyone works the same:
- Load audio (in full) file and get its AudioContext
- Get all the raw PCM samples from one channel in Float32Array (huge) with something like
ctx.decodeAudioData().getChannelData(0)
- Use drawing routine and average samples
Doing this process on the users browser is quite slow and wasteful in a magnitude proportional to the audio file size, as you have to fully load it then get huge amount of samples calculated in the drawing stage.
So one option to overcome this is to dump a shorter version of PCM data on a static file with an amount of samples enough to render the waveform and having a reasonable size by averaging the samples.
We will replace the 2 first stages of waveform generation from Javascript Audio APIs, so the first is to emulate what this process does, getting a full channel float32 samples from audio file, for this task we can use SoX, if you dont have it yet
apt install sox
apt install libsox-fmt-mp3
#to add mp3 lame support
So lets get some buffer: sox wf.mp3 -c 1 -t f32 - > wf.bin
We can load this file with ajax and read a Float32Array
So we have now a file that weights a lot more than original mp3 file (8mb mp3->72mb waveform) So lets average it on, for example 1000 samples, enough to render the waveform and that will weight 4kb (lighter than your average image)
To me seems fair size and you can still gzip the file with gzcompress
to serve it even smaller.
The script works launching a sox process with shell_exec
like the described above, then reading the samples from stdout to a variable, converting it to float32 samples with unpack
and averaging the samples.
Script will produce a file with extension .waveform with packed averaged measurements.