| | export default () => { |
| | class BufferedAudioWorkletProcessor extends AudioWorkletProcessor { |
| | constructor() { |
| | super(); |
| | this.bufferQueue = []; |
| | this.currentChunkOffset = 0; |
| | this.hadData = false; |
| |
|
| | this.port.onmessage = (event) => { |
| | const data = event.data; |
| | if (data instanceof Float32Array) { |
| | this.hadData = true; |
| | this.bufferQueue.push(data); |
| | } else if (data === "stop") { |
| | this.bufferQueue = []; |
| | this.currentChunkOffset = 0; |
| | } |
| | }; |
| | } |
| |
|
| | process(inputs, outputs) { |
| | const channel = outputs[0][0]; |
| | if (!channel) return true; |
| |
|
| | const numSamples = channel.length; |
| | let outputIndex = 0; |
| |
|
| | if (this.hadData && this.bufferQueue.length === 0) { |
| | this.port.postMessage({ type: "playback_ended" }); |
| | this.hadData = false; |
| | } |
| |
|
| | while (outputIndex < numSamples) { |
| | if (this.bufferQueue.length > 0) { |
| | const currentChunk = this.bufferQueue[0]; |
| | const remainingSamples = |
| | currentChunk.length - this.currentChunkOffset; |
| | const samplesToCopy = Math.min( |
| | remainingSamples, |
| | numSamples - outputIndex, |
| | ); |
| |
|
| | channel.set( |
| | currentChunk.subarray( |
| | this.currentChunkOffset, |
| | this.currentChunkOffset + samplesToCopy, |
| | ), |
| | outputIndex, |
| | ); |
| |
|
| | this.currentChunkOffset += samplesToCopy; |
| | outputIndex += samplesToCopy; |
| |
|
| | |
| | if (this.currentChunkOffset >= currentChunk.length) { |
| | this.bufferQueue.shift(); |
| | this.currentChunkOffset = 0; |
| | } |
| | } else { |
| | |
| | channel.fill(0, outputIndex); |
| | outputIndex = numSamples; |
| | } |
| | } |
| | return true; |
| | } |
| | } |
| |
|
| | registerProcessor( |
| | "buffered-audio-worklet-processor", |
| | BufferedAudioWorkletProcessor, |
| | ); |
| | }; |
| |
|