Package com.sun.speech.freetts.en

Source Code of com.sun.speech.freetts.en.F0ModelTerm

/**
* Portions Copyright 2001 Sun Microsystems, Inc.
* Portions Copyright 1999-2001 Language Technologies Institute,
* Carnegie Mellon University.
* All Rights Reserved.  Use is subject to license terms.
*
* See the file "license.terms" for information on usage and
* redistribution of this file, and for a DISCLAIMER OF ALL
* WARRANTIES.
*/
package com.sun.speech.freetts.en;

import com.sun.speech.freetts.UtteranceProcessor;
import com.sun.speech.freetts.Voice;
import com.sun.speech.freetts.Relation;
import com.sun.speech.freetts.Utterance;
import com.sun.speech.freetts.ProcessException;
import com.sun.speech.freetts.PathExtractorImpl;
import com.sun.speech.freetts.PathExtractor;
import com.sun.speech.freetts.Item;
import java.util.StringTokenizer;
import java.util.NoSuchElementException;
import java.util.List;
import java.util.ArrayList;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.net.URL;


/**
* Calculates the F0 curve for an utterance based on the Black and
* Hunt article "Generating F0 Contours from ToBI Labels Using Linear
* Regression," ICSLP96, vol. 3, pp 1385-1388, Philadelphia,
* PA. 1996.
*/
public class ContourGenerator implements UtteranceProcessor {
    private final static PathExtractor endPath =
        new PathExtractorImpl("R:SylStructure.daughter.R:Segment.p.end",
                              true);
    private final static PathExtractor lastDaughterEndPath =
  new PathExtractorImpl("R:SylStructure.daughtern.end",
                              true);
    private final static PathExtractor postBreakPath =
  new PathExtractorImpl("R:SylStructure.daughter.R:Segment.p.name",
                              true);
    private final static PathExtractor preBreakPath =
        new PathExtractorImpl("R:SylStructure.daughtern.R:Segment.n.name",
                              true);
    private final static PathExtractor vowelMidPath =
        new PathExtractorImpl("R:Segment.p.end",
                              true);
    private final static PathExtractor localF0Shift =
        new PathExtractorImpl(
      "R:SylStructure.parent.R:Token.parent.local_f0_shift", true);
    private final static PathExtractor localF0Range =
        new PathExtractorImpl(
      "R:SylStructure.parent.R:Token.parent.local_f0_range", true);

    private final float modelMean;
    private final float modelStddev;
    private  F0ModelTerm[] terms = { null };

    /**
     * Creates a ContourGenerator utterance processor.
     *
     * @param url source of the data
     * @param modelMean the average frequency
     * @param modelStddev the std deviation of the frequency
     *
     * @throws IOException if an error occurs while loading data
     */
    public ContourGenerator(URL  url,
      float modelMean, float modelStddev)
          throws IOException {
  this.modelMean = modelMean;
  this.modelStddev = modelStddev;

  List termsList = new ArrayList();

  String line;
  BufferedReader reader = new BufferedReader(
    new InputStreamReader(url.openStream()));
  line = reader.readLine();
  while (line != null) {
      if (!line.startsWith("***")) {
    parseAndAdd(termsList, line);
      }
      line = reader.readLine();
  }
  terms = (F0ModelTerm[]) termsList.toArray(terms);
  reader.close();
    }

    /**
     * Generates the F0 contour for the utterance.
     *
     * @param  utterance  the utterance to process
     *
     * @throws ProcessException if an <code>IOException</code> is
     *    thrown during the processing of the utterance
     */
    public void processUtterance(Utterance utterance) throws ProcessException {
  float lend = 0.0f;
  float mean;
  float stddev;
  float localMean;
  float localStddev;
  Object tval;

  mean = utterance.getVoice().getPitch();
  mean *= utterance.getVoice().getPitchShift();
  stddev = utterance.getVoice().getPitchRange();

  Relation target = utterance.createRelation(Relation.TARGET);
  for (Item syllable =
                 utterance.getRelation(Relation.SYLLABLE).getHead();
    syllable != null;
    syllable = syllable.getNext()) {

     if (syllable.getItemAs(Relation.SYLLABLE_STRUCTURE).hasDaughters()) {

          tval = localF0Shift.findFeature(syllable);
    localMean  = Float.parseFloat(tval.toString());

    if (localMean == 0.0) {
        localMean = mean;
    } else {
        localMean *= mean;
    }

          tval = localF0Range.findFeature(syllable);
    localStddev  = Float.parseFloat(tval.toString());

    if (localStddev == 0.0) {
        localStddev = stddev;
    }

          Interceptor interceptor = applyLrModel(syllable);
    if (isPostBreak(syllable)) {
        lend = mapF0(interceptor.start, localMean, localStddev);
    }

    Float val = (Float) endPath.findFeature(syllable);
    // assert val != null;
    // don't mind null ptr exception
    addTargetPoint(target, val.floatValue(),
      mapF0((interceptor.start + lend) / 2.0f,
          localMean, localStddev));
    addTargetPoint(target, vowelMid(syllable),
      mapF0(interceptor.mid, localMean, localStddev));
    lend = mapF0(interceptor.end, localMean, localStddev);
    if (isPreBreak(syllable)) {
        Float eval = (Float) lastDaughterEndPath.findFeature(
          syllable);
        addTargetPoint(target, eval.floatValue(),
          mapF0(interceptor.end, localMean, localStddev));
    }
      }
  }

  if (utterance.getRelation(Relation.SEGMENT).getHead() != null) {
      Item first = target.getHead();
      if (first == null) {
    addTargetPoint(target, 0, mean);
      } else  if (first.getFeatures().getFloat("pos") > 0) {
        Item newItem = first.prependItem(null);
        newItem.getFeatures().setFloat("pos", 0.0f);
        newItem.getFeatures().setFloat(
          "f0", first.getFeatures().getFloat("f0"));
      }
      Item last = (Item) target.getTail();
      Item lastSegment
    = utterance.getRelation(Relation.SEGMENT).getTail();
      float segEnd = 0.0f;

      if (lastSegment != null) {
    segEnd = lastSegment.getFeatures().getFloat("end");
      }

      if (last.getFeatures().getFloat("pos") < segEnd) {
    addTargetPoint(target, segEnd, last.getFeatures().
      getFloat("f0"));
      }
  }
    }

    /**
     * Applies the linear regression model.
     *
     * @param syllable the syllable to process

     * @return the 3 points for the syllable as an <code>Interceptor</code>
     */
    private Interceptor applyLrModel(Item syllable) {
  float fv = 0.0f;
  Interceptor interceptor = new Interceptor();
  interceptor.start = terms[0].start;
  interceptor.mid = terms[0].mid;
  interceptor.end = terms[0].end;

  for (int i = 1; i < terms.length; i++) {
      Object value = terms[i].findFeature(syllable);
      if (terms[i].type != null) {
    if (value.toString().equals(terms[i].type)) {
        fv = 1.0f;
    } else {
        fv = 0.0f;
    }
      } else {
    fv = Float.parseFloat(value.toString());
      }

      interceptor.start += fv * terms[i].start;
      interceptor.mid += fv * terms[i].mid;
      interceptor.end += fv * terms[i].end;
  }

  return interceptor;
    }

    /**
     * Returns the time point mid way in vowel in this syllable.
     *
     * @param syllable the syllable of interest
     *
     * @return the time point mid way in vowel in this syllable
     */
    private final float vowelMid(Item syllable) {
  Voice voice = syllable.getUtterance().getVoice();
  Item firstSeg  = syllable.getItemAs(
            Relation.SYLLABLE_STRUCTURE).getDaughter();
  Item segment;
  float val;

  for (segment = firstSeg; segment != null; segment =segment.getNext()) {
      // TODO refactor phone feature stuff like this so that
      // it can be understood.
      if ("+".equals(voice.getPhoneFeature(segment.toString(), "vc"))) {
    val = (segment.getFeatures().getFloat("end") +
         ((Float) vowelMidPath.findFeature(segment)).floatValue()) / 2.0f;
    return val;
      }
  }

  if (firstSeg == null) {
      val =  0.0f;
  } else {
      val =  (firstSeg.getFeatures().getFloat("end") +
         ((Float) vowelMidPath.findFeature(firstSeg)).floatValue())
    / 2.0f;
  }

  return val;
    }

