# My Python3 Library provides a Wrapper around the Popular espeak TTS

My code:

import subprocess
import os
import platform

class Speaker:
"""
Speaker class for differentiating different speech properties.
"""

def setVoice(self, voice):
self.voice = voice

def setWPM(self, wpm):
self.wpm = wpm

def setPitch(self, pitch):
self.pitch = pitch

def setProperties(self, voice="en", wpm=120, pitch=80):
self.setVoice(voice)
self.setWPM(wpm)
self.setPitch(pitch)

def __init__(self, voice="en", wpm=120, pitch=80):
self.prevproc = None
self.setProperties(voice, wpm, pitch)
self.executable = os.path.dirname(os.path.abspath(__file__)) +
"/espeak.exe" if platform.system() == 'Windows'
else os.path.dirname(os.path.abspath(__file__)) + "/espeak"

def generateCommand(self, phrase):
cmd = [
self.executable,
"--path=.",
"-v", self.voice,
"-p", self.pitch,
"-s", self.wpm,
phrase
]
cmd = [str(x) for x in cmd]
return cmd

def say(self, phrase, wait4prev=False):
cmd=self.generateCommand(phrase)
if wait4prev:
try: self.prevproc.wait()
except AttributeError: pass
else:
try: self.prevproc.terminate()
except AttributeError: pass
self.prevproc = subprocess.Popen(cmd, executable=self.executable,
cwd=os.path.dirname(os.path.abspath(__file__)))


How can the above code be improved?

Find it on GitHub: https://github.com/sayak-brm/espeak4py

Usage:

import espeak4py
import time

print('Testing espeak4py\n')

mySpeaker = espeak4py.Speaker()

mySpeaker.say('Testing', wait4prev=True)

print('Testing wait4prev')

mySpeaker.say('Hello, World!')
time.sleep(1)
mySpeaker.say('Interrupted!')
time.sleep(3)

mySpeaker.say('Hello, World!')
time.sleep(1)
mySpeaker.say('Not Interrupted.', wait4prev=True)
time.sleep(3)

print('Testing pitch')

myHighPitchedSpeaker = espeak4py.Speaker(pitch=120)
myHighPitchedSpeaker.say('I am a demo of the say function')
time.sleep(4)

print('Testing wpm')

myFastSpeaker = espeak4py.Speaker(wpm=140)
myFastSpeaker.say('I am a demo of the say function')
time.sleep(4)

print('Testing voice')

mySpanishSpeaker = espeak4py.Speaker(voice='es')
mySpanishSpeaker.say('Hola. Como estas?')

print('Testing Completed.')


1.PEP8

Naming

In python functions/methods/variables are using underscore as a naming separator, but not a camelCase.

Quotes

You should pick one double or single quotes and use it everywhere that is a general rule, I prefer single ones so I've changed a code as I like, but you might want to use double, just follow one way to do that.

2.Class definition

Methods order

I prefer to have __init__ and __new__ as first methods defined by class, this gives you better image on class and what it does and what it got. This is not a strong rule, but most of people and libraries are following it.

Properties definition

Most of the times you want to have all your properties defined in init, again that is not a strong rule, but in this particular case, I would define them inside __init__ instead of having a separate method to do that. If fact you I don't see much of use of your setProperties method, so I would just modify object attributes directly here if I would need it. Since there are no logics inside those methods except for changing an attribute to a value passed into it.

3.Improvements

I'm not a big fan of try:catch:pass statements you can avoid them with pre-conditions: so your say method can be modified like this:

def say(self, phrase, wait4prev=False):
cmd = self.generate_command(phrase)
if self.prevproc:
if wait4prev:
self.prevproc.wait()
else:
self.prevproc.terminate()
self.prevproc = subprocess.Popen(cmd, cwd=os.path.dirname(os.path.abspath(__file__)))


Note: you don't need to pass executable explicitly since it's already a part of your cmd param.

So in the end what we have is this:

import os
import platform
import subprocess

class Speaker:
"""
Speaker class for differentiating different speech properties.
"""
def __init__(self, voice='en', wpm=120, pitch=80):
self.prevproc = None
self.voice = voice
self.wpm = wpm
self.pitch = pitch

executable = 'espeak.exe' if platform.system() == 'Windows' else 'espeak'
self.executable = os.path.join(os.path.dirname(os.path.abspath(__file__)), executable)

def generate_command(self, phrase):
cmd = [
self.executable,
'--path=.',
'-v', self.voice,
'-p', self.pitch,
'-s', self.wpm,
phrase
]
cmd = [str(x) for x in cmd]
return cmd

def say(self, phrase, wait4prev=False):
cmd = self.generate_command(phrase)
if self.prevproc:
if wait4prev:
self.prevproc.wait()
else:
self.prevproc.terminate()
self.prevproc = subprocess.Popen(cmd, cwd=os.path.dirname(os.path.abspath(__file__)))

• I learnt a lot about Python today, thanks to you. I'll be sure to read up more about the PEP8 (I didn't know that something like that existed). – sbrm1 Jan 2 '17 at 17:22