fix: reimplement audio sync
This commit is contained in:
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user