2 * Copyright 2001 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 package com.sun.speech.engine.synthesis.text;
10 import javax.speech.Engine;
11 import javax.speech.synthesis.Speakable;
12 import javax.speech.synthesis.SpeakableEvent;
14 import com.sun.speech.engine.synthesis.BaseSynthesizer;
15 import com.sun.speech.engine.synthesis.BaseSynthesizerQueueItem;
18 import java.io.IOException;
20 import org.w3c.dom.Document;
21 import org.w3c.dom.Node;
22 import org.w3c.dom.Element;
23 import org.w3c.dom.Text;
26 * Represents an object on the speech output queue of a
27 * <code>TextSynthesizer</code>.
29 public class TextSynthesizerQueueItem extends BaseSynthesizerQueueItem {
30 static public final String JSML = "jsml";
31 static public final String[] JSML_ATTRIBUTES = {
35 static public final String DIV = "div";
36 static public final String[] DIV_ATTRIBUTES = {
40 static public final String VOICE = "voice";
41 static public final String[] VOICE_ATTRIBUTES = {
42 "voice", "gender", "age", "variant", "name", "mark"
45 static public final String SAYAS = "sayas";
46 static public final String[] SAYAS_ATTRIBUTES = {
50 static public final String PHONEME = "phoneme";
51 static public final String[] PHONEME_ATTRIBUTES = {
55 static public final String EMPHASIS = "emphasis";
56 static public final String[] EMPHASIS_ATTRIBUTES = {
60 static public final String BREAK = "break";
61 static public final String[] BREAK_ATTRIBUTES = {
62 "size", "time", "mark"
65 static public final String PROSODY = "prosody";
66 static public final String[] PROSODY_ATTRIBUTES = {
67 "rate", "volume", "pitch", "range", "mark"
70 static public final String MARKER = "marker";
71 static public final String[] MARKER_ATTRIBUTES = {
75 static public final String ENGINE = "engine";
76 static public final String[] ENGINE_ATTRIBUTES = {
77 "name", "data", "mark"
80 static public final String[] ELEMENTS = {
93 static public final String[][] ELEMENT_ATTRIBUTES = {
108 * Commands to be encoded in the text.
110 static public final String COMMAND_PREFIX = "/";
111 static public final String COMMAND_SUFFIX = "/";
112 static public final String DATA_PREFIX = "[";
113 static public final String DATA_SUFFIX = "]";
114 static public final String ELEMENT_START = "start";
115 static public final String ELEMENT_END = "end";
120 public TextSynthesizerQueueItem() {
125 * Gets the type of this queue item.
127 * @return a <code>String</code> for debug purposes
129 public String getTypeString() {
131 return "Plain-text String";
132 } else if (getSource() instanceof String) {
133 return "JSML from String";
134 } else if (getSource() instanceof Speakable) {
135 return "JSML from Speakable";
136 } else if (getSource() instanceof URL) {
137 return "JSML from URL";
139 return "Unknown Output";
144 * Appends the text for this node to the given StringBuffer.
146 * @param n the node to traverse in depth-first order
147 * @param buf the buffer to append text to
149 protected void linearize(Node n, StringBuffer buf) {
150 StringBuffer endText = processNode(n, buf);
151 for (Node child = n.getFirstChild();
153 child = child.getNextSibling()) {
154 linearize(child, buf);
157 if (endText != null) {
163 * Adds text for just this node, and returns any text that might
164 * be needed to undo the effects of this node after it is
167 * @param n the node to traverse in depth-first order
168 * @param buf the buffer to append text to
170 * @return a <code>String</code> containing text to undo the
171 * effects of the node
173 protected StringBuffer processNode(Node n, StringBuffer buf) {
174 StringBuffer endText = null;
176 int type = n.getNodeType();
178 case Node.ATTRIBUTE_NODE:
181 case Node.DOCUMENT_NODE:
184 case Node.ELEMENT_NODE:
185 endText = processElement((Element) n, buf);
189 buf.append(((Text) n).getData());
192 // Pass processing instructions (e.g., <?blah?>
193 // right on to the synthesizer. These types of things
194 // probably should not be used. Instead the 'engine'
195 // element is probably the best thing to do.
197 case Node.PROCESSING_INSTRUCTION_NODE:
200 // The document type had better be JSML.
202 case Node.DOCUMENT_TYPE_NODE:
205 // I think NOTATION nodes are only DTD's.
207 case Node.NOTATION_NODE:
210 // Should not get COMMENTS because the JSMLParser
213 case Node.COMMENT_NODE:
216 // Should not get CDATA because the JSMLParser is
219 case Node.CDATA_SECTION_NODE:
222 // Should not get ENTITY related notes because
223 // entities are expanded by the JSMLParser
225 case Node.ENTITY_NODE:
226 case Node.ENTITY_REFERENCE_NODE:
229 // Should not get DOCUMENT_FRAGMENT nodes because I
230 // [[[WDW]]] think they are only created via the API's
231 // and cannot be defined via content.
233 case Node.DOCUMENT_FRAGMENT_NODE:
244 * Adds any commands for this element and returns any text that might
245 * be needed to undo the effects of this element after it is processed.
247 * @param element the element to traverse in depth-first order
248 * @param buf the buffer to append text to
250 * @return a <code>String</code> containing text to undo the
251 * effects of the element
253 protected StringBuffer processElement(Element element, StringBuffer buf) {
254 StringBuffer endText;
255 StringBuffer attributeText = null;
257 String elementName = element.getTagName();
258 for (int i = 0; i < ELEMENTS.length; i++) {
259 if (ELEMENTS[i].equals(elementName)) {
260 attributeText = processAttributes(
261 element, ELEMENT_ATTRIBUTES[i]);
266 buf.append(COMMAND_PREFIX + elementName + " " + ELEMENT_START);
267 if (attributeText != null) {
268 buf.append(attributeText);
270 buf.append(COMMAND_SUFFIX);
272 endText = new StringBuffer(
273 COMMAND_PREFIX + elementName + " " + ELEMENT_END);
274 if (attributeText != null) {
275 endText.append(attributeText);
277 endText.append(COMMAND_SUFFIX);
283 * Gets the list of attributes of the element and returns them in
284 * a <code>StringBuffer</code>.
286 * @param element the element containing attributes (if any)
287 * @param attributes the allowed attributes for
288 * <code>element</code>
290 * @return a buffer containing the attributes in text form
292 protected StringBuffer processAttributes(Element element,
293 String[] attributes) {
294 StringBuffer attributeText = new StringBuffer();
295 for (int i = 0; i < attributes.length; i++) {
296 if (element.hasAttribute(attributes[i])) {
297 String data = element.getAttribute(attributes[i]);
298 attributeText.append(
299 DATA_PREFIX + attributes[i] + "=" + data + DATA_SUFFIX);
302 return attributeText;
306 * Gets the text form of this queue item.
308 * @return the text form of this queue item.
310 public String getEngineText() {
314 StringBuffer textBuffer = new StringBuffer();
315 Document document = getDocument();
316 linearize(document, textBuffer);
317 return(textBuffer.toString());