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

marytts.tools.voiceimport.AcousticFeatureFileWriter 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.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.SortedMap;
import java.util.TreeMap;

import marytts.exceptions.MaryConfigurationException;
import marytts.features.FeatureDefinition;
import marytts.features.FeatureVector;
import marytts.unitselection.data.FeatureFileReader;
import marytts.unitselection.data.Unit;
import marytts.unitselection.data.UnitFileReader;
import marytts.util.data.MaryHeader;
import marytts.util.math.ArrayUtils;
import marytts.util.math.Polynomial;

public class AcousticFeatureFileWriter extends VoiceImportComponent {
	protected File maryDir;
	protected FeatureFileReader feats;
	protected FeatureDefinition inFeatureDefinition;
	protected File outFeatureFile;
	protected FeatureDefinition outFeatureDefinition;
	protected UnitFileReader unitFileReader;
	protected FeatureFileReader contours;
	protected DatabaseLayout db = null;
	protected int percent = 0;

	public final String UNITFILE = "AcousticFeatureFileWriter.unitFile";
	public final String CONTOURFILE = "AcousticFeatureFileWriter.contourFile";
	public final String FEATUREFILE = "AcousticFeatureFileWriter.featureFile";
	public final String ACFEATUREFILE = "AcousticFeatureFileWriter.acFeatureFile";
	public final String ACFEATDEF = "AcousticFeatureFileWriter.acFeatDef";

	public String getName() {
		return "AcousticFeatureFileWriter";
	}

	public SortedMap getDefaultProps(DatabaseLayout theDb) {
		this.db = theDb;
		if (props == null) {
			props = new TreeMap();
			String fileDir = theDb.getProp(theDb.FILEDIR);
			String maryExt = theDb.getProp(theDb.MARYEXT);
			props.put(UNITFILE, fileDir + "halfphoneUnits" + maryExt);
			props.put(CONTOURFILE, fileDir + "syllableF0Polynomials" + maryExt);
			props.put(FEATUREFILE, fileDir + "halfphoneFeatures" + maryExt);
			props.put(ACFEATUREFILE, fileDir + "halfphoneFeatures_ac" + maryExt);
			props.put(ACFEATDEF, theDb.getProp(theDb.CONFIGDIR) + "halfphoneUnitFeatureDefinition_ac.txt");
		}
		return props;
	}

	protected void setupHelp() {
		if (props2Help == null) {
			props2Help = new TreeMap();
			props2Help.put(UNITFILE, "file containing all halfphone units");
			props2Help.put(CONTOURFILE, "file containing the polynomial contours for all syllables, indexed by phone features");
			props2Help.put(FEATUREFILE, "file containing all halfphone units and their target cost features");
			props2Help.put(ACFEATUREFILE, "file containing all halfphone units and their target cost features"
					+ " plus the acoustic target cost features. Will be created by this module.");
			props2Help.put(ACFEATDEF, "file containing the list of phone target cost features, their values and weights");
		}
	}

	@Override
	public boolean compute() throws IOException, MaryConfigurationException {
		System.out.println("Acoustic feature file writer started.");

		maryDir = new File(db.getProp(db.FILEDIR));
		if (!maryDir.exists()) {
			maryDir.mkdir();
			System.out.println("Created the output directory [" + (db.getProp(db.FILEDIR)) + "] to store the feature file.");
		}
		// System.out.println("A");
		unitFileReader = new UnitFileReader(getProp(UNITFILE));
		// System.out.println("B");
		contours = new FeatureFileReader(getProp(CONTOURFILE));
		// System.out.println("C");

		feats = new FeatureFileReader(getProp(FEATUREFILE));
		inFeatureDefinition = feats.getFeatureDefinition();
		StringWriter sw = new StringWriter();
		PrintWriter pw = new PrintWriter(sw);
		inFeatureDefinition.writeTo(pw, true);
		// And now, append the two float features for duration and f0:
		pw.println("100 linear | unit_duration");
		pw.println("100 linear | unit_logf0");
		pw.println("0 linear | unit_logf0delta");
		pw.close();
		String fd = sw.toString();
		System.out.println("Generated the following feature definition:");
		System.out.println(fd);
		StringReader sr = new StringReader(fd);
		BufferedReader br = new BufferedReader(sr);
		outFeatureDefinition = new FeatureDefinition(br, true);

		outFeatureFile = new File(getProp(ACFEATUREFILE));
		DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(outFeatureFile)));
		writeHeaderTo(out);
		writeUnitFeaturesTo(out);
		out.close();
		System.out.println("Number of processed units: " + unitFileReader.getNumberOfUnits());

		// make sure we have a feature definition with acoustic features
		File featWeights = new File(getProp(ACFEATDEF));
		if (!featWeights.exists()) {
			try {
				PrintWriter featWeightsOut = new PrintWriter(new OutputStreamWriter(new FileOutputStream(featWeights), "UTF-8"),
						true);

				outFeatureDefinition.generateFeatureWeightsFile(featWeightsOut);
			} catch (Exception e) {
				System.out.println("No halfphone feature weights ac file " + getProp(ACFEATDEF));
				return false;
			}
		}
		FeatureFileReader tester = FeatureFileReader.getFeatureFileReader(getProp(ACFEATUREFILE));
		int unitsOnDisk = tester.getNumberOfUnits();
		if (unitsOnDisk == unitFileReader.getNumberOfUnits()) {
			System.out.println("Can read right number of units");
			int r = new Random().nextInt(unitsOnDisk);
			System.out.println("feature vector " + r + ":");
			System.out.println("Orig: " + feats.getFeatureVector(r).toString());
			System.out.println("AC  : " + tester.getFeatureVector(r).toString());
			return true;
		} else {
			System.out.println("Read wrong number of units: " + unitsOnDisk);
			return false;
		}
	}

	/**
	 * @param out
	 *            out
	 * @throws IOException
	 *             IOException
	 * @throws UnsupportedEncodingException
	 *             UnsupportedEncodingException
	 * @throws FileNotFoundException
	 *             FileNotFoundException
	 */
	protected void writeUnitFeaturesTo(DataOutput out) throws IOException, UnsupportedEncodingException, FileNotFoundException {
		int numUnits = unitFileReader.getNumberOfUnits();
		int unitSampleRate = unitFileReader.getSampleRate();
		FeatureDefinition featureDefinition = feats.getFeatureDefinition();
		int fiPhoneme = featureDefinition.getFeatureIndex("phone");
		byte fvPhoneme_0 = featureDefinition.getFeatureValueAsByte(fiPhoneme, "0");
		byte fvPhoneme_Silence = featureDefinition.getFeatureValueAsByte(fiPhoneme, "_");
		int fiVowel = featureDefinition.getFeatureIndex("ph_vc");
		byte fvVowel = featureDefinition.getFeatureValueAsByte(fiVowel, "+");
		int fiLR = featureDefinition.getFeatureIndex("halfphone_lr");
		byte fvLR_L = featureDefinition.getFeatureValueAsByte(fiLR, "L");
		byte fvLR_R = featureDefinition.getFeatureValueAsByte(fiLR, "R");
		int fiSylStart = featureDefinition.getFeatureIndex("segs_from_syl_start");
		int fiSylEnd = featureDefinition.getFeatureIndex("segs_from_syl_end");
		int iSylVowel = -1;
		List unitDurs = new ArrayList();

		out.writeInt(numUnits);
		System.out.println("Number of units : " + numUnits);
		int iCurrent = 0;
		for (int i = 0; i < numUnits; i++) {
			percent = 100 * i / numUnits;
			FeatureVector inFV = feats.getFeatureVector(i);
			Unit u = unitFileReader.getUnit(i);
			float dur = u.duration / (float) unitSampleRate;

			// No syllable structure for edge and silence phone entries:
			if (inFV.getByteFeature(fiPhoneme) == fvPhoneme_0 || inFV.getByteFeature(fiPhoneme) == fvPhoneme_Silence) {
				unitDurs.add(dur);
				continue;
			}
			// Else, unit belongs to a syllable
			if (inFV.getByteFeature(fiSylStart) == 0 && inFV.getByteFeature(fiLR) == fvLR_L) { // first segment in syllable
				if (iCurrent < i) { // Something to output before this syllable
					assert i - iCurrent == unitDurs.size();
					writeFeatureVectors(out, iCurrent, iSylVowel, i - 1, unitDurs);
				}
				unitDurs.clear();
				iSylVowel = -1;
				iCurrent = i;
			}

			unitDurs.add(dur);

			if (inFV.getByteFeature(fiVowel) == fvVowel && iSylVowel == -1) { // the first vowel in the syllable
				iSylVowel = i;
			}

			if (inFV.getByteFeature(fiSylEnd) == 0 && inFV.getByteFeature(fiLR) == fvLR_R) { // last segment in syllable
				writeFeatureVectors(out, iCurrent, iSylVowel, i, unitDurs);
				iSylVowel = -1;
				unitDurs.clear();
				iCurrent = i + 1;
			}

		}

		assert numUnits - iCurrent == unitDurs.size();
		writeFeatureVectors(out, iCurrent, iSylVowel, numUnits - 1, unitDurs);
	}

	private void writeFeatureVectors(DataOutput out, int iFirst, int iVowel, int iLast, List unitDurs) throws IOException {
		float[] coeffs = null;
		if (iVowel != -1) { // Syllable contains a vowel
			coeffs = contours.getFeatureVector(iVowel).getContinuousFeatures();
			boolean isZero = true;
			for (int c = 0; c < coeffs.length; c++) {
				if (coeffs[c] != 0) {
					isZero = false;
					break;
				}
			}
			if (isZero) {
				coeffs = null;
			}
		}
		assert unitDurs.size() == iLast - iFirst + 1;

		float sylDur = 0;
		for (int i = 0, max = unitDurs.size(); i < max; i++) {
			sylDur += unitDurs.get(i);
		}
		// System.out.println("Syl dur: "+sylDur+", "+unitDurs.size()+" units");

		float uStart = 0, uEnd = 0;
		for (int i = 0; iFirst + i <= iLast; i++) {
			float logF0 = Float.NaN;
			float logF0delta = Float.NaN;
			if (coeffs != null && unitDurs.get(i) > 0) {
				float relUStart = uStart / sylDur; // in [0, 1[
				float relUEnd = (uStart + unitDurs.get(i)) / sylDur; // in [0, 1[
				double[] predUnitContour = Polynomial.generatePolynomialValues(ArrayUtils.copyFloat2Double(coeffs), 10,
						relUStart, relUEnd);
				// System.out.printf("From %.2f to %.2f:", relUStart, relUEnd);
				// for (int k=0; k




© 2015 - 2025 Weber Informatics LLC | Privacy Policy