{module,Audio}: ability to store event name and send it later

Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
This commit is contained in:
Stephen Gutekanst 2024-04-28 15:08:25 -07:00 committed by Stephen Gutekanst
parent d690814b16
commit 33bfdee520
5 changed files with 86 additions and 37 deletions

View file

@ -18,10 +18,6 @@ pub const local_events = .{
.audio_tick = .{ .handler = audioTick },
};
pub const global_events = .{
.audio_state_change = .{ .handler = fn (mach.EntityID) void },
};
const log = std.log.scoped(name);
// The number of milliseconds worth of audio to render ahead of time. The lower this number is, the
@ -35,6 +31,7 @@ ms_render_ahead: f32 = 16,
allocator: std.mem.Allocator,
ctx: sysaudio.Context,
player: sysaudio.Player,
on_state_change: mach.AnyEvent,
output_mu: std.Thread.Mutex = .{},
output: SampleBuffer,
mixing_buffer: ?std.ArrayListUnmanaged(f32) = null,
@ -45,7 +42,7 @@ var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const SampleBuffer = std.fifo.LinearFifo(u8, .Dynamic);
fn init(audio: *Mod) !void {
fn init(audio: *Mod, on_state_change: mach.AnyEvent) !void {
const allocator = gpa.allocator();
const ctx = try sysaudio.Context.init(null, allocator, .{});
try ctx.refresh();
@ -71,6 +68,7 @@ fn init(audio: *Mod) !void {
.allocator = allocator,
.ctx = ctx,
.player = player,
.on_state_change = on_state_change,
.output = SampleBuffer.init(allocator),
.debug = debug,
});
@ -133,6 +131,7 @@ fn audioTick(audio: *Mod) !void {
// not undefined memory.
@memset(mixing_buffer.items, 0);
var did_state_change = false;
var max_samples: usize = 0;
var archetypes_iter = audio.entities.query(.{ .all = &.{
.{ .mach_audio = &.{ .samples, .playing, .index } },
@ -151,7 +150,7 @@ fn audioTick(audio: *Mod) !void {
max_samples = @max(max_samples, to_read);
if (index + to_read >= samples.len) {
// No longer playing, we've read all samples
audio.sendGlobal(.audio_state_change, .{id});
did_state_change = true;
try audio.set(id, .playing, false);
try audio.set(id, .index, 0);
continue;
@ -159,6 +158,7 @@ fn audioTick(audio: *Mod) !void {
try audio.set(id, .index, index + to_read);
}
}
if (did_state_change) audio.sendAnyEvent(audio.state().on_state_change);
// Write our rendered samples to the fifo, expanding its size as needed and converting our f32
// samples to the format the driver expects.

View file

@ -32,6 +32,10 @@ pub const Mod = ModSet(modules).Mod;
pub const EntityID = @import("module/main.zig").EntityID; // TODO: rename to just Entity?
pub const Archetype = @import("module/main.zig").Archetype;
pub const ModuleID = @import("module/main.zig").ModuleID;
pub const EventID = @import("module/main.zig").EventID;
pub const AnyEvent = @import("module/main.zig").AnyEvent;
/// To use experimental sysgpu graphics API, you can write this in your main.zig:
///
/// ```

View file

@ -7,6 +7,9 @@ pub const Entities = @import("entities.zig").Entities;
pub const Archetype = @import("Archetype.zig");
pub const ModSet = @import("module.zig").ModSet;
pub const Modules = @import("module.zig").Modules;
pub const ModuleID = @import("module.zig").ModuleID;
pub const EventID = @import("module.zig").EventID;
pub const AnyEvent = @import("module.zig").AnyEvent;
test {
std.testing.refAllDeclsRecursive(@This());

View file

@ -93,16 +93,21 @@ fn Serializable(comptime T: type) type {
return T;
}
// TODO: add runtime module support
pub const ModuleID = u32;
pub const EventID = u32;
pub const AnyEvent = struct {
module_id: ModuleID,
event_id: EventID,
};
/// Manages comptime .{A, B, C} modules and runtime modules.
pub fn Modules(comptime modules: anytype) type {
// Verify that each module is valid.
inline for (modules) |M| _ = ModuleInterface(M);
return struct {
// TODO: add runtime module support
pub const ModuleID = u32;
pub const EventID = u32;
pub const GlobalEvent = GlobalEventEnum(modules);
pub const LocalEvent = LocalEventEnum(modules);
@ -593,6 +598,28 @@ pub fn ModSet(comptime modules: anytype) type {
const mods = @fieldParentPtr(ModulesT, "mod", mod_ptr);
mods.sendGlobal(module_tag, event_name, args);
}
pub inline fn event(_: *@This(), comptime event_name: LocalEventEnumM(M)) AnyEvent {
const module_name_g: ModuleName(modules) = M.name;
const event_name_g: Modules(modules).LocalEvent = comptime Modules(modules).moduleToGlobalEvent(
M,
LocalEventEnumM,
LocalEventEnum,
event_name,
);
return .{
.module_id = @intFromEnum(module_name_g),
.event_id = @intFromEnum(event_name_g),
};
}
pub inline fn sendAnyEvent(m: *@This(), ev: AnyEvent) void {
const ModulesT = Modules(modules);
const MByName = ModsByName(modules);
const mod_ptr: *MByName = @alignCast(@fieldParentPtr(MByName, @tagName(module_tag), m));
const mods = @fieldParentPtr(ModulesT, "mod", mod_ptr);
mods.sendDynamic(ev.module_id, ev.event_id, .{});
}
};
}
};