This example demonstrates how to communicate real-time data from the processor to the host. It requires using the postMessage method.
We will create a simple canvas with a gradient rule for the style. Nothing particular in this code.
// vu-meter.js
class VuMeter {
constructor(canvas, height, width) {
this.canvas = canvas;
this.canvas.height = height;
this.canvas.width = width;
this.ctx = this.canvas.getContext("2d")
let gradient = this.ctx.createLinearGradient(0,0, width, height);
gradient.addColorStop(0, "#08ff00");
gradient.addColorStop(0.33, "#fffb00");
gradient.addColorStop(0.66, "#ff7300");
gradient.addColorStop(1, "#ff0000");
this.ctx.fillStyle = gradient;
this.ctx.clearRect(0,0,width,height);
}
update(value) {
value = Math.min(value, 1);
this.ctx.clearRect(0,0, this.canvas.width, this.canvas.height);
this.ctx.fillRect(0, 0, value*this.canvas.width, this.canvas.height);
}
}
We want to minimize the call to the update function of the vu-meter. That's why we will not send a message after each call of the process method in the processor.
// audio-player-processor.js
const COUNT_BLOCK = 8;
class AudioPlayerProcessor extends AudioWorkletProcessor {
/* Code of the processor
...
*/
calculateMax(output) {
for (let i = 0; i < output.length; i++) {
this.max = Math.max(this.max, output[i]);
}
this.blockCount++;
if (this.blockCount >= COUNT_BLOCK) {
this.port.postMessage({volume: this.max});
this.max = 0;
this.blockCount = 0;
}
}
process(inputs, outputs, parameters) {
/* Process Audio
...
*/
this.calculateMax(output[0]);
return true;
}
}
For each 8 quantum blocks of the render process method, we check the maximum value of the output array. Then we send to the host the max value from all the audio with a postMessage.
Then in the host we will retrieve the value of the max.
// index.js
const vuMeterCanvas = document.getElementById("canvas2");
(async () => {
const vuMeter = new VuMeter(vuMeterCanvas, 30, 200);
/* Code of the host
...
*/
node.port.onmessage = ev => {
let vol = 0;
let sensitivity = 1.3;
if (ev.data.volume) {
vol = ev.data.volume;
}
vuMeter.update(Math.abs(vol) * sensitivity);
}
})();
After creating the vuMeter, we can receive data from the processor using the audio node.
We've seen how to get information from the processor in the host. We created a simple vu meter, but we can imagine any other implementation where we need to get information about the processor. For instance, making a playhead cursor for the host.