"Fossies" - the Fresh Open Source Software Archive

Member "speech_tools/intonation/tilt/tilt_analysis.cc" (4 Sep 2017, 27419 Bytes) of package /linux/misc/speech_tools-2.5.0-release.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "tilt_analysis.cc" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.4-release_vs_2.5.0-release.

    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 = inext(e);
  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 = inext(e))
  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 = inext(e))
  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 = inext(e);
  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 = inext(e);
  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(); inext(e); e = n)
  558     {
  559     n = inext(e);
  560     p = iprev(e);
  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 = inext(e);
  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 = inext(e))
  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(); inext(e); e = n)
  801     {
  802     n = inext(e);
  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 = inext(e))
  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 = inext(e))
  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 = inext(e);
  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(); inext(e) != 0; e = e->next())
  900     {
  901     n = inext(e);
  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(); inext(e) != 0; e = inext(e))
  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(); inext(e) != 0; e = inext(e))
  956     {
  957     n = inext(e);
  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 = inext(e);       // 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