/** * Copyright 2008 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 java.io.BufferedReader; import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; import marytts.unitselection.select.Target; /** * Compute a given set of features for a Target. * * @author schroed * */ public class TargetFeatureComputer { protected ByteValuedFeatureProcessor[] byteValuedDiscreteFeatureProcessors; protected ShortValuedFeatureProcessor[] shortValuedDiscreteFeatureProcessors; protected ContinuousFeatureProcessor[] continuousFeatureProcessors; protected String pauseSymbol = null; protected FeatureDefinition featureDefinition = null; /** * Construct a TargetFeatureComputer that knows how to compute features for a Target using the given set of feature processor * names. These names must be known to the given Feature processor manager. * * @param manager * manager * @param featureProcessorNames * a String containing the names of the feature processors to use, separated by white space, and in the right order * (byte-valued discrete feature processors first, then short-valued, then continuous) */ public TargetFeatureComputer(FeatureProcessorManager manager, String featureProcessorNames) { List<MaryFeatureProcessor> byteValuedFeatureProcessors = new ArrayList<MaryFeatureProcessor>(); List<MaryFeatureProcessor> shortValuedFeatureProcessors = new ArrayList<MaryFeatureProcessor>(); List<MaryFeatureProcessor> continuousValuedFeatureProcessors = new ArrayList<MaryFeatureProcessor>(); StringTokenizer st = new StringTokenizer(featureProcessorNames); while (st.hasMoreTokens()) { String name = st.nextToken(); MaryFeatureProcessor fp = manager.getFeatureProcessor(name); if (fp == null) { throw new IllegalArgumentException("Unknown feature processor: " + name); } else if (fp instanceof ByteValuedFeatureProcessor) { byteValuedFeatureProcessors.add(fp); } else if (fp instanceof ShortValuedFeatureProcessor) { shortValuedFeatureProcessors.add(fp); } else if (fp instanceof ContinuousFeatureProcessor) { continuousValuedFeatureProcessors.add(fp); } else { throw new IllegalArgumentException("Unknown feature processor type " + fp.getClass() + " for feature processor: " + name); } } this.byteValuedDiscreteFeatureProcessors = (ByteValuedFeatureProcessor[]) byteValuedFeatureProcessors .toArray(new ByteValuedFeatureProcessor[0]); this.shortValuedDiscreteFeatureProcessors = (ShortValuedFeatureProcessor[]) shortValuedFeatureProcessors .toArray(new ShortValuedFeatureProcessor[0]); this.continuousFeatureProcessors = (ContinuousFeatureProcessor[]) continuousValuedFeatureProcessors .toArray(new ContinuousFeatureProcessor[0]); } /** * Provide the feature definition that can be used to interpret the feature processors generated by this * TargetFeatureComputer. * * @return featureDefinition */ public FeatureDefinition getFeatureDefinition() { if (featureDefinition == null) { StringBuilder sb = new StringBuilder(); sb.append(FeatureDefinition.BYTEFEATURES).append("\n"); for (int i = 0; i < byteValuedDiscreteFeatureProcessors.length; i++) { sb.append(byteValuedDiscreteFeatureProcessors[i].getName()); String[] values = byteValuedDiscreteFeatureProcessors[i].getValues(); for (String v : values) { sb.append(" ").append(v); } sb.append("\n"); } sb.append(FeatureDefinition.SHORTFEATURES).append("\n"); for (int i = 0; i < shortValuedDiscreteFeatureProcessors.length; i++) { sb.append(shortValuedDiscreteFeatureProcessors[i].getName()); String[] values = shortValuedDiscreteFeatureProcessors[i].getValues(); for (String v : values) { sb.append(" ").append(v); } sb.append("\n"); } sb.append(FeatureDefinition.CONTINUOUSFEATURES).append("\n"); for (int i = 0; i < continuousFeatureProcessors.length; i++) { sb.append(continuousFeatureProcessors[i].getName()).append("\n"); } BufferedReader reader = new BufferedReader(new StringReader(sb.toString())); try { featureDefinition = new FeatureDefinition(reader, false); } catch (IOException e) { throw new RuntimeException("Problem creating feature definition", e); } } return featureDefinition; } /** * Using the set of feature processors defined when creating the target feature computer, compute a feature vector for the * target * * @param target * target * @return a feature vector for the target */ public FeatureVector computeFeatureVector(Target target) { byte[] byteFeatures = new byte[byteValuedDiscreteFeatureProcessors.length]; short[] shortFeatures = new short[shortValuedDiscreteFeatureProcessors.length]; float[] floatFeatures = new float[continuousFeatureProcessors.length]; for (int i = 0; i < byteValuedDiscreteFeatureProcessors.length; i++) { byteFeatures[i] = byteValuedDiscreteFeatureProcessors[i].process(target); } for (int i = 0; i < shortValuedDiscreteFeatureProcessors.length; i++) { shortFeatures[i] = shortValuedDiscreteFeatureProcessors[i].process(target); } for (int i = 0; i < continuousFeatureProcessors.length; i++) { floatFeatures[i] = continuousFeatureProcessors[i].process(target); } return new FeatureVector(byteFeatures, shortFeatures, floatFeatures, 0); } /** * For the given feature vector, convert each encoded value into its string representation. * * @param features * a feature vector, which must match the feature processors known to this feature computer. * @return a string in which the string values of all features are separated by spaces. * @throws IllegalArgumentException * if the number of byte-valued, short-valued or continuous elements in features do not match the set of feature * processors in this feature computer. */ public String toStringValues(FeatureVector features) { StringBuilder buf = new StringBuilder(); byte[] bytes = features.getByteValuedDiscreteFeatures(); short[] shorts = features.getShortValuedDiscreteFeatures(); float[] floats = features.getContinuousFeatures(); if (bytes.length != byteValuedDiscreteFeatureProcessors.length || shorts.length != shortValuedDiscreteFeatureProcessors.length || floats.length != continuousFeatureProcessors.length) { throw new IllegalArgumentException("Number of features in argument does not match number of feature processors"); } for (int i = 0; i < bytes.length; i++) { if (buf.length() > 0) buf.append(" "); buf.append(byteValuedDiscreteFeatureProcessors[i].getValues()[(int) bytes[i] & 0xff]); } for (int i = 0; i < shorts.length; i++) { if (buf.length() > 0) buf.append(" "); buf.append(shortValuedDiscreteFeatureProcessors[i].getValues()[(int) shorts[i]]); } for (int i = 0; i < floats.length; i++) { if (buf.length() > 0) buf.append(" "); buf.append(floats[i]); } return buf.toString(); } public ByteValuedFeatureProcessor[] getByteValuedFeatureProcessors() { return byteValuedDiscreteFeatureProcessors; } public ShortValuedFeatureProcessor[] getShortValuedFeatureProcessors() { return shortValuedDiscreteFeatureProcessors; } public ContinuousFeatureProcessor[] getContinuousFeatureProcessors() { return continuousFeatureProcessors; } /** * List the names of all feature processors. The first line starts with "ByteValuedFeatureProcessors", followed by the list of * names of the byte-valued feature processors; the second line starts with "ShortValuedFeatureProcessors", followed by the * list of names of the short-valued feature processors; and the third line starts with "ContinuousFeatureProcessors", * followed by the list of names of the continuous feature processors. * * @return a string with the names. */ public String getAllFeatureProcessorNames() { return "ByteValuedFeatureProcessors " + getByteValuedFeatureProcessorNames() + "\n" + "ShortValuedFeatureProcessors " + getShortValuedFeatureProcessorNames() + "\n" + "ContinuousFeatureProcessors " + getContinuousFeatureProcessorNames() + "\n"; } /** * List the names of all byte-valued feature processors, separated by space characters. * * @return a string with the names. */ public String getByteValuedFeatureProcessorNames() { StringBuilder buf = new StringBuilder(); for (int i = 0; i < byteValuedDiscreteFeatureProcessors.length; i++) { if (i > 0) buf.append(" "); buf.append(byteValuedDiscreteFeatureProcessors[i].getName()); } return buf.toString(); } /** * List the names of all short-valued feature processors, separated by space characters. * * @return a string with the names. */ public String getShortValuedFeatureProcessorNames() { StringBuilder buf = new StringBuilder(); for (int i = 0; i < shortValuedDiscreteFeatureProcessors.length; i++) { if (i > 0) buf.append(" "); buf.append(shortValuedDiscreteFeatureProcessors[i].getName()); } return buf.toString(); } /** * List the names of all byte-valued feature processors, separated by space characters. * * @return a string with the names. */ public String getContinuousFeatureProcessorNames() { StringBuilder buf = new StringBuilder(); for (int i = 0; i < continuousFeatureProcessors.length; i++) { if (i > 0) buf.append(" "); buf.append(continuousFeatureProcessors[i].getName()); } return buf.toString(); } /** * List the names and values of all feature processors. The section describing the byte-valued feature processors starts with * the string "ByteValuedFeatureProcessors" in a line by itself, followed by the list of names and values of the byte-valued * feature processors, as described in getByteValuedFeatureProcessorNamesAndValues(). The section describing the short-valued * feature processors starts with the string "ShortValuedFeatureProcessors" in a line by itself, followed by the list of names * and values of the short-valued feature processors, as described in getShortValuedFeatureProcessorNamesAndValues(). The * section describing the continuous feature processors starts with the string "ContinuousFeatureProcessors" in a line by * itself, followed by the list of names and values of the continuous feature processors, as described in * getContinuousFeatureProcessorNamesAndValues(). * * @return a string with the names and values. */ public String getAllFeatureProcessorNamesAndValues() { return FeatureDefinition.BYTEFEATURES + "\n" + getByteValuedFeatureProcessorNamesAndValues() + FeatureDefinition.SHORTFEATURES + "\n" + getShortValuedFeatureProcessorNamesAndValues() + FeatureDefinition.CONTINUOUSFEATURES + "\n" + getContinuousFeatureProcessorNamesAndValues(); } /** * List the names of all byte-valued feature processors and their possible values. Each line starts with the name of a feature * processor, followed by the full list of string values, separated by space characters. The values are ordered so that their * position corresponds to the byte value. * * @return a string with the names and values. */ public String getByteValuedFeatureProcessorNamesAndValues() { StringBuilder buf = new StringBuilder(); for (int i = 0; i < byteValuedDiscreteFeatureProcessors.length; i++) { buf.append(byteValuedDiscreteFeatureProcessors[i].getName()); String[] values = byteValuedDiscreteFeatureProcessors[i].getValues(); for (int j = 0; j < values.length; j++) { buf.append(" "); buf.append(values[j]); } buf.append("\n"); } return buf.toString(); } /** * List the names of all short-valued feature processors and their possible values. Each line starts with the name of a * feature processor, followed by the full list of string values, separated by space characters. The values are ordered so * that their position corresponds to the short value. * * @return a string with the names and values. */ public String getShortValuedFeatureProcessorNamesAndValues() { StringBuilder buf = new StringBuilder(); for (int i = 0; i < shortValuedDiscreteFeatureProcessors.length; i++) { buf.append(shortValuedDiscreteFeatureProcessors[i].getName()); String[] values = shortValuedDiscreteFeatureProcessors[i].getValues(); for (int j = 0; j < values.length; j++) { buf.append(" "); buf.append(values[j]); } buf.append("\n"); } return buf.toString(); } /** * List the names of all continuous feature processors and their possible values. Each line starts with the name of a feature * processor, followed by the value "float" to indicate that the list of possible values is not limited. * * @return a string with the names and values. */ public String getContinuousFeatureProcessorNamesAndValues() { StringBuilder buf = new StringBuilder(); for (int i = 0; i < continuousFeatureProcessors.length; i++) { buf.append(continuousFeatureProcessors[i].getName()); buf.append(" float\n"); } return buf.toString(); } /** * Get the pause symbol as associated with the "phone" feature processor used. * * @return pauseSymbol */ public String getPauseSymbol() { if (pauseSymbol == null) { for (MaryFeatureProcessor fp : byteValuedDiscreteFeatureProcessors) { if (fp instanceof MaryLanguageFeatureProcessors.Phone) { pauseSymbol = ((MaryLanguageFeatureProcessors.Phone) fp).getPauseSymbol(); break; } } } return pauseSymbol; } }