diff options
author | Niels Egberts <nielse@google.com> | 2014-07-10 11:45:23 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2014-07-09 19:47:58 +0000 |
commit | 931a0e27e114aee8e8297f4d6499d4e1891f0591 (patch) | |
tree | e687e2c27790c55281ca73cef51cd7c0d1fb751f /core/java/android/speech | |
parent | eeba0257a7d9bd10bf0d97d38828d52c035d2628 (diff) | |
parent | 34d4ac88f70c37cbe143ab01b40f343bcf02035f (diff) | |
download | frameworks_base-931a0e27e114aee8e8297f4d6499d4e1891f0591.zip frameworks_base-931a0e27e114aee8e8297f4d6499d4e1891f0591.tar.gz frameworks_base-931a0e27e114aee8e8297f4d6499d4e1891f0591.tar.bz2 |
Merge "Remove Markup and Utterance classes."
Diffstat (limited to 'core/java/android/speech')
-rw-r--r-- | core/java/android/speech/tts/Markup.java | 537 | ||||
-rw-r--r-- | core/java/android/speech/tts/Utterance.java | 595 |
2 files changed, 0 insertions, 1132 deletions
diff --git a/core/java/android/speech/tts/Markup.java b/core/java/android/speech/tts/Markup.java deleted file mode 100644 index c886e5d..0000000 --- a/core/java/android/speech/tts/Markup.java +++ /dev/null @@ -1,537 +0,0 @@ -package android.speech.tts; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.SortedMap; -import java.util.TreeMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import android.os.Bundle; -import android.os.Parcel; -import android.os.Parcelable; - -/** - * A class that provides markup to a synthesis request to control aspects of speech. - * <p> - * Markup itself is a feature agnostic data format; the {@link Utterance} class defines the currently - * available set of features and should be used to construct instances of the Markup class. - * </p> - * <p> - * A marked up sentence is a tree. Each node has a type, an optional plain text, a set of - * parameters, and a list of children. - * The <b>type</b> defines what it contains, e.g. "text", "date", "measure", etc. A Markup node - * can be either a part of sentence (often a leaf node), or node altering some property of its - * children (node with children). The top level node has to be of type "utterance" and its children - * are synthesized in order. - * The <b>plain text</b> is optional except for the top level node. If the synthesis engine does not - * support Markup at all, it should use the plain text of the top level node. If an engine does not - * recognize or support a node type, it will try to use the plain text of that node if provided. If - * the plain text is null, it will synthesize its children in order. - * <b>Parameters</b> are key-value pairs specific to each node type. In case of a date node the - * parameters may be for example "month: 7" and "day: 10". - * The <b>nested markups</b> are children and can for example be used to nest semiotic classes (a - * measure may have a node of type "decimal" as its child) or to modify some property of its - * children. See "plain text" on how they are processed if the parent of the children is unknown to - * the engine. - * <p> - */ -public final class Markup implements Parcelable { - - private String mType; - private String mPlainText; - - private Bundle mParameters = new Bundle(); - private List<Markup> mNestedMarkups = new ArrayList<Markup>(); - - private static final String TYPE = "type"; - private static final String PLAIN_TEXT = "plain_text"; - private static final String MARKUP = "markup"; - - private static final String IDENTIFIER_REGEX = "([0-9a-z_]+)"; - private static final Pattern legalIdentifierPattern = Pattern.compile(IDENTIFIER_REGEX); - - /** - * Constructs an empty markup. - */ - public Markup() {} - - /** - * Constructs a markup of the given type. - */ - public Markup(String type) { - setType(type); - } - - /** - * Returns the type of this node; can be null. - */ - public String getType() { - return mType; - } - - /** - * Sets the type of this node. can be null. May only contain [0-9a-z_]. - */ - public void setType(String type) { - if (type != null) { - Matcher matcher = legalIdentifierPattern.matcher(type); - if (!matcher.matches()) { - throw new IllegalArgumentException("Type cannot be empty and may only contain " + - "0-9, a-z and underscores."); - } - } - mType = type; - } - - /** - * Returns this node's plain text; can be null. - */ - public String getPlainText() { - return mPlainText; - } - - /** - * Sets this nodes's plain text; can be null. - */ - public void setPlainText(String plainText) { - mPlainText = plainText; - } - - /** - * Adds or modifies a parameter. - * @param key The key; may only contain [0-9a-z_] and cannot be "type" or "plain_text". - * @param value The value. - * @throws An {@link IllegalArgumentException} if the key is null or empty. - * @return this - */ - public Markup setParameter(String key, String value) { - if (key == null || key.isEmpty()) { - throw new IllegalArgumentException("Key cannot be null or empty."); - } - if (key.equals("type")) { - throw new IllegalArgumentException("Key cannot be \"type\"."); - } - if (key.equals("plain_text")) { - throw new IllegalArgumentException("Key cannot be \"plain_text\"."); - } - Matcher matcher = legalIdentifierPattern.matcher(key); - if (!matcher.matches()) { - throw new IllegalArgumentException("Key may only contain 0-9, a-z and underscores."); - } - - if (value != null) { - mParameters.putString(key, value); - } else { - removeParameter(key); - } - return this; - } - - /** - * Removes the parameter with the given key - */ - public void removeParameter(String key) { - mParameters.remove(key); - } - - /** - * Returns the value of the parameter. - * @param key The parameter key. - * @return The value of the parameter or null if the parameter is not set. - */ - public String getParameter(String key) { - return mParameters.getString(key); - } - - /** - * Returns the number of parameters that have been set. - */ - public int parametersSize() { - return mParameters.size(); - } - - /** - * Appends a child to the list of children - * @param markup The child. - * @return This instance. - * @throws {@link IllegalArgumentException} if markup is null. - */ - public Markup addNestedMarkup(Markup markup) { - if (markup == null) { - throw new IllegalArgumentException("Nested markup cannot be null"); - } - mNestedMarkups.add(markup); - return this; - } - - /** - * Removes the given node from its children. - * @param markup The child to remove. - * @return True if this instance was modified by this operation, false otherwise. - */ - public boolean removeNestedMarkup(Markup markup) { - return mNestedMarkups.remove(markup); - } - - /** - * Returns the index'th child. - * @param i The index of the child. - * @return The child. - * @throws {@link IndexOutOfBoundsException} if i < 0 or i >= nestedMarkupSize() - */ - public Markup getNestedMarkup(int i) { - return mNestedMarkups.get(i); - } - - - /** - * Returns the number of children. - */ - public int nestedMarkupSize() { - return mNestedMarkups.size(); - } - - /** - * Returns a string representation of this Markup instance. Can be deserialized back to a Markup - * instance with markupFromString(). - */ - public String toString() { - StringBuilder out = new StringBuilder(); - if (mType != null) { - out.append(TYPE + ": \"" + mType + "\""); - } - if (mPlainText != null) { - out.append(out.length() > 0 ? " " : ""); - out.append(PLAIN_TEXT + ": \"" + escapeQuotedString(mPlainText) + "\""); - } - // Sort the parameters alphabetically by key so we have a stable output. - SortedMap<String, String> sortedMap = new TreeMap<String, String>(); - for (String key : mParameters.keySet()) { - sortedMap.put(key, mParameters.getString(key)); - } - for (Map.Entry<String, String> entry : sortedMap.entrySet()) { - out.append(out.length() > 0 ? " " : ""); - out.append(entry.getKey() + ": \"" + escapeQuotedString(entry.getValue()) + "\""); - } - for (Markup m : mNestedMarkups) { - out.append(out.length() > 0 ? " " : ""); - String nestedStr = m.toString(); - if (nestedStr.isEmpty()) { - out.append(MARKUP + " {}"); - } else { - out.append(MARKUP + " { " + m.toString() + " }"); - } - } - return out.toString(); - } - - /** - * Escapes backslashes and double quotes in the plain text and parameter values before this - * instance is written to a string. - * @param str The string to escape. - * @return The escaped string. - */ - private static String escapeQuotedString(String str) { - StringBuilder out = new StringBuilder(); - for (int i = 0; i < str.length(); i++) { - char c = str.charAt(i); - if (c == '"') { - out.append("\\\""); - } else if (str.charAt(i) == '\\') { - out.append("\\\\"); - } else { - out.append(c); - } - } - return out.toString(); - } - - /** - * The reverse of the escape method, returning plain text and parameter values to their original - * form. - * @param str An escaped string. - * @return The unescaped string. - */ - private static String unescapeQuotedString(String str) { - StringBuilder out = new StringBuilder(); - for (int i = 0; i < str.length(); i++) { - char c = str.charAt(i); - if (c == '\\') { - i++; - if (i >= str.length()) { - throw new IllegalArgumentException("Unterminated escape sequence in string: " + - str); - } - c = str.charAt(i); - if (c == '\\') { - out.append("\\"); - } else if (c == '"') { - out.append("\""); - } else { - throw new IllegalArgumentException("Unsupported escape sequence: \\" + c + - " in string " + str); - } - } else { - out.append(c); - } - } - return out.toString(); - } - - /** - * Returns true if the given string consists only of whitespace. - * @param str The string to check. - * @return True if the given string consists only of whitespace. - */ - private static boolean isWhitespace(String str) { - return Pattern.matches("\\s*", str); - } - - /** - * Parses the given string, and overrides the values of this instance with those contained - * in the given string. - * @param str The string to parse; can have superfluous whitespace. - * @return An empty string on success, else the remainder of the string that could not be - * parsed. - */ - private String fromReadableString(String str) { - while (!isWhitespace(str)) { - String newStr = matchValue(str); - if (newStr == null) { - newStr = matchMarkup(str); - - if (newStr == null) { - return str; - } - } - str = newStr; - } - return ""; - } - - // Matches: key : "value" - // where key is an identifier and value can contain escaped quotes - // there may be superflouous whitespace - // The value string may contain quotes and backslashes. - private static final String OPTIONAL_WHITESPACE = "\\s*"; - private static final String VALUE_REGEX = "((\\\\.|[^\\\"])*)"; - private static final String KEY_VALUE_REGEX = - "\\A" + OPTIONAL_WHITESPACE + // start of string - IDENTIFIER_REGEX + OPTIONAL_WHITESPACE + ":" + OPTIONAL_WHITESPACE + // key: - "\"" + VALUE_REGEX + "\""; // "value" - private static final Pattern KEY_VALUE_PATTERN = Pattern.compile(KEY_VALUE_REGEX); - - /** - * Tries to match a key-value pair at the start of the string. If found, add that as a parameter - * of this instance. - * @param str The string to parse. - * @return The remainder of the string without the parsed key-value pair on success, else null. - */ - private String matchValue(String str) { - // Matches: key: "value" - Matcher matcher = KEY_VALUE_PATTERN.matcher(str); - if (!matcher.find()) { - return null; - } - String key = matcher.group(1); - String value = matcher.group(2); - - if (key == null || value == null) { - return null; - } - String unescapedValue = unescapeQuotedString(value); - if (key.equals(TYPE)) { - this.mType = unescapedValue; - } else if (key.equals(PLAIN_TEXT)) { - this.mPlainText = unescapedValue; - } else { - setParameter(key, unescapedValue); - } - - return str.substring(matcher.group(0).length()); - } - - // matches 'markup {' - private static final Pattern OPEN_MARKUP_PATTERN = - Pattern.compile("\\A" + OPTIONAL_WHITESPACE + MARKUP + OPTIONAL_WHITESPACE + "\\{"); - // matches '}' - private static final Pattern CLOSE_MARKUP_PATTERN = - Pattern.compile("\\A" + OPTIONAL_WHITESPACE + "\\}"); - - /** - * Tries to parse a Markup specification from the start of the string. If so, add that markup to - * the list of nested Markup's of this instance. - * @param str The string to parse. - * @return The remainder of the string without the parsed Markup on success, else null. - */ - private String matchMarkup(String str) { - // find and strip "markup {" - Matcher matcher = OPEN_MARKUP_PATTERN.matcher(str); - - if (!matcher.find()) { - return null; - } - String strRemainder = str.substring(matcher.group(0).length()); - // parse and strip markup contents - Markup nestedMarkup = new Markup(); - strRemainder = nestedMarkup.fromReadableString(strRemainder); - - // find and strip "}" - Matcher matcherClose = CLOSE_MARKUP_PATTERN.matcher(strRemainder); - if (!matcherClose.find()) { - return null; - } - strRemainder = strRemainder.substring(matcherClose.group(0).length()); - - // Everything parsed, add markup - this.addNestedMarkup(nestedMarkup); - - // Return remainder - return strRemainder; - } - - /** - * Returns a Markup instance from the string representation generated by toString(). - * @param string The string representation generated by toString(). - * @return The new Markup instance. - * @throws {@link IllegalArgumentException} if the input cannot be correctly parsed. - */ - public static Markup markupFromString(String string) throws IllegalArgumentException { - Markup m = new Markup(); - if (m.fromReadableString(string).isEmpty()) { - return m; - } else { - throw new IllegalArgumentException("Cannot parse input to Markup"); - } - } - - /** - * Compares the specified object with this Markup for equality. - * @return True if the given object is a Markup instance with the same type, plain text, - * parameters and the nested markups are also equal to each other and in the same order. - */ - @Override - public boolean equals(Object o) { - if ( this == o ) return true; - if ( !(o instanceof Markup) ) return false; - Markup m = (Markup) o; - - if (nestedMarkupSize() != this.nestedMarkupSize()) { - return false; - } - - if (!(mType == null ? m.mType == null : mType.equals(m.mType))) { - return false; - } - if (!(mPlainText == null ? m.mPlainText == null : mPlainText.equals(m.mPlainText))) { - return false; - } - if (!equalBundles(mParameters, m.mParameters)) { - return false; - } - - for (int i = 0; i < this.nestedMarkupSize(); i++) { - if (!mNestedMarkups.get(i).equals(m.mNestedMarkups.get(i))) { - return false; - } - } - - return true; - } - - /** - * Checks if two bundles are equal to each other. Used by equals(o). - */ - private boolean equalBundles(Bundle one, Bundle two) { - if (one == null || two == null) { - return false; - } - - if(one.size() != two.size()) { - return false; - } - - Set<String> valuesOne = one.keySet(); - for(String key : valuesOne) { - Object valueOne = one.get(key); - Object valueTwo = two.get(key); - if (valueOne instanceof Bundle && valueTwo instanceof Bundle && - !equalBundles((Bundle) valueOne, (Bundle) valueTwo)) { - return false; - } else if (valueOne == null) { - if (valueTwo != null || !two.containsKey(key)) { - return false; - } - } else if(!valueOne.equals(valueTwo)) { - return false; - } - } - return true; - } - - /** - * Returns an unmodifiable list of the children. - * @return An unmodifiable list of children that throws an {@link UnsupportedOperationException} - * if an attempt is made to modify it - */ - public List<Markup> getNestedMarkups() { - return Collections.unmodifiableList(mNestedMarkups); - } - - /** - * @hide - */ - public Markup(Parcel in) { - mType = in.readString(); - mPlainText = in.readString(); - mParameters = in.readBundle(); - in.readList(mNestedMarkups, Markup.class.getClassLoader()); - } - - /** - * Creates a deep copy of the given markup. - */ - public Markup(Markup markup) { - mType = markup.mType; - mPlainText = markup.mPlainText; - mParameters = markup.mParameters; - for (Markup nested : markup.getNestedMarkups()) { - addNestedMarkup(new Markup(nested)); - } - } - - /** - * @hide - */ - public int describeContents() { - return 0; - } - - /** - * @hide - */ - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mType); - dest.writeString(mPlainText); - dest.writeBundle(mParameters); - dest.writeList(mNestedMarkups); - } - - /** - * @hide - */ - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public Markup createFromParcel(Parcel in) { - return new Markup(in); - } - - public Markup[] newArray(int size) { - return new Markup[size]; - } - }; -} - diff --git a/core/java/android/speech/tts/Utterance.java b/core/java/android/speech/tts/Utterance.java deleted file mode 100644 index 0a29283..0000000 --- a/core/java/android/speech/tts/Utterance.java +++ /dev/null @@ -1,595 +0,0 @@ -package android.speech.tts; - -import java.util.ArrayList; -import java.util.List; - -/** - * This class acts as a builder for {@link Markup} instances. - * <p> - * Each Utterance consists of a list of the semiotic classes ({@link Utterance.TtsCardinal} and - * {@link Utterance.TtsText}). - * <p>Each semiotic class can be supplied with morphosyntactic features - * (gender, animacy, multiplicity and case), it is up to the synthesis engine to use this - * information during synthesis. - * Examples where morphosyntactic features matter: - * <ul> - * <li>In French, the number one is verbalized differently based on the gender of the noun - * it modifies. "un homme" (one man) versus "une femme" (one woman). - * <li>In German the grammatical case (accusative, locative, etc) needs to be included to be - * verbalize correctly. In German you'd have the sentence "Sie haben 1 kilometer vor Ihnen" (You - * have 1 kilometer ahead of you), "1" in this case needs to become inflected to the accusative - * form ("einen") instead of the nominative form "ein". - * </p> - * <p> - * Utterance usage example: - * Markup m1 = new Utterance().append("The Eiffel Tower is") - * .append(new TtsCardinal(324)) - * .append("meters tall."); - * Markup m2 = new Utterance().append("Sie haben") - * .append(new TtsCardinal(1).setGender(Utterance.GENDER_MALE) - * .append("Tag frei."); - * </p> - */ -public class Utterance { - - /*** - * Toplevel type of markup representation. - */ - public static final String TYPE_UTTERANCE = "utterance"; - /*** - * The no_warning_on_fallback parameter can be set to "false" or "true", true indicating that - * no warning will be given when the synthesizer does not support Markup. This is used when - * the user only provides a string to the API instead of a markup. - */ - public static final String KEY_NO_WARNING_ON_FALLBACK = "no_warning_on_fallback"; - - // Gender. - public final static int GENDER_UNKNOWN = 0; - public final static int GENDER_NEUTRAL = 1; - public final static int GENDER_MALE = 2; - public final static int GENDER_FEMALE = 3; - - // Animacy. - public final static int ANIMACY_UNKNOWN = 0; - public final static int ANIMACY_ANIMATE = 1; - public final static int ANIMACY_INANIMATE = 2; - - // Multiplicity. - public final static int MULTIPLICITY_UNKNOWN = 0; - public final static int MULTIPLICITY_SINGLE = 1; - public final static int MULTIPLICITY_DUAL = 2; - public final static int MULTIPLICITY_PLURAL = 3; - - // Case. - public final static int CASE_UNKNOWN = 0; - public final static int CASE_NOMINATIVE = 1; - public final static int CASE_ACCUSATIVE = 2; - public final static int CASE_DATIVE = 3; - public final static int CASE_ABLATIVE = 4; - public final static int CASE_GENITIVE = 5; - public final static int CASE_VOCATIVE = 6; - public final static int CASE_LOCATIVE = 7; - public final static int CASE_INSTRUMENTAL = 8; - - private List<AbstractTts<? extends AbstractTts<?>>> says = - new ArrayList<AbstractTts<? extends AbstractTts<?>>>(); - Boolean mNoWarningOnFallback = null; - - /** - * Objects deriving from this class can be appended to a Utterance. This class uses generics - * so method from this class can return instances of its child classes, resulting in a better - * API (CRTP pattern). - */ - public static abstract class AbstractTts<C extends AbstractTts<C>> { - - protected Markup mMarkup = new Markup(); - - /** - * Empty constructor. - */ - protected AbstractTts() { - } - - /** - * Construct with Markup. - * @param markup - */ - protected AbstractTts(Markup markup) { - mMarkup = markup; - } - - /** - * Returns the type of this class, e.g. "cardinal" or "measure". - * @return The type. - */ - public String getType() { - return mMarkup.getType(); - } - - /** - * A fallback plain text can be provided, in case the engine does not support this class - * type, or even Markup altogether. - * @param plainText A string with the plain text. - * @return This instance. - */ - @SuppressWarnings("unchecked") - public C setPlainText(String plainText) { - mMarkup.setPlainText(plainText); - return (C) this; - } - - /** - * Returns the plain text (fallback) string. - * @return Plain text string or null if not set. - */ - public String getPlainText() { - return mMarkup.getPlainText(); - } - - /** - * Populates the plainText if not set and builds a Markup instance. - * @return The Markup object describing this instance. - */ - public Markup getMarkup() { - return new Markup(mMarkup); - } - - @SuppressWarnings("unchecked") - protected C setParameter(String key, String value) { - mMarkup.setParameter(key, value); - return (C) this; - } - - protected String getParameter(String key) { - return mMarkup.getParameter(key); - } - - @SuppressWarnings("unchecked") - protected C removeParameter(String key) { - mMarkup.removeParameter(key); - return (C) this; - } - - /** - * Returns a string representation of this instance, can be deserialized to an equal - * Utterance instance. - */ - public String toString() { - return mMarkup.toString(); - } - - /** - * Returns a generated plain text alternative for this instance if this instance isn't - * better representated by the list of it's children. - * @return Best effort plain text representation of this instance, can be null. - */ - public String generatePlainText() { - return null; - } - } - - public static abstract class AbstractTtsSemioticClass<C extends AbstractTtsSemioticClass<C>> - extends AbstractTts<C> { - // Keys. - private static final String KEY_GENDER = "gender"; - private static final String KEY_ANIMACY = "animacy"; - private static final String KEY_MULTIPLICITY = "multiplicity"; - private static final String KEY_CASE = "case"; - - protected AbstractTtsSemioticClass() { - super(); - } - - protected AbstractTtsSemioticClass(Markup markup) { - super(markup); - } - - @SuppressWarnings("unchecked") - public C setGender(int gender) { - if (gender < 0 || gender > 3) { - throw new IllegalArgumentException("Only four types of gender can be set: " + - "unknown, neutral, maculine and female."); - } - if (gender != GENDER_UNKNOWN) { - setParameter(KEY_GENDER, String.valueOf(gender)); - } else { - setParameter(KEY_GENDER, null); - } - return (C) this; - } - - public int getGender() { - String gender = mMarkup.getParameter(KEY_GENDER); - return gender != null ? Integer.valueOf(gender) : GENDER_UNKNOWN; - } - - @SuppressWarnings("unchecked") - public C setAnimacy(int animacy) { - if (animacy < 0 || animacy > 2) { - throw new IllegalArgumentException( - "Only two types of animacy can be set: unknown, animate and inanimate"); - } - if (animacy != ANIMACY_UNKNOWN) { - setParameter(KEY_ANIMACY, String.valueOf(animacy)); - } else { - setParameter(KEY_ANIMACY, null); - } - return (C) this; - } - - public int getAnimacy() { - String animacy = getParameter(KEY_ANIMACY); - return animacy != null ? Integer.valueOf(animacy) : ANIMACY_UNKNOWN; - } - - @SuppressWarnings("unchecked") - public C setMultiplicity(int multiplicity) { - if (multiplicity < 0 || multiplicity > 3) { - throw new IllegalArgumentException( - "Only four types of multiplicity can be set: unknown, single, dual and " + - "plural."); - } - if (multiplicity != MULTIPLICITY_UNKNOWN) { - setParameter(KEY_MULTIPLICITY, String.valueOf(multiplicity)); - } else { - setParameter(KEY_MULTIPLICITY, null); - } - return (C) this; - } - - public int getMultiplicity() { - String multiplicity = mMarkup.getParameter(KEY_MULTIPLICITY); - return multiplicity != null ? Integer.valueOf(multiplicity) : MULTIPLICITY_UNKNOWN; - } - - @SuppressWarnings("unchecked") - public C setCase(int grammaticalCase) { - if (grammaticalCase < 0 || grammaticalCase > 8) { - throw new IllegalArgumentException( - "Only nine types of grammatical case can be set."); - } - if (grammaticalCase != CASE_UNKNOWN) { - setParameter(KEY_CASE, String.valueOf(grammaticalCase)); - } else { - setParameter(KEY_CASE, null); - } - return (C) this; - } - - public int getCase() { - String grammaticalCase = mMarkup.getParameter(KEY_CASE); - return grammaticalCase != null ? Integer.valueOf(grammaticalCase) : CASE_UNKNOWN; - } - } - - /** - * Class that contains regular text, synthesis engine pronounces it using its regular pipeline. - * Parameters: - * <ul> - * <li>Text: the text to synthesize</li> - * </ul> - */ - public static class TtsText extends AbstractTtsSemioticClass<TtsText> { - - // The type of this node. - protected static final String TYPE_TEXT = "text"; - // The text parameter stores the text to be synthesized. - private static final String KEY_TEXT = "text"; - - /** - * Default constructor. - */ - public TtsText() { - mMarkup.setType(TYPE_TEXT); - } - - /** - * Constructor that sets the text to be synthesized. - * @param text The text to be synthesized. - */ - public TtsText(String text) { - this(); - setText(text); - } - - /** - * Constructs a TtsText with the values of the Markup, does not check if the given Markup is - * of the right type. - */ - private TtsText(Markup markup) { - super(markup); - } - - /** - * Sets the text to be synthesized. - * @return This instance. - */ - public TtsText setText(String text) { - setParameter(KEY_TEXT, text); - return this; - } - - /** - * Returns the text to be synthesized. - * @return This instance. - */ - public String getText() { - return getParameter(KEY_TEXT); - } - - /** - * Generates a best effort plain text, in this case simply the text. - */ - @Override - public String generatePlainText() { - return getText(); - } - } - - /** - * Contains a cardinal. - * Parameters: - * <ul> - * <li>integer: the integer to synthesize</li> - * </ul> - */ - public static class TtsCardinal extends AbstractTtsSemioticClass<TtsCardinal> { - - // The type of this node. - protected static final String TYPE_CARDINAL = "cardinal"; - // The parameter integer stores the integer to synthesize. - private static final String KEY_INTEGER = "integer"; - - /** - * Default constructor. - */ - public TtsCardinal() { - mMarkup.setType(TYPE_CARDINAL); - } - - /** - * Constructor that sets the integer to be synthesized. - */ - public TtsCardinal(int integer) { - this(); - setInteger(integer); - } - - /** - * Constructor that sets the integer to be synthesized. - */ - public TtsCardinal(String integer) { - this(); - setInteger(integer); - } - - /** - * Constructs a TtsText with the values of the Markup. - * Does not check if the given Markup is of the right type. - */ - private TtsCardinal(Markup markup) { - super(markup); - } - - /** - * Sets the integer. - * @return This instance. - */ - public TtsCardinal setInteger(int integer) { - return setInteger(String.valueOf(integer)); - } - - /** - * Sets the integer. - * @param integer A non-empty string of digits with an optional '-' in front. - * @return This instance. - */ - public TtsCardinal setInteger(String integer) { - if (!integer.matches("-?\\d+")) { - throw new IllegalArgumentException("Expected a cardinal: \"" + integer + "\""); - } - setParameter(KEY_INTEGER, integer); - return this; - } - - /** - * Returns the integer parameter. - */ - public String getInteger() { - return getParameter(KEY_INTEGER); - } - - /** - * Generates a best effort plain text, in this case simply the integer. - */ - @Override - public String generatePlainText() { - return getInteger(); - } - } - - /** - * Default constructor. - */ - public Utterance() {} - - /** - * Returns the plain text of a given Markup if it was set; if it's not set, recursively call the - * this same method on its children. - */ - private String constructPlainText(Markup m) { - StringBuilder plainText = new StringBuilder(); - if (m.getPlainText() != null) { - plainText.append(m.getPlainText()); - } else { - for (Markup nestedMarkup : m.getNestedMarkups()) { - String nestedPlainText = constructPlainText(nestedMarkup); - if (!nestedPlainText.isEmpty()) { - if (plainText.length() != 0) { - plainText.append(" "); - } - plainText.append(nestedPlainText); - } - } - } - return plainText.toString(); - } - - /** - * Creates a Markup instance with auto generated plain texts for the relevant nodes, in case the - * user has not provided one already. - * @return A Markup instance representing this utterance. - */ - public Markup createMarkup() { - Markup markup = new Markup(TYPE_UTTERANCE); - StringBuilder plainText = new StringBuilder(); - for (AbstractTts<? extends AbstractTts<?>> say : says) { - // Get a copy of this markup, and generate a plaintext for it if is not set. - Markup sayMarkup = say.getMarkup(); - if (sayMarkup.getPlainText() == null) { - sayMarkup.setPlainText(say.generatePlainText()); - } - if (plainText.length() != 0) { - plainText.append(" "); - } - plainText.append(constructPlainText(sayMarkup)); - markup.addNestedMarkup(sayMarkup); - } - if (mNoWarningOnFallback != null) { - markup.setParameter(KEY_NO_WARNING_ON_FALLBACK, - mNoWarningOnFallback ? "true" : "false"); - } - markup.setPlainText(plainText.toString()); - return markup; - } - - /** - * Appends an element to this Utterance instance. - * @return this instance - */ - public Utterance append(AbstractTts<? extends AbstractTts<?>> say) { - says.add(say); - return this; - } - - private Utterance append(Markup markup) { - if (markup.getType().equals(TtsText.TYPE_TEXT)) { - append(new TtsText(markup)); - } else if (markup.getType().equals(TtsCardinal.TYPE_CARDINAL)) { - append(new TtsCardinal(markup)); - } else { - // Unknown node, a class we don't know about. - if (markup.getPlainText() != null) { - append(new TtsText(markup.getPlainText())); - } else { - // No plainText specified; add its children - // seperately. In case of a new prosody node, - // we would still verbalize it correctly. - for (Markup nested : markup.getNestedMarkups()) { - append(nested); - } - } - } - return this; - } - - /** - * Returns a string representation of this Utterance instance. Can be deserialized back to an - * Utterance instance with utteranceFromString(). Can be used to store utterances to be used - * at a later time. - */ - public String toString() { - String out = "type: \"" + TYPE_UTTERANCE + "\""; - if (mNoWarningOnFallback != null) { - out += " no_warning_on_fallback: \"" + (mNoWarningOnFallback ? "true" : "false") + "\""; - } - for (AbstractTts<? extends AbstractTts<?>> say : says) { - out += " markup { " + say.getMarkup().toString() + " }"; - } - return out; - } - - /** - * Returns an Utterance instance from the string representation generated by toString(). - * @param string The string representation generated by toString(). - * @return The new Utterance instance. - * @throws {@link IllegalArgumentException} if the input cannot be correctly parsed. - */ - static public Utterance utteranceFromString(String string) throws IllegalArgumentException { - Utterance utterance = new Utterance(); - Markup markup = Markup.markupFromString(string); - if (!markup.getType().equals(TYPE_UTTERANCE)) { - throw new IllegalArgumentException("Top level markup should be of type \"" + - TYPE_UTTERANCE + "\", but was of type \"" + - markup.getType() + "\".") ; - } - for (Markup nestedMarkup : markup.getNestedMarkups()) { - utterance.append(nestedMarkup); - } - return utterance; - } - - /** - * Appends a new TtsText with the given text. - * @param text The text to synthesize. - * @return This instance. - */ - public Utterance append(String text) { - return append(new TtsText(text)); - } - - /** - * Appends a TtsCardinal representing the given number. - * @param integer The integer to synthesize. - * @return this - */ - public Utterance append(int integer) { - return append(new TtsCardinal(integer)); - } - - /** - * Returns the n'th element in this Utterance. - * @param i The index. - * @return The n'th element in this Utterance. - * @throws {@link IndexOutOfBoundsException} - if i < 0 || i >= size() - */ - public AbstractTts<? extends AbstractTts<?>> get(int i) { - return says.get(i); - } - - /** - * Returns the number of elements in this Utterance. - * @return The number of elements in this Utterance. - */ - public int size() { - return says.size(); - } - - @Override - public boolean equals(Object o) { - if ( this == o ) return true; - if ( !(o instanceof Utterance) ) return false; - Utterance utt = (Utterance) o; - - if (says.size() != utt.says.size()) { - return false; - } - - for (int i = 0; i < says.size(); i++) { - if (!says.get(i).getMarkup().equals(utt.says.get(i).getMarkup())) { - return false; - } - } - return true; - } - - /** - * Can be set to true or false, true indicating that the user provided only a string to the API, - * at which the system will not issue a warning if the synthesizer falls back onto the plain - * text when the synthesizer does not support Markup. - */ - public Utterance setNoWarningOnFallback(boolean noWarning) { - mNoWarningOnFallback = noWarning; - return this; - } -} |