Skip to content

Commit

Permalink
version 19.8b1
Browse files Browse the repository at this point in the history
update imports for custom driver settings.
add supported commands.
fix a small mistake in characterMode command.
add indexReached and done event notiffications.
update compatibility for python 2.7 and the older speech framework.
Some issues with NVDA 2019.3 in real time changing synth parameters
update NVDA compatibility versions, now compatible from 2018.3 to 2019.3
  • Loading branch information
davidacm committed Aug 1, 2019
1 parent 019a42d commit d6e94c3
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 18 deletions.
15 changes: 11 additions & 4 deletions addon/synthDrivers/_ibmeci.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import threading, time
import config, languageHandler, nvwave, addonHandler
from logHandler import log
import _settingsDB
from . import _settingsDB

addonHandler.initTranslation()

Expand Down Expand Up @@ -54,6 +54,9 @@ class ECICallbackReturn:
eciThreadId = None
callbackThread = None
callbackQueue = queue.Queue()
onIndexReached = None
onDoneSpeaking = None

samples=3300
buffer = create_string_buffer(samples*2)
idleTimer = threading.Timer(0.3, time.sleep) # fake timer because this can't be None.
Expand Down Expand Up @@ -215,6 +218,7 @@ def _callbackExec(func, *args, **kwargs):
def setLast(lp):
global lastindex
lastindex = lp
onIndexReached(lp)

def bgPlay(stri):
if len(stri) == 0: return
Expand Down Expand Up @@ -249,7 +253,7 @@ def callback (h, ms, lp, dt):
audioStream.truncate(0)
audioStream.seek(0)
elif ms==ECIMessage.eciIndexReply:
if lp != END_STRING_MARK: #end of string
if lp != END_STRING_MARK: # not end of string
curindex = lp
else: #We reached the end of string
if audioStream.tell() > 0:
Expand Down Expand Up @@ -282,8 +286,10 @@ def _callbackExec(func, *args, **kwargs):
global callbackQueue
callbackQueue.put((func, args, kwargs))

def initialize():
global callbackThread, dll, eciThread, handle, player
def initialize(indexCallback, doneCallback):
global callbackThread, dll, eciThread, handle, onIndexReached, onDoneSpeaking, player
onIndexReached = indexCallback
onDoneSpeaking = doneCallback
player = nvwave.WavePlayer(1, 11025, 16, outputDevice=config.conf["speech"]["outputDevice"])
if not eciCheck():
raise RuntimeError("No IBMTTS synthesizer available")
Expand Down Expand Up @@ -379,6 +385,7 @@ def endStringEvent():
endMarkersCount -=1
if endMarkersCount == 0:
speaking = False
onDoneSpeaking()
idleTimer = threading.Timer(0.3, idlePlayer)
idleTimer.start()

Expand Down
53 changes: 42 additions & 11 deletions addon/synthDrivers/ibmeci.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,23 @@
import six, synthDriverHandler, speech, languageHandler, config, os, re
from collections import OrderedDict
from six import string_types
from synthDriverHandler import SynthDriver,VoiceInfo,BooleanSynthSetting,NumericSynthSetting
from synthDriverHandler import SynthDriver,VoiceInfo
from logHandler import log
import _ibmeci
from _ibmeci import ECIVoiceParam
from synthDrivers import _ibmeci
from synthDrivers._ibmeci import ECIVoiceParam
import addonHandler
addonHandler.initTranslation()

try:
try: # for python 2.7
unicode
from synthDriverHandler import BooleanSynthSetting as BooleanDriverSetting,NumericSynthSetting as NumericDriverSetting
class synthIndexReached:
@classmethod
def notify (cls, synth=None, index=None): pass
synthDoneSpeaking = synthIndexReached
except:
from driverHandler import BooleanDriverSetting,NumericDriverSetting
from synthDriverHandler import synthIndexReached, synthDoneSpeaking
def unicode(s):
return s

Expand Down Expand Up @@ -88,18 +95,34 @@ def unicode(s):
}

