2 * Copyright 2003 Sun Microsystems, Inc.
4 * See the file "license.terms" for information on usage and
5 * redistribution of this file, and for a DISCLAIMER OF ALL
8 import java.io.BufferedReader;
10 import java.io.InputStreamReader;
11 import java.io.IOException;
13 import java.util.Calendar;
14 import java.util.GregorianCalendar;
15 import java.util.Locale;
17 import java.util.regex.Pattern;
19 import javax.speech.Central;
20 import javax.speech.Engine;
21 import javax.speech.EngineList;
22 import javax.speech.EngineException;
23 import javax.speech.synthesis.Synthesizer;
24 import javax.speech.synthesis.SynthesizerModeDesc;
25 import javax.speech.synthesis.SynthesizerProperties;
26 import javax.speech.synthesis.Voice;
29 * Simple program showing how to use the Limited Domain (time)
30 * FreeTTS synthesizer.
34 Synthesizer synthesizer;
37 * Returns a "no synthesizer" message, and asks
38 * the user to check if the "speech.properties" file is
39 * at <code>user.home</code> or <code>java.home/lib</code>.
41 * @return a no synthesizer message
43 static private String noSynthesizerMessage() {
45 "No synthesizer created. This may be the result of any\n" +
46 "number of problems. It's typically due to a missing\n" +
47 "\"speech.properties\" file that should be at either of\n" +
48 "these locations: \n\n";
49 message += "user.home : " + System.getProperty("user.home") + "\n";
50 message += "java.home/lib: " + System.getProperty("java.home") +
51 File.separator + "lib\n\n" +
52 "Another cause of this problem might be corrupt or missing\n" +
53 "voice jar files in the freetts lib directory. This problem\n" +
54 "also sometimes arises when the freetts.jar file is corrupt\n" +
55 "or missing. Sorry about that. Please check for these\n" +
56 "various conditions and then try again.\n";
61 * Example of how to list all the known voices for a specific
62 * mode using just JSAPI. FreeTTS maps the domain name to the
63 * JSAPI mode name. The currently supported domains are
64 * "general," which means general purpose synthesis for tasks
65 * such as reading e-mail, and "time" which means a domain that's
66 * only good for speaking the time of day.
68 public static void listAllVoices(String modeName) {
72 "All " + modeName + " Mode JSAPI Synthesizers and Voices:");
74 /* Create a template that tells JSAPI what kind of speech
75 * synthesizer we are interested in. In this case, we're
76 * just looking for a general domain synthesizer for US
79 SynthesizerModeDesc required = new SynthesizerModeDesc(
81 modeName, // mode name
86 /* Contact the primary entry point for JSAPI, which is
87 * the Central class, to discover what synthesizers are
88 * available that match the template we defined above.
90 EngineList engineList = Central.availableSynthesizers(required);
91 for (int i = 0; i < engineList.size(); i++) {
93 SynthesizerModeDesc desc = (SynthesizerModeDesc) engineList.get(i);
94 System.out.println(" " + desc.getEngineName()
95 + " (mode=" + desc.getModeName()
96 + ", locale=" + desc.getLocale() + "):");
97 Voice[] voices = desc.getVoices();
98 for (int j = 0; j < voices.length; j++) {
99 System.out.println(" " + voices[j].getName());
105 * Construct a default JTime object. It creates the Limited Domain
106 * synthesizer, speaks the current time, and asks the user to input
107 * a new time in the format HH:MM.
109 public JTime(String voiceName) {
111 /* Find a synthesizer that has the general domain voice
112 * we are looking for. NOTE: this uses the Central class
113 * of JSAPI to find a Synthesizer. The Central class
114 * expects to find a speech.properties file in user.home
117 * If your situation doesn't allow you to set up a
118 * speech.properties file, you can circumvent the Central
119 * class and do a very non-JSAPI thing by talking to
120 * FreeTTSEngineCentral directly. See the WebStartClock
121 * demo for an example of how to do this.
123 SynthesizerModeDesc desc = new SynthesizerModeDesc(
130 synthesizer = Central.createSynthesizer(desc);
132 /* Just an informational message to guide users that didn't
133 * set up their speech.properties file.
135 if (synthesizer == null) {
136 System.err.println(noSynthesizerMessage());
140 /* Get the synthesizer ready to speak
142 synthesizer.allocate();
143 synthesizer.resume();
147 desc = (SynthesizerModeDesc) synthesizer.getEngineModeDesc();
148 Voice[] voices = desc.getVoices();
150 for (int i = 0; i < voices.length; i++) {
151 if (voices[i].getName().equals(voiceName)) {
158 "Synthesizer does not have a voice named "
162 synthesizer.getSynthesizerProperties().setVoice(voice);
164 catch (Exception e) {
170 * Starts interactive mode. Reads text from the console and gives
171 * it to the synthesizer to speak. Terminates on end of file.
173 public void interactiveMode() {
177 BufferedReader reader = new BufferedReader
178 (new InputStreamReader(System.in));
179 System.out.print("Enter time (HH:MM): ");
181 text = reader.readLine();
182 if ((text == null) || (text.length() == 0)) {
188 } catch (IOException ioe) {
189 ioe.printStackTrace();
194 * Speaks the given time. Time should be in the exact form
195 * HH:MM where HH is the hour 00 to 23, and MM is the minute 00 to
198 * @param time the time in the form HH:MM
200 * @throws IllegalArgumentException if time is not in the form
203 public void timeToSpeech(String time) {
204 String theTime = TimeUtils.timeToString(time);
205 if (theTime != null) {
206 synthesizer.speakPlainText(theTime, null);
208 // throw new IllegalArgumentException("Bad time format");
209 System.out.println("Bad time format. The format should be HH:MM");
214 * Speaks the time given the hour and minute.
216 * @param hour the hour of the day (0 to 23)
217 * @param min the minute of the hour (0 to 59)
219 public void timeToSpeech(int hour, int min) {
220 if (hour < 0 || hour > 23) {
221 throw new IllegalArgumentException("Bad time format: hour");
224 if (min < 0 || min > 59) {
225 throw new IllegalArgumentException("Bad time format: min");
228 String theTime = TimeUtils.timeToString(hour, min);
230 synthesizer.speakPlainText(theTime, null);
234 * Speaks the given time. Prints an error message if the time
237 * @param time the time in the form HH:MM
239 public void safeTimeToSpeech(String time) {
241 if (time.equals("now")) {
246 } catch (IllegalArgumentException iae) {
247 System.err.println("Bad time format");
252 * Tells the current time.
254 public void speakNow() {
255 long now = System.currentTimeMillis();
256 Calendar cal = new GregorianCalendar();
257 int hour = cal.get(Calendar.HOUR_OF_DAY);
258 int min = cal.get(Calendar.MINUTE);
259 timeToSpeech(hour, min);
265 public void close() {
267 synthesizer.deallocate();
268 } catch (EngineException ee) {
269 System.out.println("Trouble deallocating synthesizer: " + ee);
273 public static void main(String[] args) {
275 /* List all the "time" domain voices, which are voices that
276 * are only capable of speaking the time of day.
278 listAllVoices("time");
280 String voiceName = (args.length > 0)
284 System.out.println();
285 System.out.println("Using voice: " + voiceName);
288 JTime jtime = new JTime(voiceName);
290 jtime.interactiveMode();
293 catch (Exception e) {