Search code examples
javascriptfftweb-audio-api

FFT with offlineAudioContext


I'm trying to do frequency analysis of an audio file, but I want it to happen without playing. I found there was a offlineAudioContext, which is probably what I need here.

Complete code in this jsfiddle

The Web Audio API is a bit of unexplored territory for me and I'm not completely sure what I'm doing, a lot of the tutorials are focused on realtime audio and that's exactly what I want to prevent.

Inside context.oncomplete, I managed to get some accurate looking rendered audiobuffer data. When getting data from the fft, I seem to be getting a very small set of data, which I'm guessing it's just the data from the last sample. I'd rather have this data for every x ms of the audio file that I'm loading. I would love to get some ideas on how to get this format of the data?

Basically what I'm expecting is something like:

[
  // array with frequency data for every (nth) frequency band for 1st sample,
  // array with frequency data for every (nth) frequency band for 2nd sample,
  // array with frequency data for every (nth) frequency band for 3rd sample,
  …
]

Solution

  • When you set fftSize on your AnalyserNode, you'll get (fftSize / 2) number of bins. So that's why you're seeing a lot less data than you expect.

    Essentially what's happening is that getByteFrequencyData is only looking at the first 128 samples of your rendered buffer, and the rest simply get ignored.

    Instead, you might want to try using a ScriptProcessorNode with a bufferSize equal to your fftSize. Then, in the ScriptProcessorNode's onaudioprocess event handler, you can grab the buffer and get its FFT. Something like this:

    var processor = context.createScriptProcessor(fftSize, 1, 1);
    source.connect(processor);
    
    processor.onaudioprocess = function( e ) {
      var input = e.inputBuffer.getChannelData(0),
          data = new Uint8Array(fftSamples);
      fft.getByteFrequencyData(data);
      // do whatever you want with `data`
    }