Last active
March 7, 2024 12:16
-
-
Save louisgv/f210a1139d955baf511ff35f58fc8db1 to your computer and use it in GitHub Desktop.
AudioWorklet replacement for ScriptProcessorNode
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
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) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
It seems that the condition
this._bytesWritten < this.bufferSize
in the functionflush()
is redundant and will never reached.