Edinburgh Speech Tools  2.1-release
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
viterbi_main.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 /* Authors: Alan W Black and Simon King */
34 /* Date : January 1997 */
35 /*-----------------------------------------------------------------------*/
36 /* A simple use of the Viterbi decoder */
37 /* */
38 /*=======================================================================*/
39 
40 #include <cstdlib>
41 #include <cstdio>
42 #include <cmath>
43 #include "EST.h"
44 
45 EST_read_status load_TList_of_StrVector(EST_TList<EST_StrVector> &w,
46  const EST_String &filename,
47  const int vec_len);
48 
49 static void print_results(EST_Relation &wstream);
50 static bool do_search(EST_Relation &wstream);
51 static EST_VTPath *vit_npath(EST_VTPath *p,EST_VTCandidate *c,EST_Features &f);
52 static EST_VTCandidate *vit_candlist(EST_Item *s,EST_Features &f);
53 static void top_n_candidates(EST_VTCandidate* &all_c);
54 static void load_vocab(const EST_String &vfile);
55 
56 static void add_word(EST_Relation &w, const EST_String &word, int pos);
57 
58 static void load_wstream(const EST_String &filename,
59  const EST_String &vfile,
60  EST_Relation &w,
61  EST_Track &obs);
62 
63 static void load_given(const EST_String &filename,
64  const int ngram_order);
65 
66 static double find_gram_prob(EST_VTPath *p,int *state);
67 
68 // special stuff for non-sliding window ngrams
69 static double find_extra_gram_prob(EST_VTPath *p,int *state, int time);
70 static void get_history(EST_StrVector &history, EST_VTPath *p);
71 static void fill_window(EST_StrVector &window,EST_StrVector &history,
72  EST_VTPath *p,const int time);
73 static int is_a_special(const EST_String &s, int &val);
74 static int max_history=0;
75 
76 static EST_Ngrammar ngram;
77 static EST_String pstring = SENTENCE_START_MARKER;
78 static EST_String ppstring = SENTENCE_END_MARKER;
79 static float lm_scale = 1.0;
80 static float ob_scale = 1.0;
81 static float ob_scale2 = 1.0;
82 
83 // pruning beam widths
84 static float beam=-1;
85 static float ob_beam=-1;
86 static int n_beam = -1;
87 
88 static bool trace_on = FALSE;
89 
90 // always logs
91 static double ob_log_prob_floor = SAFE_LOG_ZERO;
92 static double ob_log_prob_floor2 = SAFE_LOG_ZERO;
93 static double lm_log_prob_floor = SAFE_LOG_ZERO;
94 
95 int btest_debug = FALSE;
96 static EST_String out_file = "";
97 static EST_StrList vocab;
98 static EST_Track observations;
99 static EST_Track observations2;
100 static EST_TList<EST_StrVector> given; // to do : convert to array for speed
101 int using_given=FALSE;
102 
103 // default is that obs are already logs
104 int take_logs = FALSE;
105 int num_obs = 1;
106 
107 
108 int main(int argc, char **argv)
109 {
110  EST_StrList files;
111  EST_Option al;
112  EST_Relation wstream;
113  double floor; // a temporary
114 
115  parse_command_line(argc, argv,
116  EST_String("[observations file] -o [output file]\n")+
117  "Summary: find the most likely path through a sequence of\n"+
118  " observations, constrained by a language model.\n"+
119  "-ngram <string> Grammar file, required\n"+
120  "-given <string> ngram left contexts, per frame\n"+
121  "-vocab <string> File with names of vocabulary, this\n"+
122  " must be same number as width of observations, required\n"+
123  "-ob_type <string> Observation type : likelihood .... and change doc\"probs\" or \"logs\" (default is \"logs\")\n"+
124  "\nFloor values and scaling (scaling is applied after floor value)\n"+
125  "-lm_floor <float> LM floor probability\n"+
126  "-lm_scale <float> LM scale factor factor (applied to log prob)\n"+
127  "-ob_floor <float> Observations floor probability\n"+
128  "-ob_scale <float> Observation scale factor (applied to prob or log prob, depending on -ob_type)\n\n"+
129  "-prev_tag <string>\n"+
130  " tag before sentence start\n"+
131  "-prev_prev_tag <string>\n"+
132  " all words before 'prev_tag'\n"+
133  "-last_tag <string>\n"+
134  " after sentence end\n"+
135  "-default_tags use default tags of "+SENTENCE_START_MARKER+","
136  SENTENCE_END_MARKER+" and "+SENTENCE_END_MARKER+"\n"+
137  " respectively\n\n"+
138 
139  "-observes2 <string> second observations (overlays first, ob_type must be same)\n"+
140  "-ob_floor2 <float> \n"+
141  "-ob_scale2 <float> \n\n"+
142  "-ob_prune <float> observation pruning beam width (log) probability\n"+
143  "-n_prune <int> top-n pruning of observations\n"+
144  "-prune <float> pruning beam width (log) probability\n"+
145  "-trace show details of search as it proceeds\n",
146  files, al);
147 
148  out_file = al.present("-o") ? al.val("-o") : (EST_String)"-";
149 
150  if (files.length() != 1)
151  {
152  cerr << argv[0];
153  cerr << ": you must give exactly one observations file on the command line";
154  cerr << endl;
155  cerr << "(use -observes2 for optional second observations)" << endl;
156  exit(-1);
157  }
158 
159  if (al.present("-ngram"))
160  {
161  ngram.load(al.val("-ngram"));
162  }
163  else
164  {
165  cerr << argv[0] << ": no ngram specified" << endl;
166  exit(-1);
167  }
168 
169  if(!al.present("-vocab"))
170  {
171  cerr << "You must provide a vocabulary file !" << endl;
172  exit(-1);
173  }
174 
175  load_wstream(files.first(),al.val("-vocab"),wstream,observations);
176  if (al.present("-observes2"))
177  {
178  load_wstream(al.val("-observes2"),al.val("-vocab"),wstream,observations2);
179  num_obs = 2;
180  }
181 
182  if (al.present("-given"))
183  {
184  load_given(al.val("-given"),ngram.order());
185  using_given=TRUE;
186  }
187 
188  if (al.present("-lm_scale"))
189  lm_scale = al.fval("-lm_scale");
190  else
191  lm_scale = 1.0;
192 
193  if (al.present("-ob_scale"))
194  ob_scale = al.fval("-ob_scale");
195  else
196  ob_scale = 1.0;
197 
198  if (al.present("-ob_scale2"))
199  ob_scale2 = al.fval("-ob_scale2");
200  else
201  ob_scale2 = 1.0;
202 
203  if (al.present("-prev_tag"))
204  pstring = al.val("-prev_tag");
205  if (al.present("-prev_prev_tag"))
206  ppstring = al.val("-prev_prev_tag");
207 
208  // pruning
209  if (al.present("-prune"))
210  beam = al.fval("-prune");
211  else
212  beam = -1; // no pruning
213 
214  if (al.present("-ob_prune"))
215  ob_beam = al.fval("-ob_prune");
216  else
217  ob_beam = -1; // no pruning
218 
219  if (al.present("-n_prune"))
220  {
221  n_beam = al.ival("-n_prune");
222  if(n_beam <= 0)
223  {
224  cerr << "WARNING : " << n_beam;
225  cerr << " is not a reasonable value for -n_prune !" << endl;
226  }
227  }
228  else
229  n_beam = -1; // no pruning
230 
231 
232 
233  if (al.present("-trace"))
234  trace_on = TRUE;
235 
236  // language model floor
237  if (al.present("-lm_floor"))
238  {
239  floor = al.fval("-lm_floor");
240  if(floor < 0)
241  {
242  cerr << "Error : LM floor probability is negative !" << endl;
243  exit(-1);
244  }
245  else if(floor > 1)
246  {
247  cerr << "Error : LM floor probability > 1 " << endl;
248  exit(-1);
249  }
250  lm_log_prob_floor = safe_log(floor);
251  }
252 
253  // observations floor
254  if (al.present("-ob_floor"))
255  {
256  floor = al.fval("-ob_floor");
257  if(floor < 0)
258  {
259  cerr << "Error : Observation floor probability is negative !" << endl;
260  exit(-1);
261  }
262  else if(floor > 1)
263  {
264  cerr << "Error : Observation floor probability > 1 " << endl;
265  exit(-1);
266  }
267  ob_log_prob_floor = safe_log(floor);
268  }
269 
270  if (al.present("-ob_floor2"))
271  {
272  floor = al.fval("-ob_floor2");
273  if(floor < 0)
274  {
275  cerr << "Error : Observation2 floor probability is negative !" << endl;
276  exit(-1);
277  }
278  else if(floor > 1)
279  {
280  cerr << "Error : Observation2 floor probability > 1 " << endl;
281  exit(-1);
282  }
283  ob_log_prob_floor2 = safe_log(floor);
284  }
285 
286 
287  if (al.present("-ob_type"))
288  {
289  if(al.val("-ob_type") == "logs")
290  take_logs = false;
291  else if(al.val("-ob_type") == "probs")
292  take_logs = true;
293  else
294  {
295  cerr << "\"" << al.val("-ob_type")
296  << "\" is not a valid ob_type : try \"logs\" or \"probs\"" << endl;
297  exit(-1);
298  }
299  }
300 
301  if(do_search(wstream))
302  print_results(wstream);
303  else
304  cerr << "No path could be found." << endl;
305 
306  return 0;
307 }
308 
309 static void print_results(EST_Relation &wstream)
310 {
311  EST_Item *s;
312  float pscore;
313  EST_String predict;
314  FILE *fd;
315 
316  if (out_file == "-")
317  fd = stdout;
318  else if ((fd = fopen(out_file,"wb")) == NULL)
319  {
320  cerr << "can't open \"" << out_file << "\" for output" << endl;
321  exit(-1);
322  }
323 
324  for (s=wstream.head(); s != 0 ; s=s->next())
325  {
326  predict = s->f("best").string();
327  pscore = s->f("best_score");
328  fprintf(fd,"%s %f\n",(const char *)predict,pscore);
329  }
330 
331  if (out_file != "")
332  fclose(fd);
333 
334 }
335 
336 static bool do_search(EST_Relation &wstream)
337 {
338  // Apply Ngram to matrix of probs
339  int states;
340 
341  states = ngram.num_states();
342  EST_Viterbi_Decoder vc(vit_candlist,vit_npath,states);
343 
344  vc.initialise(&wstream);
345 
346  if((beam > 0) || (ob_beam > 0))
347  vc.set_pruning_parameters(beam,ob_beam);
348 
349  if(trace_on)
350  {
351  vc.turn_on_trace();
352  cerr << "Starting Viterbi search..." << endl;
353  }
354 
355  vc.search();
356 
357  return vc.result("best"); // adds fields to w with best values
358 
359 }
360 
361 static void load_wstream(const EST_String &filename,
362  const EST_String &vfile,
363  EST_Relation &w,
364  EST_Track &obs)
365 {
366  // Load in vocab and probs into Stream (this isn't general)
367  EST_String word, pos;
368  int i=-1;
369 
370  if(vocab.empty())
371  load_vocab(vfile);
372 
373  if (obs.load(filename,0.10) != 0)
374  {
375  cerr << "can't find observations file \"" << filename << "\"" << endl;
376  exit(-1);
377  }
378 
379  if (vocab.length() != obs.num_channels())
380  {
381  cerr << "Number in vocab (" << vocab.length() <<
382  ") not equal to observation's width (" <<
383  obs.num_channels() << ")" << endl;
384  exit(-1);
385  }
386 
387  if(w.empty())
388  for (i=0; i < obs.num_frames(); i++)
389  add_word(w,itoString(i),i);
390 }
391 
392 
393 static void load_given(const EST_String &filename,
394  const int ngram_order)
395 {
396 
397  EST_String word, pos;
398  EST_Litem *p;
399  int i,j;
400 
401  if (load_TList_of_StrVector(given,filename,ngram_order-1) != 0)
402  {
403  cerr << "can't load given file \"" << filename << "\"" << endl;
404  exit(-1);
405  }
406 
407  // set max history
408  for (p = given.head(); p; p = p->next())
409  {
410  for(i=0;i<given(p).length();i++)
411  if( is_a_special( given(p)(i), j) && (-j > max_history))
412  max_history = -j;
413 
414  }
415 
416 }
417 
418 static void load_vocab(const EST_String &vfile)
419 {
420  // Load vocabulary (strings)
421  EST_TokenStream ts;
422 
423  if (ts.open(vfile) == -1)
424  {
425  cerr << "can't find vocab file \"" << vfile << "\"" << endl;
426  exit(-1);
427  }
428 
429  while (!ts.eof())
430  if (ts.peek() != "")
431  vocab.append(ts.get().string());
432 
433  ts.close();
434 }
435 
436 static void add_word(EST_Relation &w, const EST_String &word, int pos)
437 {
438  EST_Item *item = w.append();
439 
440  item->set_name(word);
441  item->set("pos",pos);
442 }
443 
444 static EST_VTCandidate *vit_candlist(EST_Item *s,EST_Features &f)
445 {
446  // Return a list of new candidates from this point
447  double prob=1.0,prob2=1.0;
448  int i;
449  EST_Litem *p;
450  int observe;
451  EST_VTCandidate *all_c = 0;
452  EST_VTCandidate *c;
453  (void)f;
454 
455  observe = s->f("pos"); // index for observations TRACK
456  for (i=0,p=vocab.head(); i < observations.num_channels(); i++,p=p->next())
457  {
458  c = new EST_VTCandidate;
459  c->name = vocab(p); // to be more efficient this could be the index
460  prob = observations.a(observe,i);
461  if(num_obs == 2)
462  prob2 = observations2.a(observe,i);
463 
464  if(take_logs)
465  {
466  prob = safe_log10(prob);
467  if (prob < ob_log_prob_floor)
468  prob = ob_log_prob_floor;
469 
470  if(num_obs == 2)
471  {
472  prob2 = safe_log10(prob2);
473  if (prob2 < ob_log_prob_floor2)
474  prob2 = ob_log_prob_floor2;
475  }
476  }
477  else // already in logs
478  {
479  if (prob < ob_log_prob_floor)
480  prob = ob_log_prob_floor;
481  if ((num_obs == 2) && (prob2 < ob_log_prob_floor2))
482  prob2 = ob_log_prob_floor2;
483  }
484 
485  prob *= ob_scale;
486  prob2 *= ob_scale2;
487 
488  if(num_obs == 2)
489  c->score = prob + prob2;
490  else
491  c->score = prob;
492 
493  c->next = all_c;
494  c->s = s;
495  all_c = c;
496  }
497 
498  if(n_beam > 0)
499  {
500  // N.B. this might be very time-consuming
501  top_n_candidates(all_c);
502  }
503 
504  return all_c;
505 }
506 
507 static EST_VTPath *vit_npath(EST_VTPath *p,EST_VTCandidate *c,
508  EST_Features &f)
509 {
510  // Build a (potential) new path link from this previous path and
511  // This candidate
512  EST_VTPath *np = new EST_VTPath;
513  double lprob,prob;
514  EST_String prev,ttt;
515  (void)f;
516 
517  np->c = c;
518  np->from = p;
519 
520  // are we using extra info ?
521  if(using_given)
522  // time of candidate is
523  // c->s->f("pos");
524  prob = find_extra_gram_prob(np,&np->state,c->s->f("pos"));
525  else
526  prob = find_gram_prob(np,&np->state);
527 
528  lprob = safe_log10(prob);
529  if (lprob < lm_log_prob_floor)
530  lprob = lm_log_prob_floor;
531 
532  lprob *= lm_scale;
533 
534  np->f.set("lscore",(c->score+lprob)); // simonk : changed prob to lprob
535  if (p==0)
536  np->score = (c->score+lprob);
537  else
538  np->score = (c->score+lprob) + p->score;
539 
540  return np;
541 }
542 
543 static double find_gram_prob(EST_VTPath *p,int *state)
544 {
545  // Look up transition probability from *state for name.
546  // Return probability and update state
547  double prob=0.0,nprob;
548  int i,f=FALSE;
549  EST_VTPath *pp;
550 
551  EST_StrVector window(ngram.order());
552  for (pp=p->from,i=ngram.order()-2; i >= 0; i--)
553  {
554  if (pp != 0)
555  {
556  window[i] = pp->c->name.string();
557  pp = pp->from;
558  }
559  else if (f)
560  window[i] = ppstring;
561  else
562  {
563  window[i] = pstring;
564  f = TRUE;
565  }
566  }
567  window[ngram.order()-1] = p->c->name.string();
568  const EST_DiscreteProbDistribution &pd = ngram.prob_dist(window);
569  if (pd.samples() == 0)
570  prob = 0;
571  else
572  prob = (double)pd.probability(p->c->name.string());
573 
574  for (i=0; i < ngram.order()-1; i++)
575  window[i] = window(i+1);
576  ngram.predict(window,&nprob,state);
577 
578  return prob;
579 }
580 
581 
582 static double find_extra_gram_prob(EST_VTPath *p,int *state,int time)
583 {
584 
585  int i;
586  double prob=0.0,nprob;
587  EST_StrVector window(ngram.order());
588  EST_StrVector history(max_history);
589 
590  get_history(history,p);
591 
592  fill_window(window,history,p,time);
593 
594  /*
595  cerr << "Looking up ngram ";
596  for(i=0;i<window.num_points();i++)
597  cerr << window(i) << " ";
598  cerr << endl;
599  */
600 
601  const EST_DiscreteProbDistribution &pd = ngram.prob_dist(window);
602  if (pd.samples() == 0)
603  prob = 0;
604  else
605  prob = (double)pd.probability(p->c->name.string());
606 
607  // shift history, adding latest item at 'end' (0)
608  if(max_history>0)
609  {
610  for(i=history.length()-1;i>0;i--)
611  history[i] = history(i-1);
612  history[0] = p->c->name.string();
613  }
614 
615  fill_window(window,history,p,time+1);
616  ngram.predict(window,&nprob,state);
617 
618  //cerr << endl << endl;
619 
620  return prob;
621 
622 }
623 
624 static void get_history(EST_StrVector &history, EST_VTPath *p)
625 {
626 
627  EST_VTPath *pp;
628  int i,f=FALSE;
629  for (pp=p->from,i=0; i < history.length(); i++)
630  {
631 
632  if (pp != 0)
633  {
634  history[i] = pp->c->name.string();
635  pp = pp->from;
636  }
637  else if (f)
638  history[i] = ppstring;
639  else
640  {
641  history[i] = pstring;
642  f = TRUE;
643  }
644  }
645 
646 }
647 
648 static void fill_window(EST_StrVector &window,EST_StrVector &history,
649  EST_VTPath *p,const int time)
650 {
651  // Look up transition probability from *state for name.
652  // Return probability and update state
653  int i,j;
654  EST_String s;
655 
656  // can we even do it?
657  if( time >= given.length() )
658  return;
659 
660  // format should be run-time defined, but try this for now
661  // first n-1 things in window come from 'given'
662  // last one is predictee
663 
664  // also want vocab and grammar mismatch allowed !!!!!!
665 
666  // predictee
667  window[ngram.order()-1] = p->c->name.string();
668 
669  // given info for this time
670  EST_StrVector *this_g = &(given.nth(time)); // inefficient to count down a list
671 
672 
673  for(i=0;i<ngram.order()-1;i++)
674  {
675 
676  if( is_a_special( (*this_g)(i), j))
677  window[i] = history(-1-j); // j=-1 -> (0) j=-2 -> (1) etc.
678  else
679  window[i] = (*this_g)(i);
680  }
681 }
682 
683 
684 
685 static int is_a_special(const EST_String &s, int &val)
686 {
687 
688  // special is "<int>"
689 
690  EST_String tmp;
691  if(s.contains("<") && s.contains(">"))
692  {
693  tmp = s.after("<");
694  tmp = tmp.before(">");
695  val = atoi(tmp);
696  //cerr << "special " << tmp << "=" << val << endl;
697  return TRUE;
698  }
699  return FALSE;
700 }
701 
702 static void top_n_candidates(EST_VTCandidate* &all_c)
703 {
704  // keep the n most likely candidates
705  // avoiding a full sort of the (potentially long) list
706 
707  EST_VTCandidate *top_c=NULL,*p,*q,*this_best, *prev_to_best;
708  int i;
709  if(n_beam < 1)
710  return; // do nothing
711 
712  // here we assume big is always good
713  //if(!big_is_good)
714  //score_multiplier = -1;
715 
716  for(i=0;i<n_beam;i++)
717  {
718 
719  // head of the list is best guess
720  this_best=all_c;
721  prev_to_best=NULL;
722 
723  // find best candidate in all_c
724  q=NULL;;
725  for(p=all_c;p!= NULL;q=p,p=p->next)
726  {
727  //cerr << "item : " << p->score << endl;
728  if(p->score > this_best->score)
729  {
730  this_best = p;
731  prev_to_best=q;
732  }
733  }
734 
735  if(this_best == NULL)
736  break; // give up now - must have run out of candidates
737 
738  // move best candidate over to new list
739  if(prev_to_best == NULL)
740  // best was head of list
741  all_c = this_best->next;
742  else
743  // best was not head of all_c
744  prev_to_best->next = this_best->next;
745 
746  this_best->next = top_c;
747  top_c = this_best;
748  }
749 
750  delete all_c;
751  all_c = top_c;
752 
753 /*
754  cerr << "Here are the top " << n_beam << " candidates" << endl;
755  for(p=all_c;p != NULL;p=p->next)
756  cerr << p->score << endl;
757 */
758 }
759 
760 
const T & first() const
return const reference to first item in list
Definition: EST_TList.h:154
EST_Item * head() const
Definition: EST_Relation.h:122
EST_TokenStream & get(EST_Token &t)
get next token in stream
Definition: EST_Token.cc:486
float & a(int i, int c=0)
Definition: EST_Track.cc:1022
double samples(void) const
Total number of example found.
int ival(const EST_String &rkey, int m=1) const
Definition: EST_Option.cc:76
int num_channels() const
return number of channels in track
Definition: EST_Track.h:656
void close(void)
Close stream.
Definition: EST_Token.cc:406
EST_String itoString(int n)
Make a EST_String object from an integer.
Definition: util_io.cc:140
float fval(const EST_String &rkey, int m=1) const
Definition: EST_Option.cc:98
void set(const EST_String &name, int ival)
Definition: EST_Features.h:186
int open(const EST_String &filename)
open a EST_TokenStream for a file.
Definition: EST_Token.cc:200
INLINE int length() const
number of items in vector.
Definition: EST_TVector.h:250
int eof()
end of file
Definition: EST_Token.h:363
void set(const EST_String &name, int ival)
Definition: EST_Item.h:180
EST_read_status load(const EST_String name, float ishift=0.0, float startt=0.0)
Definition: EST_Track.cc:1309
int empty() const
Definition: EST_Relation.h:144
T & nth(int n)
return the Nth value
Definition: EST_TList.h:147
const int present(const K &rkey) const
Returns true if key is present.
Definition: EST_TKVL.cc:222
EST_Token & peek(void)
peek at next token
Definition: EST_Token.h:333
const EST_String & string(void) const
Definition: EST_Val.h:155
const V & val(const K &rkey, bool m=0) const
return value according to key (const)
Definition: EST_TKVL.cc:145
void append(const T &item)
add item onto end of list
Definition: EST_TList.h:198
int contains(const char *s, int pos=-1) const
Does it contain this substring?
Definition: EST_String.h:378
Template vector.
Definition: EST_TVector.h:145
A class that offers a generalised Viterbi decoder.
Definition: EST_viterbi.h:134
int num_frames() const
return number of frames in track
Definition: EST_Track.h:650
EST_String after(int pos, int len=1) const
Part after pos+len.
Definition: EST_String.h:321
EST_String before(int pos, int len=0) const
Part before position.
Definition: EST_String.h:289