RapidWareTech / pyttsx

Cross-platform text-to-speech wrapper
Other
370 stars 134 forks source link

Converted SAPI5 driver and espeak driver to be compatible with 2.7 and 3.4 #30

Closed westonpace closed 3 years ago

westonpace commented 9 years ago

I am trying and get a mac so I can convert that driver as well but at the moment I do not have access to one. In the meantime I have converted the other two drivers as well as the main libraries. I used python six for most of the compatibility changes. I have run the unit tests on:

Windows 64 bit 2.7 Windows 64 bit 3.4 Linux 64 bit 2.7 Linux 64 bit 3.4

I know that some of the changes I have made are not compatible with 2.5 (and possibly 2.6) but I don't know if the code was already compatible with those earlier versions or not. My assumption was that it was only compatible with 2.7.

Feel free to suggest changes or a different way of doing things, I should have some time to work on this over the next few months as I will be using this library in my next project.

westonpace commented 9 years ago

Just realized there are a few more changes in there I should probably explain that were related more to getting the unit tests to pass than any explicit conversion.

The espeak driver was calling getCurrentVoice immediately after espeak was initialized to get the default voice. Unfortunately, in my testing, it appears that espeak doesn't actually set a default voice until something is synthesized. I checked the espeak code and it appears that, if they are asked to synthesize something, and no voice is set, then they load a voice named specifically "default" so I figured it was safe to rely on a voice named "default" being available and used that as the default voice.

The test_say test class had a testStop test. This test was setting up a listener for a "started-word" event and stopping the engine once it received that event. In espeak the callback is not called (it seems) until its buffer fills up. This was causing the stop not to happen until about a second into speaking and the test was occasionally failing because that would be enough time to speak all the words. I modified the sentence spoken in the unit test to be longer so that it would ensure not all the words were spoken.

The third thing appears to be more of a bug in espeak than a bug in pyttsx. There are two voices in espeak (on my system at least) which have a capital letter in their name (Farsi and some other voice). One of the tests iterated through all the voices and tried to set that voice. The SetVoiceByName function in espeak will take whatever name is passed in and convert it to lowercase. It then compares this modified name to each available name, unmodified. As such, it was never able to select the Farsi voice because it simply isn't possible the way espeak is written. One workaround would be to pass the espeak voice identifier into SetVoiceByName but that would require replacing the pyttsx voice identifier (which is currently set to the espeak voice name) with the espeak voice identifier and I was worried that may impact backwards compatibility so for now I just modified the test to work around this corner case with a comment explaining as much.