/**
* Copyright 2000-2006 DFKI GmbH.
* All Rights Reserved. Use is subject to license terms.
*
* This file is part of MARY TTS.
*
* MARY TTS is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package marytts.modules.phonemiser;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.w3c.dom.Element;
public class Allophone {
private String name;
private final Map<String, String> features;
/**
* Create a new Allophone object from the given XML Element
*
* @param a
* the allophone definition element
* @param featureNames
* the names of features to use for defining the allophone
* @throws IllegalArgumentException
* if a is not as expected
*/
public Allophone(Element a, String[] featureNames) {
name = a.getAttribute("ph");
String vc;
String isTone;
if (name.equals(""))
throw new IllegalArgumentException("Element must have a 'ph' attribute");
if (a.getTagName().equals("consonant")) {
vc = "-";
isTone = "-";
} else if (a.getTagName().equals("vowel")) {
vc = "+";
isTone = "-";
} else if (a.getTagName().equals("silence")) {
vc = "0";
isTone = "-";
} else if (a.getTagName().equals("tone")) {
vc = "0";
isTone = "+";
} else {
throw new IllegalArgumentException("Element must be one of <vowel>, <consonant> and <silence>, but is <"
+ a.getTagName() + ">");
}
Map<String, String> feats = new HashMap<String, String>();
feats.put("vc", vc);
feats.put("isTone", isTone);
for (String f : featureNames) {
feats.put(f, getAttribute(a, f));
}
this.features = Collections.unmodifiableMap(feats);
}
/**
* Return the requested attribute of e, or "0" if there is no such attribute.
*
* @param e
* @param att
* @return "0" if val.equals(""), val otherwise
*/
private String getAttribute(Element e, String att) {
String val = e.getAttribute(att);
if (val.equals(""))
return "0";
return val;
}
public String name() {
return name;
}
public String toString() {
return name;
}
public boolean isVowel() {
return "+".equals(features.get("vc"));
}
public boolean isDiphthong() {
assert isVowel();
return "d".equals(features.get("vlng"));
}
public boolean isSyllabic() {
return isVowel();
}
public boolean isConsonant() {
return "-".equals(features.get("vc"));
}
public boolean isVoiced() {
return isVowel() || "+".equals(features.get("cvox"));
}
public boolean isSonorant() {
return "lnr".contains(features.get("ctype"));
}
public boolean isLiquid() {
return "l".equals(features.get("ctype"));
}
public boolean isNasal() {
return "n".equals(features.get("ctype"));
}
public boolean isGlide() {
return "r".equals(features.get("ctype")) && !isVowel();
}
public boolean isFricative() {
return "f".equals(features.get("ctype"));
}
public boolean isPlosive() {
return "s".equals(features.get("ctype"));
}
public boolean isAffricate() {
return "a".equals(features.get("ctype"));
}
public boolean isPause() {
return "0".equals(features.get("vc")) && "-".equals(features.get("isTone"));
}
/**
* Whether the Allophone object represents a tone symbol.
*
* @return "+".equals(features.get("isTone"))
*/
public boolean isTone() {
return "+".equals(features.get("isTone"));
}
public int sonority() {
if (isVowel()) {
String vlng = features.get("vlng");
if (vlng == null)
return 5; // language doesn't make a distinction between vowels of different length
if ("ld".contains(vlng))
return 6;
else if ("s".equals(vlng))
return 5;
else if ("a".equals(vlng))
return 4;
else
return 5; // unknown vowel length
} else if (isSonorant())
return 3;
else if (isFricative())
return 2;
return 1;
}
/**
* Get the key-value map of features and feature values for this allophone.
*
* @return an unmodifiable map.
*/
public Map<String, String> getFeatures() {
return features;
}
/**
* Return the feature with name feat. Three types of values are possible: 1. an informative feature; 2. the value "0" to
* indicate that the feature exists but is not meaningful for this allophone; 3. null to indicate that the feature does not
* exist.
*
* @param feat
* feat
* @return the feature value, or null
*/
public String getFeature(String feat) {
return features.get(feat);
}
}