Skip to content

sokol + raylib: use shared labelle-audio-decode, drop duplicated dr_wav/stb_vorbis (#391) - #392

Merged
apotema merged 3 commits into
mainfrom
feat/backend-decode-unify
Jun 28, 2026
Merged

apotema merged 3 commits into
mainfrom
feat/backend-decode-unify

Conversation

@apotema

@apotema apotema commented Jun 28, 2026 •

Copy link
Copy Markdown
Contributor

Completes the decode-unification half of #391: sokol AND raylib each shipped an identical decodeAudio + identical dr_wav/stb_vorbis C sources. Both now forward to the shared labelle-audio-decode module (v0.4.1).

Changes (per backend)

  • Dep: raylib adds / sokol bumps labelle_audio to v0.4.1 (sokol was on v0.3.0 for the mixer; the base module is unchanged across the bump).
  • build.zig: import the labelle-audio-decode module onto the audio module; drop the addCSourceFile(stb_vorbis.c) / dr_wav_impl.c + include-path lines.
  • decodeAudio: body replaced with a forward to @import("labelle-audio-decode").decodeAudio(file_type, data, alloc). Public surface (decodeAudio/uploadSound/unloadSound/DecodedAudio/Sound) byte-identical — DecodedAudio unifies with the base mixer's type, so uploadSound→loadSoundFromPcm is unaffected.
  • Deleted: dr_wav.h, dr_wav_impl.c, stb_vorbis.c, stb_vorbis_decl.h from both — ~29,468 LOC of duplicated C removed. stb_truetype/stb_image kept (fonts/images).

WAV now decodes via the pure-Zig parser (dr_wav dropped entirely); OGG via the shared stb_vorbis.

Verified

zig build + zig build test-host green for both backends. Mixer+decode coexist in one Compile (the v0.4.0 bug, fixed in labelle-audio v0.4.1). raylib unaffected by that bug (it uses only decode). Codegen (writeAudioBackendWiring) untouched — its generalization stays the Phase-6 task.

Refs #391.

Summary by CodeRabbit

  • New Features

    • Audio decoding for supported backends now routes through a shared decoder for more consistent behavior across platforms.
  • Bug Fixes

    • Improved decode error reporting: empty input, unsupported formats, and malformed WAV files now surface clearer, more specific failures.
    • Updated backend audio decoding to forward results more directly for reliable PCM upload/playback.
  • Refactor

    • Removed backend-local WAV/OGG decoder implementations and standardized on the shared decoding module.
  • Tests

    • Adjusted Phase 4 audio decoding tests to match the shared decoder’s error behavior.

apotema added 2 commits June 27, 2026 21:09
…is (#391)

Rewire the raylib backend's decodeAudio onto the shared labelle-audio v0.4.0
`labelle-audio-decode` module (pure-Zig WAV + stb_vorbis OGG) and delete the
duplicated dr_wav/stb_vorbis C decoders.

- Add labelle_audio v0.4.0 dep; wire `labelle-audio-decode` onto audio_mod +
  audio_host_mod; drop the stb_vorbis.c / dr_wav_impl.c addCSourceFile lines.
- decodeAudio now forwards to shared_decode.decodeAudio; DecodedAudio re-exported
  from the shared module. Public surface (decodeAudio/uploadSound/unloadSound/
  DecodedAudio/Sound) unchanged; uploadSound/unloadSound still use raylib Wave +
  the slot pool.
- Error-name shift: empty -> AudioEmptyInput, unknown -> AudioUnsupportedFormat,
  malformed WAV -> NotRiff (shared pure-Zig decoder is more specific). Tests
  updated.
- Delete dr_wav.h, dr_wav_impl.c, stb_vorbis.c, stb_vorbis_decl.h (14,734 LOC).
- stb_truetype kept (font baker).

build / test / test-host all green.

Sokol NOT migrated: blocked upstream. labelle-audio v0.4.0 packages wav.zig into
BOTH the labelle-audio (mixer) and labelle-audio-decode module roots by file
path; sokol needs both in one binary (mixer + OGG decode), which Zig 0.16 rejects
("file exists in modules 'labelle-audio' and 'labelle-audio-decode'"). Needs a
package fix: promote wav.zig to a shared named module. Sokol left on v0.3.0.
#391)

Rewire the sokol backend's decodeAudio onto the shared labelle-audio v0.4.1
`labelle-audio-decode` module (pure-Zig WAV + stb_vorbis OGG) and delete the
duplicated dr_wav/stb_vorbis C decoders. This is the sokol half of #391, which
was blocked by v0.4.0's packaging bug (wav.zig in both module roots by path);
v0.4.1 fixes it (decode reaches wav by name through the base module), so the
mixer (labelle-audio) and decoder (labelle-audio-decode) now coexist in one
Compile — the sokol-specific requirement.

- Bump labelle_audio v0.3.0 -> v0.4.1; wire `labelle-audio-decode` onto
  audio_mod alongside the existing `labelle-audio` mixer; drop the
  stb_vorbis.c / dr_wav_impl.c addCSourceFile lines + the audio emsdk include.
- decode.zig now forwards to shared_decode.decodeAudio; DecodedAudio re-exported
  from the shared module (unifies with the mixer's type, so uploadSound's
  loadSoundFromPcm is unaffected). Public surface (decodeAudio/uploadSound/
  unloadSound/DecodedAudio/Sound) unchanged; Sound extern layout locked.
- Error-name shift: empty -> AudioEmptyInput, unknown -> AudioUnsupportedFormat,
  garbage WAV -> NotRiff (shared pure-Zig decoder). Tests updated.
- Delete dr_wav.h, dr_wav_impl.c, stb_vorbis.c, stb_vorbis_decl.h (14,734 LOC).
- stb_truetype / stb_image kept (font baker + image loader).

build / test / test-host all green.
@coderabbitai

coderabbitai Bot commented Jun 28, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ce7cffad-b622-4762-a731-325998aacdd9

📥 Commits

Reviewing files that changed from the base of the PR and between 52f6a63 and 8c9e7ed.

📒 Files selected for processing (1)
  • backends/raylib/build.zig.zon

📝 Walkthrough

Walkthrough

Both backends now import labelle-audio-decode for Phase 4 audio decoding, re-export DecodedAudio, and forward decodeAudio to the shared module. The local decoder C sources and headers are removed, dependency manifests are updated, and tests now expect the shared error surface.

Changes

Shared Audio Decode Migration

Layer / File(s) Summary
Dependency declarations
backends/raylib/build.zig.zon, backends/sokol/build.zig.zon
Raylib adds labelle_audio; sokol updates the dependency to v0.4.1.
Build wiring and backend-local decoder removal
backends/raylib/build.zig, backends/sokol/build.zig, backends/raylib/src/dr_wav_impl.c, backends/raylib/src/stb_vorbis_decl.h, backends/sokol/src/dr_wav_impl.c, backends/sokol/src/stb_vorbis_decl.h
Both build scripts stop compiling local decoder sources and import labelle-audio-decode; the backend-local decoder source/header files are removed.
Shared decode surface and forwarding
backends/raylib/src/audio.zig, backends/sokol/src/audio/decode.zig, backends/sokol/src/audio.zig
DecodedAudio becomes a re-export from the shared module and decodeAudio forwards to shared_decode.decodeAudio; related comments are updated.
Phase 4 test expectations
backends/raylib/src/audio.zig, backends/sokol/src/audio/decode.zig
Tests now expect error.AudioEmptyInput, error.AudioUnsupportedFormat, and error.NotRiff from the shared decoder.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related issues

Poem

🐇 Hop, hop—one decoder path today,
WAV and OGG now bounce the same way.
C files tucked away, neat and small,
Zig takes the decoding for one and all.
Thump, thump, the build is light and spry,
This bunny ears a cleaner sky.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: both backends now use shared labelle-audio-decode and remove duplicated decoder sources.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/backend-decode-unify

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request replaces the hand-rolled C-based audio decoders (dr_wav and stb_vorbis) in both the raylib and sokol backends with the shared labelle-audio-decode module from the labelle_audio package. This simplifies the build configuration and unifies the decoding logic across backends. The feedback recommends updating the labelle_audio dependency in the raylib backend from v0.4.0 to v0.4.1 to match the sokol backend, ensuring consistency and preventing potential duplicate dependency resolution issues.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +34 to +37
.labelle_audio = .{
.url = "https://github.com/labelle-toolkit/labelle-audio/archive/refs/tags/v0.4.0.tar.gz",
.hash = "labelle_audio-0.4.0-QQRmYFXHBAAvaS2Aoq6ezGPNOUWHWCmiiEKRp4RXZpdx",
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The PR description states that both backends are using v0.4.1 of labelle_audio. However, backends/raylib/build.zig.zon still specifies v0.4.0. To ensure consistency across backends and prevent duplicate dependency resolution issues in downstream projects that pull in both backends, please update this dependency to v0.4.1 with the correct hash.

        .labelle_audio = .{
            .url = "https://github.com/labelle-toolkit/labelle-audio/archive/refs/tags/v0.4.1.tar.gz",
            .hash = "labelle_audio-0.4.1-QQRmYI7UBADw8tnp-pTegdPnZ84eqnnoAxTa486MMYTb",
        },

raylib was migrated while v0.4.0 was current; sokol later moved to v0.4.1 (the
module-coexistence fix). raylib works on v0.4.0 (it uses only the decode module,
dodging that bug), but pinning both backends to the same version avoids a
downstream project that pulls both resolving two labelle-audio copies. (Gemini)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backends/raylib/build.zig.zon`:
- Around line 28-37: The `labelle_audio` dependency pin in `build.zig.zon` is
currently on a tag that lacks the wasm/emscripten include wiring needed by
`labelle-audio-decode`. Update the `labelle_audio` entry to a wasm-capable tag,
or otherwise add the missing `.emscripten` sysroot/include path setup in this
dependency declaration so `zig build -Dtarget=wasm32-emscripten` keeps the
header wiring intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 04ffd9cc-c19f-4f1b-8ba1-010354dc2bd5

📥 Commits

Reviewing files that changed from the base of the PR and between 268a9df and 52f6a63.

📒 Files selected for processing (15)
  • backends/raylib/build.zig
  • backends/raylib/build.zig.zon
  • backends/raylib/src/audio.zig
  • backends/raylib/src/dr_wav.h
  • backends/raylib/src/dr_wav_impl.c
  • backends/raylib/src/stb_vorbis.c
  • backends/raylib/src/stb_vorbis_decl.h
  • backends/sokol/build.zig
  • backends/sokol/build.zig.zon
  • backends/sokol/src/audio.zig
  • backends/sokol/src/audio/decode.zig
  • backends/sokol/src/dr_wav.h
  • backends/sokol/src/dr_wav_impl.c
  • backends/sokol/src/stb_vorbis.c
  • backends/sokol/src/stb_vorbis_decl.h
💤 Files with no reviewable changes (4)
  • backends/sokol/src/dr_wav_impl.c
  • backends/sokol/src/stb_vorbis_decl.h
  • backends/raylib/src/dr_wav_impl.c
  • backends/raylib/src/stb_vorbis_decl.h

Comment thread backends/raylib/build.zig.zon
@apotema
apotema merged commit 6dfe9f8 into main Jun 28, 2026
5 of 6 checks passed
@apotema
apotema deleted the feat/backend-decode-unify branch June 28, 2026 00:35
apotema added a commit that referenced this pull request Jun 28, 2026
…code

After #391/#392 this backend no longer ships its own dr_wav/stb_vorbis — decode
forwards to the shared labelle-audio-decode module. Update the rationale: the OGG
flag is now the load-bearing one (labelle-audio-decode's stb_vorbis vs raudio's),
the WAV flag is belt-and-suspenders (labelle decodes WAV in pure Zig now, no
dr_wav to collide). The fix itself is unchanged + still required.
apotema added a commit that referenced this pull request Jun 28, 2026
… missing InitAudioDevice) (#393)

* fix(raylib/audio): drop raudio's dr_wav/stb_vorbis to stop duplicate-symbol link failure

Any raylib game that uses a sound asset failed to link with ~120
`lld-link: duplicate symbol: drwav_*` / `stb_vorbis_*` errors. The audio
module compiles its own decoders (`src/dr_wav_impl.c` + `src/stb_vorbis.c`)
for the worker-thread `decodeAudio` path, while the linked raylib artifact's
`raudio.obj` embeds its own copies of the same libraries for playback — two
external definitions of every `drwav_*`/`stb_vorbis_*` symbol.

With no sound asset the audio module is never referenced, so `raudio.obj`
isn't pulled from `raylib.lib` and the game links fine — which is why this
went unnoticed; it only triggers once a game actually loads a sound.

Pass `-DSUPPORT_FILEFORMAT_WAV=0 -DSUPPORT_FILEFORMAT_OGG=0` to raylib via
raylib-zig's `config` option. raylib's `config.h` guards every default behind
`#ifndef`, so this suppresses the redundant `dr_wav`/`stb_vorbis` includes in
`raudio.c` while keeping the audio device + mixer intact. Playback uploads raw
PCM via `loadSoundFromWave`, which needs no file-format support, so the
backend's own decoders remain the single source of decode.

Verified on Windows 11 / Zig 0.16: a raylib project with a `.wav` sound
resource now links cleanly (previously 121 duplicate-symbol errors).

* fix(raylib/audio): initialize the audio device before first use

raylib refuses to create or play any Sound/Music until InitAudioDevice()
has run — without it loadSoundFromWave fails with "Failed to create data
conversion pipeline" / "Failed to create buffer". The generated main.zig
initializes the window but never the audio device, so loading any sound
errored out with AudioUploadFailed at runtime (surfaced as soon as the
duplicate-symbol link failure was fixed and a game could actually run).

Add `ensureAudioDevice()` — an idempotent, main-thread lazy init guarded by
isAudioDeviceReady() — and call it at every entry that creates a raylib
sound/music: `uploadSound` (the catalog decode->upload path), and the
legacy path-based `loadSound`/`loadMusic`. No codegen change required.

Verified on Windows 11 / Zig 0.16: a raylib project with a `.wav` sound
resource now reports `AUDIO: Device initialized successfully | miniaudio |
WASAPI` and loads/uploads the sound with no errors (previously
AudioUploadFailed). Host tests are unaffected — they deliberately never call
the audio entry points (see the note above uploadSound).

* docs(raylib/audio): refresh duplicate-symbol comment for post-#392 decode

After #391/#392 this backend no longer ships its own dr_wav/stb_vorbis — decode
forwards to the shared labelle-audio-decode module. Update the rationale: the OGG
flag is now the load-bearing one (labelle-audio-decode's stb_vorbis vs raudio's),
the WAV flag is belt-and-suspenders (labelle decodes WAV in pure Zig now, no
dr_wav to collide). The fix itself is unchanged + still required.

* fix(raylib/audio): init the audio device in setVolume too

`setVolume` called `rl.setMasterVolume` directly, but SetMasterVolume before
InitAudioDevice is undefined behaviour in raylib (it touches the uninitialised
miniaudio context). A game can adjust master volume before loading any sound,
so route it through the same `ensureAudioDevice()` guard as loadSound /
loadMusic / uploadSound. Idempotent and main-thread only.

Addresses gemini-code-assist review on #393. Backend builds standalone +
test-host green.

* fix(raylib/audio): keep raudio WAV enabled; only OGG must be disabled

CodeRabbit flagged that disabling raudio's file-format decoders breaks the
still-public legacy path-based loaders (`loadSound`/`loadMusic`, which route
through raylib's own `rl.loadSound`/`rl.loadMusicStream`).

Only the OGG flag is actually load-bearing: `labelle-audio-decode` links its
own `stb_vorbis`, which collides with raudio's copy. WAV does NOT collide —
`labelle-audio-decode` decodes WAV in pure Zig (no `dr_wav`), and this backend
compiles no `dr_wav` of its own (only `stb_truetype` for fonts). Disabling WAV
bought zero collision safety and only broke legacy `loadSound("x.wav")`.

Drop `-DSUPPORT_FILEFORMAT_WAV=0`, keep `-DSUPPORT_FILEFORMAT_OGG=0`. This
restores the legacy WAV path-based + streaming surface. The residual gap is
legacy path-based *OGG* file loading (raudio can no longer decode it); the
asset catalog still loads OGG via the shared decoder. Documented the limitation
on `loadSound`/`loadMusic` and in build.zig.

Backend builds standalone + test-host green. The change cannot reintroduce a
duplicate symbol — nothing on the labelle side defines `dr_wav`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant