Browse Source

Remove the Android 2.x/3.x support code.

The Android 4.x+ code has changed a lot since the initial import
of the eyes-free codebase. A lot of bug fixes and improvements
have been made to it.

The eyes-free codebase had two different code paths:
  *  one for ICS (4.0) or later, using the Java-based TTS APIs
     provided by the Android platform;
  *  one for pre-ICS using an internal C++-based TTS API.

Thus, any bug fixes or improvements would have to be done to both
code bases if Android 2.x/3.x support is required. This is not
maintainable.

If pre-ICS support is to be re-added in the future, the plan will
be to:
  *  forward the C++-based APIs to the Java-based APIs via a
     compatibility layer;
  *  use a compatibility layer (Android Support Library?) for using
     the ICS settings API on pre-ICS.
master
Reece H. Dunn 12 years ago
parent
commit
aebd02fa68

+ 0
- 55
android/AndroidManifest.xml View File

@@ -74,61 +74,6 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<!-- Legacy code for pre-ICS compatibility. -->
<activity
android:name=".eSpeak"
android:label="@string/app_name"
android:theme="@android:style/Theme.Translucent.NoTitleBar" >
<intent-filter>
<action android:name="android.intent.action.START_TTS_ENGINE" />

<category android:name="android.intent.category.tts_engine.ESPEAK" />
<category android:name="android.intent.category.tts_lang.afr" />
<category android:name="android.intent.category.tts_lang.bos" />
<category android:name="android.intent.category.tts_lang.zho" />
<category android:name="android.intent.category.tts_lang.cmn" />
<category android:name="android.intent.category.tts_lang.yue" />
<category android:name="android.intent.category.tts_lang.hrv" />
<category android:name="android.intent.category.tts_lang.ces" />
<category android:name="android.intent.category.tts_lang.nld" />
<category android:name="android.intent.category.tts_lang.eng" />
<category android:name="android.intent.category.tts_lang.eng.USA" />
<category android:name="android.intent.category.tts_lang.eng.GBR" />
<category android:name="android.intent.category.tts_lang.epo" />
<category android:name="android.intent.category.tts_lang.fin" />
<category android:name="android.intent.category.tts_lang.fra" />
<category android:name="android.intent.category.tts_lang.deu" />
<category android:name="android.intent.category.tts_lang.ell" />
<category android:name="android.intent.category.tts_lang.hin" />
<category android:name="android.intent.category.tts_lang.hun" />
<category android:name="android.intent.category.tts_lang.isl" />
<category android:name="android.intent.category.tts_lang.ind" />
<category android:name="android.intent.category.tts_lang.ita" />
<category android:name="android.intent.category.tts_lang.kur" />
<category android:name="android.intent.category.tts_lang.lat" />
<category android:name="android.intent.category.tts_lang.mkd" />
<category android:name="android.intent.category.tts_lang.nor" />
<category android:name="android.intent.category.tts_lang.pol" />
<category android:name="android.intent.category.tts_lang.por" />
<category android:name="android.intent.category.tts_lang.ron" />
<category android:name="android.intent.category.tts_lang.rus" />
<category android:name="android.intent.category.tts_lang.srp" />
<category android:name="android.intent.category.tts_lang.slk" />
<category android:name="android.intent.category.tts_lang.spa" />
<category android:name="android.intent.category.tts_lang.spa.MEX" />
<category android:name="android.intent.category.tts_lang.swa" />
<category android:name="android.intent.category.tts_lang.swe" />
<category android:name="android.intent.category.tts_lang.tam" />
<category android:name="android.intent.category.tts_lang.tur" />
<category android:name="android.intent.category.tts_lang.vie" />
<category android:name="android.intent.category.tts_lang.cym" />
</intent-filter>
</activity>

<provider
android:name="com.reecedunn.espeak.providers.SettingsProvider"
android:authorities="com.reecedunn.espeak.providers.SettingsProvider" />
</application>

</manifest>

+ 0
- 26
android/eSpeakTests/src/com/reecedunn/espeak/test/SpeechSynthesisTest.java View File

@@ -162,32 +162,6 @@ public class SpeechSynthesisTest extends TextToSpeechTestCase
return null;
}

/**
* This tests that the location of the espeak TTS shared object matches
* the location that Android 2.2 looks for it in.
*/
public void testSharedObjectLocation()
{
Intent intent = new Intent("android.intent.action.START_TTS_ENGINE");
intent.setPackage("com.reecedunn.espeak");
PackageManager pm = getContext().getPackageManager();
List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, 0);
assertThat(resolveInfos, is(notNullValue()));
assertThat(resolveInfos.isEmpty(), is(false));

ResolveInfo[] enginesArray = resolveInfos.toArray(new ResolveInfo[0]);
ActivityInfo aInfo = enginesArray[0].activityInfo;
String soFilename = aInfo.name.replace(aInfo.packageName + ".", "") + ".so";
soFilename = soFilename.toLowerCase();
assertThat(soFilename, is("espeak.so"));

soFilename = "/data/data/" + aInfo.packageName + "/lib/libtts" + soFilename;
assertThat(soFilename, is("/data/data/com.reecedunn.espeak/lib/libttsespeak.so"));

File f = new File(soFilename);
assertThat(f.exists(), is(true));
}

public void testConstruction()
{
final SpeechSynthesis synth = new SpeechSynthesis(getContext(), mCallback);

+ 0
- 245
android/jni/include/TtsEngine.h View File

@@ -1,245 +0,0 @@
/*
* Copyright (C) 2009 Google Inc.
* Copyright (C) 2012 Reece H. Dunn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/*
* This file contains the TtsEngine interface used by Android to implement
* Text-to-Speech services.
*
* Android Version: 2.2 (Froyo)
* API Version: 8
*/

#ifndef TTS_ENGINE_H_
#define TTS_ENGINE_H_

namespace android {

#define ANDROID_TTS_ENGINE_PROPERTY_CONFIG "engineConfig"
#define ANDROID_TTS_ENGINE_PROPERTY_PITCH "pitch"
#define ANDROID_TTS_ENGINE_PROPERTY_RATE "rate"
#define ANDROID_TTS_ENGINE_PROPERTY_VOLUME "volume"


enum tts_synth_status {
TTS_SYNTH_DONE = 0,
TTS_SYNTH_PENDING = 1
};

enum tts_callback_status {
TTS_CALLBACK_HALT = 0,
TTS_CALLBACK_CONTINUE = 1
};

// NOTE: This is duplicated in compat/jni/tts.h. Please
// make changes there as well.
enum tts_audio_format {
TTS_AUDIO_FORMAT_INVALID = -1,
TTS_AUDIO_FORMAT_DEFAULT = 0,
TTS_AUDIO_FORMAT_PCM_16_BIT = 1,
TTS_AUDIO_FORMAT_PCM_8_BIT = 2,
};

// The callback is used by the implementation of this interface to notify its
// client, the Android TTS service, that the last requested synthesis has been
// completed. // TODO reword
// The callback for synthesis completed takes:
// @param [inout] void *& - The userdata pointer set in the original
// synth call
// @param [in] uint32_t - Track sampling rate in Hz
// @param [in] tts_audio_format - The audio format
// @param [in] int - The number of channels
// @param [inout] int8_t *& - A buffer of audio data only valid during the
// execution of the callback
// @param [inout] size_t & - The size of the buffer
// @param [in] tts_synth_status - indicate whether the synthesis is done, or
// if more data is to be synthesized.
// @return TTS_CALLBACK_HALT to indicate the synthesis must stop,
// TTS_CALLBACK_CONTINUE to indicate the synthesis must continue if
// there is more data to produce.
typedef tts_callback_status (synthDoneCB_t)(void *&, uint32_t,
tts_audio_format, int, int8_t *&, size_t&, tts_synth_status);

class TtsEngine;
extern "C" TtsEngine* getTtsEngine();

enum tts_result {
TTS_SUCCESS = 0,
TTS_FAILURE = -1,
TTS_FEATURE_UNSUPPORTED = -2,
TTS_VALUE_INVALID = -3,
TTS_PROPERTY_UNSUPPORTED = -4,
TTS_PROPERTY_SIZE_TOO_SMALL = -5,
TTS_MISSING_RESOURCES = -6
};

enum tts_support_result {
TTS_LANG_COUNTRY_VAR_AVAILABLE = 2,
TTS_LANG_COUNTRY_AVAILABLE = 1,
TTS_LANG_AVAILABLE = 0,
TTS_LANG_MISSING_DATA = -1,
TTS_LANG_NOT_SUPPORTED = -2
};


class TtsEngine
{
public:
virtual ~TtsEngine() {}

// Initialize the TTS engine and returns whether initialization succeeded.
// @param synthDoneCBPtr synthesis callback function pointer
// @return TTS_SUCCESS, or TTS_FAILURE
virtual tts_result init(synthDoneCB_t synthDoneCBPtr, const char *engineConfig);

// Shut down the TTS engine and releases all associated resources.
// @return TTS_SUCCESS, or TTS_FAILURE
virtual tts_result shutdown();

// Interrupt synthesis and flushes any synthesized data that hasn't been
// output yet. This will block until callbacks underway are completed.
// @return TTS_SUCCESS, or TTS_FAILURE
virtual tts_result stop();

// Returns the level of support for the language, country and variant.
// @return TTS_LANG_COUNTRY_VAR_AVAILABLE if the language, country and variant are supported,
// and the corresponding resources are correctly installed
// TTS_LANG_COUNTRY_AVAILABLE if the language and country are supported and the
// corresponding resources are correctly installed, but there is no match for
// the specified variant
// TTS_LANG_AVAILABLE if the language is supported and the
// corresponding resources are correctly installed, but there is no match for
// the specified country and variant
// TTS_LANG_MISSING_DATA if the required resources to provide any level of support
// for the language are not correctly installed
// TTS_LANG_NOT_SUPPORTED if the language is not supported by the TTS engine.
virtual tts_support_result isLanguageAvailable(const char *lang, const char *country,
const char *variant);

// Load the resources associated with the specified language. The loaded
// language will only be used once a call to setLanguage() with the same
// language value is issued. Language and country values are coded according to the ISO three
// letter codes for languages and countries, as can be retrieved from a java.util.Locale
// instance. The variant value is encoded as the variant string retrieved from a
// java.util.Locale instance built with that variant data.
// @param lang pointer to the ISO three letter code for the language
// @param country pointer to the ISO three letter code for the country
// @param variant pointer to the variant code
// @return TTS_SUCCESS, or TTS_FAILURE
virtual tts_result loadLanguage(const char *lang, const char *country, const char *variant);

// Load the resources associated with the specified language, country and Locale variant.
// The loaded language will only be used once a call to setLanguageFromLocale() with the same
// language value is issued. Language and country values are coded according to the ISO three
// letter codes for languages and countries, as can be retrieved from a java.util.Locale
// instance. The variant value is encoded as the variant string retrieved from a
// java.util.Locale instance built with that variant data.
// @param lang pointer to the ISO three letter code for the language
// @param country pointer to the ISO three letter code for the country
// @param variant pointer to the variant code
// @return TTS_SUCCESS, or TTS_FAILURE
virtual tts_result setLanguage(const char *lang, const char *country, const char *variant);

// Retrieve the currently set language, country and variant, or empty strings if none of
// parameters have been set. Language and country are represented by their 3-letter ISO code
// @param[out] pointer to the retrieved 3-letter code language value
// @param[out] pointer to the retrieved 3-letter code country value
// @param[out] pointer to the retrieved variant value
// @return TTS_SUCCESS, or TTS_FAILURE
virtual tts_result getLanguage(char *language, char *country, char *variant);

// Notifies the engine what audio parameters should be used for the synthesis.
// This is meant to be used as a hint, the engine implementation will set the output values
// to those of the synthesis format, based on a given hint.
// @param[inout] encoding in: the desired audio sample format
// out: the format used by the TTS engine
// @param[inout] rate in: the desired audio sample rate
// out: the sample rate used by the TTS engine
// @param[inout] channels in: the desired number of audio channels
// out: the number of channels used by the TTS engine
// @return TTS_SUCCESS, or TTS_FAILURE
virtual tts_result setAudioFormat(tts_audio_format& encoding, uint32_t& rate,
int& channels);

// Set a property for the the TTS engine
// "size" is the maximum size of "value" for properties "property"
// @param property pointer to the property name
// @param value pointer to the property value
// @param size maximum size required to store this type of property
// @return TTS_PROPERTY_UNSUPPORTED, or TTS_SUCCESS, or TTS_FAILURE,
// or TTS_VALUE_INVALID
virtual tts_result setProperty(const char *property, const char *value,
const size_t size);

// Retrieve a property from the TTS engine
// @param property pointer to the property name
// @param[out] value pointer to the retrieved language value
// @param[inout] iosize in: stores the size available to store the
// property value.
// out: stores the size required to hold the language
// value if getLanguage() returned
// TTS_PROPERTY_SIZE_TOO_SMALL, unchanged otherwise
// @return TTS_PROPERTY_UNSUPPORTED, or TTS_SUCCESS,
// or TTS_PROPERTY_SIZE_TOO_SMALL
virtual tts_result getProperty(const char *property, char *value,
size_t *iosize);

// Synthesize the text.
// As the synthesis is performed, the engine invokes the callback to notify
// the TTS framework that it has filled the given buffer, and indicates how
// many bytes it wrote. The callback is called repeatedly until the engine
// has generated all the audio data corresponding to the text.
// Note about the format of the input: the text parameter may use the
// following elements
// and their respective attributes as defined in the SSML 1.0 specification:
// * lang
// * say-as:
// o interpret-as
// * phoneme
// * voice:
// o gender,
// o age,
// o variant,
// o name
// * emphasis
// * break:
// o strength,
// o time
// * prosody:
// o pitch,
// o contour,
// o range,
// o rate,
// o duration,
// o volume
// * mark
// Differences between this text format and SSML are:
// * full SSML documents are not supported
// * namespaces are not supported
// Text is coded in UTF-8.
// @param text the UTF-8 text to synthesize
// @param userdata pointer to be returned when the call is invoked
// @param buffer the location where the synthesized data must be written
// @param bufferSize the number of bytes that can be written in buffer
// @return TTS_SUCCESS or TTS_FAILURE
virtual tts_result synthesizeText(const char *text, int8_t *buffer,
size_t bufferSize, void *userdata);

};

} // namespace android

#endif /* TTS_ENGINE_H_ */

+ 0
- 1
android/jni/jni/eSpeakService.cpp View File

@@ -28,7 +28,6 @@
#include <jni.h>

#include <speak_lib.h>
#include <TtsEngine.h>
#include <Log.h>

/** @name Java to Wide String Helpers

+ 0
- 616
android/jni/jni/espeakengine.cpp View File

@@ -1,616 +0,0 @@
/*
* Copyright (C) 2008 Google Inc.
* Copyright (C) 2012 Reece H. Dunn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/*
* This file contains the TtsEngine implementation for the eSpeak
* Text-to-Speech engine.
*
* Android Version: 2.2 (Froyo)
* API Version: 8
*/


#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

#define LOG_TAG "eSpeak Engine"
#define DEBUG true

#include <speak_lib.h>
#include <TtsEngine.h>
#include <Log.h>

/*
* This is the Manager layer. It sits on top of the native eSpeak engine
* and provides the interface to the defined Google TTS engine API.
* The Google engine API is the boundary to allow a TTS engine to be swapped.
* The Manager layer also provide the SSML tag interpretation.
* The supported SSML tags are mapped to corresponding tags natively supported by eSpeak.
* Native eSpeak functions always begin with espeak_XXX.
*
* Only a subset of SSML 1.0 tags are supported.
* Some SSML tags involve significant complexity.
* If the language is changed through an SSML tag, there is a latency for the load.
*/

using namespace android;

const char *ESPEAK_DIRECTORY = "espeak-data";

const char *eSpeakBaseResources[] = {"intonations", "phondata", "phonindex", "phontab",
"en_dict", "voices/en/en-us" };

const int NUM_BASE_RESOURCES = 6;

// Format is {espeak voice, iso3 code, name}
const char *eSpeakSupportedVoices[][3] = {
{"en-us", "eng", "English"},
{"en-us", "eng-USA", "English (US)"},
{"en", "eng-GBR", "English (UK)"},
{"en-sc", "eng-GBR-sc", "English (Scottish)"},
{"en-n", "eng-GBR-n", "English (Northern UK)"},
{"en-rp", "eng-GBR-rp", "English (Received Pronunciation)"},
{"en-wm", "eng-GBR-wm", "English (West Midlands)"},
{"af", "afr", "Afrikaans"},
{"bs", "bos", "Bosnian"},
{"ca", "cat", "Catalan"},
{"cs", "ces", "Czech"},
{"da", "dan", "Danish"},
{"de", "deu", "German"},
{"el", "ell", "Greek"},
{"eo", "epo", "Esperanto"},
{"es", "spa", "Spanish"},
{"es-la", "spa-MEX", "Spanish (Latin America)"},
{"fi", "fin", "Finnish"},
{"fr", "fra", "French"},
{"hr", "hrv", "Croatian"},
{"hu", "hun", "Hungarian"},
{"it", "ita", "Italian"},
{"kn", "kan", "Kannada"},
{"ku", "kur", "Kurdish"},
{"lv", "lav", "Latvian"},
{"nl", "nld", "Dutch"},
{"pl", "pol", "Polish"},
{"pt", "por", "Portuguese (Brazil)"},
{"pt", "por-BRA", "Portuguese (Brazil)"},
{"pt-pt", "por-PRT", "Portuguese"},
{"ro", "ron", "Romanian"},
{"sk", "slk", "Slovak"},
{"sr", "srp", "Serbian"},
{"sv", "swe", "Swedish"},
{"sw", "swa", "Swahili"},
{"ta", "tam", "Tamil"},
{"tr", "tur", "Turkish"},
{"zh", "zho", "Chinese (Mandarin)"},
{"cy", "cym", "Welsh"},
{"hi", "hin", "Hindi"},
{"hy", "hye", "Armenian"},
{"id", "ind", "Indonesian"},
{"is", "isl", "Icelandic"},
{"ka", "kat", "Georgian"},
{"la", "lat", "Latin"},
{"mk", "mkd", "Macedonian"},
{"no", "nor", "Norwegian"},
{"ru", "rus", "Russian"},
{"sq", "sqi", "Albanian"},
{"vi", "vie", "Vietnamese"},
{"zh-yue", "zho-HKG", "Chinese (Cantonese)"},
{"grc", "grc", "Ancient Greek"},
{"jbo", "jbo", "Lojban"},
{"nci", "nci", "Nahuatl (Classical)"},
{"pap", "pap", "Papiamento" }
};

const int NUM_SUPPORTED_VOICES = 55;

// Callback to the TTS API
synthDoneCB_t *ttsSynthDoneCBPointer;

char *eSpeakDataPath = NULL;

char currentLanguage[33];
char currentLang[10];
char currentCountry[10];
char currentVariant[10];

int sampleRate = 0;
bool hasInitialized = false;

/* Functions internal to the eSpeak engine wrapper */
static void setSpeechRate(int speechRate) {
espeak_ERROR err = espeak_SetParameter(espeakRATE, speechRate, 0);
}

/* Functions exposed to the TTS API */

/* Callback from espeak. Should call back to the TTS API */
static int eSpeakCallback(short *wav, int numsamples, espeak_EVENT *events) {
LOGI("Callback with %d samples", numsamples);

int8_t * castedWav = (int8_t *) wav;
size_t bufferSize = 0;
if (numsamples < 1) {
int8_t silenceData[] = { 0, 0 };
size_t silenceBufferSize = sizeof(silenceData)/sizeof(silenceData[0]);
int8_t *silence = silenceData; // Passing in an empty buffer can cause a crash.
ttsSynthDoneCBPointer(events->user_data, 22050, TTS_AUDIO_FORMAT_PCM_16_BIT, 1, silence,
silenceBufferSize, TTS_SYNTH_DONE);
return 1;
}
bufferSize = numsamples * sizeof(short);
ttsSynthDoneCBPointer(events->user_data, 22050, TTS_AUDIO_FORMAT_PCM_16_BIT, 1, castedWav,
bufferSize, TTS_SYNTH_PENDING);
return 0; // continue synthesis (1 is to abort)
}

static bool fileExists(char *fileName) {
if (DEBUG) LOGV("%s", __FUNCTION__);
FILE *file = fopen(fileName, "r");

if (file == NULL) {
return false;
} else {
fclose(file);
return true;
}
}

static bool hasBaseResources() {
if (DEBUG) LOGV("%s", __FUNCTION__);
char filename[255];

for (int i = 0; i < NUM_BASE_RESOURCES; i++) {
sprintf(filename, "%s/%s/%s", eSpeakDataPath, ESPEAK_DIRECTORY, eSpeakBaseResources[i]);

if (!fileExists(filename)) {
LOGE("Missing resource: %s", filename);
return false;
}
}

return true;
}

/* Google Engine API function implementations */

tts_result attemptInit() {
if (DEBUG) LOGV("%s", __FUNCTION__);
if (hasInitialized) {
return TTS_SUCCESS;
}

if (!hasBaseResources()) {
return TTS_FAILURE;
}

// TODO Make sure that the speech data is loaded in
// the directory /sdcard/espeak-data before calling this.
sampleRate = espeak_Initialize(AUDIO_OUTPUT_SYNCHRONOUS, 4096, eSpeakDataPath, 0);

if (sampleRate <= 0) {
LOGE("eSpeak initialization failed!");
return TTS_FAILURE;
}

espeak_SetSynthCallback(eSpeakCallback);

espeak_VOICE voice;
memset(&voice, 0, sizeof(espeak_VOICE)); // Zero out the voice first
const char *langNativeString = "en-us"; //Default to US English
voice.languages = langNativeString;
voice.variant = 0;
espeak_SetVoiceByProperties(&voice);

strcpy(currentLanguage, "en-us");
hasInitialized = true;

return TTS_SUCCESS;
}

/** init
* Allocates eSpeak memory block and initializes the eSpeak system.
* synthDoneCBPtr - Pointer to callback function which will receive generated samples
* config - the engine configuration parameters, not used here
* return tts_result
*/
tts_result TtsEngine::init(synthDoneCB_t synthDoneCBPtr, const char *engineConfig) {
if (DEBUG) LOGV("%s", __FUNCTION__);
ttsSynthDoneCBPointer = synthDoneCBPtr;
hasInitialized = false;

if ((engineConfig != NULL) && (strlen(engineConfig) > 0)) {
eSpeakDataPath = (char *) malloc(strlen(engineConfig));
strcpy(eSpeakDataPath, engineConfig);
} else {
eSpeakDataPath = NULL;
LOGE("Data path not specified!");
return TTS_FAILURE;
}

return attemptInit();
}

/** shutdown
* Unloads all eSpeak resources; terminates eSpeak system and frees eSpeak memory block.
* return tts_result
*/
tts_result TtsEngine::shutdown(void) {
if (DEBUG) LOGV("%s", __FUNCTION__);
if (eSpeakDataPath != NULL) {
free(eSpeakDataPath);
}

espeak_Terminate();

return TTS_SUCCESS;
}

tts_result TtsEngine::loadLanguage(const char *lang, const char *country, const char *variant) {
if (DEBUG) LOGV("loadLanguage(\"%s\", \"%s\", \"%s\")", lang, country, variant);

return TTS_FAILURE;
}

tts_support_result isLanguageSupported(const char *lang, const char *country, const char *variant,
int *pindex) {
if (DEBUG) LOGV("isLanguageSupported(\"%s\", \"%s\", \"%s\")", lang, country, variant);

if ((lang == NULL) || (strlen(lang) == 0)) {
LOGE("TtsEngine::isLanguageAvailable called with no language");
return TTS_LANG_NOT_SUPPORTED;
}

if (pindex != NULL) {
*pindex = -1;
}

int langIndex = -1;
int countryIndex = -1;
int variantIndex = -1;

if (strlen(lang) == 3) {
for (int i = 0; i < NUM_SUPPORTED_VOICES; i++) {
if (strncmp(lang, eSpeakSupportedVoices[i][1], 3) == 0) {
LOGI("Found ISO3 language at index %d", i);
langIndex = i;
break;
}
}
} else if (strlen(lang) == 2) {
for (int i = 0; i < NUM_SUPPORTED_VOICES; i++) {
if (strncmp(lang, eSpeakSupportedVoices[i][0], 2) == 0) {
LOGI("Found ISO2 language at index %d", i);
langIndex = i;
break;
}
}
}

if (langIndex < 0) {
LOGV("TtsEngine::isLanguageAvailable called with unsupported language");
return TTS_LANG_NOT_SUPPORTED;
}

if ((country == NULL) || (strlen(country) == 0)) {
// TODO: Check whether resources are available for this language.

if (pindex != NULL) {
*pindex = langIndex;
}

LOGI("No country specified, language is available");
return TTS_LANG_AVAILABLE;
}

char lang_country[10];
sprintf(lang_country, "%s-%s", lang, country);

// Find country
if (strlen(country) == 3) {
for (int i = langIndex; i < NUM_SUPPORTED_VOICES; i++) {
if ((strcmp(lang_country, eSpeakSupportedVoices[i][1]) == 0)) {
LOGI("Found ISO3 country at index %d", i);
countryIndex = i;
break;
}
}
} else if (strlen(country) == 2) {
for (int i = langIndex; i < NUM_SUPPORTED_VOICES; i++) {
if ((strcmp(lang_country, eSpeakSupportedVoices[i][0]) == 0)) {
LOGI("Found ISO2 country at index %d", i);
countryIndex = i;
break;
}
}
}

if (countryIndex < 0) {
if (pindex != NULL) {
*pindex = langIndex;
}

LOGI("No country found, language is available");
return TTS_LANG_AVAILABLE;
}

if ((variant == NULL) || (strlen(variant) == 0)) {
if (pindex != NULL) {
*pindex = countryIndex;
}

LOGI("No variant specified, language and country are available");
return TTS_LANG_COUNTRY_AVAILABLE;
}

char lang_country_variant[15];
sprintf(lang_country_variant, "%s-%s-%s", lang, country, variant);

// Find variant
for (int i = countryIndex; i < NUM_SUPPORTED_VOICES; i++) {
if ((strcmp(lang_country_variant, eSpeakSupportedVoices[i][1]) == 0)) {
LOGI("Found variant at index %d", i);
variantIndex = i;
break;
}
}

if (variantIndex < 0) {
if (pindex != NULL) {
*pindex = countryIndex;
}

LOGI("No variant found, language and country are available");
return TTS_LANG_COUNTRY_AVAILABLE;
}

if (pindex != NULL) {
*pindex = variantIndex;
}

LOGI("Language, country, and variant are available");
return TTS_LANG_COUNTRY_VAR_AVAILABLE;
}

tts_result TtsEngine::setLanguage(const char *lang, const char *country, const char *variant) {
if (DEBUG) LOGV("setLanguage(\"%s\", \"%s\", \"%s\")", lang, country, variant);

// Make sure the engine is initialized!
attemptInit();

int index = -1;

isLanguageSupported(lang, country, variant, &index);

if (index < 0) {
LOGE("setLanguage called with unsupported language");
return TTS_FAILURE;
}

strcpy(currentLanguage, lang);
strcpy(currentLang, lang);
strcpy(currentCountry, country);
strcpy(currentVariant, variant);

char espeakLangStr[7];
strcpy(espeakLangStr, eSpeakSupportedVoices[index][0]);

espeak_VOICE voice;
memset(&voice, 0, sizeof(espeak_VOICE)); // Zero out the voice first
voice.variant = 0;
voice.languages = espeakLangStr;
espeak_ERROR err = espeak_SetVoiceByProperties(&voice);

if (err != EE_OK) {
LOGE("Error code %d when setting voice properties!", err);
return TTS_FAILURE;
}

return TTS_SUCCESS;
}

tts_support_result TtsEngine::isLanguageAvailable(const char *lang, const char *country,
const char *variant) {
if (DEBUG) LOGV("%s", __FUNCTION__);
return isLanguageSupported(lang, country, variant, NULL);
}

tts_result TtsEngine::getLanguage(char *language, char *country, char *variant) {
if (DEBUG) LOGV("%s", __FUNCTION__);
strcpy(language, currentLang);
strcpy(country, currentCountry);
strcpy(variant, currentVariant);

return TTS_SUCCESS;
}

/** setAudioFormat
* sets the audio format to use for synthesis, returns what is actually used.
* @encoding - reference to encoding format
* @rate - reference to sample rate
* @channels - reference to number of channels
* return tts_result
* */
tts_result TtsEngine::setAudioFormat(tts_audio_format& encoding, uint32_t& rate, int& channels) {
LOGE("setAudioFormat(%d, %d, %d) is unsupported", encoding, rate, channels);

encoding = TTS_AUDIO_FORMAT_PCM_16_BIT;
rate = sampleRate;
channels = 1;
return TTS_SUCCESS;
}

// Sets the property with the specified value
tts_result TtsEngine::setProperty(const char *property, const char *value, const size_t size) {
if (DEBUG) LOGV("setProperty(\"%s\", \"%s\", %d)", property, value, size);

/* Set a specific property for the engine.
Supported properties include: language (locale), rate, pitch, volume. */
/* Sanity check */
if (property == NULL) {
LOGE("setProperty called with property NULL");
return TTS_PROPERTY_UNSUPPORTED;
}

if (value == NULL) {
LOGE("setProperty called with value NULL");
return TTS_VALUE_INVALID;
}

espeak_ERROR result;

if (strncmp(property, "language", 8) == 0) {
// TODO: Set this property
result = EE_OK;
} else if (strncmp(property, "rate", 4) == 0) {
int rate = atoi(value) * espeak_GetParameter(espeakRATE, 0) / 100;
if (DEBUG) LOGV("setProperty rate : rate=%s, wpm=%d", value, rate);
result = espeak_SetParameter(espeakRATE, rate, 0);
} else if (strncmp(property, "pitch", 5) == 0) {
int pitch = atoi(value);
// The values of pitch from android range from 50 - 200, with 100 being normal.
// The values espeak supports are from 0 - 100, with 50 being normal.
// Therefore, halve the value to get the value that espeak supports:
pitch = pitch / 2;
if (DEBUG) LOGV("setProperty pitch : pitch=%d", pitch);
result = espeak_SetParameter(espeakPITCH, pitch, 0);
} else if (strncmp(property, "volume", 6) == 0) {
int volume = atoi(value);
result = espeak_SetParameter(espeakVOLUME, volume, 0);
} else {
return TTS_PROPERTY_UNSUPPORTED;
}

if (result == EE_OK) {
return TTS_SUCCESS;
} else {
return TTS_FAILURE;
}
}

// Sets the property with the specified value
tts_result TtsEngine::getProperty(const char *property, char *value, size_t *iosize) {
if (DEBUG) LOGV("getProperty(\"%s\", ...)", property);

/* Get the property for the engine.
This property was previously set by setProperty or by default. */
/* sanity check */
if (property == NULL) {
LOGE("getProperty called with property NULL");
return TTS_PROPERTY_UNSUPPORTED;
}

if (value == NULL) {
LOGE("getProperty called with value NULL");
return TTS_VALUE_INVALID;
}

if (strncmp(property, "language", 8) == 0) {
if (currentLanguage == NULL) {
strcpy(value, "");
} else {
if (*iosize < strlen(currentLanguage)+1) {
*iosize = strlen(currentLanguage) + 1;
return TTS_PROPERTY_SIZE_TOO_SMALL;
}
strcpy(value, currentLanguage);
}
return TTS_SUCCESS;
} else if (strncmp(property, "rate", 4) == 0) {
int rate = espeak_GetParameter(espeakRATE, 1) * 100 / espeak_GetParameter(espeakRATE, 0);
char tmprate[4];
sprintf(tmprate, "%d", rate);
if (*iosize < strlen(tmprate)+1) {
*iosize = strlen(tmprate) + 1;
return TTS_PROPERTY_SIZE_TOO_SMALL;
}
strcpy(value, tmprate);
return TTS_SUCCESS;
} else if (strncmp(property, "pitch", 5) == 0) {
char tmppitch[4];
sprintf(tmppitch, "%d", (espeak_GetParameter(espeakPITCH, 1) * 2));
if (*iosize < strlen(tmppitch)+1) {
*iosize = strlen(tmppitch) + 1;
return TTS_PROPERTY_SIZE_TOO_SMALL;
}
strcpy(value, tmppitch);
return TTS_SUCCESS;
} else if (strncmp(property, "volume", 6) == 0) {
char tmpvolume[4];
sprintf(tmpvolume, "%d", espeak_GetParameter(espeakVOLUME, 1));
if (*iosize < strlen(tmpvolume)+1) {
*iosize = strlen(tmpvolume) + 1;
return TTS_PROPERTY_SIZE_TOO_SMALL;
}
strcpy(value, tmpvolume);
return TTS_SUCCESS;
}

LOGE("Unsupported property");
return TTS_PROPERTY_UNSUPPORTED;
}

/** synthesizeText
* Synthesizes a text string.
* The text string could be annotated with SSML tags.
* @text - text to synthesize
* @buffer - buffer which will receive generated samples
* @bufferSize - size of buffer
* @userdata - pointer to user data which will be passed back to callback function
* return tts_result
*/
tts_result TtsEngine::synthesizeText(const char *text, int8_t *buffer, size_t bufferSize,
void *userdata) {
if (DEBUG) LOGV("%s", __FUNCTION__);

espeak_SetSynthCallback(eSpeakCallback);

unsigned int unique_identifier;

espeak_Synth(text, strlen(text), 0, // position
POS_CHARACTER, 0, // end position (0 means no end position)
espeakCHARS_UTF8, // text is UTF-8 encoded
&unique_identifier, userdata);
espeak_Synchronize();

LOGI("Synthesis done");

return TTS_SUCCESS;
}

/** stop
* Aborts the running synthesis.
* return tts_result
*/
tts_result TtsEngine::stop() {
if (DEBUG) LOGV("%s", __FUNCTION__);
espeak_Cancel();
return TTS_SUCCESS;
}

#ifdef __cplusplus
extern "C" {
#endif

TtsEngine* getTtsEngine() {
if (DEBUG) LOGV("%s", __FUNCTION__);
return new TtsEngine();
}

#ifdef __cplusplus
}
#endif

+ 0
- 43
android/src/com/reecedunn/espeak/eSpeak.java View File

@@ -1,43 +0,0 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.reecedunn.espeak;

import android.app.Activity;
import android.os.Bundle;

/*
* The Java portion of this TTS plugin engine app does nothing.
* This activity is only here so that the native code can be
* wrapped up inside an apk file.
*
* The file path structure convention is that the native library
* implementing TTS must be a file placed here:
* /data/data/<PACKAGE_NAME>/lib/libtts<ACTIVITY_NAME_LOWERCASED>.so
* Example:
* /data/data/com.reecedunn.espeak/lib/libttsespeak.so
*/

public class eSpeak extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// The Java portion of this does nothing.
// This activity is only here so that everything
// can be wrapped up inside an apk file.
finish();
}
}

+ 0
- 94
android/src/com/reecedunn/espeak/providers/SettingsProvider.java View File

@@ -1,94 +0,0 @@
/*
* Copyright (C) 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.reecedunn.espeak.providers;

import com.reecedunn.espeak.CheckVoiceData;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;

import java.io.File;

/**
* Provides the "engineConfig" parameter for the legacy (pre-ICS) TTS API.
*
* @author [email protected] (Alan Viverette)
*/
public class SettingsProvider extends ContentProvider {
private class SettingsCursor extends MatrixCursor {
private String settings;

public SettingsCursor(String[] columnNames) {
super(columnNames);
}

public void putSettings(String settings) {
this.settings = settings;
}

@Override
public int getCount() {
return 1;
}

@Override
public String getString(int column) {
return settings;
}
}

@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}

@Override
public String getType(Uri uri) {
return null;
}

@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}

@Override
public boolean onCreate() {
return true;
}

@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
final File dataPath = CheckVoiceData.getDataPath(getContext());
final String[] dummyColumns = {
"", ""
};
final SettingsCursor cursor = new SettingsCursor(dummyColumns);
cursor.putSettings(dataPath.getParent());
return cursor;
}

@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}

}

Loading…
Cancel
Save