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 java.io.IOException; 014import java.net.URL; 015 016import com.sun.speech.freetts.FeatureSet; 017import com.sun.speech.freetts.Item; 018import com.sun.speech.freetts.ProcessException; 019import com.sun.speech.freetts.Relation; 020import com.sun.speech.freetts.Utterance; 021import com.sun.speech.freetts.UtteranceProcessor; 022import com.sun.speech.freetts.relp.Sample; 023import com.sun.speech.freetts.relp.SampleInfo; 024 025 026/** 027 * Generates the Unit Relation of an Utterance from the 028 * Segment Relation. 029 */ 030public class DiphoneUnitSelector implements UtteranceProcessor { 031 032 // the UnitDatabase to use 033 private DiphoneUnitDatabase diphoneDatabase; 034 035 // The Utterance that this DiphoneUnitSelector works on 036 // private Utterance utterance; 037 038 039 /** 040 * Constructs a DiphoneUnitSelector. 041 * 042 * @param url the URL for the unit database. If the URL path ends 043 * with a '.bin' it is assumed that the DB is a binary database, 044 * otherwise, its assumed that its a text database1 045 * 046 * @throws IOException if an error occurs while loading the 047 * database 048 * 049 */ 050 public DiphoneUnitSelector(URL url) throws IOException { 051 if (url == null) { 052 throw new IOException("Can't load unit database"); 053 } 054 boolean binary = url.getPath().endsWith(".bin"); 055 diphoneDatabase = new DiphoneUnitDatabase(url, binary); 056 } 057 058 /** 059 * Get the sample info for the underlying database. 060 * @return the sample info object 061 */ 062 public SampleInfo getSampleInfo() { 063 return diphoneDatabase.getSampleInfo(); 064 } 065 066 /** 067 * Generates the Unit Relation from the Segment Relation. 068 * 069 * @param utterance the utterance to generate the Unit Relation 070 * 071 * @throws ProcessException if an IOException is thrown during the 072 * processing of the utterance 073 */ 074 public void processUtterance(Utterance utterance) throws ProcessException { 075 076 if (utterance.getRelation(Relation.SEGMENT) == null) { 077 throw new IllegalStateException 078 ("DiphoneUnitSelector: Segment relation does not exist"); 079 } 080 081 utterance.setObject(SampleInfo.UTT_NAME, 082 diphoneDatabase.getSampleInfo()); 083 createUnitRelation(utterance); 084 } 085 086 /** 087 * Creates the Unit Relation in the given utterance from 088 * the diphone units and their some associated information from 089 * the units database. 090 * 091 * @param utterance the utterance that gets the new unit relation 092 */ 093 private void createUnitRelation(Utterance utterance) { 094 095 Item segmentItem0, segmentItem1; 096 float end0, end1; 097 int targetEnd; 098 099 Item unitItem0, unitItem1; 100 101 String diphoneName; 102 103 Relation unitRelation = utterance.createRelation(Relation.UNIT); 104 Relation segmentRelation = utterance.getRelation(Relation.SEGMENT); 105 106 for (segmentItem0 = segmentRelation.getHead(); 107 segmentItem0 != null && segmentItem0.getNext() != null; 108 segmentItem0 = segmentItem1) { 109 segmentItem1 = segmentItem0.getNext(); 110 diphoneName = segmentItem0.getFeatures().getString("name") + "-" + 111 segmentItem1.getFeatures().getString("name"); 112 113 114 // First half of diphone 115 end0 = segmentItem0.getFeatures().getFloat("end"); 116 targetEnd = (int) (end0 * 117 diphoneDatabase.getSampleInfo().getSampleRate()); 118 unitItem0 = createUnitItem(unitRelation, diphoneName, targetEnd, 1); 119 segmentItem0.addDaughter(unitItem0); 120 121 // Second half of diphone 122 end1 = segmentItem1.getFeatures().getFloat("end"); 123 targetEnd = (int) (((end0 + end1)/2.0) * 124 diphoneDatabase.getSampleInfo().getSampleRate()); 125 unitItem1 = createUnitItem(unitRelation, diphoneName, targetEnd, 2); 126 segmentItem1.addDaughter(unitItem1); 127 } 128 } 129 130 /** 131 * Returns a new Item (a Unit) in the given Relation, and 132 * sets the new Item to the given diphone name, target end, 133 * unit entry (index in the database), and unit part (1 or 2). 134 * 135 * @param unitRelation the relation that gets the new item 136 * @param diphoneName the name of the dipohone 137 * @param targetEnd the time at the end of this unit 138 * @param unitPart the item can be in the first(1) or second part (2) 139 */ 140 private Item createUnitItem(Relation unitRelation, 141 String diphoneName, 142 int targetEnd, 143 int unitPart) { 144 Diphone diphone = (Diphone) diphoneDatabase.getUnit(diphoneName); 145 if (diphone == null) { 146 System.err.println 147 ("FreeTTS: unit database failed to find entry for: " + 148 diphoneName); 149 } 150 Item unit = unitRelation.appendItem(); 151 FeatureSet unitFeatureSet = unit.getFeatures(); 152 153 unitFeatureSet.setString("name", diphoneName); 154 unitFeatureSet.setInt("target_end", targetEnd); 155 unitFeatureSet.setObject("unit", new DiphoneUnit(diphone, unitPart)); 156 // unitFeatureSet.setInt("unit_part", unitPart); 157 return unit; 158 } 159 160 /** 161 * Returns a string representation of this object. 162 * 163 * @return a string representation of this object 164 */ 165 public String toString() { 166 return "DiphoneUnitSelector"; 167 } 168} 169 170 171/** 172 * A wrapper around the Diphone class that turns the 173 * diphone into a unit 174 */ 175class DiphoneUnit implements com.sun.speech.freetts.Unit { 176 177 private Diphone diphone; 178 private int unitPart; 179 180 /** 181 * Contructs a diphone unit given a diphone and unit part. 182 * 183 * @param diphone the diphone to wrap 184 * @param unitPart which half (1 or 2) does this unit represent 185 */ 186 public DiphoneUnit(Diphone diphone, int unitPart) { 187 this.diphone = diphone; 188 this.unitPart = unitPart; 189 } 190 191 /** 192 * Returns the name of this Unit. 193 * 194 * @return the name of the unit 195 */ 196 public String getName() { 197 return diphone.getName(); 198 } 199 200 /** 201 * Returns the size of the unit. 202 * 203 * @return the size of the unit 204 */ 205 public int getSize() { 206 return diphone.getUnitSize(unitPart); 207 } 208 209 /** 210 * Retrieves the nearest sample. 211 * 212 * @param index the ideal index 213 * 214 * @return the nearest Sample 215 */ 216 public Sample getNearestSample(float index) { 217 return diphone.nearestSample(index, unitPart); 218 } 219 220 /** 221 * Returns a string representation of this object. 222 * 223 * @return a string representation of this object 224 */ 225 public String toString() { 226 return getName(); 227 } 228 229 230 /** 231 * Dumps this unit. 232 */ 233 public void dump() { 234 diphone.dump(); 235 } 236}