1# Orca 2# 3# Copyright 2004-2009 Sun Microsystems Inc. 4# 5# This library is free software; you can redistribute it and/or 6# modify it under the terms of the GNU Lesser General Public 7# License as published by the Free Software Foundation; either 8# version 2.1 of the License, or (at your option) any later version. 9# 10# This library is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13# Lesser General Public License for more details. 14# 15# You should have received a copy of the GNU Lesser General Public 16# License along with this library; if not, write to the 17# Free Software Foundation, Inc., Franklin Street, Fifth Floor, 18# Boston MA 02110-1301 USA. 19 20"""Manages the default speech server for orca. A script can use this 21as its speech server, or it can feel free to create one of its own.""" 22 23__id__ = "$Id$" 24__version__ = "$Revision$" 25__date__ = "$Date$" 26__copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc." 27__license__ = "LGPL" 28 29import importlib 30import time 31 32from . import debug 33from . import logger 34from . import orca_state 35from . import settings 36from . import speech_generator 37from .speechserver import VoiceFamily 38 39from .acss import ACSS 40 41_logger = logger.getLogger() 42log = _logger.newLog("speech") 43 44# The speech server to use for all speech operations. 45# 46_speechserver = None 47 48# The last time something was spoken. 49_timestamp = 0 50 51def getSpeechServerFactories(): 52 """Imports all known SpeechServer factory modules. Returns a list 53 of modules that implement the getSpeechServers method, which 54 returns a list of speechserver.SpeechServer instances. 55 """ 56 57 factories = [] 58 59 moduleNames = settings.speechFactoryModules 60 for moduleName in moduleNames: 61 try: 62 module = importlib.import_module('orca.%s' % moduleName) 63 factories.append(module) 64 except: 65 debug.printException(debug.LEVEL_CONFIGURATION) 66 67 return factories 68 69def _initSpeechServer(moduleName, speechServerInfo): 70 71 global _speechserver 72 73 if not moduleName: 74 return 75 76 factory = None 77 try: 78 factory = importlib.import_module('orca.%s' % moduleName) 79 except: 80 try: 81 factory = importlib.import_module(moduleName) 82 except: 83 debug.printException(debug.LEVEL_SEVERE) 84 85 # Now, get the speech server we care about. 86 # 87 speechServerInfo = settings.speechServerInfo 88 if speechServerInfo: 89 _speechserver = factory.SpeechServer.getSpeechServer(speechServerInfo) 90 91 if not _speechserver: 92 _speechserver = factory.SpeechServer.getSpeechServer() 93 if speechServerInfo: 94 msg = 'SPEECH: Invalid speechServerInfo: %s' % speechServerInfo 95 debug.println(debug.LEVEL_INFO, msg, True) 96 97 if not _speechserver: 98 raise Exception("ERROR: No speech server for factory: %s" % moduleName) 99 100def init(): 101 debug.println(debug.LEVEL_INFO, 'SPEECH: Initializing', True) 102 if _speechserver: 103 debug.println(debug.LEVEL_INFO, 'SPEECH: Already initialized', True) 104 return 105 106 try: 107 moduleName = settings.speechServerFactory 108 _initSpeechServer(moduleName, 109 settings.speechServerInfo) 110 except: 111 moduleNames = settings.speechFactoryModules 112 for moduleName in moduleNames: 113 if moduleName != settings.speechServerFactory: 114 try: 115 _initSpeechServer(moduleName, None) 116 if _speechserver: 117 break 118 except: 119 debug.printException(debug.LEVEL_SEVERE) 120 121 if _speechserver: 122 msg = 'SPEECH: Using speech server factory: %s' % moduleName 123 debug.println(debug.LEVEL_INFO, msg, True) 124 else: 125 msg = 'SPEECH: Not available' 126 debug.println(debug.LEVEL_INFO, msg, True) 127 128 debug.println(debug.LEVEL_INFO, 'SPEECH: Initialized', True) 129 130def checkSpeechSetting(): 131 msg = "SPEECH: Checking speech setting." 132 debug.println(debug.LEVEL_INFO, msg, True) 133 134 if not settings.enableSpeech: 135 shutdown() 136 else: 137 init() 138 139def __resolveACSS(acss=None): 140 if isinstance(acss, ACSS): 141 family = acss.get(acss.FAMILY) 142 try: 143 family = VoiceFamily(family) 144 except: 145 family = VoiceFamily({}) 146 acss[acss.FAMILY] = family 147 return acss 148 elif isinstance(acss, list) and len(acss) == 1: 149 return ACSS(acss[0]) 150 else: 151 voices = settings.voices 152 return ACSS(voices[settings.DEFAULT_VOICE]) 153 154def sayAll(utteranceIterator, progressCallback): 155 if settings.silenceSpeech: 156 return 157 if _speechserver: 158 _speechserver.sayAll(utteranceIterator, progressCallback) 159 else: 160 for [context, acss] in utteranceIterator: 161 logLine = "SPEECH OUTPUT: '" + context.utterance + "'" 162 debug.println(debug.LEVEL_INFO, logLine, True) 163 log.info(logLine) 164 165def _speak(text, acss, interrupt): 166 """Speaks the individual string using the given ACSS.""" 167 168 logLine = "SPEECH OUTPUT: '" + text + "'" 169 extraDebug = "" 170 if acss in list(settings.voices.values()): 171 for key in settings.voices: 172 if acss == settings.voices[key]: 173 if key != settings.DEFAULT_VOICE: 174 extraDebug = " voice=%s" % key 175 break 176 177 debug.println(debug.LEVEL_INFO, logLine + extraDebug + str(acss), True) 178 log.info(logLine + extraDebug) 179 180 if _speechserver: 181 voice = ACSS(settings.voices.get(settings.DEFAULT_VOICE)) 182 try: 183 voice.update(__resolveACSS(acss)) 184 except: 185 pass 186 _speechserver.speak(text, __resolveACSS(voice), interrupt) 187 188def speak(content, acss=None, interrupt=True): 189 """Speaks the given content. The content can be either a simple 190 string or an array of arrays of objects returned by a speech 191 generator.""" 192 193 if settings.silenceSpeech: 194 return 195 196 validTypes = (str, list, speech_generator.Pause, 197 speech_generator.LineBreak, ACSS) 198 error = "SPEECH: bad content sent to speak(): '%s'" 199 if not isinstance(content, validTypes): 200 debug.printStack(debug.LEVEL_WARNING) 201 debug.println(debug.LEVEL_WARNING, error % content, True) 202 return 203 204 global _timestamp 205 if _timestamp: 206 msg = "SPEECH: Last spoke %.4f seconds ago" % (time.time() - _timestamp) 207 debug.println(debug.LEVEL_INFO, msg, True) 208 _timestamp = time.time() 209 210 if isinstance(content, str): 211 _speak(content, acss, interrupt) 212 if not isinstance(content, list): 213 return 214 215 toSpeak = [] 216 activeVoice = ACSS(acss) 217 for element in content: 218 if not isinstance(element, validTypes): 219 debug.println(debug.LEVEL_WARNING, error % element, True) 220 elif isinstance(element, list): 221 speak(element, acss, interrupt) 222 elif isinstance(element, str): 223 if len(element): 224 toSpeak.append(element) 225 elif toSpeak: 226 newVoice = ACSS(acss) 227 newItemsToSpeak = [] 228 if isinstance(element, speech_generator.Pause): 229 if toSpeak[-1] and toSpeak[-1][-1].isalnum(): 230 toSpeak[-1] += '.' 231 elif isinstance(element, ACSS): 232 newVoice.update(element) 233 if newVoice == activeVoice: 234 continue 235 newItemsToSpeak.append(toSpeak.pop()) 236 237 if toSpeak: 238 string = " ".join(toSpeak) 239 _speak(string, activeVoice, interrupt) 240 activeVoice = newVoice 241 toSpeak = newItemsToSpeak 242 243 if toSpeak: 244 string = " ".join(toSpeak) 245 _speak(string, activeVoice, interrupt) 246 247def speakKeyEvent(event, acss=None): 248 """Speaks a key event immediately. 249 250 Arguments: 251 - event: input_event.KeyboardEvent to speak. 252 """ 253 254 if settings.silenceSpeech: 255 return 256 257 keyname = event.getKeyName() 258 lockingStateString = event.getLockingStateString() 259 acss = __resolveACSS(acss) 260 msg = "%s %s" % (keyname, lockingStateString) 261 logLine = "SPEECH OUTPUT: '%s' %s" % (msg, acss) 262 debug.println(debug.LEVEL_INFO, logLine, True) 263 log.info(logLine) 264 265 if _speechserver: 266 _speechserver.speakKeyEvent(event, acss) 267 268def speakCharacter(character, acss=None): 269 """Speaks a single character immediately. 270 271 Arguments: 272 - character: text to be spoken 273 - acss: acss.ACSS instance; if None, 274 the default voice settings will be used. 275 Otherwise, the acss settings will be 276 used to augment/override the default 277 voice settings. 278 """ 279 if settings.silenceSpeech: 280 return 281 282 acss = __resolveACSS(acss) 283 msg = "SPEECH OUTPUT: '" + character + "' " + str(acss) 284 debug.println(debug.LEVEL_INFO, msg, True) 285 log.info("SPEECH OUTPUT: '%s'" % character) 286 287 if _speechserver: 288 _speechserver.speakCharacter(character, acss=acss) 289 290def isSpeaking(): 291 """Returns True if the system is currently speaking.""" 292 if _speechserver: 293 return _speechserver.isSpeaking() 294 else: 295 return False 296 297def getInfo(): 298 info = None 299 if _speechserver: 300 info = _speechserver.getInfo() 301 302 return info 303 304def stop(): 305 if _speechserver: 306 _speechserver.stop() 307 308def updateCapitalizationStyle(script=None, inputEvent=None): 309 if _speechserver: 310 _speechserver.updateCapitalizationStyle() 311 312 return True 313 314def updatePunctuationLevel(script=None, inputEvent=None): 315 """ Punctuation level changed, inform this speechServer. """ 316 317 if _speechserver: 318 _speechserver.updatePunctuationLevel() 319 320 return True 321 322def increaseSpeechRate(script=None, inputEvent=None): 323 if _speechserver: 324 _speechserver.increaseSpeechRate() 325 326 return True 327 328def decreaseSpeechRate(script=None, inputEvent=None): 329 if _speechserver: 330 _speechserver.decreaseSpeechRate() 331 else: 332 logLine = "SPEECH OUTPUT: 'slower'" 333 debug.println(debug.LEVEL_INFO, logLine) 334 log.info(logLine) 335 336 return True 337 338def increaseSpeechPitch(script=None, inputEvent=None): 339 if _speechserver: 340 _speechserver.increaseSpeechPitch() 341 342 return True 343 344def decreaseSpeechPitch(script=None, inputEvent=None): 345 if _speechserver: 346 _speechserver.decreaseSpeechPitch() 347 348 return True 349 350def increaseSpeechVolume(script=None, inputEvent=None): 351 if _speechserver: 352 _speechserver.increaseSpeechVolume() 353 return True 354 355def decreaseSpeechVolume(script=None, inputEvent=None): 356 if _speechserver: 357 _speechserver.decreaseSpeechVolume() 358 return True 359 360def shutdown(): 361 debug.println(debug.LEVEL_INFO, 'SPEECH: Shutting down', True) 362 global _speechserver 363 if _speechserver: 364 _speechserver.shutdownActiveServers() 365 _speechserver = None 366 367def reset(text=None, acss=None): 368 if _speechserver: 369 _speechserver.reset(text, acss) 370 371def testNoSettingsInit(): 372 init() 373 speak("testing") 374 speak("this is higher", ACSS({'average-pitch' : 7})) 375 speak("this is slower", ACSS({'rate' : 3})) 376 speak("this is faster", ACSS({'rate' : 80})) 377 speak("this is quiet", ACSS({'gain' : 2})) 378 speak("this is loud", ACSS({'gain' : 10})) 379 speak("this is normal") 380 381def test(): 382 from . import speechserver 383 factories = getSpeechServerFactories() 384 for factory in factories: 385 print(factory.__name__) 386 servers = factory.SpeechServer.getSpeechServers() 387 for server in servers: 388 try: 389 print(" ", server.getInfo()) 390 for family in server.getVoiceFamilies(): 391 name = family[speechserver.VoiceFamily.NAME] 392 print(" ", name) 393 acss = ACSS({ACSS.FAMILY : family}) 394 server.speak(name, acss) 395 server.speak("testing") 396 server.shutdown() 397 except: 398 debug.printException(debug.LEVEL_OFF) 399