Skip to content

Commit 556f199

Browse files
version 4.6
Many works has done to prevent fatal error in using various SAPI 5 voices. Furthermore, now if any fatal error occure in speaking the dual voice will change the synthesizer to espeak.
1 parent 295d6f8 commit 556f199

File tree

9 files changed

+152
-124
lines changed

9 files changed

+152
-124
lines changed

addon/globalPlugins/dual_voice_globalPlugin/__init__.py

+10-13
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
1-
# https://github.com/Mahmood-Taghavi
1+
# -*- coding: UTF-8 -*-
2+
#A part of Dual Voice for NVDA
3+
#Copyright (C) 2015-2020 Seyed Mahmood Taghavi Shahri
4+
#https://mahmood-taghavi.github.io/dual_voice/
5+
#This file is covered by the GNU General Public License version 3.
6+
#See the file COPYING for more details.
27

38
import globalPluginHandler, wx, gui
49
from .dialogs import *
510
import webbrowser
11+
import addonHandler
12+
addonHandler.initTranslation()
613
import config
7-
8-
confspec = {
9-
"sapi5SecondVoice": "string(default='')",
10-
"sapi5SecondRate": "integer(default=50)",
11-
"sapi5SecondPitch": "integer(default=50)",
12-
"sapi5SecondVolume": "integer(default=100)",
13-
"sapi5SecondIsLatin": "boolean(default=False)",
14-
"sapi5NonLatinPriority": "boolean(default=False)",
15-
"sapi5ConsiderContext": "boolean(default=False)",
16-
}
17-
config.conf.spec["dual_voice"] = confspec
14+
from synthDrivers import _realtime
1815

1916
class GlobalPlugin (globalPluginHandler.GlobalPlugin):
2017
def __init__(self):
@@ -32,7 +29,7 @@ def createMenu(self):
3229
self.submenu_item = gui.mainFrame.sysTrayIcon.menu.InsertMenu(2, wx.ID_ANY, _("Dual &voice"), self.submenu_dualvoice)
3330

3431
def onAbout(self, event):
35-
gui.messageBox("Version 4.5 by Seyed Mahmood Taghavi-Shahri", _("About the Dual voice add-on for NVDA"), wx.OK)
32+
gui.messageBox("Version 4.6 by Seyed Mahmood Taghavi-Shahri", _("About the Dual voice add-on for NVDA"), wx.OK)
3633

3734

3835
def onCheckUpdate(self, event):
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
# https://github.com/Mahmood-Taghavi
1+
# -*- coding: UTF-8 -*-
2+
#A part of Dual Voice for NVDA
3+
#Copyright (C) 2015-2020 Seyed Mahmood Taghavi Shahri
4+
#https://mahmood-taghavi.github.io/dual_voice/
5+
#This file is covered by the GNU General Public License version 3.
6+
#See the file COPYING for more details.
27

3-
#from collections import defaultdict
48
import wx
59
import gui
6-
#import addonHandler
7-
#addonHandler.initTranslation()
10+
import addonHandler
11+
addonHandler.initTranslation()
812
import config
913

1014
#import languageHandler
@@ -15,32 +19,9 @@
1519

1620
class DualVoiceLanguageSettingsDialog(gui.SettingsDialog):
1721
title = _('The "Dual Voice" settings')
18-
_tempSecondVoice = ''
19-
_tempSecondRate = 50
20-
_tempSecondPitch = 50
21-
_tempSecondVolume = 100
22-
_tempSecondIsLatin = False
23-
_tempNonLatinPriority = False
24-
_tempConsiderContext = False
2522
def __init__(self, parent):
2623
super(DualVoiceLanguageSettingsDialog, self).__init__(parent)
27-
global _tempSecondVoice
28-
global _tempSecondRate
29-
global _tempSecondPitch
30-
global _tempSecondVolume
31-
global _tempSecondIsLatin
32-
global _tempNonLatinPriority
33-
global _tempConsiderContext
3424
#_realtime.typingArea = "Alaki"
35-
if ("dual_sapi5" in speech.getSynth().name):
36-
#config.conf["dual_voice"]["tempSecondVoice"] = config.conf["dual_voice"]["sapi5SecondVoice"]
37-
_tempSecondVoice = config.conf["dual_voice"]["sapi5SecondVoice"]
38-
_tempSecondRate = config.conf["dual_voice"]["sapi5SecondRate"]
39-
_tempSecondPitch = config.conf["dual_voice"]["sapi5SecondPitch"]
40-
_tempSecondVolume = config.conf["dual_voice"]["sapi5SecondVolume"]
41-
_tempSecondIsLatin = config.conf["dual_voice"]["sapi5SecondIsLatin"]
42-
_tempNonLatinPriority = config.conf["dual_voice"]["sapi5NonLatinPriority"]
43-
_tempConsiderContext = config.conf["dual_voice"]["sapi5ConsiderContext"]
4425

