diff --git a/src/runtime/mod.rs b/src/runtime/mod.rs index 2427991..8210d08 100644 --- a/src/runtime/mod.rs +++ b/src/runtime/mod.rs @@ -19,5 +19,6 @@ pub trait Runtime { const FPS: u64 = 60; const FRAME_DURATION: Duration = Duration::from_micros(1_000_000 / FPS); -const NES_AUDIO_FREQ: f64 = 894886.5; +// True frequency is 894886.5Hz, but tuned to match my emulator's rate +const NES_AUDIO_FREQ: f64 = 93_3000.0; const TARGET_AUDIO_FREQ: i32 = 44100; diff --git a/web/audio-processor.js b/web/audio-processor.js index 835492b..742e2a7 100644 --- a/web/audio-processor.js +++ b/web/audio-processor.js @@ -2,11 +2,9 @@ class AudioProcessor extends AudioWorkletProcessor { constructor(nodeOptions) { super(); this.buffer = new CircularBuffer(2048); - this.port.onmessage = event => { + this.port.onmessage = async event => { if (event.data.type === "buffer") { - for (const value of event.data.buffer) { - this.buffer.write(value); - } + this.buffer.write(event.data.buffer); } else if (event.data.type === "mute") { console.log("Muting"); this.buffer.clear(); @@ -27,27 +25,48 @@ class CircularBuffer { this.buffer = new Float32Array(size); this.writeCursor = Math.floor(size / 2); this.readCursor = 0; + this.reads = 0; + this.writes = 0; } clear() { this.buffer.fill(0); } - write(value) { - this.buffer[this.writeCursor] = value; - this.writeCursor = (this.writeCursor + 1) % this.buffer.length; + write(values) { + this.writes += 1; + let end = this.writeCursor + values.length; + if (end < this.buffer.length) { + if (this.writeCursor < this.readCursor && this.readCursor <= end) { + // Don't write over slice that is about to be read, skip this audio + return; + } + this.buffer.set(values, this.writeCursor); + } else { + end = end - this.buffer.length; + if (this.writeCursor < this.readCursor && this.readCursor <= end) { + // Don't write over slice that is about to be read, skip this audio + return; + } + const cut = this.writeCursor - values.length + this.buffer.set(values.subarray(0, cut), this.writeCursor); + this.buffer.set(values.subarray(cut), 0); + } + this.writeCursor = end; } readSlice(length) { + this.reads += 1; + // console.log("Reads, writes", this.reads / this.writes); let end = this.readCursor + length; let result = null; if (end < this.buffer.length) { - result = this.buffer.slice(this.readCursor, end); + result = this.buffer.subarray(this.readCursor, end); } else { end = end - this.buffer.length; result = new Float32Array([ - ...this.buffer.slice(this.readCursor), - ...this.buffer.slice(0, end) + ...this.buffer.subarray(this.readCursor), + ...this.buffer.subarray(0, end) ]); } this.readCursor = end;