Playback and spatial audio¶
The convenience runtime¶
play() opens its default audio session lazily. It reuses clips
loaded from the same resolved path and releases the session automatically at
process exit. Call shutdown() when an application needs
to close it earlier.
File clips use a 64 MiB least-recently-used byte budget. Clips attached to active sounds remain pinned until those sounds stop. Cache policy and explicit eviction remain function-oriented:
from pyalsoft import (
clear_sound_cache,
get_sound_cache_info,
set_sound_cache_limit,
)
set_sound_cache_limit(128 * 1024 * 1024) # None selects an unlimited cache.
print(get_sound_cache_info())
clear_sound_cache("notification.wav")
Clearing an active clip marks it for eviction after its final sound stops.
Control one sound¶
Every VoiceConfig field can also be passed directly to
play(). Direct keywords override the corresponding field when
both forms are used:
from pyalsoft import play
sound = play(
"engine.wav",
gain=0.7,
pitch=1.1,
looping=True,
relative=True,
position=(-2.0, 0.0, -4.0),
reference_distance=1.0,
max_distance=20.0,
rolloff_factor=1.0,
)
sound.position = (2.0, 0.0, -4.0)
sound.pitch = 1.25
sound.seek(3.0)
sound.update(
position=(3.0, 0.0, -2.0),
velocity=(1.0, 0.0, 0.0),
gain=0.6,
)
offset_seconds is the playhead position on the original source-audio
timeline, not elapsed wall-clock time. At pitch=2.0, for example, the offset
advances two source seconds per wall-clock second while duration_seconds
remains unchanged. For sample-accurate work, use offset_frames,
remaining_frames, frame_count, and seek_frames().
rewind() follows OpenAL behavior by moving to the beginning and entering the
INITIAL state. restart() moves to the beginning and immediately plays.
Inspect a sound¶
Format and length information is available without opening an audio device:
from pyalsoft import get_sound_info
info = get_sound_info("engine.wav")
print(info.duration_seconds, info.frame_count)
print(info.channels, info.sample_rate, info.bit_depth)
The same immutable SoundInfo is available as clip.info
and sound.info. When a sound ends, end_reason distinguishes natural
completion, an explicit stop(), runtime shutdown, and a disconnected device
when the backend supports connection reporting.
Spatial controls¶
The spatial controls describe a sound relative to the playback listener:
| Control | Meaning |
|---|---|
position |
The sound's (x, y, z) location. By default, +X is right, +Y is up, and -Z is forward. |
velocity |
Motion used for Doppler shift. It does not automatically update position. |
direction |
The vector the sound's directional cone points along. (0, 0, 0) makes it omnidirectional. |
relative |
Selects listener-local coordinates instead of world coordinates. |
reference_distance |
The reference point where distance attenuation has unity gain. |
max_distance |
The outer distance used by clamped distance models. |
rolloff_factor |
Scales distance attenuation; 0 disables distance rolloff. |
min_gain, max_gain |
Lower and upper gain clamps. |
cone_inner_angle, cone_outer_angle |
The full angles defining the directional cone. |
cone_outer_gain |
Gain multiplier outside the outer cone. |
Gain is a linear amplitude multiplier: 1.0 is unchanged, 0.5 is about
-6 dB, and 0.0 is silent. Pitch changes playback rate and audible pitch
together; OpenAL does not perform independent time stretching. Prefer mono
sounds for positional audio because OpenAL normally plays stereo sources
without applying 3D position or direction.
Configure the listener¶
The default runtime's listener and global distance and Doppler behavior can be configured without opening an explicit playback session:
from pyalsoft import (
Acoustics,
DistanceModel,
Listener,
set_acoustics,
set_listener,
update_listener,
)
set_listener(Listener(position=(0.0, 1.7, 0.0)))
set_acoustics(
Acoustics(
distance_model=DistanceModel.INVERSE_CLAMPED,
doppler_factor=1.0,
speed_of_sound=343.3,
)
)
update_listener(position=(2.0, 1.7, 0.0))
get_listener(), get_acoustics(), update_listener(), and
update_acoustics() operate on the convenience runtime by default. Pass an
explicit Playback as the first argument to use that
session instead.
See the runnable
play_file.py
and
move_sine.py
examples.