// Plays the blocks the audio worker renders. The page sends the worker's feed
// port across; every block taken off the queue is acknowledged so another one
// can be rendered. Blocks are planar: the left channel first, then the right.

class QuackPlayer extends AudioWorkletProcessor {
	constructor() {
		super();
		this.blocks = [];
		this.current = null;
		this.pos = 0;
		this.feed = null;
		this.port.onmessage = ({ data }) => {
			if (data?.type !== 'feed') return;
			this.feed = data.feed;
			this.feed.onmessage = ({ data: block }) => this.blocks.push(block);
		};
	}

	process(_inputs, outputs) {
		const [left, right] = outputs[0];
		for (let i = 0; i < left.length; i++) {
			if (!this.current || this.pos >= this.current.audio.length / 2) {
				this.current = this.blocks.shift() ?? null;
				this.pos = 0;
				if (!this.current) {
					// the worker fell behind (or is just starting)
					left.fill(0, i);
					right.fill(0, i);
					break;
				}
				this.feed?.postMessage(0);
			}
			const frames = this.current.audio.length / 2;
			left[i] = this.current.audio[this.pos];
			right[i] = this.current.audio[frames + this.pos];
			this.pos++;
		}
		return true;
	}
}

registerProcessor('quack-audio-player', QuackPlayer);