-
Notifications
You must be signed in to change notification settings - Fork 0
Audio
Added in 0.5.0.
Sound with the same degradation contract as everything else in the engine: a game on a machine with no audio device runs identically to one with speakers, the way a game with no I2C bus runs identically on a laptop. No method ever raises into your frame.
from texastoast import Mixer
mixer = Mixer() # picks the best backend available
game.on_close(mixer.close) # you wire the teardown
mixer.load("jump", "assets/jump.wav")
mixer.load("theme", "assets/theme.wav", volume=0.6)
mixer.play_music("theme") # one music slot; loops; replaces previous
mixer.play("jump") # fire-and-forget SFX
mixer.play("jump", volume=0.4) # per-play override
mixer.set_master_volume(0.8) # effective = master × load × override
mixer.stop_music()
mixer.stop_all()WAV is the guaranteed format on every tier. A missing file logs a warning
at load and plays as silence — a Pi image missing one asset must not kill
the game. An unknown name is a logged no-op, never an error.
Mixer() detects the best backend; mixer.backend_name tells you which won.
| Tier | Gets you | Install |
|---|---|---|
pygame |
Real mixing, seamless loops, per-channel volume; also decodes OGG (allowed, not promised) | pip install "texastoast[audio]" |
winsound |
Windows built-in. One sound at a time — a new play cancels the previous. SFX-grade. | nothing |
aplay / afplay
|
Linux/Pi / macOS command players. Process per sound (the system mixer mixes); loops respawn with an audible seam. | nothing |
null |
Every call is a silent no-op. | nothing |
The pygame tier is the one to use for real games — pygame-ce ships SDL2
wheels that are first-class on the Raspberry Pi, which is the target
hardware. The basic tiers exist so a fresh clone makes some sound with zero
pip installs; their set_volume is a documented no-op where the player has
no volume control, so code written against them upgrades cleanly (the same
role present() plays on the tkinter renderer).
pygame is imported only when its backend is constructed — import texastoast
never pulls it in.
Inject a backend, exactly like I2CBus(backend=...):
class RecordingBackend:
name = "test"
def __init__(self): self.calls = []
def play(self, path, *, loop=False, volume=1.0):
self.calls.append(("play", path, loop, volume)); return len(self.calls)
def stop(self, handle): self.calls.append(("stop", handle))
def stop_all(self): self.calls.append(("stop_all",))
def set_volume(self, handle, volume): pass
def close(self): pass
backend = RecordingBackend()
mixer = Mixer(backend=backend)NullBackend (importable from texastoast.audio) is the ready-made silent
one. AudioBackend is a typing.Protocol — a backend is anything with the
surface, nothing to inherit.
m = tt.mixer()
g.on_close(m.close)
texastoast · PyPI · Apache-2.0