simvx.core.audio_backend

Desktop audio backends for SimVX.

Three backends ship in this module:

  • MiniaudioBackend: the production path. Mixes audio natively via ma_engine (CFFI wrapper at simvx.core._native.miniaudio_engine). The native extension is built at uv pip install time by the PEP 517 build hook in packages/core/build_audio_ext_hook.py. If that build is skipped or fails, the runtime falls back to legacy.

  • _LegacyMiniaudioBackend: the fallback. Mixes in a numpy generator callback driven by miniaudio.PlaybackDevice from the miniaudio distribution, which wraps the same C library as the native path but exposes only its device and decoder layer, not its engine. Mixing therefore happens in Python under the GIL on the audio thread, which is what forces the 100 ms buffer: 20 ms would underrun on any heavy main-thread frame. It has no spatializer, so 3D positional audio is inactive on this path; bus routing, gain and effects still work.

  • NullAudioBackend: silent no-op backend used when no audio device is available (sandboxed CI, headless containers).

make_backend() resolution order, with loud warnings at every fallback (never silent degradation):

  1. Native MiniaudioBackend: picked when the extension is importable.

  2. Legacy _LegacyMiniaudioBackend: picked when native is unavailable AND a real audio device opens. Emits a one-time WARNING explaining the latency hit, and the rebuild command when the extension is the thing that is missing rather than the device.

  3. Null NullAudioBackend: picked when neither native nor legacy can start (no audio device). Emits a one-time WARNING.

Set SIMVX_ALLOW_LEGACY_AUDIO=0 to disable the legacy/null fallbacks and raise :class:AudioBackendUnavailable instead.

The runtime never invokes a C compiler. Use simvx build-audio (or uv pip install --reinstall -e packages/core) to (re)build the extension manually.

Package Contents

Functions

make_backend

Pick the best available audio backend, falling back loudly on failure.

Data

API

simvx.core.audio_backend.log

‘getLogger(…)’

simvx.core.audio_backend.__all__

[‘MiniaudioBackend’, ‘_LegacyMiniaudioBackend’, ‘NullAudioBackend’, ‘make_backend’]

simvx.core.audio_backend.make_backend(sample_rate: int = _DEFAULT_SAMPLE_RATE, nchannels: int = _DEFAULT_CHANNELS) simvx.core.audio_backend._miniaudio.MiniaudioBackend | simvx.core.audio_backend._legacy._LegacyMiniaudioBackend | simvx.core.audio_backend._null.NullAudioBackend[source]

Pick the best available audio backend, falling back loudly on failure.

Resolution order (the runtime never invokes a C compiler: that’s the install-time build hook’s job):

  1. Native MiniaudioBackend (~20 ms latency). Selected when the compiled _simvx_miniaudio_engine extension imports cleanly.

  2. Legacy _LegacyMiniaudioBackend (~100 ms latency). Selected when native is unavailable AND SIMVX_ALLOW_LEGACY_AUDIO is not set to "0". Emits a one-time WARNING naming what is lost, with rebuild instructions only when the extension is absent: a built extension that failed to open a device is not fixed by rebuilding.

  3. Null NullAudioBackend (silent). Selected when neither native nor legacy can start: typically a sandboxed CI without an audio device. Emits another one-time WARNING.

Set SIMVX_ALLOW_LEGACY_AUDIO=0 to refuse the fallback chain and raise :class:AudioBackendUnavailable if the native extension is missing or fails to initialise.