# Pulsar: Zig-only PulseAudio Library

**URL:** <https://ziggit.dev/t/pulsar-zig-only-pulseaudio-library/8737>\
**Category:** Showcase\
**Created:** [February 24, 2025, 10:34pm UTC](https://ziggit.dev/t/pulsar-zig-only-pulseaudio-library/8737 "2025-02-24T22:34:03Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![desttinghim](https://ziggit.dev/user_avatar/ziggit.dev/desttinghim/32/70_2.png) [@desttinghim](https://ziggit.dev/u/desttinghim)\
**Post date:** [February 24, 2025, 10:34pm UTC](https://ziggit.dev/t/pulsar-zig-only-pulseaudio-library/8737/1 "2025-02-24T22:34:03Z")

</div>

[Link to the repository.](https://codeberg.org/desttinghim/pulsar)

# 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](https://en.wikipedia.org/wiki/Pulsar)

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`.

```zig
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](https://ziggit.dev/t/shimizu-the-wayland-protocol-in-zig/6246). I plan to use it as a component in [Seizer: Wayland application framework](https://ziggit.dev/t/seizer-wayland-application-framework/6788). 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](https://www.gamingonlinux.com/2025/02/the-glibc-2-41-update-has-been-causing-problems-for-linux-gaming/).

---

<div class="post-metadata">

**Author:** ![andrewrk](https://ziggit.dev/user_avatar/ziggit.dev/andrewrk/32/7011_2.png) [@andrewrk](https://ziggit.dev/u/andrewrk)\
**Post date:** [February 25, 2025, 7:27pm UTC](https://ziggit.dev/t/pulsar-zig-only-pulseaudio-library/8737/2 "2025-02-25T19:27:27Z")

</div>

Very cool!

Here is the [libpulse API surface area](https://codeberg.org/andrewrk/groovebasin/src/commit/832f8ec6595e23d70ab63526a406838c05e92ac4/player/root.zig#L585-L763) in my music player project. Do you think Pulsar could be a good fit?

---

<div class="post-metadata">

**Author:** ![desttinghim](https://ziggit.dev/user_avatar/ziggit.dev/desttinghim/32/70_2.png) [@desttinghim](https://ziggit.dev/u/desttinghim)\
**Post date:** [February 25, 2025, 8:03pm UTC](https://ziggit.dev/t/pulsar-zig-only-pulseaudio-library/8737/3 "2025-02-25T20:03:09Z")

</div>

In the future I think it will be. Pulsar currently doesn’t have most features implemented, so it would be too soon to try and port it though 😅 My own use case is games which can use a little less of the API, but I’d be happy to add the features necessary for GrooveBasin to make use of it too. I’ve made a [tracking issue](https://codeberg.org/desttinghim/pulsar/issues/1) for it.

---

<div class="post-metadata">

**Author:** ![andrewrk](https://ziggit.dev/user_avatar/ziggit.dev/andrewrk/32/7011_2.png) [@andrewrk](https://ziggit.dev/u/andrewrk)\
**Post date:** [February 26, 2025, 5:11am UTC](https://ziggit.dev/t/pulsar-zig-only-pulseaudio-library/8737/4 "2025-02-26T05:11:50Z")

</div>

Would be pretty sweet to combine this, seizer, and [dvui](https://www.youtube.com/watch?v=B9dwuBXmTW0) 🤔

---

<div class="post-metadata">

**Author:** ![Luke](https://ziggit.dev/letter_avatar_proxy/v4/letter/l/7ab992/32.png) [@Luke](https://ziggit.dev/u/Luke)\
**Post date:** [February 28, 2025, 4:34pm UTC](https://ziggit.dev/t/pulsar-zig-only-pulseaudio-library/8737/5 "2025-02-28T16:34:17Z")

</div>

I was thinking of using this and create a [GeigerAllocator](https://github.com/laserallan/malloc_geiger). Could be a fun WE project.

---

<div class="post-metadata">

**Author:** ![desttinghim](https://ziggit.dev/user_avatar/ziggit.dev/desttinghim/32/70_2.png) [@desttinghim](https://ziggit.dev/u/desttinghim)\
**Post date:** [March 9, 2025, 11:30pm UTC](https://ziggit.dev/t/pulsar-zig-only-pulseaudio-library/8737/6 "2025-03-09T23:30:54Z")

</div>

I’ve made a new release of Pulsar!

> **[pulsar](https://codeberg.org/desttinghim/pulsar/src/tag/0.1.0)**
>
> pulsar

> This release greatly improves Pulsar’s API from version `0.0.0`. It removes the need to use an allocator, gives the user greater control over the event loop, and handles the PulseAudio protocol more correctly in general. A few more examples have been added to make Pulsar easier to figure out.

Read the [changelog](https://codeberg.org/desttinghim/pulsar/src/tag/0.1.0/CHANGELOG.md) for more details.

---

<div class="post-metadata">

**Author:** ![desttinghim](https://ziggit.dev/user_avatar/ziggit.dev/desttinghim/32/70_2.png) [@desttinghim](https://ziggit.dev/u/desttinghim)\
**Post date:** [March 13, 2025, 7:23pm UTC](https://ziggit.dev/t/pulsar-zig-only-pulseaudio-library/8737/7 "2025-03-13T19:23:33Z")

</div>

I’ve made a patch release, [Pulsar 0.1.1](https://codeberg.org/desttinghim/pulsar/src/branch/0.1.1). The only change is that I’ve marked the dependencies in `build.zig.zon` as lazy. They is a non-breaking change, and the only effect is to prevent extra downloads when using Pulsar as a dependency. The dependencies are only there for some of the examples to use, as otherwise Pulsar depends only on the zig standard library for compilation.
