Skip to content

Instantly share code, notes, and snippets.

@greggman
Last active September 24, 2022 23:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save greggman/3b875aa07cae22d1f946b9b8df56d4d5 to your computer and use it in GitHub Desktop.
Save greggman/3b875aa07cae22d1f946b9b8df56d4d5 to your computer and use it in GitHub Desktop.
WebAudio AnalyserNode issue
canvas {
display: block;
background: #DDF;
}
<button type="button" id="play">play</button>
<button type="button" id="nan">inject a single NaN</button>
<canvas></canvas>
const processorJS = `
class MyWorkletProcessor extends AudioWorkletProcessor {
constructor(options) {
super();
this.position = 0;
this.port.onmessage = () => {
console.log('inject NaN');
this.injectNaN = true;
}
}
process(inputs, outputs, parameters) {
// assuming one output with 2 channels
const output = outputs[0];
const ch0 = output[0];
const ch1 = output[1];
const len = ch0.length;
const pos = this.position;
for (let i = 0; i < len; ++i) {
const t = (pos + i) >> 2;
const s = this.injectNaN
? Number.NaN
: (((t | t % 255 | t % 257) & 255) / 127.5 - 1);
this.injectNaN = false;
ch0[i] = s;
ch1[i] = s;
}
this.position += len;
return true;
}
}
registerProcessor('my-worklet-processor', MyWorkletProcessor);
`;
function makeURLForString(src) {
const blob = new Blob([src], {type: 'application/javascript'});
return URL.createObjectURL(blob);
}
let node;
async function start() {
const processorURL = makeURLForString(processorJS);
const context = new AudioContext();
context.resume(); // needed by safari
await context.audioWorklet.addModule(processorURL);
node = new AudioWorkletNode(context, 'my-worklet-processor', {
outputChannelCount: [2],
});
analyser = context.createAnalyser();
analyser.maxDecibels = -1;
node.connect(analyser);
analyser.connect(context.destination);
const numPoints = analyser.frequencyBinCount;
const audioDataArray = new Uint8Array(numPoints);
const ctx = document.querySelector('canvas').getContext('2d');
function render() {
analyser.getByteFrequencyData(audioDataArray);
const {width, height} = ctx.canvas;
ctx.clearRect(0, 0, width, height);
const size = 2;
for (let x = 0; x < width; x += size) {
const ndx = x * numPoints / width | 0;
const audioValue = 1 - audioDataArray[ndx] / 255;
const y = audioValue * height;
ctx.fillRect(x, y, size, size);
}
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
function injectNaN() {
node.port.postMessage({});
}
document.querySelector('#play').addEventListener('click', start, {once: true});
document.querySelector('#nan').addEventListener('click', injectNaN, {once: true});
{"name":"WebAudio AnalyserNode issue","settings":{},"filenames":["index.html","index.css","index.js"]}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment