Spaces:
Running
Running
| 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; | |
| // Remove the chunk if fully consumed. | |
| if (this.currentChunkOffset >= currentChunk.length) { | |
| this.bufferQueue.shift(); | |
| this.currentChunkOffset = 0; | |
| } | |
| } else { | |
| // If no data is available, fill the rest of the buffer with silence. | |
| channel.fill(0, outputIndex); | |
| outputIndex = numSamples; | |
| } | |
| } | |
| return true; | |
| } | |
| } | |
| registerProcessor( | |
| "buffered-audio-worklet-processor", | |
| BufferedAudioWorkletProcessor, | |
| ); | |
| }; | |