"use strict"; // Dedicated audio output thread class AudioThread extends AudioWorkletProcessor { ///////////////////////// Initialization Methods ////////////////////////// constructor() { super(); // Configure instance fields this.buffers = []; // Input sample buffer queue this.offset = 0; // Offset into oldest buffer // Wait for initializer message from parent thread this.port.onmessage = m=>this.init(m.data); } async init(main) { // Configure message ports this.core = this.port; this.core.onmessage = m=>this.onCore(m.data); this.main = main; this.main.onmessage = m=>this.onMain(m.data); // Notify main thread this.port.postMessage(0); } ///////////////////////////// Public Methods ////////////////////////////// // Produce output samples (called by the user agent) process(inputs, outputs, parameters) { let output = outputs[0]; let length = output [0].length; let empty = null; // Process all samples for (let x = 0; x < length;) { // No bufferfed samples are available if (this.buffers.length == 0) { for (; x < length; x++) output[0] = output[1] = 0; break; } // Transfer samples from the oldest buffer let y, buffer = this.buffers[0]; for (y = this.offset; x < length && y < buffer.length; x++, y+=2) { output[0][x] = buffer[y ]; output[1][x] = buffer[y + 1]; } // Advance to the next buffer if ((this.offset = y) == buffer.length) { if (empty == null) empty = []; empty.push(this.buffers.shift()); this.offset = 0; } } // Return emptied sample buffers to the core thread if (empty != null) this.core.postMessage(empty, empty.map(e=>e.buffer)); return true; } ///////////////////////////// Message Methods ///////////////////////////// // Message received from core thread onCore(msg) { } // Message received from main thread onMain(msg) { } } registerProcessor("AudioThread", AudioThread);