Published
Edited
Nov 12, 2021
1 fork
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
volumeData = Generators.observe((change) => {
try {
const microphone = audioCtx.createMediaStreamSource(stream);
const node = new AudioWorkletNode(audioCtx, "audio-monitor", {
parameterData: {
clipLevel: clipLevel,
averaging: 0.9,
clipLag: 750
}
});
node.port.onmessage = (event) => {
change(event.data.volume);
};

invalidation.then(() => microphone.disconnect());
microphone.connect(node).connect(audioCtx.destination);
} catch (e) {
console.log(e);
}
})
Insert cell
scriptURL = {
const codeString = `
const QUANTUM_SIZE = 128;

class audioMonitor extends AudioWorkletProcessor {

constructor() {
super();
this._volume = 0;
this._updateIntervalInMS = 25;
this._nextUpdateFrame = this._updateIntervalInMS;
}
static get parameterDescriptors() {
return [{name: 'clipLevel', defaultValue: 0.98},
{name: 'averaging', defaultValue: 0.95},
{name: 'clipLag', defaultValue: 750}];
}
get intervalInFrames() {
return this._updateIntervalInMS / 1000 * sampleRate;
}

process(inputs, outputs, parameters) {
const clipLevel = parameters.clipLevel[0];
const averaging = parameters.averaging[0];
const clipLag = parameters.clipLag[0];
const input = inputs[0];
const volumes = input.map((channel, id) => {
const samples = channel;
let sum = 0;
let isClipping = false;
let lastClip = 0;
// Calculated the squared-sum.
for (let i = 0; i < samples.length; ++i){
if(Math.abs(samples[i]) >= clipLevel) {
isClipping = true;
lastClip = Date.now();
}
if((lastClip + clipLag) < Date.now()) isClipping = false;
sum += samples[i] * samples[i];
}

// Calculate the RMS level and update the volume.
const rms = Math.sqrt(sum / samples.length);

// Now smooth this out with the averaging factor applied
// to the previous sample - take the max here because we
// want "fast attack, slow release."
this._volume = Math.max(rms, this._volume * averaging);
return { value: this._volume, clipping: isClipping }
})

// Update and sync the volume property with the main thread.
this._nextUpdateFrame -= QUANTUM_SIZE;
if (this._nextUpdateFrame < 0) {
this._nextUpdateFrame += this.intervalInFrames;
this.port.postMessage({
volume: volumes
});
}
return true;
}
};

registerProcessor('audio-monitor', audioMonitor)`;

return URL.createObjectURL(
new Blob([codeString], { type: "text/javascript" })
);
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more