001/** 002 * Copyright 2003 Sun Microsystems, Inc. 003 * 004 * See the file "license.terms" for information on usage and 005 * redistribution of this file, and for a DISCLAIMER OF ALL 006 * WARRANTIES. 007 */ 008package com.sun.speech.freetts.jsapi; 009 010import java.util.Locale; 011import java.util.Vector; 012 013import javax.speech.EngineCentral; 014import javax.speech.EngineList; 015import javax.speech.EngineModeDesc; 016 017import com.sun.speech.freetts.ValidationException; 018import com.sun.speech.freetts.Voice; 019 020 021/** 022 * Supports the EngineCentral JSAPI 1.0 interface for the 023 * FreeTTSSynthesizer. To use a FreeTTSSynthesizer, you should place 024 * a line into the speech.properties file as so: 025 * 026 * <pre> 027 * FreeTTSSynthEngineCentral=com.sun.speech.freetts.jsapi.FreeTTSEngineCentral 028 * </pre> 029 * 030 */ 031 032public class FreeTTSEngineCentral implements EngineCentral { 033 private static final String ENGINE_NAME = "FreeTTS Synthesizer"; 034 035 /** 036 * Creates a FreeTTSEngineCentral 037 */ 038 public FreeTTSEngineCentral() throws Exception { 039 // Note that the JSAPI layer currently is silent 040 // about any exceptions thrown from here, so we are noisy here 041 } 042 043 /** 044 * Returns a list containing references to all matching 045 * synthesizers. The mapping of FreeTTS VoiceDirectories and 046 * Voices to JSAPI Synthesizers and Voices is as follows: 047 * 048 * <p><ul> 049 * <li>Each FreeTTS VoiceDirectory specifies the list of FreeTTS 050 * Voices supported by that directory. Each Voice in that 051 * directory specifies its name (e.g., "kevin" "kevin16" "alan"), 052 * domain (e.g., "general" or "time") and locale (e.g., Locale.US). 053 * <li>For all FreeTTS Voices from all VoiceDirectories discovered 054 * by the VoiceManager, this method will group the Voices 055 * according to those that have both a common locale and domain 056 * (e.g, all "general" domain voices for the US local will be 057 * grouped together). 058 * <li>For each group of voices that shares a common locale and 059 * domain, this method generates a new JSAPI SynthesizerModeDesc 060 * with the following attributes: 061 * <ul> 062 * <li>The engine name is of the form: "FreeTTS <locale> 063 * <domain> synthesizer" For example, "FreeTTS en_us general 064 * synthesizer" 065 * <li>The locale is the locale shared by all the voices (e.g., 066 * Locale.US) 067 * <li>The mode name is the domain shared by all the voices 068 * (e.g., "general"). 069 * </ul> 070 * <li>The JSAPI Voices for each resulting Synthesizer will have 071 * the name of the FreeTTS Voice (e.g. "kevin" "kevin16"). 072 * </ul> 073 * 074 * @param require an engine mode that describes the desired 075 * synthesizer 076 * 077 * @return an engineList containing matching engines, or null if 078 * no matching engines are found 079 */ 080 public EngineList createEngineList(EngineModeDesc require) { 081 EngineList el = new EngineList(); 082 083 com.sun.speech.freetts.VoiceManager voiceManager = 084 com.sun.speech.freetts.VoiceManager.getInstance(); 085 086 com.sun.speech.freetts.Voice[] voices = voiceManager.getVoices(); 087 088 // We want to get all combinations of domains and locales 089 Vector domainLocaleVector = new Vector(); 090 for (int i = 0; i < voices.length; i++) { 091 DomainLocale dl = 092 new DomainLocale(voices[i].getDomain(), voices[i].getLocale()); 093 DomainLocale dlentry = (DomainLocale) 094 getItem(domainLocaleVector, dl); 095 if (dlentry == null) { 096 domainLocaleVector.add(dl); 097 dlentry = dl; 098 } 099 dlentry.addVoice(voices[i]); 100 } 101 102 // build list of SynthesizerModeDesc's for each domain/locale 103 // combination 104 for (int i = 0; i < domainLocaleVector.size(); i++) { 105 DomainLocale dl = (DomainLocale) domainLocaleVector.get(i); 106 107 FreeTTSSynthesizerModeDesc desc = new 108 FreeTTSSynthesizerModeDesc("FreeTTS " 109 + dl.getLocale().toString() + " " + dl.getDomain() 110 + " synthesizer", dl.getDomain(), dl.getLocale()); 111 112 // iterate through the voices in a different order 113 voices = dl.getVoices(); 114 for (int j = 0; j < voices.length; j++) { 115 FreeTTSVoice jsapiVoice = new FreeTTSVoice(voices[j], null); 116 desc.addVoice(jsapiVoice); 117 } 118 119 if (require == null || desc.match(require)) { 120 try { 121 desc.validate(); 122 el.addElement(desc); 123 } catch (ValidationException ve) { 124 System.err.println(ve.getMessage()); 125 } 126 } 127 } 128 129 if (el.size() == 0) { 130 el = null; 131 } 132 return el; 133 } 134 135 /** 136 * Gets an item out of a vector. 137 * Warning: linear search 138 * 139 * @param vector the vector to search 140 * @param o the object to look for using vector.get(i).equals(o) 141 * 142 * @return the item if it exists in the vector, else null 143 */ 144 private Object getItem(Vector vector, Object o) { 145 for (int i = 0; i < vector.size(); i++) { 146 if (vector.get(i).equals(o)) { 147 return vector.get(i); 148 } 149 } 150 return null; 151 } 152} 153 154 155/** 156 * Used to be able to generate a list of voices based on unique 157 * combinations of domain/locale pairs. 158 */ 159class DomainLocale { 160 private String domain; 161 private Locale locale; 162 private Vector<Voice> voices; 163 164 /** 165 * Constructor 166 * 167 * @param domain the domain to use 168 * @param locale the locale to use 169 */ 170 public DomainLocale(String domain, Locale locale) { 171 this.domain = domain; 172 this.locale = locale; 173 this.voices = new Vector<Voice>(); 174 } 175 176 /** 177 * See if two DomainLocale objects are equal. 178 * The voices are NOT compared. 179 * 180 * @param o, the object to compare to 181 * 182 * @return true if the domain and locale are both equal, else 183 * false 184 */ 185 public boolean equals(Object o) { 186 if (! (o instanceof DomainLocale)) { 187 return false; 188 } 189 return (domain.equals(((DomainLocale) o).getDomain()) 190 && locale.equals(((DomainLocale) o).getLocale())); 191 } 192 193 /** 194 * Gets the domain. 195 * @return the domain 196 */ 197 public String getDomain() { 198 return domain; 199 } 200 201 /** 202 * Gets the locale. 203 * @return the locale 204 */ 205 public Locale getLocale() { 206 return locale; 207 } 208 209 /** 210 * Adds a voice to this instance. 211 * 212 * @param voice the voice to add 213 */ 214 public void addVoice(com.sun.speech.freetts.Voice voice) { 215 voices.add(voice); 216 } 217 218 /** 219 * Gets the voices of this instance. 220 * 221 * @return all of the voices that have been added to this 222 * instance. 223 */ 224 public com.sun.speech.freetts.Voice[] getVoices() { 225 com.sun.speech.freetts.Voice[] voiceArray = 226 new com.sun.speech.freetts.Voice[voices.size()]; 227 return (com.sun.speech.freetts.Voice[]) voices.toArray(voiceArray); 228 } 229}