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 settings_manager
|
||||||
from . import speech
|
from . import speech
|
||||||
from . import sound
|
from . import sound
|
||||||
|
from . import sound_theme_manager
|
||||||
from . import mouse_review
|
from . import mouse_review
|
||||||
from .ax_object import AXObject
|
from .ax_object import AXObject
|
||||||
from .ax_utilities import AXUtilities
|
from .ax_utilities import AXUtilities
|
||||||
@@ -871,6 +872,7 @@ def shutdown(script=None, inputEvent=None):
|
|||||||
cthulhu_state.activeScript.presentationInterrupt()
|
cthulhu_state.activeScript.presentationInterrupt()
|
||||||
|
|
||||||
cthulhuApp.getSignalManager().emitSignal('stop-application-completed')
|
cthulhuApp.getSignalManager().emitSignal('stop-application-completed')
|
||||||
|
sound_theme_manager.getManager().playStopSound(wait=True)
|
||||||
cthulhuApp.getPluginSystemManager().unloadAllPlugins(ForceAllPlugins=True)
|
cthulhuApp.getPluginSystemManager().unloadAllPlugins(ForceAllPlugins=True)
|
||||||
|
|
||||||
# Deactivate the event manager first so that it clears its queue and will not
|
# 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)
|
debug.printMessage(debug.LEVEL_INFO, "CTHULHU: Initialized.", True)
|
||||||
|
|
||||||
script = cthulhu_state.activeScript
|
script = cthulhu_state.activeScript
|
||||||
|
sound_theme_manager.getManager().playStartSound(wait=True)
|
||||||
cthulhuApp.getSignalManager().emitSignal('start-application-completed')
|
cthulhuApp.getSignalManager().emitSignal('start-application-completed')
|
||||||
if script:
|
if script:
|
||||||
window = script.utilities.activeWindow()
|
window = script.utilities.activeWindow()
|
||||||
|
|||||||
@@ -93,6 +93,36 @@ class Player:
|
|||||||
self._player.set_property('uri', f'file://{icon.path}')
|
self._player.set_property('uri', f'file://{icon.path}')
|
||||||
self._player.set_state(Gst.State.PLAYING)
|
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):
|
def _playTone(self, tone, interrupt=True):
|
||||||
"""Plays a tone, interrupting the current play first unless specified."""
|
"""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"]
|
tokens = ["SOUND ERROR:", item, "is not an Icon or Tone"]
|
||||||
debug.printTokens(debug.LEVEL_INFO, tokens, True)
|
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):
|
def stop(self, element=None):
|
||||||
"""Stops play."""
|
"""Stops play."""
|
||||||
|
|
||||||
|
|||||||
@@ -47,9 +47,11 @@ from .sound_generator import Icon
|
|||||||
_settingsManager = settings_manager.getManager()
|
_settingsManager = settings_manager.getManager()
|
||||||
|
|
||||||
# Sound event constants - add new events here for easy extensibility
|
# 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_BROWSE_MODE = "browse_mode"
|
||||||
SOUND_BUTTON = "button"
|
SOUND_BUTTON = "button"
|
||||||
|
SOUND_START = "start"
|
||||||
|
SOUND_STOP = "stop"
|
||||||
|
|
||||||
# Special theme name for no sounds
|
# Special theme name for no sounds
|
||||||
THEME_NONE = "none"
|
THEME_NONE = "none"
|
||||||
@@ -144,17 +146,23 @@ class SoundThemeManager:
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def playSound(self, soundName, interrupt=True):
|
def _playThemeSound(self, soundName, interrupt=True, wait=False,
|
||||||
"""Play a sound from the current theme if enabled.
|
requireModeChangeSetting=False, requireSoundSetting=False):
|
||||||
|
"""Play a themed sound with optional gating and blocking.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
soundName: The name of the sound file (without extension)
|
soundName: The name of the sound file (without extension)
|
||||||
interrupt: Whether to interrupt currently playing sounds
|
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:
|
Returns:
|
||||||
True if sound was played, False otherwise
|
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
|
return False
|
||||||
|
|
||||||
themeName = _settingsManager.getSetting('soundTheme')
|
themeName = _settingsManager.getSetting('soundTheme')
|
||||||
@@ -175,6 +183,8 @@ class SoundThemeManager:
|
|||||||
icon = Icon(os.path.dirname(soundPath), os.path.basename(soundPath))
|
icon = Icon(os.path.dirname(soundPath), os.path.basename(soundPath))
|
||||||
if icon.isValid():
|
if icon.isValid():
|
||||||
player = sound.getPlayer()
|
player = sound.getPlayer()
|
||||||
|
if wait and hasattr(player, "playAndWait"):
|
||||||
|
return player.playAndWait(icon, interrupt=interrupt)
|
||||||
player.play(icon, interrupt=interrupt)
|
player.play(icon, interrupt=interrupt)
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -183,6 +193,24 @@ class SoundThemeManager:
|
|||||||
|
|
||||||
return False
|
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):
|
def playFocusModeSound(self):
|
||||||
"""Play sound for entering focus mode."""
|
"""Play sound for entering focus mode."""
|
||||||
return self.playSound(SOUND_FOCUS_MODE)
|
return self.playSound(SOUND_FOCUS_MODE)
|
||||||
@@ -195,6 +223,24 @@ class SoundThemeManager:
|
|||||||
"""Play sound for button focus (future use)."""
|
"""Play sound for button focus (future use)."""
|
||||||
return self.playSound(SOUND_BUTTON)
|
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
|
_manager = None
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user