4526
def makeSettings(self, sizer):
4627
synthInfo = _('Your current speech synthesizer is the %. Please select the Dual Voice as the speech synthesizer in the NVDA speech settings.')
@@ -51,14 +32,10 @@ def makeSettings(self, sizer):
5132
else:
5233
## find the primary voice and show it in a label
5334
try:
54-
primaryVoiceID = config.conf["speech"]["dual_sapi5"]["voice"]
55-
index = _realtime.list_VoiceID.index(primaryVoiceID)
35+
index = _realtime.list_VoiceID.index(_realtime.primaryVoiceID)
5636
voiceName = _realtime.list_VoiceName[index]
5737
except:
58-
config.conf["speech"]["dual_sapi5"]["voice"] = _realtime.list_VoiceID[0]
59-
primaryVoiceID = config.conf["speech"]["dual_sapi5"]["voice"]
60-
index = _realtime.list_VoiceID.index(primaryVoiceID)
61-
voiceName = _realtime.list_VoiceName[index]
38+
voiceName = 'a voice without the required name attribute'
6239
voiceInfo = _('You have selected % as the primary voice.')
6340
voiceInfo = voiceInfo.replace('%', voiceName)
6441
infoLabel = wx.StaticText(self, label = voiceInfo)
@@ -70,15 +47,15 @@ def makeSettings(self, sizer):
7047
sizer.Add(sVoicesLabel)
7148
self._sVoicesChoice = wx.Choice(self, choices = _realtime.list_VoiceName)
7249
if ("dual_sapi5" in speech.getSynth().name):
73-
check = config.conf["dual_voice"]["sapi5SecondVoice"] in _realtime.list_VoiceAttribName
50+
check = _realtime.sapi5SecondVoice in _realtime.list_VoiceAttribName
7451
if check:
75-
index = _realtime.list_VoiceAttribName.index(config.conf["dual_voice"]["sapi5SecondVoice"])
52+
index = _realtime.list_VoiceAttribName.index(_realtime.sapi5SecondVoice)
7653
self._sVoicesChoice.SetSelection(index)
7754
else:
7855
#self._sVoicesChoice.SetSelection(0)
79-
check = config.conf["speech"]["dual_sapi5"]["voice"] in _realtime.list_VoiceID
56+
check = _realtime.primaryVoiceID in _realtime.list_VoiceID
8057
if check:
81-
index = _realtime.list_VoiceID.index(config.conf["speech"]["dual_sapi5"]["voice"])
58+
index = _realtime.list_VoiceID.index(_realtime.primaryVoiceID)
8259
self._sVoicesChoice.SetSelection(index)
8360
else:
8461
self._sVoicesChoice.SetSelection(0)
@@ -87,7 +64,7 @@ def makeSettings(self, sizer):
8764
##
8865
self._secondIsLatinCheckBox = wx.CheckBox(self, label = _("&Use the secondary voice for reading Latin text instead of non-Latin."))
8966
if ("dual_sapi5" in speech.getSynth().name):
90-
self._secondIsLatinCheckBox.SetValue(config.conf["dual_voice"]["sapi5SecondIsLatin"])
67+
self._secondIsLatinCheckBox.SetValue(_realtime.sapi5SecondIsLatin)
9168
self._secondIsLatinCheckBox.Bind(wx.EVT_CHECKBOX, self.onSIsLatinCheck)
9269
sizer.Add(self._secondIsLatinCheckBox)
9370
##
@@ -96,33 +73,33 @@ def makeSettings(self, sizer):
9673
self._sRateSlider = wx.Slider(self, value = 50, minValue = 0, maxValue = 100, style = wx.SL_HORIZONTAL)
9774
self._sRateSlider.Bind(wx.EVT_SLIDER, self.OnSRateSliderScroll)
9875
if ("dual_sapi5" in speech.getSynth().name):
99-
self._sRateSlider.SetValue(config.conf["dual_voice"]["sapi5SecondRate"])
76+
self._sRateSlider.SetValue(_realtime.sapi5SecondRate)
10077
sizer.Add(self._sRateSlider)
10178
##
10279
sPitchLabel = wx.StaticText(self, label=_("&Pitch:"))
10380
sizer.Add(sPitchLabel)
10481
self._sPitchSlider = wx.Slider(self, value = 50, minValue = 0, maxValue = 100, style = wx.SL_HORIZONTAL)
10582
self._sPitchSlider.Bind(wx.EVT_SLIDER, self.OnSPitchSliderScroll)
10683
if ("dual_sapi5" in speech.getSynth().name):
107-
self._sPitchSlider.SetValue(config.conf["dual_voice"]["sapi5SecondPitch"])
84+
self._sPitchSlider.SetValue(_realtime.sapi5SecondPitch)
10885
sizer.Add(self._sPitchSlider)
10986
##
11087
sVolumeLabel = wx.StaticText(self, label=_("V&olume:"))
11188
sizer.Add(sVolumeLabel)
11289
self._sVolumeSlider = wx.Slider(self, value = 100, minValue = 0, maxValue = 100, style = wx.SL_HORIZONTAL)
11390
self._sVolumeSlider.Bind(wx.EVT_SLIDER, self.OnSVolumeSliderScroll)
11491
if ("dual_sapi5" in speech.getSynth().name):
115-
self._sVolumeSlider.SetValue(config.conf["dual_voice"]["sapi5SecondVolume"])
92+
self._sVolumeSlider.SetValue(_realtime.sapi5SecondVolume)
11693
sizer.Add(self._sVolumeSlider)
11794
##
11895
self._nonLatinPriorityCheckBox = wx.CheckBox(self, label = _("&Prioritize non-Latin text over Latin text."))
11996
if ("dual_sapi5" in speech.getSynth().name):
120-
self._nonLatinPriorityCheckBox.SetValue(config.conf["dual_voice"]["sapi5NonLatinPriority"])
97+
self._nonLatinPriorityCheckBox.SetValue(_realtime.sapi5NonLatinPriority)
12198
self._nonLatinPriorityCheckBox.Bind(wx.EVT_CHECKBOX, self.nonLatinPriorityCheck)
12299
sizer.Add(self._nonLatinPriorityCheckBox)
123-
self._considerContextCheckBox = wx.CheckBox(self, label = _("Read &numbers and punctuations based on context."))
100+
self._considerContextCheckBox = wx.CheckBox(self, label = _("Read &numbers and punctuations based on their context."))
124101
if ("dual_sapi5" in speech.getSynth().name):
125-
self._considerContextCheckBox.SetValue(config.conf["dual_voice"]["sapi5ConsiderContext"])
102+
self._considerContextCheckBox.SetValue(_realtime.sapi5ConsiderContext)
126103
self._considerContextCheckBox.Bind(wx.EVT_CHECKBOX, self.considerContextCheck)
127104
sizer.Add(self._considerContextCheckBox)
128105
##
@@ -154,45 +131,54 @@ def onOk(self, event):
154131
# Update Configurations
155132
if ("dual_sapi5" in speech.getSynth().name):
156133
_realtime.typingArea = self._typingAreaTextCtrl.GetValue()
134+
config.conf["dual_voice"]["sapi5SecondVoice"] = _realtime.sapi5SecondVoice
135+
config.conf["dual_voice"]["sapi5SecondRate"] = _realtime.sapi5SecondRate
136+
config.conf["dual_voice"]["sapi5SecondPitch"] = _realtime.sapi5SecondPitch
137+
config.conf["dual_voice"]["sapi5SecondVolume"] = _realtime.sapi5SecondVolume
138+
config.conf["dual_voice"]["sapi5SecondIsLatin"] = _realtime.sapi5SecondIsLatin
139+
config.conf["dual_voice"]["sapi5NonLatinPriority"] = _realtime.sapi5NonLatinPriority
140+
config.conf["dual_voice"]["sapi5ConsiderContext"] = _realtime.sapi5ConsiderContext
141+
157142
return super(DualVoiceLanguageSettingsDialog, self).onOk(event)
158143

