Edinburgh Speech Tools  2.4-release
 All Classes Functions Variables Typedefs Enumerations Enumerator Friends Pages
EST_TrackFile.cc
1 /*************************************************************************/
2 /* */
3 /* Centre for Speech Technology Research */
4 /* University of Edinburgh, UK */
5 /* Copyright (c) 1995,1996 */
6 /* All Rights Reserved. */
7 /* */
8 /* Permission is hereby granted, free of charge, to use and distribute */
9 /* this software and its documentation without restriction, including */
10 /* without limitation the rights to use, copy, modify, merge, publish, */
11 /* distribute, sublicense, and/or sell copies of this work, and to */
12 /* permit persons to whom this work is furnished to do so, subject to */
13 /* the following conditions: */
14 /* 1. The code must retain the above copyright notice, this list of */
15 /* conditions and the following disclaimer. */
16 /* 2. Any modifications must be clearly marked as such. */
17 /* 3. Original authors' names are not deleted. */
18 /* 4. The authors' names are not used to endorse or promote products */
19 /* derived from this software without specific prior written */
20 /* permission. */
21 /* */
22 /* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */
23 /* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */
24 /* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */
25 /* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */
26 /* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */
27 /* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */
28 /* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */
29 /* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */
30 /* THIS SOFTWARE. */
31 /* */
32 /*************************************************************************/
33 /* Author : Paul Taylor */
34 /* Date : August 1995 */
35 /*-----------------------------------------------------------------------*/
36 /* File I/O functions for EST_Track class */
37 /* */
38 /*=======================================================================*/
39 #include <fstream>
40 #include <iostream>
41 #include <cstdlib>
42 #include <cmath>
43 #include <time.h>
44 #include "EST_unix.h"
45 #include "EST_types.h"
46 #include "EST_Track.h"
47 #include "EST_track_aux.h"
48 #include "EST_TrackMap.h"
49 #include "EST_cutils.h"
50 #include "EST_Token.h"
51 #include "EST_TList.h"
52 #include "EST_string_aux.h"
53 #include "EST_walloc.h"
54 #include "EST_TrackFile.h"
55 #include "EST_FileType.h"
56 #include "EST_WaveFile.h"
57 #include "EST_wave_utils.h"
58 
59 // size of locally allocated buffer. If more channels than this we have to
60 // call new
61 
62 #define NEARLY_ZERO 0.00001
63 
64 #define REASONABLE_FRAME_SIZE (20)
65 #define UNREASONABLE_FRAME_SIZE (80)
66 
67 #if 0
68 static const char *NIST_SIG = "NIST_1A\n 1024\n";
69 static const char *NIST_END_SIG = "end_head\n";
70 #define NIST_HDR_SIZE 1024
71 // default for tracks is the standard EMA sample rate
72 static int def_load_sample_rate = 500;
73 
74 #endif
75 
76 // some functions written for reading NIST headered waveform files,
77 // but useful here.
78 int nist_get_param_int(char *hdr, char *field, int def_val);
79 char *nist_get_param_str(char *hdr, char *field, char *def_val);
80 const char *sample_type_to_nist(enum EST_sample_type_t sample_type);
81 enum EST_sample_type_t nist_to_sample_type(char *type);
82 
83 EST_read_status read_est_header(EST_TokenStream &ts, EST_Features &hinfo,
84  bool &ascii, EST_EstFileType &t);
85 
86 EST_read_status EST_TrackFile::load_esps(const EST_String filename, EST_Track &tr, float ishift, float startt)
87 {
88  (void)ishift;
89  (void)startt;
90 
91  float **tt;
92  float fsize;
93  char **fields;
94  int num_points, num_fields, num_values;
95  int i,j;
96  EST_read_status r_val;
97  short fixed;
98  int first_channel=0;
99 
100  r_val = get_track_esps(filename, &fields, &tt, &fsize, &num_points,
101  &num_values, &fixed);
102  if (r_val == misc_read_error)
103  {
104  cerr << "Error reading ESPS file " << filename << endl;
105  return misc_read_error;
106  }
107  else if (r_val == wrong_format)
108  return wrong_format;
109 
110  num_fields = num_values;
111  if (!fixed)
112  {
113  --num_fields;
114  ++first_channel;
115  }
116 
117  tr.resize(num_points,num_fields);
118  tr.fill_time(fsize);
119 
120  for (i = 0; i < num_points; ++i)
121  {
122  for (j = 0; j < num_fields; ++j)
123  tr.a(i, j) = tt[i][j+first_channel];
124  tr.set_value(i);
125  if (!fixed)
126  tr.t(i) = tt[i][0];
127  }
128 
129  for (i = 0; i < num_fields; ++i)
130  tr.set_channel_name(fields[i+first_channel], i);
131 
132 
133  // REORG not sure what these should be -- awb
134  tr.set_single_break(false);
135  tr.set_equal_space(true);
136 
137  // get_track_esps allocs all the memory, we therefore need to release it
138  for (i = 0; i < num_values; ++i)
139  wfree(fields[i]);
140  wfree(fields);
141  for (i = 0; i < num_values; ++i)
142  wfree(tt[i]);
143  wfree(tt);
144 
145  tr.set_file_type(tff_esps);
146  tr.set_name(filename);
147 
148  if (tr.channel_name(0) == "F0")
149  espsf0_to_track(tr);
150 
151  return format_ok;
152 }
153 
154 EST_read_status EST_TrackFile::load_ascii(const EST_String filename, EST_Track &tr, float ishift, float startt)
155 {
156  (void)startt;
157 
158  EST_TokenStream ts, tt;
159  EST_StrList sl;
160 
161  int i, j, n_rows, n_cols=0;
162  EST_String t;
163  EST_Litem *p;
164 
165  if (((filename == "-") ? ts.open(cin) : ts.open(filename)) != 0)
166  {
167  cerr << "Can't open track file " << filename << endl;
168  return misc_read_error;
169  }
170  // set up the character constant values for this stream
171  ts.set_SingleCharSymbols(";");
172 
173  if (ishift < NEARLY_ZERO)
174  {
175  cerr<<
176  "Error: Frame spacing must be specified (or apparent frame shift nearly zero)\n";
177  return misc_read_error;
178  }
179 
180  // first read in as list
181 
182  for (n_rows = 0; !ts.eof(); ++n_rows)
183  sl.append(ts.get_upto_eoln().string());
184 
185  if (n_rows > 0)
186  {
187  tt.open_string(sl.first());
188  for (n_cols = 0; !tt.eof(); ++n_cols)
189  tt.get().string();
190  }
191 
192  // resize track and copy values in
193  tr.resize(n_rows, n_cols);
194 
195  for (p = sl.head(), i = 0; p != 0; ++i, p = p->next())
196  {
197  bool ok;
198  tt.open_string(sl(p));
199  for (j = 0; !tt.eof(); ++j)
200  tr.a(i, j) = tt.get().Float(ok);
201  if (j != n_cols)
202  {
203  cerr << "Wrong number of points in row " << i << endl;
204  cerr << "Expected " << n_cols << " got " << j << endl;
205  return misc_read_error;
206  }
207  }
208 
209  tr.fill_time(ishift);
210  tr.set_single_break(FALSE);
211  tr.set_equal_space(TRUE);
212  tr.set_file_type(tff_ascii);
213  tr.set_name(filename);
214 
215  return format_ok;
216 }
217 
218 EST_read_status EST_TrackFile::load_xgraph(const EST_String filename, EST_Track &tr, float ishift, float startt)
219 {
220  (void)ishift;
221  (void)startt;
222 
223  EST_TokenStream ts, tt;
224  EST_StrList sl;
225  // const float NEARLY_ZERO = 0.001;
226  int i, j, n_rows, n_cols;
227  EST_String t;
228  EST_Litem *p;
229 
230  if (((filename == "-") ? ts.open(cin) : ts.open(filename)) != 0)
231  {
232  cerr << "Can't open track file " << filename << endl;
233  return misc_read_error;
234  }
235  // set up the character constant values for this stream
236  ts.set_SingleCharSymbols(";");
237 
238  // first read in as list
239 
240  for (n_rows = 0; !ts.eof(); ++n_rows)
241  sl.append(ts.get_upto_eoln().string());
242 
243  tt.open_string(sl.first());
244  for (n_cols = 0; !tt.eof(); ++n_cols)
245  tt.get().string();
246 
247  --n_cols; // first column is time marks
248 
249  // resize track and copy values in
250  tr.resize(n_rows, n_cols);
251 
252  for (p = sl.head(), i = 0; p != 0; ++i, p = p->next())
253  {
254  bool ok;
255  tt.open_string(sl(p));
256  tr.t(i) = tt.get().Float(ok);
257  for (j = 0; !tt.eof(); ++j)
258  tr.a(i, j) = tt.get().Float(ok);
259  if (j != n_cols)
260  {
261  cerr << "Wrong number of points in row " << i << endl;
262  cerr << "Expected " << n_cols << " got " << j << endl;
263  return misc_read_error;
264  }
265  }
266 
267  tr.set_single_break(FALSE);
268  tr.set_equal_space(TRUE);
269  tr.set_file_type(tff_xgraph);
270  tr.set_name(filename);
271 
272  return format_ok;
273 }
274 
275 EST_read_status EST_TrackFile::load_xmg(const EST_String filename, EST_Track &tr, float ishift, float startt)
276 {
277  (void)ishift;
278  (void)startt;
279 
280  EST_TokenStream ts;
281  EST_StrList sl;
282  int i, n, sr;
283  EST_String t, k, v;
284  EST_Litem *p;
285 
286  if (((filename == "-") ? ts.open(cin) : ts.open(filename)) != 0)
287  {
288  cerr << "Can't open track file " << filename << endl;
289  return misc_read_error;
290  }
291  // set up the character constant values for this stream
292  ts.set_SingleCharSymbols(";");
293 
294  if (ts.peek().string() != "XAO1")
295  return wrong_format;
296 
297  ts.get().string();
298 
299  while ((!ts.eof()) && (ts.peek().string() != "\014"))
300  {
301  k = ts.get().string();
302  v = ts.get().string();
303  if (k == "Freq")
304  sr = v.Int() * 1000;
305  else if (k == "YMin")
306  /* tr.amin = atof(v) */;
307  else if (k == "YMax")
308  /*tr.amax = atof(v) */;
309  }
310 
311  if (ts.eof())
312  {
313  cerr << "Unexpected end of file in reading xmg header\n";
314  return misc_read_error;
315  }
316  ts.get().string(); // read control L
317  ts.get_upto_eoln().string(); // read until end of header
318 
319  // read in lines to a list
320  for (n = 0; !ts.eof(); ++n)
321  sl.append(ts.get_upto_eoln().string());
322 
323  // note the track size is total number of points *and* breaks
324  tr.resize(n, 1 ); // REORG - fix this for multi channel work
325 
326  for (p = sl.head(), i = 0; p != 0; ++i, p = p->next())
327  {
328  bool ok;
329  ts.open_string(sl(p));
330  if (ts.peek().string() != "=")
331  {
332  tr.t(i) = ts.get().Float(ok) / 1000.0;
333  tr.a(i) = ts.get().Float(ok);
334  }
335  else
336  {
337  ts.get().string();
338  tr.set_break(i);
339  }
340  }
341 
342  tr.set_single_break(TRUE);
343  tr.set_equal_space(FALSE);
344  tr.set_file_type(tff_xmg);
345  tr.set_name(filename);
346 
347  return format_ok;
348 }
349 
350 EST_read_status EST_TrackFile::load_est(const EST_String filename,
351  EST_Track &tr, float ishift, float startt)
352 {
353  EST_TokenStream ts;
354  EST_read_status r;
355 
356  if (((filename == "-") ? ts.open(cin) : ts.open(filename)) != 0)
357  {
358  cerr << "Can't open track file " << filename << endl;
359  return misc_read_error;
360  }
361  // set up the character constant values for this stream
362  ts.set_SingleCharSymbols(";");
363  tr.set_name(filename);
364  r = load_est_ts(ts, tr, ishift, startt);
365 
366  if ((r == format_ok) && (!ts.eof()))
367  {
368  cerr << "Not end of file, but expected it\n";
369  return misc_read_error;
370  }
371  else
372  return r;
373 }
374 
375 static float get_float(EST_TokenStream &ts,int swap)
376 {
377  float f;
378  ts.fread(&f,4,1);
379  if (swap) swapfloat(&f);
380  return f;
381 }
382 
383 EST_read_status EST_TrackFile::load_est_ts(EST_TokenStream &ts,
384  EST_Track &tr, float ishift, float startt)
385 {
386  (void)ishift;
387  (void)startt;
388  int i, j;
389  int num_frames, num_channels, num_aux_channels;
390  EST_Features hinfo;
391  EST_EstFileType t;
392  EST_String v;
393  bool ascii;
394  bool breaks;
395  bool eq_space;
396  EST_read_status r;
397  int swap;
398 
399  if ((r = read_est_header(ts, hinfo, ascii, t)) != format_ok)
400  return r;
401  if (t != est_file_track)
402  return misc_read_error;
403 
404  breaks = hinfo.present("BreaksPresent") ? true : false;
405  eq_space = false;
406  if ((hinfo.present("EqualSpace")) &&
407  ((hinfo.S("EqualSpace") == "true") ||
408  (hinfo.S("EqualSpace") == "1")))
409  eq_space = true;
410 
411  num_frames = hinfo.I("NumFrames");
412  num_channels = hinfo.I("NumChannels");
413  num_aux_channels = hinfo.I("NumAuxChannels", 0);
414  tr.resize(num_frames, num_channels);
415 
416  hinfo.remove("NumFrames");
417  hinfo.remove("EqualSpace");
418  hinfo.remove("NumChannels");
419  hinfo.remove("BreaksPresent");
420  hinfo.remove("DataType");
421  if (hinfo.present("NumAuxChannels"))
422  hinfo.remove("NumAuxChannels");
423 
424  EST_String strn, cname;
425 
427  EST_StrList ch_map;
428 
429  for (p.begin(hinfo); p;)
430  {
431  c = p++;
432 
433  if (c->k.contains("Aux_Channel_"))
434  {
435  ch_map.append(c->v.String());
436  hinfo.remove(c->k);
437  }
438  else if (c->k.contains("Channel_"))
439  {
440  tr.set_channel_name(c->v.String(),
441  c->k.after("Channel_").Int());
442  hinfo.remove(c->k);
443  }
444  }
445 
446  tr.resize_aux(ch_map);
447 
448 // tr.create_map();
449 
450 // if (((hinfo.S("ByteOrder", "") == "01") ? bo_little : bo_big)
451 
452  if (!hinfo.present("ByteOrder"))
453  swap = FALSE; // ascii or not there for some reason
454  else if (((hinfo.S("ByteOrder") == "01") ? bo_little : bo_big)
455  != EST_NATIVE_BO)
456  swap = TRUE;
457  else
458  swap = FALSE;
459 
460  const int BINARY_CHANNEL_BUFFER_SIZE=1024;
461  float *frame=0;
462  float frame_buffer[BINARY_CHANNEL_BUFFER_SIZE];
463  if( !ascii )
464  {
465  if( num_channels > BINARY_CHANNEL_BUFFER_SIZE )
466  frame = new float[num_channels];
467  else
468  frame = frame_buffer;
469  }
470 
471  // there are too many ifs here
472  for (i = 0; i < num_frames; ++i)
473  {
474  bool ok;
475 
476  // Read Times
477  if (ascii)
478  {
479  if (ts.eof())
480  {
481  cerr << "unexpected end of file when looking for " << num_frames-i << " more frame(s)" << endl;
482  return misc_read_error;
483  }
484  tr.t(i) = ts.get().Float(ok);
485  if (!ok)
486  return misc_read_error;
487  }
488  else
489  tr.t(i) = get_float(ts,swap);
490 
491  // Read Breaks
492  if (breaks)
493  {
494  if (ascii)
495  {
496  v = ts.get().string();
497  if (v == "0")
498  tr.set_break(i);
499  else
500  tr.set_value(i);
501  }
502  else
503  {
504  if (get_float(ts,swap) == 0.0)
505  tr.set_break(i);
506  else
507  tr.set_value(i);
508  }
509  }
510  else
511  tr.set_value(i);
512 
513  // Read Channels
514 // for (j = 0; j < num_channels; ++j)
515 // {
516 // if(ascii)
517 // {
518 // tr.a(i, j) = ts.get().Float(ok);
519 // if (!ok)
520 // return misc_read_error;
521 // }
522 // else
523 // tr.a(i,j) = get_float(ts,swap);
524 // }
525 
526  if( ascii ){
527  for (j = 0; j < num_channels; ++j){
528  tr.a(i, j) = ts.get().Float(ok);
529  if (!ok)
530  return misc_read_error;
531  }
532  }
533  else{
534  ts.fread( frame, sizeof(float), num_channels );
535  if( swap )
536  for( j=0; j<num_channels; ++j ){
537  swapfloat( &frame[j] );
538  tr.a(i,j) = frame[j];
539  }
540  else
541  for( j=0; j<num_channels; ++j )
542  tr.a(i,j) = frame[j];
543  }
544 
545 
546  // Read aux Channels
547  for (j = 0; j < tr.num_aux_channels(); ++j)
548  {
549  if (ascii)
550  {
551  tr.aux(i, j) = ts.get().string();
552  if (!ok)
553  return misc_read_error;
554  }
555  else
556  {
557  cerr << "Warning: Aux Channel reading not yet implemented";
558  cerr << "for binary tracks\n";
559  }
560  }
561  }
562 
563  if( !ascii )
564  if( frame != frame_buffer )
565  delete [] frame;
566 
567  // copy header info into track
568  tr.f_set(hinfo);
569 
570  tr.set_single_break(FALSE);
571  tr.set_equal_space(eq_space);
572 
573  if(ascii)
574  tr.set_file_type(tff_est_ascii);
575  else
576  tr.set_file_type(tff_est_binary);
577 
578  return format_ok;
579 }
580 
581 EST_read_status load_snns_res(const EST_String filename, EST_Track &tr,
582  float ishift, float startt)
583 {
584  (void)startt;
585 
586  EST_TokenStream ts, str;
587  EST_StrList sl;
588  int i, j;
589  EST_String t, k, v;
590 
591  if (ishift < NEARLY_ZERO)
592  {
593  cerr<<
594  "Error: Frame spacing must be specified (or apparent frame shift nearly zero)\n";
595  return misc_read_error;
596  }
597 
598  if (((filename == "-") ? ts.open(cin) : ts.open(filename)) != 0)
599  {
600  cerr << "Can't open track file " << filename << endl;
601  return misc_read_error;
602  }
603 
604  if (ts.get().string() != "SNNS")
605  return wrong_format;
606  if (ts.get().string() != "result")
607  return wrong_format;
608 
609  ts.get_upto_eoln(); // SNNS bit
610  ts.get_upto_eoln(); // Time info
611 
612  int num_frames=0, num_channels=0;
613  int teaching = 0;
614 
615  while (1)
616  {
617  t = (EST_String)ts.get_upto_eoln();
618  // cout << "t=" << t << endl;
619  if (t.contains("teaching output included"))
620  teaching = 1;
621  if (!t.contains(":"))
622  break;
623  str.open_string(t);
624  k = (EST_String)str.get_upto(":");
625  v = (EST_String)str.get_upto_eoln();
626  if (k == "No. of output units")
627  num_channels = v.Int();
628  if (k == "No. of patterns")
629  num_frames = v.Int();
630 
631  // cout << "key " << k << endl;
632  // cout << "val " << v << endl;
633  }
634 
635  // cout << "num_frames = " << num_frames << endl;
636  // cout << "num_channels = " << num_channels << endl;
637  tr.resize(num_frames, num_channels);
638  // cout << "peek" << ts.peek().string() << endl;
639  // cout << "teaching " << teaching << endl;
640 
641  for (i = 0; (!ts.eof()) && (i < num_frames);)
642  // for (i = 0; i < 10; ++i)
643  {
644  if (ts.peek().string().contains("#")) // comment
645  {
646  ts.get_upto_eoln();
647  continue;
648  }
649  if (teaching) // get rid of teaching patterns
650  for (j = 0; j < num_channels; ++j)
651  ts.get().string();
652 
653  // cout << "i = " << i << " t = " << ts.peek().string() << endl;
654 
655  bool ok;
656 
657  for (j = 0; j < num_channels; ++j)
658  tr.a(i, j) = ts.get().Float(ok);
659 
660  ++i;
661  }
662 
663  tr.fill_time(ishift);
664  tr.set_single_break(FALSE);
665  tr.set_equal_space(TRUE);
666  tr.set_file_type(tff_snns);
667  tr.set_name(filename);
668 
669  return format_ok;
670 }
671 
672 EST_write_status EST_TrackFile::save_esps(const EST_String filename, EST_Track tr)
673 {
674  EST_write_status rc;
675  int i, j;
676  float shift;
677  bool include_time;
678  int extra_channels=0;
679 
680  EST_Track &track_tosave = tr;
681 
682  if (filename == "-")
683  {
684  cerr << "Output to stdout not available for ESPS file types:";
685  cerr << "no output written\n";
686  return write_fail;
687  }
688 
689  if ((include_time = (track_tosave.equal_space() != TRUE)))
690  {
691  shift = EST_Track::default_frame_shift;
692  extra_channels++;
693  }
694  else
695  shift = track_tosave.shift();
696 
697  track_tosave.change_type(0.0,FALSE);
698 
699  float **a = new float*[track_tosave.num_frames()];
700  // pity we need to copy it
701  for (i=0; i < track_tosave.num_frames(); i++)
702  {
703  a[i] = new float[track_tosave.num_channels() + extra_channels];
704 
705  if (include_time)
706  a[i][0] = track_tosave.t(i);
707 
708  for (j=0; j < track_tosave.num_channels(); j++)
709  a[i][j + extra_channels] = track_tosave.a(i,j);
710  }
711 
712  char **f_names = new char*[track_tosave.num_channels() + extra_channels];
713  for (i=0; i < track_tosave.num_channels(); i++)
714  {
715  // cout << "field " << i << "is '" << track_tosave.field_name(i) << "'\n";
716  f_names[i + extra_channels] = wstrdup(track_tosave.channel_name(i, esps_channel_names, 0));
717  }
718 
719  if (include_time)
720  f_names[0] = wstrdup("EST_TIME");
721 
722  rc = put_track_esps(filename, f_names,
723  a, shift, 1.0/shift,
724  track_tosave.num_channels() + extra_channels,
725  track_tosave.num_frames(),
726  !include_time);
727 
728  for (i=0; i < track_tosave.num_frames(); i ++)
729  delete [] a[i];
730  delete [] a;
731  for (i=0; i < track_tosave.num_channels()+extra_channels; i++)
732  delete [] f_names[i];
733  delete [] f_names;
734 
735  return rc;
736 }
737 
738 EST_write_status EST_TrackFile::save_est_ts(FILE *fp, EST_Track tr)
739 {
740  int i, j;
741 
742  fprintf(fp, "EST_File Track\n"); // EST header identifier.
743  fprintf(fp, "DataType ascii\n");
744  fprintf(fp, "NumFrames %d\n", tr.num_frames());
745  fprintf(fp, "NumChannels %d\n", tr.num_channels());
746  fprintf(fp, "NumAuxChannels %d\n", tr.num_aux_channels());
747  fprintf(fp, "EqualSpace %d\n",tr.equal_space());
748 
749  fprintf(fp, "BreaksPresent true\n");
750  for (i = 0; i < tr.num_channels(); ++i)
751  fprintf(fp, "Channel_%d %s\n", i, (const char *)(tr.channel_name(i)));
752 
753  for (i = 0; i < tr.num_aux_channels(); ++i)
754  fprintf(fp, "Aux_Channel_%d %s\n", i,
755  (const char *)(tr.aux_channel_name(i)));
756 
758 
759  for (p.begin(tr); p; ++p)
760  fprintf(fp, "%s %s\n", (const char *)p->k,
761  (const char *) p->v.String());
762 
763  fprintf(fp, "EST_Header_End\n");
764 
765  for (i = 0; i < tr.num_frames(); ++i)
766  {
767  fprintf(fp, "%f\t", tr.t(i));
768  fprintf(fp, "%s\t", (char *)(tr.val(i) ? "1 " : "0 "));
769  for (j = 0; j < tr.num_channels(); ++j)
770  fprintf(fp, "%f ", tr.a_no_check(i, j));
771  for (j = 0; j < tr.num_aux_channels(); ++j)
772  fprintf(fp, "%s ", (const char *)tr.aux(i, j).string());
773  fprintf(fp, "\n");
774  }
775  return write_ok;
776 }
777 
778 EST_write_status EST_TrackFile::save_est_ascii(const EST_String filename,
779  EST_Track tr)
780 {
781  FILE *fd;
782  EST_write_status r;
783 
784  if (filename == "-")
785  fd = stdout;
786  else if ((fd = fopen(filename,"wb")) == NULL)
787  return write_fail;
788 
789  r = save_est_ts(fd,tr);
790 
791  if (fd != stdout)
792  fclose(fd);
793  return r;
794 }
795 
796 EST_write_status EST_TrackFile::save_est_binary(const EST_String filename, EST_Track tr)
797 {
798  FILE *fd;
799  EST_write_status r;
800 
801  if (filename == "-")
802  fd = stdout;
803  else if ((fd = fopen(filename,"wb")) == NULL)
804  return write_fail;
805 
806  r = save_est_binary_ts(fd,tr);
807 
808  if (fd != stdout)
809  fclose(fd);
810  return r;
811 
812 }
813 
814 EST_write_status EST_TrackFile::save_est_binary_ts(FILE *fp, EST_Track tr)
815 {
816  int i,j;
817 
818  // This should be made optional
819  bool breaks = TRUE;
820 
821  fprintf(fp, "EST_File Track\n");
822  fprintf(fp, "DataType binary\n");
823  fprintf(fp, "ByteOrder %s\n", ((EST_NATIVE_BO == bo_big) ? "10" : "01"));
824  fprintf(fp, "NumFrames %d\n", tr.num_frames());
825  fprintf(fp, "NumChannels %d\n",tr.num_channels());
826  fprintf(fp, "EqualSpace %d\n",tr.equal_space());
827  if(breaks)
828  fprintf(fp, "BreaksPresent true\n");
829  fprintf(fp, "CommentChar ;\n\n");
830  for (i = 0; i < tr.num_channels(); ++i)
831  fprintf(fp, "Channel_%d %s\n",i,tr.channel_name(i).str());
832  fprintf(fp, "EST_Header_End\n");
833 
834  for (i = 0; i < tr.num_frames(); ++i)
835  {
836  // time
837  if((int)fwrite(&tr.t(i),4,1,fp) != 1)
838  return misc_write_error;
839 
840  // break marker
841  if (breaks)
842  {
843  float bm = (tr.val(i) ? 1 : 0);
844  if((int)fwrite(&bm,4,1,fp) != 1)
845  return misc_write_error;
846  }
847  // data - restricted to floats at this time
848  for (j = 0; j < tr.num_channels(); ++j)
849  if((int)fwrite(&tr.a_no_check(i, j),4,1,fp) != 1)
850  return misc_write_error;
851 
852  }
853  return write_ok;
854 }
855 
856 EST_write_status EST_TrackFile::save_ascii(const EST_String filename, EST_Track tr)
857 {
858 
859  if (tr.equal_space() == TRUE)
860  tr.change_type(0.0, FALSE);
861 
862  ostream *outf;
863  if (filename == "-")
864  outf = &cout;
865  else
866  outf = new ofstream(filename);
867 
868  if (!(*outf))
869  return write_fail;
870 
871  outf->precision(5);
872  outf->setf(ios::fixed, ios::floatfield);
873  outf->width(8);
874 
875  for (int i = 0; i < tr.num_frames(); ++i)
876  {
877  for (int j = 0; j < tr.num_channels(); ++j)
878  *outf << tr.a(i, j) << " ";
879  *outf << endl;
880  }
881 
882  if (outf != &cout)
883  delete outf;
884 
885  return write_ok;
886 }
887 
888 EST_write_status EST_TrackFile::save_xgraph(const EST_String filename, EST_Track tr)
889 {
890 
891  ostream *outf;
892 
893  if (filename == "-")
894  outf = &cout;
895  else
896  outf = new ofstream(filename);
897 
898  if (!(*outf))
899  return write_fail;
900 
901  tr.change_type(0.0, TRUE);
902 
903  for (int j = 0; j < tr.num_channels(); ++j)
904  {
905  *outf << "\""<< tr.channel_name(j) << "\"\n";
906  for (int i = 0; i < tr.num_frames(); ++i)
907  if (tr.val(i))
908  *outf << tr.t(i) << "\t" << tr.a(i, j) << endl;
909  else
910  *outf << "move ";
911  }
912  if (outf != &cout)
913  delete outf;
914 
915  return write_ok;
916 }
917 
918 EST_write_status save_snns_pat(const EST_String filename,
919  EST_TrackList &inpat, EST_TrackList &outpat)
920 {
921  ostream *outf;
922  int num_inputs, num_outputs, num_pats, i;
923  EST_Litem *pi, *po;
924 
925  if (filename == "-")
926  outf = &cout;
927  else
928  outf = new ofstream(filename);
929 
930  if (!(*outf))
931  return write_fail;
932 
933  num_pats = 0;
934  for (pi = inpat.head(); pi ; pi = pi->next())
935  num_pats += inpat(pi).num_frames();
936 
937  *outf << "SNNS pattern definition file V3.2\n";
938 
939  time_t thetime = time(0);
940  char *date = ctime(&thetime);
941 
942  *outf << date;
943  *outf << endl;
944 
945  num_inputs = inpat.first().num_channels();
946  num_outputs = outpat.first().num_channels();
947 
948  *outf << "No. of patterns : " << num_pats << endl;
949  *outf << "No. of input units : "<< num_inputs << endl;
950  *outf << "No. of output units : "<< num_outputs << endl;
951  *outf << endl << endl;
952 
953  for (pi = inpat.head(), po = outpat.head(); pi ;
954  pi = pi->next(), po = po->next())
955  {
956  if (inpat(pi).num_frames() != outpat(pi).num_frames())
957  {
958  cerr << "Error: Input pattern has " << inpat(pi).num_frames()
959  << " output pattern has " << outpat(pi).num_frames() << endl;
960  if (outf != &cout)
961  delete outf;
962  return misc_write_error;
963  }
964  for (i = 0; i < inpat(pi).num_frames(); ++i)
965  {
966  int j;
967  *outf << "#Input pattern " << (i + 1) << ":\n";
968  for (j = 0; j < inpat(pi).num_channels(); ++j)
969  *outf << inpat(pi).a(i, j) << " ";
970  *outf << endl;
971  *outf << "#Output pattern " << (i + 1) << ":\n";
972  for (j = 0; j < outpat(po).num_channels(); ++j)
973  *outf << outpat(po).a(i, j) << " ";
974  *outf << endl;
975  }
976  }
977  if (outf != &cout)
978  delete outf;
979 
980  return write_ok;
981 }
982 
983 /*
984  EST_write_status EST_TrackFile::save_snns_pat(const EST_String filename,
985  EST_TrackList &trlist)
986  {
987  ostream *outf;
988  int num_inputs, num_outputs, i;
989  EST_Litem *p;
990 
991  if (filename == "-")
992  outf = &cout;
993  else
994  outf = new ofstream(filename);
995 
996  if (!(*outf))
997  return write_fail;
998 
999  *outf << "SNNS pattern definition file V3.2\n";
1000 
1001  char *date;
1002  date = ctime(clock());
1003 
1004  *cout << date << endl;
1005 
1006  *cout << endl << endl;
1007 
1008  num_inputs = tr.first.num_channels();
1009  num_outputs = tr.first.num_channels();
1010 
1011  *cout << "No. of patterns : " << tr.size() << endl;
1012  *cout << "No. of input units : "<< num_inputs << endl;
1013  *cout << "No. of output units : "<< num_outputs << endl;
1014 
1015  for (i = 0, p = trlist.head(); p ; p = p->next(), ++i)
1016  {
1017  *outf << "#Input pattern " << i << ":\n";
1018  for (int j = 0; j < num_inputs; ++j)
1019  *outf << << trlist(p)._name(j) << "\"\n";
1020  for (int i = 0; i < tr.num_frames(); ++i)
1021  if (tr.val(i))
1022  *outf << tr.t(i) << "\t" << tr.a(i, j) << endl;
1023  else
1024  *outf << "move ";
1025  }
1026  if (outf != &cout)
1027  delete outf;
1028 
1029  return write_ok;
1030  }
1031  */
1032 
1033 EST_write_status EST_TrackFile::save_xmg(const EST_String filename, EST_Track tr)
1034 {
1035  ostream *outf;
1036  int i, j;
1037  // float min, max;
1038  int sr = 16000; // REORG - fixed sample rate until xmg is fixed
1039 
1040  // this takes care of rescaling
1041  tr.change_type(0.0, TRUE);
1042 
1043  if (filename == "-")
1044  outf = &cout;
1045  else
1046  outf = new ofstream(filename);
1047 
1048  if (!(*outf))
1049  return write_fail;
1050 
1051  outf->precision(5);
1052  outf->setf(ios::fixed, ios::floatfield);
1053  outf->width(8);
1054 
1055 /* min = max = tr.a(0);
1056  for (i = 0; i < tr.num_frames(); ++i)
1057  {
1058  if (tr.a(i) > max) max = tr.a(i);
1059  if (tr.a(i) < min) min = tr.a(i);
1060  }
1061 */
1062  *outf << "XAO1\n\n"; // xmg header identifier.
1063  *outf << "LineType segments \n";
1064  *outf << "LineStyle solid \n";
1065  *outf << "LineWidth 0 \n";
1066  *outf << "Freq " << sr / 1000 << endl; // a REAL pain!
1067  *outf << "Format Binary \n";
1068  // *outf << "YMin " << ((tr.amin != 0.0) ? tr.amin : min) << endl;
1069  // *outf << "YMax " << ((tr.amax != 0.0) ? tr.amax : max) << endl;
1070  /* if (tr.color != "")
1071  *outf << "LineColor " << tr.color << endl;
1072  */
1073  *outf << char(12) << "\n"; // control L character
1074 
1075  // rm_excess_breaks();
1076  // rm_trailing_breaks();
1077  for (i = 0; i < tr.num_frames(); ++i)
1078  if (tr.val(i))
1079  {
1080  *outf << tr.ms_t(i) << "\t";
1081  for (j = 0; j < tr.num_channels(); ++j)
1082  *outf <<tr.a(i, j) << " ";
1083  *outf << endl;
1084  }
1085  else
1086  *outf << "=\n";
1087  if (outf != &cout)
1088  delete outf;
1089 
1090  return write_ok;
1091 }
1092 
1093 static EST_write_status save_htk_as(const EST_String filename,
1094  EST_Track &orig,
1095  int use_type)
1096 {
1097  // file format is a 12 byte header
1098  // followed by data
1099 
1100  // the data is generally floats, except for DISCRETE
1101  // where it is 2 byte ints
1102 
1103  float s;
1104 
1105  EST_Track track;
1106  int type;
1107  int file_num_channels = orig.num_channels();
1108 
1109  if (orig.f_String("contour_type","none") == "ct_lpc")
1110  type = track_to_htk_lpc(orig, track);
1111  else
1112  {
1113  track = orig;
1114  type = use_type;
1115  }
1116 
1117  if (track.equal_space() != TRUE)
1118  {
1119  track.change_type(0.0, FALSE);
1120  s = rint((HTK_UNITS_PER_SECOND * EST_Track::default_frame_shift/1000.0)/10.0) * 10.0;
1121  type |= HTK_EST_PS;
1122  file_num_channels += 1;
1123  }
1124  else
1125  {
1126  track.change_type(0.0, FALSE);
1127  s = rint((HTK_UNITS_PER_SECOND * track.shift())/10.0) * 10.0;
1128  }
1129 
1130  // hkt files need to be big_endian irrespective of hardware. The
1131  // code here was obviously only ever ran on a Sun. I've tried to
1132  // fix this and it seems to work with floats, don't have data to
1133  // check with shorts though. (Rob, March 2004)
1134 
1135  struct htk_header header;
1136 
1137  header.num_samps = (EST_BIG_ENDIAN ? track.num_frames()
1138  : SWAPINT(track.num_frames()));
1139 
1140 
1141  header.samp_period = (EST_BIG_ENDIAN ? (long) s : SWAPINT((long) s));
1142  if(use_type == HTK_DISCRETE)
1143  header.samp_size = (EST_BIG_ENDIAN ? sizeof(short) :
1144  SWAPSHORT(sizeof(short)));
1145  else
1146  header.samp_size = (EST_BIG_ENDIAN ? (sizeof(float) * file_num_channels) :
1147  SWAPSHORT((sizeof(float) * file_num_channels)));
1148 
1149  header.samp_type = EST_BIG_ENDIAN ? type : SWAPSHORT(type);
1150 
1151  int i, j;
1152  FILE *outf;
1153  if (filename == "-")
1154  outf = stdout;
1155  else if ((outf = fopen(filename,"wb")) == NULL)
1156  {
1157  cerr << "save_htk: cannot open file \"" << filename <<
1158  "\" for writing." << endl;
1159  return misc_write_error;
1160  }
1161 
1162  // write the header
1163  fwrite((char*)&(header.num_samps), 1, sizeof(header.num_samps), outf);
1164  fwrite((char*)&(header.samp_period), 1, sizeof(header.samp_period), outf);
1165  fwrite((char*)&(header.samp_size), 1, sizeof(header.samp_size), outf);
1166  fwrite((char*)&(header.samp_type), 1, sizeof(header.samp_type), outf);
1167 
1168  // write the data
1169  if(use_type == HTK_DISCRETE)
1170  {
1171  if(track.num_channels() < 1)
1172  {
1173  cerr << "No data to write as HTK_DISCRETE !" << endl;
1174  }
1175  else
1176  {
1177  if(track.num_channels() > 1)
1178  {
1179  cerr << "Warning: multiple channel track being written" << endl;
1180  cerr << " as discrete will only save channel 0 !" << endl;
1181  }
1182  for (i = 0; i < track.num_frames(); ++i)
1183  {
1184  short tempshort = (EST_BIG_ENDIAN ? (short)(track.a(i, 0)) :
1185  SWAPSHORT((short)(track.a(i, 0)))) ;
1186  fwrite((unsigned char*) &tempshort, 1, sizeof(short), outf);
1187  }
1188  }
1189  }
1190  else // not HTK_DISCRETE
1191  for (i = 0; i < track.num_frames(); ++i)
1192  {
1193  if ((type & HTK_EST_PS) != 0)
1194  {
1195  if(!EST_BIG_ENDIAN)
1196  swapfloat(&(track.t(i)));
1197  fwrite((unsigned char*) &(track.t(i)), 1, sizeof(float), outf);
1198  }
1199  for (j = 0; j < track.num_channels(); ++j)
1200  {
1201  if(!EST_BIG_ENDIAN)
1202  swapfloat(&(track.a(i,j)));
1203  fwrite((unsigned char*) &(track.a(i, j)), 1, sizeof(float), outf);
1204  }
1205  }
1206 
1207  if (outf != stdout)
1208  fclose(outf);
1209 
1210  return write_ok;
1211 }
1212 
1213 static int htk_sane_header(htk_header *htk)
1214 {
1215  return htk->num_samps > 0 &&
1216  htk->samp_period > 0 &&
1217  htk->samp_size > 0 &&
1218  htk->samp_size < (short)(UNREASONABLE_FRAME_SIZE * sizeof(float));
1219 }
1220 
1221 static int htk_swapped_header(htk_header *header)
1222 {
1223  // Tries to guess if the header is swapped. If so it
1224  // swaps the contents and returns TRUE, other returns FALSE
1225  // HTK doesn't have a magic number so we need heuristics to
1226  // guess when its byte swapped
1227 
1228  if (htk_sane_header(header))
1229  return 0;
1230 
1231  header->num_samps = SWAPINT(header->num_samps);
1232  header->samp_period = SWAPINT(header->samp_period);
1233  header->samp_size = SWAPSHORT(header->samp_size);
1234  header->samp_type = SWAPSHORT(header->samp_type);
1235 
1236  if (htk_sane_header(header))
1237  return 1;
1238 
1239  return -1;
1240 
1241 }
1242 
1243 EST_write_status EST_TrackFile::save_htk(const EST_String filename, EST_Track tmp)
1244 {
1245  return save_htk_as(filename, tmp, HTK_FBANK);
1246 }
1247 
1248 EST_write_status EST_TrackFile::save_htk_fbank(const EST_String filename, EST_Track tmp)
1249 {
1250  return save_htk_as(filename, tmp, HTK_FBANK);
1251 }
1252 
1253 EST_write_status EST_TrackFile::save_htk_mfcc(const EST_String filename, EST_Track tmp)
1254 {
1255  return save_htk_as(filename, tmp, HTK_MFCC);
1256 }
1257 
1258 EST_write_status EST_TrackFile::save_htk_mfcc_e(const EST_String filename, EST_Track tmp)
1259 {
1260  return save_htk_as(filename, tmp, HTK_MFCC | HTK_ENERGY);
1261 }
1262 
1263 EST_write_status EST_TrackFile::save_htk_user(const EST_String filename, EST_Track tmp)
1264 {
1265  return save_htk_as(filename, tmp, HTK_USER);
1266 }
1267 
1268 EST_write_status EST_TrackFile::save_htk_discrete(const EST_String filename, EST_Track tmp)
1269 {
1270  return save_htk_as(filename, tmp, HTK_DISCRETE);
1271 }
1272 
1273 
1274 static EST_read_status load_ema_internal(const EST_String filename, EST_Track &tmp, float ishift, float startt, bool swap)
1275 {
1276  (void)ishift;
1277  (void)startt;
1278 
1279  int i, j, k, nframes, new_order;
1280  EST_TVector<short> file_data;
1281  int sample_width, data_length;
1282  float shift;
1283  FILE *fp;
1284 
1285  if ((fp = fopen(filename, "rb")) == NULL)
1286  {
1287  cerr << "EST_Track load: couldn't open EST_Track input file" << endl;
1288  return misc_read_error;
1289  }
1290 
1291  fseek(fp, 0, SEEK_END);
1292  sample_width = 2;
1293  data_length = ftell(fp)/sample_width;
1294  new_order = 10;
1295  nframes = data_length /new_order;
1296  shift = 0.002;
1297 
1298  cout << "d length: " << data_length << " nfr " << nframes << endl;
1299 
1300  tmp.resize(nframes, new_order);
1301  tmp.fill_time(shift);
1302  tmp.set_equal_space(TRUE);
1303 
1304  file_data.resize(data_length);
1305 
1306  fseek(fp, 0, SEEK_SET);
1307 
1308  if ((int)fread(file_data.memory(), sample_width, data_length, fp) != data_length)
1309  {
1310  fclose(fp);
1311  return misc_read_error;
1312  }
1313 
1314  if (swap)
1315  swap_bytes_short(file_data.memory(), data_length);
1316 
1317  for (i = k = 0; i < nframes; ++i)
1318  for (j = 0; j < new_order; ++j, ++k)
1319  tmp.a(i, j) = (float)file_data.a_no_check(k);
1320 
1321  // name the fields
1322  EST_String t;
1323  // the first 'order' fields are always called c1,c2...
1324  // AWB bug -- the following corrupts memory
1325  /* for (i = 0; i < order; i++)
1326  {
1327  EST_String t2;
1328  t2 = EST_String("c") + itoString(i+1);
1329  tmp.set_field_name(t2, i);
1330  }
1331  i=order;
1332  */
1333  cout << "here \n";
1334 
1335  tmp.set_name(filename);
1336  tmp.set_file_type(tff_ema);
1337 
1338  fclose(fp);
1339  return format_ok;
1340 }
1341 
1342 EST_read_status EST_TrackFile::load_ema(const EST_String filename, EST_Track &tmp, float ishift, float startt)
1343 {
1344  return load_ema_internal(filename, tmp, ishift, startt, FALSE);
1345 }
1346 
1347 
1348 EST_read_status EST_TrackFile::load_ema_swapped(const EST_String filename, EST_Track &tmp, float ishift, float startt)
1349 {
1350  return load_ema_internal(filename, tmp, ishift, startt, TRUE);
1351 }
1352 
1353 #if 0
1354 EST_read_status EST_TrackFile::load_NIST(const EST_String filename, EST_Track &tmp, float ishift, float startt)
1355 {
1356  (void)ishift; // what does this do ?
1357  (void)startt;
1358 
1359  char header[NIST_HDR_SIZE];
1360  int samps,sample_width,data_length,actual_bo;
1361  unsigned char *file_data;
1362  enum EST_sample_type_t actual_sample_type;
1363  char *byte_order, *sample_coding;
1364  int n,i,j,k;
1365  int current_pos;
1366  int offset=0;
1367 
1368  EST_TokenStream ts;
1369  if (((filename == "-") ? ts.open(cin) : ts.open(filename)) != 0)
1370  {
1371  cerr << "Can't open track file " << filename << endl;
1372  return misc_read_error;
1373  }
1374 
1375  current_pos = ts.tell();
1376  if (ts.fread(header,NIST_HDR_SIZE,1) != 1)
1377  return misc_read_error;
1378 
1379  if (strncmp(header,NIST_SIG,sizeof(NIST_SIG)) != 0)
1380  return wrong_format;
1381 
1382  samps = nist_get_param_int(header,"sample_count",-1);
1383  int num_channels = nist_get_param_int(header,"channel_count",1);
1384  sample_width = nist_get_param_int(header,"sample_n_bytes",2);
1385  int sample_rate =
1386  nist_get_param_int(header,"sample_rate",def_load_sample_rate);
1387  byte_order = nist_get_param_str(header,"sample_byte_format",
1388  (EST_BIG_ENDIAN ? "10" : "01"));
1389  sample_coding = nist_get_param_str(header,"sample_coding","pcm");
1390 
1391  data_length = (samps - offset)*num_channels;
1392  file_data = walloc(unsigned char,sample_width * data_length);
1393 
1394  ts.seek(current_pos+NIST_HDR_SIZE+(sample_width*offset*(num_channels)));
1395 
1396  n = ts.fread(file_data,sample_width,data_length);
1397 
1398  if ((n < 1) && (n != data_length))
1399  {
1400  wfree(file_data);
1401  wfree(sample_coding);
1402  wfree(byte_order);
1403  return misc_read_error;
1404  }
1405  else if ((n < data_length) && (data_length/num_channels == n))
1406  {
1407  fprintf(stderr,"TRACK read: nist header is (probably) non-standard\n");
1408  fprintf(stderr,"TRACK read: assuming different num_channel interpretation\n");
1409  data_length = n; /* wrongly headered file */
1410  }
1411  else if (n < data_length)
1412  {
1413  fprintf(stderr,"TRACK read: short file %s\n",
1414  (const char *)ts.filename());
1415  fprintf(stderr,"WAVE read: at %d got %d instead of %d samples\n",
1416  offset,n,data_length);
1417  data_length = n;
1418  }
1419 
1420  actual_sample_type = nist_to_sample_type(sample_coding);
1421  actual_bo = ((strcmp(byte_order,"10") == 0) ? bo_big : bo_little);
1422 
1423  short *data;
1424  data = convert_raw_data(file_data,data_length,
1425  actual_sample_type,actual_bo);
1426 
1427  // copy into the Track
1428  int num_samples = data_length/num_channels;
1429  tmp.resize(num_samples, num_channels);
1430  tmp.set_equal_space(TRUE);
1431  tmp.fill_time(1/(float)sample_rate);
1432 
1433  cerr << "shift " << 1/(float)sample_rate << endl;
1434 
1435  k=0;
1436  for (i=0; i<num_samples; i++)
1437  {
1438  for (j = 0; j < num_channels; ++j)
1439  tmp.a(i, j) = data[k++]; // channels are simply interleaved
1440  tmp.set_value(i);
1441  }
1442  for (j = 0; j < num_channels; ++j)
1443  tmp.set_channel_name("name", j);
1444 
1445 
1446 
1447  /*
1448  *sample_type = st_short;
1449  *bo = EST_NATIVE_BO;
1450  *word_size = 2;
1451  */
1452 
1453  //cerr << "NIST OK" << endl;
1454 
1455  return format_ok;
1456 }
1457 
1458 EST_write_status EST_TrackFile::save_NIST(const EST_String filename, EST_Track tr)
1459 {
1460  FILE *fd;
1461  int i,j,k=0;
1462  if (filename == "-")
1463  fd = stdout;
1464  else if ((fd = fopen(filename,"wb")) == NULL)
1465  return write_fail;
1466 
1467  // create header
1468  char header[NIST_HDR_SIZE], p[1024];;
1469  const char *t;
1470 
1471  memset(header,0,1024);
1472  strcat(header, NIST_SIG);
1473  sprintf(p, "channel_count -i %d\n", tr.num_channels());
1474  strcat(header, p);
1475  sprintf(p, "sample_count -i %d\n", tr.num_frames());
1476  strcat(header, p);
1477  int sr = (int)(rint(1/(float)tr.shift()));
1478  sprintf(p, "sample_rate -i %d\n", sr);
1479  strcat(header, p);
1480  t = sample_type_to_nist(st_short);
1481  sprintf(p, "sample_coding -s%d %s\n", (signed)strlen(t), t);
1482  strcat(header, p);
1483 
1484  strcat(header, NIST_END_SIG);
1485  /*makes it nice to read */
1486  strcat(header, "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
1487 
1488  // write header
1489  if (fwrite(&header, 1024, 1, fd) != 1)
1490  return misc_write_error;
1491 
1492  // data
1493  short data[tr.num_frames() * tr.num_channels()];
1494 
1495 
1496  for (i = 0; i < tr.num_frames(); ++i)
1497  // restricted to shorts at this time
1498  for (j = 0; j < tr.num_channels(); ++j)
1499  data[k++] = (short)(tr.a_no_check(i, j));
1500 
1501  // byte swapping of output not supported - only write native bo
1502  int bo = str_to_bo("native");
1503  return save_raw_data(fd,data,0,tr.num_frames(),tr.num_channels(),
1504  st_short,bo);
1505 
1506  if (fd != stdout)
1507  fclose(fd);
1508  return write_ok;
1509 
1510 }
1511 #endif
1512 
1513 
1514 EST_read_status EST_TrackFile::load_htk(const EST_String filename, EST_Track &tmp, float ishift, float startt)
1515 {
1516  (void)ishift;
1517 
1518  // num_values is total number of fields in file
1519  // num_channels is number of fields in resultant track
1520  // order is order of LPC etc. analysis
1521  // e.g. if order is 12 and we have energy and delta then num_values = (12 + 1) * 2 = 26
1522 
1523  int i,j, order, new_frames, num_values, num_channels;
1524 
1525  EST_String pname;
1526  int swap;
1527  int time_included;
1528 
1529  FILE *fp;
1530  struct htk_header header;
1531  int header_sz = sizeof(header);
1532 
1533  // numbers A and B for decompression of generally compressed files
1534  float *compressA=NULL, compressA_Buffer[REASONABLE_FRAME_SIZE];
1535  float *compressB=NULL, compressB_Buffer[REASONABLE_FRAME_SIZE];
1536  bool fileIsCompressed=false;
1537 
1538  unsigned short samp_type, base_samp_type;
1539 
1540  if ((fp = fopen(filename, "rb")) == NULL){
1541  cerr << "EST_Track load: couldn't open EST_Track input file" << endl;
1542  return misc_read_error;
1543  }
1544 
1545  // try and read the header
1546  if (fread(&header, header_sz, 1, fp) != 1){
1547  fclose(fp);
1548  return wrong_format;
1549  }
1550 
1551  swap = htk_swapped_header(&header); // this is regrettable
1552 
1553  if( swap<0 ){
1554  fclose(fp);
1555  return read_format_error;
1556  }
1557 
1558  samp_type = header.samp_type;
1559  base_samp_type = samp_type & HTK_MASK;
1560 
1561  time_included = (samp_type & HTK_EST_PS) != 0;
1562 
1563  switch(base_samp_type){
1564  case HTK_WAVE:
1565  cerr << "Can't read HTK WAVEFORM format file into track" << endl;
1566  return misc_read_error;
1567  break;
1568 
1569  case HTK_LPC:
1570  pname = "ct_lpc";
1571  break;
1572 
1573  case HTK_LPCREFC:
1574  case HTK_IREFC:
1575  EST_warning( "reading HTK_IREFC and HTK_LPREC parameter types is unsupported" );
1576  fclose( fp );
1577  return read_format_error;
1578  break;
1579 
1580  case HTK_LPCCEP:
1581  pname = "ct_cepstrum";
1582  break;
1583 
1584  case HTK_LPDELCEP:
1585  // equivalent to HTK_LPCCEP + DELTA
1586  base_samp_type = HTK_LPCCEP;
1587  samp_type = HTK_LPCCEP | HTK_DELTA; // set delta bit
1588  pname = "ct_cepstrum";
1589  break;
1590 
1591  case HTK_MFCC:
1592  pname = "ct_other";
1593  break;
1594 
1595  case HTK_FBANK:
1596  case HTK_USER:
1597  pname = "ct_other";
1598  break;
1599 
1600  case HTK_DISCRETE:
1601  cerr << "Can't read HTK DISCRETE format file into track" << endl;
1602  return misc_read_error;
1603  break;
1604 
1605  case HTK_MELSPEC:
1606  pname = "ct_other";
1607  break;
1608 
1609  default:
1610  fclose(fp);
1611  return wrong_format;
1612  break;
1613  }
1614 
1615  // if we get this far we have decided this is a HTK format file
1616 
1617  // handle compressed/uncompressed files differently
1618  if( header.samp_type & HTK_COMP ){
1619 
1620  fileIsCompressed = true;
1621 
1622  num_channels = num_values = header.samp_size / sizeof(short int);
1623 
1624  // get compression numbers A and B
1625  if (num_channels > REASONABLE_FRAME_SIZE){
1626  compressA = new float[num_values];
1627  compressB = new float[num_values];
1628  }
1629  else{
1630  compressA = compressA_Buffer;
1631  compressB = compressB_Buffer;
1632  }
1633 
1634  if( (fread( compressA, sizeof(float), num_values, fp )) != static_cast<size_t>(num_values) ){
1635  fclose( fp );
1636  return read_format_error;
1637  }
1638 
1639  if( (fread( compressB, sizeof(float), num_values, fp )) != static_cast<size_t>(num_values) ){
1640  fclose( fp );
1641  return read_format_error;
1642  }
1643 
1644  if (swap){
1645  swap_bytes_float( compressA, num_values );
1646  swap_bytes_float( compressB, num_values );
1647  }
1648 
1649  // subtract extra frames to account for the two vectors of floats
1650  // used for decompression.
1651  new_frames = header.num_samps - (2*(sizeof(float)-sizeof(short int)));
1652  }
1653  else{
1654  num_channels = num_values = header.samp_size / sizeof(float);
1655  new_frames = header.num_samps;
1656  }
1657 
1658  if (num_values > UNREASONABLE_FRAME_SIZE){
1659  fclose(fp);
1660  return read_format_error;
1661  }
1662 
1663  if (time_included)
1664  num_channels -= 1;
1665 
1666  float shift = ((float)header.samp_period/ (float)HTK_UNITS_PER_SECOND);
1667 
1668  tmp.resize(new_frames, num_channels);
1669 
1670  if ((startt > 0) && (startt < NEARLY_ZERO ))
1671  EST_warning( "setting htk file start to %f", startt );
1672 
1673  tmp.fill_time(shift, startt);
1674 
1675  tmp.set_equal_space(!time_included);
1676 
1677  // check length of file is as expected from header info
1678  long dataBeginPosition = ftell(fp);
1679  if( dataBeginPosition == -1 ){
1680  fclose(fp);
1681  return wrong_format;
1682  }
1683 
1684  if (fseek(fp,0,SEEK_END)){
1685  fclose(fp);
1686  return wrong_format;
1687  }
1688 
1689  long file_length;
1690  if ((file_length = ftell(fp)) == -1){
1691  fclose(fp);
1692  return wrong_format;
1693  }
1694 
1695  long expected_vals;
1696  if( fileIsCompressed ){
1697  expected_vals = (file_length-dataBeginPosition) / sizeof(short int);
1698 
1699  if( header.samp_type & HTK_CRC )
1700  expected_vals -= 1; // just ignore the appended cyclic redundancy checksum
1701  }
1702  else
1703  expected_vals = (file_length-dataBeginPosition) / sizeof(float);
1704 
1705  /*
1706  printf( "%d %d %d %d %d %d\n",
1707  expected_vals, file_length, dataBeginPosition, sizeof(float), num_values, new_frames );
1708  */
1709 
1710  if( expected_vals != (num_values * new_frames) ){
1711  // it probably isn't HTK format after all
1712  fclose(fp);
1713  return wrong_format;
1714  }
1715 
1716  // work out the order of the analysis
1717  // Reorg -- surely you can't increase order
1718  order = num_channels;
1719  if( samp_type & HTK_NO_E )
1720  order++;
1721 
1722  if( samp_type & HTK_AC )
1723  order /= 3;
1724  else if( samp_type & HTK_DELTA )
1725  order /= 2;
1726 
1727  if( samp_type & HTK_ENERGY )
1728  order--;
1729 
1730  // go to start of data
1731  if( fseek(fp, dataBeginPosition, SEEK_SET) == -1 ){
1732  cerr << "Couldn't position htk file at start of data" << endl;
1733  fclose(fp);
1734  return misc_read_error;
1735  }
1736 
1737  if( fileIsCompressed ){
1738  short int *frame, frame_buffer[REASONABLE_FRAME_SIZE];
1739  if( num_values > REASONABLE_FRAME_SIZE )
1740  frame = new short int[num_values];
1741  else
1742  frame = frame_buffer;
1743 
1744  int first_channel = time_included?1:0;
1745 
1746  for( i=0; i<new_frames; i++ ){
1747  if( fread( frame, sizeof(short int), num_values, fp ) != (size_t) num_values ){
1748  cerr << "Could not read data from htk track file" << endl;
1749  fclose(fp);
1750 
1751  if( frame != frame_buffer )
1752  delete [] frame;
1753  if( compressA != compressA_Buffer )
1754  delete [] compressA;
1755  if( compressB != compressB_Buffer )
1756  delete [] compressB;
1757 
1758  return misc_read_error;
1759  }
1760 
1761  if( swap )
1762  swap_bytes_short( frame, num_values );
1763 
1764  if( time_included )
1765  tmp.t(i) = ((float)frame[0]+compressB[0])/compressA[0];
1766 
1767  for( j=0; j<num_channels; ++j ){
1768  int index = j+first_channel;
1769  tmp.a(i,j) = ((float)frame[index]+compressB[index])/compressA[index];
1770  }
1771 
1772  tmp.set_value(i);
1773  }
1774 
1775  if( frame != frame_buffer )
1776  delete [] frame;
1777  if( compressA != compressA_Buffer )
1778  delete [] compressA;
1779  if( compressB != compressB_Buffer )
1780  delete [] compressB;
1781  }
1782  else{
1783  float *frame, frame_buffer[REASONABLE_FRAME_SIZE];
1784 
1785  if (num_values > REASONABLE_FRAME_SIZE)
1786  frame = new float[num_values];
1787  else
1788  frame = frame_buffer;
1789 
1790  int first_channel = time_included?1:0;
1791  for( i=0; i<new_frames; i++ ){
1792  if( fread( frame, sizeof(float), num_values, fp ) != (size_t) num_values ){
1793  cerr << "Could not read data from htk track file" << endl;
1794  fclose(fp);
1795  if (frame != frame_buffer)
1796  delete [] frame;
1797  return misc_read_error;
1798  }
1799  if( swap )
1800  swap_bytes_float( frame, num_values );
1801 
1802  if( time_included )
1803  tmp.t(i) = frame[0];
1804 
1805  for( j=0; j<num_channels; ++j )
1806  tmp.a(i, j) = frame[j+first_channel];
1807 
1808  tmp.set_value(i);
1809  }
1810 
1811  if( frame != frame_buffer )
1812  delete [] frame;
1813  }
1814 
1815  // name the fields
1816  EST_String t;
1817  // the first 'order' fields are always called c1,c2...
1818  // AWB bug -- the following corrupts memory
1819  for (i=0;i<order;i++)
1820  {
1821  EST_String t2;
1822  t2 = EST_String("c") + itoString(i+1);
1823  tmp.set_channel_name(t2, i);
1824  }
1825  i=order;
1826 
1827  // energy present and not suppressed
1828  if ( (samp_type & HTK_ENERGY) && !(samp_type & HTK_NO_E) )
1829  tmp.set_channel_name("E", i++);
1830 
1831  // delta coeffs ?
1832  if (samp_type & HTK_DELTA){
1833  for (j = 0; j < order; j++){
1834  t = EST_String("c") + itoString(j+1) + "_d";
1835  tmp.set_channel_name(t, i++);
1836  }
1837 
1838  // energy ?
1839  if (samp_type & HTK_ENERGY)
1840  tmp.set_channel_name("E_d", i++);
1841  }
1842 
1843  // 'acceleration' coeffs ?
1844  if (samp_type & HTK_AC){
1845  for(j=0;j<order;j++){
1846  t = EST_String("ac")+ itoString(j+1)+ "_d_d";
1847  tmp.set_channel_name(t, i++);
1848  }
1849  // energy ?
1850  if (samp_type & HTK_ENERGY)
1851  tmp.set_channel_name("E_d_d", i++);
1852  }
1853 
1854  // sanity check
1855  if (i != num_channels){
1856  cerr << "Something went horribly wrong - wanted " << num_values
1857  << " channels in track but got " << i << endl;
1858  fclose(fp);
1859  return wrong_format;
1860  }
1861  tmp.f_set("contour_type",pname);
1862  tmp.set_name(filename);
1863  tmp.set_file_type(tff_htk);
1864  fclose(fp);
1865  return format_ok;
1866 }
1867 
1868 /************************************************************************/
1869 /* */
1870 /* Convert single f0 channel tracks into arbitrarily chosen esps FEA */
1871 /* subtype, reputedly to make waves happy. This is evil beyond all */
1872 /* understanding. */
1873 /* */
1874 /************************************************************************/
1875 
1876 // format of the desired track.
1877 static struct EST_TrackMap::ChannelMappingElement espsf0_mapping[] =
1878 {
1879 { channel_f0, 0 },
1880 { channel_voiced, 1 },
1881 { channel_power, 2},
1882 { channel_peak, 3},
1883 { channel_unknown, 0}
1884 };
1885 static EST_TrackMap ESPSF0TrackMap(espsf0_mapping);
1886 
1887 // It seems that the vital thing is to call the track "F0", and so
1888 // we only need 1 channel instead of the normal 5. This saves *lots* of
1889 // space. For the time being we use 2 channels as the prob_voicnug filed is
1890 // used by our input routine.
1891 
1892 int track_to_espsf0(EST_Track &track, EST_Track &f0_track)
1893 {
1894  f0_track.resize(track.num_frames(), 2);
1895 
1896  f0_track.assign_map(ESPSF0TrackMap);
1897 
1898  // k1 is ratio of the first two cross-correlation values
1899  // f0_track.set_channel_name("k1", 4);
1900 
1901  // copy data. Remaining channels zeroed by resize. This is of course stupid
1902  // as if k1 iz zero mathematics is in deep problems.
1903  for (int i = 0; i < track.num_frames(); ++i)
1904  {
1905  f0_track.a(i, channel_voiced) = track.track_break(i) ? 0.1 : 1.2;
1906  f0_track.a(i, channel_f0) = track.track_break(i) ? 0.0: track.a(i,0);
1907  }
1908 
1909  f0_track.set_file_type(tff_esps);
1910  f0_track.fill_time(track.shift());
1911  track.set_name(track.name());
1912 
1913  /* f0_track.resize(track.num_frames(), 5);
1914 
1915  f0_track.assign_map(ESPSF0TrackMap);
1916 
1917  // k1 is ratio of the first two cross-correlation values
1918  f0_track.set_channel_name("k1", 4);
1919 
1920  // copy data. Remaining channels zeroed by resize. This is of course stupid
1921  // as if k1 iz zero mathematics is in deep problems.
1922  for (int i = 0; i < track.num_frames(); ++i)
1923  {
1924  f0_track.a(i, channel_voiced) = track.track_break(i) ? 0.1 : 1.2;
1925  f0_track.a(i, channel_f0) = track.a(i,0);
1926  }
1927 
1928  f0_track.set_file_type("esps");
1929  f0_track.fill_time(track.shift());
1930  track.set_name(track.name());
1931  */
1932 
1933  return 0;
1934 }
1935 
1936 int espsf0_to_track(EST_Track &fz)
1937 {
1938  int f, p, i;
1939  f = p = -1;
1940 
1941  // check to see if prob of voicing channel exists
1942  for (i = 0; i < fz.num_channels(); ++i)
1943  {
1944  if (fz.channel_name(i) == "prob_voice")
1945  p = i;
1946  }
1947  for (i = 0; i < fz.num_channels(); ++i)
1948  {
1949  if (fz.channel_name(i) == "F0")
1950  f = i;
1951  }
1952 
1953  for (i = 0; i < fz.num_frames(); ++i)
1954  {
1955  if (p == -1) // if f0 val is < 1 make this a break
1956  {
1957  if (fz.a(i, f) < 1.0)
1958  fz.set_break(i);
1959  else
1960  fz.set_value(i);
1961  }
1962  else // use prob voicing
1963  {
1964  if (fz.a(i, p) < 0.5)
1965  {
1966  fz.a(i, f) = 0.0;
1967  fz.set_break(i);
1968  }
1969  else
1970  fz.set_value(i);
1971  }
1972  }
1973 
1974  return 0;
1975 }
1976 
1977 int track_to_htk_lpc(EST_Track &track, EST_Track &lpc)
1978 {
1979  int type = HTK_LPC;
1980  int ncoefs, nchannels;
1981 
1982  if (track.has_channel(channel_lpc_N))
1983  ncoefs = track.channel_position(channel_lpc_N) - track.channel_position(channel_lpc_0)+1;
1984  else
1985  ncoefs = track.num_channels()-track.channel_position(channel_lpc_0);
1986 
1987  nchannels = ncoefs;
1988 
1989  if (track.has_channel(channel_power))
1990  {
1991  nchannels++;
1992  type |= HTK_ENERGY;
1993  }
1994 
1995  lpc.resize(track.num_frames(), nchannels);
1996  lpc.set_equal_space(track.equal_space());
1997  lpc.set_single_break(track.single_break());
1998  lpc.set_single_break(track.single_break());
1999 
2000  for(int i = 0; i< track.num_frames(); i++)
2001  for (int c = 0; c < ncoefs; c++)
2002  {
2003  lpc.a(i, c) = track.a(i, channel_lpc_0, c);
2004  lpc.t(i) = track.t(i);
2005  }
2006 
2007 
2008  if (track.has_channel(channel_power))
2009  {
2010  for(int ii = 0; ii< track.num_frames(); ii++)
2011  lpc.a(ii, ncoefs) = track.a(ii, channel_power);
2012  }
2013 
2014  return type;
2015 
2016 }
2017 
2018 EST_write_status save_ind_TrackList(EST_TrackList &tlist, EST_String &otype)
2019 {
2020  for (EST_Litem *p = tlist.head(); p ; p = p->next())
2021  tlist(p).save(tlist(p).name(), otype);
2022 
2023  return write_ok;
2024 }
2025 
2026 EST_read_status read_TrackList(EST_TrackList &tlist, EST_StrList &files,
2027  EST_Option &al)
2028 {
2029  EST_Track s;
2030  EST_Litem *p, *plp;
2031 
2032  for (p = files.head(); p; p = p->next())
2033  {
2034  tlist.append(s);
2035  plp = tlist.tail();
2036  if (read_track(tlist(plp), files(p), al) != format_ok)
2037  exit (-1);
2038 
2039  tlist(plp).set_name(files(p));
2040  }
2041 
2042  return format_ok;
2043 }
2044 
2045 int read_track(EST_Track &tr, const EST_String &in_file, EST_Option &al)
2046 {
2047 
2048  float ishift = 0;
2049  float startt = 0.0;
2050 
2051  if( al.present("-startt") )
2052  startt = al.fval( "-startt" );
2053 
2054  if (al.present("ishift"))
2055  ishift = al.fval("ishift");
2056  else if (al.present("-s"))
2057  ishift = al.fval("-s");
2058  else if (al.present("time_channel"))
2059  ishift = 1.0; // doesn't matter, will be reset by track
2060 
2061  if (al.present("-itype"))
2062  {
2063  if (tr.load(in_file, al.val("-itype", 0), ishift, startt) != format_ok)
2064  return -1;
2065  }
2066  else
2067  {
2068  if (tr.load(in_file, ishift, startt ) != format_ok)
2069  return -1;
2070  }
2071 
2072 // tr.create_map();
2073 
2074  // cout << "f0 "<< tr.has_channel(channel_f0) << ".\n";
2075 // if (al.present("time_channel") && tr.has_channel(al.sval("time_channel")))
2076 // {
2077 // cout << " time from channel " << al.sval("time_channel") << "\n";
2078 // channel_to_time(tr, al.sval("time_channel"), al.fval("time_scale"));
2079 // }
2080 
2081 
2082  // cout << tr;
2083  return 0;
2084 }
2085 
2086 
2087 EST_String EST_TrackFile::options_short(void)
2088 {
2089  EST_String s("");
2090 
2091  for(int n=0; n< EST_TrackFile::map.n() ; n++)
2092  {
2093  const char *nm = EST_TrackFile::map.name(EST_TrackFile::map.token(n));
2094 
2095  if (s != "")
2096  s += ", ";
2097 
2098  s += nm;
2099 
2100  }
2101  return s;
2102 }
2103 
2104 EST_String EST_TrackFile::options_supported(void)
2105 {
2106  EST_String s("AvailablE track file formats:\n");
2107 
2108  for(int n=0; n< EST_TrackFile::map.n() ; n++)
2109  {
2110  const char *nm = EST_TrackFile::map.name(EST_TrackFile::map.token(n));
2111  const char *d = EST_TrackFile::map.info(EST_TrackFile::map.token(n)).description;
2112 
2113  s += EST_String::cat(" ", nm, EST_String(" ")*(13-strlen(nm)), d, "\n");
2114  }
2115  return s;
2116 }
2117 
2118 // note the order here defines the order in which loads are tried.
2120 {
2121 { tff_none, { "none" },
2122 {FALSE, NULL, NULL,
2123  "unknown track file type"}},
2124 {tff_esps, { "esps" },
2125 {TRUE, EST_TrackFile::load_esps, EST_TrackFile::save_esps,
2126  "entropic sps file"}},
2127 {tff_est_ascii, { "est", "est_ascii" },
2128 {TRUE, EST_TrackFile::load_est, EST_TrackFile::save_est_ascii,
2129  "Edinburgh Speech Tools track file"}},
2130 {tff_est_binary, { "est_binary" },
2131 {TRUE, EST_TrackFile::load_est, EST_TrackFile::save_est_binary,
2132  "Edinburgh Speech Tools track file"}}
2133 ,
2134 {tff_htk, { "htk" },
2135 {TRUE, EST_TrackFile::load_htk, EST_TrackFile::save_htk,
2136  "htk file"}},
2137 //{tff_NIST, { "NIST" },
2138 //{TRUE, EST_TrackFile::load_NIST, EST_TrackFile::save_NIST,
2139 // "NIST"}},
2140 {tff_htk_fbank, { "htk_fbank" },
2141 {FALSE, EST_TrackFile::load_htk, EST_TrackFile::save_htk_fbank,
2142  "htk file (as FBANK)"}},
2143 {tff_htk_mfcc, { "htk_mfcc" },
2144 {FALSE, EST_TrackFile::load_htk, EST_TrackFile::save_htk_mfcc,
2145  "htk file (as MFCC)"}},
2146 {tff_htk_mfcc_e, { "htk_mfcc_e" },
2147 {FALSE, EST_TrackFile::load_htk, EST_TrackFile::save_htk_mfcc_e,
2148  "htk file (as MFCC_E)"}},
2149 {tff_htk_user, { "htk_user" },
2150 {FALSE, EST_TrackFile::load_htk, EST_TrackFile::save_htk_user,
2151  "htk file (as USER)"}},
2152 {tff_htk_discrete, { "htk_discrete" },
2153 {FALSE, EST_TrackFile::load_htk, EST_TrackFile::save_htk_discrete,
2154  "htk file (as DISCRETE)"}},
2155 {tff_ssff, {"ssff"},
2156 {TRUE, EST_TrackFile::load_ssff, EST_TrackFile::save_ssff,
2157  "Macquarie University's Simple Signal File Format"}},
2158 {tff_xmg, { "xmg" },
2159 {TRUE, EST_TrackFile::load_xmg, EST_TrackFile::save_xmg,
2160  "xmg file viewer"}},
2161 {tff_xgraph, { "xgraph" },
2162 {FALSE, EST_TrackFile::load_xgraph, EST_TrackFile::save_xgraph,
2163  "xgraph display program format"}},
2164 {tff_ema, { "ema" },
2165 {FALSE, EST_TrackFile::load_ema, NULL,
2166  "ema"}},
2167 {tff_ema_swapped, { "ema_swapped" },
2168 {FALSE, EST_TrackFile::load_ema_swapped, NULL,
2169  "ema, swapped"}},
2170 {tff_ascii, { "ascii" },
2171 {TRUE, EST_TrackFile::load_ascii, EST_TrackFile::save_ascii,
2172  "ascii decimal numbers"}},
2173 { tff_none, {"none"}, {FALSE, NULL, NULL, "unknown track file type"} }
2174 };
2175 
2176 EST_TNamedEnumI<EST_TrackFileType, EST_TrackFile::Info> EST_TrackFile::map(trackfile_names);
2177 
2178 static EST_TValuedEnumDefinition<EST_TrackFileType, const char *,
2179 EST_TrackFile::TS_Info> track_ts_names[] =
2180 {
2181 { tff_none, { "none" },
2182 {FALSE, NULL, NULL,
2183  "unknown track file type"}},
2184 
2185 {tff_est_ascii, {"est"},
2186 {TRUE, EST_TrackFile::load_est_ts, EST_TrackFile::save_est_ts,
2187  "Edinburgh Speech Tools track file"}},
2188 
2189 {tff_est_binary, {"est_binary"},
2190 {TRUE, EST_TrackFile::load_est_ts, EST_TrackFile::save_est_binary_ts,
2191  "Edinburgh Speech Tools track file"}},
2192 
2193 {tff_ssff, {"ssff"},
2194 {TRUE, EST_TrackFile::load_ssff_ts, EST_TrackFile::save_ssff_ts,
2195  "Macquarie University's Simple Signal File Format"}},
2196 
2197 { tff_none, { "none" },
2198 {FALSE, NULL, NULL,
2199  "unknown track file type"}}
2200 };
2201 
2203 EST_TrackFile::ts_map(track_ts_names);
2204 
2205 
2206 #if defined(INSTANTIATE_TEMPLATES)
2207 
2208 #include "../base_class/EST_TNamedEnum.cc"
2210 template class EST_TValuedEnumI<EST_TrackFileType,
2211 const char *, EST_TrackFile::Info>;
2213 template class EST_TValuedEnumI<EST_TrackFileType,
2214 const char *, EST_TrackFile::TS_Info>;
2215 
2216 #endif
2217