Skip to content

zig-gamedev/zaudio

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

23 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Zig build package and wrapper for miniaudio v0.11.22

As an example program please see audio experiments (wgpu).

Features

Provided structs:

  • Device
  • Engine
  • Sound
  • SoundGroup
  • NodeGraph
  • Fence
  • Context (missing methods)
  • ResourceManager (missing methods)
  • Log (missing methods)
  • DataSource (missing methods)
    • Waveform
    • Noise
    • custom data sources
  • Node
    • DataSourceNode
    • SplitterNode
    • BiquadNode
    • LpfNode // Low-Pass Filter
    • HpfNode // High-Pass Filter
    • NotchNode
    • PeakNode
    • LoshelfNode // Low Shelf Filter
    • HishelfNode // High Shelf Filter
    • DelayNode
    • custom nodes
  • Decoder (missing methods)
  • Encoder (missing methods)
  • DataConverter

Getting started

In your build.zig add:

pub fn build(b: *std.Build) void {
    const exe = b.addExecutable(.{ ... });

    const zaudio = b.dependency("zaudio", .{});
    exe.root_module.addImport("zaudio", zaudio.module("root"));
    exe.linkLibrary(zaudio.artifact("miniaudio"));
}

Now in your code you may import and use the high level API of zaudio:

const zaudio = @import("zaudio");

pub fn main() !void {
    ...
    zaudio.init(allocator);
    defer zaudio.deinit();

    const engine = try zaudio.Engine.create(null);
    defer engine.destroy();

    const music = try engine.createSoundFromFile(
        content_dir ++ "Broke For Free - Night Owl.mp3",
        .{ .flags = .{ .stream = true } },
    );
    defer music.destroy();
    try music.start();
    ...
}

Or use the low level API which is similar to the original miniaudio library, but because the callback function is bridged from the original C library, you must explicitly handle the errors at the callback level:

const zaudio = @import("zaudio");

pub fn main() !void {
  ...
  zaudio.init(std.heap.smp_allocator);
  defer zaudio.deinit();

  const decoder_config = zaudio.Decoder.Config.initDefault();
  var mp3_decoder = try zaudio.Decoder.createFromFile("testing_media/Accipiter Supersaw Demo.mp3", decoder_config);
  defer mp3_decoder.destroy();

  // device
  var device_config = zaudio.Device.Config.init(.playback);
  device_config.playback.format = zaudio.Format.float32;
  device_config.playback.channels = 2;
  device_config.sample_rate = SAMPLE_RATE;
  device_config.data_callback = data_callback; // we will fill that with actual signal source
  device_config.user_data = mp3_decoder;

  const device = zaudio.Device.create(null, device_config) catch {
      @panic("Failed to open playback device");
  };
  defer device.destroy();

  zaudio.Device.start(device) catch {
      zaudio.Device.destroy(device);
      @panic("Failed to start playback device");
  };
  ...
}

fn data_callback(device: *zaudio.Device, pOutput: ?*anyopaque, _: ?*const anyopaque, frame_count: u32) callconv(.c) void {
    const decoder_opt: ?*zaudio.Decoder = @ptrCast(device.getUserData());

    if (decoder_opt) |decoder| {
        var frames_read: u64 = 0;

        _ = try decoder.readPCMFrames(pOutput.?, frame_count) catch |err| {
            std.debug.print("ERROR: {any}", .{err});
            return;
        };

        if (frames_read < frame_count) {
            decoder.seekToPCMFrames(0) catch {
                @panic("cannot seek");
            };
        }
    } else {
        return;
    }
}

Releases

No releases published

Packages

No packages published

Contributors 5