class SynthDriver(synthDriverHandler.SynthDriver):
supportedSettings=(SynthDriver.VoiceSetting(), SynthDriver.VariantSetting(),
SynthDriver.RateSetting(), BooleanSynthSetting("rateBoost", _("Rate boos&t"), True),
SynthDriver.PitchSetting(), SynthDriver.InflectionSetting(), SynthDriver.VolumeSetting(), NumericSynthSetting("hsz", _("Head Size"), False), NumericSynthSetting("rgh", _("Roughness"), False), NumericSynthSetting("bth", _("Breathiness"), False), BooleanSynthSetting("backquoteVoiceTags", _("Enable backquote voice &tags"), False))
supportedSettings=(SynthDriver.VoiceSetting(), SynthDriver.VariantSetting(), SynthDriver.RateSetting(),
BooleanDriverSetting("rateBoost", _("Rate boos&t"), True),
SynthDriver.PitchSetting(), SynthDriver.InflectionSetting(), SynthDriver.VolumeSetting(),
NumericDriverSetting("hsz", _("Head Size"), False),
NumericDriverSetting("rgh", _("Roughness"), False),
NumericDriverSetting("bth", _("Breathiness"), False),
BooleanDriverSetting("backquoteVoiceTags", _("Enable backquote voice &tags"), False))
supportedCommands = {
speech.IndexCommand,
speech.CharacterModeCommand,
speech.LangChangeCommand,
speech.BreakCommand,
speech.PitchCommand,
speech.RateCommand,
speech.VolumeCommand
}
supportedNotifications = {synthIndexReached, synthDoneSpeaking}

description='IBMTTS'
name='ibmeci'
speakingLanguage=""

@classmethod
def check(cls):
return _ibmeci.eciCheck()

def __init__(self):
_ibmeci.initialize()
_ibmeci.initialize(self._onIndexReached, self._onDoneSpeaking)
# This information doesn't really need to be displayed, and makes IBMTTS unusable if the addon is not in the same drive as NVDA executable.
# But display it only on debug mode in case of it can be useful
log.debug("Using IBMTTS version %s" % _ibmeci.eciVersion())
Expand All @@ -108,6 +131,11 @@ def __init__(self):
self.speakingLanguage=lang
self.variant="1"

PROSODY_ATTRS = {
speech.PitchCommand: "`vs",
speech.VolumeCommand: "`vv",
speech.RateCommand: "vb",
}

def speak(self,speechSequence):
last = None
Expand All @@ -133,14 +161,14 @@ def speak(self,speechSequence):
outlist.append((_ibmeci.speak, (langsAnnotations[defaultLanguage],)))
self.speakingLanguage = defaultLanguage
elif isinstance(item,speech.CharacterModeCommand):
outlist.append((_ibmeci.speak, (b"`ts1" if item.state else "b`ts0",)))
outlist.append((_ibmeci.speak, (b"`ts1" if item.state else b"`ts0",)))
elif isinstance(item,speech.BreakCommand):
outlist.append((_ibmeci.speak, (b' `p%d ' %item.time,)))
elif isinstance(item,speech.SpeechCommand):
log.debugWarning("Unsupported speech command: %s"%item)
else:
log.error("Unknown speech: %s"%item)
if last is not None and not last[-1] in punctuation: outlist.append((_ibmeci.speak, (b'`p1. ',)))
if last is not None and not str(last[-1]) in punctuation: outlist.append((_ibmeci.speak, (b'`p1. ',)))
outlist.append((_ibmeci.setEndStringMark, ()))
outlist.append((_ibmeci.synth, ()))
_ibmeci.eciQueue.put(outlist)
Expand Down Expand Up @@ -285,6 +313,9 @@ def _set_variant(self, v):

def _get_variant(self): return self._variant

def _onIndexReached(self, index): synthIndexReached.notify(synth=self, index=index)

def _onDoneSpeaking(self): synthDoneSpeaking.notify(synth=self)

def resub(dct, s):
for r in six.iterkeys(dct):
Expand Down
6 changes: 3 additions & 3 deletions buildVars.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,17 @@
# Translators: Long description to be shown for this add-on on add-on information from add-ons manager
"addon_description" : _("""This is the IBMTTS synthesizer driver for NVDA."""),
# version
"addon_version" : "19.5B1",
"addon_version" : "19.8B1",
# Author(s)
"addon_author" : u"David CM <dhf360@gmail.com> and others",
# URL for the add-on documentation support
"addon_url" : "https://github.com/david-acm/NVDA-IBMTTS-Driver",
# Documentation file name
"addon_docFileName" : "readme.html",
# Minimum NVDA version supported (e.g. "2018.3.0")
"addon_minimumNVDAVersion" : "2018.2.0",
"addon_minimumNVDAVersion" : "2018.3.0",
# Last NVDA version supported/tested (e.g. "2018.4.0", ideally more recent than minimum version)
"addon_lastTestedNVDAVersion" : "2019.2.0",
"addon_lastTestedNVDAVersion" : "2019.3.0",
# Add-on update channel (default is stable or None)
"addon_updateChannel" : None,
}
Expand Down

0 comments on commit d6e94c3

Please sign in to comment.