Example #1
0
 /**
  * Convert an item in the Syllable relation into XML, inserting it at the specified location in
  * the XML tree.
  *
  * @param deep whether to create a deep structure of <syllable> and <ph> elements or not.
  */
 protected String insertSyllable(Item syllableItem, Element token, boolean deep) {
   if (syllableItem == null || token == null) {
     throw new NullPointerException("Null arguments to insertSyllable()");
   }
   if (!token.getTagName().equals(MaryXML.TOKEN)) {
     throw new IllegalArgumentException("Syllables can only be inserted in <t> elements");
   }
   Document doc = token.getOwnerDocument();
   Element syllable = null;
   StringBuilder sampa = new StringBuilder();
   if (deep) {
     syllable = MaryXML.createElement(doc, MaryXML.SYLLABLE);
     token.appendChild(syllable);
   }
   if (syllableItem.getFeatures().isPresent("accent")) {
     String accentString = syllableItem.getFeatures().getString("accent");
     if (deep) syllable.setAttribute("accent", accentString);
     token.setAttribute("accent", accentString);
   }
   if (syllableItem.getFeatures().isPresent("stress")) {
     String stressString = syllableItem.getFeatures().getString("stress");
     if (!stressString.equals("0")) {
       if (deep) syllable.setAttribute("stress", stressString);
       if (stressString.equals("1")) sampa.append("'");
       else if (stressString.equals("2")) sampa.append(",");
     }
   }
   // Any segments?
   Item segmentItem = syllableItem.getDaughter();
   while (segmentItem != null) {
     if (sampa.length() > 0) sampa.append(" ");
     sampa.append(insertSegment(segmentItem, syllable, deep));
     segmentItem = segmentItem.getNext();
   }
   String sampaString = sampa.toString();
   if (deep) syllable.setAttribute("ph", sampaString);
   // Any boundary?
   if (syllableItem.getFeatures().isPresent("endtone")
       && !tokenItemHasFollowingBoundary(
           syllableItem.getParent().getItemAs(Relation.TOKEN).getParent())) {
     String endtone = syllableItem.getFeatures().getString("endtone");
     if (!endtone.equals("")) {
       Element boundary = MaryXML.createElement(doc, MaryXML.BOUNDARY);
       boundary.setAttribute("tone", endtone);
       boundary.setAttribute("breakindex", "4");
       boundary.setAttribute("duration", "200");
       // And the boundary comes after the current token:
       token.getParentNode().appendChild(boundary);
     }
   }
   return sampaString;
 }
Example #2
0
 /**
  * Convert an item in the Segment relation into XML, inserting it at the specified location in the
  * XML tree.
  *
  * @param deep whether to create a deep structure of <syllable> and <ph> elements or not.
  */
 protected String insertSegment(Item segmentItem, Element syllable, boolean deep) {
   // allow for syllable == null if not deep:
   if (segmentItem == null || deep && syllable == null) {
     throw new NullPointerException("Null arguments to insertSegment()");
   }
   if (deep && !syllable.getTagName().equals(MaryXML.SYLLABLE)) {
     throw new IllegalArgumentException("Segments can only be inserted in <syllable> elements");
   }
   String segmentString = segmentItem.toString();
   Voice maryVoice = FreeTTSVoices.getMaryVoice(segmentItem.getUtterance().getVoice());
   if (deep) {
     Document doc = syllable.getOwnerDocument();
     Element segment = MaryXML.createElement(doc, MaryXML.PHONE);
     syllable.appendChild(segment);
     segment.setAttribute("p", segmentString);
     if (segmentItem.getFeatures().isPresent("end")) {
       float endInSeconds = segmentItem.getFeatures().getFloat("end");
       int endInMillis = (int) (1000 * endInSeconds);
       segment.setAttribute("end", String.valueOf(endInMillis));
     }
     if (segmentItem.getFeatures().isPresent("mbr_dur")) {
       int mbrDur = segmentItem.getFeatures().getInt("mbr_dur");
       segment.setAttribute("d", String.valueOf(mbrDur));
     }
     if (segmentItem.getFeatures().isPresent("mbr_targets")) {
       String mbrTargets = segmentItem.getFeatures().getString("mbr_targets");
       if (!mbrTargets.equals("")) {
         segment.setAttribute("f0", mbrTargets);
       }
     }
   }
   return segmentString;
 }
Example #3
0
 /**
  * For a given utterance or token, see if there are any prosodic settings defined, and if so,
  * create a corresponding prosody element as a child of insertHere.
  *
  * @param featureSet an utterance, optionally containing prosody settings
  * @param insertHere an element into which to insert the new prosody element if required.
  * @return the new prosody element, or null if none was created.
  */
 protected Element insertProsodySettings(Element insertHere, FeatureSet featureSet) {
   if (insertHere == null || featureSet == null)
     throw new NullPointerException("I thoroughly dislike getting null arguments!");
   boolean haveProsodyInfo = false;
   for (String att : XML2UttBase.PROSODY_ATTRIBUTES) {
     if (featureSet.getString(att) != null) {
       haveProsodyInfo = true;
       break;
     }
   }
   if (!haveProsodyInfo) {
     return null;
   }
   Document doc = insertHere.getOwnerDocument();
   Element prosody = MaryXML.createElement(doc, MaryXML.PROSODY);
   insertHere.appendChild(prosody);
   for (String att : XML2UttBase.PROSODY_ATTRIBUTES) {
     String val = featureSet.getString(att);
     if (val != null) {
       prosody.setAttribute(att, val);
     }
   }
   return prosody;
 }
Example #4
0
  public MaryData process(MaryData d) throws Exception {
    Document doc = MaryXML.newDocument();
    Element root = doc.getDocumentElement();
    Locale locale = d.getLocale();
    if (locale != null) {
      root.setAttribute("xml:lang", MaryUtils.locale2xmllang(locale));
    }
    Element paragraph = MaryXML.appendChildElement(root, MaryXML.PARAGRAPH);

    List<Utterance> utterances = d.getUtterances();
    Iterator<Utterance> it = utterances.iterator();
    while (it.hasNext()) {
      Utterance utterance = it.next();
      Element insertHere = paragraph;

      if (logger.getEffectiveLevel().equals(Level.DEBUG)) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        utterance.dump(pw, 2, name(), true); // padding, justRelations
        logger.debug("Converting the following Utterance to XML:\n" + sw.toString());
      }

      // Make sure we have the correct voice:
      Voice maryVoice = null;
      if (utterance.getVoice() != null) {
        maryVoice = FreeTTSVoices.getMaryVoice(utterance.getVoice());
      }
      if (maryVoice != null) {
        if (insertHere.getTagName().equals(MaryXML.VOICE)) {
          // Are utterance voice and voiceElement voice the same?
          if (maryVoice.hasName(insertHere.getAttribute("name"))) {
            // then insertHere is set OK, leave it like it is
          } else {
            // get one higher up, create new voice element after this
            // one, and make insertHere point to the new voice element
            Element parent = (Element) insertHere.getParentNode();
            Element newVoice = MaryXML.createElement(doc, MaryXML.VOICE);
            parent.appendChild(newVoice);
            newVoice.setAttribute("name", maryVoice.getName());
            insertHere = newVoice;
          }
        } else {
          // Check if the last child of insertHere is a voice with the right name
          Element lastChild = MaryDomUtils.getLastChildElement(insertHere);
          if (lastChild != null
              && lastChild.getTagName().equals(MaryXML.VOICE)
              && maryVoice.hasName(lastChild.getAttribute("name"))) {
            insertHere = lastChild;
          } else {
            // create a new voice element, insert it as a child of this
            // node, and let insertHere point to it
            Element newVoice = MaryXML.createElement(doc, MaryXML.VOICE);
            insertHere.appendChild(newVoice);
            newVoice.setAttribute("name", maryVoice.getName());
            insertHere = newVoice;
          }
        }
        // Now insertHere is the correct <voice> element.

        // Any prosodic settings to insert?
        Element prosody = insertProsodySettings(insertHere, utterance);
        if (prosody != null) insertHere = prosody;
      }
      // Create a sentence element <s> for this utterance:
      Element sentence = MaryXML.createElement(doc, MaryXML.SENTENCE);
      insertHere.appendChild(sentence);

      fillSentence(sentence, utterance);
    }

    if (logger.getEffectiveLevel().equals(Level.DEBUG)) {
      logger.debug("Constructed the following XML structure:");
      MaryNormalisedWriter mnw = new MaryNormalisedWriter();
      ByteArrayOutputStream debugOut = new ByteArrayOutputStream();
      mnw.output(doc, debugOut);
      logger.debug(debugOut.toString());
    }

    MaryData output = new MaryData(outputType(), d.getLocale());
    output.setDocument(doc);
    return output;
  }
Example #5
0
  /**
   * Convert an item in the Token relation into XML, inserting it at the specified location in the
   * XML tree.
   *
   * @param deep whether to create a deep structure of <syllable> and <ph> elements or not.
   */
  protected void insertToken(Item tokenItem, Element parent, boolean deep) {
    if (tokenItem == null || parent == null) {
      throw new NullPointerException("Null arguments to insertToken()");
    }
    Document doc = parent.getOwnerDocument();
    Voice maryVoice = null;
    if (tokenItem.getUtterance().getVoice() != null) {
      maryVoice = FreeTTSVoices.getMaryVoice(tokenItem.getUtterance().getVoice());
    }
    AllophoneSet allophoneSet = (AllophoneSet) tokenItem.getUtterance().getObject("allophoneset");
    if (allophoneSet == null) {
      throw new NullPointerException(
          "Utterance does not have an AllophoneSet -- should have been set in XML2UttBase.process()");
    }
    Element insertHere = parent;
    boolean needMtu = false;
    boolean insertPhonesFromToken = tokenItem.getFeatures().isPresent("phones");
    Item testWordItem = null;
    if (tokenItem.getFeatures().isPresent("precedingMarks")) {
      String marks = tokenItem.getFeatures().getString("precedingMarks");
      StringTokenizer markTok = new StringTokenizer(marks, ",");
      while (markTok.hasMoreTokens()) {
        String markStr = markTok.nextToken();
        Element markEl = MaryXML.createElement(doc, MaryXML.MARK);
        markEl.setAttribute("name", markStr);
        insertHere.appendChild(markEl);
      }
    }
    // Any boundary preceding the word?
    if (tokenItem.getFeatures().isPresent("precedingBoundaryTone")
        || tokenItem.getFeatures().isPresent("precedingBoundaryBreakindex")
        || tokenItem.getFeatures().isPresent("precedingBoundaryDuration")) {
      Element boundary = MaryXML.createElement(doc, MaryXML.BOUNDARY);
      insertHere.appendChild(boundary);
      if (tokenItem.getFeatures().isPresent("precedingBoundaryTone"))
        boundary.setAttribute("tone", tokenItem.getFeatures().getString("precedingBoundaryTone"));
      if (tokenItem.getFeatures().isPresent("precedingBoundaryBreakindex"))
        boundary.setAttribute(
            "breakindex", tokenItem.getFeatures().getString("precedingBoundaryBreakindex"));
      if (tokenItem.getFeatures().isPresent("precedingBoundaryDuration"))
        boundary.setAttribute(
            "duration", tokenItem.getFeatures().getString("precedingBoundaryDuration"));
    }
    if (tokenItem.getNthDaughter(1) != null
        || (testWordItem = tokenItem.getDaughter()) != null
            && !testWordItem.toString().equals(tokenItem.toString().toLowerCase())) {
      // Token has more than one daughter, or the only daughter is an
      // expanded form -- need to create an <mtu> element
      needMtu = true;
      Element mtu = MaryXML.createElement(doc, MaryXML.MTU);
      parent.appendChild(mtu);
      mtu.setAttribute("orig", tokenItem.toString());
      insertHere = mtu;
    }
    // Any words?
    FeatureSet tokenFeatureSet = tokenItem.getFeatures();
    Item tokenDaughter = tokenItem.getDaughter();
    if (tokenDaughter == null) { // no word relation present
      // Create a <t> element based on token information only
      Element t = MaryXML.createElement(doc, MaryXML.TOKEN);
      insertHere.appendChild(t);
      MaryDomUtils.setTokenText(t, tokenItem.toString());
      if (insertPhonesFromToken) {
        String[] phones = (String[]) tokenItem.getFeatures().getObject("phones");
        t.setAttribute("ph", phoneArray2phoneString(allophoneSet, phones));
        insertPhonesFromToken = false;
      }
      if (tokenFeatureSet.isPresent("accent")) {
        t.setAttribute("accent", tokenFeatureSet.getString("accent"));
      }
    }
    while (tokenDaughter != null) {
      // Part of speech, if present, is associated with the word
      // relation.
      Item wordItem = tokenDaughter.getItemAs("Word");
      Element t = null;
      StringBuilder sampa = new StringBuilder();
      if (wordItem != null) {
        t = MaryXML.createElement(doc, MaryXML.TOKEN);
        insertHere.appendChild(t);
        String tokenText = null;
        // If there is only one, non-expanded word, use text from
        // tokenItem in order to retain capitalisation:
        if (needMtu) tokenText = wordItem.toString();
        else tokenText = tokenItem.toString();
        MaryDomUtils.setTokenText(t, tokenText);
        if (insertPhonesFromToken) {
          String[] phones = (String[]) tokenItem.getFeatures().getObject("phones");
          t.setAttribute("ph", phoneArray2phoneString(allophoneSet, phones));
          insertPhonesFromToken = false;
        } else if (wordItem.getFeatures().isPresent("phones")) {
          // the word item has phones, take them only if there are no Token phones
          String[] phones = (String[]) wordItem.getFeatures().getObject("phones");
          t.setAttribute("ph", phoneArray2phoneString(allophoneSet, phones));
        }
        if (tokenFeatureSet.isPresent("accent")) {
          t.setAttribute("accent", tokenFeatureSet.getString("accent"));
        }
        FeatureSet wordFeatureSet = wordItem.getFeatures();
        if (wordFeatureSet.isPresent("pos")) t.setAttribute("pos", wordFeatureSet.getString("pos"));
      }
      // Any syllables?
      Item sylStruct = tokenDaughter.getItemAs("SylStructure");
      if (sylStruct != null && sylStruct.hasDaughters()) {
        Item syllableItem = sylStruct.getDaughter();
        while (syllableItem != null) {
          if (sampa.length() > 0) sampa.append(" - ");
          sampa.append(insertSyllable(syllableItem, t, deep));
          syllableItem = syllableItem.getNext();
        }
      }
      if (sampa.length() > 0) t.setAttribute("ph", sampa.toString());
      tokenDaughter = tokenDaughter.getNext();
    }
    // Any marks after the word but before the punctuation?
    if (tokenItem.getFeatures().isPresent("prePuncMarks")) {
      String marks = tokenItem.getFeatures().getString("prePuncMarks");
      StringTokenizer markTok = new StringTokenizer(marks, ",");
      while (markTok.hasMoreTokens()) {
        String markStr = markTok.nextToken();
        Element markEl = MaryXML.createElement(doc, MaryXML.MARK);
        markEl.setAttribute("name", markStr);
        insertHere.appendChild(markEl);
      }
    }
    // Any punctuation after the word?
    if (tokenItem.getFeatures().isPresent("punc")) {
      String puncString = tokenItem.getFeatures().getString("punc");
      if (!puncString.equals("")) {
        Element punctuation = MaryXML.createElement(doc, MaryXML.TOKEN);
        MaryDomUtils.setTokenText(punctuation, puncString);
        String pos = null;
        if (puncString.equals(",")) pos = "$,";
        else pos = "$PUNCT";
        punctuation.setAttribute("pos", pos);
        parent.appendChild(punctuation);
      }
    }
    // Any marks after the word?
    if (tokenItem.getFeatures().isPresent("followingMarks")) {
      String marks = tokenItem.getFeatures().getString("followingMarks");
      StringTokenizer markTok = new StringTokenizer(marks, ",");
      while (markTok.hasMoreTokens()) {
        String markStr = markTok.nextToken();
        Element markEl = MaryXML.createElement(doc, MaryXML.MARK);
        markEl.setAttribute("name", markStr);
        insertHere.appendChild(markEl);
      }
    }
    // Any boundary after the word?
    if (tokenItemHasFollowingBoundary(tokenItem)) {
      Element boundary = MaryXML.createElement(doc, MaryXML.BOUNDARY);
      insertHere.appendChild(boundary);
      if (tokenItem.getFeatures().isPresent("followingBoundaryTone"))
        boundary.setAttribute("tone", tokenItem.getFeatures().getString("followingBoundaryTone"));

      int breakindex = 0;
      if (tokenItem.getFeatures().isPresent("followingBoundaryBreakindex")) {
        String breakindexString = tokenItem.getFeatures().getString("followingBoundaryBreakindex");
        boundary.setAttribute("breakindex", breakindexString);
        try {
          breakindex = Integer.parseInt(breakindexString);
        } catch (NumberFormatException nfe) {
        }
      }

      if (tokenItem.getFeatures().isPresent("followingBoundaryDuration"))
        boundary.setAttribute(
            "duration", tokenItem.getFeatures().getString("followingBoundaryDuration"));
      else { // estimate reasonable duration values based on the break index
        if (breakindex >= 4) {
          boundary.setAttribute("duration", "400");
        } else if (breakindex == 3) {
          boundary.setAttribute("duration", "200");
        } // and no duration for boundaries with bi < 3
      }
    }
  }
