public MaryData process(MaryData d) throws Exception {
    Document doc = d.getDocument();
    NodeIterator it = MaryDomUtils.createNodeIterator(doc, doc, MaryXML.TOKEN);
    Element t = null;
    while ((t = (Element) it.nextNode()) != null) {
      String text;

      // Do not touch tokens for which a transcription is already
      // given (exception: transcription contains a '*' character:
      if (t.hasAttribute("ph") && !t.getAttribute("ph").contains("*")) {
        continue;
      }
      if (t.hasAttribute("sounds_like")) text = t.getAttribute("sounds_like");
      else text = MaryDomUtils.tokenText(t);

      String pos = null;
      // use part-of-speech if available
      if (t.hasAttribute("pos")) {
        pos = t.getAttribute("pos");
      }

      if (text != null
          && !text.equals("")
          && (pos == null || !pos.startsWith("$") /*punctuation*/)) {
        // If text consists of several parts (e.g., because that was
        // inserted into the sounds_like attribute), each part
        // is transcribed separately.
        StringBuilder ph = new StringBuilder();
        String g2pMethod = null;
        StringTokenizer st = new StringTokenizer(text, " -");
        while (st.hasMoreTokens()) {
          String graph = st.nextToken();
          StringBuilder helper = new StringBuilder();

          String phon = phonemise(graph, pos, helper);

          if (ph.length() == 0) { // first part
            // The g2pMethod of the combined beast is
            // the g2pMethod of the first constituant.
            g2pMethod = helper.toString();
            ph.append(phon);
          } else { // following parts
            ph.append(" - ");
            // Reduce primary to secondary stress:
            ph.append(phon.replace('\'', ','));
          }
        }

        if (ph != null && ph.length() > 0) {
          setPh(t, ph.toString());
          t.setAttribute("g2p_method", g2pMethod);
        }
      }
    }
    MaryData result = new MaryData(outputType(), d.getLocale());
    result.setDocument(doc);
    return result;
  }
Beispiel #2
0
 /**
  * For an element in a MaryXML document, do what you can to determine the appropriate
  * AllophoneSet. First search for the suitable voice, then if that fails, go by locale.
  *
  * @param e
  * @return an allophone set if there is any way of determining it, or null.
  * @throws MaryConfigurationException if a suitable allophone set exists in principle, but there
  *     were problems loading it.
  */
 public static AllophoneSet determineAllophoneSet(Element e) throws MaryConfigurationException {
   AllophoneSet allophoneSet = null;
   Element voice = (Element) MaryDomUtils.getAncestor(e, MaryXML.VOICE);
   Voice maryVoice = Voice.getVoice(voice);
   if (maryVoice == null) {
     // Determine Locale in order to use default voice
     Locale locale =
         MaryUtils.string2locale(
             e.getOwnerDocument().getDocumentElement().getAttribute("xml:lang"));
     maryVoice = Voice.getDefaultVoice(locale);
   }
   if (maryVoice != null) {
     allophoneSet = maryVoice.getAllophoneSet();
   } else {
     Locale locale =
         MaryUtils.string2locale(
             e.getOwnerDocument().getDocumentElement().getAttribute("xml:lang"));
     allophoneSet = determineAllophoneSet(locale);
   }
   return allophoneSet;
 }
Beispiel #3
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;
  }
Beispiel #4
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
      }
    }
  }