Browse Source

Convert eSpeakService.cpp to C so it can be compiled with clang's -std=c11 flag.

master
Reece H. Dunn 8 years ago
parent
commit
e4e572aadc
2 changed files with 58 additions and 74 deletions
  1. 1
    1
      android/jni/Android.mk
  2. 57
    73
      android/jni/jni/eSpeakService.c

+ 1
- 1
android/jni/Android.mk View File

# JNI # JNI


LOCAL_SRC_FILES += \ LOCAL_SRC_FILES += \
$(subst $(LOCAL_PATH)/jni,jni,$(wildcard $(LOCAL_PATH)/jni/*.c*))
$(subst $(LOCAL_PATH)/jni,jni,$(wildcard $(LOCAL_PATH)/jni/*.c))


# Common # Common



android/jni/jni/eSpeakService.cpp → android/jni/jni/eSpeakService.c View File

/* /*
* Copyright (C) 2012-2015 Reece H. Dunn
* Copyright (C) 2012-2017 Reece H. Dunn
* Copyright (C) 2011 Google Inc. * Copyright (C) 2011 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h>
#include <jni.h> #include <jni.h>


#include <speak_lib.h>
#include <espeak/speak_lib.h>
#include <Log.h> #include <Log.h>


#define BUFFER_SIZE_IN_MILLISECONDS 1000 #define BUFFER_SIZE_IN_MILLISECONDS 1000


/** @name Java to Wide String Helpers
* @brief These are helpers for converting a jstring to wchar_t*.
*
* This assumes that wchar_t is a 32-bit (UTF-32) value.
*/
/* These are helpers for converting a jstring to wchar_t*.
*
* This assumes that wchar_t is a 32-bit (UTF-32) value.
*/
//@{ //@{


const char *utf8_read(const char *in, wchar_t &c)
static const char *utf8_read(const char *in, wchar_t *c)
{ {
if (uint8_t(*in) < 0x80)
c = *in++;
else switch (uint8_t(*in) & 0xF0)
if (((uint8_t)*in) < 0x80)
*c = *in++;
else switch (((uint8_t)*in) & 0xF0)
{ {
default: default:
c = uint8_t(*in++) & 0x1F;
c = (c << 6) + (uint8_t(*in++) & 0x3F);
*c = ((uint8_t)*in++) & 0x1F;
*c = (*c << 6) + (((uint8_t)*in++) & 0x3F);
break; break;
case 0xE0: case 0xE0:
c = uint8_t(*in++) & 0x0F;
c = (c << 6) + (uint8_t(*in++) & 0x3F);
c = (c << 6) + (uint8_t(*in++) & 0x3F);
*c = ((uint8_t)*in++) & 0x0F;
*c = (*c << 6) + (((uint8_t)*in++) & 0x3F);
*c = (*c << 6) + (((uint8_t)*in++) & 0x3F);
break; break;
case 0xF0: case 0xF0:
c = uint8_t(*in++) & 0x07;
c = (c << 6) + (uint8_t(*in++) & 0x3F);
c = (c << 6) + (uint8_t(*in++) & 0x3F);
c = (c << 6) + (uint8_t(*in++) & 0x3F);
*c = ((uint8_t)*in++) & 0x07;
*c = (*c << 6) + (((uint8_t)*in++) & 0x3F);
*c = (*c << 6) + (((uint8_t)*in++) & 0x3F);
*c = (*c << 6) + (((uint8_t)*in++) & 0x3F);
break; break;
} }
return in; return in;
} }


class unicode_string
{
static_assert(sizeof(wchar_t) == 4, "wchar_t is not UTF-32");
public:
unicode_string(JNIEnv *env, jstring str);
~unicode_string();

const wchar_t *c_str() const { return mString; }
private:
wchar_t *mString;
};

unicode_string::unicode_string(JNIEnv *env, jstring str)
: mString(NULL)
static wchar_t *unicode_string(JNIEnv *env, jstring str)
{ {
if (str == NULL) return;
if (str == NULL) return NULL;


const char *utf8 = env->GetStringUTFChars(str, NULL);
mString = (wchar_t *)malloc((strlen(utf8) + 1) * sizeof(wchar_t));
const char *utf8 = (*env)->GetStringUTFChars(env, str, NULL);
wchar_t *utf32 = (wchar_t *)malloc((strlen(utf8) + 1) * sizeof(wchar_t));


const char *utf8_current = utf8; const char *utf8_current = utf8;
wchar_t *utf32_current = mString;
wchar_t *utf32_current = utf32;
while (*utf8_current) while (*utf8_current)
{ {
utf8_current = utf8_read(utf8_current, *utf32_current);
utf8_current = utf8_read(utf8_current, utf32_current);
++utf32_current; ++utf32_current;
} }
*utf32_current = 0; *utf32_current = 0;


env->ReleaseStringUTFChars(str, utf8);
}

unicode_string::~unicode_string()
{
if (mString) free(mString);
(*env)->ReleaseStringUTFChars(env, str, utf8);
return utf32;
} }


//@} //@}


static JNIEnv *getJniEnv() { static JNIEnv *getJniEnv() {
JNIEnv *env = NULL; JNIEnv *env = NULL;
jvm->AttachCurrentThread(&env, NULL);
(*jvm)->AttachCurrentThread(jvm, &env, NULL);
return env; return env;
} }


jobject object = (jobject)events->user_data; jobject object = (jobject)events->user_data;


if (numSamples < 1) { if (numSamples < 1) {
env->CallVoidMethod(object, METHOD_nativeSynthCallback, NULL);
(*env)->CallVoidMethod(env, object, METHOD_nativeSynthCallback, NULL);
return SYNTH_ABORT; return SYNTH_ABORT;
} else { } else {
jbyteArray arrayAudioData = env->NewByteArray(numSamples * 2);
env->SetByteArrayRegion(arrayAudioData, 0, (numSamples * 2), (jbyte *) audioData);
env->CallVoidMethod(object, METHOD_nativeSynthCallback, arrayAudioData);
jbyteArray arrayAudioData = (*env)->NewByteArray(env, numSamples * 2);
(*env)->SetByteArrayRegion(env, arrayAudioData, 0, (numSamples * 2), (jbyte *) audioData);
(*env)->CallVoidMethod(env, object, METHOD_nativeSynthCallback, arrayAudioData);
return SYNTH_CONTINUE; return SYNTH_CONTINUE;
} }
} }
jvm = vm; jvm = vm;
JNIEnv *env; JNIEnv *env;


