SpeechSynthesis.java: expose the different voice options from eSpeak

This makes the following changes:

1.  setVoice takes a Voice object instead of a language string.

    This is to make the API cleaner and allows SpeechSynthesis
    to pass the correct parameter (identifier for SetVoiceByName,
    or name for SetVoiceByProperties) to espeak.

2.  The espeak_SetVoiceByName API is also exposed to support passing
    the voice variant to use.

3.  The age parameter has been re-added with the constants:
    *  SpeechSynthesis.AGE_ANY
    *  SpeechSynthesis.AGE_YOUNG
    *  SpeechSynthesis.AGE_OLD
    based on the behaviour of the eSpeak voice selection algorithm.

NOTE: Due to the way that voice selection is implemented in eSpeak,
if variant is specified, the age and gender cannot be specified and
vice versa.
This commit is contained in:
Reece H. Dunn
2013-05-02 18:06:41 +01:00
parent 88eab88d8a
commit cc72825682
3 changed files with 41 additions and 7 deletions
+25 -3
View File
@@ -241,16 +241,38 @@ JNICALL Java_com_reecedunn_espeak_SpeechSynthesis_nativeGetAvailableVoices(
}
JNIEXPORT jboolean
JNICALL Java_com_reecedunn_espeak_SpeechSynthesis_nativeSetVoice(
JNIEnv *env, jobject object, jstring language, jint gender) {
JNICALL Java_com_reecedunn_espeak_SpeechSynthesis_nativeSetVoiceByName(
JNIEnv *env, jobject object, jstring name) {
const char *c_name = name ? env->GetStringUTFChars(name, NULL) : NULL;
if (DEBUG) LOGV("%s(name=%s)", __FUNCTION__, c_name);
const espeak_ERROR result = espeak_SetVoiceByName(c_name);
if (c_name) env->ReleaseStringUTFChars(name, c_name);
switch (result) {
case EE_OK: return JNI_TRUE;
case EE_INTERNAL_ERROR: LOGE("espeak_SetVoiceByName: internal error."); break;
case EE_BUFFER_FULL: LOGE("espeak_SetVoiceByName: buffer full."); break;
case EE_NOT_FOUND: LOGE("espeak_SetVoiceByName: not found."); break;
}
return JNI_FALSE;
}
JNIEXPORT jboolean
JNICALL Java_com_reecedunn_espeak_SpeechSynthesis_nativeSetVoiceByProperties(
JNIEnv *env, jobject object, jstring language, jint gender, jint age) {
const char *c_language = language ? env->GetStringUTFChars(language, NULL) : NULL;
if (DEBUG) LOGV("%s(language=%s, gender=%d)", __FUNCTION__, c_language, gender);
if (DEBUG) LOGV("%s(language=%s, gender=%d, age=%d)", __FUNCTION__, c_language, gender, age);
espeak_VOICE voice_select;
memset(&voice_select, 0, sizeof(espeak_VOICE));
voice_select.languages = c_language;
voice_select.gender = (int) gender;
voice_select.age = (int) age;
const espeak_ERROR result = espeak_SetVoiceByProperties(&voice_select);
@@ -45,6 +45,10 @@ public class SpeechSynthesis {
public static final int GENDER_MALE = 1;
public static final int GENDER_FEMALE = 2;
public static final int AGE_ANY = 0;
public static final int AGE_YOUNG = 12;
public static final int AGE_OLD = 60;
static {
System.loadLibrary("ttsespeak");
@@ -169,8 +173,14 @@ public class SpeechSynthesis {
return voices;
}
public void setVoice(String language, int gender) {
nativeSetVoice(language, gender);
public void setVoice(Voice voice, String variant, int gender, int age) {
// NOTE: espeak_SetVoiceByProperties does not support specifying the
// voice variant (e.g. klatt), but espeak_SetVoiceByName does.
if (variant == null) {
nativeSetVoiceByProperties(voice.name, gender, age);
} else {
nativeSetVoiceByName(voice.identifier + "+" + variant);
}
}
public void setRate(int rate) {
@@ -300,7 +310,9 @@ public class SpeechSynthesis {
private native final String[] nativeGetAvailableVoices();
private native final boolean nativeSetVoice(String language, int gender);
private native final boolean nativeSetVoiceByName(String name);
private native final boolean nativeSetVoiceByProperties(String language, int gender, int age);
private native final boolean nativeSetRate(int rate);
@@ -221,7 +221,7 @@ public class TtsService extends TextToSpeechService {
mCallback.start(mEngine.getSampleRate(), mEngine.getAudioFormat(),
mEngine.getChannelCount());
mEngine.setVoice(mMatchingVoice.name, gender);
mEngine.setVoice(mMatchingVoice, null, gender, SpeechSynthesis.AGE_ANY);
mEngine.setRate(rate);
mEngine.setPitch(pitch);
mEngine.synthesize(text, text.startsWith("<speak"));