    /**
     * Adds the target point at the given time to the given frequency
     * to the given relation.
     *
     * @param target the target of interest
     * @param pos the time
     * @param f0 the frequency
     */
    private void addTargetPoint(Relation target, float pos, float f0) {
  Item item = target.appendItem();
  item.getFeatures().setFloat("pos", pos);
  if (f0 > 500.0) {
      item.getFeatures().setFloat("f0", 500.0f);
  } else if (f0 < 50.0)  {
      item.getFeatures().setFloat("f0", 50.0f);
  } else {
      item.getFeatures().setFloat("f0", f0);
  }
    }
   
    /**
     * Determines if this syllable is following a break.
     *
     * @param syllable the syllable to check
     *
     * @return <code>true</code> if this syllable is following a
     *   break; otherwise <code>false</code>.
     */
    private final boolean isPostBreak(Item syllable) {
  return ((syllable.getPrevious() == null) ||
    "pau".equals(postBreakPath.findFeature(syllable)));
    }
   
    /**
     * Determines if this syllable is before a break.
     *
     * @param syllable the syllable to check
     *
     * @return <code>true</code> if this syllable is before a
     *   break; otherwise <code>false</code>.
     */
    private final boolean isPreBreak(Item syllable) {
  return ((syllable.getNext() == null) ||
    "pau".equals(preBreakPath.findFeature(syllable)));
    }

    /**
     * Maps the given value to the curve.
     *
     * @param val the value to map
     *
     * @return the mapped value
     */
    private final float mapF0(float val, float mean, float stddev) {
  return ((((val - modelMean)/ modelStddev) * stddev) + mean);
    }

    /**
     * Parses the line into an F0ModelTerm.
     *
     * @param list resulting F0ModelTerm is added to this list
     * @param line the string to parse
     */
    protected void parseAndAdd(List list, String line) {
        try {
      StringTokenizer tokenizer = new StringTokenizer(line," ");
      String feature = tokenizer.nextToken();       
      float start = Float.parseFloat(tokenizer.nextToken());       
      float mid = Float.parseFloat(tokenizer.nextToken());       
      float end = Float.parseFloat(tokenizer.nextToken());       
      String type = tokenizer.nextToken();

      if (type.equals("null")) {
    type = null;
      }

      list.add(new F0ModelTerm(feature, start, mid, end, type));
  } catch (NoSuchElementException nsee) {
      throw new Error("ContourGenerator: Error while parsing F0ModelTerm "
        + nsee.getMessage());
  } catch (NumberFormatException nfe) {
      throw new Error("ContourGenerator: Bad float format "
        + nfe.getMessage());
  }
    }

    /**
     * Returns the string representation of the object.
     *
     * @return the string representation of the object
     */
    public String toString() {
        return "ContourGenerator";
    }
}

/**
* Represents a single term for the F0 model
*/
class  F0ModelTerm {
    PathExtractor path;
    float start;
    float mid;
    float end;
    String type;

    /**
     * Constructs an F0ModelTerm.
     *
     * @param feature the feature of the term
     * @param start the starting point of the term
     * @param mid the mid-point of the term
     * @param end the end point of the term
     * @param type the type of the term
     */
    F0ModelTerm(String feature, float start, float mid,
  float end, String type) {
  path = new PathExtractorImpl(feature, true);
  this.start = start;
  this.mid = mid;
  this.end = end;
  this.type = type;
    }

    /**
     * Find the feature associated with the given item
     *
     * @param item the item of interest
     *
     * @return the object representing the feature.
     */
    public Object findFeature(Item item) {
  return path.findFeature(item);
    }

    /**
     * Returns the string representation of the object
     *
     * @return the string representation of the object
     */
    public String toString() {
  return path.toString();
    }
}

/**
* Represents an interceptor.
*/
class Interceptor {
    float start;
    float mid;
    float end;

    /**
     * Constructs the default interceptor
     */
    Interceptor() {
  start = 0.0f;
  mid = 0.0f;
  end = 0.0f;
    }

    /**
     * Returns the string representation of the object.
     *
     * @return the string representation of the object
     */
    public String toString() {
  return Float.toString(start) + " " +
         Float.toString(mid) + " " +
         Float.toString(end);
    }
}
TOP

Related Classes of com.sun.speech.freetts.en.F0ModelTerm

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.