Short version: doomkit does not support sound, and that is deliberate, not an
oversight. The six DG_* callbacks doomkit documents are video, input, and
timing only. DOOM's audio lives inside the engine, behind a different seam, and
on the kinds of constrained platforms doomkit targets it is usually unwanted (or
physically impossible) anyway. This document explains the architecture so the
absence makes sense, and points you at the engine's own backend if your platform
can have sound.
The doomkit contract is six callbacks: DG_Init, DG_DrawFrame, DG_SleepMs,
DG_GetTicksMs, DG_GetKey, DG_SetWindowTitle. None of them touch audio —
because DOOM's sound was never part of the platform porting layer in the first
place. It is handled within the engine by i_sound.c, which dispatches through
its own internal interface (sound_module_t / music_module_t in
i_sound.h) to backends like SDL or Allegro.
So sound and video sit behind two different seams:
VIDEO / INPUT / TIMING SOUND
────────────────────── ─────
engine ──DG_DrawFrame──▶ platform engine ──sound_module_t──▶ SDL / Allegro
(the doomkit contract) (internal to the engine, not doomkit)
doomkit is the documentation and clean extraction of the left seam. The right seam is engine-internal upstream code; doomkit neither owns it nor exposes it.
This is the part worth internalising, because it explains why "just add a sound
callback like DG_DrawFrame" is not actually simple:
| What the engine hands the platform | What the platform must do | |
|---|---|---|
| Video | A finished 8-bit paletted frame buffer | Convert + blit it. That's all. |
| Sound | Events ("play lump #37 on channel 3, volume V, stereo separation S") and for music a raw blob of MUS bytes | Mix several PCM channels into one stream (resample 11 kHz mono, apply volume + L/R pan) and synthesize the MUS/MIDI music into audio |
The engine renders video for you; it only orchestrates sound. Producing the actual samples — a software mixer plus a MIDI/OPL synth — is real DSP work, and it is exactly the work the SDL and Allegro backends exist to do. That is why audio needs a backend at all, while video needs only a memcpy.
doomkit exists to make porting DOOM to a new or constrained platform legible — the "I ran DOOM on my toaster / oscilloscope / microcontroller" class of port. For those targets:
- The demo is the picture. Sound is rarely the point.
- The hardware often has no audio output, or no spare cycles to mix PCM and emulate an OPL2 chip in real time — which is the heaviest part of DOOM audio.
- Adding a generic mixer + synth would be the most code, for the least-wanted feature, on the platforms least able to run it — while diluting the one thing doomkit is for: a small, fully-testable, six-function seam.
So the absence is a feature of the scope, not a gap to be filled.
If your platform has SDL or another OS-level audio API, you do not need doomkit to add anything — the upstream engine already ships a complete backend. You enable it at the engine layer, not the doomkit layer:
- Compile the engine's audio files that doomkit's library build deliberately
omits:
i_sdlsound.c,i_sdlmusic.c,mus2mid.c(and their support files such asgusconf.c). doomkit'sMakefilelists the portable engine set explicitly inDG_ENGINE_NAMESand leaves these out on purpose — add them back for an SDL build. - Define
FEATURE_SOUNDwhen compiling the engine. Without it,i_sound.cwires up no modules and every audio call is a no-op (this is doomkit's current default). - Link
SDL2andSDL2_mixer. - Initialise the audio subsystem on your side — e.g.
SDL_InitSubSystem( SDL_INIT_AUDIO)in yourDG_Init.
That is the whole job for an SDL desktop or wasm port: it is build-and-link
plumbing, not new logic, because the mixing and music synthesis already exist in
the engine. The DOOM sound code is pull-based — once the backend is initialised
the engine drives it directly from the WAD; no extra DG_* callback is involved.
Then you are in the genuinely hard case, and it is out of scope for doomkit. To produce sound you would have to supply, yourself, the two pieces the SDL backend otherwise provides:
- a software mixer that combines DOOM's PCM channels (with volume and stereo separation) into one output buffer, and
- a music synth —
mus2mid.cconverts MUS → MIDI portably, but turning MIDI into audio needs an OPL2 emulator, a SoundFont/Timidity synth, or a hardware MIDI device.
Both have clean, dependency-free reference implementations in
Chocolate Doom (i_sound.c
mixing and the opl/ library). If you ever attempt this, the lowest-cost path is
SFX only, no music — the iconic sounds for a fraction of the effort, since the
OPL/MIDI synth is the bulk of the work — exposed through a single "here are
finished samples, play them" hook rather than a full audio contract. But for
doomkit's purpose, documenting the boundary (this file) is the deliverable;
building that subsystem is not.