All Downloads are FREE. Search and download functionalities are using the official Maven repository.

marytts.modules.phonemiser.TrainedLTS Maven / Gradle / Ivy

The newest version!
/**
 * 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 .
 *
 */
package marytts.modules.phonemiser;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Properties;

import org.hsqldb.error.Error;

import marytts.cart.CART;
import marytts.cart.LeafNode.StringAndFloatLeafNode;
import marytts.cart.io.MaryCARTReader;
import marytts.exceptions.MaryConfigurationException;
import marytts.features.FeatureDefinition;
import marytts.features.FeatureVector;

/**
 * 
 * This predicts pronunciation from a model trained with LTSTrainer.
 * 
 * @author benjaminroth
 * 
 */
public class TrainedLTS {
	public static final String PREDICTED_STRING_FEATURENAME = "predicted-string";

	private CART tree;
	private FeatureDefinition featureDefinition;
	private int indexPredictedFeature;
	private int context;
	private AllophoneSet allophoneSet;
	private boolean convertToLowercase;
	protected boolean removeTrailingOneFromPhones = true;

	/**
	 * 
	 * Initializes letter to sound system with a phoneSet, and load the decision tree from the given file.
	 * 
	 * @param aPhonSet
	 *            phoneset used in syllabification
	 * @param treeStream
	 *            treeStream
	 * @param removeTrailingOneFromPhones
	 *            removeTrailingOneFromPhones
	 * @throws IOException
	 *             IOException
	 * @throws MaryConfigurationException
	 *             MaryConfigurationException
	 */
	public TrainedLTS(AllophoneSet aPhonSet, InputStream treeStream, boolean removeTrailingOneFromPhones) throws IOException,
			MaryConfigurationException {
		this.allophoneSet = aPhonSet;
		this.loadTree(treeStream);
		this.removeTrailingOneFromPhones = removeTrailingOneFromPhones;
	}

	/**
	 * 
	 * Initializes letter to sound system with a phoneSet, and load the decision tree from the given file.
	 * 
	 * @param aPhonSet
	 *            phoneset used in syllabification
	 * @param treeStream
	 *            treeStream
	 * @throws IOException
	 *             IOException
	 * @throws MaryConfigurationException
	 *             MaryConfigurationException
	 */
	public TrainedLTS(AllophoneSet aPhonSet, InputStream treeStream) throws IOException, MaryConfigurationException {
		this(aPhonSet, treeStream, true);
	}

	public TrainedLTS(AllophoneSet aPhonSet, CART predictionTree) {
		this.allophoneSet = aPhonSet;
		this.tree = predictionTree;
		this.featureDefinition = tree.getFeatureDefinition();
		this.indexPredictedFeature = featureDefinition.getFeatureIndex(PREDICTED_STRING_FEATURENAME);
		Properties props = tree.getProperties();
		if (props == null)
			throw new IllegalArgumentException("Prediction tree does not contain properties");
		convertToLowercase = Boolean.parseBoolean(props.getProperty("lowercase"));
		context = Integer.parseInt(props.getProperty("context"));
	}

	/**
	 * 
	 * Convenience method to load tree from an inputstream
	 * 
	 * @param treeStream
	 *            treeStream
	 * @throws IOException
	 *             IOException
	 * @throws MaryConfigurationException
	 *             MaryConfigurationException
	 */
	public void loadTree(InputStream treeStream) throws IOException, MaryConfigurationException {
		MaryCARTReader cartReader = new MaryCARTReader();
		this.tree = cartReader.loadFromStream(treeStream);
		this.featureDefinition = tree.getFeatureDefinition();
		this.indexPredictedFeature = featureDefinition.getFeatureIndex(PREDICTED_STRING_FEATURENAME);
		this.convertToLowercase = false;
		Properties props = tree.getProperties();
		if (props == null)
			throw new IllegalArgumentException("Prediction tree does not contain properties");
		convertToLowercase = Boolean.parseBoolean(props.getProperty("lowercase"));
		context = Integer.parseInt(props.getProperty("context"));
	}

	public String predictPronunciation(String graphemes) {
		if (convertToLowercase)
			graphemes = graphemes.toLowerCase(allophoneSet.getLocale());

		String returnStr = "";

		for (int i = 0; i < graphemes.length(); i++) {

			byte[] byteFeatures = new byte[2 * this.context + 1];

			for (int fnr = 0; fnr < 2 * this.context + 1; fnr++) {
				int pos = i - context + fnr;

				String grAtPos = (pos < 0 || pos >= graphemes.length()) ? "null" : graphemes.substring(pos, pos + 1);

				try {
					byteFeatures[fnr] = this.tree.getFeatureDefinition().getFeatureValueAsByte(fnr, grAtPos);
					// ... can also try to call explicit:
					// features[fnr] = this.fd.getFeatureValueAsByte("att"+fnr, cg.substr(pos)
				} catch (IllegalArgumentException iae) {
					// Silently ignore unknown characters
					byteFeatures[fnr] = this.tree.getFeatureDefinition().getFeatureValueAsByte(fnr, "null");
				}
			}

			FeatureVector fv = new FeatureVector(byteFeatures, new short[] {}, new float[] {}, 0);

			StringAndFloatLeafNode leaf = (StringAndFloatLeafNode) tree.interpretToNode(fv, 0);
			String prediction = leaf.mostProbableString(featureDefinition, indexPredictedFeature);
			returnStr += prediction.substring(1, prediction.length() - 1);

		}

		return returnStr;

	}

	/**
	 * Phone chain is syllabified. After that, no white spaces are included, stress is on syllable of first stress bearing vowal,
	 * or assigned rule-based if there is no stress predicted by the tree.
	 * 
	 * @param phones
	 *            input phone chain, unsyllabified, stress marking attached to vowals
	 * @return phone chain, with syllable sepeators "-" and stress symbols "'"
	 * @throws IllegalArgumentException
	 *             if the input cannot be syllabified
	 */
	public String syllabify(String phones) throws IllegalArgumentException {
		return allophoneSet.syllabify(phones);
	}

	public static void main(String[] args) throws IOException, MaryConfigurationException {

		if (args.length < 2) {
			System.out.println("Usage:");
			System.out
					.println("java marytts.modules.phonemiser.TrainedLTS allophones.xml lts-model.lts [removeTrailingOneFromPhones]");
			System.exit(0);
		}
		String allophoneFile = args[0];
		String ltsFile = args[1];
		boolean myRemoveTrailingOneFromPhones = true;
		if (args.length > 2) {
			myRemoveTrailingOneFromPhones = Boolean.getBoolean(args[2]);
		}

		TrainedLTS lts = new TrainedLTS(AllophoneSet.getAllophoneSet(allophoneFile), new FileInputStream(ltsFile),
				myRemoveTrailingOneFromPhones);

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String line;
		while ((line = br.readLine()) != null) {
			line = line.trim();
			String pron = lts.predictPronunciation(line);
			String syl = lts.syllabify(pron);
			String sylStripped = syl.replaceAll("[-' ]+", "");
			System.out.println(sylStripped);
		}
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy