upstream version 1.2.2
[debian/freetts] / com / sun / speech / freetts / diphone / DiphoneUnitSelector.java
1 /**
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.
6  * 
7  * See the file "license.terms" for information on usage and
8  * redistribution of this file, and for a DISCLAIMER OF ALL 
9  * WARRANTIES.
10  */
11 package com.sun.speech.freetts.diphone;
12
13 import java.io.IOException;
14 import java.net.URL;
15
16 import com.sun.speech.freetts.FeatureSet;
17 import com.sun.speech.freetts.Item;
18 import com.sun.speech.freetts.ProcessException;
19 import com.sun.speech.freetts.Relation;
20 import com.sun.speech.freetts.Utterance;
21 import com.sun.speech.freetts.UtteranceProcessor;
22 import com.sun.speech.freetts.relp.Sample;
23 import com.sun.speech.freetts.relp.SampleInfo;
24
25
26 /**
27  * Generates the Unit Relation of an Utterance from the
28  * Segment Relation.
29  */
30 public class DiphoneUnitSelector implements UtteranceProcessor {
31
32     // the UnitDatabase to use
33     private DiphoneUnitDatabase diphoneDatabase;
34         
35     // The Utterance that this DiphoneUnitSelector works on
36     // private Utterance utterance;
37     
38     
39     /**
40      * Constructs a DiphoneUnitSelector.
41      *
42      * @param url the URL for the unit database. If the URL path ends
43      *     with a '.bin' it is assumed that the DB is a binary database,
44      *     otherwise, its assumed that its a text database1
45      *
46      * @throws IOException if an error occurs while loading the
47      *     database
48      *
49      */
50     public DiphoneUnitSelector(URL url) throws IOException {
51         if (url == null) {
52             throw new IOException("Can't load unit database");
53         }
54         boolean binary = url.getPath().endsWith(".bin");
55         diphoneDatabase = new DiphoneUnitDatabase(url, binary);
56     }
57     
58     /**
59      * Get the sample info for the underlying database.
60      * @return the sample info object
61      */
62     public SampleInfo getSampleInfo() {
63         return diphoneDatabase.getSampleInfo();
64     }
65     
66     /**
67      * Generates the Unit Relation from the Segment Relation.
68      *
69      * @param  utterance  the utterance to generate the Unit Relation
70      *
71      * @throws ProcessException if an IOException is thrown during the
72      *         processing of the utterance
73      */
74     public void processUtterance(Utterance utterance) throws ProcessException {
75
76         if (utterance.getRelation(Relation.SEGMENT) == null) {
77             throw new IllegalStateException
78                 ("DiphoneUnitSelector: Segment relation does not exist");
79         }
80         
81         utterance.setObject(SampleInfo.UTT_NAME,
82                 diphoneDatabase.getSampleInfo());
83         createUnitRelation(utterance);
84     }
85
86     /**
87      * Creates the Unit Relation in the given utterance from
88      * the diphone units and their some associated information from
89      * the units database.
90      *
91      * @param utterance the utterance that gets the new unit relation
92      */
93     private void createUnitRelation(Utterance utterance) {
94
95         Item segmentItem0, segmentItem1;
96         float end0, end1;
97         int targetEnd;
98         
99         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  */
175 class 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 }