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

marytts.tools.voiceimport.SphinxLabeler Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 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 .
 *
 */
package marytts.tools.voiceimport;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.text.DecimalFormat;
import java.util.SortedMap;
import java.util.StringTokenizer;
import java.util.TreeMap;

import marytts.util.io.StreamGobbler;

/**
 * Preparate the directory of the voice for sphinx labelling
 * 
 * @author Anna Hunecke
 */
public class SphinxLabeler extends VoiceImportComponent {

	private DatabaseLayout db;

	public final String SPHINX2DIR = "SphinxLabeler.sphinx2Dir";
	public final String STDIR = "SphinxLabeler.stDir";

	public final String getName() {
		return "SphinxLabeler";
	}

	public SortedMap getDefaultProps(DatabaseLayout db) {
		this.db = db;
		if (props == null) {
			props = new TreeMap();
			String sphinx2dir = System.getProperty("SPHINX2DIR");
			if (sphinx2dir == null) {
				sphinx2dir = "/project/mary/anna/sphinx/sphinx2/";
			}
			props.put(SPHINX2DIR, sphinx2dir);
			props.put(STDIR, db.getProp(db.ROOTDIR) + "st");
		}
		return props;
	}

	protected void setupHelp() {
		props2Help = new TreeMap();
		props2Help.put(SPHINX2DIR, "directory containing the local installation of Sphinx2");
		props2Help.put(STDIR, "directory containing all files used for training and labeling");
	}

	/**
	 * Do the computations required by this component.
	 * 
	 * @throws Exception
	 *             Exception
	 * @return true on success, false on failure
	 */
	public boolean compute() throws Exception {

		System.out.println("Labelling the voice data");

		// get voicename and root dir name
		// get the root dir and the voicename
		String rootDirName = db.getProp(db.ROOTDIR);
		String voicename = db.getProp(db.VOICENAME);

		/* Sphinx2 variables */
		System.out.println("Calling Sphinx2 ...");
		String stdir = getProp(STDIR);
		// model directory
		String hmm = stdir + "/model_parameters/" + voicename + ".s2models/";

		// the 'task'
		String task = stdir + "/wav";

		// dictionary and silence-symbol files
		String dictfile = stdir + "/etc/" + voicename + ".dic";
		String ndictfile = stdir + "/etc/" + voicename + ".sil";

		// list of filenames
		String ctlfile = stdir + "/etc/" + voicename + ".fileids";

		// the transcription file
		String tactlfn = stdir + "/etc/" + voicename + ".align";

		// make lab-directory if it does not exist
		File stLabDir = new File(stdir + "/lab");
		if (!stLabDir.exists()) {
			stLabDir.mkdir();
		}

		/* Run Sphinx2 */

		Runtime rtime = Runtime.getRuntime();
		// get a shell
		Process process = rtime.exec("/bin/bash");
		// get an output stream to write to the shell
		PrintWriter pw = new PrintWriter(new OutputStreamWriter(process.getOutputStream()));
		// go to voice directory
		pw.print("cd " + rootDirName + "\n");
		pw.flush();
		// call Sphinx2 and exit

		pw.print("( " + getProp(SPHINX2DIR) + "build/bin/sphinx2-batch -adcin TRUE -adcext wav " + "-ctlfn " + ctlfile
				+ " -tactlfn " + tactlfn + " -ctloffset 0" + "-ctlcount 100000000 -datadir wav -agcmax FALSE "
				+ "-langwt 6.5 -fwdflatlw 8.5 -rescorelw 9.5 -ugwt 0.5" + "-fillpen 1e-10 -silpen 1e-10 -inspen 0.65 -topn 5"
				+ "-topsenfrm 3 -topsenthresh -70000 -beam 2e-90 " + "-npbeam 2e-90 -lpbeam 2e-90 -lponlybeam 0.0005 "
				+ "-nwbeam 0.0005 -fwdflat FALSE -fwdflatbeam 1e-08 " + "-fwdflatnwbeam 0.0003 -bestpath TRUE -kbdumpdir " + task
				+ " " + "-dictfn " + dictfile + " -fdictfn " + ndictfile + " " + "-phnfn " + hmm + "/phone -mapfn " + hmm
				+ "/map -hmmdir " + hmm + " " + "-hmmdirlist " + hmm + " -8bsen TRUE -sendumpfn " + hmm + "/sendump" + " -cbdir "
				+ hmm + " -phonelabdir st/lab" + "; exit)\n");
		pw.flush();
		pw.close();

		// collect the output
		// collect error messages
		StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream(), "err");

