Zig build package and wrapper for miniaudio v0.11.22
As an example program please see audio experiments (wgpu).
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
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;
    }
}