Edinburgh Speech Tools 2.4-release
 
Loading...
Searching...
No Matches
EST_Utterance.cc
1/*************************************************************************/
2/* */
3/* Centre for Speech Technology Research */
4/* University of Edinburgh, UK */
5/* Copyright (c) 1995,1996 */
6/* All Rights Reserved. */
7/* */
8/* Permission is hereby granted, free of charge, to use and distribute */
9/* this software and its documentation without restriction, including */
10/* without limitation the rights to use, copy, modify, merge, publish, */
11/* distribute, sublicense, and/or sell copies of this work, and to */
12/* permit persons to whom this work is furnished to do so, subject to */
13/* the following conditions: */
14/* 1. The code must retain the above copyright notice, this list of */
15/* conditions and the following disclaimer. */
16/* 2. Any modifications must be clearly marked as such. */
17/* 3. Original authors' names are not deleted. */
18/* 4. The authors' names are not used to endorse or promote products */
19/* derived from this software without specific prior written */
20/* permission. */
21/* */
22/* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */
23/* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */
24/* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */
25/* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */
26/* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */
27/* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */
28/* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */
29/* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */
30/* THIS SOFTWARE. */
31/* */
32/*************************************************************************/
33/* Author : Alan W Black */
34/* Date : May 1998 */
35/*-----------------------------------------------------------------------*/
36/* EST_Utterance class source file */
37/* */
38/*=======================================================================*/
39#include <cstdlib>
40#include <cstdio>
41#include <iostream>
42#include <fstream>
43#include "EST_error.h"
44#include "EST_string_aux.h"
45#include "ling_class/EST_Utterance.h"
46#include "EST_UtteranceFile.h"
47#include "EST_string_aux.h"
48
49const EST_String DEF_FILE_TYPE = "est_ascii";
50
51static void clear_up_sisilist(EST_TKVL<EST_Item_Content *,EST_Item *> &s);
52static EST_Item *map_ling_item(EST_Item *si,
54 EST_Item *> &s);
55static void copy_relation(EST_Item *to,EST_Item *from,
57
58Declare_KVL_T(EST_Item_Content *, EST_Item *, KVL_ICP_IP)
59
60#if defined(INSTANTIATE_TEMPLATES)
61
62#include "../base_class/EST_TList.cc"
63#include "../base_class/EST_TKVL.cc"
64
65Instantiate_KVL_T(EST_Item_Content *, EST_Item *, KVL_ICP_IP)
66#endif
67
69{
70 init();
71}
72
74{
75 highest_id = 0;
76 f.set("max_id", 0);
77}
78
80{
81 int i = f.val("max_id").Int();
82 f.set("max_id", i+1);
83 return i+1;
84}
85
90
92{
94 for (p.begin(relations); p; p++)
95 ::relation(p->v)->clear();
96}
97
99{
100 EST_Relation *r = relation(n,FALSE);
101 if (r) // there is one already, so clear it
102 r->clear();
103 else
104 {
105 r = new EST_Relation(n);
106 r->set_utt(this);
107 relations.set_val(n,est_val(r));
108 }
109
110 return r;
111}
112
113static EST_Item *item_id(EST_Item *p, const EST_String &n)
114{
115 EST_Item *s, *t;
116
117 t = 0;
118 if ((p == 0) || (p->S("id","0") == n))
119 return p;
120
121 for (s = daughter1(p); s; s = inext(s))
122 {
123 t = item_id(s, n);
124 if (t != 0)
125 return t;
126 }
127
128 return 0;
129}
130
132{
133 EST_Item *s, *t;
135
136 for (p.begin(relations); p; p++)
137 for (s = ::relation(p->v)->head(); s; s = next_item(s))
138 if ((t = item_id(s, n)) != 0)
139 return t;
140 EST_error("Could not find item matching id %s\n", (const char *)n);
141 return 0;
142}
143
151
153{
154 EST_Relation *r = relation(n,FALSE);
155
156 if (r != 0)
157 relations.remove(n);
158}
159
160EST_Relation *EST_Utterance::relation(const char *name,int err) const
161{
162 if (err)
163 return ::relation(relations.f(name));
164 else
165 {
166 EST_Relation *r = 0;
167 return ::relation(relations.f(name,est_val(r)));
168 }
169}
170
172{
173 if (!name.contains("("))
174 return relations.present(name);
175 EST_StrList s;
176 BracketStringtoStrList(name, s);
177 return relation_present(s);
178}
179
181{
182 for (EST_Litem *p = names.head(); p ; p = p->next())
183 if (!relations.present(names(p)))
184 return false;
185 return true;
186}
187
188EST_Utterance &EST_Utterance::operator=(const EST_Utterance &s)
189{
190 copy(s);
191 return *this;
192}
193
195{
196 u.save(st,"est_ascii");
197 return st;
198}
199
200void EST_Utterance::copy(const EST_Utterance &u)
201{
202 // Make a copy of the utterance
206
207 clear();
208 f = u.f;
209
211 for (r.begin(u.relations); r; r++)
212 {
214 nrel = create_relation(rr->name());
215 nrel->f = rr->f;
216 if (rr->head() != 0)
217 {
218 rnode = nrel->append(map_ling_item(rr->head(),sisilist));
219 copy_relation(rnode,rr->head(),sisilist);
220 }
221 }
222 clear_up_sisilist(sisilist);
223}
224
225static void extra_sub_utterance(EST_Utterance &u,EST_Item *i)
226{
227 sub_utterance(u,i);
228}
229
230void EST_Utterance::sub_utterance(EST_Item *i)
231{
232 extra_sub_utterance(*this,i);
233}
234
235static void merge_tree(EST_Relation *urel,
236 EST_Relation *rel,
238 EST_Item *root,
241{
242 EST_Item *n=0;
243 merge_features(uroot->features(), root->features());
244 // copy horizontally
245 if (inext(root)!= NULL)
246 {
247 EST_Item *old = item(items.f(inext(root)->S(feature),est_val(n)));
248 EST_Item *new_root = old?uroot->insert_after(old):uroot->insert_after();
249 merge_tree(urel, rel, new_root, inext(root), items, feature);
250 }
251 // vertically
252 if (idown(root)!= NULL)
253 {
254 EST_Item *old = item(items.f(idown(root)->S(feature),est_val(n)));
255 EST_Item *new_root = old?uroot->insert_below(old):uroot->insert_below();
256 merge_tree(urel, rel, new_root, idown(root), items, feature);
257 }
258}
259
260int utterance_merge(EST_Utterance &utt,
263{
264 // Global merge. Uses the feature to determine which items correspond.
265
266 // First build a table of existing contents.
267
270 for(ri.begin(utt.relations); ri; ri++)
271 {
272 EST_Relation *rel = relation(ri->v);
273 for(EST_Item *i=rel->head(); i != NULL; i=next_item(i))
274 {
275 EST_String id = i->S(feature);
276 items.set_val(id,est_val(i));
277 }
278 }
279
281 for(eri.begin(extra.relations); eri; eri++)
282 {
283 EST_Relation *rel = relation(eri->v);
284 EST_String rel_name = rel->name();
285
286 while (utt.relation_present(rel_name))
287 rel_name += "+";
288
290
291 if (rel->head() != NULL)
292 {
293 EST_Item *n = 0;
294 EST_Item *old = item(items.f(rel->head()->S(feature),est_val(n)));
295 EST_Item *new_root = old?urel->append(old):urel->append();
296 merge_tree(urel, rel, new_root, rel->head(), items, feature);
297 }
298 }
299
300 return TRUE;
301}
302
303int utterance_merge(EST_Utterance &utt,
307{
308 // Joins sub_utt to utt at ling_item at, merging the root
309 // of relname in sub_utt with ling_item at. All other relations
310 // in sub_utt get their root's appended (not merged) with the
311 // corresponding relations in utt (and created if necessary).
315
316 if (utt_root->relation_name() != sub_root->relation_name())
317 EST_error("utterance_merge: items not is same relation");
318
319 if ((utt_root == 0) || (sub_root == 0))
320 EST_error("utterance_merge: items are null");
321
322 // merge features but preserve root id
323 EST_String root_id = utt_root->S("id");
324 merge_features(utt_root->features(), sub_root->features());
325 utt_root->set("id", root_id);
326 // in case root item in sub is referenced elsewhere in the structure
327 sisilist.add_item(sub_root->contents(),utt_root);
328 copy_relation(utt_root,sub_root,sisilist);
329
331 for (r.begin(sub_utt.relations); r; r++)
332 {
333 EST_Relation *rr = ::relation(r->v);
334 if (rr->name() != utt_root->relation_name())
335 {
336 if (!utt.relation_present(rr->name()))
337 nrel = utt.create_relation(rr->name());
338 else
339 nrel = utt.relation(rr->name());
340 if (rr->head() != 0)
341 {
342 EST_Item *nn = map_ling_item(rr->head(),sisilist);
343 rnode = nrel->append(nn);
344 copy_relation(rnode,rr->head(),sisilist);
345 }
346 }
347 }
348 sisilist.remove_item(sub_root->contents());
349 clear_up_sisilist(sisilist);
350 return TRUE;
351}
352
353static void copy_relation(EST_Item *to,EST_Item *from,
355{
356 // Construct next and down nodes of from, into to, mapping
357 // stream_items through slist
358
359 if (inext(from))
360 copy_relation(to->insert_after(map_ling_item(inext(from),slist)),
361 inext(from),
362 slist);
363 if (idown(from))
364 copy_relation(to->insert_below(map_ling_item(idown(from),slist)),
365 idown(from),
366 slist);
367}
368
369static EST_Item *map_ling_item(EST_Item *si,
371{
372 // If si is already in s return its map otherwise copy
373 // si and add it to the list
374 EST_Item *msi;
375 EST_Item *def = 0;
376
377 msi = s.val_def(si->contents(),def);
378 if (msi == def)
379 { // First time, so copy it and add to map list
380 msi = new EST_Item(*si);
381 msi->f_remove("id");
382 s.add_item(si->contents(),msi);
383 }
384 return msi;
385}
386
387static void clear_up_sisilist(EST_TKVL<EST_Item_Content *,EST_Item *> &s)
388{
389 // The EST_Items in the value of this need to be freed, its
390 // contents however will not be freed as they will be referenced
391 // somewhere in the copied utterance
392
393 for (EST_Litem *r=s.list.head(); r != 0; r=r->next())
394 delete s.list(r).v;
395
396}
397
398static EST_Item *mapped_parent(EST_Item *i,const EST_String &relname,
400{
401 EST_Item *p;
402
403 if ((p=parent(i,relname)) == 0)
404 return 0;
405 else if (s.present(p->contents()))
406 return map_ling_item(p,s)->as_relation(relname);
407 else
408 return 0;
409}
410
411static void sub_utt_copy(EST_Utterance &sub,EST_Item *i,
413{
414 if (s.present(i->contents()))
415 return;
416 else
417 {
418 EST_Item *np,*d;
419 EST_Litem *r;
420 EST_Item *ni = map_ling_item(i,s);
421 for (r = i->relations().list.head(); r; r = r->next())
422 {
423 EST_String relname = i->relations().list(r).k;
424 if (!sub.relation_present(relname))
425 sub.create_relation(relname)->append(ni);
426 else if ((np=mapped_parent(i,relname,s)) != 0)
427 np->append_daughter(ni);
428 else
429 sub.relation(relname)->append(ni);
430
431 // Do its daughters
432 for (d = daughter1(i,relname); d ; d=inext(d))
433 sub_utt_copy(sub,d,s);
434 }
435 }
436}
437
438void sub_utterance(EST_Utterance &sub,EST_Item *i)
439{
440 // Extract i and all its relations, and daughters ... to build
441 // a new utterance in sub.
443
444 sub.clear();
445 sub_utt_copy(sub,i,sisilist);
446
447 clear_up_sisilist(sisilist);
448}
449
450EST_read_status EST_Utterance::load(const EST_String &filename)
451{
453 EST_read_status v=format_ok;
454
455 if (((filename == "-") ? ts.open(cin) : ts.open(filename)) != 0)
456 {
457 cerr << "load_utt: can't open utterance input file "
458 << filename << endl;
459 return misc_read_error;
460 }
461
462 v = load(ts);
463
464 if (v == read_ok)
465 f.set("filename", filename);
466
467 ts.close();
468
469 return v;
470}
471
473{
474 EST_read_status stat=read_error;
475 int pos = ts.tell();
476 int max_id;
477
478 init(); // we're committed to reading something so clear utterance
479
480 for(int n=0; n< EST_UtteranceFile::map.n() ; n++)
481 {
482 EST_UtteranceFileType t = EST_UtteranceFile::map.token(n);
483
484 if (t == uff_none)
485 continue;
486
487 EST_UtteranceFile::Info *info = &(EST_UtteranceFile::map.info(t));
488
489 if (! info->recognise)
490 continue;
491
492 EST_UtteranceFile::Load_TokenStream * l_fun = info->load;
493
494 if (l_fun == NULL)
495 continue;
496
497 ts.seek(pos);
498
499 stat = (*l_fun)(ts, *this, max_id);
500
501 if (stat == read_ok)
502 {
503 // set_file_type(EST_UtteranceFile::map.value(t));
504 break;
505 }
506 }
507
508 highest_id = max_id;
509 return stat;
510}
511
512EST_write_status EST_Utterance::save(const EST_String &filename,
513 const EST_String &type) const
514{
515 EST_write_status v;
516 ostream *outf;
517
518 if (filename == "-")
519 outf = &cout;
520 else
521 outf = new ofstream(filename);
522
523 if (!(*outf))
524 return write_fail;
525
526 v = save(*outf,type);
527
528 if (outf != &cout)
529 delete outf;
530
531 return v;
532}
533
535 const EST_String &type) const
536{
537 EST_String save_type = (type == "") ? DEF_FILE_TYPE : type;
538
539 EST_UtteranceFileType t = EST_UtteranceFile::map.token(save_type);
540
541 if (t == uff_none)
542 {
543 cerr << "Utterance: unknown filetype in saving " << save_type << endl;
544 return write_fail;
545 }
546
547 EST_UtteranceFile::Save_TokenStream * s_fun = EST_UtteranceFile::map.info(t).save;
548
549 if (s_fun == NULL)
550 {
551 cerr << "Can't save utterances to files type " << save_type << endl;
552 return write_fail;
553 }
554
555 return (*s_fun)(outf, *this);
556}
557
558void utt_2_flat_repr( const EST_Utterance &utt,
560{
561 EST_Item *phrase = utt.relation("Phrase")->head();
562 for( ; phrase; phrase=inext(phrase) ){
563 flat_repr += "<";
564
565 EST_Item *word = daughter1(phrase);
566 for( ; word; word=inext(word) ){
567 flat_repr += "{";
568
569 EST_Item *syllable = daughter1(word, "SylStructure");
570 for( ; syllable; syllable=inext(syllable) ){
571 flat_repr += EST_String::cat( "(", syllable->S("stress") );
572
573 EST_Item *phone = daughter1(syllable);
574 for( ; phone; phone=inext(phone) )
575 flat_repr += EST_String::cat( " ", phone->S("name"), " " );
576 flat_repr += ")";
577 }
578 flat_repr += "}";
579 }
580 flat_repr += EST_String::cat( "> _", phrase->S("name"), " " );
581 }
582}
void set(const EST_String &name, int ival)
const EST_Val & val(const char *name) const
void remove(const EST_String &name)
void set_val(const EST_String &name, const EST_Val &sval)
const EST_Val & f(const EST_String &path) const
int present(const EST_String &name) const
V v
The value.
Definition EST_THash.h:80
EST_TKVL< EST_String, EST_Val > & relations()
Access to the relation links.
Definition EST_Item.h:310
const EST_String S(const EST_String &name) const
Definition EST_Item.h:143
EST_Item * head() const
const EST_String & name() const
void set_utt(EST_Utterance *u)
void evaluate_item_features()
static EST_String cat(const EST_String s1, const EST_String s2=Empty, const EST_String s3=Empty, const EST_String s4=Empty, const EST_String s5=Empty, const EST_String s6=Empty, const EST_String s7=Empty, const EST_String s8=Empty, const EST_String s9=Empty)
int contains(const char *s, int pos=-1) const
Does it contain this substring?
Definition EST_String.h:375
void begin(const Container &over)
Set the iterator ready to run over this container.
EST_TList< EST_TKVI< K, V > > list
Linked list of key-val pairs. Don't use this as it will be made private in the future.
Definition EST_TKVL.h:93
EST_Features f
Utterance level features.
EST_read_status load(const EST_String &filename)
EST_Relation * relation(const char *name, int err_on_not_found=1) const
get relation by name
bool relation_present(const EST_String name) const
EST_Item * id(const EST_String &n) const
return EST_Item whose id is <parameter>n</parameter>.
EST_write_status save(const EST_String &filename, const EST_String &type="est_ascii") const
EST_Utterance()
default constructor
EST_Features relations
The list of named relations.
void clear()
remove everything in utterance
EST_Relation * create_relation(const EST_String &relname)
create a new relation called <parameter>n</parameter>.
int next_id()
return the id of the next item
void init()
initialise utterance
void clear_relations()
clear the contents of the relations only
void evaluate_all_features()
Evaluate all feature functions in utterance.
void remove_relation(const EST_String &relname)
remove the relation called <parameter>n</parameter>.