Skip to content

Latest commit

 

History

History
132 lines (106 loc) · 3.57 KB

File metadata and controls

132 lines (106 loc) · 3.57 KB

Zig build package and wrapper for miniaudio v0.11.25

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;
    }
}