upstream version 1.2.2
[debian/freetts] / com / sun / speech / freetts / jsapi / FreeTTSEngineCentral.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 package com.sun.speech.freetts.jsapi;
9
10 import java.util.Locale;
11 import java.util.Vector;
12
13 import javax.speech.EngineCentral;
14 import javax.speech.EngineList;
15 import javax.speech.EngineModeDesc;
16
17 import com.sun.speech.freetts.ValidationException;
18
19
20 /**
21  * Supports the EngineCentral JSAPI 1.0 interface for the
22  * FreeTTSSynthesizer.  To use a FreeTTSSynthesizer, you should place 
23  * a line into the speech.properties file as so:
24  *
25  * <pre>
26  * FreeTTSSynthEngineCentral=com.sun.speech.freetts.jsapi.FreeTTSEngineCentral
27  * </pre>
28  *
29  */
30
31 public class FreeTTSEngineCentral implements EngineCentral {
32     private String engineName = "FreeTTS Synthesizer";
33
34     /**
35      * Creates a FreeTTSEngineCentral
36      */
37     public FreeTTSEngineCentral() throws Exception {
38         // Note that the JSAPI layer currently is silent
39         // about any exceptions thrown from here, so we are noisy here
40     }
41
42     /**
43      * Returns a list containing references to all matching 
44      * synthesizers.  The mapping of FreeTTS VoiceDirectories and
45      * Voices to JSAPI Synthesizers and Voices is as follows:
46      *
47      * <p><ul>
48      * <li>Each FreeTTS VoiceDirectory specifies the list of FreeTTS
49      * Voices supported by that directory.  Each Voice in that
50      * directory specifies its name (e.g., "kevin" "kevin16" "alan"),
51      * domain (e.g., "general" or "time") and locale (e.g., Locale.US).
52      * <li>For all FreeTTS Voices from all VoiceDirectories discovered
53      * by the VoiceManager, this method will group the Voices
54      * according to those that have both a common locale and domain
55      * (e.g, all "general" domain voices for the US local will be
56      * grouped together).
57      * <li>For each group of voices that shares a common locale and
58      * domain, this method generates a new JSAPI SynthesizerModeDesc
59      * with the following attributes:
60      *   <ul>
61      *   <li>The engine name is of the form: "FreeTTS &lt;locale>
62      *   &lt;domain> synthesizer"  For example, "FreeTTS en_us general
63      *   synthesizer"
64      *   <li>The locale is the locale shared by all the voices (e.g.,
65      *   Locale.US)
66      *   <li>The mode name is the domain shared by all the voices
67      *   (e.g., "general").
68      *   </ul>
69      * <li>The JSAPI Voices for each resulting Synthesizer will have
70      * the name of the FreeTTS Voice (e.g. "kevin" "kevin16").
71      * </ul>
72      *
73      * @param require  an engine mode that describes the desired
74      *                  synthesizer
75      *
76      * @return an engineList containing matching engines, or null if
77      *          no matching engines are found
78      */
79     public EngineList createEngineList(EngineModeDesc require) {
80         EngineList el = new EngineList();
81
82         com.sun.speech.freetts.VoiceManager voiceManager =
83             com.sun.speech.freetts.VoiceManager.getInstance();
84         
85         com.sun.speech.freetts.Voice[] voices = voiceManager.getVoices();
86
87         // We want to get all combinations of domains and locales
88         Vector domainLocaleVector = new Vector();
89         for (int i = 0; i < voices.length; i++) {
90             DomainLocale dl =
91                 new DomainLocale(voices[i].getDomain(), voices[i].getLocale());
92             DomainLocale dlentry = (DomainLocale)
93                 getItem(domainLocaleVector, dl);
94             if (dlentry == null) {
95                 domainLocaleVector.add(dl);
96                 dlentry = dl;
97             }
98             dlentry.addVoice(voices[i]);
99         }
100
101         // build list of SynthesizerModeDesc's for each domain/locale
102         // combination
103         for (int i = 0; i < domainLocaleVector.size(); i++) {
104             DomainLocale dl = (DomainLocale) domainLocaleVector.get(i);
105
106             FreeTTSSynthesizerModeDesc desc = new
107                 FreeTTSSynthesizerModeDesc("FreeTTS "
108                         + dl.getLocale().toString() + " " + dl.getDomain()
109                         + " synthesizer", dl.getDomain(), dl.getLocale());
110
111             // iterate through the voices in a different order
112             voices = dl.getVoices();
113             for (int j = 0; j < voices.length; j++) {
114                 FreeTTSVoice jsapiVoice = new FreeTTSVoice(voices[j], null);
115                 desc.addVoice(jsapiVoice);
116             }
117
118             if (require == null || desc.match(require)) {
119                 try {
120                     desc.validate();
121                     el.addElement(desc);
122                 } catch (ValidationException ve) {
123                     System.err.println(ve.getMessage());
124                 }
125             }
126         }
127
128         if (el.size() == 0) {
129             el = null;
130         }
131         return el;
132     }
133
134     /**
135      * Gets an item out of a vector.
136      * Warning: linear search
137      *
138      * @param vector the vector to search
139      * @param o the object to look for using vector.get(i).equals(o)
140      *
141      * @return the item if it exists in the vector, else null
142      */
143     private Object getItem(Vector vector, Object o) {
144         for (int i = 0; i < vector.size(); i++) {
145             if (vector.get(i).equals(o)) {
146                 return vector.get(i);
147             }
148         }
149         return null;
150     }
151 }
152
153
154 /**
155  * Used to be able to generate a list of voices based on unique
156  * combinations of domain/locale pairs.
157  */
158 class DomainLocale {
159     private String domain;
160     private Locale locale;
161     private Vector voices;
162
163     /**
164      * Constructor
165      *
166      * @param domain the domain to use
167      * @param locale the locale to use
168      */
169     public DomainLocale(String domain, Locale locale) {
170         this.domain = domain;
171         this.locale = locale;
172         this.voices = new Vector();
173     }
174
175     /**
176      * See if two DomainLocale objects are equal.
177      * The voices are NOT compared.
178      *
179      * @param o, the object to compare to
180      *
181      * @return true if the domain and locale are both equal, else
182      * false
183      */
184     public boolean equals(Object o) {
185         if (! (o instanceof DomainLocale)) {
186             return false;
187         }
188         return (domain.equals(((DomainLocale) o).getDomain())
189                 && locale.equals(((DomainLocale) o).getLocale()));
190     }
191
192     /**
193      * Gets the domain.
194      * @return the domain
195      */
196     public String getDomain() {
197         return domain;
198     }
199
200     /**
201      * Gets the locale.
202      * @return the locale
203      */
204     public Locale getLocale() {
205         return locale;
206     }
207
208     /**
209      * Adds a voice to this instance.
210      *
211      * @param voice the voice to add
212      */
213     public void addVoice(com.sun.speech.freetts.Voice voice) {
214         voices.add(voice);
215     }
216
217     /**
218      * Gets the voices of this instance.
219      *
220      * @return all of the voices that have been added to this
221      * instance.
222      */
223     public com.sun.speech.freetts.Voice[] getVoices() {
224         com.sun.speech.freetts.Voice[] voiceArray =
225             new com.sun.speech.freetts.Voice[voices.size()];
226         return (com.sun.speech.freetts.Voice[]) voices.toArray(voiceArray);
227     }
228 }