1  """Python wrapper for Emacspeak speech servers. 
  2   
  3  The emacspeak TTS server provides a simple but powerful and 
  4  well-tested speech-server abstraction. That server is implemented 
  5  as an external program (typically in TCL).  This wrapper class 
  6  provides Python access to available Emacspeak speech servers. 
  7   
  8  Initially, this class will provide Python access to the TTS 
  9  server commands.  Over time, this module may also implement 
 10  functionality present in Emacspeak's Lisp layer ---specifically, 
 11  higher level TTS functionality provided by the following 
 12  emacspeak modules: 
 13   
 14  0)  dtk-speak.el 
 15   
 16  1)  emacspeak-pronounce.el 
 17   
 18  2)  accs-structure.el 
 19   
 20  """ 
 21   
 22  __id__ = "$Id: speaker.py 7067 2011-06-25 02:49:51Z tv.raman.tv $" 
 23  __author__ = "$Author: tv.raman.tv $" 
 24  __version__ = "$Revision: 7067 $" 
 25  __date__ = "$Date: 2011-06-24 19:49:51 -0700 (Fri, 24 Jun 2011) $" 
 26  __copyright__ = "Copyright (c) 2005 T. V. Raman" 
 27  __license__ = "LGPL" 
 28  __all__=['Speaker'] 
 29   
 30  import os, sys, subprocess 
 31   
 33       
 34      """Provides speech servre abstraction. 
 35   
 36      Class Variables: 
 37   
 38          location -- specifies directory where Emacspeak 
 39          speech servers are installed. 
 40   
 41          config --  dictionary of default settings. 
 42       
 43      Speaker objects can be initialized with the following parameters: 
 44   
 45          engine -- TTS server to instantiate. Default: outloud 
 46          host -- Host that runs   server. Default: localhost 
 47          settings -- Dictionary of default settings. 
 48   
 49      """ 
 50   
 51      location="/usr/share/emacs/site-lisp/emacspeak/servers" 
 52   
 53      config = {'splitcaps' : 1, 
 54                'rate' : 70, 
 55      'capitalize' : 0, 
 56      'allcaps' : 0, 
 57      'punctuations' : 'all' 
 58      } 
 59   
 61          """Enumerate available engines.""" 
 62          f = open(os.path.join(Speaker.location, '.servers')) 
 63          engines = [] 
 64          for line in f: 
 65              if line[0] == '#' or line.strip() == '': continue 
 66              engines.append(line.strip()) 
 67          f.close() 
 68          return engines 
  69   
 70      listEngines = staticmethod(listEngines) 
 71           
 72 -    def __init__ (self, 
 73                    engine='32-outloud', 
 74                    host='localhost', 
 75                    initial=config): 
  76          """Launches speech engine.""" 
 77           
 78          self._engine =engine 
 79          e =  __import__(_getcodes(engine)) 
 80          self.getvoice =e.getvoice 
 81          self.getrate = e.getrate 
 82          if host == 'localhost': 
 83              self._server = os.path.join(Speaker.location, self._engine) 
 84          else: 
 85              self._server = os.path.join(Speaker.location, 
 86                                           "ssh-%s" % 
 87                                           self._engine) 
 88          cmd = '{ ' + self._server + '; } 2>&1' 
 89          server_process = subprocess.Popen(cmd, 1, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, close_fds=True) 
 90          (self._w, self._r, self._e) = server_process.stdin, server_process.stdout, server_process.stderr 
 91          self._settings ={} 
 92          if initial is not None: 
 93              self._settings.update(initial) 
 94              self.configure(self._settings) 
  95   
101   
102 -    def settings(self): return self._settings 
 103       
104 -    def say(self, text="", acss=None): 
 105          """Speaks specified text. 
106  All queued text is spoken immediately.""" 
107           
108           
109          if acss is not None: 
110              code =self.getvoice(acss) 
111              self._w.write("q {%s %s %s}\nd\n" %(code[0], text, code[1])) 
112          else: 
113              self._w.write("q {%s}\nd\n" %text) 
 114   
