upstream version 1.2.2
[debian/freetts] / demo / JSAPI / JTime / JTime.java
1 /**
2  * Copyright 2003 Sun Microsystems, Inc.
3  * 
4  * See the file "license.terms" for information on usage and
5  * redistribution of this file, and for a DISCLAIMER OF ALL 
6  * WARRANTIES.
7  */
8 import java.io.BufferedReader;
9 import java.io.File;
10 import java.io.InputStreamReader;
11 import java.io.IOException;
12
13 import java.util.Calendar;
14 import java.util.GregorianCalendar;
15 import java.util.Locale;
16
17 import java.util.regex.Pattern;
18
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;
27
28 /**
29  * Simple program showing how to use the Limited Domain (time)
30  * FreeTTS synthesizer.
31  */
32 public class JTime {
33
34     Synthesizer synthesizer;
35
36     /**
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>.
40      *
41      * @return a no synthesizer message
42      */
43     static private String noSynthesizerMessage() {
44         String message =
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";
57         return message;
58     }
59
60     /**
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. 
67      */
68     public static void listAllVoices(String modeName) {
69         
70         System.out.println();
71         System.out.println(
72             "All " + modeName + " Mode JSAPI Synthesizers and Voices:");
73
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
77          * English.
78          */ 
79         SynthesizerModeDesc required = new SynthesizerModeDesc(
80             null,      // engine name
81             modeName,  // mode name
82             Locale.US, // locale
83             null,      // running
84             null);     // voices
85
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.
89          */
90         EngineList engineList = Central.availableSynthesizers(required);
91         for (int i = 0; i < engineList.size(); i++) {
92             
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());
100             }
101         }
102     }
103     
104     /**
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.
108      */
109     public JTime(String voiceName) {
110         try {
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
115              * or java.home/lib.
116              *
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.
122              */
123             SynthesizerModeDesc desc = new SynthesizerModeDesc(
124                 null,          // engine name
125                 "time",        // mode name
126                 Locale.US,     // locale
127                 null,          // running
128                 null);         // voice
129
130             synthesizer = Central.createSynthesizer(desc);
131
132             /* Just an informational message to guide users that didn't
133              * set up their speech.properties file. 
134              */
135             if (synthesizer == null) {
136                 System.err.println(noSynthesizerMessage());
137                 System.exit(1);
138             }
139
140             /* Get the synthesizer ready to speak
141              */
142             synthesizer.allocate();
143             synthesizer.resume();
144
145             /* Choose the voice.
146              */
147             desc = (SynthesizerModeDesc) synthesizer.getEngineModeDesc();
148             Voice[] voices = desc.getVoices();
149             Voice voice = null;
150             for (int i = 0; i < voices.length; i++) {
151                 if (voices[i].getName().equals(voiceName)) {
152                     voice = voices[i];
153                     break;
154                 }
155             }
156             if (voice == null) {
157                 System.err.println(
158                     "Synthesizer does not have a voice named "
159                     + voiceName + ".");
160                 System.exit(1);
161             }
162             synthesizer.getSynthesizerProperties().setVoice(voice);
163         }
164         catch (Exception e) {
165             e.printStackTrace();
166         }
167     }
168
169     /**
170      * Starts interactive mode. Reads text from the console and gives
171      * it to the synthesizer to speak.  Terminates on end of file.
172      */
173     public void interactiveMode() {
174         try {
175             while (true) {
176                 String text;
177                 BufferedReader reader = new BufferedReader
178                     (new InputStreamReader(System.in));
179                 System.out.print("Enter time (HH:MM): ");
180                 System.out.flush();
181                 text = reader.readLine();
182                 if ((text == null) || (text.length() == 0)) {
183                     break;
184                 } else {
185                     timeToSpeech(text);
186                 }
187             }
188         } catch (IOException ioe) {
189             ioe.printStackTrace();
190         }
191     }
192
193     /**
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
196      * 59.
197      *
198      * @param time the time in the form HH:MM
199      *
200      * @throws IllegalArgumentException if time is not in the form
201      *   HH:MM
202      */
203     public void timeToSpeech(String time) {
204         String theTime = TimeUtils.timeToString(time);
205         if (theTime != null) {
206             synthesizer.speakPlainText(theTime, null);
207         } else {
208             // throw new IllegalArgumentException("Bad time format");
209             System.out.println("Bad time format. The format should be HH:MM");
210         }
211     }
212     
213     /**
214      * Speaks the time given the hour and minute.
215      *
216      * @param hour the hour of the day (0 to 23)
217      * @param min the minute of the hour (0 to 59)
218      */
219     public void timeToSpeech(int hour, int min) {
220         if (hour < 0 || hour > 23) {
221             throw new IllegalArgumentException("Bad time format: hour");
222         }
223
224         if (min < 0 || min > 59) {
225             throw new IllegalArgumentException("Bad time format: min");
226         }
227
228         String theTime = TimeUtils.timeToString(hour, min);
229
230         synthesizer.speakPlainText(theTime, null);
231     }
232
233     /**
234      * Speaks the given time.  Prints an error message if the time
235      * is ill-formed.
236      *
237      * @param time the time in the form HH:MM
238      */
239     public void safeTimeToSpeech(String time) {
240         try {
241             if (time.equals("now")) {
242                 speakNow();
243             } else {
244                 timeToSpeech(time);
245             }
246         } catch (IllegalArgumentException iae) {
247             System.err.println("Bad time format");
248         }
249     }
250
251     /**
252      * Tells the current time.
253      */
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);
260     }
261
262     /**
263      * Closes things down
264      */
265     public void close() {
266         try {
267             synthesizer.deallocate();
268         } catch (EngineException ee) {
269             System.out.println("Trouble deallocating synthesizer: " + ee);
270         }
271     }
272
273     public static void main(String[] args) {
274
275         /* List all the "time" domain voices, which are voices that
276          * are only capable of speaking the time of day.
277          */
278         listAllVoices("time");
279
280         String voiceName = (args.length > 0)
281             ? args[0]
282             : "alan";
283         
284         System.out.println();
285         System.out.println("Using voice: " + voiceName);
286         
287         try {
288             JTime jtime = new JTime(voiceName);
289             jtime.speakNow();
290             jtime.interactiveMode();
291             jtime.close();
292         }
293         catch (Exception e) {
294             e.printStackTrace();
295         }
296
297         System.exit(0);
298     }
299 }