Edinburgh Speech Tools  2.4-release
 All Classes Functions Variables Typedefs Enumerations Enumerator Friends Pages
tilt_analysis.cc
1 /*************************************************************************/
2 /* */
3 /* Centre for Speech Technology Research */
4 /* University of Edinburgh, UK */
5 /* Copyright (c) 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 : Paul Taylor */
34 /* Date : March 1998 */
35 /*-----------------------------------------------------------------------*/
36 /* Tilt Analysis */
37 /* */
38 /*=======================================================================*/
39 
40 #include <cstdlib>
41 #include "EST_math.h"
42 #include "EST_tilt.h"
43 #include "tilt.h"
44 #include "EST_Track.h"
45 #include "EST_track_aux.h"
46 #include "EST_Features.h"
47 #include "EST_error.h"
48 
49 static int match_rf_point(EST_Track &fz, int b_start, int b_stop,
50  int e_start, int e_stop,
51  int &mi, int &mj);
52 
53 static void make_int_item(EST_Item &e, const EST_String name, float end,
54  float start_pos,
55  float start_f0,
56  float peak_pos,
57  float peak_f0);
58 
59 //void rfc_segment_features_only(EST_Relation &ev);
60 //void convert_to_event(EST_Relation &ev);
61 
62 static int rf_match(EST_Track &fz, EST_Item &ev, float range);
63 
64 static int zero_cross(EST_Track &fz);
65 
66 static int comp_extract(EST_Track &fz, EST_Track &part, float &start, float
67  &end, float min);
68 //void segment_to_event(EST_Relation &ev);
69 //void event_to_segment(EST_Relation &ev, float min_length = 0.01);
70 
71 void int_segment_to_unit(EST_Relation &a, EST_Relation &ev);
72 
73 static void convert_to_local(EST_Relation &ev);
74 
75 static void silence_f0(EST_Relation &ev, EST_Track &fz);
76 
77 static void add_phrases(EST_Relation &ev);
78 
79 
80 // find event portions of fz in contour, cut out, and send one by one
81 // to individual labeller.
82 
83 // This routine takes an Fz contour and a list of potential events,
84 // and peforms RFC matching on them. It returns a list of events with RFC
85 // parameters marked.
86 //
87 // The algorithm works as follows:
88 //
89 // make a list of events, with start and stop times.
90 //
91 // for every event
92 // {
93 // find start and stop times.
94 // call comp_extract() to get best section of contour that
95 // falls between these times. If no suitable contour is found the
96 // event is deleted and not labelled.
97 // call rf_match to determine the optimal start and end times for
98 // that section
99 // }
100 //
101 // Now add connections between non-overlapping events. Overlapping events
102 // get readjusted to make them simply adjacent
103 
104 void default_rfc_params(EST_Features &op)
105 {
106  op.set("start_limit", 0.1);
107  op.set("stop_limit", 0.1);
108  op.set("range", 0.3);
109  op.set("min_event_duration", 0.03);
110 }
111 void print_event(EST_Item &ev);
112 
113 void rfc_analysis(EST_Track &fz, EST_Relation &ev, EST_Features &op)
114 {
115  EST_Item *e, *tmp, *n;
116  float start_search, end_search;
117  EST_Track part;
118  EST_Relation eva;
119 
120  if (op.present("debug"))
121  {
122  cout << "rfc_recognise\n";
123  cout << ev;
124  }
125 
126  int_segment_to_unit(ev, eva);
127 
128  if (op.present("debug"))
129  {
130  cout << "rfc_recognise\n";
131  cout << ev;
132  }
133 
134  // fill values in event labels using matching algorithms
135  for (e = ev.head(); e != 0; e = n)
136  {
137  n = e->next();
138  // cout << endl << endl;
139  if (!event_item(*e))
140  continue;
141  end_search = e->F("end") + op.F("stop_limit");
142  start_search = e->F("start") - op.F("start_limit");
143 
144  if (op.present("debug"))
145  {
146  cout << "start = " << e->F("start") << " End "
147  << e->F("end")<< endl;
148  cout << "s start = " << start_search << " sEnd "
149  << end_search << endl;
150  cout << *e << endl;;
151  }
152 
153  if (comp_extract(fz, part, start_search, end_search,
154  op.F("min_event_duration")))
155  rf_match(part, *e, op.F("range"));
156  else
157  ev.remove_item(e);
158  }
159 
160  // hack to deal with cases where no events exist
161  if (ev.head() == 0)
162  {
163  tmp = ev.append();
164  make_int_item(*tmp, "sil", fz.t(0), fz.t(fz.num_frames() - 1),
165  0.0, 0.0, 0.0);
166  }
167 
168  silence_f0(ev, fz);
169  add_phrases(ev);
170 
171  // cout << endl << endl << ev;
172  convert_to_local(ev);
173 
174  // make sure events don't overlap
175 // adjust_overlaps(ev);
176 
177  ev.f.set("intonation_style", "rfc");
178 
179  if (op.present("debug"))
180  {
181  cout << "After RFC analysis\n";
182  cout << ev;
183  }
184 }
185 
186 // convert intonation stream from segment type to event type description.
187 // Note this has to be done in 2 loops.
188 
189 // Create a section of fz contour, bounded by times "start" and "end".
190 // The created contour is defined to be the largest single continuous
191 // section of contour bounded by the two times. If no fz contour exits within
192 // the limits an error is returned.
193 
194 static void convert_to_local(EST_Item *e)
195 {
196  if (e->S("rfc.type", "0") == "RISEFALL")
197  {
198  e->set("rfc.rise_amp", (e->F("rfc.peak_f0") - e->F("ev.start_f0")));
199  e->set("rfc.rise_dur", (e->F("rfc.peak_pos") - e->F("start")));
200  e->set("rfc.fall_amp", (e->F("rfc.end_f0") - e->F("rfc.peak_f0")));
201  e->set("rfc.fall_dur", (e->F("end") - e->F("rfc.peak_pos")));
202  e->set("ev.f0", e->F("rfc.peak_f0"));
203 // e->set("ev.f0", e->F("rfc.peak_f0") - e->F("rfc.rise_amp"));
204 
205  e->A("rfc").remove("peak_f0");
206  e->A("rfc").remove("peak_pos");
207  e->A("rfc").remove("end_f0");
208  e->A("rfc").remove("type");
209  e->A("ev").remove("start_f0");
210  }
211  else if (e->S("rfc.type", "0") == "RISE")
212  {
213  e->set("rfc.rise_amp", (e->F("rfc.end_f0") - e->F("ev.start_f0")));
214  e->set("rfc.rise_dur", (e->F("end") - e->F("start")));
215  e->set("rfc.fall_amp", 0.0);
216  e->set("rfc.fall_dur", 0.0);
217  e->set("ev.f0", e->F("rfc.end_f0"));
218 // e->set("ev.f0", e->F("rfc.end_f0") - e->F("rfc.rise_amp"));
219 
220  e->A("rfc").remove("peak_f0");
221  e->A("rfc").remove("peak_pos");
222  e->A("rfc").remove("end_f0");
223  e->A("rfc").remove("type");
224  e->A("ev").remove("start_f0");
225  }
226  else if (e->S("rfc.type", "0") == "FALL")
227  {
228  e->set("rfc.rise_amp", 0.0);
229  e->set("rfc.rise_dur", 0.0);
230  e->set("rfc.fall_amp", (e->F("rfc.end_f0") - e->F("ev.start_f0")));
231  e->set("rfc.fall_dur", (e->F("end") - e->F("start")));
232  e->set("ev.f0", e->F("ev.start_f0"));
233 
234  e->A("rfc").remove("peak_f0");
235  e->A("rfc").remove("peak_pos");
236  e->A("rfc").remove("end_f0");
237  e->A("rfc").remove("type");
238  e->A("ev").remove("start_f0");
239  }
240  if (!e->f_present("time"))
241  e->set("time", (e->F("end") - e->F("rfc.fall_dur")));
242 }
243 
244 void convert_to_local(EST_Relation &ev)
245 {
246  EST_Item *e;
247 
248  for (e = ev.head(); e; e = e->next())
249  convert_to_local(e);
250 
251  // cout << "c to l \n\n\n" << ev << endl << endl;
252 
253 // ev.remove_item_feature("rfc.peak_f0");
254 // ev.remove_item_feature("rfc.peak_pos");
255  ev.remove_item_feature("ev.start_f0");
256  ev.remove_item_feature("start");
257 // ev.remove_item_feature("rfc.end_f0");
258  ev.remove_item_feature("end");
259 // remove_item_feature(ev, "int_event");
260 
261  ev.f.set("timing_style", "event");
262 }
263 
264 void extract2(EST_Track &orig, float start, float end, EST_Track &ret);
265 
266 static int comp_extract(EST_Track &fz, EST_Track &part, float &start, float
267  &end, float min_length)
268 {
269  int i;
270  int continuous = 1;
271  cout.precision(6);
272  EST_Track tr_tmp, tmp2;
273 
274  if (start > end)
275  EST_error("Illegal start and end times: %f %f\n", start, end);
276 
277 // int from = fz.index(start);
278 // int to = fz.index_below(end);
279 
280  // cout << "full f0 = " << fz.num_frames() << endl;
281 // fz.copy_sub_track(tr_tmp, from, to, 0, EST_ALL);
282 
283 // cout << "sub_track: " << tr_tmp;
284 
285  extract2(fz, start, end, tr_tmp);
286 
287 // cout << "tr_tmp 1\n" << tr_tmp;
288  tr_tmp.rm_trailing_breaks();
289 // cout << "tr_tmp 2\n" << tr_tmp;
290 
291 // cout << "end " << tr_tmp.end() << " start "<< tr_tmp.start() << endl;
292 
293 // i = tr_tmp.num_frames();
294 
295 // cout << "starting i = " << tr_tmp.num_frames() << endl;
296 // cout << "starting i = " << tr_tmp.num_channels() << endl;
297 // cout << "found end at " << i << tr_tmp.t(i) << endl;
298 
299 // cout << "tr_tmp 1\n" << tr_tmp;
300  if ((tr_tmp.end() - tr_tmp.start()) < min_length)
301  {
302  cout << "Contour too small for analysis\n";
303  return 0;
304  }
305 
306  for (i = 0; i < tr_tmp.num_frames(); ++i)
307  if (tr_tmp.track_break(i))
308  continuous = 0;
309 
310  // if no breaks are found in this section return.
311  if (continuous)
312  {
313  part = tr_tmp;
314  return 1;
315  }
316 
317  // tracks can legitimately have breaks in them due to the
318  // search region overlapping a silence. In this case we find
319  // the longest single section
320  // cout << "tilt_analysis: This contour has a break in it\n";
321 
322  int longest, s_c, s_l;
323  longest = s_c = s_l = 0;
324 
325  for (i = 0; i < tr_tmp.num_frames(); ++i)
326  if (tr_tmp.track_break(i))
327  {
328  if ((i - s_c) > longest)
329  {
330  longest = i - s_c - 1;
331  s_l = s_c;
332  }
333  // skip to next real values
334  for (;(i < tr_tmp.num_frames()) && (tr_tmp.track_break(i)); ++i)
335  s_c = i;
336  }
337 
338  if ((i - s_c) > longest)
339  {
340  longest = i - s_c - 1;
341  s_l = s_c;
342  }
343 
344  // cout << "Longest fragment is " << longest << " starting at " << s_l <<endl;
345  // cout << "Times: " << tr_tmp.t(s_l) << " : " <<tr_tmp.t(s_l + longest) << endl;
346 
347  extract2(tr_tmp, tr_tmp.t(s_l), tr_tmp.t(s_l + longest), part);
348 // cout << "Part\n" << part;
349  part.rm_trailing_breaks();
350  start = part.t(0);
351  end = part.t(part.num_frames()-1);
352 
353  return 1;
354 
355 }
356 
357 static int zero_cross(EST_Track &fz)
358 {
359  for (int i = 0; i < fz.num_frames() - 1; ++i)
360  if ((fz.a(i) >= 0.0) && (fz.a(i + 1) < 0.0))
361  return i;
362 
363  return -1;
364 }
365 
366 // 1. There should be a more sophisticated decision about whether there
367 // should be a risefall analysis, and if so, where the peak (zero cross)
368 // region should be.
369 // 2. There should be minimum endforced distances for rises and falls.
370 
371 static int rf_match(EST_Track &fz, EST_Item &ev, float range)
372 {
373  int n;
374  EST_Track diff;
375  int start, stop;
376  int b_start, b_stop, e_start, e_stop, region;
377  EST_Features empty;
378 
379  if (fz.num_frames() <= 0)
380  {
381  ev.set("start", 0.0);
382  ev.set("ev", empty);
383  ev.set("rfc", empty);
384  ev.set("ev.start_f0", 0.0);
385  ev.set("rfc.peak_f0", 0.0);
386  ev.set("rfc.peak_pos", 0.0);
387  }
388 
389  diff = differentiate(fz);
390 
391  // cout << "Extracted Contour:\n";
392  // cout << fz;
393 
394  n = zero_cross(diff);
395 
396  if (n >= 0) // rise + fall combination
397  {
398  // cout << "zero crossing at point " << n << " time " << fz.t(n) << endl;
399  b_start = 0;
400  stop = n;
401  // find rise part
402  region = (int)(range * float(stop - b_start));
403  // ensure region is bigger than 0
404  region = region > 0 ? region : 1;
405 
406  b_stop = b_start + region;
407  e_start = stop - region;
408  e_stop = stop + region;
409  // ensure regions are separate
410  e_start = (e_start < b_stop)? b_stop : e_start;
411 
412  //printf("rise: b_start %d, b_stop %d, end %d, end stop%d\n", b_start,
413  // b_stop, e_start, e_stop);
414  match_rf_point(fz, b_start, b_stop, e_start, e_stop, start, stop);
415  // cout << "Rise is at start: " << start << " Stop = " << stop << endl;
416 
417  ev.set("ev.start_f0", fz.a(start));
418  ev.set("start", fz.t(start));
419 
420  // find fall part. The start of the search is FIXED by the position
421  // of where the rise stopped
422 
423  b_start = n;
424  b_stop = n + 1;
425  e_stop = fz.num_frames() - 1;
426  region = (int)(range * float(e_stop - b_start));
427  region = region > 0 ? region : 1;
428  e_start = e_stop - region;
429 
430  // printf("fall: b_start %d, b_stop %d, end %d, end stop%d\n", b_start,
431  // b_stop, e_start, e_stop);
432 
433  match_rf_point(fz, b_start, b_stop, e_start, e_stop, start, stop);
434  // cout << "Fall is at start: " << start << " Stop = " << stop << endl;
435  // cout << "region: " << region << endl;
436  // cout << "stop could be " << e_stop << " value " << fz.t(e_stop) << endl;
437  // cout << "start could be " << e_start << " value " << fz.t(e_start) << endl;
438 
439  ev.set("rfc.peak_f0", fz.a(start));
440  ev.set("rfc.peak_pos", fz.t(start));
441  ev.set("rfc.end_f0", fz.a(stop));
442 
443  ev.set("end", fz.t(stop));
444  ev.set("rfc.type", "RISEFALL");
445 
446 /* ev.set("rfc.setpeak_f0", fz.a(start));
447  ev.fA("rfc").set("peak_pos", fz.t(start));
448  ev.fA("rfc",1).set("end_f0", fz.a(stop));
449 
450  ev.set("end", fz.t(stop));
451 
452  ev.fA("rfc").set("type", "RISEFALL");
453 */
454  // cout << "peak pos: " << ev.F("rfc.peak_pos") << endl;
455  // cout << "peak pos: " << ev.A("rfc").F("peak_pos") << endl;
456  // cout << "rfc:\n" << ev.A("rfc") << endl;
457  // cout << "labelled event: " << ev << endl;
458  }
459  else // separate rise or fall
460  {
461  b_start = 0;
462  e_stop = fz.num_frames() - 1;
463 
464  region = (int)(range * float(e_stop - b_start));
465  region = region > 0 ? region : 1;
466 
467  b_stop = b_start + region;
468  e_start = e_stop - region;
469 
470  // printf("b_start %d, b_stop %d, end start %d, end stop%d\n", b_start,
471  // b_stop, e_start, e_stop);
472 
473  match_rf_point(fz, b_start, b_stop, e_start, e_stop, start, stop);
474 
475  ev.set("start", fz.t(start));
476  ev.set("ev.start_f0", fz.a(start));
477  ev.set("rfc.peak_f0", 0.0);
478  ev.set("rfc.peak_pos", 0.0);
479 
480  ev.set("rfc.end_f0", fz.a(stop));
481  ev.set("end", fz.t(stop));
482 
483  // cout << "start " << fz.t(start) << " end " << fz.t(stop) << endl;
484 
485  if (fz.a(fz.index(fz.start())) < fz.a(fz.index(fz.end())))
486  ev.set("rfc.type", "RISE");
487  else
488  ev.set("rfc.type", "FALL");
489 
490  // cout << "labelled event: " << ev << endl;
491  }
492  return 0;
493 }
494 
495 static void silence_f0(EST_Relation &ev, EST_Track &fz)
496 {
497  EST_Item * e;
498  int i;
499 
500  for (e = ev.head(); e; e = e->next())
501  if (sil_item(*e))
502  {
503  i = fz.prev_non_break(fz.index(e->F("start")));
504 
505  e->set("ev.start_f0", fz.a(i));
506  i = fz.next_non_break(fz.index(e->F("end")));
507  e->set("ev.end_f0", fz.a(i));
508  }
509 }
510 
511 static void add_phrases(EST_Relation &ev)
512 {
513  EST_Item *e, *n, *s;
514 
515  // cout << "phrase edges: " << endl;
516  // cout << ev;
517 
518  for (e = ev.head(); e; e = n)
519  {
520  n = e->next();
521  if (sil_item(*e))
522  {
523  if (e != ev.head())
524  {
525  s = e->insert_before();
526  s->set("name", "phrase_end");
527  s->set("ev.f0", e->F("ev.start_f0"));
528  s->set("time", e->F("start"));
529  }
530  if (e != ev.tail())
531  {
532  s = e->insert_after();
533  s->set("name", "phrase_start");
534  s->set("ev.f0", e->F("ev.end_f0"));
535  s->set("time", e->F("end"));
536  }
537  }
538  }
539 
540  for (e = ev.head(); e; e = n)
541  {
542  n = e->next();
543  if (sil_item(*e))
544  ev.remove_item(e);
545  }
546 }
547 
548 /*
549 static void add_phrases(EST_Relation &ev, bool phrase_edges)
550 {
551  EST_Item *e, *n, *s, *p;
552  float min_duration = 0.02;
553 
554  cout << "phrase edges: " << phrase_edges << endl;
555  cout << ev;
556 
557  for (e = ev.head(); next(e); e = n)
558  {
559  n = e->next();
560  p = e->prev();
561  if (!sil_item(*e))
562  continue;
563 
564  s = 0;
565 
566  if ((e != ev.head()) && (phrase_edges
567  || (p &&(e->F("start") - p->F("end"))
568  > min_duration)))
569  {
570  s = e->insert_before();
571  s->set("name", "phrase_end");
572  s->set("ev.f0", e->F("ev.start_f0", 1));
573  s->set("position", e->F("start"));
574  }
575 
576  if (phrase_edges || (n &&((n->F("start")- e->F("end")) >min_duration)))
577  {
578  s = e->insert_after();
579  s->set("name", "phrase_start");
580  s->set("ev.f0", e->F("ev.end_f0",1));
581  s->set("position", e->F("end"));
582  }
583 
584  if (s == 0)
585  {
586  s = e->insert_before();
587  s->set("name", "pause");
588  s->set("position", e->F("start"));
589  }
590  }
591 
592  s = e->insert_after();
593  s->set("name", "phrase_end");
594  s->set("ev.f0", e->F("ev.start_f0", 1));
595  s->set("position", e->F("end"));
596 
597  for (e = ev.head(); e; e = n)
598  {
599  n = e->next();
600  if (sil_item(*e))
601  ev.remove_item(e);
602  }
603  cout << "end phrase edges\n";
604 }
605 */
606 static void make_int_item(EST_Item &tmp,
607  const EST_String name, float end, float start,
608  float start_f0, float peak_pos,
609  float peak_f0)
610 
611 {
612  tmp.set_name(name);
613  EST_Features dummy;
614 
615  tmp.set("start", start);
616  tmp.set("end", end);
617  tmp.set("ev", dummy);
618  tmp.set("ev.start_f0", start_f0);
619 
620  if ((name != "sil") && (name != "c"))
621  {
622  tmp.set("rfc", dummy);
623  tmp.set("rfc.peak_pos", peak_pos);
624  tmp.set("rfc.peak_f0", peak_f0);
625  tmp.set("rfc.pos", 1);
626  }
627 }
628 
629 static float distance(EST_Track &fz, int pos, EST_Track &new_fz, int
630  num_points)
631 {
632  int i;
633  float distance = 0.0;
634  float diff;
635 
636  for (i = 0; i < num_points; ++i)
637  {
638  diff = fz.a(i + pos) - new_fz.a(i);
639  /* dprintf("o = %f, n = %f\n", old_contour[i + pos],
640  new_contour[i]); */
641  distance += (diff * diff);
642  }
643  return (distance);
644 }
645 
646 static float weight(float duration)
647 {
648  (void)duration;
649  /* return ((MAX_DUR + 0.7) - duration); */
650  return(1.0);
651 }
652 
653 // Return indexs in fz to best fitting region of monomial curve to
654 // fz contour. The search is bounded by the b/e_start an b/e_stop
655 // values. The contour fz, should have no breaks in it.
656 
657 static int match_rf_point(EST_Track &fz, int b_start, int b_stop,
658  int e_start, int e_stop, int &mi, int &mj)
659 {
660  int i, j, k;
661  float s_pos, e_pos, s_freq, e_freq, t;
662  float amp, duration, dist, ndist;
663  float min_dist = MAXFLOAT;
664  int length;
665  EST_Track new_fz(fz.num_frames(), 1);
666  float f_shift;
667 
668  mi = mj = 0; // set values to zero for safety
669 
670  if ((b_start >= b_stop) || (b_start < 0))
671  {
672  cerr << "Illegal beginning search region in match_rf_point:" <<
673  b_start << "-" << b_stop << endl;
674  return -1;
675  }
676  if ((e_start >= e_stop) || (e_stop > fz.num_frames()))
677  {
678  cerr << "Illegal ending search region in match_rf_point:" <<
679  e_start << "-" << e_stop << endl;
680  return -1;
681  }
682 
683  f_shift = fz.shift();
684  duration = 0.0;
685 
686  for (i = b_start; i < b_stop; ++i)
687  for (j = e_start; j < e_stop; ++j)
688  {
689  s_pos = fz.t(i);
690  s_freq = fz.a(i);
691 
692  e_pos = fz.t(j);
693  e_freq = fz.a(j);
694 
695  duration = e_pos - s_pos;
696  amp = e_freq - s_freq;
697  length = j - i;
698 
699  for (k = 0; k < length + 1; ++k)
700  {
701  t = ((float) k) * f_shift;
702  new_fz.a(k) = (amp * fncurve(duration, t, 2.0))
703  + s_freq;
704  }
705 
706  dist = distance(fz, i, new_fz, length);
707  ndist = dist / (duration * 100.0);
708  ndist *= weight(duration);
709 
710  if (ndist < min_dist)
711  {
712  min_dist = ndist;
713  mi = i;
714  mj = j;
715  }
716  }
717  return 0;
718 }
719 
720 /*
721 #if 0
722 
723 static void fill_f0_values(EST_Track &fz, EST_Relation &ev)
724 {
725  EST_Item *e;
726  float start_a;
727  int pos;
728  float prev = 0.0;
729 
730  for (e = ev.head(); e != 0; e = e->next())
731  {
732  if (e->name() == "sil")
733  {
734  pos = fz.index(prev);
735  pos = fz.prev_non_break(pos);
736  start_a = pos > 0 ? fz.a(pos) : 0.0;
737  }
738  else if (e->name() == "c")
739  {
740  pos = fz.index(prev);;
741  pos = fz.next_non_break(pos);
742  start_a = fz.a(pos);
743  }
744  else
745  start_a = fz.a(prev);
746 
747  e->set("ev:start_f0", start_a);
748  e->set("start", prev);
749  // cout << "setting start to be " << start_a << " at pos " << pos << endl;
750  // cout << *e << " " << *RFCS(*e) << endl;
751 
752  if (e->f("rfc:type") == "RISEFALL")
753  {
754  start_a = fz.a(e->F("rfc:peak_pos"));
755  e->set("rfc:peak_f0", start_a);
756  }
757  prev = e->f("end");
758  }
759 }
760 
761 static void insert_silence(EST_Item *n, EST_Track &fz, int i, int j)
762 {
763  EST_Item *prev_item, *new_sil;
764  float min_length = 0.015;
765  float sil_start, sil_end, start_f0;
766 
767  sil_start = i > 0 ? fz.t(i - 1) : 0.0;
768  sil_end = fz.t(j);
769 
770  if ((sil_end - sil_start) < min_length)
771  return;
772 
773  // add silence
774  start_f0 = (i > 0) ? fz.a(i -1) : fz.a(i);
775  new_sil = n->insert_after();
776  make_int_item(*new_sil, "sil", sil_end, sil_start, start_f0, 0.0, 0.0);
777  new_sil->set("rfc:type", "SIL");
778 
779  // if silence leaves a gap, make a new element before it
780  if ((sil_start - n->F("start")) < min_length)
781  return;
782 
783  // make new element, setting end time to silence start time.
784  prev_item = n->prev()->insert_before();
785  make_int_item(*prev_item, n->name(), sil_start, 0.0, n->f("ev:start_f0"),
786  0.0,0.0);
787 
788  // now tidy up values of existing element
789  n->set("ev:start_f0", fz.a(j));
790  n->set("start", sil_end);
791 }
792 
793 static void add_phrases_old(EST_Relation &ev, EST_Track &fz)
794 {
795  int i;
796  EST_Item *e, *n, *s;
797  bool sil = false;
798  float start, end;
799 
800  for (e = ev.head(); next(e); e = n)
801  {
802  n = e->next();
803  start = e->F("end");
804  end = n->F("start");
805  sil = false;
806 
807  cout << endl << endl;
808 
809  cout << *e << endl;
810  cout << *n << endl;
811 
812  cout << "start = " << start << endl;
813  cout << "end = " << end << endl;
814 
815  for (i = fz.index(start); i < fz.index(end); ++i)
816  {
817  cout << i << endl;
818  cout << fz.val(i) << endl;
819  if ((!sil) &&(!fz.val(i)))
820  {
821  cout << "phrase_end\n";
822  sil = true;
823  s = e->insert_after();
824  s->set("name", "phrase_end");
825  s->set("position", fz.t(i - 1));
826  if (i > (fz.index(start) + 1))
827  s->set("ev:f0", fz.a(i - 1));
828  e = s;
829  }
830 
831  if (sil && fz.val(i)) // just come out of silence
832  {
833  cout << "phrase_start\n";
834  sil = false;
835  s = e->insert_after();
836  s->set("name", "phrase_start");
837  s->set("position", fz.t(i));
838  s->set("ev:f0", fz.a(i));
839  }
840  }
841  }
842 }
843 
844 static void add_silences(EST_Track &fz, EST_Relation &ev,
845  float end_sil_length)
846 {
847  int i, j;
848  EST_Item *e;
849 
850  for (i = 0; i < fz.num_frames(); ++i)
851  if (fz.track_break(i))
852  {
853  for (j = i; j < fz.num_frames(); ++j)
854  if (fz.val(j))
855  break;
856  if (j == fz.num_frames()) // off end of array
857  break;
858  cout << "silence between " <<i << " and " << j << endl;
859  // cout << " " << fz.t(i) << " and " << fz.t(j) << endl;
860 
861  for (e = ev.head(); e != 0; e = e->next())
862  if (e->F("end") >= fz.t(j))
863  break;
864  insert_silence(e, fz, i, j);
865  // for (e = ev.head(); e != 0; e = e->next())
866  // cout << *e << " : " << *RFCS(*e) << endl;
867 
868  i = j;
869  }
870 
871  if (sil_item(*ev.tail()))
872  return;
873 
874  float start_f0 = fz.a(fz.end());
875 
876  e = ev.append();
877  make_int_item(*e, "sil", fz.end() + end_sil_length, fz.end(),
878  start_f0, 0.0, 0.0);
879  e->set("rfc:type", "SIL");
880 }
881 */
882 /*static void minimum_duration(EST_Relation &ev, float min_dur)
883 {
884  EST_Item *e, *n;
885 
886  for (e = ev.head(); e != 0; e = n)
887  {
888  n = e->next();
889  if (dur(*e) < min_dur)
890  ev.remove_item(e);
891  }
892 }
893 
894 static void adjust_overlaps(EST_Relation &ev)
895 {
896  EST_Item *e, *n;
897  float pos=0.0;
898 
899  for (e = ev.head(); next(e) != 0; e = e->next())
900  {
901  n = e->next();
902  if (e->F("end") > n->F("start"))
903  {
904 */
905 /* cout << "Overlapping events " << *e <<":" << *n << endl;
906  // case a: genuine overlap
907  if (n->F("end") > e->F("end"))
908  {
909  cout << "case A\n";
910 // pos = (e->F("end") + start(n)) / 2.0;
911  }
912 
913  // case b: second element is enclosed by first
914  else if (n->F("end") <= e->F("end"))
915  {
916  cout << "case A\n";
917 // pos = start(n);
918  }
919 
920  // case c: second element is before first
921 * else if ((n->F("end") < e->F("end")) &&
922  (start(n) < start(e)))
923  {
924  cout << "case A\n";
925  pos = (n->F("end") + start(e)) / 2.0;
926  }
927  else
928  cout << "No overlap conditions met\n";
929  // cout << "pos =" << pos << endl;
930 */
931 /* e->set("end", pos);
932  n->set("start", pos);
933  cout << endl << endl;
934  }
935  }
936 
937  // The overlap adjustments may cause the peak position to lie outside
938  // the start and end points. This checks for this and makes an
939  // arbitrary adjustment
940  for (e = ev.head(); next(e) != 0; e = e->next())
941  if ((e->f("rfc:type") == "RISEFALL") && (e->F("rfc:peak_pos") <
942  e->F("start")))
943  e->set("rfc:peak_pos",
944  (e->F("start") + e->F("end") / 2.0));
945 }
946 
947 static void conn_ends(EST_Track &fz, EST_Relation &ev, float min_length)
948 {
949  EST_Item *e, *n, *tmp;
950  float t, f0;
951  const float ARB_DISTANCE = 0.1;
952 
953  cout << min_length << endl;
954 
955  for (e = ev.head(); next(e) != 0; e = e->next())
956  {
957  n = e->next();
958  cout << *e << ":";
959  cout << "n: " << n->F("start") << " e "<< e->F("end") << endl;
960 
961  if ((n->F("start") - e->F("end")) > min_length)
962  {
963  cout << "making connection\n";
964  tmp = n->insert_before();
965  make_int_item(*tmp, "c", n->f("start"), e->f("start"),
966  e->f("rfc:end_f0"), 0.0, 0.0);
967 
968  e = e->next(); // advance after new connection
969  }
970  else
971  {
972  t = (n->F("start") + e->F("end")) /2.0;
973  n->set("start", t);
974  e->set("end", t);
975  }
976  }
977 
978  t = (ev.head())->f("start"); // store time of start of first event
979 
980  // insert silence at beginning if contour doesn't start at near time 0
981  // if (fz.start() > fz.shift())
982  // {
983  // tmp = make_int_item("sil", fz.start(), 0.0, 0.0, 0.0, 0.0);
984  // ev.prepend(tmp);
985  // }
986  // add connection between silence and first event
987 
988  tmp = ev.head()->insert_after();
989  make_int_item(*tmp, "c", t, 0.0, fz.a(fz.start()), 0.0, 0.0);
990 
991  if ((ev.tail()->F("end") + min_length) < fz.end())
992  {
993  f0 = fz.a(ev.tail()->F("end"));
994  // add connection after last event.
995  //ev.insert_after(ev.tail(), tmp);
996  tmp = ev.append();
997  make_int_item(*tmp, "c", fz.end(), 0.0, f0, 0.0, 0.0);
998  }
999 
1000  // add silence, an arbitrary distance after end - what a hack!
1001  // ev.insert_after(ev.tail(), tmp);
1002  tmp = ev.append();
1003  make_int_item(*tmp, "sil", fz.end() + ARB_DISTANCE,
1004  0.0, fz.a(fz.end()), 0.0, 0.0);
1005 }
1006 */
1007 
1008 
1009