Lucky Robots Blog Open Roles

2.11 · Audio

Real-time audio built on miniaudio: a singleton engine that owns the output device, a voice pool, optional spatialisation and room simulation, sound graphs for procedural synthesis, and a sound-bank packaging step for shipping.

Module: Hazel/src/Hazel/Audio/ AudioEngine.h Sound.h miniaudio backend spatial: HZ_HAS_SPATIAL_AUDIO
Audio asset .wav / .ogg / SoundGraph SoundBank runtime packaging MiniAudioEngine singleton · context + device SourceManager voice pool Sound playback state · volume / pitch Output device OS audio mixer AudioComponent ECS AudioListener ECS AudioPlayback (static API) fire-and-forget playback edit-time runtime pack
Signal flow: asset → (optional) SoundBank → MiniAudioEngine → SourceManager → Sound → OS output. ECS components and the static AudioPlayback API drive playback.

Overview

Audio is built around miniaudio. MiniAudioEngine is a process-wide singleton that owns the audio context and the output device, manages listeners, and — when the build defines HZ_HAS_SPATIAL_AUDIO — runs room simulation for 3D sounds. The engine subscribes to the active scene through OnSceneStart(scene) and OnSceneStop(), so listeners and voices reset cleanly when the editor enters and exits play mode.

Ownership & lifecycle

  • Process scope: MiniAudioEngine initialises miniaudio once at boot and holds it until shutdown.
  • Scene scope: OnSceneStart(scene) binds the engine to the scene's listeners and audio sources; OnSceneStop() tears them down.
  • Voice scope: the SourceManager pre-allocates a fixed pool of voices and hands them out to Sound instances. When the pool is exhausted, new requests steal the lowest-priority voice.

Key types

TypeHeaderRole
MiniAudioEngine AudioEngine.h Singleton. Owns miniaudio context + device. Listener management, scene lifecycle hooks, room simulation when HZ_HAS_SPATIAL_AUDIO is set.
Sound Sound.h Per-voice playback state — volume, pitch, spatialisation, looping, position.
SourceManager SourceManager.h Fixed-size voice pool. Allocates and recycles Sound voices.
AudioPlayback AudioPlayback.h Static playback API. Fire-and-forget convenience entry point for scripts and gameplay code.
SoundBank SoundBank.h Runtime asset packaging for audio. Lets a shipped build load all sound data from a single bundle.
AudioComponent AudioComponent.h ECS component. Attaches a sound source to an entity for 3D playback that follows the entity transform.
AudioListenerComponent AudioListenerComponent.h ECS component. Marks the entity that drives the listener pose for spatial audio.

Spatial audio

Spatialisation is gated behind HZ_HAS_SPATIAL_AUDIO. When enabled, MiniAudioEngine tracks the listener pose from AudioListenerComponent, applies HRTF / panning to each Sound, and runs room simulation if the active scene specifies an audio environment. Builds without the flag fall back to non-spatial stereo mixing — the API still compiles.

Listener uniqueness

Spatial mixing assumes a single active AudioListenerComponent. If a scene has more than one, the engine picks the first encountered and ignores the rest — verify in the editor that you have exactly one listener.

Extending

  • New sound source: import an audio file as a SoundConfig asset, then either drive it from gameplay via AudioPlayback or attach it to an entity through AudioComponent.
  • Procedural synthesis: use the SoundGraphSound asset and the audio sound graph editor (a panel under the Editor system).
  • New DSP effect: add the node to the sound graph runtime and register it with the editor node catalogue.
  • Shipping: the build pipeline packs audio into a SoundBank — nothing special is required from gameplay code, but make sure any runtime-generated audio uses AssetFlag::MemoryOnly (see Asset System).