simvx.core._native.miniaudio_engine¶
Python wrapper around the compiled _simvx_miniaudio_engine cffi extension.
Exposes a small, Pythonic surface over miniaudio’s ma_engine / ma_sound /
ma_sound_group API. Used by simvx.core.audio_backend.MiniaudioBackend
to run audio mixing in native C.
Build the extension once after install:
uv run python -m simvx.core._native.miniaudio_engine_build
If the .so is missing, importing this module raises MiniaudioEngineUnavailable
with build instructions. Callers (the backend) catch this and fall back to
the pure-Python mixer with a one-time warning.
Module Contents¶
Classes¶
Owns a single |
|
An |
|
An |
|
An |
|
An |
|
Base wrapper for ma_*_node effect nodes attached to the engine’s node graph. |
|
2nd-order low-pass biquad with configurable Q (resonance). |
|
2nd-order high-pass biquad with configurable Q (resonance). |
|
2nd-order band-pass biquad with configurable Q (bandwidth). |
|
2nd-order notch biquad (band-stop). |
|
Peaking-EQ band biquad. |
|
Low-shelf parametric-EQ band biquad. |
|
High-shelf parametric-EQ band biquad. |
|
Single-tap delay with feedback decay and wet/dry mix. |
|
Tanh-curve symmetric soft clipping (custom DSP node). |
|
Feed-forward compressor with soft knee (custom DSP node). |
|
Schroeder-style algorithmic reverb (custom DSP node). |
Functions¶
True if the native extension was built and loaded successfully. |
|
Re-run the extension import. |
|
Human-readable miniaudio result code. |
|
Return the engine’s audio destination node (chain tail attaches here). |
|
Cast a SoundGroup to a generic node pointer for chain wiring. |
|
Route |
|
Detach the output bus on |
|
Scale the gain on an output bus (used for GainEffect: FadeEffect was removed in the audio refactor; per-player fades live on AudioStreamPlayer .fade_in/.fade_out). |
Data¶
API¶
- simvx.core._native.miniaudio_engine.log¶
‘getLogger(…)’
- simvx.core._native.miniaudio_engine.__all__¶
[‘MiniaudioEngineUnavailable’, ‘Engine’, ‘Sound’, ‘SoundGroup’, ‘AudioBuffer’, ‘StreamSource’, ‘Effe…
Bases:
RuntimeErrorThe compiled
_simvx_miniaudio_engineextension was not found.Run
uv run python -m simvx.core._native.miniaudio_engine_build(orsimvx build-audio) to compile it once.Initialization
Initialize self. See help(type(self)) for accurate signature.
- simvx.core._native.miniaudio_engine.is_available() bool[source]¶
True if the native extension was built and loaded successfully.
- simvx.core._native.miniaudio_engine.refresh() bool[source]¶
Re-run the extension import.
Called by
audio_backend.make_backend()after a successful auto-build, so module-level_FFI/_LIBpick up the freshly-compiled .so without a Python restart.
- simvx.core._native.miniaudio_engine.ma_result_message(code: int) str[source]¶
Human-readable miniaudio result code.
- class simvx.core._native.miniaudio_engine.Engine(*, sample_rate: int = 48000, channels: int = 2, device: bool = True)[source]¶
Owns a single
ma_engineinstance.Pass
device=True(default) for a real playback device, ordevice=Falseto use the no-device path (read mixed PCM manually viaread_pcm_frames: useful for headless testing).Initialization
- read_pcm_frames(frame_count: int) numpy.ndarray[source]¶
Pull
frame_countmixed PCM frames (float32, interleaved).Only valid for engines built with
device=False. Returns an ndarray of shape(frame_count, channels). The number of frames actually read may be less than requested if the engine is idle.
- class simvx.core._native.miniaudio_engine.SoundGroup(engine: simvx.core._native.miniaudio_engine.Engine, *, parent: simvx.core._native.miniaudio_engine.SoundGroup | None = None)[source]¶
An
ma_sound_group: a named bus that sounds attach to.parent=Noneparents to the engine root. Volumes multiply through the parent chain in native code.Initialization
- class simvx.core._native.miniaudio_engine.AudioBuffer(samples: numpy.ndarray, *, sample_rate: int, channels: int)[source]¶
An
ma_audio_bufferbacked by a numpy ndarray.The ndarray must remain alive for the lifetime of the buffer: we do not copy. Stored as a Python attribute so the GC keeps it pinned.
Initialization
- class simvx.core._native.miniaudio_engine.StreamSource(engine: simvx.core._native.miniaudio_engine.Engine, *, sample_rate: int, channels: int, buffer_seconds: float = 0.5, format: str = 's16')[source]¶
An
ma_pcm_rb(PCM ring buffer) wrapped as ama_data_source.Used by
MiniaudioBackend.open_streamfor live procedural audio (AudioSynth.attach_to) and disk-streamed playback. Producer writes chunks viawrite(bytes)from the main thread; miniaudio’s audio thread pulls from the ring buffer’s built-in data source view. SPSC thread-safe: no locks needed.Underrun semantics: when the ring is empty, miniaudio’s read callback pads with silence and continues. The audio thread never stalls or glitches; consumers just hear silence until more chunks arrive.
Default format is
s16to match the legacy backend’sfeed_audio_chunk(bytes)convention.Initialization
- property data_source: Any[source]¶
The
ma_data_source*view of this ring buffer (forSound.from_data_source).
- write(chunk: bytes) int[source]¶
Push
chunkinto the ring buffer. Returns frames actually written.Frame-misaligned chunks have the trailing partial frame trimmed rather than rejected (most consumers feed in fixed-size sample-count buffers, so misalignment usually means the caller produced more samples than channels divide cleanly).
Returns the number of frames written. If the ring is full, returns less than requested: the caller can retry on the next tick.
- class simvx.core._native.miniaudio_engine.Sound(engine: simvx.core._native.miniaudio_engine.Engine, *, spatial: bool = False, pitch_enabled: bool = True)[source]¶
An
ma_sound: a single playable voice.Construct via
Sound.from_file(engine, path)orSound.from_buffer(engine, buffer). Optionalgroupattaches the sound to aSoundGroup(bus).Initialization
- classmethod from_file(engine: simvx.core._native.miniaudio_engine.Engine, path: str | os.PathLike, *, group: simvx.core._native.miniaudio_engine.SoundGroup | None = None, spatial: bool = False, pitch_enabled: bool = True, decode_now: bool = True, stream: bool = False) simvx.core._native.miniaudio_engine.Sound[source]¶
- classmethod from_buffer(engine: simvx.core._native.miniaudio_engine.Engine, buffer: simvx.core._native.miniaudio_engine.AudioBuffer, *, group: simvx.core._native.miniaudio_engine.SoundGroup | None = None, spatial: bool = False, pitch_enabled: bool = True) simvx.core._native.miniaudio_engine.Sound[source]¶
- classmethod from_stream(engine: simvx.core._native.miniaudio_engine.Engine, stream: simvx.core._native.miniaudio_engine.StreamSource, *, group: simvx.core._native.miniaudio_engine.SoundGroup | None = None, spatial: bool = False) simvx.core._native.miniaudio_engine.Sound[source]¶
Bind a
ma_soundto a liveStreamSource(ma_pcm_rb backed).Pitch is disabled by default because the engine’s pitch resampler would try to read ahead into the ring buffer past what’s been written, producing audible artifacts. Stream consumers wanting pitch control should resample Python-side before
feed_audio_chunk.
- classmethod from_data_source(engine: simvx.core._native.miniaudio_engine.Engine, data_source: Any, *, keeper: Any = None, group: simvx.core._native.miniaudio_engine.SoundGroup | None = None, spatial: bool = False, pitch_enabled: bool = True) simvx.core._native.miniaudio_engine.Sound[source]¶
Bind a
ma_soundto any ma_data_source-compatible source.keeperis pinned via the sound’s_source_keeperso the source’s GC can’t reap it while the sound is alive (essential for ndarray-backed AudioBuffer + ring-buffer-backed StreamSource).
- class simvx.core._native.miniaudio_engine.EffectNode(engine: simvx.core._native.miniaudio_engine.Engine)[source]¶
Bases:
abc.ABCBase wrapper for ma_*_node effect nodes attached to the engine’s node graph.
Abstract: instantiating it directly (or a subclass that omits
_init) raisesTypeError. Subclasses set_alloc_fn/_free_fn/_uninit_fn(callable cffi function handles) and implement_init(engine). The base class manages allocation, init, output-bus connections, and cleanup.handlereturns the rawma_node*(the first field isma_node_base, so the alloc’d struct pointer doubles as a node). Engine, source, and destination nodes plug into each other viaattach_node/detach_nodemodule-level helpers.Initialization
- __slots__¶
()
- class simvx.core._native.miniaudio_engine.LPFEffectNode(engine: simvx.core._native.miniaudio_engine.Engine, *, cutoff_hz: float = 1000.0, q: float = 0.707)[source]¶
Bases:
simvx.core._native.miniaudio_engine.EffectNode2nd-order low-pass biquad with configurable Q (resonance).
Wraps the C
simvx_biquad_lpf_node(an ma_node subclass that runsma_lpf2_process_pcm_framesin its process callback). Unlike the stockma_lpf_node, which hardcodes Q to 0.707, this honours the Q passed byLowPassFilter(q=...)so the engine’s filter behaviour matches the web backend’s BiquadFilterNode.Initialization
- property handle: Any¶
- shutdown() None¶
- __del__() None¶
- __slots__¶
()
- class simvx.core._native.miniaudio_engine.HPFEffectNode(engine: simvx.core._native.miniaudio_engine.Engine, *, cutoff_hz: float = 1000.0, q: float = 0.707)[source]¶
Bases:
simvx.core._native.miniaudio_engine.EffectNode2nd-order high-pass biquad with configurable Q (resonance).
Initialization
- property handle: Any¶
- shutdown() None¶
- __del__() None¶
- __slots__¶
()
- class simvx.core._native.miniaudio_engine.BPFEffectNode(engine: simvx.core._native.miniaudio_engine.Engine, *, cutoff_hz: float = 1000.0, q: float = 0.707)[source]¶
Bases:
simvx.core._native.miniaudio_engine.EffectNode2nd-order band-pass biquad with configurable Q (bandwidth).
Initialization
- property handle: Any¶
- shutdown() None¶
- __del__() None¶
- __slots__¶
()
- class simvx.core._native.miniaudio_engine.NotchEffectNode(engine: simvx.core._native.miniaudio_engine.Engine, *, cutoff_hz: float = 1000.0, q: float = 1.0)[source]¶
Bases:
simvx.core._native.miniaudio_engine.EffectNode2nd-order notch biquad (band-stop).
Initialization
- property handle: Any¶
- shutdown() None¶
- __del__() None¶
- __slots__¶
()
- class simvx.core._native.miniaudio_engine.PeakEffectNode(engine: simvx.core._native.miniaudio_engine.Engine, *, freq: float = 1000.0, q: float = 1.0, gain_db: float = 0.0)[source]¶
Bases:
simvx.core._native.miniaudio_engine.EffectNodePeaking-EQ band biquad.
Initialization
- property handle: Any¶
- shutdown() None¶
- __del__() None¶
- __slots__¶
()
- class simvx.core._native.miniaudio_engine.LowShelfEffectNode(engine: simvx.core._native.miniaudio_engine.Engine, *, freq: float = 200.0, q: float = 1.0, gain_db: float = 0.0)[source]¶
Bases:
simvx.core._native.miniaudio_engine.EffectNodeLow-shelf parametric-EQ band biquad.
Initialization
- property handle: Any¶
- shutdown() None¶
- __del__() None¶
- __slots__¶
()
- class simvx.core._native.miniaudio_engine.HighShelfEffectNode(engine: simvx.core._native.miniaudio_engine.Engine, *, freq: float = 8000.0, q: float = 1.0, gain_db: float = 0.0)[source]¶
Bases:
simvx.core._native.miniaudio_engine.EffectNodeHigh-shelf parametric-EQ band biquad.
Initialization
- property handle: Any¶
- shutdown() None¶
- __del__() None¶
- __slots__¶
()
- class simvx.core._native.miniaudio_engine.DelayEffectNode(engine: simvx.core._native.miniaudio_engine.Engine, *, delay_seconds: float = 0.25, decay: float = 0.4, wet: float = 0.5, dry: float = 0.5)[source]¶
Bases:
simvx.core._native.miniaudio_engine.EffectNodeSingle-tap delay with feedback decay and wet/dry mix.
Initialization
- property handle: Any¶
- shutdown() None¶
- __del__() None¶
- __slots__¶
()
- class simvx.core._native.miniaudio_engine.SoftClipEffectNode(engine: simvx.core._native.miniaudio_engine.Engine, *, drive: float = 2.0, output_gain: float = 1.0)[source]¶
Bases:
simvx.core._native.miniaudio_engine.EffectNodeTanh-curve symmetric soft clipping (custom DSP node).
Initialization
- property handle: Any¶
- shutdown() None¶
- __del__() None¶
- __slots__¶
()
- class simvx.core._native.miniaudio_engine.CompressorEffectNode(engine: simvx.core._native.miniaudio_engine.Engine, *, threshold_db: float = -24.0, ratio: float = 4.0, attack_ms: float = 5.0, release_ms: float = 100.0, knee_db: float = 6.0, makeup_db: float = 0.0)[source]¶
Bases:
simvx.core._native.miniaudio_engine.EffectNodeFeed-forward compressor with soft knee (custom DSP node).
Initialization
- set_params(*, threshold_db: float | None = None, ratio: float | None = None, attack_ms: float | None = None, release_ms: float | None = None, knee_db: float | None = None, makeup_db: float | None = None) None[source]¶
- property handle: Any¶
- shutdown() None¶
- __del__() None¶
- __slots__¶
()
- class simvx.core._native.miniaudio_engine.FreeverbEffectNode(engine: simvx.core._native.miniaudio_engine.Engine, *, room_size: float = 0.5, damping: float = 0.5, wet: float = 0.3, dry: float = 0.7, width: float = 1.0, freeze: bool = False)[source]¶
Bases:
simvx.core._native.miniaudio_engine.EffectNodeSchroeder-style algorithmic reverb (custom DSP node).
8 parallel comb filters → 4 series allpass filters per channel. Same parameters as
WebAudioBackend’s ConvolverNode-based reverb so the cross-backend sound is consistent within “same vibe” tolerance.Initialization
- set_params(*, room_size: float | None = None, damping: float | None = None, wet: float | None = None, dry: float | None = None, width: float | None = None, freeze: bool | None = None) None[source]¶
- property handle: Any¶
- shutdown() None¶
- __del__() None¶
- __slots__¶
()
- simvx.core._native.miniaudio_engine.engine_endpoint(engine: simvx.core._native.miniaudio_engine.Engine) Any[source]¶
Return the engine’s audio destination node (chain tail attaches here).
- simvx.core._native.miniaudio_engine.sound_group_as_node(group: simvx.core._native.miniaudio_engine.SoundGroup) Any[source]¶
Cast a SoundGroup to a generic node pointer for chain wiring.
- simvx.core._native.miniaudio_engine.attach_node(src: Any, src_bus: int, dst: Any, dst_bus: int) None[source]¶
Route
srcoutput bus todstinput bus. Either may be NULL.