159144
def onCancel(self, event):
160145
# Restore Configurations
161146
if ("dual_sapi5" in speech.getSynth().name):
162-
config.conf["dual_voice"]["sapi5SecondVoice"] = _tempSecondVoice
163-
config.conf["dual_voice"]["sapi5SecondRate"] = _tempSecondRate
164-
config.conf["dual_voice"]["sapi5SecondPitch"] = _tempSecondPitch
165-
config.conf["dual_voice"]["sapi5SecondVolume"] = _tempSecondVolume
166-
config.conf["dual_voice"]["sapi5SecondIsLatin"] = _tempSecondIsLatin
167-
config.conf["dual_voice"]["sapi5NonLatinPriority"] = _tempNonLatinPriority
168-
config.conf["dual_voice"]["sapi5ConsiderContext"] = _tempConsiderContext
147+
_realtime.sapi5SecondVoice = config.conf["dual_voice"]["sapi5SecondVoice"]
148+
_realtime.sapi5SecondRate = config.conf["dual_voice"]["sapi5SecondRate"]
149+
_realtime.sapi5SecondPitch = config.conf["dual_voice"]["sapi5SecondPitch"]
150+
_realtime.sapi5SecondVolume = config.conf["dual_voice"]["sapi5SecondVolume"]
151+
_realtime.sapi5SecondIsLatin = config.conf["dual_voice"]["sapi5SecondIsLatin"]
152+
_realtime.sapi5NonLatinPriority = config.conf["dual_voice"]["sapi5NonLatinPriority"]
153+
_realtime.sapi5ConsiderContext = config.conf["dual_voice"]["sapi5ConsiderContext"]
169154
return super(DualVoiceLanguageSettingsDialog, self).onCancel(event)
170155

171156

172157
def onSVoiceChange(self, event):
173158
if ("dual_sapi5" in speech.getSynth().name):
174-
config.conf["dual_voice"]["sapi5SecondVoice"] = _realtime.list_VoiceAttribName[self._sVoicesChoice.GetSelection()]
159+
_realtime.sapi5SecondVoice = _realtime.list_VoiceAttribName[self._sVoicesChoice.GetSelection()]
160+
_realtime.problemisticSapi5SecondVoice = ''
175161

176162
def OnSRateSliderScroll(self, event):
177163
if ("dual_sapi5" in speech.getSynth().name):
178-
config.conf["dual_voice"]["sapi5SecondRate"] = self._sRateSlider.GetValue()
164+
_realtime.sapi5SecondRate = self._sRateSlider.GetValue()
179165

180166
def OnSPitchSliderScroll(self, event):
181167
if ("dual_sapi5" in speech.getSynth().name):
182-
config.conf["dual_voice"]["sapi5SecondPitch"] = self._sPitchSlider.GetValue()
168+
_realtime.sapi5SecondPitch = self._sPitchSlider.GetValue()
183169

184170
def OnSVolumeSliderScroll(self, event):
185171
if ("dual_sapi5" in speech.getSynth().name):
186-
config.conf["dual_voice"]["sapi5SecondVolume"] = self._sVolumeSlider.GetValue()
172+
_realtime.sapi5SecondVolume = self._sVolumeSlider.GetValue()
187173

188174
def onSIsLatinCheck(self, event):
189175
if ("dual_sapi5" in speech.getSynth().name):
190-
config.conf["dual_voice"]["sapi5SecondIsLatin"] = self._secondIsLatinCheckBox.GetValue()
176+
_realtime.sapi5SecondIsLatin = self._secondIsLatinCheckBox.GetValue()
191177

192178
def nonLatinPriorityCheck(self, event):
193179
if ("dual_sapi5" in speech.getSynth().name):
194-
config.conf["dual_voice"]["sapi5NonLatinPriority"] = self._nonLatinPriorityCheckBox.GetValue()
180+
_realtime.sapi5NonLatinPriority = self._nonLatinPriorityCheckBox.GetValue()
195181

196182
def considerContextCheck(self, event):
197183
if ("dual_sapi5" in speech.getSynth().name):
198-
config.conf["dual_voice"]["sapi5ConsiderContext"] = self._considerContextCheckBox.GetValue()
184+
_realtime.sapi5ConsiderContext = self._considerContextCheckBox.GetValue()

addon/synthDrivers/_dual_sapi5.py

+16-18
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,31 @@
1-
# -*- coding: utf-8 -*-
2-
# Dual voice Add-on for NVDA.
3-
# Copyright (C) 2015 Seyed Mahmood Taghavi-Shahri.
4-
# This file is covered by the GNU General Public License.
5-
# This code initially developed for Persian (Farsi) language.
6-
# Release: 2015-01-31 Version: 3.0
7-
# Project homepage: http://dualvoice.sf.net
8-
# This file contain functions for natural language processing.
9-
import config
1+
# -*- coding: UTF-8 -*-
2+
#A part of Dual Voice for NVDA
3+
#Copyright (C) 2015-2020 Seyed Mahmood Taghavi Shahri
4+
#https://mahmood-taghavi.github.io/dual_voice/
5+
#This file is covered by the GNU General Public License version 3.
6+
#See the file COPYING for more details.
7+
8+
#import config
109
from synthDrivers import _realtime
1110
from . import _dualvoice
1211

