pvbemu/web/core/AudioThread.js

89 lines
2.3 KiB
JavaScript

"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);