[309599] setGender and related code
diff --git a/plugins/org.eclipse.actf.ai.tts.msp/src/org/eclipse/actf/ai/tts/msp/engine/MspVoice.java b/plugins/org.eclipse.actf.ai.tts.msp/src/org/eclipse/actf/ai/tts/msp/engine/MspVoice.java
index 733c2e1..4fec6d8 100644
--- a/plugins/org.eclipse.actf.ai.tts.msp/src/org/eclipse/actf/ai/tts/msp/engine/MspVoice.java
+++ b/plugins/org.eclipse.actf.ai.tts.msp/src/org/eclipse/actf/ai/tts/msp/engine/MspVoice.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2008 IBM Corporation and Others
+ * Copyright (c) 2007, 2012 IBM Corporation and Others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -49,6 +49,8 @@
.getPreferenceStore();
private boolean isDisposed = false;
+ private SpObjectToken curVoiceToken = null;
+
public MspVoice() {
int pv = COMUtil.createDispatch(ISpVoice.IID);
dispSpVoice = new ISpVoice(pv);
@@ -66,7 +68,7 @@
setAudioOutputName();
// switch to actual engine
preferenceStore.setValue(ID, orgID);
- // setVoiceName();
+ setVoiceName(); //for init curVoiceToken
// to avoid access violation error at application shutdown
stop();
@@ -168,8 +170,12 @@
* @return The invocation is succeeded then it returns true.
*/
public boolean setVoice(Variant varVoice) {
- return OLE.S_OK == dispSpVoice.put_Voice(varVoice.getDispatch()
- .getAddress());
+ boolean result = OLE.S_OK == dispSpVoice.put_Voice(varVoice
+ .getDispatch().getAddress());
+ if (result) {
+ curVoiceToken = SpObjectToken.getToken(varVoice);
+ }
+ return result;
}
/**
@@ -359,15 +365,48 @@
* @see org.eclipse.actf.ai.tts.ITTSEngine#setLanguage(java.lang.String)
*/
public void setLanguage(String language) {
- String token;
- if (LANG_JAPANESE.equals(language)) {
- token = "language=411"; //$NON-NLS-1$
- } else if (LANG_ENGLISH.equals(language)) {
- token = "language=409;9"; //$NON-NLS-1$
+ String gender = null;
+ if (curVoiceToken != null) {
+ gender = curVoiceToken.getAttribute("gender");
+ }
+
+ if (gender == null) {
+ gender = "";
} else {
+ gender = "gender=" + gender;
+ }
+
+ String langId = LANGID_MAP.get(language);
+ if (langId == null) {
+ // for backward compatibility
+ if (LANG_JAPANESE.equals(language)) {
+ langId = "411"; //$NON-NLS-1$
+ } else if (LANG_ENGLISH.equals(language)) {
+ langId = "409"; //old value "409;9" //$NON-NLS-1$
+ }
+ // TODO other lang
+ }
+ if (langId == null) {
return;
}
- setVoiceName(token);
+ String lang = "language=" + langId + ";";
+
+ // try to keep original gender
+ Variant varVoices = getVoices(lang + gender, null);
+ if (varVoices == null && gender.length() > 0) {
+ varVoices = getVoices(lang, null); // try all
+ }
+ if (varVoices != null) {
+ SpeechObjectTokens tokens = SpeechObjectTokens.getTokens(varVoices);
+ if (null != tokens && 0 < tokens.getCount()) {
+ // TODO priority
+ Variant varVoice = tokens.getItem(0);
+ if (null != varVoice) {
+ setVoice(varVoice);
+ }
+ }
+ varVoices.dispose();
+ }
}
/*
@@ -376,11 +415,33 @@
* @see org.eclipse.actf.ai.tts.ITTSEngine#setGender(java.lang.String)
*/
public void setGender(String gender) {
- // TODO
+ String langId = null;
+ if (curVoiceToken != null) {
+ langId = curVoiceToken.getAttribute("language");
+ if ("409;9".equals(langId)) {
+ langId = "409";
+ }
+ }
+ Variant varVoices = null;
+ String lang = "";
+ if (langId != null) {
+ lang = "language=" + langId + ";";
+ }
if (GENDER_MALE.equalsIgnoreCase(gender)) {
- // setVoiceName("name=Microsoft Mike");
+ varVoices = getVoices(lang + "gender=Male", null);
} else if (GENDER_FEMALE.equalsIgnoreCase(gender)) {
- // setVoiceName("name=Microsoft Mary");
+ varVoices = getVoices(lang + "gender=Female", null);
+ }
+ if (null != varVoices) {
+ SpeechObjectTokens tokens = SpeechObjectTokens.getTokens(varVoices);
+ if (null != tokens && 0 < tokens.getCount()) {
+ // TODO priority
+ Variant varVoice = tokens.getItem(0);
+ if (null != varVoice) {
+ setVoice(varVoice);
+ }
+ }
+ varVoices.dispose();
}
}
@@ -452,7 +513,7 @@
autoSpFileStream = null;
}
}
- setAudioOutputName(); //reset output
+ setAudioOutputName(); // reset output
return speakToFileResult;
}
}
diff --git a/plugins/org.eclipse.actf.ai.tts.msp/src/org/eclipse/actf/ai/tts/msp/engine/SpObjectToken.java b/plugins/org.eclipse.actf.ai.tts.msp/src/org/eclipse/actf/ai/tts/msp/engine/SpObjectToken.java
index 5402f12..b8fb580 100644
--- a/plugins/org.eclipse.actf.ai.tts.msp/src/org/eclipse/actf/ai/tts/msp/engine/SpObjectToken.java
+++ b/plugins/org.eclipse.actf.ai.tts.msp/src/org/eclipse/actf/ai/tts/msp/engine/SpObjectToken.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007 IBM Corporation and Others
+ * Copyright (c) 2007, 2012 IBM Corporation and Others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,6 +7,7 @@
*
* Contributors:
* Takashi ITOH - initial API and implementation
+ * Kentarou FUKUDA - initial API and implementation
*******************************************************************************/
package org.eclipse.actf.ai.tts.msp.engine;
@@ -23,10 +24,12 @@
private OleAutomation automation;
private int idGetDescription;
+ private int idGetAttribute;
public SpObjectToken(Variant varToken) {
automation = varToken.getAutomation();
idGetDescription = getIDsOfNames("GetDescription"); //$NON-NLS-1$
+ idGetAttribute = getIDsOfNames("GetAttribute"); //$NON-NLS-1$
}
public static SpObjectToken getToken(Variant varToken) {
@@ -38,8 +41,19 @@
public String getDescription(int locale) {
try {
- return automation.invoke(idGetDescription,
- new Variant[] { new Variant(locale) }).getString().trim();
+ return automation
+ .invoke(idGetDescription,
+ new Variant[] { new Variant(locale) }).getString()
+ .trim();
+ } catch (Exception e) {
+ }
+ return null;
+ }
+
+ public String getAttribute(String attr) {
+ try {
+ return automation.invoke(idGetAttribute,
+ new Variant[] { new Variant(attr) }).getString();
} catch (Exception e) {
}
return null;
diff --git a/plugins/org.eclipse.actf.ai.tts.sapi/plugin.properties b/plugins/org.eclipse.actf.ai.tts.sapi/plugin.properties
index add5a93..da23982 100644
--- a/plugins/org.eclipse.actf.ai.tts.sapi/plugin.properties
+++ b/plugins/org.eclipse.actf.ai.tts.sapi/plugin.properties
@@ -1,5 +1,5 @@
###############################################################################
-# Copyright (c) 2007 IBM Corporation and others.
+# Copyright (c) 2007, 2012 IBM Corporation and others.
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
# which accompanies this distribution, and is available at
@@ -9,4 +9,4 @@
# IBM Corporation - initial API and implementation
###############################################################################
SapiPreferencePage.name=SAPI 5
-voice.exclude=AcTF On-Screen TTS
\ No newline at end of file
+voice.exclude=Sample TTS Voice
\ No newline at end of file
diff --git a/plugins/org.eclipse.actf.ai.tts.sapi/src/org/eclipse/actf/ai/tts/sapi/engine/SapiVoice.java b/plugins/org.eclipse.actf.ai.tts.sapi/src/org/eclipse/actf/ai/tts/sapi/engine/SapiVoice.java
index c35e4fb..ccab2e4 100644
--- a/plugins/org.eclipse.actf.ai.tts.sapi/src/org/eclipse/actf/ai/tts/sapi/engine/SapiVoice.java
+++ b/plugins/org.eclipse.actf.ai.tts.sapi/src/org/eclipse/actf/ai/tts/sapi/engine/SapiVoice.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2008 IBM Corporation and Others
+ * Copyright (c) 2007, 2012 IBM Corporation and Others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -12,6 +12,10 @@
package org.eclipse.actf.ai.tts.sapi.engine;
import java.io.File;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeSet;
import org.eclipse.actf.ai.tts.ISAPIEngine;
import org.eclipse.actf.ai.tts.sapi.SAPIPlugin;
@@ -19,6 +23,7 @@
import org.eclipse.actf.util.win32.COMUtil;
import org.eclipse.actf.util.win32.MemoryUtil;
import org.eclipse.actf.util.win32.NativeIntAccess;
+import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
@@ -49,6 +54,22 @@
.getPreferenceStore();
private boolean isDisposed = false;
+ private SpObjectToken curVoiceToken = null;
+
+ private class EngineInfo {
+ String name;
+ String langId;
+ String gender;
+
+ public EngineInfo(String name, String langId, String gender) {
+ this.name = name;
+ this.langId = langId;
+ this.gender = gender;
+ }
+ }
+
+ private Map<String, TreeSet<EngineInfo>> langId2EngineMap = new HashMap<String, TreeSet<EngineInfo>>();
+
public SapiVoice() {
int pv = COMUtil.createDispatch(ISpVoice.IID);
dispSpVoice = new ISpVoice(pv);
@@ -66,7 +87,53 @@
setAudioOutputName();
// switch to actual engine
preferenceStore.setValue(ID, orgID);
- // setVoiceName();
+ setVoiceName(); // for init curVoiceToken
+
+ Variant varVoices = getVoices(null, null);
+ if (null != varVoices) {
+ SpeechObjectTokens voiceTokens = SpeechObjectTokens
+ .getTokens(varVoices);
+ if (null != voiceTokens) {
+ String exclude = Platform.getResourceString(SAPIPlugin
+ .getDefault().getBundle(), "%voice.exclude"); //$NON-NLS-1$
+ int count = voiceTokens.getCount();
+ for (int i = 0; i < count; i++) {
+ Variant varVoice = voiceTokens.getItem(i);
+ if (null != varVoice) {
+ SpObjectToken token = SpObjectToken.getToken(varVoice);
+ if (null != token) {
+ String voiceName = token.getDescription(0);
+ String langId = token.getAttribute("language"); //$NON-NLS-1$
+ if ("409;9".equals(langId)) {
+ langId = "409";
+ }
+ String gender = token.getAttribute("gender"); //$NON-NLS-1$
+ if (null == exclude || !exclude.equals(voiceName)) {
+ TreeSet<EngineInfo> set = langId2EngineMap
+ .get(langId);
+ if (set == null) {
+ set = new TreeSet<SapiVoice.EngineInfo>(
+ new Comparator<EngineInfo>() {
+ @Override
+ public int compare(
+ EngineInfo o1,
+ EngineInfo o2) {
+ // TODO priority
+ return -o1.name
+ .compareTo(o2.name);
+ }
+ });
+ langId2EngineMap.put(langId, set);
+ }
+ set.add(new EngineInfo(voiceName, langId,
+ gender));
+ }
+ }
+ }
+ }
+ }
+ varVoices.dispose();
+ }
// to avoid access violation error at application shutdown
stop();
@@ -168,8 +235,12 @@
* @return The invocation is succeeded then it returns true.
*/
public boolean setVoice(Variant varVoice) {
- return OLE.S_OK == dispSpVoice.put_Voice(varVoice.getDispatch()
- .getAddress());
+ boolean result = OLE.S_OK == dispSpVoice.put_Voice(varVoice
+ .getDispatch().getAddress());
+ if (result) {
+ curVoiceToken = SpObjectToken.getToken(varVoice);
+ }
+ return result;
}
/**
@@ -359,15 +430,43 @@
* @see org.eclipse.actf.ai.tts.ITTSEngine#setLanguage(java.lang.String)
*/
public void setLanguage(String language) {
- String token;
- if (LANG_JAPANESE.equals(language)) {
- token = "language=411"; //$NON-NLS-1$
- } else if (LANG_ENGLISH.equals(language)) {
- token = "language=409;9"; //$NON-NLS-1$
- } else {
+ String gender = null;
+ if (curVoiceToken != null) {
+ gender = curVoiceToken.getAttribute("gender");
+ }
+
+ String langId = LANGID_MAP.get(language);
+ if (langId == null) {
+ // for backward compatibility
+ if (LANG_JAPANESE.equals(language)) {
+ langId = "411"; //$NON-NLS-1$
+ } else if (LANG_ENGLISH.equals(language)) {
+ langId = "409"; //old value "409;9" //$NON-NLS-1$
+ }
+ // TODO other lang
+ }
+ if (langId == null) {
return;
}
- setVoiceName(token);
+
+ // Workaround:
+ // In some cases, getVoices("language=***",null) doesn't work well.
+ // So, get all voices first. Then select lang and gender.
+
+ TreeSet<EngineInfo> set = langId2EngineMap.get(langId);
+ if (set != null && set.size() > 0) {
+ if (gender != null) {
+ for (EngineInfo i : set) {
+ if (gender.equalsIgnoreCase(i.gender)) {
+ setVoiceName("name=" + i.name);
+ // System.out.println(i.name);
+ return;
+ }
+ }
+ }
+ setVoiceName("name=" + set.first().name);
+ // System.out.println(set.first().name);
+ }
}
/*
@@ -376,12 +475,28 @@
* @see org.eclipse.actf.ai.tts.ITTSEngine#setGender(java.lang.String)
*/
public void setGender(String gender) {
- // TODO
- if (GENDER_MALE.equalsIgnoreCase(gender)) {
- setVoiceName("name=Microsoft Mike");
- } else if (GENDER_FEMALE.equalsIgnoreCase(gender)) {
- setVoiceName("name=Microsoft Mary");
+ if (gender == null) {
+ return;
}
+ String langId = null;
+ if (curVoiceToken != null) {
+ langId = curVoiceToken.getAttribute("language");
+ if ("409;9".equals(langId)) {
+ langId = "409";
+ }
+ }
+
+ TreeSet<EngineInfo> set = langId2EngineMap.get(langId);
+ if (set != null && set.size() > 0) {
+ for (EngineInfo i : set) {
+ if (gender.equalsIgnoreCase(i.gender)) {
+ setVoiceName("name=" + i.name);
+ // System.out.println(i.name);
+ return;
+ }
+ }
+ }
+
}
/*
@@ -452,7 +567,8 @@
autoSpFileStream = null;
}
}
- setAudioOutputName(); //reset output
+ setAudioOutputName(); // reset output
return speakToFileResult;
}
+
}
diff --git a/plugins/org.eclipse.actf.ai.tts.sapi/src/org/eclipse/actf/ai/tts/sapi/engine/SpObjectToken.java b/plugins/org.eclipse.actf.ai.tts.sapi/src/org/eclipse/actf/ai/tts/sapi/engine/SpObjectToken.java
index 4737740..f904a04 100644
--- a/plugins/org.eclipse.actf.ai.tts.sapi/src/org/eclipse/actf/ai/tts/sapi/engine/SpObjectToken.java
+++ b/plugins/org.eclipse.actf.ai.tts.sapi/src/org/eclipse/actf/ai/tts/sapi/engine/SpObjectToken.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007 IBM Corporation and Others
+ * Copyright (c) 2007, 2012 IBM Corporation and Others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,6 +7,7 @@
*
* Contributors:
* Takashi ITOH - initial API and implementation
+ * Kentarou FUKUDA - initial API and implementation
*******************************************************************************/
package org.eclipse.actf.ai.tts.sapi.engine;
@@ -23,10 +24,12 @@
private OleAutomation automation;
private int idGetDescription;
+ private int idGetAttribute;
public SpObjectToken(Variant varToken) {
automation = varToken.getAutomation();
idGetDescription = getIDsOfNames("GetDescription"); //$NON-NLS-1$
+ idGetAttribute = getIDsOfNames("GetAttribute"); //$NON-NLS-1$
}
public static SpObjectToken getToken(Variant varToken) {
@@ -38,8 +41,19 @@
public String getDescription(int locale) {
try {
- return automation.invoke(idGetDescription,
- new Variant[] { new Variant(locale) }).getString().trim();
+ return automation
+ .invoke(idGetDescription,
+ new Variant[] { new Variant(locale) }).getString()
+ .trim();
+ } catch (Exception e) {
+ }
+ return null;
+ }
+
+ public String getAttribute(String attr) {
+ try {
+ return automation.invoke(idGetAttribute,
+ new Variant[] { new Variant(attr) }).getString();
} catch (Exception e) {
}
return null;
diff --git a/plugins/org.eclipse.actf.ai.voice/src/org/eclipse/actf/ai/tts/ISAPIEngine.java b/plugins/org.eclipse.actf.ai.voice/src/org/eclipse/actf/ai/tts/ISAPIEngine.java
index 7ac30a3..a918872 100644
--- a/plugins/org.eclipse.actf.ai.voice/src/org/eclipse/actf/ai/tts/ISAPIEngine.java
+++ b/plugins/org.eclipse.actf.ai.voice/src/org/eclipse/actf/ai/tts/ISAPIEngine.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2008 IBM Corporation and Others
+ * Copyright (c) 2008, 2012 IBM Corporation and Others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -10,6 +10,9 @@
*******************************************************************************/
package org.eclipse.actf.ai.tts;
+import java.util.HashMap;
+import java.util.Map;
+
/**
* ISAPIEngine interface defines text synthesis interface to be
@@ -22,6 +25,113 @@
SVSFPurgeBeforeSpeak = 2, SVSFIsFilename = 4, SVSFIsXML = 8,
SVSFIsNotXML = 16, SVSFPersistXML = 32;
+
+ /**
+ * Map to get LangId from "Language"-"Country" code (e.g., en-US).
+ */
+ public static final Map<String, String> LANGID_MAP = new HashMap<String, String>() {
+ private static final long serialVersionUID = 8393339647554273101L;
+ {
+ put("ar-SA", "401");
+ put("bg-BG", "402");
+ put("ca-ES", "403");
+ put("zh-TW", "404");
+ put("cs-CZ", "405");
+ put("da-DK", "406");
+ put("de-DE", "407");
+ put("el-GR", "408");
+ put("en-US", "409");
+ put("fi-FI", "40B");
+ put("fr-FR", "40C");
+ put("he-IL", "40D");
+ put("hu-HU", "40E");
+ put("it-IT", "410");
+ put("ja-JP", "411");
+ put("ko-KR", "412");
+ put("nl-NL", "413");
+ put("nb-NO", "414");
+ put("pl-PL", "415");
+ put("pt-BR", "416");
+ put("ro-RO", "418");
+ put("ru-RU", "419");
+ put("hr-HR", "41A");
+ put("sk-SK", "41B");
+ put("sv-SE", "41D");
+ put("th-TH", "41E");
+ put("tr-TR", "41F");
+ put("uk-UA", "422");
+ put("sl-SI", "424");
+ put("et-EE", "425");
+ put("lv-LV", "426");
+ put("lt-LT", "427");
+ put("vi-VN", "42A");
+ put("eu-ES", "42D");
+ put("zh-CN", "804");
+ put("pt-PT", "816");
+ put("sr-CS", "81A");
+ put("es-ES", "C0A");
+ put("en-AU", "C09");
+ put("en-CA", "1009");
+ put("en-GB", "809");
+ put("en-IN", "4009");
+ put("fr-CA", "C0C");
+ put("zh-HK", "C04");
+ }
+ };
+
+ /**
+ * Map to get "Language"-"Country" code (e.g., en-US) from LangId.
+ */
+ public static final Map<String, String> LANGID_REVERSE_MAP = new HashMap<String, String>() {
+ private static final long serialVersionUID = -4065510530588377900L;
+ {
+ put("401","ar-SA");
+ put("402","bg-BG");
+ put("403","ca-ES");
+ put("404","zh-TW");
+ put("405","cs-CZ");
+ put("406","da-DK");
+ put("407","de-DE");
+ put("408","el-GR");
+ put("409","en-US");
+ put("40B","fi-FI");
+ put("40C","fr-FR");
+ put("40D","he-IL");
+ put("40E","hu-HU");
+ put("410","it-IT");
+ put("411","ja-JP");
+ put("412","ko-KR");
+ put("413","nl-NL");
+ put("414","nb-NO");
+ put("415","pl-PL");
+ put("416","pt-BR");
+ put("418","ro-RO");
+ put("419","ru-RU");
+ put("41A","hr-HR");
+ put("41B","sk-SK");
+ put("41D","sv-SE");
+ put("41E","th-TH");
+ put("41F","tr-TR");
+ put("422","uk-UA");
+ put("424","sl-SI");
+ put("425","et-EE");
+ put("426","lv-LV");
+ put("427","lt-LT");
+ put("42A","vi-VN");
+ put("42D","eu-ES");
+ put("804","zh-CN");
+ put("816","pt-PT");
+ put("81A","sr-CS");
+ put("C0A","es-ES");
+ put("C09","en-AU");
+ put("1009","en-CA");
+ put("809","en-GB");
+ put("4009","en-IN");
+ put("C0C","fr-CA");
+ put("C04","zh-HK");
+ }
+ };
+
/**
* @param rate
* The rate property to be set.