upstream version 1.2.2
[debian/freetts] / com / sun / speech / freetts / en / us / PronounceableFSM.java
1 /**
2  * Portions Copyright 2001 Sun Microsystems, Inc.
3  * Portions Copyright 1999-2001 Language Technologies Institute, 
4  * Carnegie Mellon University.
5  * All Rights Reserved.  Use is subject to license terms.
6  * 
7  * See the file "license.terms" for information on usage and
8  * redistribution of this file, and for a DISCLAIMER OF ALL 
9  * WARRANTIES.
10  */
11 package com.sun.speech.freetts.en.us;
12
13 import java.io.BufferedReader;
14 import java.io.IOException;
15 import java.io.InputStream;
16 import java.io.InputStreamReader;
17 import java.net.URL;
18 import java.util.StringTokenizer;
19
20 /**
21  * Implements a finite state machine that checks if a given string
22  * is pronounceable. If it is pronounceable, the method
23  * <code>accept()</code> will return true.
24  */
25 public class PronounceableFSM {
26
27     private static final String VOCAB_SIZE = "VOCAB_SIZE";
28     private static final String NUM_OF_TRANSITIONS = "NUM_OF_TRANSITIONS";
29     private static final String TRANSITIONS = "TRANSITIONS";
30
31
32     /**
33      * The vocabulary size.
34      */
35     protected int vocabularySize;
36
37
38     /**
39      * The transitions of this FSM
40      */
41     protected int[] transitions;
42
43
44     /**
45      * Whether we should scan the input string from the front.
46      */
47     protected boolean scanFromFront;
48
49
50     /**
51      * Constructs a PronounceableFSM with information in the given URL.
52      *
53      * @param url the URL that contains the FSM specification
54      * @param scanFromFront indicates whether this FSM should scan the input
55      * string from the front, or from the back
56      */
57     public PronounceableFSM(URL url, boolean scanFromFront) throws IOException {
58         this.scanFromFront = scanFromFront;
59         InputStream is = url.openStream();
60         loadText(is);
61         is.close();
62     }
63
64
65     /**
66      * Constructs a PronounceableFSM with the given attributes.
67      *
68      * @param vocabularySize the vocabulary size of the FSM
69      * @param transitions the transitions of the FSM
70      * @param scanFromFront indicates whether this FSM should scan the input
71      * string from the front, or from the back
72      */
73     public PronounceableFSM(int vocabularySize, int[] transitions,
74                             boolean scanFromFront) {
75         this.vocabularySize = vocabularySize;
76         this.transitions = transitions;
77         this.scanFromFront = scanFromFront;
78     }
79
80
81     /**
82      * Loads the ASCII specification of this FSM from the given InputStream.
83      *
84      * @param is the input stream to load from
85      *
86      * @throws IOException if an error occurs on input.
87      */
88     private void loadText(InputStream is) throws IOException {
89         BufferedReader reader = new BufferedReader(new InputStreamReader(is));
90         String line = null;
91         while ((line = reader.readLine()) != null) {
92             if (!line.startsWith("***")) {
93                 if (line.startsWith(VOCAB_SIZE)) {
94                     vocabularySize = parseLastInt(line);
95                 } else if (line.startsWith(NUM_OF_TRANSITIONS)) {
96                     int transitionsSize = parseLastInt(line);
97                     transitions = new int[transitionsSize];
98                 } else if (line.startsWith(TRANSITIONS)) {
99                     StringTokenizer st = new StringTokenizer(line);
100                     String transition = st.nextToken();
101                     int i = 0;
102                     while (st.hasMoreTokens() && i < transitions.length) {
103                         transition = st.nextToken().trim();
104                         transitions[i++] = Integer.parseInt(transition);
105                     }
106                 }
107             }
108         }
109         reader.close();
110     }
111
112
113     /**
114      * Returns the integer value of the last integer in the given string.
115      *
116      * @param line the line to parse the integer from
117      *
118      * @return an integer
119      */
120     private int parseLastInt(String line) {
121         String lastInt = line.trim().substring(line.lastIndexOf(" "));
122         return Integer.parseInt(lastInt.trim());
123     }
124
125
126     /**
127      * Causes this FSM to transition to the next state given
128      * the current state and input symbol.
129      *
130      * @param state the current state
131      * @param symbol the input symbol
132      */
133     private int transition(int state, int symbol) {
134         for (int i = state; i < transitions.length; i++) {
135             if ((transitions[i] % vocabularySize) == symbol) {
136                 return (transitions[i] / vocabularySize);
137             }
138         }
139         return -1;
140     }
141
142
143     /**
144      * Checks to see if this finite state machine accepts the given
145      * input string.
146      *
147      * @param inputString the input string to be tested
148      *
149      * @return true if this FSM accepts, false if it rejects
150      */
151     public boolean accept(String inputString) {
152         int symbol;
153         int state = transition(0, '#');
154         int leftEnd = inputString.length() - 1;
155         int start = (scanFromFront) ? 0 : leftEnd;
156         
157         for (int i = start; 0 <= i && i <= leftEnd; ) {
158             char c = inputString.charAt(i);
159             if (c == 'n' || c == 'm') {
160                 symbol = 'N';
161             } else if ("aeiouy".indexOf(c) != -1) {
162                 symbol = 'V';
163             } else {
164                 symbol = c;
165             }
166             state = transition(state, symbol);
167             if (state == -1) {
168                 return false;
169             } else if (symbol == 'V') {
170                 return true;
171             }
172             if (scanFromFront) {
173                 i++;
174             } else {
175                 i--;
176             }
177         }
178         return false;
179     }
180 }
181
182
183
184
185
186