001/** 002 * Portions Copyright 2001 Sun Microsystems, Inc. 003 * Portions Copyright 1999-2001 Language Technologies Institute, 004 * Carnegie Mellon University. 005 * All Rights Reserved. Use is subject to license terms. 006 * 007 * See the file "license.terms" for information on usage and 008 * redistribution of this file, and for a DISCLAIMER OF ALL 009 * WARRANTIES. 010 */ 011package com.sun.speech.freetts.diphone; 012 013import com.sun.speech.freetts.FeatureSet; 014import com.sun.speech.freetts.Item; 015import com.sun.speech.freetts.relp.LPCResult; 016import com.sun.speech.freetts.UtteranceProcessor; 017import com.sun.speech.freetts.Utterance; 018import com.sun.speech.freetts.Relation; 019import com.sun.speech.freetts.ProcessException; 020import com.sun.speech.freetts.relp.SampleInfo; 021 022/** 023 * Calculates pitchmarks. This is an utterance processor that expects 024 * the utterance to have a target relation. It will create an 025 * LPCResult and add it to the utterance based upon features of the 026 * target relation. 027 * 028 * @see LPCResult 029 * @see Relation 030 * @see SampleInfo 031 */ 032public class DiphonePitchmarkGenerator implements UtteranceProcessor { 033 034 /** 035 * Generates the LPCResult for this utterance. 036 * 037 * @param utterance the utterance to process 038 * 039 * @throws ProcessException if an error occurs while processing 040 * the utterance 041 * @throws IllegalStateException if the given utterance has no 042 * relation named Relation.TARGET or a feature named 043 * SampleInfo.UTT_NAME 044 */ 045 public void processUtterance(Utterance utterance) throws ProcessException { 046 047 // precondition that must be satisfied 048 Relation targetRelation = utterance.getRelation(Relation.TARGET); 049 if (targetRelation == null) { 050 throw new IllegalStateException 051 ("DiphonePitchmarkGenerator: Target relation does not exist"); 052 } 053 054 SampleInfo sampleInfo; 055 sampleInfo = (SampleInfo) utterance.getObject(SampleInfo.UTT_NAME); 056 if (sampleInfo == null) { 057 throw new IllegalStateException 058 ("DiphonePitchmarkGenerator: SampleInfo does not exist"); 059 } 060 061 float pos, f0, m = 0; 062 float lf0 = utterance.getVoice().getPitch(); 063 064 double time = 0; 065 int pitchMarks = 0; // how many pitch marks 066 067 LPCResult lpcResult; 068 IntLinkedList timesList = new IntLinkedList(); 069 070 // first pass to count how many pitch marks will be required 071 for (Item targetItem = targetRelation.getHead(); 072 targetItem != null; targetItem = targetItem.getNext()) { 073 FeatureSet featureSet = targetItem.getFeatures(); 074 pos = featureSet.getFloat("pos"); 075 f0 = featureSet.getFloat("f0"); 076 //System.err.println("Target pos="+pos+", f0="+f0); 077 if (time == pos) { 078 lf0 = f0; 079 continue; 080 } 081 m = (f0-lf0)/pos; 082 //System.err.println("m=("+f0+"-"+lf0+")/"+pos+"="+m); 083 for (; time < pos; pitchMarks++) { 084 time += 1/(lf0 + (time * m)); 085 //System.err.println("f("+time+")="+((lf0+(time*m)))); 086 // save the time value in a list 087 timesList.add((int) (time * sampleInfo.getSampleRate())); 088 } 089 lf0 = f0; 090 } 091 lpcResult = new LPCResult(); 092 // resize the number of frames to the number of pitchmarks 093 lpcResult.resizeFrames(pitchMarks); 094 095 pitchMarks = 0; 096 097 int[] targetTimes = lpcResult.getTimes(); 098 099 // second pass puts the values in 100 timesList.resetIterator(); 101 for (; pitchMarks < targetTimes.length; pitchMarks++) { 102 targetTimes[pitchMarks] = timesList.nextInt(); 103 } 104 utterance.setObject("target_lpcres", lpcResult); 105 } 106 107 108 /** 109 * Returns a string representation of this object. 110 * 111 * @return a string representation of this object 112 */ 113 public String toString() { 114 return "DiphonePitchmarkGenerator"; 115 } 116} 117 118/** 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. 124 * 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 132 * impact. 133 * 134 * [[[ TODO look at replacing this with a simple int array ]]] 135 */ 136class IntLinkedList { 137 private IntListNode head = null; 138 private IntListNode tail = null; 139 private IntListNode iterator = null; 140 141 /** 142 * Constructs an empty IntLinkedList. 143 */ 144 public IntLinkedList() { 145 head = null; 146 tail = null; 147 iterator = null; 148 } 149 150 /** 151 * Adds the given float to the end of the list. 152 * 153 * @param val the float to add 154 */ 155 public void add(int val) { 156 IntListNode node = new IntListNode(val); 157 if (head == null) { 158 head = node; 159 tail = node; 160 } else { 161 tail.next = node; 162 tail = node; 163 } 164 } 165 166 /** 167 * Moves the iterator to point to the front of the list. 168 */ 169 public void resetIterator() { 170 iterator = head; 171 } 172 173 /** 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. 178 * 179 * @return the next value 180 */ 181 public int nextInt() { 182 int val = iterator.val; 183 if (iterator != null) { 184 iterator = iterator.next; 185 } 186 return val; 187 } 188 189 /** 190 * Checks if there are more elements for the iterator. 191 * 192 * @return <code>true</code> if there are more elements; 193 * otherwise <code>false</code> 194 */ 195 public boolean hasNext() { 196 return (iterator != null); 197 } 198} 199 200/** 201 * Represents a node for the IntList 202 */ 203class IntListNode { 204 int val; 205 IntListNode next; 206 207 /** 208 * Creates a node that wraps the given value. 209 * 210 * @param val the value to be contained in the list 211 */ 212 public IntListNode(int val) { 213 this.val = val; 214 next = null; 215 } 216}