Skip to content

Audio: voice budget — priority/distance-based voice stealing and virtualization #730

Description

@drsnuggles8

Is your feature request related to a problem? Please describe.

There is no voice budget. Audio/AudioEngine.cpp has no max-voice cap, no per-sound priority and no stealing policy (the only Priority in the file is an OS thread priority). Every AudioSourceComponent that starts playing gets a real voice, so a firefight, a physics pile-up or a particle system with impact sounds can spawn dozens to hundreds of simultaneous voices — which costs CPU, exceeds the backend's practical channel count, and produces mud rather than a mix. #424 (closed) routed SoundGraph voices through the 3D spatializer, which makes the distance information needed for this readily available.

Describe the solution you'd like

  • A configurable max concurrent voice count.
  • A per-sound priority field plus a computed runtime score (priority, distance to listener, current gain).
  • Stealing: when the budget is full, a new sound either takes the lowest-scoring active voice or is refused, depending on its own score.
  • Virtualization: a stolen or refused looping sound keeps advancing its logical playback position so it resumes in the right place and at the right phase when a voice frees up — a stopped-and-restarted loop is an audible bug.
  • Per-category limits (e.g. at most N footsteps) would be a natural follow-up.

Describe alternatives you've considered

Relying on miniaudio's own limits — hits a hard ceiling with no policy, so which sounds survive is arbitrary rather than the loudest/nearest/most important.

Additional context

Reference approach: D:\repos\tachyonfire\src\fn_engine\th_audio.c / .h implements a priority + distance based voice system for an arena FPS — GPLv3, read for approach only. The pattern (score, steal, virtualize) is standard across FMOD/Wwise and is documented in their public design docs.

Related: #424 (closed), Audio/SoundGraph/SoundGraphSound.

Acceptance criteria

  • Triggering far more sounds than the budget keeps the nearest/highest-priority ones audible and never exceeds the cap.
  • A virtualized looping sound resumes at the correct playback position, not from the start.
  • Headless test over the scoring/stealing policy.

Score

capability: 3
craft: 1
stability: 5
decay: 1
effort: 2
confidence: 1.0
learning: 1
fun: 3
kano: table-stakes
blocked_by: []
blocks: []

Rated per issue-scoring · score = confidence × (capability + craft + stability + decay) / effort, derived by the picker.

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    featureNew feature or requestperformancePerformance / data-oriented optimizationrobustnessProduction hardening / shipping robustness

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions