---
servers/espeak | 72 +++++--------
servers/linux-espeak/tclespeak.cpp | 200 +++++++++++++++++++------------------
2 files changed, 129 insertions(+), 143 deletions(-)
diff --git a/servers/espeak b/servers/espeak
index c339fb7..53881b2 100755
--- a/servers/espeak
+++ b/servers/espeak
@@ -44,10 +44,7 @@ source $wd/tts-lib.tcl
# Language switching
#
-# langsynth: available languages of the voice synthesis
-# This variable is set by atcleci
-# For example: langsynth(0)=3
-# 3 is the atcleci code for the finnish language
+# langsynth: current and max index into table of synth languages.
# langsynth(current): current synthesis language,
# Gives the code of the current synth language.
@@ -59,21 +56,19 @@ source $wd/tts-lib.tcl
# For example, if there are three available languages:
# langsynth(top)=2
-# langlabel: what will be announced
-# e.g. langlabel(0)="finnish"
+# voicename: name of the current voice for announcements
# This variable is set by tclespeak
# langcode: language identifier
# e.g. langcode(0)="fi"
# This variable is set by tclespeak
-# langalias converts a code language ("en", "en_GB",...) to its index in the langsynth array.
+# langalias converts a code language ("en", "en_GB",...) to its index in the language table.
# e.g. langalias(fi)=3 could mean "fi_FI" will be used if "fi" is required.
-set langsynth(0) 0
set langsynth(current) 0
set langsynth(top) 0
-set langlabel(0) "english"
+set voicename "default"
set langcode(0) "en-uk"
set langcode(current) "en-uk"
set mswindows [expr { $tcl_platform(platform) == "windows" } ]
@@ -82,31 +77,29 @@ set mswindows [expr { $tcl_platform(platform) == "windows" } ]
proc set_next_lang {say_it} {
global langsynth
global langalias
- global langlabel
+ global voicename
global langcode
- set langsynthkey 0
set index 0
while { $index <= $langsynth(top) } {
- if { $langsynth($index) == $langsynth(current) } {
- set langsynthkey $index
+ if { $index == $langsynth(current) } {
break
}
incr index
}
- if { $langsynthkey >= $langsynth(top) } {
- set langsynthkey 0
+ if { $index >= $langsynth(top) } {
+ set index 0
} else {
- incr langsynthkey
+ incr index
}
- set langsynth(current) $langsynth($langsynthkey)
- set langcode(current) $langcode($langsynthkey)
+ set langsynth(current) $index
+ set langcode(current) $langcode($index)
setLanguage $langsynth(current)
if { [info exists say_it]} {
- tts_say "$langlabel($langsynthkey) "
+ tts_say "$voicename"
}
}
@@ -114,30 +107,28 @@ proc set_next_lang {say_it} {
proc set_previous_lang {say_it} {
global langsynth
global langalias
- global langlabel
+ global voicename
global langcode
- set langsynthkey 0
set index 0
while { $index <= $langsynth(top) } {
- if { $langsynth($index) == $langsynth(current) } {
- set langsynthkey $index
+ if { $index == $langsynth(current) } {
break
}
incr index
}
- if { $langsynthkey <= 0 } {
- set langsynthkey $langsynth(top)
+ if { $index <= 0 } {
+ set index $langsynth(top)
} else {
- incr langsynthkey -1
+ incr index -1
}
- set langsynth(current) $langsynth($langsynthkey)
- set langcode(current) $langcode($langsynthkey)
+ set langsynth(current) $index
+ set langcode(current) $langcode($index)
setLanguage $langsynth(current)
if { [info exists say_it]} {
- tts_say "$langlabel($langsynthkey) "
+ tts_say "$voicename "
}
}
@@ -147,7 +138,7 @@ proc set_lang {{name "en"} {say_it "nil"}} {
global langsynth
global langalias
global langcode
-global langlabel
+global voicename
if { ![info exists langalias($name)]} {
return
}
@@ -157,21 +148,11 @@ global langlabel
}
set langsynth(current) $langalias($name)
- set langcode(current) $langcode($langsynthkey)
+ set langcode(current) $langcode($langalias($name))
setLanguage $langsynth(current)
- set langsynthkey 0
- set index 0
- while { $index <= $langsynth(top) } {
- if { $langsynth($index) == $langsynth(current) } {
- set langsynthkey $index
- break
- }
- incr index
- }
-
if { $say_it == "t"} {
- tts_say "$langlabel($langsynthkey) "
+ tts_say "$voicename"
}
}
@@ -188,8 +169,8 @@ proc set_preferred_lang {alias lang} {
#debug
proc list_lang {} {
- global langsynth
- echo [ array get langsynth ]
+ global langcode
+ echo [ array get langcode ]
}
proc list_langalias {} {
@@ -238,7 +219,6 @@ proc tts_set_character_scale {factor} {
proc tts_say {text} {
global tts
global langcode
- global langsynth
service
set la $langcode(current)
@@ -253,7 +233,6 @@ proc tts_say {text} {
proc l {text} {
global tts
global langcode
- global langsynth
set la $langcode(current)
set prefix "<voice xml:lang=\"$la\" gender=\"male\" variant=\"1\">"
@@ -462,7 +441,6 @@ proc service {} {
proc speech_task {} {
global queue tts
global langcode
- global langsynth
set tts(talking?) 1
set tts(not_stopped) 1
diff --git a/servers/linux-espeak/tclespeak.cpp b/servers/linux-espeak/tclespeak.cpp
index e67b07f..9943633 100644
--- a/servers/linux-espeak/tclespeak.cpp
+++ b/servers/linux-espeak/tclespeak.cpp
@@ -48,8 +48,12 @@
#define ESPEAK_API_REVISION 1
#endif
+#include <set>
#include <string>
+#include <vector>
+using std::set;
using std::string;
+using std::vector;
#define PACKAGENAME "tts"
#define PACKAGEVERSION "1.0"
@@ -76,50 +80,7 @@ int Pause(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST[]);
int Resume(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST[]);
static void initLanguage(Tcl_Interp *interp);
-static int getLangIndex(Tcl_Interp *interp, int *theIndex);
-
-//>
-//< preferred languages
-
-// Uncomment below your preferred languages
-
-static const char *ThePreferredLanguages[] = {
- // "af", // afrikaans
- // "cs", // czech-test
- // "cy", // welsh-test
- // "de", // german
- // "el", // greek_test
- // "en-r", // en-rhotic
- // "en-sc", // en-scottish
- "en-uk", // english
- // "en-uk-north", // lancashire
- // "en-uk-rp", // english_rp
- // "en-uk-wmids", // english_wmids
- // "eo", // esperanto
- // "es", // spanish
- // "fi" // finnish
- "fr", // french-test
- // "fr-ca", // quebec-test
- // "hi", // hindi-test
- // "hu", // hungarian
- // "it", // italian
- // "nl", // dutch-test
- // "no", // norwegian-test
- // "pl", // polish_test
- // "pt", // brazil
- // "pt-pt", // portugal
- // "ro", // romanian
- // "ro", // romanian-mbrola
- // "ru", // russian_test
- // "sk", // slovak-test
- // "sv", // swedish-test
- // "sw", // swahihi-test
- // "vi", // vietnam-test
- // "zh", // cantonese-test
-};
-
-#define MaxPreferredLang \
- (int)(sizeof(ThePreferredLanguages) / sizeof(ThePreferredLanguages[0]))
+static int getLangIndex(Tcl_Interp *interp, unsigned long *theIndex);
//>
//<TclEspeakFree
@@ -465,16 +426,27 @@ int getTTSVersion(ClientData handle, Tcl_Interp *interp, int objc,
//>
//<SetLanguage
+static vector<string> available_languages;
+
+static void SetLanguageHelper(Tcl_Interp *interp, size_t aIndex) {
+ espeak_VOICE *current_voice = NULL;
+ espeak_VOICE a_voice;
+ memset(&a_voice, 0, sizeof(espeak_VOICE));
+ a_voice.languages = (char *)available_languages[aIndex].c_str();
+ a_voice.gender = 1;
+ espeak_SetVoiceByProperties(&a_voice);
+ current_voice = espeak_GetCurrentVoice();
+ Tcl_SetVar(interp, "voicename", current_voice->name, 0);
+ // But what if we couldn't set the voice? Need some better error handling.
+ return;
+}
+
int SetLanguage(ClientData eciHandle, Tcl_Interp *interp, int objc,
Tcl_Obj *CONST objv[]) {
- int aIndex = 0;
+ unsigned long aIndex = 0;
if (getLangIndex(interp, &aIndex)) {
- espeak_VOICE a_voice;
- memset(&a_voice, 0, sizeof(espeak_VOICE));
- a_voice.languages = (char *)(ThePreferredLanguages[aIndex]);
- a_voice.gender = 1;
- espeak_SetVoiceByProperties(&a_voice);
+ SetLanguageHelper(interp, aIndex);
}
return TCL_OK;
}
@@ -482,71 +454,107 @@ int SetLanguage(ClientData eciHandle, Tcl_Interp *interp, int objc,
//>
//<initLanguage, getLangIndex
+static vector<string> ParseLanguages(const char *lang_str) {
+ vector<string> voice_langs;
+ const char *p = lang_str;
+ // The languages string is a string of (priority-byte, language-name)
+ // pairs. Each language name ends with a NUL byte, and the whole string
+ // ends with a NUL. So in BNF:
+ // (priority-byte text NUL-byte)* NUL-byte
+ // We can ignore the priority byte for now. Revisit it later?
+ while(*p) {
+ voice_langs.push_back(string(p+1));
+ p += strlen(p + 1) + 2;
+ }
+ return voice_langs;
+}
+
static void initLanguage(Tcl_Interp *interp) {
// List the available languages
+ set<string> unique_languages;
int i = 0;
- int j = 0;
- char *aDefaultLang = (char *)getenv("LANGUAGE");
- if (aDefaultLang == NULL) {
- aDefaultLang = (char *)getenv("LANG");
- if (aDefaultLang == NULL) {
- aDefaultLang = (char *)"en";
+ unsigned long ui = 0;
+ char *envDefaultLang = (char *)getenv("LANGUAGE");
+ if (envDefaultLang == NULL) {
+ envDefaultLang = (char *)getenv("LANG");
+ if (envDefaultLang == NULL) {
+ envDefaultLang = (char *)"en";
}
}
+ string aDefaultLang = envDefaultLang;
+ size_t remove = aDefaultLang.find('.', 0);
- Tcl_SetVar2(interp, "langsynth", "current", "0", 0);
+ // Snip off everything following a period. So en-us.utf8 becomes en-us.
+ if (remove != string::npos) {
+ aDefaultLang.erase(aDefaultLang.begin() + remove, aDefaultLang.end());
+ }
+ // And replace _ with -, E.G. en_US becomes en-US.
+ for (string::iterator it = aDefaultLang.begin();
+ it != aDefaultLang.end(); it++) {
+ if (*it == '_') {
+ *it = '-';
+ }
+ }
const espeak_VOICE **voices = espeak_ListVoices(NULL);
- int langInfoMax = 0;
- for (i = 0; voices[i] != NULL; i++) {
- char buffer_i[3];
- snprintf(buffer_i, 3, "%d", i);
- Tcl_SetVar2(interp, "langalias", (char *)(voices[i]->languages), buffer_i,
- 0);
+ for (i = 0; voices[i] != 0; i++) {
+ vector<string> voice_langs = ParseLanguages(voices[i]->languages);
+ unique_languages.insert(voice_langs.begin(), voice_langs.end());
}
-
- langInfoMax = i;
-
- int aLang;
- for (aLang = 0; aLang < MaxPreferredLang; aLang++) {
- char buffer_i[3];
- char buffer_j[3];
-
- for (i = 0; i < langInfoMax; i++) {
- if (voices[i] && voices[i]->languages &&
- (strcmp(1 + voices[i]->languages, ThePreferredLanguages[aLang]) == 0))
- break;
+ available_languages.assign(unique_languages.begin(), unique_languages.end());
+ vector<string>::iterator it;
+ size_t lang_count = available_languages.size();
+ size_t english_index = lang_count;
+ size_t default_index = lang_count;
+ char buffer[256];
+ for (ui = 0; ui < lang_count; ui++) {
+ const char *aLangCode = available_languages[ui].c_str();
+ snprintf(buffer, sizeof(buffer), "%lu", ui);
+ Tcl_SetVar2(interp, "langalias", aLangCode, buffer, 0);
+ Tcl_SetVar2(interp, "langcode", buffer, aLangCode, 0);
+ if (default_index == lang_count) {
+ if (strcasecmp(aDefaultLang.c_str(), aLangCode) == 0) {
+ Tcl_SetVar2(interp, "langsynth", "current", buffer, 0);
+ Tcl_SetVar2(interp, "langcode", "current", (char *)aLangCode, 0);
+ default_index = ui;
+ }
}
-
- if (i == langInfoMax) {
- continue;
+ if (strcmp(aLangCode, "en") == 0) {
+ english_index = ui;
}
-
- const char *aLangCode = 1 + voices[i]->languages;
- snprintf(buffer_i, 3, "%d", aLang);
- snprintf(buffer_j, 3, "%d", j++);
- Tcl_SetVar2(interp, (char *)"langsynth", buffer_j, buffer_i, 0);
-
- if (strncmp(aDefaultLang, aLangCode, 2) == 0) {
- Tcl_SetVar2(interp, "langsynth", "current", buffer_i, 0);
- Tcl_SetVar2(interp, "langcode", "current", (char *)aLangCode, 0);
- }
-
- Tcl_SetVar2(interp, "langlabel", buffer_j, (char *)(voices[i]->name), 0);
- Tcl_SetVar2(interp, "langcode", buffer_j, (char *)aLangCode, 0);
- Tcl_SetVar2(interp, "langsynth", "top", buffer_j, 0);
}
+ if ((default_index == lang_count) && (english_index == lang_count)) {
+ fprintf(stderr, "Could not find your default language, and English\n");
+ fprintf(stderr, "doesn't seem to be available either. Bailing now.\n");
+ exit(1);
+ }
+ fprintf(stderr, "default_index %d\n", default_index);
+ if(default_index == lang_count) {
+ default_index = english_index;
+ fprintf(stderr, "Couldn't find your default language, using English.\n");
+ snprintf(buffer, sizeof(buffer), "%lu", english_index);
+ Tcl_SetVar2(interp, "langsynth", "current", buffer, 0);
+ Tcl_SetVar2(interp, "langcode", "current", "en", 0);
+ }
+ SetLanguageHelper(interp, default_index);
+ // Presumably we have at least one language, namely English,
+ // so no chance of underflowing size_t with this subtraction:
+ snprintf(buffer, sizeof(buffer), "%lu", lang_count - 1);
+ Tcl_SetVar2(interp, "langsynth", "top", buffer, 0);
}
-static int getLangIndex(Tcl_Interp *interp, int *theIndex) {
+static int getLangIndex(Tcl_Interp *interp, unsigned long *theIndex) {
int aStatus = 0;
const char *aInfo = Tcl_GetVar2(interp, "langsynth", "current", 0);
+ char *end = NULL;
if (aInfo) {
- *theIndex = atoi(aInfo);
+ *theIndex = strtoul(aInfo, &end, 10);
- if ((*theIndex > 0) && (*theIndex < MaxPreferredLang)) {
- aStatus = 1;
+ if (end && !*end) {
+ if ((*theIndex > 0) && (*theIndex < available_languages.size())) {
+ aStatus = 1;
+ }
}
}
return aStatus;
--
2.10.1
|All Past Years |Current Year|
If you have questions about this archive or had problems using it, please contact us.