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 :  Paul Taylor                            */
34 /*                      Date   :  August 1995                            */
35 /*-----------------------------------------------------------------------*/
36 /*                   EST_Track Auxiliary routines                        */
37 /*                                                                       */
38 /*=======================================================================*/
39 
40 #include <cmath>
41 #include <cstdlib>
42 #include "EST_cutils.h"
43 #include "EST_simplestats.h"
44 #include "EST_sort.h"
45 #include "EST_Track.h"
46 #include "EST_TrackFile.h"
47 #include "EST_Option.h"
48 #include "EST_track_aux.h"
49 #include "EST_error.h"
50 
51 //static inline int irint(float f) { return (int)(f+0.5); }
52 //static inline int irint(double f) { return (int)(f+0.5); }
53 //static inline int ifloor(float f) { return (int)(f); }
54 
55 float correlation(EST_Track &a, EST_Track &b, int cha, int chb);
56 
57 /* Allow EST_Track to be used in an EST_Val */
VAL_REGISTER_CLASS(track,EST_Track)58 VAL_REGISTER_CLASS(track,EST_Track)
59 
60 static int sorttest(const void *a, const void *b)
61 { // for use with qsort C library function.
62     float *c = (float *)a;
63     float *d = (float *)b;
64     float res = (*c - *d);
65     if (res == 0.0)
66 	return 0;
67     return (res < 0.0) ? -1 : 1;
68 }
69 
track_smooth(EST_Track & c,float x,EST_String stype)70 void track_smooth(EST_Track &c, float x, EST_String stype)
71 {
72     if (stype == "median")
73 	time_med_smooth(c, x);
74     else
75 	time_mean_smooth(c, x);
76 }
77 
time_med_smooth(EST_Track & c,float x)78 void time_med_smooth(EST_Track &c, float x)
79 {
80   if (!c.equal_space())
81     {
82 	cerr << "Error: Time smoothing can only operate on fixed contours\n";
83 	return;
84     }
85     // want to check for divide by zero
86     if (c.shift() == 0.0)
87     {
88 	cerr << "Error in smoothing: time spacing problem\n";
89 	return;
90     }
91     int n = (int)(x / c.shift());
92     for (int i = 0; i < c.num_channels(); ++i)
93 	simple_med_smooth(c, n, i);
94 }
95 
time_mean_smooth(EST_Track & c,float x)96 void time_mean_smooth(EST_Track &c, float x)
97 {
98     int j;
99     EST_Track t;
100     int n = (int)(x / c.shift());
101 
102     for (j = 0; j < c.num_channels(); ++j)
103 	simple_mean_smooth(c, n, j);
104 }
105 
simple_med_smooth(EST_Track & c,int n,int channel)106 void simple_med_smooth(EST_Track &c, int n, int channel)
107 {// simple median smoother of order n
108 
109 
110     // windows longer than twice the track length cause problems
111     // here is one solution
112     if(n > c.num_frames())
113 	n=c.num_frames();
114 
115     // and tiny windows don't work either
116     // can't do median of 2 of fewer points
117     if(n < 3)
118 	return;
119 
120     int i, j, h, k;
121     float *a = new float[c.num_frames()];
122     float *m = new float[n];
123     h = n/2;
124 
125 
126     // sort start using < n order smoothing
127     for (i = 0; i < h; ++i)
128     {
129 	k = (i * 2) + 1;
130 	for (j = 0; j < k; ++j)
131 	    m[j] = c.a(j, channel);
132 	qsort(m, k, sizeof(float), sorttest);
133 	a[i] = m[i];
134     }
135 
136     // sort main section using n order smoothing
137     for (i = h; i < c.num_frames() - h; ++i)
138     {
139 	for (j = 0; j < n; ++j)
140 	    m[j] = c.a(i - h + j, channel);
141 
142 	qsort(m, n, sizeof(float), sorttest);
143 	a[i] = m[h];
144     }
145     // sort end section using < n order smoothing
146     for (; i < c.num_frames(); ++i)
147     {
148 	k = ((c.num_frames() - i)* 2) -1;
149 	for (j = 0; j < k; ++j)
150 	    m[j] = c.a(i - (k/2) + j, channel);
151 	qsort(m, k, sizeof(float), sorttest);
152 	a[i] = m[k/2];
153     }
154 
155     for (i = 0; i < c.num_frames(); ++i)
156 	c.a(i,channel) = a[i];
157 
158     delete [] a;
159     delete [] m;
160 }
161 
simple_mean_smooth(EST_Track & c,int n,int channel)162 void simple_mean_smooth(EST_Track &c, int n, int channel)
163 { // simple mean smoother of order n
164     int i, j, h, k=1;
165     float *a = new float[c.num_frames()];
166     float sum;
167     h = n/2;
168 
169     for (i = 0; i < h; ++i)
170     {
171 	k = (i * 2) + 1;
172 	sum = 0.0;
173 	for (j = 0; j < k; ++j)
174 	    sum += c.a(j, channel);
175 	a[i] = sum /(float) k;
176     }
177 
178     k= h*2 + 1;
179 
180     for (i = h; i < c.num_frames() - h; ++i)
181     {
182 	sum = 0.0;
183 	for (j = 0; j < k; ++j)
184 	    sum += c.a(i - h + j, channel);
185 	a[i] = sum /(float) k;
186     }
187 
188     for (; i < c.num_frames(); ++i)
189     {
190 	k = ((c.num_frames() - i)* 2) -1;
191 	sum = 0.0;
192 	for (j = 0; j < k; ++j)
193 	    sum += c.a(i - (k/2) + j, channel);
194 	a[i] = sum /(float) k;
195     }
196 
197     for (i = 0; i < c.num_frames(); ++i)
198 	c.a(i,channel) = a[i];
199 
200     delete [] a;
201 }
202 
absolute(EST_Track & tr)203 void absolute(EST_Track &tr)
204 {
205     int i, j;
206     for (i = 0; i < tr.num_frames(); ++i)
207 	for (j = 0; j < tr.num_channels(); ++j)
208 	    tr.a(i, j) = fabs(tr.a(i, j));
209 }
210 
normalise(EST_Track & tr)211 void normalise(EST_Track &tr)
212 {
213     EST_FVector mean, sd;
214 
215     meansd(tr, mean, sd);
216     normalise(tr, mean, sd, -1.0, 1.0);
217 }
218 
219 /* Normalise a list of tracks */
normalise(EST_TrackList & trlist,EST_FVector & mean,EST_FVector & sd,float upper,float lower)220 void normalise(EST_TrackList &trlist, EST_FVector &mean, EST_FVector &sd,
221 	       float upper, float lower)
222 {
223     for (EST_Litem *p = trlist.head(); p; p = p->next())
224 	normalise(trlist(p), mean, sd, upper, lower);
225 }
226 
227 /* Normalise by subtracting the mean and dividing by TWICE the
228    standard deviation. */
normalise(EST_Track & tr,EST_FVector & mean,EST_FVector & sd,float upper,float lower)229 void normalise(EST_Track &tr, EST_FVector &mean, EST_FVector &sd,
230 	       float upper, float lower)
231 {
232     for (int i = 0; i < tr.num_channels(); ++i)
233 	normalise(tr, mean(i), sd(i), i, upper, lower);
234 }
235 
normalise(EST_Track & tr,float mean,float sd,int channel,float upper,float lower)236 void normalise(EST_Track &tr, float mean, float sd, int channel,
237 	       float upper, float lower)
238 {
239     // This scales the data so that 2 standard deviations worth of values
240     // lie between upper and lower.
241     int i;
242     // cout << "upper = " << upper << " lower " << lower << endl;
243     for (i = 0; i < tr.num_frames(); ++i)
244 	if (!tr.track_break(i))
245 	    tr.a(i, channel) = ((((tr.a(i, channel) - mean) / (4 *sd)) + 0.5)
246 				* (upper -lower))  + lower;
247 }
248 
differentiate(EST_Track & c,float samp_int)249 EST_Track differentiate(EST_Track &c, float samp_int)
250 {
251     // Differentiate track. SEE ALSO delta(EST_Track, int) which does
252     // this in a more sophisticated way!!!
253 
254     EST_Track diff;
255     int i, j;
256     float dist;
257 
258     if (samp_int != 0.0)
259 	c.sample(samp_int);
260 
261     diff.copy_setup(c);
262     diff.resize(c.num_frames() - 1, c.num_channels());
263 
264     for (i = 0; i < diff.num_frames(); ++i)
265     {
266 	dist = c.t(i + 1) - c.t(i);
267 	for (j = 0; j < diff.num_channels(); ++j)
268 	    diff.a(i, j) = (c.track_break(i) || c.track_break(i + 1)) ? 0.0
269 		: (c.a(i + 1) - c.a(i)) / dist;
270 	diff.t(i) = c.t(i) + (dist / 2.0);
271     }
272 
273     return diff;
274 }
275 
difference(EST_Track & a,EST_Track & b)276 EST_Track difference(EST_Track &a, EST_Track &b)
277 {
278     int i, j;
279 
280     int size = Lof(a.num_frames(), b.num_frames());
281     EST_Track diff = a;
282 
283     // ERROR REORG - this needs to return a proper error
284     if (a.num_channels() != b.num_channels())
285     {
286 	cerr << "Error: Can't compare " << a.num_channels() <<
287 	    " channel EST_Track with " << b.num_channels() << " channel EST_Track\n";
288 	return diff;
289     }
290 
291     for (i = 0; i < size; ++i)
292 	for (j = 0; j < a.num_channels(); ++j)
293 	    diff.a(i, j) = a.a(i, j) - b.a(i, j);
294 
295     return diff;
296 }
297 
difference(EST_Track & a,EST_Track & b,int channel_a,int channel_b)298 EST_Track difference(EST_Track &a, EST_Track &b, int channel_a, int channel_b)
299 {
300     int i;
301 
302     int size = Lof(a.num_frames(), b.num_frames());
303     EST_Track diff = a;
304 
305     for (i = 0; i < size; ++i)
306 	diff.a(i, channel_a) = a.a(i, channel_a) - b.a(i, channel_b);
307 
308     return diff;
309 }
310 
difference(EST_Track & a,EST_Track & b,EST_String fname)311 EST_Track difference(EST_Track &a, EST_Track &b, EST_String fname)
312 {
313     int ch_a, ch_b;
314     EST_Track cor;
315 
316     if (!a.has_channel(fname))
317     {
318 	cerr << "Error: Couldn't find field named " << fname <<
319 	    " in first Track\n";
320 	return cor;
321     }
322 
323     if (!b.has_channel(fname))
324     {
325 	cerr << "Error: Couldn't find field named " << fname <<
326 	    " in second Track\n";
327 	return cor;
328     }
329 
330     ch_a = a.channel_position(fname);
331     ch_b = b.channel_position(fname);
332 
333     return difference(a, b, ch_a, ch_b);
334 }
335 
336 
mean(const EST_Track & tr,int channel)337 float mean( const EST_Track &tr, int channel )
338 {
339   if ( channel<0 || channel >= tr.num_channels() )
340     EST_error( "Tried to access channel %d of %d channel track",
341 	       channel, tr.num_channels() );
342 
343   float mean=0.0;
344   int i, n;
345   int tr_num_frames = tr.num_frames();
346 
347   for( i=0, n=0; i<tr_num_frames; ++i )
348     if( !tr.track_break(i) ){
349       mean += tr.a_no_check( i, channel );
350       ++n;
351     }
352 
353   return mean/(float)n;
354 }
355 
mean(const EST_Track & tr,EST_FVector & m)356 void mean( const EST_Track &tr, EST_FVector &m )
357 {
358   unsigned int tr_num_channels = tr.num_channels();
359 
360   m.resize( tr_num_channels, 0 );
361 
362   for( unsigned int i=0; i<tr_num_channels; ++i )
363     m.a_no_check(i) = mean( tr, i );
364 }
365 
366 
367 /** Calculate the mead and standard deviation for a single channel of a track
368 */
369 
meansd(EST_Track & tr,float & m,float & sd,int channel)370 void meansd(EST_Track &tr, float &m, float &sd, int channel)
371 {
372   int i, n;
373 
374   m = mean( tr, channel );
375 
376   float var=0.0;
377   int tr_num_frames = tr.num_frames();
378   for( i=0, n=0; i<tr_num_frames; ++i)
379     if( !tr.track_break(i) ){
380       var += pow(tr.a_no_check(i, channel) - m, float(2.0));
381       ++n;
382     }
383 
384   if( n>1 ){ // use n, not tr_num_frames because of breaks
385     var /= (float) (n-1);
386     sd = sqrt(var);
387   }
388   else
389     sd = 0.0;
390 }
391 
392 /** Calculate the root mean square error between the same channel in
393 two tracks
394 @see abs_error, rms_error
395 */
rms_error(EST_Track & a,EST_Track & b,int channel)396 float rms_error(EST_Track &a, EST_Track &b, int channel)
397 {
398     int i;
399     int size = Lof(a.num_frames(), b.num_frames());
400     float sum = 0;
401 
402     for (i = 0; i < size; ++i)
403 	if (a.val(i) && b.val(i))
404 	  sum += pow((a.a(i, channel) - b.a(i, channel)), float(2.0));
405 
406     sum = sqrt(sum / size);
407     return sum;
408 }
409 
abs_error(EST_Track & a,EST_Track & b,int channel)410 float abs_error(EST_Track &a, EST_Track &b, int channel)
411 {
412     int i;
413     int size = Lof(a.num_frames(), b.num_frames());
414     float sum = 0;
415     for (i = 0; i < size; ++i)
416     {
417 	// cout << i << " " << a.a(i, channel) << " " << b.a(i, channel) << endl;
418 	if (a.val(i) && b.val(i))
419 	    sum += fabs(a.a(i, channel) - b.a(i, channel));
420     }
421     return sum / size;
422 }
423 
correlation(EST_Track & a,EST_Track & b,int channela,int channelb)424 float correlation(EST_Track &a, EST_Track &b, int channela, int channelb)
425 {
426     int i;
427     int size = Lof(a.num_frames(), b.num_frames());
428     float predict,real;
429     EST_SuffStats x,y,xx,yy,xy,se,e;
430     float cor,error;
431 
432     for (i = 0; i < size; ++i)
433 	if (a.val(i) && b.val(i))
434 	{
435 //	    cout << a.t(i) << " " << a.a(i, channela) << " " << b.a(i, channelb) << endl;
436 	    predict = b.a(i, channelb);
437 	    real = a.a(i, channela);
438 	    x += predict;
439 	    y += real;
440 	    error = predict-real;
441 	    se += error*error;
442 	    e += fabs(error);
443 	    xx += predict*predict;
444 	    yy += real*real;
445 	    xy += predict*real;
446 	}
447 
448     cor = (xy.mean() - (x.mean()*y.mean()))/
449         (sqrt(xx.mean()-(x.mean()*x.mean())) *
450 	 sqrt(yy.mean()-(y.mean()*y.mean())));
451 
452 //    cout << xy.mean()  << " " << x.mean() << " " << y.mean() << " "
453 //        << xx.mean() << " " << yy.mean() << endl;
454 
455     cout << "RMSE " << sqrt(se.mean()) << " Correlation is " << cor
456         << " Mean (abs) Error " << e.mean() << " (" << e.stddev() << ")"
457             << endl;
458     return cor;
459 }
460 
meansd(EST_Track & a,EST_FVector & m,EST_FVector & sd)461 void meansd(EST_Track &a, EST_FVector &m, EST_FVector &sd)
462 {
463     int i;
464 
465     m.resize(a.num_channels());
466     sd.resize(a.num_channels());
467 
468     for (i = 0; i < a.num_channels(); ++i)
469 	meansd(a, m[i], sd[i], i);
470 }
471 
meansd(EST_TrackList & tl,float & mean,float & sd,int channel)472 void meansd(EST_TrackList &tl, float &mean, float &sd, int channel)
473 {
474     EST_Litem *p;
475     float var=0.0;
476     int i, n;
477 
478     n = 0;
479     mean = 0.0;
480 
481     for (p = tl.head(); p; p = p->next())
482 	for (i = 0; i < tl(p).num_frames(); ++i)
483 	{
484 	    if (!tl(p).track_break(i))
485 	    {
486 		mean += tl(p).a(i, channel);
487 		++n;
488 	    }
489     }
490 
491     mean /= n;
492 
493     for (p = tl.head(); p; p = p->next())
494 	for (i = 0; i < tl(p).num_frames(); ++i)
495 	    if (!tl(p).track_break(i))
496 	      var +=  pow(tl(p).a(i, channel) - mean, float(2.0));
497 
498     var /= n;
499     sd = sqrt(var);
500 }
501 
meansd(EST_TrackList & tl,EST_FVector & m,EST_FVector & sd)502 void meansd(EST_TrackList &tl, EST_FVector &m, EST_FVector &sd)
503 {
504     int i;
505 
506     m.resize(tl.first().num_channels());
507     sd.resize(tl.first().num_channels());
508 
509     for (i = 0; i < tl.first().num_channels(); ++i)
510 	meansd(tl, m[i], sd[i], i);
511 }
512 
rms_error(EST_Track & a,EST_Track & b)513 EST_FVector rms_error(EST_Track &a, EST_Track &b)
514 {
515     int i;
516     EST_FVector e;
517 
518     // ERROR REORG - this needs to return a proper error
519     if (a.num_channels() != b.num_channels())
520     {
521 	cerr << "Error: Can't compare " << a.num_channels() <<
522 	    " channel EST_Track with " << b.num_channels() << " channel EST_Track\n";
523 	return e;
524     }
525     e.resize(a.num_channels());
526     for (i = 0; i < a.num_channels(); ++i)
527 	e[i] = rms_error(a, b, i);
528 
529     return e;
530 }
531 
abs_error(EST_Track & a,EST_Track & b)532 EST_FVector abs_error(EST_Track &a, EST_Track &b)
533 {
534     int i;
535     EST_FVector e;
536 
537     // ERROR REORG - this needs to return a proper error
538     if (a.num_channels() != b.num_channels())
539     {
540 	cerr << "Error: Can't compare " << a.num_channels() <<
541 	    " channel EST_Track with " << b.num_channels() << " channel EST_Track\n";
542 	return e;
543     }
544     e.resize(a.num_channels());
545     for (i = 0; i < a.num_channels(); ++i)
546 	e[i] = abs_error(a, b, i);
547 
548     return e;
549 }
550 
correlation(EST_Track & a,EST_Track & b)551 EST_FVector correlation(EST_Track &a, EST_Track &b)
552 {
553     int i;
554     EST_FVector cor;
555 
556     // ERROR REORG - this needs to return a proper error
557     if (a.num_channels() != b.num_channels())
558     {
559 	cerr << "Error: Can't compare " << a.num_channels() <<
560 	    " channel EST_Track with " << b.num_channels() << " channel EST_Track\n";
561 	return cor;
562     }
563     cor.resize(a.num_channels());
564     for (i = 0; i < a.num_channels(); ++i)
565 	cor[i] = correlation(a, b, i, i);
566 
567     return cor;
568 }
569 
correlation(EST_Track & a,EST_Track & b,EST_String fname)570 EST_FVector correlation(EST_Track &a, EST_Track &b, EST_String fname)
571 {
572     int ch_a, ch_b;
573     EST_FVector cor;
574 
575     if (!a.has_channel(fname))
576     {
577 	cerr << "Error: Couldn't find field named " << fname <<
578 	    " in first Track\n";
579 	return cor;
580     }
581 
582     if (!b.has_channel(fname))
583     {
584 	cerr << "Error: Couldn't find field named " << fname <<
585 	    " in second Track\n";
586 	return cor;
587     }
588 
589     ch_a = a.channel_position(fname);
590     ch_b = b.channel_position(fname);
591 
592     cor.resize(1);
593     cor[0] = correlation(a, b, ch_a, ch_b);
594 
595     return cor;
596 }
597 
error(EST_Track & ref,EST_Track & test,int relax)598 EST_Track error(EST_Track &ref, EST_Track &test, int relax)
599 {
600     int i, j, k, l;
601     EST_Track diff;
602     diff = ref;
603     float t;
604 
605     // relaxation allows an error to be ignored near boundaries. The
606     // degree of relation specifies how many frames can be ignored.
607 
608     float *r = new float[relax*3];
609 
610     for (l = 0; l < ref.num_channels(); ++l)
611 	for (i = 0; i < ref.num_frames(); ++i)
612 	{
613 	    t = 0;
614 	    for (k = 0, j = Gof((i - relax), 0); j < i + relax + 1; ++j, ++k)
615 	    {
616 		if (ref.a(i, l) > 0.5)
617 		    r[k] = ((j < test.num_frames()) && (test.a(j, l)> 0.6)) ?1
618 			: 0.5;
619 		else
620 		    r[k] = ((j < test.num_frames()) && (test.a(j, l)< 0.4)) ? -1
621 			: -0.5;
622 
623 		// fix for relaxation
624 		t = r[k];
625 	    }
626 //	    cout << "ref: " << ref.a(i, l) << " test:" << test.a(i, l) << " error:" << t << endl;
627 	    diff.a(i, l) = t;
628 	}
629 
630     delete [] r;
631     return diff;
632 }
633 
align_to_track(EST_Track & tr,float & start,float & end)634 void align_to_track(EST_Track &tr, float &start, float &end)
635 {
636   int is, ie;
637 
638   // cout << " in " << start << " " << end << "\n";
639 
640   is = tr.index(start);
641   ie = tr.index(end);
642 
643   // cout << " indexes " << is << " " << ie << "\n";
644 
645   start = tr.t(is);
646   end   = tr.t(ie);
647   // cout << " out " << start << " " << end << "\n";
648 }
649 
align_to_track(EST_Track & tr,int & start,int & end,int sample_rate)650 void align_to_track(EST_Track &tr, int &start, int &end, int sample_rate)
651 {
652     float start_t = start/(float)sample_rate;
653     float   end_t =   end/(float)sample_rate;
654 
655 
656     // cout << "align " << start_t << " " << end_t << " " << sample_rate << "\n";
657     align_to_track(tr, start_t, end_t);
658     // cout << " gives " << start_t << " " << end_t << "\n";
659 
660     start = (int)(start_t*sample_rate + 0.5);
661       end = (int)(  end_t*sample_rate + 0.5);
662 }
663 
move_to_frame_ends(EST_Track & tr,int & start,int & end,int sample_rate,float offset)664 void move_to_frame_ends(EST_Track &tr,
665 			int &start, int &end,
666 			int sample_rate,
667 			float offset)
668 {
669     float start_t = start/(float)sample_rate;
670     float   end_t =   end/(float)sample_rate;
671 
672     // cout << "move " << start_t << " " << end_t << " " << sample_rate << "\n";
673 
674     int is = tr.index(start_t-offset);
675     int ie = tr.index(end_t-offset);
676 
677     int start_s, start_c, start_e;
678     int end_s, end_c, end_e=0;
679 
680     if (tr.has_channel(channel_length))
681     {
682 	get_frame(tr, sample_rate, is, start_s, start_c, start_e);
683 	get_frame(tr, sample_rate, ie, end_s, end_c, end_e);
684     }
685     else
686     {
687 	start_s = (int)(tr.t(is) * sample_rate);
688 	end_s = (int)(tr.t(ie) * sample_rate);
689     }
690 
691     start = start_s + (int)(offset*sample_rate + 0.5);
692     end = end_e   + (int)(offset*sample_rate + 0.5);
693 }
694 
nearest_boundary(EST_Track & tr,float time,int sample_rate,float offset)695 int nearest_boundary(EST_Track &tr, float time, int sample_rate, float offset)
696 {
697     time -= offset;
698 
699     float distance = 10000;
700 
701     for (int i = 0; i < tr.num_frames(); ++i)
702     {
703 	float start, center, end;
704 
705 	get_frame(tr, sample_rate, i, start, center, end);
706 
707 	// printf("nb %f: %d distance %f start %f\n", time, i, distance, start);
708 
709 	if (fabs(start-time) > distance)
710 	    return i-1;
711 	distance = fabs(start-time);
712     }
713 
714     return  tr.num_frames();
715 }
716 
move_start(EST_Track & tr,float shift)717 void move_start(EST_Track &tr, float shift)
718 {
719     for(int i=0; i<tr.num_frames(); i++)
720 	tr.t(i) += shift;
721 }
722 
set_start(EST_Track & tr,float start)723 void set_start(EST_Track &tr, float start)
724 {
725     float shift = start - tr.t(0);
726 
727     move_start(tr, shift);
728 }
729 
730 
extract2(EST_Track & orig,float start,float end,EST_Track & ret)731 void extract2(EST_Track &orig, float start, float end, EST_Track &ret)
732 {
733     int from, to;
734     int i, j;
735     from = orig.index(start);
736     to = orig.index_below(end);
737 
738     ret.copy_setup(orig);
739 
740     ret.resize(to - from, orig.num_channels());
741 
742     for (i = 0; i < ret.num_frames(); ++i)
743 	for (j = 0; j < ret.num_channels(); ++j)
744 	{
745 	    ret.a(i, j) = orig.a(i + from, j);
746 	    ret.t(i) = orig.t(i + from);
747 	    if (orig.track_break(i + from))
748 		ret.set_break(i);
749 	    else
750 		ret.set_value(i);
751 	}
752 
753 
754     // cout << "from " << from << " to " << to << endl;
755     // cout << "times from " << orig.t(from) << " to " << orig.t(to) << endl;
756 
757     //    orig.sub_track(ret, from, to);
758     // cout << ret.num_frames() << " " << ret.start() << " " << ret.end() << endl;
759     // cout << "ret " << ret;
760 }
761 
762 
extract(EST_Track & orig,float start,float end,EST_Track & ret)763 void extract(EST_Track &orig, float start, float end, EST_Track &ret)
764 {
765     int new_num_frames;
766 
767     ret.copy_setup(orig);
768 
769     int i, j;
770     int is = 0, ie = 0;
771 
772     is = orig.index(start);
773     ie = orig.index(end);
774 
775     // check in case above results in negative length
776     new_num_frames = (ie - is) > 0 ?ie - is : 0;
777     ret.resize(new_num_frames, orig.num_channels());
778 
779     for (i = 0; i < new_num_frames; ++i)
780     {
781 	for (j = 0; j < orig.num_channels(); ++j)
782 	    ret.a(i, j) = orig.a(i + is, j);
783 	ret.t(i) = orig.t(i + is);
784 	if (orig.track_break(i + is))
785 	    ret.set_break(i);
786 	else
787 	    ret.set_value(i);
788     }
789 }
790 
get_order(const EST_Track & t,EST_CoefficientType type,int d)791 int get_order(const EST_Track &t, EST_CoefficientType type, int d)
792 {
793     int order;
794     EST_ChannelType start_c = (EST_ChannelType)EST_CoefChannelId(type, d, 0);
795     EST_ChannelType end_c = (EST_ChannelType)EST_CoefChannelId(type, d, 1);
796 
797     if (t.has_channel(start_c))
798 	if (t.has_channel(end_c))
799 	    order = t.channel_position(end_c) - t.channel_position(start_c);
800 	else
801 	    order = t.num_channels()-t.channel_position(start_c)-1;
802     else
803 	order=0;
804     return order;
805 }
806 
get_order(const EST_Track & tr)807 int get_order(const EST_Track &tr)
808 {
809     int order=0;
810     EST_CoefficientType t;
811 
812     for(t=cot_first; t <cot_free; t=(EST_CoefficientType)(t+1))
813 	if ((order=get_order(tr,t))>0)
814 	    return order;
815 
816     cout << "No coefficients in track\n";
817     return 0;
818 }
819 
sum_lengths(const EST_Track & t,int sample_rate,int start_frame,int end_frame)820 int sum_lengths(const EST_Track &t,
821 		int sample_rate,
822 		int start_frame, int end_frame)
823 {
824     (void)sample_rate;
825     int l=0;
826 
827     if (end_frame < 0)
828 	end_frame = t.num_frames();
829 
830     if (t.has_channel(channel_length))
831 	for(int i=start_frame; i<end_frame; i++)
832 	    l += (int)t.a(i, channel_length);
833     else
834     {
835 	cout << "no length channel";
836     }
837 
838     return l;
839 }
840 
get_start_positions(const EST_Track & t,int sample_rate,EST_TBuffer<int> & pos)841 void get_start_positions(const EST_Track &t, int sample_rate,
842 			 EST_TBuffer<int> &pos)
843 {
844     pos.ensure(t.num_frames());
845 
846     if (!t.has_channel(channel_length))
847     {
848 	cout << "no length channel\n";
849 	return;
850     }
851 
852     for(int i=0; i<t.num_frames(); i++)
853     {
854 	int wstart, wcent, wend;
855 	get_frame(t, sample_rate, i, wstart, wcent, wend);
856 	pos[i] = wstart;
857 	// cout << "frame " << i << " t " << t.t(i) << " sr " << sample_rate << " offset " << t.a(i,channel_offset) << " cent " << wcent << " pos " << wstart << "\n";
858     }
859 }
860 
861 
extract(EST_Track & tr,EST_Option & al)862 void extract(EST_Track &tr, EST_Option &al)
863 {
864     int from, to;
865     EST_Track sub_track;
866 
867     if (al.present("-start"))
868 	from = tr.index(al.fval("-start"));
869     else if (al.present("-from"))
870 	from = al.ival("-from");
871     else
872 	from = 0;
873 
874     if (al.present("-end"))
875 	to = tr.index(al.fval("-end"));
876     else if (al.present("-to"))
877 	to = al.ival("-to");
878     else
879 	to = tr.num_frames() - 1;
880 
881     tr.sub_track(sub_track, from, to-from+1, 0, EST_ALL);
882     EST_Track tr2 = sub_track;
883     tr = tr2;
884 }
885 
extract_channel(EST_Track & orig,EST_Track & nt,EST_IList & ch_list)886 void extract_channel(EST_Track &orig, EST_Track &nt, EST_IList &ch_list)
887 {
888     int new_ch, i, j, k;
889     EST_Litem *p;
890     new_ch = ch_list.length();
891 
892     nt.copy_setup(orig);
893     nt.resize(orig.num_frames(), new_ch);
894 
895     for (i = 0, p = ch_list.head(); p; p = p->next(), ++i)
896     {
897 	k = ch_list(p);
898 
899 	if (k >= orig.num_channels())
900 	    EST_error("Tried to extract channel number %d from track with "
901 		      "only %d channels\n",  k, orig.num_channels());
902 
903 	for (j = 0; j < orig.num_frames(); ++j)
904 	    nt.a(j, i) = orig.a(j, k);
905 	nt.set_channel_name(orig.channel_name(k), i);
906     }
907     for (j = 0; j < orig.num_frames(); ++j)
908 	nt.t(j) = orig.t(j);
909 }
910 
ParallelTracks(EST_Track & a,EST_TrackList & list,const EST_String & style)911 void ParallelTracks(EST_Track &a, EST_TrackList &list,const EST_String &style)
912 {
913     // Make multi channel track out of list of tracks. There are two
914     // "styles". "0" means take the size of the first track in the list,
915     // "1" means take the size of the longest as the number of frames in
916     // the created track.
917     EST_Litem *p, *longest;
918     int num_channels, num_frames;
919     int i, j, k, n;
920 
921     for (num_channels=0,p=list.head(); p; p=p->next())
922 	num_channels += list(p).num_channels();
923 
924     if (style == "first")
925     {
926 	num_frames = list.first().num_frames();
927 	longest = list.head();
928     }
929     else
930     {
931 	if (style != "longest")
932 	    cerr << "EST_Track: unknown combine style \"" << style <<
933 		"\" assuming longest" << endl;
934 	for (num_frames = 0, longest = p = list.head(); p; p = p->next())
935 	    if (num_frames < list(p).num_frames())
936 	    {
937 		num_frames = list(p).num_frames();
938 		longest = p;
939 	    }
940     }
941 
942     a.resize(num_frames, num_channels);
943     a.fill(0.0);
944 
945     for (k = 0, p = list.head(); p; p = p->next())
946     {
947 	n = Lof(num_frames, list(p).num_frames());
948 	for (j = 0; j < list(p).num_channels(); ++j, ++k)
949 	{
950 	    for (i = 0; i < n; ++i)
951 		a(i, k) = list(p).a(i, j);
952 	    a.set_channel_name(list(p).channel_name(j), k);
953 	}
954     }
955     // fill time with times from longest file.
956     for (i = 0; i < list(longest).num_frames(); ++i)
957 	a.t(i) = list(longest).t(i);
958 }
959 
channel_to_time(EST_Track & tr,int channel,float scale)960 void channel_to_time(EST_Track &tr, int channel, float scale)
961 {
962 
963     for(int i=0; i < tr.num_frames(); i++)
964     {
965 	tr.t(i) = tr.a(i,channel) * scale;
966     }
967     tr.set_equal_space(FALSE);
968 }
969 
channel_to_time(EST_Track & tr,EST_ChannelType c,float scale)970 void channel_to_time(EST_Track &tr, EST_ChannelType c, float scale)
971 {
972     int channel = NO_SUCH_CHANNEL;
973 
974     if (tr.map() != 0 && (channel = (tr.map()->get(c)) != NO_SUCH_CHANNEL))
975     {
976 	channel_to_time(tr, channel, scale);
977 	return;
978     }
979     else
980     {
981 	cerr << "no channel '" << EST_default_channel_names.name(c) << "' = " << (int)c << "\n";
982 	abort();
983     }
984 }
985 
channel_to_time(EST_Track & tr,const EST_String c_name,float scale)986 void channel_to_time(EST_Track &tr, const EST_String c_name, float scale)
987 {
988     for (int c=0; c<tr.num_channels(); c++)
989 	if (tr.channel_name(c) == c_name)
990 	{
991 	    channel_to_time(tr, c, scale);
992 	    return;
993 	}
994 
995     cerr << "no channel named '" << c_name << "'\n";
996     abort();
997 }
998 
channel_to_time_lengths(EST_Track & tr,int channel,float scale)999 void channel_to_time_lengths(EST_Track &tr, int channel, float scale)
1000 {
1001     float tt=0;
1002     for(int i=0; i < tr.num_frames(); i++)
1003     {
1004 	// cout << "c_t_t " << i << " " << tt << "\n";
1005 	tr.t(i) = tt;
1006 	tt += tr.a(i,channel) * scale;
1007     }
1008     tr.set_equal_space(FALSE);
1009 }
1010 
channel_to_time_lengths(EST_Track & tr,EST_ChannelType c,float scale)1011 void channel_to_time_lengths(EST_Track &tr, EST_ChannelType c, float scale)
1012 {
1013     int channel = NO_SUCH_CHANNEL;
1014 
1015     if (tr.map()!=0 && (channel = tr.map()->get(c)) != NO_SUCH_CHANNEL)
1016     {
1017 	channel_to_time_lengths(tr, channel, scale);
1018 	return;
1019     }
1020     else
1021     {
1022 	cerr << "no channel '" << EST_default_channel_names.name(c) << "' = " << (int)c << "\n";
1023 	abort();
1024     }
1025 }
1026 
channel_to_time_lengths(EST_Track & tr,const EST_String c_name,float scale)1027 void channel_to_time_lengths(EST_Track &tr, const EST_String c_name, float scale)
1028 {
1029     for (int c=0; c<tr.num_channels(); c++)
1030 	if (tr.channel_name(c) == c_name)
1031 	{
1032 	    channel_to_time_lengths(tr, c, scale);
1033 	    return;
1034 	}
1035 
1036     cerr << "no channel named '" << c_name << "'\n";
1037     abort();
1038 }
1039 
options_subtrack(void)1040 EST_String options_subtrack(void)
1041 {
1042     return
1043 	EST_String("")+
1044 	"-start <float>   Extract track starting at this time, \n"
1045 	"                 specified in seconds\n\n"
1046 	"-end   <float>   Extract track ending at this time, \n"
1047 	"                 specified in seconds\n\n"
1048 	"-from  <int>     Extract track starting at this frame position\n\n"
1049 	"-to    <int>     Extract track ending at this frame position\n\n";
1050 }
1051 
options_track_input(void)1052 EST_String options_track_input(void)
1053 {
1054     // The standard waveform input options
1055     return
1056 	EST_String("")+
1057 	"-itype <string>  Input file type (optional).  If no type is\n"
1058 	"                 specified type is automatically derived from\n"
1059 	"                 file's header. Supported types\n"
1060 	"                 are: "+options_track_filetypes()+"\n\n"
1061 // remove ???
1062 	"-ctype <string>  Contour type: F0, track\n\n"
1063 	"-s <float>       Frame spacing of input in seconds, for unheadered input file\n\n"
1064         "-startt <float>  Time of first frame, for formats which don't provide this\n\n"
1065 	"-c <string>      Select a subset of channels (starts from 0). \n"
1066 	"                 Tracks can have multiple channels. This option \n"
1067         "                 specifies a list of numbers, refering to the channel \n"
1068 	"                 numbers which are to be used for for processing. \n\n"+
1069 	options_subtrack();
1070 }
1071 
1072 
options_track_output(void)1073 EST_String options_track_output(void)
1074 {
1075     // The standard track output options
1076   return
1077 	EST_String("")+
1078 	"-otype <string> {ascii}\n"+
1079 	"    Output file type, if unspecified ascii is\n"+
1080         "    assumed, types are: "+options_track_filetypes()+", label\n\n"+
1081         "-S <float>       Frame spacing of output in seconds. If this is \n"
1082 	"    different from the internal spacing, the contour is \n"
1083 	"    resampled at this spacing \n\n"
1084 	"-o <ofile>       Output filename, defaults to stdout\n\n";
1085 }
1086 
track_info(EST_Track & t)1087 void track_info(EST_Track &t)
1088 {
1089     cout <<  t.name() << endl;
1090     cout << "Number of frames: " << t.num_frames() << endl;
1091     cout << "Number of channels: " << t.num_channels() << endl;
1092     cout << "File type: " << EST_TrackFile::map.name(t.file_type()) << endl;
1093     if (t.equal_space())
1094 	cout << "Frame shift: " << t.shift() << endl;
1095     else
1096 	cout << "Frame shift: varied" << endl;
1097     for (int i = 0; i < t.num_channels(); ++i)
1098 	cout << "Channel: " << i << ": " << t.channel_name(i) << endl;
1099 }
1100 
options_track_filetypes(void)1101 EST_String options_track_filetypes(void)
1102 {
1103     // Returns list of currently support track filetypes
1104     // Should be extracted from the list in EST_Track
1105 
1106     return EST_TrackFile::options_short();
1107 }
1108 
options_track_filetypes_long(void)1109 EST_String options_track_filetypes_long(void)
1110 {
1111     // Returns list of currently support track filetypes
1112     // Should be extracted from the list in EST_Track
1113 
1114     return EST_TrackFile::options_supported();
1115 }
1116 
1117