fix: reimplement audio sync

This commit is contained in:
2025-11-12 17:59:21 -06:00
parent 497a62c16d
commit 242060e35d
2 changed files with 21 additions and 36 deletions

View File

@@ -255,8 +255,6 @@ pub const Apu = struct {
fs: FrameSequencer, fs: FrameSequencer,
capacitor: f32, capacitor: f32,
is_buffer_full: bool,
pub const Tick = enum { Length, Envelope, Sweep }; pub const Tick = enum { Length, Envelope, Sweep };
pub fn init(sched: *Scheduler) Self { pub fn init(sched: *Scheduler) Self {
@@ -278,7 +276,6 @@ pub const Apu = struct {
.capacitor = 0, .capacitor = 0,
.fs = FrameSequencer.init(), .fs = FrameSequencer.init(),
.is_buffer_full = false,
}; };
Self.initEvents(apu.sched, apu.interval()); Self.initEvents(apu.sched, apu.interval());
@@ -399,11 +396,6 @@ pub const Apu = struct {
pub fn sampleAudio(self: *Self, late: u64) void { pub fn sampleAudio(self: *Self, late: u64) void {
self.sched.push(.SampleAudio, self.interval() -| late); self.sched.push(.SampleAudio, self.interval() -| late);
// Whether the APU is busy or not is determined by the main loop in emu.zig
// This should only ever be true (because this side of the emu is single threaded)
// When audio sync is disaabled
if (self.is_buffer_full) return;
var left: i16 = 0; var left: i16 = 0;
var right: i16 = 0; var right: i16 = 0;

View File

@@ -95,7 +95,7 @@ fn inner(comptime kind: RunKind, audio_sync: bool, cpu: *Arm7tdmi, scheduler: *S
if (sync.paused.load(.monotonic)) continue; if (sync.paused.load(.monotonic)) continue;
runFrame(scheduler, cpu); runFrame(scheduler, cpu);
audioSync(audio_sync, bus_ptr.apu.stream, &bus_ptr.apu.is_buffer_full); if (audio_sync) audioSync(bus_ptr.apu.stream);
if (kind == .UnlimitedFPS) tracker.?.tick(); if (kind == .UnlimitedFPS) tracker.?.tick();
} }
@@ -117,10 +117,13 @@ fn inner(comptime kind: RunKind, audio_sync: bool, cpu: *Arm7tdmi, scheduler: *S
// the amount of time needed for audio to catch up rather than // the amount of time needed for audio to catch up rather than
// our expected wake-up time // our expected wake-up time
audioSync(audio_sync, bus_ptr.apu.stream, &bus_ptr.apu.is_buffer_full); if (audio_sync) {
if (!audio_sync) spinLoop(&timer, wake_time); audioSync(bus_ptr.apu.stream);
wake_time = new_wake_time; } else {
spinLoop(&timer, wake_time);
}
wake_time = new_wake_time;
if (kind == .LimitedFPS) tracker.?.tick(); if (kind == .LimitedFPS) tracker.?.tick();
} }
}, },
@@ -160,35 +163,25 @@ pub fn runFrame(sched: *Scheduler, cpu: *Arm7tdmi) void {
} }
} }
fn audioSync(audio_sync: bool, stream: ?*c.SDL_AudioStream, is_buffer_full: *bool) void { fn audioSync(stream: ?*c.SDL_AudioStream) void {
if (stream == null) return; if (stream == null) {
@branchHint(.cold);
return log.err("audio sync failed. no SDL_AudioStream to sync to", .{});
}
const sample_size = 2 * @sizeOf(u16); const sample_size = 2 * @sizeOf(u16);
const max_buf_size: c_int = 0x400; const max_sample_delay: c_int = 0x800;
var is_behind = true;
_ = audio_sync; while (is_behind) {
_ = is_buffer_full; const bytes = c.SDL_GetAudioStreamQueued(stream);
if (bytes == -1) std.debug.panic("failed to query amount of queued bytes in audio stream: SDL Error {s}", .{c.SDL_GetError()});
_ = sample_size; is_behind = bytes > max_sample_delay * sample_size;
_ = max_buf_size; std.atomic.spinLoopHint();
}
// TODO(paoda): re-enable // FIXME(paoda, 2025-11-12): There was an is_buffer_full thing going on here that I'm sure was really important for some niche reason
// // Determine whether the APU is busy right at this moment
// var still_full: bool = SDL.SDL_AudioStreamAvailable(stream) > sample_size * if (is_buffer_full.*) max_buf_size >> 1 else max_buf_size;
// defer is_buffer_full.* = still_full; // Update APU Busy status right before exiting scope
// // If Busy is false, there's no need to sync here
// if (!still_full) return;
// // TODO: Refactor!!!!
// // while (SDL.SDL_AudioStreamAvailable(stream) > sample_size * max_buf_size >> 1)
// // std.atomic.spinLoopHint();
// while (true) {
// still_full = SDL.SDL_AudioStreamAvailable(stream) > sample_size * max_buf_size >> 1;
// if (!audio_sync or !still_full) break;
// }
} }
fn videoSync(timer: *Timer, wake_time: u64) u64 { fn videoSync(timer: *Timer, wake_time: u64) u64 {