2 * Portions Copyright 2001 Sun Microsystems, Inc.
3 * Portions Copyright 1999-2001 Language Technologies Institute,
4 * Carnegie Mellon University.
5 * All Rights Reserved. Use is subject to license terms.
7 * See the file "license.terms" for information on usage and
8 * redistribution of this file, and for a DISCLAIMER OF ALL
11 package com.sun.speech.freetts.diphone;
13 import com.sun.speech.freetts.FeatureSet;
14 import com.sun.speech.freetts.Item;
15 import com.sun.speech.freetts.relp.LPCResult;
16 import com.sun.speech.freetts.UtteranceProcessor;
17 import com.sun.speech.freetts.Utterance;
18 import com.sun.speech.freetts.Relation;
19 import com.sun.speech.freetts.ProcessException;
20 import com.sun.speech.freetts.relp.SampleInfo;
23 * Calculates pitchmarks. This is an utterance processor that expects
24 * the utterance to have a target relation. It will create an
25 * LPCResult and add it to the utterance based upon features of the
32 public class DiphonePitchmarkGenerator implements UtteranceProcessor {
35 * Generates the LPCResult for this utterance.
37 * @param utterance the utterance to process
39 * @throws ProcessException if an error occurs while processing
41 * @throws IllegalStateException if the given utterance has no
42 * relation named Relation.TARGET or a feature named
45 public void processUtterance(Utterance utterance) throws ProcessException {
47 // precondition that must be satisfied
48 Relation targetRelation = utterance.getRelation(Relation.TARGET);
49 if (targetRelation == null) {
50 throw new IllegalStateException
51 ("DiphonePitchmarkGenerator: Target relation does not exist");
54 SampleInfo sampleInfo;
55 sampleInfo = (SampleInfo) utterance.getObject(SampleInfo.UTT_NAME);
56 if (sampleInfo == null) {
57 throw new IllegalStateException
58 ("DiphonePitchmarkGenerator: SampleInfo does not exist");
62 float lf0 = utterance.getVoice().getPitch();
65 int pitchMarks = 0; // how many pitch marks
68 IntLinkedList timesList = new IntLinkedList();
70 // first pass to count how many pitch marks will be required
71 for (Item targetItem = targetRelation.getHead();
72 targetItem != null; targetItem = targetItem.getNext()) {
73 FeatureSet featureSet = targetItem.getFeatures();
74 pos = featureSet.getFloat("pos");
75 f0 = featureSet.getFloat("f0");
76 //System.err.println("Target pos="+pos+", f0="+f0);
82 //System.err.println("m=("+f0+"-"+lf0+")/"+pos+"="+m);
83 for (; time < pos; pitchMarks++) {
84 time += 1/(lf0 + (time * m));
85 //System.err.println("f("+time+")="+((lf0+(time*m))));
86 // save the time value in a list
87 timesList.add((int) (time * sampleInfo.getSampleRate()));
91 lpcResult = new LPCResult();
92 // resize the number of frames to the number of pitchmarks
93 lpcResult.resizeFrames(pitchMarks);
97 int[] targetTimes = lpcResult.getTimes();
99 // second pass puts the values in
100 timesList.resetIterator();
101 for (; pitchMarks < targetTimes.length; pitchMarks++) {
102 targetTimes[pitchMarks] = timesList.nextInt();
104 utterance.setObject("target_lpcres", lpcResult);
109 * Returns a string representation of this object.
111 * @return a string representation of this object
113 public String toString() {
114 return "DiphonePitchmarkGenerator";
119 * Represents a linked list with each node of the list storing
120 * a primitive int data type. Unlike the java.util.LinkedList, it avoids
121 * the need to wrap the float number in a Float object. This avoids
122 * unnecessary object creation, and is therefore faster and saves memory.
123 * However, it does not implement the java.util.List interface.
125 * This linked list is used as a replacement for a simple array of
126 * ints. Certain performance critical loops have had performance
127 * issues due to the overhead associated with array index bounds
128 * checking performed by the VM. Using this type of data structure
129 * allowed the checking to be bypassed. Note however that we've seen
130 * great improvement in compiler performance in this area such that we
131 * may be able to revert to using an array without any performance
134 * [[[ TODO look at replacing this with a simple int array ]]]
136 class IntLinkedList {
137 private IntListNode head = null;
138 private IntListNode tail = null;
139 private IntListNode iterator = null;
142 * Constructs an empty IntLinkedList.
144 public IntLinkedList() {
151 * Adds the given float to the end of the list.
153 * @param val the float to add
155 public void add(int val) {
156 IntListNode node = new IntListNode(val);
167 * Moves the iterator to point to the front of the list.
169 public void resetIterator() {
174 * Returns the next float in the list, advances the iterator.
175 * The <code>hasNext()</code> method MUST be called before calling
176 * this method to check if the iterator is point to null,
177 * otherwise NullPointerException will be thrown.
179 * @return the next value
181 public int nextInt() {
182 int val = iterator.val;
183 if (iterator != null) {
184 iterator = iterator.next;
190 * Checks if there are more elements for the iterator.
192 * @return <code>true</code> if there are more elements;
193 * otherwise <code>false</code>
195 public boolean hasNext() {
196 return (iterator != null);
201 * Represents a node for the IntList
208 * Creates a node that wraps the given value.
210 * @param val the value to be contained in the list
212 public IntListNode(int val) {