Skip to content

Instantly share code, notes, and snippets.

@louisgv
Last active March 7, 2024 12:16
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save louisgv/f210a1139d955baf511ff35f58fc8db1 to your computer and use it in GitHub Desktop.
Save louisgv/f210a1139d955baf511ff35f58fc8db1 to your computer and use it in GitHub Desktop.
AudioWorklet replacement for ScriptProcessorNode
const main = async () => {
const context = new AudioContext();
const microphone = await navigator.mediaDevices
.getUserMedia({
audio: true
})
const source = context.createMediaStreamSource(microphone);
// NEW A: Loading the worklet processor
await context.audioWorklet.addModule("/recorder.worklet.js")
// Create the recorder worklet
const recorder = new AudioWorkletNode(
context,
"recorder.worklet"
)
source
.connect(recorder)
.connect(context.destination);
recorder.port.onmessage = (e: {
data: Float32Array
}) => {
console.log(data)
// `data` is a Float32Array array containing our audio samples
}
}
/**
An in-place replacement for ScriptProcessorNode using AudioWorklet
*/
class RecorderProcessor extends AudioWorkletProcessor {
// 0. Determine the buffer size (this is the same as the 1st argument of ScriptProcessor)
bufferSize = 4096
// 1. Track the current buffer fill level
_bytesWritten = 0
// 2. Create a buffer of fixed size
_buffer = new Float32Array(this.bufferSize)
constructor() {
this.initBuffer()
}
initBuffer() {
this._bytesWritten = 0
}
isBufferEmpty() {
return this._bytesWritten === 0
}
isBufferFull() {
return this._bytesWritten === this.bufferSize
}
/**
* @param {Float32Array[][]} inputs
* @returns {boolean}
*/
process(inputs) {
// Grabbing the 1st channel similar to ScriptProcessorNode
this.append(inputs[0][0])
return true
}
/**
*
* @param {Float32Array} channelData
*/
append(channelData) {
if (this.isBufferFull()) {
this.flush()
}
if (!channelData) return
for (let i = 0; i < channelData.length; i++) {
this._buffer[this._bytesWritten++] = channelData[i]
}
}
flush() {
// trim the buffer if ended prematurely
this.port.postMessage(
this._bytesWritten < this.bufferSize
? this._buffer.slice(0, this._bytesWritten)
: this._buffer
)
this.initBuffer()
}
}
registerProcessor("recorder.worklet", RecorderProcessor)
@jkeshet
Copy link

jkeshet commented Mar 7, 2024

It seems that the condition this._bytesWritten < this.bufferSize in the function flush() is redundant and will never reached.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment