eSpeak NG is an open source speech synthesizer that supports more than hundred languages and accents.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SpeechSynthesis.java 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /*
  2. * Copyright (C) 2011 Google Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /*
  17. * This file implements the Java API to eSpeak using the JNI bindings.
  18. *
  19. * Android Version: 4.0 (Ice Cream Sandwich)
  20. * API Version: 14
  21. */
  22. package com.googlecode.eyesfree.espeak;
  23. import android.content.Context;
  24. import android.speech.tts.TextToSpeech;
  25. import android.util.Log;
  26. import java.io.File;
  27. import java.util.LinkedList;
  28. import java.util.List;
  29. import java.util.Locale;
  30. public class SpeechSynthesis {
  31. private static final String TAG = SpeechSynthesis.class.getSimpleName();
  32. public static final int GENDER_MALE = 1;
  33. public static final int GENDER_FEMALE = 2;
  34. static {
  35. System.loadLibrary("ttsespeak");
  36. nativeClassInit();
  37. }
  38. private final Context mContext;
  39. private final SynthReadyCallback mCallback;
  40. private final String mDatapath;
  41. private boolean mInitialized = false;
  42. public SpeechSynthesis(Context context, SynthReadyCallback callback) {
  43. // First, ensure the data directory exists, otherwise init will crash.
  44. final File dataPath = CheckVoiceData.getDataPath(context);
  45. if (!dataPath.exists()) {
  46. Log.e(TAG, "Missing voice data");
  47. dataPath.mkdirs();
  48. }
  49. mContext = context;
  50. mCallback = callback;
  51. mDatapath = dataPath.getParentFile().getPath();
  52. attemptInit();
  53. }
  54. @Override
  55. protected void finalize() {
  56. nativeDestroy();
  57. }
  58. public int getSampleRate() {
  59. return nativeGetSampleRate();
  60. }
  61. public int getChannelCount() {
  62. return nativeGetChannelCount();
  63. }
  64. public int getAudioFormat() {
  65. return nativeGetAudioFormat();
  66. }
  67. public int getBufferSizeInBytes() {
  68. final int bufferSizeInMillis = nativeGetBufferSizeInMillis();
  69. final int sampleRate = nativeGetSampleRate();
  70. return (bufferSizeInMillis * sampleRate) / 1000;
  71. }
  72. public List<Voice> getAvailableVoices() {
  73. final List<Voice> voices = new LinkedList<Voice>();
  74. final String[] results = nativeGetAvailableVoices();
  75. for (int i = 0; i < results.length; i += 4) {
  76. final String name = results[i];
  77. final String identifier = results[i + 1];
  78. final int gender = Integer.parseInt(results[i + 2]);
  79. final int age = Integer.parseInt(results[i + 3]);
  80. final Voice voice = new Voice(name, identifier, gender, age);
  81. voices.add(voice);
  82. }
  83. return voices;
  84. }
  85. public void setVoiceByProperties(
  86. String name, String languages, int gender, int age, int variant) {
  87. nativeSetVoiceByProperties(name, languages, gender, age, variant);
  88. }
  89. public void setRate(int rate) {
  90. nativeSetRate(rate);
  91. }
  92. public void setPitch(int pitch) {
  93. nativeSetPitch(pitch);
  94. }
  95. public void synthesize(String text) {
  96. nativeSynthesize(text);
  97. }
  98. public void stop() {
  99. nativeStop();
  100. }
  101. private void nativeSynthCallback(byte[] audioData) {
  102. if (mCallback == null)
  103. return;
  104. if (audioData == null) {
  105. mCallback.onSynthDataComplete();
  106. } else {
  107. mCallback.onSynthDataReady(audioData);
  108. }
  109. }
  110. private void attemptInit() {
  111. if (mInitialized) {
  112. return;
  113. }
  114. if (!CheckVoiceData.hasBaseResources(mContext)) {
  115. Log.e(TAG, "Missing base resources");
  116. return;
  117. }
  118. if (!nativeCreate(mDatapath)) {
  119. Log.e(TAG, "Failed to initialize speech synthesis library");
  120. return;
  121. }
  122. Log.i(TAG, "Initialized synthesis library with sample rate = " + getSampleRate());
  123. mInitialized = true;
  124. }
  125. private int mNativeData;
  126. private static native final boolean nativeClassInit();
  127. private native final boolean nativeCreate(String path);
  128. private native final boolean nativeDestroy();
  129. private native final int nativeGetSampleRate();
  130. private native final int nativeGetChannelCount();
  131. private native final int nativeGetAudioFormat();
  132. private native final int nativeGetBufferSizeInMillis();
  133. private native final String[] nativeGetAvailableVoices();
  134. private native final boolean nativeSetVoiceByProperties(
  135. String name, String languages, int gender, int age, int variant);
  136. private native final boolean nativeSetRate(int rate);
  137. private native final boolean nativeSetPitch(int pitch);
  138. private native final boolean nativeSynthesize(String text);
  139. private native final boolean nativeStop();
  140. public interface SynthReadyCallback {
  141. void onSynthDataReady(byte[] audioData);
  142. void onSynthDataComplete();
  143. }
  144. public class Voice {
  145. public final String name;
  146. public final String identifier;
  147. public final int gender;
  148. public final int age;
  149. public final Locale locale;
  150. public Voice(String name, String identifier, int gender, int age) {
  151. this.name = name;
  152. this.identifier = identifier;
  153. this.gender = gender;
  154. this.age = age;
  155. locale = new Locale(name);
  156. }
  157. /**
  158. * Attempts a partial match against a query locale.
  159. *
  160. * @param query The locale to match.
  161. * @return A text-to-speech availability code. One of:
  162. * <ul>
  163. * <li>{@link TextToSpeech#LANG_NOT_SUPPORTED}
  164. * <li>{@link TextToSpeech#LANG_AVAILABLE}
  165. * <li>{@link TextToSpeech#LANG_COUNTRY_AVAILABLE}
  166. * <li>{@link TextToSpeech#LANG_COUNTRY_VAR_AVAILABLE}
  167. * </ul>
  168. */
  169. public int match(Locale query) {
  170. if (!locale.getISO3Language().equals(query.getISO3Language())) {
  171. return TextToSpeech.LANG_NOT_SUPPORTED;
  172. } else if (!locale.getISO3Country().equals(query.getISO3Country())) {
  173. return TextToSpeech.LANG_AVAILABLE;
  174. } else if (!locale.getVariant().equals(query.getVariant())) {
  175. return TextToSpeech.LANG_COUNTRY_AVAILABLE;
  176. } else {
  177. return TextToSpeech.LANG_COUNTRY_VAR_AVAILABLE;
  178. }
  179. }
  180. @Override
  181. public String toString() {
  182. return name;
  183. }
  184. }
  185. }