Default sound pack extended.
This commit is contained in:
BIN
sounds/default/start.wav
Normal file
BIN
sounds/default/start.wav
Normal file
Binary file not shown.
BIN
sounds/default/stop.wav
Normal file
BIN
sounds/default/stop.wav
Normal file
Binary file not shown.
@@ -219,6 +219,7 @@ from . import settings
|
||||
from . import settings_manager
|
||||
from . import speech
|
||||
from . import sound
|
||||
from . import sound_theme_manager
|
||||
from . import mouse_review
|
||||
from .ax_object import AXObject
|
||||
from .ax_utilities import AXUtilities
|
||||
@@ -871,6 +872,7 @@ def shutdown(script=None, inputEvent=None):
|
||||
cthulhu_state.activeScript.presentationInterrupt()
|
||||
|
||||
cthulhuApp.getSignalManager().emitSignal('stop-application-completed')
|
||||
sound_theme_manager.getManager().playStopSound(wait=True)
|
||||
cthulhuApp.getPluginSystemManager().unloadAllPlugins(ForceAllPlugins=True)
|
||||
|
||||
# Deactivate the event manager first so that it clears its queue and will not
|
||||
@@ -993,6 +995,7 @@ def main():
|
||||
debug.printMessage(debug.LEVEL_INFO, "CTHULHU: Initialized.", True)
|
||||
|
||||
script = cthulhu_state.activeScript
|
||||
sound_theme_manager.getManager().playStartSound(wait=True)
|
||||
cthulhuApp.getSignalManager().emitSignal('start-application-completed')
|
||||
if script:
|
||||
window = script.utilities.activeWindow()
|
||||
|
||||
@@ -93,6 +93,36 @@ class Player:
|
||||
self._player.set_property('uri', f'file://{icon.path}')
|
||||
self._player.set_state(Gst.State.PLAYING)
|
||||
|
||||
def _playIconAndWait(self, icon, interrupt=True, timeout_seconds=10):
|
||||
"""Plays a sound icon and waits for completion."""
|
||||
|
||||
if interrupt:
|
||||
self._player.set_state(Gst.State.NULL)
|
||||
|
||||
self._player.set_property('uri', f'file://{icon.path}')
|
||||
self._player.set_state(Gst.State.PLAYING)
|
||||
|
||||
bus = self._player.get_bus()
|
||||
if not bus:
|
||||
return False
|
||||
|
||||
if timeout_seconds is None:
|
||||
timeout_ns = Gst.CLOCK_TIME_NONE
|
||||
else:
|
||||
timeout_ns = int(timeout_seconds * Gst.SECOND)
|
||||
|
||||
message = bus.timed_pop_filtered(
|
||||
timeout_ns,
|
||||
Gst.MessageType.EOS | Gst.MessageType.ERROR
|
||||
)
|
||||
if message and message.type == Gst.MessageType.ERROR:
|
||||
error, info = message.parse_error()
|
||||
msg = f'SOUND ERROR: {error}'
|
||||
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||
|
||||
self._player.set_state(Gst.State.NULL)
|
||||
return message is not None and message.type == Gst.MessageType.EOS
|
||||
|
||||
def _playTone(self, tone, interrupt=True):
|
||||
"""Plays a tone, interrupting the current play first unless specified."""
|
||||
|
||||
@@ -152,6 +182,25 @@ class Player:
|
||||
tokens = ["SOUND ERROR:", item, "is not an Icon or Tone"]
|
||||
debug.printTokens(debug.LEVEL_INFO, tokens, True)
|
||||
|
||||
def playAndWait(self, item, interrupt=True, timeout_seconds=10):
|
||||
"""Plays a sound and blocks until completion or timeout."""
|
||||
|
||||
if not self._player:
|
||||
if _gstreamerAvailable and not self._initialized:
|
||||
self.init()
|
||||
if not self._player:
|
||||
return False
|
||||
|
||||
if isinstance(item, Icon):
|
||||
return self._playIconAndWait(
|
||||
item,
|
||||
interrupt=interrupt,
|
||||
timeout_seconds=timeout_seconds
|
||||
)
|
||||
|
||||
self.play(item, interrupt)
|
||||
return False
|
||||
|
||||
def stop(self, element=None):
|
||||
"""Stops play."""
|
||||
|
||||
|
||||
@@ -47,9 +47,11 @@ from .sound_generator import Icon
|
||||
_settingsManager = settings_manager.getManager()
|
||||
|
||||
# Sound event constants - add new events here for easy extensibility
|
||||
SOUND_FOCUS_MODE = "editbox"
|
||||
SOUND_FOCUS_MODE = "focus_mode"
|
||||
SOUND_BROWSE_MODE = "browse_mode"
|
||||
SOUND_BUTTON = "button"
|
||||
SOUND_START = "start"
|
||||
SOUND_STOP = "stop"
|
||||
|
||||
# Special theme name for no sounds
|
||||
THEME_NONE = "none"
|
||||
@@ -144,17 +146,23 @@ class SoundThemeManager:
|
||||
|
||||
return None
|
||||
|
||||
def playSound(self, soundName, interrupt=True):
|
||||
"""Play a sound from the current theme if enabled.
|
||||
def _playThemeSound(self, soundName, interrupt=True, wait=False,
|
||||
requireModeChangeSetting=False, requireSoundSetting=False):
|
||||
"""Play a themed sound with optional gating and blocking.
|
||||
|
||||
Args:
|
||||
soundName: The name of the sound file (without extension)
|
||||
interrupt: Whether to interrupt currently playing sounds
|
||||
wait: Whether to block until the sound finishes playing
|
||||
requireModeChangeSetting: Honor enableModeChangeSound setting
|
||||
requireSoundSetting: Honor enableSound setting
|
||||
|
||||
Returns:
|
||||
True if sound was played, False otherwise
|
||||
"""
|
||||
if not _settingsManager.getSetting('enableModeChangeSound'):
|
||||
if requireModeChangeSetting and not _settingsManager.getSetting('enableModeChangeSound'):
|
||||
return False
|
||||
if requireSoundSetting and not _settingsManager.getSetting('enableSound'):
|
||||
return False
|
||||
|
||||
themeName = _settingsManager.getSetting('soundTheme')
|
||||
@@ -175,6 +183,8 @@ class SoundThemeManager:
|
||||
icon = Icon(os.path.dirname(soundPath), os.path.basename(soundPath))
|
||||
if icon.isValid():
|
||||
player = sound.getPlayer()
|
||||
if wait and hasattr(player, "playAndWait"):
|
||||
return player.playAndWait(icon, interrupt=interrupt)
|
||||
player.play(icon, interrupt=interrupt)
|
||||
return True
|
||||
except Exception as e:
|
||||
@@ -183,6 +193,24 @@ class SoundThemeManager:
|
||||
|
||||
return False
|
||||
|
||||
def playSound(self, soundName, interrupt=True, wait=False):
|
||||
"""Play a sound from the current theme if enabled.
|
||||
|
||||
Args:
|
||||
soundName: The name of the sound file (without extension)
|
||||
interrupt: Whether to interrupt currently playing sounds
|
||||
wait: Whether to block until the sound finishes playing
|
||||
|
||||
Returns:
|
||||
True if sound was played, False otherwise
|
||||
"""
|
||||
return self._playThemeSound(
|
||||
soundName,
|
||||
interrupt=interrupt,
|
||||
wait=wait,
|
||||
requireModeChangeSetting=True
|
||||
)
|
||||
|
||||
def playFocusModeSound(self):
|
||||
"""Play sound for entering focus mode."""
|
||||
return self.playSound(SOUND_FOCUS_MODE)
|
||||
@@ -195,6 +223,24 @@ class SoundThemeManager:
|
||||
"""Play sound for button focus (future use)."""
|
||||
return self.playSound(SOUND_BUTTON)
|
||||
|
||||
def playStartSound(self, wait=False):
|
||||
"""Play sound for application startup."""
|
||||
return self._playThemeSound(
|
||||
SOUND_START,
|
||||
interrupt=True,
|
||||
wait=wait,
|
||||
requireSoundSetting=True
|
||||
)
|
||||
|
||||
def playStopSound(self, wait=False):
|
||||
"""Play sound for application shutdown."""
|
||||
return self._playThemeSound(
|
||||
SOUND_STOP,
|
||||
interrupt=True,
|
||||
wait=wait,
|
||||
requireSoundSetting=True
|
||||
)
|
||||
|
||||
|
||||
_manager = None
|
||||
|
||||
|
||||
Reference in New Issue
Block a user