Edinburgh Speech Tools  2.4-release
 All Classes Functions Variables Typedefs Enumerations Enumerator Friends Pages
ssff.cc
1 /*************************************************************************/
2 /* */
3 /* Centre for Speech Technology Research */
4 /* University of Edinburgh, UK */
5 /* Copyright (c) 1999 */
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 : Alan W Black */
34 /* Date : November 1999 */
35 /*-----------------------------------------------------------------------*/
36 /* Version of code for reading and writing MacQuarie's SSFF format as */
37 /* used in emulabel */
38 /* */
39 /*=======================================================================*/
40 #include <fstream>
41 #include <iostream>
42 #include <cstdlib>
43 #include <cmath>
44 #include <time.h>
45 #include "EST_unix.h"
46 #include "EST_types.h"
47 #include "EST_Track.h"
48 #include "EST_track_aux.h"
49 #include "EST_TrackMap.h"
50 #include "EST_cutils.h"
51 #include "EST_Token.h"
52 #include "EST_TList.h"
53 #include "EST_string_aux.h"
54 #include "EST_walloc.h"
55 #include "EST_TrackFile.h"
56 #include "EST_FileType.h"
57 
58 EST_read_status EST_TrackFile::load_ssff(const EST_String filename,
59  EST_Track &tr, float ishift, float startt)
60 {
61  EST_TokenStream ts;
62 
63  if (((filename == "-") ? ts.open(cin) : ts.open(filename)) != 0)
64  {
65  cerr << "Can't open track file " << filename << endl;
66  return misc_read_error;
67  }
68  tr.set_name(filename);
69  return load_ssff_ts(ts, tr, ishift, startt);
70 }
71 
72 EST_read_status EST_TrackFile::load_ssff_ts(EST_TokenStream &ts, EST_Track &tr, float ishift, float startt)
73 {
74  (void)ishift;
75  (void)startt;
76  int num_frames, num_channels;
77  int swap = FALSE;
78  int i,j,pos,end;
79  float Start_Time, Record_Freq;
80  EST_Features channels;
81  EST_String c, name, type, size, cname;
82  FILE *fp;
83  double dbuff[2];
84  short sbuff[2];
85 
86  num_frames = num_channels = 0;
87  Start_Time = Record_Freq = 0;
88 
89  if (ts.get() != "SSFF")
90  return wrong_format;
91 
92  if ((ts.get() != "--") ||
93  (ts.get() != "(c)") ||
94  (ts.get() != "SHLRC"))
95  {
96  cerr << "ssff load track \"" << ts.filename() << "\": bad header"
97  << endl;
98  return misc_read_error;
99  }
100 
101  while (ts.peek() != "-----------------")
102  {
103  c = (EST_String)ts.get();
104  if (c == "Comment")
105  ts.get_upto_eoln();
106  else if (c == "Start_Time")
107  {
108  Start_Time = atof(ts.get().string());
109  tr.f_set("Start_Time",Start_Time);
110  }
111  else if (c == "Record_Freq")
112  {
113  Record_Freq = atof(ts.get().string());
114  tr.f_set("Record_Freq",Record_Freq);
115  }
116  else if (c == "Machine")
117  {
118  if (ts.get() == "SPARC")
119  {
120  if (EST_NATIVE_BO != bo_big)
121  swap = TRUE;
122  }
123  else if (EST_NATIVE_BO == bo_big)
124  swap = TRUE;
125  }
126  else if (c == "Column")
127  {
128  name = (EST_String)ts.get();
129  type = (EST_String)ts.get();
130  size = (EST_String)ts.get();
131  cname = EST_String("Channel_")+itoString(num_channels);
132  channels.set(cname+".name",name);
133  channels.set(cname+".type",type);
134  channels.set(cname+".size",atoi(size));
135  num_channels++;
136  }
137  else if ((c == "window_type") ||
138  (c == "window_duration") ||
139  (c == "lpc_order") ||
140  (c == "lpc_type") ||
141  (c == "end_time") ||
142  (c == "preemphasis") ||
143  (c == "frame_duration"))
144  {
145  type = (EST_String)ts.get();
146  if (type == "SHORT")
147  tr.f_set(c,atoi(ts.get().string()));
148  else if (type == "DOUBLE")
149  tr.f_set(c,(float)atof(ts.get().string()));
150  else
151  tr.f_set(c,ts.get().string());
152  }
153  else if (ts.eof())
154  {
155  cerr << "ssff load track \"" << ts.filename() <<
156  "\": bad header unexpected eof" << endl;
157  return misc_read_error;
158  }
159  // else
160  // {
161  // cerr << "ssff load track \"" << ts.filename() <<
162  // "\": unknown header value \"" << c << "\"" << endl;
163  // }
164  }
165  ts.get(); // skip over end of header line
166 
167  // There's no num_records field in the header so have to use file's
168  // length to calculate it
169  fp = ts.filedescriptor();
170  pos = ftell(fp);
171  fseek(fp,0,SEEK_END);
172  end = ftell(fp);
173  fseek(fp,pos,SEEK_SET);
174  num_frames = (end - pos)/(num_channels*sizeof(double));
175 
176  // Finished reading header
177  tr.resize(num_frames,num_channels);
178  tr.fill_time(1.0/Record_Freq);
179  tr.set_equal_space(true);
180 
181  for (i=0; i<num_channels; i++)
182  tr.set_channel_name(channels.S(EST_String("Channel_")+
183  itoString(i)+".name"),i);
184 
185  for (i=0; i < num_frames; i++)
186  for (j=0; j<num_channels; j++)
187  {
188  type = channels.S(EST_String("Channel_")+ itoString(j)+".type");
189  if (type == "DOUBLE")
190  {
191  ts.fread(dbuff,sizeof(double),1);
192  if (swap)
193  swap_bytes_double(dbuff,1);
194  tr(i,j) = *dbuff;
195  }
196  else if (type == "SHORT")
197  {
198  ts.fread(sbuff,sizeof(short),1);
199  if (swap)
200  swap_bytes_short(sbuff,1);
201  tr(i,j) = (float)(*sbuff);
202  }
203  else
204  {
205  cerr << "ssff load track \"" << ts.filename() <<
206  "\": unknown channel type value \"" << type << "\"" << endl;
207  return misc_read_error;
208  }
209  }
210 
211  return format_ok;
212 }
213 
214 EST_write_status EST_TrackFile::save_ssff(const EST_String filename, EST_Track tr)
215 {
216  FILE *fd;
217  EST_write_status r;
218 
219  if (filename == "-")
220  fd = stdout;
221  else if ((fd = fopen(filename,"wb")) == NULL)
222  return write_fail;
223 
224  r = save_ssff_ts(fd,tr);
225 
226  if (fd != stdout)
227  fclose(fd);
228  return r;
229 
230 }
231 
232 EST_write_status EST_TrackFile::save_ssff_ts(FILE *fp, EST_Track tr)
233 {
234  int i,j;
235  int need_prob_voice = 0;
236 
237  if (tr.equal_space() != 1)
238  {
239  cerr << "ssf save track: can't save variable spaced track as SSFF"
240  << endl;
241  return write_error;
242  }
243 
244  fprintf(fp,"SSFF -- (c) SHLRC\n");
245  if (EST_NATIVE_BO == bo_big)
246  fprintf(fp,"Machine SPARC\n");
247  else
248  fprintf(fp,"Machine IBM-PC\n");
249  if (tr.f_present("Start_Time"))
250  fprintf(fp,"Start_Time %g\n",(double)tr.f_F("Start_Time"));
251  else
252  fprintf(fp,"Start_Time 0.000000\n");
253  // If there are less than two sample points I can't get this value
254  if (tr.f_present("Record_Freq"))
255  fprintf(fp,"Record_Freq %g\n",(double)tr.f_F("Record_Freq"));
256  else if (tr.num_frames() < 2)
257  fprintf(fp,"Record_Freq %d\n", 100);
258  else
259  fprintf(fp,"Record_Freq %g\n", 1/(tr.t(1)-tr.t(0)));
260 
261  for (i = 0; i < tr.num_channels(); ++i)
262  fprintf(fp, "Column %s DOUBLE 1\n",(const char *)(tr.channel_name(i)));
263  // For EMULABEL to read this is needs prob_voice too
264  if ((tr.num_channels() == 1) &&
265  (tr.channel_name(0) == "F0"))
266  {
267  need_prob_voice = 1;
268  fprintf(fp, "Column prob_voice DOUBLE 1\n");
269  }
271 
272  for (p.begin(tr); p; ++p)
273  {
274  if ((p->k == "Start_Time") ||
275  (p->k == "Record_Freq"))
276  continue;
277  else
278  fprintf(fp, "%s DOUBLE %s\n", (const char *)p->k,
279  (const char *) p->v.String());
280  }
281  fprintf(fp,"-----------------\n");
282  for (i=0; i< tr.num_frames(); i++)
283  {
284  double prob_voice;
285  double dd;
286  for (j=0; j< tr.num_channels(); j++)
287  {
288  dd = tr(i,j);
289  fwrite(&dd,sizeof(double),1,fp);
290  }
291  if (need_prob_voice)
292  {
293  if (tr(i,0) == 0)
294  prob_voice = 0;
295  else
296  prob_voice = 1;
297  fwrite(&prob_voice,sizeof(double),1,fp);
298  }
299  }
300 
301  return write_ok;
302 }