1312
def nlp(text):
14-
SecondVoice = config.conf["dual_voice"]["sapi5SecondVoice"]
13+
SecondVoice = _realtime.sapi5SecondVoice
1514
if SecondVoice=="":
16-
primaryVoiceID = config.conf["speech"]["dual_sapi5"]["voice"]
17-
index = _realtime.list_VoiceID.index(primaryVoiceID)
15+
index = _realtime.list_VoiceID.index(_realtime.primaryVoiceID)
1816
voiceAttribName = _realtime.list_VoiceAttribName[index]
1917
SecondVoice = voiceAttribName # use the name attribute value of the primary voice as the secondary voice name.
20-
SecondVolume = str(config.conf["dual_voice"]["sapi5SecondVolume"])
21-
SecondRate = str(round((config.conf["dual_voice"]["sapi5SecondRate"]-50)/5))
22-
SecondPitch = str(round((config.conf["dual_voice"]["sapi5SecondPitch"]-50)/5))
23-
latinPriority = (config.conf["dual_voice"]["sapi5NonLatinPriority"]==False)
24-
considerContext = config.conf["dual_voice"]["sapi5ConsiderContext"]
18+
SecondVolume = str(_realtime.sapi5SecondVolume)
19+
SecondRate = str(round((_realtime.sapi5SecondRate-50)/5))
20+
SecondPitch = str(round((_realtime.sapi5SecondPitch-50)/5))
21+
latinPriority = (_realtime.sapi5NonLatinPriority==False)
22+
considerContext = _realtime.sapi5ConsiderContext
2523
nonLatinStartTag = ' <voice required="Name=' + SecondVoice + '"> <volume level="' + SecondVolume + '"> <rate absspeed="' + SecondRate + '"> <pitch absmiddle="' + SecondPitch + '"> '
2624
nonLatinEndTag = ' </pitch> </rate> </volume> </voice> '
2725
FirstVolume = str(_realtime.sapi5FirstVolume)
2826
LatinStartTag = '<volume level="' + FirstVolume + '">'
2927
LatinEndTag = '</volume>'
30-
if config.conf["dual_voice"]["sapi5SecondIsLatin"] == False:
28+
if _realtime.sapi5SecondIsLatin == False:
3129
return _dualvoice.nlp(text,latinPriority,considerContext,nonLatinStartTag,nonLatinEndTag,LatinStartTag,LatinEndTag)
3230
else:
3331
return _dualvoice.nlp(text,latinPriority,considerContext,LatinStartTag,LatinEndTag,nonLatinStartTag,nonLatinEndTag)

addon/synthDrivers/_dualvoice.py

+6-8
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
# -*- coding: utf-8 -*-
2-
# Dual voice Add-on for NVDA.
3-
# Copyright (C) 2015 Seyed Mahmood Taghavi-Shahri.
4-
# This file is covered by the GNU General Public License.
5-
# This code initially developed for Persian (Farsi) language.
6-
# Release: 2015-01-31 Version: 3.0
7-
# Project homepage: http://dualvoice.sf.net
8-
# This file contain functions for natural language processing.
1+
# -*- coding: UTF-8 -*-
2+
#A part of Dual Voice for NVDA
3+
#Copyright (C) 2015-2020 Seyed Mahmood Taghavi Shahri
4+
#https://mahmood-taghavi.github.io/dual_voice/
5+
#This file is covered by the GNU General Public License version 3.
6+
#See the file COPYING for more details.
97

108
def charactertype(character):
119
character.encode('utf-8')

addon/synthDrivers/_realtime.py

+17-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,24 @@
1-
# https://github.com/Mahmood-Taghavi
1+
# -*- coding: UTF-8 -*-
2+
#A part of Dual Voice for NVDA
3+
#Copyright (C) 2015-2020 Seyed Mahmood Taghavi Shahri
4+
#https://mahmood-taghavi.github.io/dual_voice/
5+
#This file is covered by the GNU General Public License version 3.
6+
#See the file COPYING for more details.
7+
28
typingArea = "You can type here to check the voices"
39
list_VoiceAttribName = []
410
list_VoiceID = []
511
list_VoiceName = []
612
list_VoiceLang = []
713
sapi5FirstVolume = 100
814
tempStringVar = ''
15+
sapi5SecondVoice = ''
16+
sapi5SecondRate = 50
17+
sapi5SecondPitch = 50
18+
sapi5SecondVolume = 100
19+
sapi5SecondIsLatin = False
20+
sapi5NonLatinPriority = False
21+
sapi5ConsiderContext = False
22+
primaryVoiceID = ''
23+
problemisticSapi5SecondVoice = ''
24+
problemisticPrimaryVoiceID = ''

0 commit comments

Comments
 (0)