/**
* Copyright 2000-2009 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.features;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.logging.Logger;
import marytts.datatypes.MaryData;
import marytts.datatypes.MaryDataType;
import marytts.datatypes.MaryXML;
import marytts.features.MaryGenericFeatureProcessors.TargetElementNavigator;
import marytts.server.MaryProperties;
import marytts.unitselection.select.HalfPhoneTarget;
import marytts.unitselection.select.Target;
import marytts.util.dom.MaryDomUtils;
import org.apache.log4j.BasicConfigurator;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.traversal.NodeIterator;
public class FeatureProcessorIT {
private static MaryData acoustparams;
private static List<Target> phoneTargets;
private static List<Target> halfphoneTargets;
private static FeatureProcessorManager mgr;
@BeforeClass
public static void setupClass() throws Exception {
BasicConfigurator.configure();
acoustparams = new MaryData(MaryDataType.ACOUSTPARAMS, Locale.ENGLISH);
acoustparams.readFrom(FeatureProcessorIT.class.getResourceAsStream("test1.acoustparams"));
phoneTargets = new ArrayList<Target>();
halfphoneTargets = new ArrayList<Target>();
Document doc = acoustparams.getDocument();
NodeIterator segs = MaryDomUtils.createNodeIterator(doc, doc, MaryXML.PHONE, MaryXML.BOUNDARY);
Element s;
while ((s = (Element) segs.nextNode()) != null) {
String phone;
if (s.getTagName().equals(MaryXML.PHONE))
phone = s.getAttribute("p");
else
phone = "_"; // boundary --> pause
phoneTargets.add(new Target(phone, s));
halfphoneTargets.add(new HalfPhoneTarget(phone, s, true));
halfphoneTargets.add(new HalfPhoneTarget(phone, s, false));
}
try {
if (System.getProperty("mary.base") == null) {
System.setProperty("mary.base", ".");
Logger.global.warning("System property 'mary.base' is not defined -- trying " + new File(".").getAbsolutePath()
+ " -- if this fails, please start this using VM property \"-Dmary.base=/path/to/mary/runtime\"!");
}
mgr = new marytts.features.FeatureProcessorManager("en_US");
} catch (Exception e) {
e.printStackTrace();
}
}
@Before
public void setUp() throws Exception {
}
@Test
public void haveAcoustparams() {
assertNotNull(acoustparams);
assertNotNull(acoustparams.getDocument());
}
@Test
public void haveTargets() {
assertNotNull(phoneTargets);
assertNotNull(halfphoneTargets);
assertTrue(phoneTargets.size() > 0);
assertTrue(phoneTargets.size() * 2 == halfphoneTargets.size());
}
@Test
public void sameNumberOfTargetsAndSegments() {
NodeList segs = acoustparams.getDocument().getElementsByTagName(MaryXML.PHONE);
NodeList boundaries = acoustparams.getDocument().getElementsByTagName(MaryXML.BOUNDARY);
assertEquals(segs.getLength() + boundaries.getLength(), phoneTargets.size());
}
@Test
public void targetHasMatchingXML() {
for (Target p : phoneTargets) {
targetHasMatchingXML(p);
}
for (Target p : halfphoneTargets) {
targetHasMatchingXML(p);
}
}
private void targetHasMatchingXML(Target p) {
Element sOrB = p.getMaryxmlElement();
assertNotNull(sOrB);
assertTrue(sOrB.getTagName().equals(MaryXML.PHONE) || sOrB.getTagName().equals(MaryXML.BOUNDARY));
assertTrue(p.getName().equals(getPhoneName(sOrB)));
}
private String getPhoneName(Element segmentOrBoundary) {
if (segmentOrBoundary == null)
return "null";
if (segmentOrBoundary.getTagName().equals(MaryXML.PHONE)) {
return segmentOrBoundary.getAttribute("p");
} else {
return "_";
}
}
@Test
public void segmentNavigators() {
TargetElementNavigator segmentNavigator = new MaryGenericFeatureProcessors.SegmentNavigator();
TargetElementNavigator prevSegmentNavigator = new MaryGenericFeatureProcessors.PrevSegmentNavigator();
TargetElementNavigator nextSegmentNavigator = new MaryGenericFeatureProcessors.NextSegmentNavigator();
TargetElementNavigator prevprevSegmentNavigator = new MaryGenericFeatureProcessors.PrevPrevSegmentNavigator();
TargetElementNavigator nextnextSegmentNavigator = new MaryGenericFeatureProcessors.NextNextSegmentNavigator();
Element prevprev = null;
Element prev = null;
Element seg = phoneTargets.get(0).getMaryxmlElement();
Element next = phoneTargets.get(1).getMaryxmlElement();
for (Target t : phoneTargets) {
assertEquals(
"Mismatch: expected " + getPhoneName(prevprev) + ", got "
+ getPhoneName(prevprevSegmentNavigator.getElement(t)), prevprev,
prevprevSegmentNavigator.getElement(t));
assertEquals(prev, prevSegmentNavigator.getElement(t));
assertEquals(seg, segmentNavigator.getElement(t));
assertEquals(
"Mismatch: expected " + getPhoneName(next) + ", got " + getPhoneName(nextSegmentNavigator.getElement(t)),
next, nextSegmentNavigator.getElement(t));
prevprev = prev;
prev = seg;
seg = next;
next = nextnextSegmentNavigator.getElement(t);
}
}
@Test
public void syllableNavigators() {
TargetElementNavigator syllableNavigator = new MaryGenericFeatureProcessors.SyllableNavigator();
TargetElementNavigator prevSyllableNavigator = new MaryGenericFeatureProcessors.PrevSyllableNavigator();
TargetElementNavigator prevprevSyllableNavigator = new MaryGenericFeatureProcessors.PrevPrevSyllableNavigator();
TargetElementNavigator nextSyllableNavigator = new MaryGenericFeatureProcessors.NextSyllableNavigator();
TargetElementNavigator nextnextSyllableNavigator = new MaryGenericFeatureProcessors.NextNextSyllableNavigator();
NodeList phrases = acoustparams.getDocument().getElementsByTagName(MaryXML.PHRASE);
assertEquals(2, phrases.getLength());
Element phrase1 = (Element) phrases.item(0);
Element phrase2 = (Element) phrases.item(1);
NodeList syllables1 = phrase1.getElementsByTagName(MaryXML.SYLLABLE);
assertEquals(2, syllables1.getLength());
NodeList syllables2 = phrase2.getElementsByTagName(MaryXML.SYLLABLE);
Element lastSylPhrase1 = (Element) syllables1.item(syllables1.getLength() - 1);
Element prevSylPhrase1 = (Element) syllables1.item(syllables1.getLength() - 2);
Element firstSylPhrase2 = (Element) syllables2.item(0);
Element secondSylPhrase2 = (Element) syllables2.item(1);
Element thirdSylPhrase2 = (Element) syllables2.item(2);
Element lastSegPhrase1 = MaryDomUtils.getLastChildElement(lastSylPhrase1);
Element firstSegPhrase2 = MaryDomUtils.getFirstChildElement(firstSylPhrase2);
Target t1 = new Target(getPhoneName(lastSegPhrase1), lastSegPhrase1);
Target t2 = new Target(getPhoneName(firstSegPhrase2), firstSegPhrase2);
assertEquals(lastSylPhrase1, syllableNavigator.getElement(t1));
assertEquals(prevSylPhrase1, prevSyllableNavigator.getElement(t1));
assertNull(prevprevSyllableNavigator.getElement(t1));
// syllable navigator crosses phrase boundaries
assertEquals(firstSylPhrase2, nextSyllableNavigator.getElement(t1));
assertEquals(secondSylPhrase2, nextnextSyllableNavigator.getElement(t1));
// and for the other target:
assertEquals(prevSylPhrase1, prevprevSyllableNavigator.getElement(t2));
assertEquals(lastSylPhrase1, prevSyllableNavigator.getElement(t2));
assertEquals(firstSylPhrase2, syllableNavigator.getElement(t2));
assertEquals(secondSylPhrase2, nextSyllableNavigator.getElement(t2));
assertEquals(thirdSylPhrase2, nextnextSyllableNavigator.getElement(t2));
}
@Test
public void otherNavigators() {
TargetElementNavigator firstSegInWordNavigator = new MaryGenericFeatureProcessors.FirstSegmentInWordNavigator();
TargetElementNavigator firstSegNextWordNavigator = new MaryGenericFeatureProcessors.FirstSegmentNextWordNavigator();
TargetElementNavigator lastSegInWordNavigator = new MaryGenericFeatureProcessors.LastSegmentInWordNavigator();
TargetElementNavigator firstSylInWordNavigator = new MaryGenericFeatureProcessors.FirstSyllableInWordNavigator();
TargetElementNavigator lastSylInWordNavigator = new MaryGenericFeatureProcessors.LastSyllableInWordNavigator();
TargetElementNavigator lastSylInPhraseNavigator = new MaryGenericFeatureProcessors.LastSyllableInPhraseNavigator();
TargetElementNavigator wordNavigator = new MaryGenericFeatureProcessors.WordNavigator();
TargetElementNavigator nextWordNavigator = new MaryGenericFeatureProcessors.NextWordNavigator();
TargetElementNavigator lastWordInSentenceNavigator = new MaryGenericFeatureProcessors.LastWordInSentenceNavigator();
NodeList phrases = acoustparams.getDocument().getElementsByTagName(MaryXML.PHRASE);
assertEquals(2, phrases.getLength());
Element phrase1 = (Element) phrases.item(0);
Element phrase2 = (Element) phrases.item(1);
NodeList syllables1 = phrase1.getElementsByTagName(MaryXML.SYLLABLE);
assertEquals(2, syllables1.getLength());
NodeList syllables2 = phrase2.getElementsByTagName(MaryXML.SYLLABLE);
Element firstSylPhrase1 = (Element) syllables1.item(0);
Element lastSylPhrase1 = (Element) syllables1.item(syllables1.getLength() - 1);
Element prevSylPhrase1 = (Element) syllables1.item(syllables1.getLength() - 2);
Element firstSylPhrase2 = (Element) syllables2.item(0);
Element secondSylPhrase2 = (Element) syllables2.item(1);
Element thirdSylPhrase2 = (Element) syllables2.item(2);
Element lastSylPhrase2 = (Element) syllables2.item(syllables2.getLength() - 1);
Element firstSegPhrase1 = MaryDomUtils.getFirstChildElement(firstSylPhrase1);
Element lastSegPhrase1 = MaryDomUtils.getLastChildElement(lastSylPhrase1);
Element firstSegPhrase2 = MaryDomUtils.getFirstChildElement(firstSylPhrase2);
Element firstWord = (Element) firstSylPhrase1.getParentNode();
Element firstWordPhrase2 = (Element) firstSylPhrase2.getParentNode();
Element lastWord = (Element) lastSylPhrase2.getParentNode();
Target t0 = new Target(getPhoneName(firstSegPhrase1), firstSegPhrase1);
Target t1 = new Target(getPhoneName(lastSegPhrase1), lastSegPhrase1);
Target t2 = new Target(getPhoneName(firstSegPhrase2), firstSegPhrase2);
assertEquals(firstSegPhrase1, firstSegInWordNavigator.getElement(t0));
assertEquals(firstSegPhrase1, firstSegInWordNavigator.getElement(t1));
assertEquals(firstSegPhrase2, firstSegNextWordNavigator.getElement(t0));
assertEquals(firstSegPhrase2, firstSegNextWordNavigator.getElement(t1));
assertEquals(lastSegPhrase1, lastSegInWordNavigator.getElement(t0));
assertEquals(lastSegPhrase1, lastSegInWordNavigator.getElement(t1));
assertEquals(firstSylPhrase1, firstSylInWordNavigator.getElement(t0));
assertEquals(firstSylPhrase1, firstSylInWordNavigator.getElement(t1));
assertEquals(lastSylPhrase1, lastSylInWordNavigator.getElement(t0));
assertEquals(lastSylPhrase1, lastSylInWordNavigator.getElement(t1));
assertEquals(lastSylPhrase1, lastSylInPhraseNavigator.getElement(t0));
assertEquals(lastSylPhrase1, lastSylInPhraseNavigator.getElement(t1));
assertEquals(lastSylPhrase2, lastSylInPhraseNavigator.getElement(t2));
assertEquals(firstWord, wordNavigator.getElement(t0));
assertEquals(firstWordPhrase2, wordNavigator.getElement(t2));
assertEquals(firstWordPhrase2, nextWordNavigator.getElement(t0));
assertEquals(lastWord, lastWordInSentenceNavigator.getElement(t0));
assertEquals(lastWord, lastWordInSentenceNavigator.getElement(t2));
}
@Test
public void phone() {
ByteValuedFeatureProcessor phoneFP = (ByteValuedFeatureProcessor) mgr.getFeatureProcessor("phone");
for (Target t : halfphoneTargets) {
String phone = getPhoneName(t.getMaryxmlElement());
String predicted = phoneFP.getValues()[phoneFP.process(t)];
assertEquals(phone, predicted);
}
}
// TODO: write test methods for the all the other feature processors...
}