Files
katrain-qt/katrain/gui/sound.py
T
ad244ffc7e v1.18.0 (#815)
Co-authored-by: Artur Tamazian <artur-tamazian>
Co-authored-by: Javier Gonzalez <javierggt@yahoo.com>
2026-06-05 13:22:00 +02:00

72 lines
2.2 KiB
Python

from kivy.clock import Clock
from kivy.core.audio import SoundLoader
from kivy.utils import platform
cached_sounds = {}
_audio_available = False
# prefer ffpyplayer on linux, then others, avoid gst and avoid or ffpyplayer on windows
ranking = [("ffplay", 98 if platform in ["win", "macosx"] else -2), ("sdl", -1), ("gst", 99), ("", 0)]
try:
SoundLoader._classes.sort(key=lambda cls: [v for k, v in ranking if k in cls.__name__.lower()][0])
except Exception as e:
print("Exception sorting sound loaders: ", e) # private vars, so could break with versions etc
def preload_sounds(sound_dir):
"""Preload all sounds before the SDL2 window is created.
SoundLoader.load() deadlocks when no audio output device is available,
so we test audio in a subprocess first.
"""
global _audio_available
import os
import sys
import subprocess
audio_files = [
os.path.join(sound_dir, fn) for fn in os.listdir(sound_dir)
if fn.endswith((".wav", ".ogg", ".mp3"))
]
if not audio_files:
return
# Test if audio subsystem works by loading one sound in a subprocess
try:
subprocess.run(
[sys.executable, "-c",
f"from kivy.core.audio import SoundLoader; SoundLoader.load({audio_files[0]!r})"],
timeout=3, capture_output=True,
)
except subprocess.TimeoutExpired as e:
print(f"Warning: Audio unavailable ({e}). Sounds disabled.", file=sys.stderr)
return
# Audio works, preload all sounds
for path in audio_files:
cached_sounds[os.path.basename(path)] = SoundLoader.load(path)
_audio_available = True
def play_sound(file, volume=1, cache=True):
if not _audio_available:
return
# the following import causes the creation of an SDL2 window, and if there
# is no sound device, it deadlocks. We delay the import until we know audio
# is available
from kivymd.app import MDApp
app = MDApp.get_running_app()
if app and app.gui and app.gui.config("timer/sound"):
sound = cached_sounds.get(file)
if sound is not None:
sound.volume = volume
sound.play()
sound.seek(0)
def stop_sound(file):
sound = cached_sounds.get(file)
if sound:
sound.stop()