93 lines
3.0 KiB
Python
93 lines
3.0 KiB
Python
"""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._active = False
|
|
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"
|
|
self._active = True
|
|
except ImportError:
|
|
try:
|
|
import accessible_output2.outputs.auto
|
|
self._speech = accessible_output2.outputs.auto.Auto()
|
|
self._provider = "accessible_output2"
|
|
self._active = True
|
|
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
|
|
"""
|
|
currentTime = time.time() * 1000
|
|
|
|
# Prevent rapid repeated messages
|
|
if (self._lastSpoken["text"] == text and
|
|
currentTime - self._lastSpoken["time"] < self._speechDelay):
|
|
return
|
|
|
|
# Update last spoken tracking
|
|
self._lastSpoken["text"] = text
|
|
self._lastSpoken["time"] = currentTime
|
|
|
|
# Handle speech output based on provider
|
|
try:
|
|
if self._provider == "speechd":
|
|
if interrupt:
|
|
self._speech.cancel()
|
|
self._speech.speak(text)
|
|
else:
|
|
self._speech.speak(text, interrupt=interrupt)
|
|
except Exception as e:
|
|
self._active = False
|
|
|
|
# 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 not self._active:
|
|
return
|
|
if self._provider == "speechd":
|
|
self._speech.close()
|
|
|
|
def draw(self):
|
|
"""Draw the current text on screen."""
|
|
self._font.draw()
|