declare global { interface AudioWorkletProcessor { readonly port: MessagePort; process( inputs: Float32Array[][], outputs: Float32Array[][], parameters: Map ): void; } const AudioWorkletProcessor: { prototype: AudioWorkletProcessor; new (options?: AudioWorkletNodeOptions): AudioWorkletProcessor; }; function registerProcessor( name: string, ctor: { new (): AudioWorkletProcessor } ): void; } export interface AppleAudioMessageEvent extends MessageEvent { data: Float32Array; } export class AppleAudioProcessor extends AudioWorkletProcessor { private samples: Float32Array[] = []; constructor() { super(); console.info('AppleAudioProcessor constructor'); this.port.onmessage = (ev: AppleAudioMessageEvent) => { this.samples.push(ev.data); if (this.samples.length > 256) { this.samples.shift(); } }; } static get parameterDescriptors() { return []; } process( _inputList: Float32Array[][], outputList: Float32Array[][], _parameters: Map ) { const sample = this.samples.shift(); const output = outputList[0]; if (sample) { for (let idx = 0; idx < sample.length; idx++) { output[0][idx] = sample[idx]; } } // Keep alive indefinitely. return true; } } registerProcessor('audio_worker', AppleAudioProcessor);