Skip to content

Fix for issue #23 on the list of languages of voice definition. #24

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 29 additions & 4 deletions pyttsx/drivers/_espeak.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

import ctypes
from ctypes import cdll, c_int, c_char_p, c_wchar_p, POINTER, c_short, c_uint, c_long, c_void_p
from ctypes import CFUNCTYPE, byref, Structure, Union, c_wchar, c_ubyte, c_ulong
from ctypes import CFUNCTYPE, cast, byref, Structure, Union, c_wchar, c_ubyte, c_ulong
from ctypes import string_at, create_string_buffer
import time

def cfunc(name, dll, result, *args):
Expand Down Expand Up @@ -339,7 +340,7 @@ def Synth_Mark(text, index_mark, end_position=0, flags=CHARS_AUTO):
class VOICE(Structure):
_fields_ = [
('name', c_char_p),
('languages', c_char_p),
('languages', c_void_p),
('identifier', c_char_p),
('gender', c_ubyte),
('age', c_ubyte),
Expand All @@ -354,7 +355,20 @@ def __repr__(self):
for field in self._fields_:
res.append('%s=%s' % (field[0], repr(getattr(self, field[0]))))
return self.__class__.__name__ + '(' + ','.join(res) + ')'

def getLanguages(self):
languages = []
c_ubyte_p = POINTER(c_ubyte)
p = self.languages
while True:
priority = ctypes.cast(p, c_ubyte_p).contents.value
if priority == 0:
break
lang = string_at(p + 1)
langlen = len(lang)
languages.append((priority, lang))
p += 1 + langlen + 1
languages.sort(lambda x,y: cmp(x[0], y[0]))
return [ t[1] for t in languages ]

cListVoices = cfunc('espeak_ListVoices', dll, POINTER(POINTER(VOICE)),
('voice_spec', POINTER(VOICE), 1))
Expand All @@ -379,6 +393,17 @@ def ListVoices(voice_spec=None):
i += 1
return res

def ListLanguageVoices(language=None):
'''List the languages available for a given language.

If the language is NULL, all voices are listed.'''
voice_spec_p = None
if language:
voice_spec = VOICE()
voice_spec.languages = cast(create_string_buffer(language), c_void_p)
voice_spec_p = byref(voice_spec)
return ListVoices(voice_spec_p)

SetVoiceByName = cfunc('espeak_SetVoiceByName', dll, c_int,
('name', c_char_p, 1))
SetVoiceByName.__doc__ = '''Searches for a voice with a matching "name" field. Language is not considered.
Expand Down Expand Up @@ -457,4 +482,4 @@ def synth_cb(wav, numsample, events):
#SetParameter(PITCH, 50, 0)
print Synth(s)
while IsPlaying():
time.sleep(0.1)
time.sleep(0.1)
30 changes: 18 additions & 12 deletions pyttsx/drivers/espeak.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ def buildDriver(proxy):
class EspeakDriver(object):
_moduleInitialized = False
_defaultVoice = ''
genders = [None, 'male', 'female']

def __init__(self, proxy):
if not EspeakDriver._moduleInitialized:
# espeak cannot initialize more than once per process and has
Expand Down Expand Up @@ -57,26 +59,30 @@ def stop(self):
if _espeak.IsPlaying():
self._stopping = True

def getVoices(self, language=None):
voices = []
for v in _espeak.ListLanguageVoices(language):
kwargs = {}
kwargs['id'] = v.name
kwargs['name'] = v.name
if v.languages:
kwargs['languages'] = v.getLanguages()
kwargs['gender'] = self.genders[v.gender]
kwargs['age'] = v.age or None
voices.append(Voice(**kwargs))
return voices

def getProperty(self, name):
if name == 'voices':
voices = []
for v in _espeak.ListVoices(None):
kwargs = {}
kwargs['id'] = v.name
kwargs['name'] = v.name
if v.languages:
kwargs['languages'] = [v.languages]
genders = [None, 'male', 'female']
kwargs['gender'] = genders[v.gender]
kwargs['age'] = v.age or None
voices.append(Voice(**kwargs))
return voices
return self.getVoices()
elif name == 'voice':
return _espeak.GetCurrentVoice().contents.name
elif name == 'rate':
return _espeak.GetParameter(_espeak.RATE)
elif name == 'volume':
return _espeak.GetParameter(_espeak.VOLUME)/100.0
elif name.startswith('voices-'):
return self.getVoices(name[7:])
else:
raise KeyError('unknown property %s' % name)

Expand Down