if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_6) != JNI_OK) {
LOGE("Failed to get the environment using GetEnv()"); LOGE("Failed to get the environment using GetEnv()");
return -1; return -1;
} }
JNICALL Java_com_reecedunn_espeak_SpeechSynthesis_nativeClassInit( JNICALL Java_com_reecedunn_espeak_SpeechSynthesis_nativeClassInit(
JNIEnv* env, jclass clazz) { JNIEnv* env, jclass clazz) {
if (DEBUG) LOGV("%s", __FUNCTION__); if (DEBUG) LOGV("%s", __FUNCTION__);
METHOD_nativeSynthCallback = env->GetMethodID(clazz, "nativeSynthCallback", "([B)V");
METHOD_nativeSynthCallback = (*env)->GetMethodID(env, clazz, "nativeSynthCallback", "([B)V");


return JNI_TRUE; return JNI_TRUE;
} }
JNIEnv *env, jobject object, jstring path) { JNIEnv *env, jobject object, jstring path) {
if (DEBUG) LOGV("%s [env=%p, object=%p]", __FUNCTION__, env, object); if (DEBUG) LOGV("%s [env=%p, object=%p]", __FUNCTION__, env, object);


const char *c_path = path ? env->GetStringUTFChars(path, NULL) : NULL;
const char *c_path = path ? (*env)->GetStringUTFChars(env, path, NULL) : NULL;


if (DEBUG) LOGV("Initializing with path %s", c_path); if (DEBUG) LOGV("Initializing with path %s", c_path);
int sampleRate = espeak_Initialize(AUDIO_OUTPUT_SYNCHRONOUS, BUFFER_SIZE_IN_MILLISECONDS, c_path, 0); int sampleRate = espeak_Initialize(AUDIO_OUTPUT_SYNCHRONOUS, BUFFER_SIZE_IN_MILLISECONDS, c_path, 0);


if (c_path) env->ReleaseStringUTFChars(path, c_path);
if (c_path) (*env)->ReleaseStringUTFChars(env, path, c_path);


return sampleRate; return sampleRate;
} }
JNICALL Java_com_reecedunn_espeak_SpeechSynthesis_nativeGetVersion( JNICALL Java_com_reecedunn_espeak_SpeechSynthesis_nativeGetVersion(
JNIEnv *env, jclass clazz) { JNIEnv *env, jclass clazz) {
if (DEBUG) LOGV("%s", __FUNCTION__); if (DEBUG) LOGV("%s", __FUNCTION__);
return env->NewStringUTF(espeak_Info(NULL));
return (*env)->NewStringUTF(env, espeak_Info(NULL));
} }