Example #6
0
 /**
  * Depending on the data type, find the right information in the utterance and insert it into the
  * sentence.
  */
 protected final void fillSentence(Element sentence, Utterance utterance) {
   Document doc = sentence.getOwnerDocument();
   Relation tokenRelation = utterance.getRelation(Relation.TOKEN);
   if (tokenRelation == null) return;
   Item tokenItem = tokenRelation.getHead();
   Relation phraseRelation = utterance.getRelation(Relation.PHRASE);
   Item phraseItem = null;
   if (phraseRelation != null) {
     phraseItem = phraseRelation.getHead();
     // Challenge: Bring token and phrase relations together. They have
     // common children, which can be interpreted as Word or SylStructure
     // items. Algorithm: For a given phrase, look at tokens. If a token's
     // first child, interpreted in the phrase relation, has the phrase as
     // its parent, then insert the token and all its children, and move to
     // the next token. If not, move to the next phrase.
     while (phraseItem != null) {
       // The phrases:
       Element phrase = MaryXML.createElement(doc, MaryXML.PHRASE);
       sentence.appendChild(phrase);
       Element insertHere = phrase;
       // Is this token part of this phrase?
       while (tokenItem != null
           && tokenItem.getDaughter().findItem("R:Phrase.parent").equals(phraseItem)) {
         FeatureSet tokenFeatures = tokenItem.getFeatures();
         if (tokenFeatures.isPresent(XML2UttBase.PROSODY_START)) {
           Element prosody = insertProsodySettings(insertHere, tokenFeatures);
           if (prosody != null) {
             insertHere = prosody;
           }
         }
         insertToken(tokenItem, phrase, true); // create deep structure
         if (tokenFeatures.isPresent(XML2UttBase.PROSODY_END)) {
           assert insertHere.getTagName().equals(MaryXML.PROSODY);
           insertHere = (Element) insertHere.getParentNode();
         }
         tokenItem = tokenItem.getNext();
       }
       phraseItem = phraseItem.getNext();
     }
   } else {
     // No phrase relation, simply create tokens.
     Element insertHere = sentence;
     while (tokenItem != null) {
       FeatureSet tokenFeatures = tokenItem.getFeatures();
       if (tokenFeatures.isPresent(XML2UttBase.PROSODY_START)) {
         Element prosody = insertProsodySettings(insertHere, tokenFeatures);
         if (prosody != null) {
           insertHere = prosody;
         }
       }
       insertToken(tokenItem, insertHere);
       if (tokenFeatures.isPresent(XML2UttBase.PROSODY_END)) {
         if (insertHere.getTagName().equals(MaryXML.PROSODY)) {
           insertHere = (Element) insertHere.getParentNode();
         } // else, we are looking at an empty prosody tag with no arguments, which is being
         // deleted right now.
       }
       tokenItem = tokenItem.getNext();
     }
   }
 }