001 002package ca.bc.webarts.tools; 003//import com.sun.speech.freetts.util.Utilities; 004 005import java.io.BufferedReader; 006import java.io.File; 007import java.io.IOException; 008import java.io.InputStreamReader; 009 010import java.util.Calendar; 011import java.util.GregorianCalendar; 012import java.util.Locale; 013 014import javax.speech.Central; 015import javax.speech.Engine; 016import javax.speech.EngineList; 017import javax.speech.EngineException; 018import javax.speech.synthesis.Synthesizer; 019import javax.speech.synthesis.SynthesizerModeDesc; 020import javax.speech.synthesis.SynthesizerProperties; 021import javax.speech.synthesis.Voice; 022//import com.sun.speech.freetts.util.Utilities; 023 024import ca.bc.webarts.widgets.Util; 025 026 027/** 028 * Simple program showing how to use the Limited Domain (time) FreeTTS 029 * synthesizer. 030 * 031 * @author TGutwin 032 */ 033public class JVoice implements Runnable 034{ 035 036 private Synthesizer synthesizer; 037 private boolean initialized_ = false; 038 private static boolean activeThread_ = false; 039 private static JVoice singletonInstance= null; 040 private static String [] textToRead_ = {""}; 041 private static boolean verboseOutput_ = true; 042 043 044 /** 045 * Construct a default JVoice object. It creates the Limited Domain 046 * synthesizer. 047 */ 048 private JVoice() 049 { 050 try 051 { 052 // Create a new SynthesizerModeDesc that will match the FreeTTS 053 // Synthesizer. 054 /*SynthesizerModeDesc desc = new SynthesizerModeDesc 055 ("Limited domain FreeTTS Speech Synthesizer from Sun Labs", 056 null, 057 Locale.US, 058 Boolean.FALSE, 059 null);*/ 060 SynthesizerModeDesc desc = new SynthesizerModeDesc( 061 null, // engine name 062 "general", // mode name 063 Locale.US, // locale 064 null, // running 065 null); // voice 066 synthesizer = Central.createSynthesizer(desc); 067 068 if (synthesizer == null) 069 { 070 String message = "Can't find synthesizer.\n" + 071 "Make sure that there is a \"speech.properties\" file " + 072 "at either of these locations: \n"; 073 message += "user.home : " + 074 System.getProperty("user.home") + "\n"; 075 message += "java.home/lib: " + System.getProperty("java.home") 076 + File.separator + "lib\n"; 077 078 System.err.println(message); 079 initialized_ = false; 080 } 081 else 082 { 083 084 // create the voice 085 String systemVoiceName = System.getProperty("voiceName", "kevin16"); 086 087 Voice systemVoice = new Voice(systemVoiceName, Voice.GENDER_DONT_CARE, Voice.AGE_DONT_CARE, null); 088 089 // here are some other ones.... 090 Voice voiceLQ = new Voice("kevin", Voice.GENDER_DONT_CARE, Voice.AGE_DONT_CARE, null); 091 Voice voiceHQ = new Voice("kevin16", Voice.GENDER_DONT_CARE, Voice.AGE_DONT_CARE, null); 092 Voice voiceAlan = new Voice("alan", Voice.GENDER_DONT_CARE, Voice.AGE_DONT_CARE, null); 093 094 // get it ready to speak 095 synthesizer.allocate(); 096 synthesizer.waitEngineState(Synthesizer.ALLOCATED); 097 synthesizer.resume(); 098 synthesizer.getSynthesizerProperties().setVoice(systemVoice); 099 initialized_ = true; 100 } 101 } 102 catch (Exception e) 103 { 104 e.printStackTrace(); 105 } 106 } 107 108 109 /** Gets the singleton for this class **/ 110 public static JVoice getInstance() 111 { 112 JVoice retVal = null; 113 if (singletonInstance != null && singletonInstance.isInitialized()) 114 retVal = singletonInstance; 115 else 116 { 117 // create a new one 118 retVal = new JVoice(); 119 } 120 return retVal; 121 } 122 123 124 /* Implements the Runnable by override run() method in interface */ 125 public void run() 126 { 127 activeThread_ = true; 128 //System.out.println("JVoice Thread: run()"); 129 readText(); 130 activeThread_ = false; 131 } 132 133 134 /* waits until the read thread is done before returning */ 135 public void blockUntilDoneVoicing() 136 { 137 while (activeThread_) 138 Util.sleep(500); 139 } 140 141 142 public void setTextToRead(String textToRead) 143 { 144 String [] txt = {textToRead}; 145 setTextToRead(txt); 146 } 147 148 149 public void setTextToRead(String[] textToRead) 150 { 151 textToRead_ = textToRead; 152 } 153 154 155 /* a simple helper to inform if this class singleton has been init. */ 156 public boolean isInitialized(){return initialized_;} 157 158 159 /** 160 * Example of how to list all the known voices for a specific 161 * mode using just JSAPI. FreeTTS maps the domain name to the 162 * JSAPI mode name. The currently supported domains are 163 * "general," which means general purpose synthesis for tasks 164 * such as reading e-mail, and "time" which means a domain that's 165 * only good for speaking the time of day. 166 */ 167 public static void listAllVoices(String modeName) 168 { 169 System.out.println(); 170 System.out.print( 171 "All " + modeName + " Mode JSAPI Synthesizers and Voices "); 172 173 /* Create a template that tells JSAPI what kind of speech 174 * synthesizer we are interested in. In this case, we're 175 * just looking for a general domain synthesizer for US 176 * English. 177 */ 178 SynthesizerModeDesc required = new SynthesizerModeDesc( 179 null, // engine name 180 modeName, // mode name 181 Locale.US, // locale 182 null, // running 183 null); // voices 184 185 /* Contact the primary entry point for JSAPI, which is 186 * the Central class, to discover what synthesizers are 187 * available that match the template we defined above. 188 */ 189 EngineList engineList = Central.availableSynthesizers(required); 190 if(engineList!=null) System.out.println(" [" + engineList.size() + "]"); 191 for (int i = 0; i < engineList.size(); i++) { 192 193 SynthesizerModeDesc desc = (SynthesizerModeDesc) engineList.get(i); 194 System.out.println(" " + desc.getEngineName() 195 + " (mode=" + desc.getModeName() 196 + ", locale=" + desc.getLocale() + "):"); 197 Voice[] voices = desc.getVoices(); 198 for (int j = 0; j < voices.length; j++) { 199 System.out.println(" " + voices[j].getName()); 200 } 201 } 202 } 203 204 205 /** some simple test routines. **/ 206 private static void runTests(String[] argv) 207 { 208 listAllVoices("general"); 209 if (argv!= null && argv.length >1) 210 { 211 try 212 { 213 String sentence = ""; 214 JVoice jVoice = JVoice.getInstance(); 215 216 for (int i=1; i <argv.length; i++) 217 sentence += argv[i]+" "; 218 if (jVoice.isInitialized()) 219 { 220 jVoice.readText("J-Voice Test 1:"); 221 jVoice.readText(sentence); 222 //jVoice.close(); 223 } 224 jVoice = JVoice.getInstance(); 225 if (jVoice.isInitialized()) 226 { 227 jVoice.readText("J-Voice Test 2:"); 228 jVoice.readText(sentence); 229 //jVoice.close(); 230 } 231 jVoice.close(); 232 } 233 catch (Exception e) 234 { 235 e.printStackTrace(); 236 } 237 } 238 } 239 240 /** 241 * The main program for the JVoice class 242 * 243 * @param argv The command line arguments 244 */ 245 public static void main(String[] argv) 246 { 247 if (argv!= null && argv.length >0 && argv[0].equals("test")) 248 { 249 // Run Some tests 250 System.out.println("JVoice: Test Mode."); 251 JVoice jVoice = JVoice.getInstance(); 252 jVoice.runTests(argv); 253 } 254 else 255 { 256 try 257 { 258 if (verboseOutput_) 259 System.out.println("JVoice: Voicing a Sentence."); 260 String sentence = ""; 261 for (int i=0; i <argv.length; i++) 262 sentence += argv[i]+" "; 263 JVoice jVoice = JVoice.getInstance(); 264 if (jVoice.isInitialized()) 265 { 266 try 267 { 268 if (verboseOutput_) 269 System.out.println("JVoice: Start " + sentence); 270 jVoice.setTextToRead(argv); 271 (new Thread(jVoice)).start(); 272 jVoice.activeThread_ = true; 273 while (jVoice.activeThread_) 274 Util.sleep(500); 275 //jVoice.readText(sentence); 276 jVoice.close(); 277 } 278 catch (Exception ex) 279 { 280 if (jVoice != null) 281 jVoice.close(); 282 ex.printStackTrace(); 283 } 284 } 285 else 286 System.out.println("JVoice: Can't Initialize Speech Engine"); 287 jVoice = null; 288 } 289 catch (Exception e) 290 { 291 e.printStackTrace(); 292 } 293 } 294 295 System.exit(0); 296 } 297 298 299 /** 300 * Reads the text in this class's textToRead_ field. 301 * 302 */ 303 synchronized public void readText() 304 { 305 if (textToRead_ != null && textToRead_.length > 0) 306 { 307 String sentence = ""; 308 for (int i=0; i <textToRead_.length; i++) 309 sentence += textToRead_[i]+" "; 310 readText(sentence); 311 } 312 } 313 314 315 /** 316 * Reads an array of Strings. 317 * 318 * @param theTextArray An Array of Strings to read. 319 */ 320 synchronized public void readText(String [] theTextArray) 321 { 322 if (theTextArray != null && theTextArray.length > 0) 323 { 324 textToRead_ = theTextArray; 325 readText(); 326 } 327 } 328 329 330 /** 331 * Reads text from the console and gives it to the synthesizer to speak. 332 * 333 * @param theText Description of the Parameter 334 */ 335 synchronized public void readText(String theText) 336 { 337 if (synthesizer != null && initialized_) 338 { 339 if (verboseOutput_) 340 System.out.println("JVoice: Attempting to read the following sentence:"); 341 342 if (theText != null && !(theText.equals(""))) 343 { 344 if (verboseOutput_) 345 System.out.print(" "+ theText); 346 synthesizer.speakPlainText(theText, null); 347 if (verboseOutput_) 348 System.out.println(" !"); 349 } 350 351 try 352 { 353 // wait 'till speaking is done 354 //System.out.println("JVoice: Waiting for the QUEUE to empty before proceeding"); 355 synthesizer.waitEngineState(Synthesizer.QUEUE_EMPTY); 356 //System.out.println("! Done"); 357 } 358 catch (java.lang.InterruptedException ie) 359 { 360 System.out.println("JVoice: readText(String): Interupted: " + ie); 361 } 362 } 363 else 364 { 365 System.out.println("JVoice: NOT Initialized"); 366 } 367 } 368 369 370 /** Closes things down */ 371 public void close() 372 { 373 //System.out.println("JVoice: close(): synthesizer==null ->"+ (synthesizer==null)); 374 if (synthesizer != null) 375 { 376 try 377 { 378 try 379 { 380 // wait till speaking is done 381 synthesizer.waitEngineState(Synthesizer.QUEUE_EMPTY); 382 } 383 catch (java.lang.InterruptedException ie) 384 { 385 System.out.println("JVoice: close(): Interupted: " + ie); 386 } 387 synthesizer.deallocate(); 388 synthesizer = null; 389 this.initialized_ = false; 390 } 391 catch (EngineException ee) 392 { 393 System.out.println("JVoice: close(): Trouble deallocating synthesizer: " + ee); 394 } 395 catch (Exception e) 396 { 397 e.printStackTrace(); 398 } 399 } 400 } 401} 402 403