		// collect output messages
		StreamGobbler outputGobbler = new StreamGobbler(process.getInputStream(), "out");

		// start the stream readers
		errorGobbler.start();
		outputGobbler.start();

		// shut down
		process.waitFor();
		process.exitValue();
		System.out.println("... done.");

		/* Write the labels into lab directory */
		System.out.println("Exporting Labels ...");

		// lab destination directory
		String labDestDir = db.getProp(db.LABDIR);
		String labExtension = db.getProp(db.LABEXT);
		// used to prune the times to 5 positions behind .
		DecimalFormat df = new DecimalFormat("0.00000");
		String line;
		// go through original lab files
		File[] labFiles = stLabDir.listFiles();
		for (int i = 0; i < labFiles.length; i++) {
			File nextFile = labFiles[i];
			System.out.println(nextFile.getName());

			// open original lab file
			BufferedReader labIn = new BufferedReader(new FileReader(nextFile));

			// open destination lab file
			PrintWriter labOut = new PrintWriter(new FileWriter(new File(labDestDir + nextFile.getName())));

			String pauseString = null;

			// go through original lab file
			while ((line = labIn.readLine()) != null) {
				if (line.startsWith("#")) {
					// copy the line to destination lab file
					labOut.println(line);
				} else {
					// tokenize the line
					StringTokenizer tok = new StringTokenizer(line);

					// first token is time
					double time = Float.parseFloat(tok.nextToken());
					// add 0.012
					// TODO: find out why we are adding 0.012
					time += 0.012;
					// prune time to 5 positions behind the dot
					String timeString = df.format(time);

					// next token is some number
					String mysteriousNumber = tok.nextToken();

					// next token is the phone
					String phone = tok.nextToken();

					if (phone.equals("SIL")) {
						// replace silence symbol
						phone = "_";
						// store the pause in pause string; to be written later
						// (this has the effect that if two pauses follow
						// each other, only the last one is printed)
						pauseString = timeString + " " + mysteriousNumber + " " + phone;
					} else {
						if (pauseString != null) {
							// there is still a pause to print
							labOut.println(pauseString);
							// remove the pause
							pauseString = null;
						}
						// cut off the stuff behind the phone
						phone = phone.substring(0, phone.indexOf("("));
						// convert phone back to SAMPA
						phone = convertPhone(phone);
						labOut.println(timeString + " " + mysteriousNumber + " " + phone);
					}

				}
			}

			if (pauseString != null) {
				// print last pause
				labOut.println(pauseString);
			}
			// close files
			labIn.close();
			labOut.flush();
			labOut.close();
		}
		System.out.println("... done.");
		System.out.println("All done!");

		return true;
	}

	/**
	 * Convert the given phone from Sphinx-readable format back to SAMPA
	 * 
	 * @param phone
	 *            the phone
	 * @return the converted phone
	 */
	private String convertPhone(String phone) {
		boolean uppercase = false;
		char[] phoneChars = phone.toCharArray();
		StringBuilder convertedPhone = new StringBuilder();
		for (int i = 0; i < phoneChars.length; i++) {
			char phoneChar = phoneChars[i];
			if (Character.isLetter(phoneChar)) {
				if (uppercase) {
					// character originally was uppercase
					// append the phone as it is
					convertedPhone.append(phoneChar);
					uppercase = false;
				} else {
					// character originally was lowercase
					// convert back to lowercase
					convertedPhone.append(Character.toLowerCase(phoneChar));
				}
			} else {
				if (phoneChar == '*') {
					// next letter was uppercase, set uppercase to true
					uppercase = true;
				} else {
					// just append other non-letter signs
					convertedPhone.append(phoneChar);
				}
			}
		}
		return convertedPhone.toString();
	}

	/**
	 * Provide the progress of computation, in percent, or -1 if that feature is not implemented.
	 * 
	 * @return -1 if not implemented, or an integer between 0 and 100.
	 */
	public int getProgress() {
		return -1;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy