Audio system: miniaudio mixing

raudio.c is the most isolated raylib module — no OpenGL. Audio is opt-in: call InitAudioDevice() separately from InitWindow(). Playback uses miniaudio's device callback to mix linked AudioBuffer nodes.

Startup and load

InitAudioDevice()
  ├─ ma_context_init()
  ├─ ma_device_init(..., OnSendAudioDataToDevice)
  └─ ma_device_start()

Sound s = LoadSound("hit.wav")
  ├─ LoadWave() → dr_wav / stb_vorbis / dr_mp3 / …
  ├─ LoadSoundFromWave()
  │     ma_convert_frames() → device format (float32 stereo)
  │     LoadAudioBuffer() → linked list AUDIO.Buffer
  └─ UnloadWave()

PlaySound(s) → PlayAudioBuffer()

raudio.c — InitAudioDevice

Mixing callback (each audio buffer period)

OnSendAudioDataToDevice(pDevice, pFramesOut, ..., frameCount)
  ├─ memset output to silence
  ├─ ma_mutex_lock(AUDIO.System.lock)
  ├─ for each AudioBuffer in linked list:
  │     if playing && !paused:
  │         read frames (static sound or stream)
  │         MixAudioFrames(out, in, volume, pitch, pan)
  └─ ma_mutex_unlock()

raudio.c L2560+ — OnSendAudioDataToDevice

Sound vs Music vs AudioStream
  • Sound — fully decoded static buffer in RAM, low latency replay
  • Music — streaming decoder (OGG, MP3, XM, MOD) refills buffer over time
  • AudioStream — raw PCM you push with UpdateAudioStream
Format conversion at load time

Sounds are converted to the device format at load (ma_convert_frames) rather than during mixing — simpler mixer, more memory for 8/16-bit sources.

raudio.c — LoadSoundFromWave

Threading model

Mixing runs on miniaudio's audio thread. A mutex protects the buffer list — documented as not real-time safe but acceptable for games. Main thread calls PlaySound, StopSound, etc.

Compile without audio

-DSUPPORT_MODULE_RAUDIO=0 or CMake -DCUSTOMIZE_BUILD=ON -DSUPPORT_MODULE_RAUDIO=OFF removes raudio.c from the build entirely.