Problem with using `miniaudio` C library

My goal is to find a library to play sound (and link it statically).
I searched for such Zig libraries, but to my knowledge there are none.
I searched for C libraries instead and found miniaudio and it seemed simple enough especially I hardly know C and this was my first time using C in Zig.

zig version => 0.15.0-dev.64+2a4e06bcb

I tried to run their hello word example and at first I tried translating it to Zig via the build system like so…

in build.zig.zon

        .miniaudio_c = .{
            .url = "https://github.com/mackron/miniaudio/archive/refs/tags/0.11.22.tar.gz",
            .hash = "N-V-__8AAIX6uQBMQoqkZK7Ws3HsCwSJf1Z_KLsW4CJx81k3",
        },

in build.zig

    const miniaudio_c = b.dependency("miniaudio_c", .{});
    const miniaudio_translated = b.addTranslateC(.{
        .root_source_file = miniaudio_c.path("miniaudio.c"),
        .target = target,
        .optimize = optimize,
    });
    const miniaudio_mod = miniaudio_translated.createModule();
    exe.root_module.addImport("miniaudio_c", miniaudio_mod);

in src/main.zig

    var result: miniaudio.ma_result = undefined;
    var engine: miniaudio.ma_engine = undefined;

    result = miniaudio.ma_engine_init(null, &engine); // not sure what to plut here instead of `Null`
    if (result != miniaudio.MA_SUCCESS) {
        std.debug.print("Failed to initialize audio engine.", .{});
        return error.FailedToInitialize;
    }

    _ = miniaudio.ma_engine_play_sound(&engine, "../assets/sound.mp3", null);

    std.debug.print("Press Enter to quit...", .{});
    _ = try stdin.readByte();

    miniaudio.ma_engine_uninit(&engine);

But I get this error…

run
└─ run clock_temp
   └─ install
      └─ install clock_temp
         └─ zig build-exe clock_temp Debug native 2 errors
.zig-cache/o/bf127350f0098089ddfc5eab65845b26/miniaudio.zig:16658:34: error: @ptrCast increases pointer alignment
    return @as([*c]ma_node_base, @ptrCast(@volatileCast(@constCast(pNode)))).*.inputBusCount;
                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.zig-cache/o/bf127350f0098089ddfc5eab65845b26/miniaudio.zig:16658:68: note: '?*const anyopaque' has alignment '1'
    return @as([*c]ma_node_base, @ptrCast(@volatileCast(@constCast(pNode)))).*.inputBusCount;
                                                                   ^~~~~
.zig-cache/o/bf127350f0098089ddfc5eab65845b26/miniaudio.zig:16658:34: note: '[*c]miniaudio.struct_ma_node_base' has alignment '8'
.zig-cache/o/bf127350f0098089ddfc5eab65845b26/miniaudio.zig:16658:34: note: use @alignCast to assert pointer alignment
.zig-cache/o/bf127350f0098089ddfc5eab65845b26/miniaudio.zig:16666:34: error: @ptrCast increases pointer alignment
    return @as([*c]ma_node_base, @ptrCast(@volatileCast(@constCast(pNode)))).*.outputBusCount;
                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.zig-cache/o/bf127350f0098089ddfc5eab65845b26/miniaudio.zig:16666:68: note: '?*const anyopaque' has alignment '1'
    return @as([*c]ma_node_base, @ptrCast(@volatileCast(@constCast(pNode)))).*.outputBusCount;
                                                                   ^~~~~
