Pulsar
A pulsar is a highly magnetized rotating neutron star… [they] are very dense and have short, regular rotational periods. This produces… pulses that range from milliseconds to seconds… exceeding the accuracy of [certain] atomic clocks in keeping time. — Wikipedia page on pulsars
Pulsar is a small library for audio playback on linux, with no dependency on libc or other shared libraries. Pulsar does depend on the presence of a PulseAudio server on the target system. This can be PulseAudio itself or something like pipewire-pulse. Pulsar’s target audience is game developers, so it exposes only the subset of PulseAudio meant for realtime audio playback.
Example Code
This code is also available in examples/sine.zig
, it can be run using zig build run -Dexample=sine
.
const std = @import("std");
const pulsar = @import("pulsar");
var sample_offset: usize = 0;
fn audio_callback(info: pulsar.Stream.Info, samples: []i16) usize {
const sample_rate: f32 = @floatFromInt(info.sample_rate);
for (0..samples.len) |i| {
const amp = @cos(880 * @as(f32, @floatFromInt(sample_offset + i)) / sample_rate);
samples[i] = @intFromFloat(amp * 32000.0);
}
sample_offset += samples.len;
return samples.len;
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var ctx = try pulsar.Context.create(allocator, .{});
defer ctx.destroy(allocator);
var stream = try pulsar.Stream.create(ctx, &audio_callback, .{});
ctx.addStream(&stream);
sample_offset = 0;
const start_time = std.time.timestamp();
while (std.time.timestamp() - start_time < 10) {
try ctx.run();
}
}
What
Pulsar is inspired mostly by Shimizu - The Wayland Protocol, in Zig. I plan to use it as a component in Seizer: Wayland application framework. The basic idea is to allow for audio applications on Linux with no shared library dependencies - only system calls. PulseAudio (or pipewire exposing a PulseAudio API) is still a run-time dependency with this approach, but by avoiding shared libraries Pulsar-powered applications won’t break when glibc or other libraries make a breaking change.