JNIEXPORT jobjectArray JNIEXPORT jobjectArray
for (count = 0; voices[count] != NULL; count++); for (count = 0; voices[count] != NULL; count++);


// Next, create a Java String array. // Next, create a Java String array.
jobjectArray voicesArray = (jobjectArray) env->NewObjectArray(
count * 4, env->FindClass("java/lang/String"), NULL);
jobjectArray voicesArray = (jobjectArray) (*env)->NewObjectArray(
env, count * 4, (*env)->FindClass(env, "java/lang/String"), NULL);


const espeak_VOICE *v; const espeak_VOICE *v;
char gender_buf[12]; char gender_buf[12];
sprintf(gender_buf, "%d", v->gender); sprintf(gender_buf, "%d", v->gender);
sprintf(age_buf, "%d", v->age); sprintf(age_buf, "%d", v->age);


env->SetObjectArrayElement(
voicesArray, voicesIndex++, env->NewStringUTF(lang_name));
env->SetObjectArrayElement(
voicesArray, voicesIndex++, env->NewStringUTF(identifier));
env->SetObjectArrayElement(
voicesArray, voicesIndex++, env->NewStringUTF(gender_buf));
env->SetObjectArrayElement(
voicesArray, voicesIndex++, env->NewStringUTF(age_buf));
(*env)->SetObjectArrayElement(
env, voicesArray, voicesIndex++, (*env)->NewStringUTF(env, lang_name));
(*env)->SetObjectArrayElement(
env, voicesArray, voicesIndex++, (*env)->NewStringUTF(env, identifier));
(*env)->SetObjectArrayElement(
env, voicesArray, voicesIndex++, (*env)->NewStringUTF(env, gender_buf));
(*env)->SetObjectArrayElement(
env, voicesArray, voicesIndex++, (*env)->NewStringUTF(env, age_buf));
} }


