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

marytts.modules.SoPDurationModeller Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2010 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;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.StringReader;
import java.util.Locale;
import java.util.Scanner;

import marytts.datatypes.MaryData;
import marytts.datatypes.MaryDataType;
import marytts.datatypes.MaryXML;
import marytts.features.FeatureDefinition;
import marytts.features.FeatureProcessorManager;
import marytts.features.FeatureRegistry;
import marytts.features.TargetFeatureComputer;
import marytts.machinelearning.SoP;
import marytts.modules.phonemiser.AllophoneSet;
import marytts.modules.synthesis.Voice;
import marytts.server.MaryProperties;
import marytts.unitselection.select.Target;
import marytts.unitselection.select.UnitSelector;
import marytts.util.MaryRuntimeUtils;
import marytts.util.MaryUtils;
import marytts.util.dom.MaryDomUtils;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.traversal.NodeIterator;
import org.w3c.dom.traversal.TreeWalker;

public class SoPDurationModeller extends InternalModule {

	private String sopFileName;
	private SoP vowelSop;
	private SoP consonantSop;
	private SoP pauseSop;
	private boolean logDuration = true;

	protected TargetFeatureComputer featureComputer;
	private FeatureProcessorManager featureProcessorManager;
	private AllophoneSet allophoneSet;
	private FeatureDefinition voiceFeatDef;

	/**
	 * Constructor which can be directly called from init info in the config file. This constructor will use the registered
	 * feature processor manager for the given locale.
	 * 
	 * @param locale
	 *            a locale string, e.g. "en"
	 * @param sopFile
	 *            sopFile
	 * @throws Exception
	 *             Exception
	 */
	public SoPDurationModeller(String locale, String sopFile) throws Exception {
		this(MaryUtils.string2locale(locale), sopFile, FeatureRegistry
				.getFeatureProcessorManager(MaryUtils.string2locale(locale)));
	}

	/**
	 * Constructor which can be directly called from init info in the config file. Different languages can call this code with
	 * different settings.
	 * 
	 * @param locale
	 *            a locale string, e.g. "en"
	 * @param sopFile
	 *            the prefix to be used when looking up entries in the config files, e.g. "english.duration"
	 * @param featprocClassInfo
	 *            a package name for an instance of FeatureProcessorManager, e.g. "marytts.language.en.FeatureProcessorManager"
	 * @throws Exception
	 *             Exception
	 */
	public SoPDurationModeller(String locale, String sopFile, String featprocClassInfo) throws Exception {
		this(MaryUtils.string2locale(locale), sopFile, (FeatureProcessorManager) MaryRuntimeUtils
				.instantiateObject(featprocClassInfo));
	}

	/**
	 * Constructor to be called with instantiated objects.
	 * 
	 * @param locale
	 *            locale
	 * @param sopFile
	 *            the prefix to be used when looking up entries in the config files, e.g. "english.duration"
	 * @param featureProcessorManager
	 *            the manager to use when looking up feature processors.
	 */
	protected SoPDurationModeller(Locale locale, String sopFile, FeatureProcessorManager featureProcessorManager) {
		super("SoPDurationModeller", MaryDataType.ALLOPHONES, MaryDataType.DURATIONS, locale);
		this.sopFileName = sopFile;
		this.featureProcessorManager = featureProcessorManager;

	}

	public void startup() throws Exception {
		super.startup();

		// Read dur.sop file to load linear equations
		// The first section contains the feature definition, after one empty line,
		// the first line corresponds to vowels, next line to consonants and next line to pause
		String sopFile = MaryProperties.getFilename(sopFileName);
		// System.out.println("sopFileName: " + sopFile);
		String nextLine;
		String strContext = "";
		Scanner s = null;
		try {
			s = new Scanner(new BufferedReader(new FileReader(sopFile)));

			// The first part contains the feature definition
			while (s.hasNext()) {
				nextLine = s.nextLine();
				if (nextLine.trim().equals(""))
					break;
				else
					strContext += nextLine + "\n";
			}
			// the featureDefinition is the same for vowel, consonant and Pause
			voiceFeatDef = new FeatureDefinition(new BufferedReader(new StringReader(strContext)), false);

			// vowel line
			if (s.hasNext()) {
				nextLine = s.nextLine();
				// System.out.println("line vowel = " + nextLine);
				vowelSop = new SoP(nextLine, voiceFeatDef);
				// vowelSop.printCoefficients();
			}
			// consonant line
			if (s.hasNext()) {
				nextLine = s.nextLine();
				// System.out.println("line consonants = " + nextLine);
				consonantSop = new SoP(nextLine, voiceFeatDef);
				// consonantSop.printCoefficients();
			}
			// pause line
			if (s.hasNext()) {
				nextLine = s.nextLine();
				// System.out.println("line pause = " + nextLine);
				pauseSop = new SoP(nextLine, voiceFeatDef);
				// pauseSop.printCoefficients();
			}
		} finally {
			if (s != null)
				s.close();
		}

		// get a feature computer
		featureComputer = FeatureRegistry.getTargetFeatureComputer(featureProcessorManager, voiceFeatDef.getFeatureNames());

	}

	public MaryData process(MaryData d) throws Exception {
		Document doc = d.getDocument();
		NodeIterator sentenceIt = MaryDomUtils.createNodeIterator(doc, MaryXML.SENTENCE);
		Element sentence = null;
		while ((sentence = (Element) sentenceIt.nextNode()) != null) {
			// Make sure we have the correct voice:
			Element voice = (Element) MaryDomUtils.getAncestor(sentence, MaryXML.VOICE);
			Voice maryVoice = Voice.getVoice(voice);

			if (maryVoice == null) {
				maryVoice = d.getDefaultVoice();
			}
			if (maryVoice == null) {
				// Determine Locale in order to use default voice
				Locale locale = MaryUtils.string2locale(doc.getDocumentElement().getAttribute("xml:lang"));
				maryVoice = Voice.getDefaultVoice(locale);
			}

			allophoneSet = maryVoice.getAllophoneSet();
			TargetFeatureComputer currentFeatureComputer = featureComputer;

			// cumulative duration from beginning of sentence, in seconds:
			float end = 0;
			float durInSeconds;
			TreeWalker tw = MaryDomUtils.createTreeWalker(sentence, MaryXML.PHONE, MaryXML.BOUNDARY);
			Element segmentOrBoundary;
			Element previous = null;
			while ((segmentOrBoundary = (Element) tw.nextNode()) != null) {
				String phone = UnitSelector.getPhoneSymbol(segmentOrBoundary);

				Target t = new Target(phone, segmentOrBoundary);
				t.setFeatureVector(currentFeatureComputer.computeFeatureVector(t));

				if (segmentOrBoundary.getTagName().equals(MaryXML.BOUNDARY)) { // a pause
					System.out.print("Pause PHONE: " + phone);
					durInSeconds = (float) pauseSop.solve(t, voiceFeatDef, logDuration, false);
					if (durInSeconds < 0.0) {
						System.out.println("\nWARNING: duration < 0.0");
						durInSeconds = (float) pauseSop.solve(t, voiceFeatDef, logDuration, true);
					}
				} else {
					if (allophoneSet.getAllophone(phone).isVowel()) {
						// calculate duration with vowelSop
						System.out.print("Vowel PHONE: " + phone);
						durInSeconds = (float) vowelSop.solve(t, voiceFeatDef, logDuration, false);
						if (durInSeconds < 0.0) {
							System.out.println("\nWARNING: duration < 0.0");
							durInSeconds = (float) vowelSop.solve(t, voiceFeatDef, logDuration, true);
						}
					} else {
						// calculate duration with consonantSop
						System.out.print("Cons. PHONE: " + phone);
						durInSeconds = (float) consonantSop.solve(t, voiceFeatDef, logDuration, false);
						if (durInSeconds < 0.0) {
							System.out.println("\nWARNING: duration < 0.0");
							durInSeconds = (float) consonantSop.solve(t, voiceFeatDef, logDuration, true);
						}
					}
				}
				// TODO: where do we check that the solution is log(duration) or duration???
				System.out.format(" = %.3f\n", durInSeconds);
				// TODO: this problem is not solved, it seems it has to do with punctuation (?)
				if (durInSeconds < 0) {
					throw new Exception("Error generating SoP Duration: durInSeconds < 0.0 ");
				}
				end += durInSeconds;
				int durInMillis = (int) (1000 * durInSeconds);
				if (segmentOrBoundary.getTagName().equals(MaryXML.BOUNDARY)) {
					segmentOrBoundary.setAttribute("duration", String.valueOf(durInMillis));
				} else { // phone
					segmentOrBoundary.setAttribute("d", String.valueOf(durInMillis));
					segmentOrBoundary.setAttribute("end", String.valueOf(end));
				}
				previous = segmentOrBoundary;
			}
		}
		MaryData output = new MaryData(outputType(), d.getLocale());
		output.setDocument(doc);
		return output;

	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy