"""Speech and text display module for PygStormGames. Provides text-to-speech functionality with screen text display support. Uses either speechd or accessible_output2 as the speech backend. """ import time import pyglet from pyglet.window import key import textwrap class Speech: """Handles speech output and text display.""" def __init__(self): """Initialize speech system with fallback providers.""" self._lastSpoken = {"text": None, "time": 0} self._speechDelay = 250 # ms delay between identical messages # Try to initialize speech providers in order of preference try: import speechd self._speech = speechd.Client() self._provider = "speechd" except ImportError: try: import accessible_output2.outputs.auto self._speech = accessible_output2.outputs.auto.Auto() self._provider = "accessible_output2" except ImportError: raise RuntimeError("No speech providers found. Install either speechd or accessible_output2.") # Display settings self._font = pyglet.text.Label( '', font_name='Arial', font_size=36, x=400, y=300, # Will be centered later anchor_x='center', anchor_y='center', multiline=True, width=760 # Allow 20px margin on each side ) def speak(self, text, interrupt=True): """Speak text and display it on screen. Args: text (str): Text to speak and display interrupt (bool): Whether to interrupt current speech """ current_time = time.time() * 1000 # Prevent rapid repeated messages if (self._lastSpoken["text"] == text and current_time - self._lastSpoken["time"] < self._speechDelay): return # Update last spoken tracking self._lastSpoken["text"] = text self._lastSpoken["time"] = current_time # Handle speech output based on provider if self._provider == "speechd": if interrupt: self._speech.cancel() self._speech.speak(text) else: self._speech.speak(text, interrupt=interrupt) # Update display text self._font.text = text # Center text vertically based on line count lineCount = len(text.split('\n')) self._font.y = 300 + (lineCount * self._font.font_size // 4) def cleanup(self): """Clean up speech system resources.""" if self._provider == "speechd": self._speech.close() def draw(self): """Draw the current text on screen.""" self._font.draw()