superpoweredSDK/web-audio-javascript-webassembly-SDK-interactive-audio

Superpowered.Analyzer and .Waveform are completely broken?

JohannesKlauss opened this issue · 5 comments

I am trying to evaluate the SDK for a large web audio project, but it is giving me a hard time to get anything donw.
Nothing the analyzer calculates makes any sense.

I have a mono wave file containing a 1kHz sine wave tone for 1s at -3dBFS which I use to check results of the analyzer.

This is my code (running at 44.1 KHz sample rate and it lives inside a worker):

const leftChannel = new Superpowered.Float32Buffer(e.data.inputSabLeftChannel.length);
const rightChannel = new Superpowered.Float32Buffer(e.data.inputSabRightChannel.length);

leftChannel.array = e.data.inputSabLeftChannel.slice();
rightChannel.array = e.data.inputSabRightChannel.slice();

const interleavedArray = new Superpowered.Float32Buffer(e.data.inputSabLeftChannel.length * 2);

Superpowered.Interleave(leftChannel.pointer, rightChannel.pointer, interleavedArray.pointer, leftChannel.length);

const waveform = new Superpowered.Waveform(
  e.data.sampleRate,
  e.data.duration,
);

waveform.process(
  interleavedArray.pointer,
  128,
  e.data.duration,
);

waveform.makeResult();

const peakWaveform = waveform.getPeakWaveform();

console.log('peaks', peakWaveform.array);

First of all the documentation is wrong. The docs tell to access the peak waveform via waveform.peakWaveform which returns undefined. I had to return all the keys of the waveform object to see that I have to call waveform.getPeakWaveform(). But this also returns nonsense.

Because even though I process only 128 frames of the 44100 available frames, the peaksWaveform array has a length of 47312.

The first values are:

[0, 0, 0, 0, 169, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...]

Which also makes no sense.

Also there is no documentation on what the third parameter on waveform.process actually does. It doesn't seem to matter, because putting in -1, 0, or 1 returns the same peaks array.

Am I doing something wrong here? For context, this is my init code inside the worker:

importScripts('../superpowered/SuperpoweredGlue.js');

// Create a SuperpoweredGlue instance and load WebAssembly:
let Superpowered;
let isReady = false;

SuperpoweredGlue.fetch('../superpowered/superpowered.wasm').then((res) => {
  Superpowered = res;

  // Initialize Superpowered.
  Superpowered.Initialize({
    licenseKey: 'ExampleLicenseKey-WillExpire-OnNextUpdate',
    enableAudioAnalysis: true,
    enableFFTAndFrequencyDomain: true,
    enableAudioTimeStretching: false,
    enableAudioEffects: false,
    enableAudioPlayerAndDecoder: true,
    enableCryptographics: false,
    enableNetworking: false
  });

  isReady = true;
});

Thanks discovering the documentation bug. Yes, you need to use getPeakWaveform().

Don't assign values like this: leftChannel.array = e.data.inputSabLeftChannel.slice();
The buffer ("leftChannel") represents a region in WebAssembly linear memory. Overwriting its "array" property points to a regular memory object this way, so WebAssembly can't read that.

How would I assign the array then?

leftChannel.array.set(e.data.inputSabLeftChannel) produces the same result?
Do I have to for loop the assignment? Seems counterproductive to loop through the arrays to be able to use WebAssembly.

Also looping it with

for(let i = 0; i < leftChannel.length; i++) {
  leftChannel.array[i] = e.data.inputSabLeftChannel[i];
  rightChannel.array[i] = e.data.inputSabRightChannel[i];
}

doesn't work and produces the same incorrect result.

waveform.process(interleavedArray.pointer, e.data.inputSabLeftChannel.length, -1);

The size of the result is waveform.waveformSize, not the array length, since it's just a "memory view", not a "true array".

Just updated Superpowered, now the returned typed array has the correct length set.