.zig-cache/o/bf127350f0098089ddfc5eab65845b26/miniaudio.zig:16666:34: note: '[*c]miniaudio.struct_ma_node_base' has alignment '8'
.zig-cache/o/bf127350f0098089ddfc5eab65845b26/miniaudio.zig:16666:34: note: use @alignCast to assert pointer alignment
error: the following command failed with 2 compilation errors:
/home/ahmed/Zig/Zig/bin/zig build-exe -ODebug --dep sound --dep soundio_c --dep miniaudio_c --dep play_audio_c -Mroot=/home/ahmed/Zig/clock_temp/src/main.zig -ODebug -Msound=/home/ahmed/Zig/clock_temp/assets/sound.zig -ODebug -Msoundio_c=/home/ahmed/Zig/clock_temp/.zig-cache/o/8d2c807bbd3ff0adcc5e3e47ecc74ae2/soundio.zig -ODebug -Mminiaudio_c=/home/ahmed/Zig/clock_temp/.zig-cache/o/bf127350f0098089ddfc5eab65845b26/miniaudio.zig -ODebug -Mplay_audio_c=/home/ahmed/Zig/clock_temp/.zig-cache/o/729b66ccbe1f2a5b0e23ed03b7593c4f/play_audio.zig -lc --cache-dir /home/ahmed/Zig/clock_temp/.zig-cache --global-cache-dir /home/ahmed/.cache/zig --name clock_temp --zig-lib-dir /home/ahmed/Zig/Zig/lib/zig/ --listen=-
Build Summary: 3/8 steps succeeded; 1 failed
run transitive failure
└─ run clock_temp transitive failure
   ├─ zig build-exe clock_temp Debug native 2 errors
   └─ install transitive failure
      └─ install clock_temp transitive failure
         └─ zig build-exe clock_temp Debug native (+3 more reused dependencies)
error: the following build command failed with exit code 1:
/home/ahmed/Zig/clock_temp/.zig-cache/o/0cb2459cf918cd9b16c97edc9c87995c/build /home/ahmed/Zig/Zig/bin/zig /home/ahmed/Zig/Zig/lib/zig /home/ahmed/Zig/clock_temp /home/ahmed/Zig/clock_temp/.zig-cache /home/ahmed/.cache/zig --seed 0xa4919efe -Z2fcf186e3233738b run

And after some failed attempts to align properly, I said why bother and just have a src_c/play_audio.c and in src/main.zig I just play_audio.play()

in build.zig

    const play_audio_translated = b.addTranslateC(.{
        .root_source_file = b.path("src_c/play_audio.c"),
        .target = target,
        .optimize = optimize,
    });
    play_audio_translated.addIncludePath(miniaudio_c.path("."));
    const play_audio_mod = play_audio_translated.createModule();
    exe.root_module.addImport("play_audio_c", play_audio_mod);

But then, strangely, I got the same error.

After that I tried just linking it
in build.zig

    exe.addCSourceFile(.{
        .file = b.path("src_c/play_audio.c"),
    });
    exe.addIncludePath(miniaudio_c.path("."));

in src/main.zig

pub fn main() !void {
    _ = play();
}
extern fn play() i32;

in src_c/play_audi.c

#include <stdint.h>
#include <stdio.h>

#include <miniaudio.c>

int32_t play() {
    ma_result result;
    ma_engine engine;

    result = ma_engine_init(NULL, &engine);
    if (result != MA_SUCCESS) {
        printf("Failed to initialize audio engine.");
        return -1;
    }

    ma_engine_play_sound(&engine, "/../assets/sound.mp3", NULL);

    // replace with sleep
    printf("Press Enter to quit...");
    getchar();

    ma_engine_uninit(&engine);

    return 0;
}

But with the following error

thread 23461 panic: addition of unsigned offset to 0x1014d94 overflowed to 0x1014d80
/home/ahmed/.cache/zig/p/N-V-__8AAIX6uQBMQoqkZK7Ws3HsCwSJf1Z_KLsW4CJx81k3/miniaudio.h:67647:5: 0x12adfe6 in ma_hash_32 (/home/ahmed/Zig/clock_temp/src_c/play_audio.c)
    MA_COPY_MEMORY(&block, ma_offset_ptr(blocks, i * sizeof(block)), sizeof(block));
    ^
