11
22import time
33import ctypes
4+ import io
5+ import wave
6+ import os
7+ from tempfile import NamedTemporaryFile
48from ..voice import Voice
59from . import _espeak , toUtf8 , fromUtf8
610
@@ -18,7 +22,7 @@ def __init__(self, proxy):
1822 # espeak cannot initialize more than once per process and has
1923 # issues when terminating from python (assert error on close)
2024 # so just keep it alive and init once
21- rate = _espeak .Initialize (_espeak .AUDIO_OUTPUT_PLAYBACK , 1000 )
25+ rate = _espeak .Initialize (_espeak .AUDIO_OUTPUT_RETRIEVAL , 1000 )
2226 if rate == - 1 :
2327 raise RuntimeError ('could not initialize espeak' )
2428 EspeakDriver ._defaultVoice = 'default'
@@ -31,6 +35,15 @@ def __init__(self, proxy):
3135 self ._proxy = proxy
3236 self ._looping = True
3337 self ._stopping = False
38+ self ._data_buffer = b''
39+ self ._numerise_buffer = []
40+
41+ def numerise (self , data ):
42+ self ._numerise_buffer .append (data )
43+ return ctypes .c_void_p (len (self ._numerise_buffer ))
44+
45+ def decode_numeric (self , data ):
46+ return self ._numerise_buffer [int (data ) - 1 ]
3447
3548 def destroy (self ):
3649 _espeak .SetSynthCallback (None )
@@ -111,7 +124,9 @@ def startLoop(self):
111124 time .sleep (0.01 )
112125
113126 def save_to_file (self , text , filename ):
114- raise NotImplementedError
127+ code = self .numerise (filename )
128+ _espeak .Synth (toUtf8 (text ), flags = _espeak .ENDPAUSE |
129+ _espeak .CHARS_UTF8 , user_data = code )
115130
116131 def endLoop (self ):
117132 self ._looping = False
@@ -139,7 +154,25 @@ def _onSynth(self, wav, numsamples, events):
139154 location = event .text_position - 1 ,
140155 length = event .length )
141156 elif event .type == _espeak .EVENT_MSG_TERMINATED :
157+ stream = NamedTemporaryFile ()
158+
159+ with wave .open (stream , 'wb' ) as f :
160+ f .setnchannels (1 )
161+ f .setsampwidth (2 )
162+ f .setframerate (22050.0 )
163+ f .writeframes (self ._data_buffer )
164+
165+ if event .user_data :
166+ os .system ('ffmpeg -y -i {} {} -loglevel quiet' .format (stream .name , self .decode_numeric (event .user_data )))
167+ else :
168+ os .system ('aplay {} -q' .format (stream .name )) # -q for quiet
169+
170+ self ._data_buffer = b''
142171 self ._proxy .notify ('finished-utterance' , completed = True )
143172 self ._proxy .setBusy (False )
144173 i += 1
174+
175+ if numsamples > 0 :
176+ self ._data_buffer += ctypes .string_at (wav , numsamples *
177+ ctypes .sizeof (ctypes .c_short ))
145178 return 0
0 commit comments