1 /*************************************************************************/
2 /*                                                                       */
3 /*                   Carnegie Mellon University and                      */
4 /*                Centre for Speech Technology Research                  */
5 /*                     University of Edinburgh, UK                       */
6 /*                       Copyright (c) 1998-2001                         */
7 /*                        All Rights Reserved.                           */
8 /*                                                                       */
9 /*  Permission is hereby granted, free of charge, to use and distribute  */
10 /*  this software and its documentation without restriction, including   */
11 /*  without limitation the rights to use, copy, modify, merge, publish,  */
12 /*  distribute, sublicense, and/or sell copies of this work, and to      */
13 /*  permit persons to whom this work is furnished to do so, subject to   */
14 /*  the following conditions:                                            */
15 /*   1. The code must retain the above copyright notice, this list of    */
16 /*      conditions and the following disclaimer.                         */
17 /*   2. Any modifications must be clearly marked as such.                */
18 /*   3. Original authors' names are not deleted.                         */
19 /*   4. The authors' names are not used to endorse or promote products   */
20 /*      derived from this software without specific prior written        */
21 /*      permission.                                                      */
22 /*                                                                       */
23 /*  THE UNIVERSITY OF EDINBURGH, CARNEGIE MELLON UNIVERSITY AND THE      */
24 /*  CONTRIBUTORS TO THIS WORK DISCLAIM ALL WARRANTIES WITH REGARD TO     */
25 /*  THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY   */
26 /*  AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF EDINBURGH, CARNEGIE */
27 /*  MELLON UNIVERSITY NOR THE CONTRIBUTORS BE LIABLE FOR ANY SPECIAL,    */
28 /*  INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER          */
29 /*  RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN  AN ACTION   */
30 /*  OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF     */
31 /*  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.       */
32 /*                                                                       */
33 /*************************************************************************/
34 /*             Author :  Alan W Black                                    */
35 /*             Date   :  April 1998                                      */
36 /*-----------------------------------------------------------------------*/
37 /*                                                                       */
38 /*  A quick database structure                                           */
39 /*                                                                       */
40 /*=======================================================================*/
41 #include <cstdlib>
42 #include <cmath>
43 #include "festival.h"
44 #include "EST_FileType.h"
45 #include "clunits.h"
46 
47 VAL_REGISTER_CLASS(clunitsdb,CLDB)
48 SIOD_REGISTER_CLASS(clunitsdb,CLDB)
49 static void cl_load_catalogue(CLDB *cldb,EST_String &indexfile);
50 
51 static LISP CLDB_list = NIL;
52 static CLDB *current_cldb = 0;
53 
cldb_add(const EST_String & name,CLDB * cldb)54 static void cldb_add(const EST_String &name, CLDB *cldb)
55 {
56     //  Add lexicon to list of lexicons
57     LISP lpair;
58 
59     lpair = siod_assoc_str(name,CLDB_list);
60 
61     if (CLDB_list == NIL)
62 	gc_protect(&CLDB_list);
63 
64     if (lpair == NIL)
65     {
66 	CLDB_list = cons(cons(strintern(name),
67 				   cons(siod(cldb),NIL)),
68 			    CLDB_list);
69     }
70     else
71     {
72 	cwarn << "CLDB " << name << " recreated" << endl;
73 	// old one will be garbage collected
74 	setcar(cdr(lpair),siod(cldb));
75     }
76 
77     return;
78 }
79 
80 
cl_load_db(LISP params)81 LISP cl_load_db(LISP params)
82 {
83     EST_String indexfile;
84     int i;
85     LISP w;
86     CLDB *cldb = new CLDB;
87 
88     cldb->params = params;
89 
90     indexfile = EST_String("") +
91 	get_param_str("db_dir",params,"./")+
92 	get_param_str("catalogue_dir",params,"./")+
93 	get_param_str("index_name",params,"catalogue")+
94 	    ".catalogue";
95 
96     cl_load_catalogue(cldb,indexfile);
97 
98     cldb->cweights.resize(siod_llength(get_param_lisp("join_weights",params,NIL)));
99     for (i=0,w=get_param_lisp("join_weights",params,NIL); w; w=cdr(w),i++)
100 	cldb->cweights[i] = get_c_float(car(w));
101 
102     cldb_add(get_param_str("index_name",params,"catalogue"),cldb);
103 
104     current_cldb = cldb;
105 
106     return NIL;
107 }
108 
cl_load_catalogue(CLDB * cldb,EST_String & indexfile)109 static void cl_load_catalogue(CLDB *cldb,EST_String &indexfile)
110 {
111     EST_TokenStream ts;
112     EST_EstFileType t;
113     EST_Option hinfo;
114     EST_String v;
115     bool ascii;
116     EST_read_status r;
117 
118     if (((indexfile == "-") ? ts.open(cin) : ts.open(indexfile)) != 0)
119     {
120 	cerr << "CLUNITS: Can't open catalogue file " << indexfile << endl;
121 	festival_error();
122     }
123 
124     if (((r = read_est_header(ts, hinfo, ascii, t)) != format_ok) ||
125 	(t != est_file_index))
126     {
127 	cerr << "CLUNITS: " << indexfile << " is not an indexfile" << endl;
128 	festival_error();
129     }
130 
131    CLunit *ls = 0;
132     while(!ts.eof())
133     {
134 	CLunit *s = new CLunit;
135 	s->name = ts.get().string();
136 	s->base_name = s->name.before("_");
137 	s->fileid = ts.get().string();
138 	s->start = atof(ts.get().string());
139 	s->mid = atof(ts.get().string());
140 	s->end = atof(ts.get().string());
141 
142 	if ((ls != 0) &&
143 	    (ls->fileid == s->fileid) &&
144 	    (ls->end == s->start))
145 	{
146 	    s->prev_unit = ls;
147 	    ls->next_unit = s;
148 	}
149 	cldb->index.add(s->name,s);
150 	ls = s;
151     }
152 }
153 
check_cldb()154 CLDB *check_cldb()
155 {
156     if (current_cldb == 0)
157     {
158 	cerr << "CLDB: no database loaded\n";
159 	festival_error();
160     }
161     return current_cldb;
162 }
163 
cl_maybe_fix_pitch_c0(EST_Track * c)164 void cl_maybe_fix_pitch_c0(EST_Track *c)
165 {
166     // If its pitch synchronous, trash the first coefficient with
167     // the pitch value, there should be a cleaner way to do this
168     int i;
169     float ltime = 0;
170 
171     if (!c->equal_space())
172     {
173 	for (i=0; i < c->num_frames(); i++)
174 	{
175 	    c->a_no_check(i,0) = 1/(c->t(i)-ltime);
176 	    ltime = c->t(i);
177 	}
178     }
179 }
180 
load_join_coefs(CLunit * unit)181 void CLDB::load_join_coefs(CLunit *unit)
182 {
183     // Load in the coefficients and signal for this unit.
184     CLfile *fileitem;
185     EST_Track *join_coeffs;
186 
187     if (unit->join_coeffs != 0)
188 	return;
189 
190     fileitem = get_file_join_coefs(unit->fileid);
191 
192     EST_Track *unit_join_coeffs = new EST_Track;
193     join_coeffs = fileitem->join_coeffs;
194 
195     int pm_start = join_coeffs->index(unit->start);
196     int pm_end = join_coeffs->index(unit->end);
197 
198     join_coeffs->sub_track(*unit_join_coeffs, pm_start, pm_end-pm_start+1,0);
199     unit->join_coeffs = unit_join_coeffs;
200 }
201 
get_file_join_coefs(const EST_String & fileid)202 CLfile *CLDB::get_file_join_coefs(const EST_String &fileid)
203 {
204     CLfile *fileitem;
205 
206     fileitem = get_fileitem(fileid);
207 
208     if (fileitem == 0)
209     {   // even the file isn't here
210 	fileitem = new CLfile;
211 	fileindex.add(fileid,fileitem);
212     }
213     if (fileitem->join_coeffs == 0)
214     {
215 	EST_Track *join_coeffs = new EST_Track;
216 	EST_String jc_filename =
217 	    EST_String("") +
218 		get_param_str("db_dir",params,"./") +
219 		    get_param_str("coeffs_dir",params,"wav/") +
220 			fileid+
221   		          get_param_str("coeffs_ext",params,".dcoeffs");
222 	if (join_coeffs->load(jc_filename) != format_ok)
223 	{
224 	    delete join_coeffs;
225 	    cerr << "CLUNITS: failed to load join coeffs file " <<
226 		jc_filename << endl;
227 	    festival_error();
228 	}
229 //	cl_maybe_fix_pitch_c0(join_coeffs);
230 	fileitem->join_coeffs = join_coeffs;
231     }
232 
233     return fileitem;
234 }
235 
get_file_coefs_sig(const EST_String & fileid)236 CLfile *CLDB::get_file_coefs_sig(const EST_String &fileid)
237 {
238     CLfile *fileitem = get_fileitem(fileid);
239 
240     if (fileitem == 0)
241     {   // even the file isn't here
242 	fileitem = new CLfile;
243 	fileindex.add(fileid,fileitem);
244     }
245     if (fileitem->sig == 0)
246     {
247 	EST_Track *track = new EST_Track;
248 	EST_String coef_filename =
249 	    EST_String("") +
250 		get_param_str("db_dir",params,"./") +
251 		    get_param_str("pm_coeffs_dir",params,"pm/") +
252 			fileid+
253 			    get_param_str("pm_coeffs_ext",params,".pm");
254 	if (track->load(coef_filename) != format_ok)
255 	{
256 	    delete track;
257 	    cerr << "CLUNITS: failed to load coeffs file " <<
258 		coef_filename << endl;
259 	    festival_error();
260 	}
261 	fileitem->coefs = track;
262 
263 	EST_Wave *sig = new EST_Wave;
264 	EST_String sig_filename =
265 	    EST_String("") +
266 		get_param_str("db_dir",params,"./") +
267 		    get_param_str("sig_dir",params,"wav/") +
268 			fileid+
269 			    get_param_str("sig_ext",params,".wav");
270 	if (sig->load(sig_filename) != format_ok)
271 	{
272 	    delete sig;
273 	    cerr << "CLUNITS: failed to load signal file " <<
274 		sig_filename << endl;
275 	    festival_error();
276 	}
277 	fileitem->sig = sig;
278     }
279     return fileitem;
280 }
281 
load_coefs_sig(EST_Item * unit)282 void CLDB::load_coefs_sig(EST_Item *unit)
283 {
284     // Load in the coefficients and signal for this unit.
285     EST_String fileid = unit->f("fileid");
286     CLfile *fileitem;
287 
288     fileitem = get_file_coefs_sig(fileid);
289 
290     EST_Track *coeffs = fileitem->coefs;
291     EST_Wave *sig = fileitem->sig;
292     EST_Track u1;
293     EST_Wave *unit_sig = new EST_Wave;
294 
295     int pm_start = coeffs->index(unit->F("start"));
296     int pm_middle = coeffs->index(unit->F("middle"));
297     int pm_end = coeffs->index(unit->F("end"));
298 
299 //    coeffs->sub_track(u1,Gof((pm_start-1),0), pm_end - pm_start + 1);
300     coeffs->sub_track(u1,pm_start, pm_end - pm_start + 1,0);
301     EST_Track *unit_coeffs = new EST_Track(u1);
302     for (int j = 0; j < u1.num_frames(); ++j)
303 	unit_coeffs->t(j) = u1.t(j) - coeffs->t(Gof((pm_start - 1), 0));
304 
305 /*    printf("coefs %s: pm_start %d pm_end %d pm_length %d\n",
306 	   (const char *)fileid,
307 	   pm_start, pm_end, pm_end - pm_start + 1); */
308     unit->set_val("coefs",est_val(unit_coeffs));
309 
310     if ((pm_middle-pm_start-1) < 1)
311 	unit->set("middle_frame", 1);
312     else
313 	unit->set("middle_frame", pm_middle - pm_start -1);
314     int samp_start = (int)(coeffs->t(Gof((pm_start - 1), 0))
315  		  * (float)sig->sample_rate());
316     int samp_end;
317     if ((pm_end + 1) < coeffs->num_frames())
318  	samp_end = (int)(coeffs->t(pm_end + 1) * (float)sig->sample_rate());
319     else
320  	samp_end = (int)(coeffs->t(pm_end) * (float)sig->sample_rate());
321     int real_samp_start = (int)(unit->F("start") * (float)sig->sample_rate());
322     int real_samp_end = (int)(unit->F("end") * (float)sig->sample_rate());
323     if (samp_end-samp_start < 1)
324 	sig->sub_wave(*unit_sig,samp_start, 1);
325     else
326 	sig->sub_wave(*unit_sig,samp_start, samp_end-samp_start);
327     if (real_samp_start-samp_start<0)
328         unit->set("samp_start",0);
329     else
330         unit->set("samp_start",real_samp_start-samp_start);
331     unit->set("samp_end",real_samp_end-samp_start);
332     /* Need to preserve where the phone boundary is  (which may actually */
333     /* be past the end of this unit                                      */
334     unit->set("samp_seg_start",
335 	      (int)(unit->F("seg_start") *
336 		    (float)sig->sample_rate())-samp_start);
337     unit->set_val("sig",est_val(unit_sig));
338 }
339 
CLunit()340 CLunit::CLunit()
341 {
342     start=0;
343     mid=0;
344     end=0;
345     prev_unit = 0;
346     next_unit = 0;
347     samp_start = 0;
348     samp_end = 0;
349     join_coeffs = 0;
350     coefs = 0;
351     sig = 0;
352 }
353 
~CLunit()354 CLunit::~CLunit()
355 {
356     delete join_coeffs;
357     delete coefs;
358     delete sig;
359 }
360 
CLfile()361 CLfile::CLfile()
362 {
363     join_coeffs = 0;
364     coefs = 0;
365     sig = 0;
366 }
367 
~CLfile()368 CLfile::~CLfile()
369 {
370     delete join_coeffs;
371     delete coefs;
372     delete sig;
373 }
374 
CLDB()375 CLDB::CLDB()
376 {
377     gc_protect(&params);
378 }
379 
del_clunit(void * s)380 static void del_clunit(void *s) { delete (CLunit *)s; }
del_clfile(void * s)381 static void del_clfile(void *s) { delete (CLfile *)s; }
~CLDB()382 CLDB::~CLDB()
383 {
384     index.clear(del_clunit);
385     fileindex.clear(del_clfile);
386     gc_unprotect(&params);
387 }
388 
cldb_list(void)389 LISP cldb_list(void)
390 {
391     // List names of all current defined cluster dbs
392     LISP d = NIL;
393     LISP l;
394 
395     for (l=CLDB_list; l != NIL; l=cdr(l))
396 	d = cons(car(car(l)),d);
397 
398     return d;
399 }
400 
cldb_select(LISP dbname)401 LISP cldb_select(LISP dbname)
402 {
403     // Select named cldb and make it current
404     EST_String name = get_c_string(dbname);
405     LISP lpair;
406 
407     lpair = siod_assoc_str(name,CLDB_list);
408 
409     if (lpair == NIL)
410     {
411 	cerr << "CLDB " << name << " not defined" << endl;
412 	festival_error();
413     }
414     else
415 	current_cldb = clunitsdb(car(cdr(lpair)));
416 
417     return dbname;
418 }
419 
420 
421 
422