/home/ahmed/.cache/zig/p/N-V-__8AAIX6uQBMQoqkZK7Ws3HsCwSJf1Z_KLsW4CJx81k3/miniaudio.h:67718:12: 0x12ac62c in ma_hash_string_32 (/home/ahmed/Zig/clock_temp/src_c/play_audio.c)
    return ma_hash_32(str, (int)strlen(str), MA_DEFAULT_HASH_SEED);
           ^
/home/ahmed/.cache/zig/p/N-V-__8AAIX6uQBMQoqkZK7Ws3HsCwSJf1Z_KLsW4CJx81k3/miniaudio.h:69070:28: 0x11b7a70 in ma_resource_manager_data_buffer_node_acquire (/home/ahmed/Zig/clock_temp/src_c/play_audio.c)
            hashedName32 = ma_hash_string_32(pFilePath);
                           ^
/home/ahmed/.cache/zig/p/N-V-__8AAIX6uQBMQoqkZK7Ws3HsCwSJf1Z_KLsW4CJx81k3/miniaudio.h:69408:18: 0x11b2522 in ma_resource_manager_data_buffer_init_ex_internal (/home/ahmed/Zig/clock_temp/src_c/play_audio.c)
        result = ma_resource_manager_data_buffer_node_acquire(pResourceManager, pConfig->pFilePath, pConfig->pFilePathW, hashedName32, flags, NULL, notifications.init.pFence, notifications.done.pFence, &pDataBufferNode);
                 ^
/home/ahmed/.cache/zig/p/N-V-__8AAIX6uQBMQoqkZK7Ws3HsCwSJf1Z_KLsW4CJx81k3/miniaudio.h:69525:12: 0x11b1dd6 in ma_resource_manager_data_buffer_init_ex (/home/ahmed/Zig/clock_temp/src_c/play_audio.c)
    return ma_resource_manager_data_buffer_init_ex_internal(pResourceManager, pConfig, 0, pDataBuffer);
           ^
/home/ahmed/.cache/zig/p/N-V-__8AAIX6uQBMQoqkZK7Ws3HsCwSJf1Z_KLsW4CJx81k3/miniaudio.h:70794:16: 0x11be420 in ma_resource_manager_data_source_init_ex (/home/ahmed/Zig/clock_temp/src_c/play_audio.c)
        return ma_resource_manager_data_buffer_init_ex(pResourceManager, pConfig, &pDataSource->backend.buffer);
               ^
/home/ahmed/.cache/zig/p/N-V-__8AAIX6uQBMQoqkZK7Ws3HsCwSJf1Z_KLsW4CJx81k3/miniaudio.h:76737:18: 0x11dd081 in ma_sound_init_from_file_internal (/home/ahmed/Zig/clock_temp/src_c/play_audio.c)
        result = ma_resource_manager_data_source_init_ex(pEngine->pResourceManager, &resourceManagerDataSourceConfig, pSound->pResourceManagerDataSource);
                 ^
/home/ahmed/.cache/zig/p/N-V-__8AAIX6uQBMQoqkZK7Ws3HsCwSJf1Z_KLsW4CJx81k3/miniaudio.h:76881:16: 0x11deb57 in ma_sound_init_ex (/home/ahmed/Zig/clock_temp/src_c/play_audio.c)
        return ma_sound_init_from_file_internal(pEngine, pConfig, pSound);
               ^
/home/ahmed/.cache/zig/p/N-V-__8AAIX6uQBMQoqkZK7Ws3HsCwSJf1Z_KLsW4CJx81k3/miniaudio.h:76777:12: 0x11dc164 in ma_sound_init_from_file (/home/ahmed/Zig/clock_temp/src_c/play_audio.c)
    return ma_sound_init_ex(pEngine, &config, pSound);
           ^
/home/ahmed/.cache/zig/p/N-V-__8AAIX6uQBMQoqkZK7Ws3HsCwSJf1Z_KLsW4CJx81k3/miniaudio.h:76530:22: 0x11db8e0 in ma_engine_play_sound_ex (/home/ahmed/Zig/clock_temp/src_c/play_audio.c)
            result = ma_sound_init_from_file(pEngine, pFilePath, soundFlags, NULL, NULL, &pSound->sound);
                     ^