return voicesArray; return voicesArray;
JNIEXPORT jboolean JNIEXPORT jboolean
JNICALL Java_com_reecedunn_espeak_SpeechSynthesis_nativeSetVoiceByName( JNICALL Java_com_reecedunn_espeak_SpeechSynthesis_nativeSetVoiceByName(
JNIEnv *env, jobject object, jstring name) { JNIEnv *env, jobject object, jstring name) {
const char *c_name = name ? env->GetStringUTFChars(name, NULL) : NULL;
const char *c_name = name ? (*env)->GetStringUTFChars(env, name, NULL) : NULL;


if (DEBUG) LOGV("%s(name=%s)", __FUNCTION__, c_name); if (DEBUG) LOGV("%s(name=%s)", __FUNCTION__, c_name);


const espeak_ERROR result = espeak_SetVoiceByName(c_name); const espeak_ERROR result = espeak_SetVoiceByName(c_name);


if (c_name) env->ReleaseStringUTFChars(name, c_name);
if (c_name) (*env)->ReleaseStringUTFChars(env, name, c_name);


switch (result) { switch (result) {
case EE_OK: return JNI_TRUE; case EE_OK: return JNI_TRUE;
JNIEXPORT jboolean JNIEXPORT jboolean
JNICALL Java_com_reecedunn_espeak_SpeechSynthesis_nativeSetVoiceByProperties( JNICALL Java_com_reecedunn_espeak_SpeechSynthesis_nativeSetVoiceByProperties(
JNIEnv *env, jobject object, jstring language, jint gender, jint age) { JNIEnv *env, jobject object, jstring language, jint gender, jint age) {
const char *c_language = language ? env->GetStringUTFChars(language, NULL) : NULL;
const char *c_language = language ? (*env)->GetStringUTFChars(env, language, NULL) : NULL;


if (DEBUG) LOGV("%s(language=%s, gender=%d, age=%d)", __FUNCTION__, c_language, gender, age); if (DEBUG) LOGV("%s(language=%s, gender=%d, age=%d)", __FUNCTION__, c_language, gender, age);




const espeak_ERROR result = espeak_SetVoiceByProperties(&voice_select); const espeak_ERROR result = espeak_SetVoiceByProperties(&voice_select);


if (c_language) env->ReleaseStringUTFChars(language, c_language);
if (c_language) (*env)->ReleaseStringUTFChars(env, language, c_language);


switch (result) { switch (result) {
case EE_OK: return JNI_TRUE; case EE_OK: return JNI_TRUE;
JNIEnv *env, jobject object, jstring characters) { JNIEnv *env, jobject object, jstring characters) {
if (DEBUG) LOGV("%s)", __FUNCTION__); if (DEBUG) LOGV("%s)", __FUNCTION__);


unicode_string list(env, characters);
const espeak_ERROR result = espeak_SetPunctuationList(list.c_str());
wchar_t *list = unicode_string(env, characters);
const espeak_ERROR result = espeak_SetPunctuationList(list);
free(list);
switch (result) { switch (result) {
case EE_OK: return JNI_TRUE; case EE_OK: return JNI_TRUE;
case EE_INTERNAL_ERROR: LOGE("espeak_SetPunctuationList: internal error."); break; case EE_INTERNAL_ERROR: LOGE("espeak_SetPunctuationList: internal error."); break;
JNICALL Java_com_reecedunn_espeak_SpeechSynthesis_nativeSynthesize( JNICALL Java_com_reecedunn_espeak_SpeechSynthesis_nativeSynthesize(
JNIEnv *env, jobject object, jstring text, jboolean isSsml) { JNIEnv *env, jobject object, jstring text, jboolean isSsml) {
if (DEBUG) LOGV("%s", __FUNCTION__); if (DEBUG) LOGV("%s", __FUNCTION__);
const char *c_text = text ? env->GetStringUTFChars(text, NULL) : NULL;
const char *c_text = text ? (*env)->GetStringUTFChars(env, text, NULL) : NULL;
unsigned int unique_identifier; unsigned int unique_identifier;


espeak_SetSynthCallback(SynthCallback); espeak_SetSynthCallback(SynthCallback);
&unique_identifier, object); &unique_identifier, object);
espeak_Synchronize(); espeak_Synchronize();


if (c_text) env->ReleaseStringUTFChars(text, c_text);
if (c_text) (*env)->ReleaseStringUTFChars(env, text, c_text);


switch (result) { switch (result) {
case EE_OK: return JNI_TRUE; case EE_OK: return JNI_TRUE;

Loading…
Cancel
Save