1 |
|
# Orca |
2 |
|
# |
3 |
|
# Copyright 2004-2007 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 Library General Public |
7 |
|
# License as published by the Free Software Foundation; either |
8 |
|
# version 2 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 |
|
# Library General Public License for more details. |
14 |
|
# |
15 |
|
# You should have received a copy of the GNU Library General Public |
16 |
|
# License along with this library; if not, write to the |
17 |
|
# Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
18 |
|
# Boston, MA 02111-1307, USA. |
19 |
|
|
20 |
|
"""Manages the default speech server for orca. A script can use this |
21 |
1 |
as its speech server, or it can feel free to create one of its own.""" |
22 |
|
|
23 |
1 |
__id__ = "$Id: speech.py 2548 2007-07-21 21:46:43Z wwalker $" |
24 |
1 |
__version__ = "$Revision: 2548 $" |
25 |
1 |
__date__ = "$Date: 2007-07-21 17:46:43 -0400 (Sat, 21 Jul 2007) $" |
26 |
1 |
__copyright__ = "Copyright (c) 2005-2007 Sun Microsystems Inc." |
27 |
1 |
__license__ = "LGPL" |
28 |
|
|
29 |
1 |
import logging |
30 |
1 |
log = logging.getLogger("speech") |
31 |
|
|
32 |
1 |
import time |
33 |
|
|
34 |
1 |
import debug |
35 |
1 |
import keynames |
36 |
1 |
import orca |
37 |
1 |
import orca_state |
38 |
1 |
import settings |
39 |
|
|
40 |
1 |
from acss import ACSS |
41 |
1 |
from orca_i18n import _ # for gettext support |
42 |
|
|
43 |
|
# The speech server to use for all speech operations. |
44 |
|
# |
45 |
1 |
_speechserver = None |
46 |
|
|
47 |
1 |
def getSpeechServerFactories(): |
48 |
|
"""Imports all known SpeechServer factory modules. Returns a list |
49 |
|
of modules that implement the getSpeechServers method, which |
50 |
|
returns a list of speechserver.SpeechServer instances. |
51 |
|
""" |
52 |
|
|
53 |
0 |
factories = [] |
54 |
|
|
55 |
0 |
moduleNames = settings.speechFactoryModules |
56 |
0 |
for moduleName in moduleNames: |
57 |
0 |
try: |
58 |
0 |
module = __import__(moduleName, |
59 |
0 |
globals(), |
60 |
0 |
locals(), |
61 |
0 |
['']) |
62 |
0 |
factories.append(module) |
63 |
0 |
except: |
64 |
0 |
debug.printException(debug.LEVEL_OFF) |
65 |
|
|
66 |
0 |
return factories |
67 |
|
|
68 |
1 |
def init(): |
69 |
|
|
70 |
|
global _speechserver |
71 |
|
|
72 |
1 |
if _speechserver: |
73 |
0 |
return |
74 |
|
|
75 |
|
# First, find the factory module to use. We will |
76 |
|
# allow the user to give their own factory module, |
77 |
|
# thus we look first in the global name space, and |
78 |
|
# then we look in the orca namespace. |
79 |
|
# |
80 |
1 |
moduleName = settings.speechServerFactory |
81 |
|
|
82 |
1 |
if moduleName: |
83 |
0 |
debug.println(debug.LEVEL_CONFIGURATION, |
84 |
0 |
"Using speech server factory: %s" % moduleName) |
85 |
|
else: |
86 |
1 |
debug.println(debug.LEVEL_CONFIGURATION, |
87 |
1 |
"Speech not available.") |
88 |
1 |
return |
89 |
|
|
90 |
0 |
factory = None |
91 |
0 |
try: |
92 |
0 |
factory = __import__(moduleName, |
93 |
0 |
globals(), |
94 |
0 |
locals(), |
95 |
0 |
['']) |
96 |
0 |
except: |
97 |
0 |
try: |
98 |
0 |
moduleName = moduleName.replace("orca.","",1) |
99 |
0 |
factory = __import__(moduleName, |
100 |
0 |
globals(), |
101 |
0 |
locals(), |
102 |
0 |
['']) |
103 |
0 |
except: |
104 |
0 |
debug.printException(debug.LEVEL_SEVERE) |
105 |
|
|
106 |
|
# Now, get the speech server we care about. |
107 |
|
# |
108 |
0 |
speechServerInfo = settings.speechServerInfo |
109 |
0 |
if speechServerInfo: |
110 |
0 |
_speechserver = factory.SpeechServer.getSpeechServer(speechServerInfo) |
111 |
|
else: |
112 |
0 |
_speechserver = factory.SpeechServer.getSpeechServer() |
113 |
|
|
114 |
1 |
def __resolveACSS(acss=None): |
115 |
0 |
if acss: |
116 |
0 |
return acss |
117 |
|
else: |
118 |
0 |
voices = settings.voices |
119 |
0 |
return voices[settings.DEFAULT_VOICE] |
120 |
|
|
121 |
1 |
def sayAll(utteranceIterator, progressCallback): |
122 |
1 |
if settings.silenceSpeech: |
123 |
0 |
return |
124 |
1 |
if _speechserver: |
125 |
0 |
_speechserver.sayAll(utteranceIterator, progressCallback) |
126 |
|
else: |
127 |
4 |
for [context, acss] in utteranceIterator: |
128 |
3 |
debug.println(debug.LEVEL_INFO, |
129 |
3 |
"SPEECH OUTPUT: '" + context.utterance + "'") |
130 |
3 |
log.info("sayAll utterance='%s'" % context.utterance) |
131 |
|
|
132 |
1 |
def speak(text, acss=None, interrupt=True): |
133 |
|
"""Speaks all queued text immediately. If text is not None, |
134 |
|
it is added to the queue before speaking. |
135 |
|
|
136 |
|
Arguments: |
137 |
|
- text: optional text to add to the queue before speaking |
138 |
|
- acss: acss.ACSS instance; if None, |
139 |
|
the default voice settings will be used. |
140 |
|
Otherwise, the acss settings will be |
141 |
|
used to augment/override the default |
142 |
|
voice settings. |
143 |
|
- interrupt: if True, stops any speech in progress before |
144 |
|
speaking the text |
145 |
|
""" |
146 |
|
|
147 |
|
# We will not interrupt a key echo in progress. |
148 |
|
# |
149 |
89 |
if orca_state.lastKeyEchoTime: |
150 |
0 |
interrupt = interrupt \ |
151 |
0 |
and ((time.time() - orca_state.lastKeyEchoTime) > 0.5) |
152 |
|
|
153 |
89 |
if settings.silenceSpeech: |
154 |
0 |
return |
155 |
|
|
156 |
89 |
debug.println(debug.LEVEL_INFO, "SPEECH OUTPUT: '" + text + "'") |
157 |
89 |
log.info("speak utterance='%s'" % text) |
158 |
|
|
159 |
89 |
if _speechserver: |
160 |
0 |
_speechserver.speak(text, __resolveACSS(acss), interrupt) |
161 |
|
|
162 |
1 |
def speakKeyEvent(event_string, type): |
163 |
|
"""Speaks a key event immediately. |
164 |
|
|
165 |
|
Arguments: |
166 |
|
- event_string: string representing the key event as defined by |
167 |
|
input_event.KeyboardEvent. |
168 |
|
- type: key event type as one of orca.KeyEventType constants. |
169 |
|
|
170 |
|
""" |
171 |
0 |
if settings.silenceSpeech: |
172 |
0 |
return |
173 |
|
|
174 |
0 |
if _speechserver: |
175 |
0 |
_speechserver.speakKeyEvent(event_string, type) |
176 |
|
else: |
177 |
|
# Check to see if there are localized words to be spoken for |
178 |
|
# this key event. |
179 |
|
# |
180 |
0 |
event_string = keynames.getKeyName(event_string) |
181 |
|
|
182 |
0 |
if type == orca.KeyEventType.LOCKING_LOCKED: |
183 |
|
# Translators: this represents the state of a locking modifier |
184 |
|
# key (e.g., Caps Lock) |
185 |
|
# |
186 |
0 |
event_string += " " + _("on") |
187 |
0 |
elif type == orca.KeyEventType.LOCKING_UNLOCKED: |
188 |
|
# Translators: this represents the state of a locking modifier |
189 |
|
# key (e.g., Caps Lock) |
190 |
|
# |
191 |
0 |
event_string += " " + _("off") |
192 |
|
|
193 |
0 |
debug.println(debug.LEVEL_INFO, "SPEECH OUTPUT: '" + event_string +"'") |
194 |
0 |
log.info("speakKeyEvent utterance='%s'" % event_string) |
195 |
|
|
196 |
1 |
def isSpeaking(): |
197 |
|
""""Returns True if the system is currently speaking.""" |
198 |
0 |
if _speechserver: |
199 |
0 |
return _speechserver.isSpeaking() |
200 |
|
else: |
201 |
0 |
return False |
202 |
|
|
203 |
1 |
def speakUtterances(utterances, acss=None, interrupt=True): |
204 |
|
"""Speaks the given list of utterances immediately. |
205 |
|
|
206 |
|
Arguments: |
207 |
|
- list: list of strings to be spoken |
208 |
|
- acss: acss.ACSS instance; if None, |
209 |
|
the default voice settings will be used. |
210 |
|
Otherwise, the acss settings will be |
211 |
|
used to augment/override the default |
212 |
|
voice settings. |
213 |
|
- interrupt: if True, stop any speech currently in progress. |
214 |
|
""" |
215 |
|
|
216 |
|
# We will not interrupt a key echo in progress. |
217 |
|
# |
218 |
810 |
if orca_state.lastKeyEchoTime: |
219 |
0 |
interrupt = interrupt \ |
220 |
0 |
and ((time.time() - orca_state.lastKeyEchoTime) > 0.5) |
221 |
|
|
222 |
810 |
if settings.silenceSpeech: |
223 |
0 |
return |
224 |
|
|
225 |
2648 |
for utterance in utterances: |
226 |
1838 |
debug.println(debug.LEVEL_INFO, |
227 |
1838 |
"SPEECH OUTPUT: '" + utterance + "'") |
228 |
1838 |
log.info("speakUtterances utterance='%s'" % utterance) |
229 |
|
|
230 |
810 |
if _speechserver: |
231 |
0 |
_speechserver.speakUtterances(utterances, |
232 |
0 |
__resolveACSS(acss), |
233 |
0 |
interrupt) |
234 |
|
|
235 |
1 |
def stop(): |
236 |
1914 |
if _speechserver: |
237 |
0 |
_speechserver.stop() |
238 |
|
|
239 |
1 |
def increaseSpeechRate(script=None, inputEvent=None): |
240 |
0 |
if _speechserver: |
241 |
0 |
_speechserver.increaseSpeechRate() |
242 |
|
else: |
243 |
0 |
debug.println(debug.LEVEL_INFO, |
244 |
0 |
"SPEECH OUTPUT: 'faster'") |
245 |
0 |
log.info("increaseSpeechRate") |
246 |
|
|
247 |
0 |
return True |
248 |
|
|
249 |
1 |
def decreaseSpeechRate(script=None, inputEvent=None): |
250 |
0 |
if _speechserver: |
251 |
0 |
_speechserver.decreaseSpeechRate() |
252 |
|
else: |
253 |
0 |
debug.println(debug.LEVEL_INFO, |
254 |
0 |
"SPEECH OUTPUT: 'slower'") |
255 |
0 |
log.info("decreaseSpeechRate") |
256 |
|
|
257 |
0 |
return True |
258 |
|
|
259 |
1 |
def increaseSpeechPitch(script=None, inputEvent=None): |
260 |
0 |
if _speechserver: |
261 |
0 |
_speechserver.increaseSpeechPitch() |
262 |
|
else: |
263 |
0 |
debug.println(debug.LEVEL_INFO, |
264 |
0 |
"SPEECH OUTPUT: 'higher'") |
265 |
0 |
log.info("increaseSpeechPitch") |
266 |
|
|
267 |
0 |
return True |
268 |
|
|
269 |
1 |
def decreaseSpeechPitch(script=None, inputEvent=None): |
270 |
0 |
if _speechserver: |
271 |
0 |
_speechserver.decreaseSpeechPitch() |
272 |
|
else: |
273 |
0 |
debug.println(debug.LEVEL_INFO, |
274 |
0 |
"SPEECH OUTPUT: 'lower'") |
275 |
0 |
log.info("decreaseSpeechPitch") |
276 |
|
|
277 |
0 |
return True |
278 |
|
|
279 |
1 |
def shutdown(): |
280 |
|
global _speechserver |
281 |
2 |
if _speechserver: |
282 |
0 |
_speechserver.shutdownActiveServers() |
283 |
0 |
_speechserver = None |
284 |
|
|
285 |
1 |
def reset(text=None, acss=None): |
286 |
|
global _speechserver |
287 |
0 |
if _speechserver: |
288 |
0 |
_speechserver.reset(text, acss) |
289 |
|
|
290 |
1 |
def testNoSettingsInit(): |
291 |
0 |
init() |
292 |
0 |
speak("testing") |
293 |
0 |
speak("this is higher", ACSS({'average-pitch' : 7})) |
294 |
0 |
speak("this is slower", ACSS({'rate' : 3})) |
295 |
0 |
speak("this is faster", ACSS({'rate' : 80})) |
296 |
0 |
speak("this is quiet", ACSS({'gain' : 2})) |
297 |
0 |
speak("this is loud", ACSS({'gain' : 10})) |
298 |
0 |
speak("this is normal") |
299 |
|
|
300 |
1 |
def test(): |
301 |
0 |
import speechserver |
302 |
0 |
factories = getSpeechServerFactories() |
303 |
0 |
for factory in factories: |
304 |
0 |
print factory.__name__ |
305 |
0 |
servers = factory.SpeechServer.getSpeechServers() |
306 |
0 |
for server in servers: |
307 |
0 |
try: |
308 |
0 |
print " ", server.getInfo() |
309 |
0 |
for family in server.getVoiceFamilies(): |
310 |
0 |
name = family[speechserver.VoiceFamily.NAME] |
311 |
0 |
print " ", name |
312 |
0 |
acss = ACSS({ACSS.FAMILY : family}) |
313 |
0 |
server.speak(name, acss) |
314 |
0 |
server.speak("testing") |
315 |
0 |
server.shutdown() |
316 |
0 |
except: |
317 |
0 |
debug.printException(debug.LEVEL_OFF) |
318 |
0 |
pass |