/home/ahmed/.cache/zig/p/N-V-__8AAIX6uQBMQoqkZK7Ws3HsCwSJf1Z_KLsW4CJx81k3/miniaudio.h:76573:12: 0x11dc306 in ma_engine_play_sound (/home/ahmed/Zig/clock_temp/src_c/play_audio.c)
    return ma_engine_play_sound_ex(pEngine, pFilePath, pGroup, 0);
           ^
src_c/play_audio.c:16:5: 0x1239527 in play (/home/ahmed/Zig/clock_temp/src_c/play_audio.c)
    ma_engine_play_sound(&engine, "/../assets/sound.mp3", NULL);
    ^
/home/ahmed/Zig/clock_temp/src/main.zig:24:13: 0x14659c8 in main (clock_temp)
    _ = play();
            ^
/home/ahmed/Zig/Zig/lib/zig/std/start.zig:656:37: 0x1465d4c in main (clock_temp)
            const result = root.main() catch |err| {
                                    ^
src/env/__libc_start_main.c:94:2: 0x7f25852b2efa in libc_start_main_stage2 (src/env/__libc_start_main.c)
Unwind error at address `ld-musl-x86_64.so.1:0x7f25852b2efa` (error.AddressOutOfRange), trace may be incomplete
                                                                                                                        
???:?:?: 0x0 in ??? (???)
run
└─ run clock_temp failure
error: the following command terminated unexpectedly:
/home/ahmed/Zig/clock_temp/zig-out/bin/clock_temp
Build Summary: 6/8 steps succeeded; 1 failed
run transitive failure
└─ run clock_temp failure
error: the following build command failed with exit code 1:
/home/ahmed/Zig/clock_temp/.zig-cache/o/537fd08735f315d6db5267019e9ec247/build /home/ahmed/Zig/Zig/bin/zig /home/ahmed/Zig/Zig/lib/zig /home/ahmed/Zig/clock_temp /home/ahmed/Zig/clock_temp/.zig-cache /home/ahmed/.cache/zig --seed 0xa1d9c2c-Z174ab9f221c5bfe3 run

And out of curiosity I tried just building their hello world example and running it alone as an executable with system gcc, clang and with zig cc
It compiles and runs successfully, but for zig cc in only compiles and ran with the almost the previous error

thread 24410 panic: addition of unsigned offset to 0x10176e5 overflowed to 0x10176d5
/home/ahmed/Zig/interesting/c/miniaudio/miniaudio.h:67647:5: 0x12848a6 in ma_hash_32 (engine_hello_world.c)
    MA_COPY_MEMORY(&block, ma_offset_ptr(blocks, i * sizeof(block)), sizeof(block));
    ^
/home/ahmed/Zig/interesting/c/miniaudio/miniaudio.h:67718:12: 0x1282eec in ma_hash_string_32 (engine_hello_world.c)
    return ma_hash_32(str, (int)strlen(str), MA_DEFAULT_HASH_SEED);
           ^
/home/ahmed/Zig/interesting/c/miniaudio/miniaudio.h:69070:28: 0x118e2c0 in ma_resource_manager_data_buffer_node_acquire (engine_hello_world.c)
            hashedName32 = ma_hash_string_32(pFilePath);
                           ^
/home/ahmed/Zig/interesting/c/miniaudio/miniaudio.h:69408:18: 0x1188d72 in ma_resource_manager_data_buffer_init_ex_internal (engine_hello_world.c)
        result = ma_resource_manager_data_buffer_node_acquire(pResourceManager, pConfig->pFilePath, pConfig->pFilePathW, hashedName32, flags, NULL, notifications.init.pFence, notifications.done.pFence, &pDataBufferNode);
                 ^
/home/ahmed/Zig/interesting/c/miniaudio/miniaudio.h:69525:12: 0x1188626 in ma_resource_manager_data_buffer_init_ex (engine_hello_world.c)
    return ma_resource_manager_data_buffer_init_ex_internal(pResourceManager, pConfig, 0, pDataBuffer);
           ^
/home/ahmed/Zig/interesting/c/miniaudio/miniaudio.h:70794:16: 0x1194c70 in ma_resource_manager_data_source_init_ex (engine_hello_world.c)
        return ma_resource_manager_data_buffer_init_ex(pResourceManager, pConfig, &pDataSource->backend.buffer);
               ^
/home/ahmed/Zig/interesting/c/miniaudio/miniaudio.h:76737:18: 0x11b38e1 in ma_sound_init_from_file_internal (engine_hello_world.c)
        result = ma_resource_manager_data_source_init_ex(pEngine->pResourceManager, &resourceManagerDataSourceConfig, pSound->pResourceManagerDataSource);
                 ^
/home/ahmed/Zig/interesting/c/miniaudio/miniaudio.h:76881:16: 0x11b53b7 in ma_sound_init_ex (engine_hello_world.c)
        return ma_sound_init_from_file_internal(pEngine, pConfig, pSound);
               ^
/home/ahmed/Zig/interesting/c/miniaudio/miniaudio.h:76777:12: 0x11b29c4 in ma_sound_init_from_file (engine_hello_world.c)
    return ma_sound_init_ex(pEngine, &config, pSound);
           ^
/home/ahmed/Zig/interesting/c/miniaudio/miniaudio.h:76530:22: 0x11b2140 in ma_engine_play_sound_ex (engine_hello_world.c)
            result = ma_sound_init_from_file(pEngine, pFilePath, soundFlags, NULL, NULL, &pSound->sound);
                     ^
/home/ahmed/Zig/interesting/c/miniaudio/miniaudio.h:76573:12: 0x11b2b66 in ma_engine_play_sound (engine_hello_world.c)
    return ma_engine_play_sound_ex(pEngine, pFilePath, pGroup, 0);
           ^
/home/ahmed/Zig/clock_temp/src_c/engine_hello_world.c:15:5: 0x120fdee in main (engine_hello_world.c)
    ma_engine_play_sound(&engine, "../assets/sound.mp3", NULL);
    ^
src/env/__libc_start_main.c:94:2: 0x7fc319979efa in libc_start_main_stage2 (src/env/__libc_start_main.c)
Unwind error at address `ld-musl-x86_64.so.1:0x7fc319979efa` (error.AddressOutOfRange), trace may be incomplete
                                                                                                                                       
???:?:?: 0x0 in ??? (???)
zsh: abort      ./play

And indeed when I link the manullay compiled src_c/play_audio.c by either system’s gcc or clang it runs and plays the sound.

So, can I play it with miniaudio?
what went wrong?
any suggestions for an alternative library?

translate-c/addTranslateC is only intended for header files.

Here’s a standalone test that shows the intended way to interoperate with C libraries:

4 Likes

Please search the forum for “miniaudio” there are already a bunch of older related topics (that should work with slight changes), once you have tried some of what was described there, or have new error messages we can help out with more info.

Regarding only using translate-c on the header, I prefer raylib’s way of doing that (generating the file that includes the implementation): raylib/build.zig at 2f63a15630d084290b0e41e13e8d9c35756152d4 · raysan5/raylib · GitHub
But both should work.

I didn’t know it was intended for headers files only especially that I remember testing it a few times before with C files directly and it always worked (though simple files not libraries).

Anyway I tried again and, as I expected, THE SAME ERROR

Probably many ways to skin this cat, but what I ended up doing for Terminal Doom was vendoring miniaudio.h, write the audio glue code in C and use Zig as the build system. Maybe you can find some ideas (mostly just look at build.zig and src/miniaudio/doom_miniaudio_sound_bridge.c: source repo

1 Like

I’m stuck with the same exact error. After linking I can use functions like miniaudio.ma_version or even ma_engine_init that returns sussess. If I try to use the method ma_engine_play_sound I get exactly this. Is this a bug with zig cc ?

Also wondering what I could use instead for sounds.

zig: 0.14.1

If you only need very simple buffer-streaming (e.g. no effect mixing, music, etc…) you could try sokol_audio.h, which is part of the sokol-zig package.

It’s very bare bones though and has some known issues with some obscure Linux hardware configs.

Simplest possible example to play a sine wave:

…documentation is here:

It’s used here for instance:

…all those except except the chipz emulators are written in C though.

Thanks @floooh :).

This morning someone on the Zig discord helped me figure out that the issue is due to undefined behaviour sanitize “ubsan”. Basically zig having better defaut for building than gcc and clang. Building in ReleaseFast makes the error go away and the sound playing.

When staticaly linking you can set the optimize for the lib itself within the “addStaticLibrary” to ReleaseFast

3 Likes

You could probably also try to build miniaudio with -fno-sanitize=undefined, I do this when building the sokol C code for WASM:

1 Like

Also I would like to add to this conversation with miniaudio when I try to make it run with pulseaudio backend I got some strange behavior that was making my program crash, the reason is sometime I did got the internal resampler of miniaudio try to perform some bit shifts operation on negative value which by default with zig will make my program crash.

I did take a while to understand this issue and what you should do is build miniaudio with -fwrapv to not having issue.

Zig has sane default for overflow but sadly not every C project as the same idea when it’s desirable or not :sweat_smile:.

AFAIK this is the undefined-behaviour-sanitizer at work, and should only happen in debug mode (tbh though, in reality this is unlikely to cause any critical issues - e.g. not the ‘nasal demons’ type of UB).

Thanks everyone, and thank you @bytewav.

It turned out eventually that Zig just have better defaults and that miniaudio triggered undefined behavior.

I’ve tested all of the following and it works

  • just building with -Doptimize=ReleaseFast
  • or even better only edit miniaudio_lib with .optimize = .ReleaseFast
  • or even better, I think, only edit miniaudio_lib with .sanitize_c = false
  • or even better, I think, only add to C flags fno-sanitize=undefined (instead of turning sanitization off apparently)
    miniaudio_lib.addCSourceFile(.{ .file = miniaudio_dep.path("miniaudio.c"), .flags = &.{"-fno-sanitize=undefined"} });

How I’m using it

    const miniaudio_dep = b.dependency("miniaudio_c", .{ .target = target, .optimize = optimize });
    const miniaudio_lib = b.addLibrary(.{
        .name = "miniaudio",
        .root_module = b.createModule(.{
            .target = target,
            .optimize = optimize,
            .link_libc = true,
        }),
    });
    miniaudio_lib.addCSourceFile(.{ .file = miniaudio_dep.path("miniaudio.c"), .flags = &.{"-fno-sanitize=undefined"} });
    const miniaudio_translated = b.addTranslateC(.{
        .root_source_file = miniaudio_dep.path("miniaudio.h"),
        .target = target,
        .optimize = optimize,
    });
    exe.linkLibrary(miniaudio_lib);
    exe.root_module.addImport("miniaudio_c", miniaudio_translated.createModule());

Oh! and in main.zig

fn playAudio(sound_file: [:0]const u8) !void {
    var result: ma.ma_result = undefined;
    var engine: ma.ma_engine = undefined;

    result = ma.ma_engine_init(null, &engine);
    if (result != ma.MA_SUCCESS) {
        return error.FailedToInitAudioEngine;
    }

    result = ma.ma_engine_play_sound(&engine, sound_file, null);
    if (result != ma.MA_SUCCESS) {
        return error.FailedToPlaySound;
    }

    time.sleep(14 * time.ns_per_s); // hardcoded sleep duration, figure out how to figure out audio length
}

3 Likes