simvx.core._audio_stream

Audio stream/data layer: :class:AudioClip resource + container detection.

Private leaf module behind the :mod:simvx.core.audio facade. Holds the audio data concerns: the :class:AudioClip resource handle, the header-probe container detection helpers, the chunk-at-a-time decoder that feeds streaming playback, the clip-length probe, and the sample-rate/channel constants and type aliases that belong to this layer. The playback mixin and the player nodes live in sibling _audio_playback / _audio_players modules.

Module Contents

Classes

AudioClip

Audio resource (WAV/OGG file or synthetic PCM).

Data

API

simvx.core._audio_stream.AudioSource

None

simvx.core._audio_stream.AudioContainer

None

simvx.core._audio_stream.log

‘getLogger(…)’

class simvx.core._audio_stream.AudioClip(source: simvx.core._audio_stream.AudioSource)[source]

Audio resource (WAV/OGG file or synthetic PCM).

This is a lightweight handle to audio data. Actual decoding is deferred to the backend (miniaudio, SDL3, web audio).

Accepts any of:

  • class:

    str / :class:os.PathLike – a filesystem audio file.

  • class:

    ~simvx.core.Resource – audio inside a Python package.

  • class:

    importlib.resources.abc.Traversable – the raw return of importlib.resources.files(pkg) / name.

Use :meth:tone for procedural sine-wave tones and :meth:from_pcm to wrap pre-rendered PCM data.

Attributes: source: Original spec the stream was constructed from – a string, :class:pathlib.Path, :class:Resource, or :class:Traversable. Preserved verbatim so scene serialisation can round-trip it. path: Resolved filesystem path string used by the backend (empty string for synthetic streams that have no file). backend_data: Backend-specific audio data (PCM ndarray, channel id, etc). Set automatically when decoded; may also be set by :meth:from_pcm / :meth:tone. container: Detected container format – one of "wav", "ogg", "mp3", "flac", "pcm" (synthetic) or "unknown". Probed from the file header at construction time; the streaming open path uses it to pick the right decoder. duration: How long the clip plays for in seconds, or None when that cannot be read.

Initialization

__slots__

(‘source’, ‘_path’, ‘backend_data’, ‘sample_rate’, ‘channels’, ‘_container’, ‘_decoded_format’)

property path: str[source]

Resolved filesystem path string used by the backend.

Synthetic streams (from_pcm / tone / empty) carry their assigned name here. The dual-field design (separate source + path slots both holding the same string for synthetic streams) was collapsed during the audio refactor; path is now a derived attribute backed by _path.

property container: simvx.core._audio_stream.AudioContainer[source]

Detected container format. See :data:AudioContainer for the value set.

property duration: float | None[source]

Seconds of audio in this clip, or None when its length cannot be read.

Two sources answer it. A clip carrying its own decoded PCM (:meth:from_pcm, :meth:tone, anything baked by AudioSynth) is measured from the buffer and the rate and channel count it declares. A file-backed one is measured from the container’s metadata, read through the same decoder that plays the file, so no audio device is opened and a compressed format needs no second parser. File lengths are cached per (path, size, mtime_ns): asking twice costs one stat, and rewriting the file is seen.

None is “unknown”, never “zero”. It is the answer for

Meth:

empty, for a file that is missing, truncated, mislabelled or in a codec this build of miniaudio lacks, and for a buffer assigned to backend_data by hand, which declares no format to divide by.

__repr__()[source]
classmethod tone(freq_hz: float, *, duration: float = 1.0, volume: float = 0.3, sample_rate: int = _SAMPLE_RATE) simvx.core._audio_stream.AudioClip[source]

Generate a sine-wave tone at freq_hz with a short fade-in/out.

The resulting stream has its PCM data baked into backend_data so the audio backend skips file decoding entirely.

classmethod from_pcm(samples: numpy.ndarray, *, sample_rate: int, channels: int, name: str = 'pcm') simvx.core._audio_stream.AudioClip[source]

Wrap a pre-rendered PCM buffer as an AudioClip.

Args: samples: float32 ndarray. For stereo, interleaved (channels first within each frame); for mono, a 1-D array. sample_rate: PCM sample rate in Hz. Required: playing a 44.1 kHz buffer on a 48 kHz backend produces wrong-pitch audio if this is omitted. channels: 1 (mono) or 2 (stereo). Required for the same reason: a mono buffer played as stereo gives left-channel-only sound. name: Descriptive label used in :meth:__repr__ and as the stream’s path. The backend ignores it when backend_data is set.

Raises: InvalidStreamError: sample_rate <= 0, channels is not 1 or 2, the buffer holds no whole frame, or its length is not a multiple of channels. TypeError: samples isn’t a numpy ndarray.

classmethod empty(*, name: str = 'empty') simvx.core._audio_stream.AudioClip[source]

Return a synthetic stream with no audio data.

Used internally by :meth:AudioSynth.bake (before it overwrites the synthetic frame buffer) and by null-backend tests that need a placeholder stream object without touching the filesystem. The returned stream carries container="pcm" and backend_data=None: playing it through a real backend is undefined.

Replaces the legacy AudioClip("") sentinel.