diff --git a/build.zig b/build.zig index 548a91e..654a6e5 100644 --- a/build.zig +++ b/build.zig @@ -39,7 +39,6 @@ pub fn build(b: *std.Build) void { // Later on we'll use this module as the root module of a test executable // which requires us to specify a target. .target = target, - .link_libc = true, }); // Here we define an executable. An executable needs to have a root module diff --git a/src/core/apu.zig b/src/core/apu.zig index c0cae37..7d8ac36 100644 --- a/src/core/apu.zig +++ b/src/core/apu.zig @@ -247,7 +247,9 @@ pub const Apu = struct { sampling_cycle: u2, - stream: *c.SDL_AudioStream, + // NB: This AudioStream is owned by platform.zig + stream: ?*c.SDL_AudioStream = null, + sched: *Scheduler, fs: FrameSequencer, @@ -273,7 +275,6 @@ pub const Apu = struct { .sampling_cycle = 0b00, .sched = sched, - .stream = undefined, // FIXME: bad practice .capacitor = 0, .fs = FrameSequencer.init(), @@ -461,32 +462,23 @@ pub const Apu = struct { if (self.sampling_cycle != self.bias.sampling_cycle.read()) self.replaceSDLResampler(); const ret = c.SDL_PutAudioStreamData(self.stream, &[2]i16{ @bitCast(ext_left ^ 0x8000), @bitCast(ext_right ^ 0x8000) }, 2 * @sizeOf(i16)); - if (!ret) @panic("TODO: Failed to put i16s into SDL Audio Queue"); + if (!ret) std.debug.panic("failed to append to sample queue. SDL Error: {s}", .{c.SDL_GetError()}); } fn replaceSDLResampler(self: *Self) void { - @branchHint(.cold); - _ = self; + const sample_rate = Self.sampleRate(self.bias.sampling_cycle.read()); + log.info("Sample Rate changed from {}Hz to {}Hz", .{ Self.sampleRate(self.sampling_cycle), sample_rate }); - // @panic("TODO: Implement Multiple Sample Rates..."); + self.sampling_cycle = self.bias.sampling_cycle.read(); - // const sample_rate = Self.sampleRate(self.bias.sampling_cycle.read()); - // log.info("Sample Rate changed from {}Hz to {}Hz", .{ Self.sampleRate(self.sampling_cycle), sample_rate }); + const desired: c.SDL_AudioSpec = .{ + .channels = 2, + .format = c.SDL_AUDIO_S16LE, + .freq = @intCast(Self.sampleRate(self.sampling_cycle)), + }; - // // Sampling Cycle (Sample Rate) changed, Craete a new SDL Audio Resampler - // // FIXME: Replace SDL's Audio Resampler with either a custom or more reliable one - // const old_stream = self.stream; - // defer c.SDL_DestroyAudioStream(old_stream); - - // self.sampling_cycle = self.bias.sampling_cycle.read(); - - // var desired: c.SDL_AudioSpec = std.mem.zeroes(c.SDL_AudioSpec); - // desired.format = c.SDL_AUDIO_S16; - // desired.channels = 2; - // desired.freq = @intCast(sample_rate); - - // const new_stream = c.SDL_OpenAudioDeviceStream(c.SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &desired, null, null) orelse @panic("TODO: Failed to replace SDL Audio Stream"); - // self.stream = new_stream; + const ret = c.SDL_SetAudioStreamFormat(self.stream, &desired, null); + if (!ret) std.debug.panic("failed to change sample rate. SDL Error: {s}", .{c.SDL_GetError()}); } fn interval(self: *const Self) u64 { diff --git a/src/core/emu.zig b/src/core/emu.zig index 0ae6f1c..9e60777 100644 --- a/src/core/emu.zig +++ b/src/core/emu.zig @@ -160,13 +160,13 @@ pub fn runFrame(sched: *Scheduler, cpu: *Arm7tdmi) void { } } -fn audioSync(audio_sync: bool, stream: *c.SDL_AudioStream, is_buffer_full: *bool) void { - // comptime std.debug.assert(@import("../platform.zig").sample_format == SDL.AUDIO_U16); +fn audioSync(audio_sync: bool, stream: ?*c.SDL_AudioStream, is_buffer_full: *bool) void { + if (stream == null) return; + const sample_size = 2 * @sizeOf(u16); const max_buf_size: c_int = 0x400; _ = audio_sync; - _ = stream; _ = is_buffer_full; _ = sample_size; diff --git a/src/platform.zig b/src/platform.zig index 738fbe0..8a9abdd 100644 --- a/src/platform.zig +++ b/src/platform.zig @@ -46,6 +46,8 @@ pub const Gui = struct { allocator: Allocator, pub fn init(allocator: Allocator, apu: *Apu, title_opt: ?*const [12]u8) !Self { + errdefer |err| if (err == error.sdl_error) log.err("SDL Error: {s}", .{c.SDL_GetError()}); + c.SDL_SetMainReady(); try errify(c.SDL_Init(c.SDL_INIT_VIDEO | c.SDL_INIT_AUDIO | c.SDL_INIT_EVENTS)); @@ -200,16 +202,16 @@ pub const Gui = struct { var zgui_redraw: bool = false; switch (self.state.emulation) { - .Transition => |inner| switch (inner) { + .Transition => |target| switch (target) { .Active => { sync.paused.store(false, .monotonic); - // if (!config.config().host.mute) try errify(c.SDL_PauseAudioDevice(c.SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK)); + if (!config.config().host.mute) try errify(c.SDL_ResumeAudioStreamDevice(self.audio.stream)); self.state.emulation = .Active; }, .Inactive => { // Assert that double pausing is impossible - // try errify(c.SDL_ResumeAudioDevice(c.SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK)); + if (!config.config().host.mute) try errify(c.SDL_PauseAudioStreamDevice(self.audio.stream)); sync.paused.store(true, .monotonic); self.state.emulation = .Inactive; @@ -233,7 +235,7 @@ pub const Gui = struct { // spurious calls to SDL_LockAudioDevice? try errify(c.SDL_LockAudioStream(self.audio.stream)); - defer errify(c.SDL_UnlockAudioStream(self.audio.stream)) catch @panic("TODO: FIXME"); + defer errify(c.SDL_UnlockAudioStream(self.audio.stream)) catch std.debug.panic("SDL Error: {s}", .{c.SDL_GetError()}); zgui_redraw = imgui.draw(&self.state, sync, win_dim, cpu, out_tex[0]); }, @@ -257,17 +259,17 @@ pub const Gui = struct { } }; -const Audio = struct { - const Self = @This(); - const log = std.log.scoped(.PlatformAudio); +pub const Audio = struct { + const log = std.log.scoped(.platform_audio); stream: *c.SDL_AudioStream, - fn init(apu: *Apu) !Self { - var desired: c.SDL_AudioSpec = std.mem.zeroes(c.SDL_AudioSpec); - desired.freq = sample_rate; - desired.format = c.SDL_AUDIO_S16LE; - desired.channels = 2; + fn init(apu: *Apu) !@This() { + const desired: c.SDL_AudioSpec = .{ + .freq = sample_rate, + .format = c.SDL_AUDIO_S16LE, + .channels = 2, + }; log.info("Host Sample Rate: {}Hz, Host Format: SDL_AUDIO_S16LE", .{sample_rate}); @@ -278,7 +280,7 @@ const Audio = struct { return .{ .stream = stream }; } - fn deinit(self: *Self) void { + fn deinit(self: *@This()) void { c.SDL_DestroyAudioStream(self.stream); self.* = undefined; }