116       
118          """Speak list of utterances.""" 
119          if acss is not None: 
120              code =self.getvoice(acss) 
121              for t in list: 
122                  self._w.write("q { %s %s %s }\n" %(code[0], str(t), code[1])) 
123          else: 
124              for t in list: 
125                  self._w.write("q { %s }\n" % str(t)) 
126          self._w.write("d\n") 
 127       
129          """Speak single character.""" 
130          self._w.write("l {%s}\n" %l) 
 131   
132 -    def queueTone(self, pitch=440, duration=50): 
 133          """Queue specified tone.""" 
134          self._w.write("t %s %s\n " % (pitch, duration)) 
 135   
137          """Queue specified silence.""" 
138          self._w.write("sh  %s" %  duration) 
 139       
140 -    def queueText(self, text="", acss=None): 
 141          """Queue text to be spoken. 
142          Output is produced by next call to say() or speak().""" 
143          if acss is not None: 
144              code =self.getvoice(acss) 
145              self._w.write("q {%s %s %s}\n" %(code[0], text, 
146          code[1])) 
147          else: 
148              self._w.write("q {%s}\n" %text) 
 149   
151          """Silence ongoing speech.""" 
152          self._w.write("s\n") 
 153   
155          """Shutdown speech engine.""" 
156          self._w.close() 
157          self._r.close() 
158          self._e.close() 
159          sys.stderr.write("shut down TTS\n") 
 160       
162          """Reset TTS engine.""" 
163          self._w.write("tts_reset\n") 
 164       
166          """Speak TTS version info.""" 
167          self._w.write("version\n") 
 168   
170          """Set punctuation mode.""" 
171          if mode in ['all', 'some', 'none']: 
172              self._settings['punctuations'] = mode 
173              self._w.write("tts_set_punctuations %s\n" % mode) 
 174   
176          """Set speech rate.""" 
177          self._settings['rate'] = r 
178          self._w.write("tts_set_speech_rate %s\n" % self.getrate(r)) 
 179   
181          """Set speech rate.""" 
182          self._settings['rate'] += step 
183          self._w.write("tts_set_speech_rate %s\n" % self.getrate(self._settings['rate'])) 
 184   
186          """Set speech rate.""" 
187          self._settings['rate'] -= step 
188          self._w.write("tts_set_speech_rate %s\n" % self.getrate(self._settings['rate'])) 
 189   
191          """Set splitcaps mode. 1  turns on, 0 turns off""" 
192          flag = bool(flag) and 1 or 0 
193          self._settings['splitcaps'] = flag 
194          self._w.write("tts_split_caps %s\n" % flag) 
 195   
197          """Set capitalization  mode. 1  turns on, 0 turns off""" 
198          flag = bool(flag) and 1 or 0 
199          self._settings['capitalize'] = flag 
200          self._w.write("tts_capitalize %s\n" % flag) 
 201   
203          """Set allcaps  mode. 1  turns on, 0 turns off""" 
204          flag = bool(flag) and 1 or 0 
205          self._settings['allcaps'] = flag 
206          self._w.write("tts_allcaps_beep %s\n" % flag) 
 207   
209          "Shutdown speech engine." 
210          if not self._w.closed: self.shutdown() 
  211   
213   
214  _codeTable = { 
215      'dtk-exp' : 'dectalk', 
216      'dtk-mv' : 'dectalk', 
217      'dtk-soft' : 'dectalk', 
218      'outloud' : 'outloud', 
219      '32-outloud' : 'outloud', 
220      } 
221   
223      """Self test.""" 
224      import time 
225      import acss 
226      s=Speaker() 
227      a=acss.ACSS() 
228      s.punctuations('all') 
229      s.queueText("This is an initial test. test."); 
230      s.queueText("Next, we'll test audio formatted output.") 
231      for d in ['average-pitch', 'pitch-range', 
232                'richness', 'stress']: 
233          for i in range(0,10,2): 
234              a[d] = i 
235              s.queueText("Set %s to %i. " % (d, i), a) 
236          del a[d] 
237          s.queueText("Reset %s." % d, a) 
238      s.speak("") 
239      print "sleeping  while waiting for speech to complete." 
240      time.sleep(40) 
241      s.shutdown() 
 242   
243   
244  if __name__=="__main__": _test() 
245