Audio Visualization

November 12, 2021

I’ve been meaning to delve into the Web Audio API for a while, but I didn’t know enough about Canvas to do anything interesting. Until now!

The javascript can be found here.

Edit 11/17

After experimenting a little with progressively rendering to a canvas, I added a spectrogram. I also made a few optimization tweaks to the oscilloscope, and I finally made a favicon!

Oscillocope
Histogram
Spectrogram

The code is mostly a standard use of the API, but I did run into one problem: the Analyser’s frequency data is linear, but human hearing is logarithmic. Displaying the raw frequency data would result in 6 octaves (of the 10 that healthy human ears can hear) being condensed into about 6% of the graph. Half of the graph would be displaying just the highest octave, which is almost nonexistent in the mp3 I’m using!

For the histogram, I converted the data like so:

function logAverage(arr) {
  let ret = [];
  let i = 0;

  while (i < arr.length) {
    let next_i = 2 * i + 1;
    let average = arr.slice(i, next_i).reduce((acc, el) => acc + el) / (i + 1);
    ret.push(average);
    i = next_i;
  }

  return ret;
}

Each iteration of the while loop averages twice as many data points as the previous one, which makes each bar on the frequency graph represent the same perceptual frequency range. I thought of initializing the return array size using Math.log2() to prevent multiple allocations, but it felt like a premature optimization. The push syntax is cleaner.

For the spectrogram, this method didn’t provide enough resolution, so I used Math.sqrt() when calculating color placement instead.

I’d still like to add a waveform-seek display, but I’m not sure yet how I want to generate the waveform image.