let U8 = (...a) => new Uint8Array(...a); class APU extends AudioWorkletProcessor { constructor() { super(); this.sampleIndex = 0; this.currentTime = 0; this.isFirstMessage = true; this.pendingUpdates = []; this.port.onmessage = (ev) => { if(this.memory) { if(this.isFirstMessage) { this.currentTime += (ev.data.t - this.currentTime) / 8; this.isFirstMessage = false; } this.pendingUpdates.push(ev.data); } else { this.load(ev.data[0], ev.data[1]); } }; } async load(platform_data, data) { let memory = new WebAssembly.Memory({ initial: 4, maximum: 4 }); let importObject = { env: { memory }, }; for (let n of ['acos', 'asin', 'atan', 'atan2', 'cos', 'exp', 'log', 'sin', 'tan', 'pow']) { importObject.env[n] = Math[n]; } for (let i = 9; i < 64; ++i) { importObject.env['reserved' + i] = () => { }; } let logLine = ''; importObject.env['logChar'] = (c) => { if(c == 10) { console.log(logLine); logLine = ''; } else { logLine += String.fromCharCode(c); } }; for (let i = 0; i < 16; ++i) { importObject.env['g_reserved' + i] = 0; } let instantiate = async (data) => (await WebAssembly.instantiate(data, importObject)).instance; let platform_instance = await instantiate(platform_data); for (let name in platform_instance.exports) { importObject.env[name] = platform_instance.exports[name] } let instance = await instantiate(data); this.memory = memory; this.snd = instance.exports.snd || platform_instance.exports.gesSnd; this.port.postMessage(2); } process(inputs, outputs, parameters) { this.isFirstMessage = true; if(this.snd) { while(this.pendingUpdates.length > 0 && this.pendingUpdates[0].t <= this.currentTime) { U8(this.memory.buffer, 80, 32).set(U8(this.pendingUpdates.shift().r)); } let u32Mem = new Uint32Array(this.memory.buffer); u32Mem[16] = this.currentTime; let channels = outputs[0]; let index = this.sampleIndex; let numSamples = channels[0].length; for(let i = 0; i < numSamples; ++i) { channels[0][i] = this.snd(index++); channels[1][i] = this.snd(index++); } this.sampleIndex = index & 0xffffffff; this.currentTime += numSamples / 44.1; } return true; } } registerProcessor('apu', APU);