Edinburgh Speech Tools  2.4-release
 All Classes Functions Variables Typedefs Enumerations Enumerator Friends Pages
EST_WaveFile.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  /* */
34  /* Author : Richard Caley <rjc@cstr.ed.ac.uk> */
35  /* ------------------------------------------------------------------- */
36  /* Wave file input and output. */
37  /* */
38  /*************************************************************************/
39 #include <cstdlib>
40 #include "EST_Wave.h"
41 #include "EST_WaveFile.h"
42 #include "waveP.h"
43 #include "EST_cutils.h"
44 #include "EST_Option.h"
45 #include "EST_io_aux.h"
46 #include "stdio.h"
47 #include "math.h"
48 
49 void extract(EST_Wave &sig, EST_Option &al);
50 
51 typedef
52 EST_read_status (*standard_load_fn_fp)(EST_TokenStream &ts,
53  short **data, int *nsamp, int *nchan,
54  int *wsize,
55  int *srate,
56  EST_sample_type_t *stype, int *bo,
57  int offset, int length);
58 
59 typedef
60 EST_write_status (*standard_save_fn_fp)(FILE *fp,
61  const short *data,
62  int offset, int nsamp,
63  int nchan, int srate,
64  EST_sample_type_t stype, int bo);
65 
66 
67 static
68 EST_read_status load_using(standard_load_fn_fp fn,
69  EST_TokenStream &ts,
70  EST_Wave &wv,
71  int rate,
72  EST_sample_type_t stype, int bo, int nchan,
73  int offset, int length)
74 {
75  short *data;
76  int nsamp;
77  int wsize;
78  int srate = rate;
79 
80  EST_read_status status = (*fn)(ts,
81  &data, &nsamp, &nchan,
82  &wsize,
83  &srate, &stype, &bo,
84  offset, length);
85 
86  if (status == read_ok)
87  {
88  wv.values().set_memory(data, 0, nsamp, nchan, TRUE);
89  wv.set_sample_rate(srate);
90  }
91 
92  return status;
93 }
94 
95 static
96 EST_write_status save_using(standard_save_fn_fp fn,
97  FILE *fp, const EST_Wave wv,
98  EST_sample_type_t stype, int bo)
99 {
100 EST_write_status status = (*fn)(fp,
101  wv.values().memory(),
102  0, wv.num_samples(), wv.num_channels(),
103  wv.sample_rate(),
104  stype, bo);
105 
106 return status;
107 }
108 
109 EST_read_status EST_WaveFile::load_nist(EST_TokenStream &ts,
110  EST_Wave &wv,
111  int rate,
112  EST_sample_type_t stype, int bo, int nchan,
113  int offset, int length)
114 {
115  return load_using(load_wave_nist,
116  ts, wv, rate,
117  stype, bo, nchan,
118  offset, length);
119 }
120 
121 EST_write_status EST_WaveFile::save_nist(FILE *fp,
122  const EST_Wave &wv,
123  EST_sample_type_t stype, int bo)
124 {
125  return save_using(save_wave_nist, fp, wv, stype, bo);
126 }
127 
128 EST_read_status EST_WaveFile::load_est(EST_TokenStream &ts,
129  EST_Wave &wv,
130  int rate,
131  EST_sample_type_t stype, int bo, int nchan,
132  int offset, int length)
133 {
134  (void) ts;
135  return load_using(load_wave_est,
136  ts, wv, rate,
137  stype, bo, nchan,
138  offset, length);
139 
140 }
141 
142 EST_write_status EST_WaveFile::save_est(FILE *fp,
143  const EST_Wave &wv,
144  EST_sample_type_t stype, int bo)
145 {
146  return save_using(save_wave_est,
147  fp, wv,
148  stype, bo);
149 
150 }
151 
152 EST_read_status EST_WaveFile::load_aiff(EST_TokenStream &ts,
153  EST_Wave &wv,
154  int rate,
155  EST_sample_type_t stype, int bo, int nchan,
156  int offset, int length)
157 {
158  return load_using(load_wave_aiff,
159  ts, wv, rate,
160  stype, bo, nchan,
161  offset, length);
162 }
163 
164 EST_write_status EST_WaveFile::save_aiff(FILE *fp,
165  const EST_Wave &wv,
166  EST_sample_type_t stype, int bo)
167 {
168  return save_using(save_wave_aiff, fp, wv, stype, bo);
169 }
170 
171 
172 EST_read_status EST_WaveFile::load_riff(EST_TokenStream &ts,
173  EST_Wave &wv,
174  int rate,
175  EST_sample_type_t stype, int bo, int nchan,
176  int offset, int length)
177 {
178  return load_using(load_wave_riff,
179  ts, wv, rate,
180  stype, bo, nchan,
181  offset, length);
182 }
183 
184 EST_write_status EST_WaveFile::save_riff(FILE *fp,
185  const EST_Wave &wv,
186  EST_sample_type_t stype, int bo)
187 {
188  return save_using(save_wave_riff, fp, wv, stype, bo);
189 }
190 
191 
192 EST_read_status EST_WaveFile::load_esps(EST_TokenStream &ts,
193  EST_Wave &wv,
194  int rate,
195  EST_sample_type_t stype, int bo, int nchan,
196  int offset, int length)
197 {
198  return load_using(load_wave_sd,
199  ts, wv, rate,
200  stype, bo, nchan,
201  offset, length);
202 }
203 
204 EST_write_status EST_WaveFile::save_esps(FILE *fp,
205  const EST_Wave &wv,
206  EST_sample_type_t stype, int bo)
207 {
208  return save_using(save_wave_sd,
209  fp, wv,
210  stype, bo);
211 }
212 
213 
214 EST_read_status EST_WaveFile::load_audlab(EST_TokenStream &ts,
215  EST_Wave &wv,
216  int rate,
217  EST_sample_type_t stype, int bo, int nchan,
218  int offset, int length)
219 {
220  return load_using(load_wave_audlab,
221  ts, wv, rate,
222  stype, bo, nchan,
223  offset, length);
224 }
225 
226 EST_write_status EST_WaveFile::save_audlab(FILE *fp,
227  const EST_Wave &wv,
228  EST_sample_type_t stype, int bo)
229 {
230  return save_using(save_wave_audlab, fp, wv, stype, bo);
231 }
232 
233 
234 EST_read_status EST_WaveFile::load_snd(EST_TokenStream &ts,
235  EST_Wave &wv,
236  int rate,
237  EST_sample_type_t stype, int bo, int nchan,
238  int offset, int length)
239 {
240  return load_using(load_wave_snd,
241  ts, wv, rate,
242  stype, bo, nchan,
243  offset, length);
244 }
245 
246 EST_write_status EST_WaveFile::save_snd(FILE *fp,
247  const EST_Wave &wv,
248  EST_sample_type_t stype, int bo)
249 {
250  return save_using(save_wave_snd, fp, wv, stype, bo);
251 }
252 
253 
254 EST_read_status EST_WaveFile::load_raw(EST_TokenStream &ts,
255  EST_Wave &wv,
256  int rate,
257  EST_sample_type_t stype, int bo, int nchan,
258  int offset, int length)
259 {
260  short *data;
261  int nsamp;
262  int wsize;
263  int srate = rate;
264 
265  EST_read_status status = load_wave_raw(ts,
266  &data, &nsamp, &nchan,
267  &wsize,
268  &srate, &stype, &bo,
269  offset, length,
270  rate, stype, bo, nchan);
271 
272  if (status == read_ok)
273  {
274  wv.values().set_memory(data, 0, nsamp, nchan, TRUE);
275  wv.set_sample_rate(srate);
276  }
277 
278  return status;
279 }
280 
281 EST_write_status EST_WaveFile::save_raw(FILE *fp,
282  const EST_Wave &wv,
283  EST_sample_type_t stype, int bo)
284 {
285 EST_write_status status = save_wave_raw(fp,
286  (short *)wv.values().memory(),
287  0, wv.num_samples(), wv.num_channels(),
288  wv.sample_rate(),
289  stype, bo);
290 return status;
291 }
292 
293 
294 EST_read_status EST_WaveFile::load_ulaw(EST_TokenStream &ts,
295  EST_Wave &wv,
296  int rate,
297  EST_sample_type_t stype, int bo, int nchan,
298  int offset, int length)
299 {
300  return load_using(load_wave_ulaw,
301  ts, wv, rate,
302  stype, bo, nchan,
303  offset, length);
304 }
305 
306 EST_write_status EST_WaveFile::save_ulaw(FILE *fp,
307  const EST_Wave &wv,
308  EST_sample_type_t stype, int bo)
309 {
310  EST_Wave localwv = wv;
311  localwv.resample(8000);
312  return save_using(save_wave_ulaw, fp, localwv, stype, bo);
313 }
314 
315 static int parse_esps_r_option(EST_String arg, int &offset, int &length)
316 {
317  EST_String s, e;
318 
319  if (arg.contains("-"))
320  {
321  s = arg.before("-");
322  e = arg.after("-");
323  }
324  else if (arg.contains(":"))
325  {
326  s = arg.before(":");
327  e = arg.after(":");
328  }
329  else
330  {
331  cerr << "Argument to -r is illformed " << arg << endl;
332  return -1;
333  }
334 
335  if (!s.matches(RXint))
336  {
337  cerr << "First argument to -r must be an integer " << arg << endl;
338  return -1;
339  }
340 
341  offset = atoi(s);
342  if (e.contains("+"))
343  {
344  e = e.after("+");
345  length = atoi(e);
346  }
347  else
348  length = atoi(e) - offset;
349 
350  if (length <= 0)
351  {
352  cerr << "length is negative or zero " << arg << endl;
353  return -1;
354  }
355 
356  return 0;
357 }
358 
359 EST_read_status read_wave(EST_Wave &sig, const EST_String &in_file,
360  EST_Option &al)
361 {
362  char *sr;
363  EST_String fname, file_type, sample_type;
364  int sample_rate;
365  EST_read_status rval;
366  int num_channels;
367  int offset=0, length=0;
368  int bo;
369 
370  if (in_file == "-")
371  fname = stdin_to_file();
372  else
373  fname = in_file;
374 
375  if (al.present("-n"))
376  num_channels = al.ival("-n", 0);
377  else
378  num_channels = 1;
379 
380  if (al.present("-ulaw"))
381  {
382  al.add_item("-itype","ulaw");
383  al.add_item("-f","8000");
384  }
385  if (al.present("-iswap"))
386  al.add_item("-ibo","other");
387 
388  if (al.present("-istype"))
389  sample_type = al.val("-istype");
390  else
391  sample_type = sig.sample_type(); // else default type;
392 
393  if (al.present("-itype"))
394  file_type = al.val("-itype"); // else default type;
395  else
396  file_type = "undef";
397 
398 
399  if (al.present("-f"))
400  sample_rate = al.ival("-f", 0);
401  else if ((sr = getenv("NA_PLAY_SAMPLE_RATE")) != NULL)
402  {
403  sample_rate = atoi(sr);
404  cerr << "Warning: no sample rate specified, " <<
405  " using NA_PLAY_SAMPLE_RATE environment variable\n";
406  }
407  else
408  {
409  sample_rate = EST_Wave::default_sample_rate;
410  if (file_type == "raw")
411  cerr << "Warning: no sample rate specified - using default " <<
412  sample_rate << endl;
413  }
414 
415  if (file_type == "ulaw")
416  {
417  sample_rate = 8000;
418  sample_type = "mulaw";
419  }
420 
421  if (al.present("-r")) // only load in part of waveform
422  {
423  if (parse_esps_r_option(al.val("-r"), offset, length) != 0)
424  return read_error;
425  }
426  else
427  offset = length = 0;
428 
429  if (al.present("-iswap"))
430  bo = str_to_bo("swap");
431  else
432  bo = str_to_bo("native");
433  if (al.present("-ibo")) // can override -iswap
434  bo = str_to_bo(al.val("-ibo"));
435 
436  if (file_type == "" ||file_type == "undef")
437  rval = sig.load(fname, offset, length, sample_rate);
438  else
439  rval = sig.load_file(fname,file_type, sample_rate,
440  sample_type, bo, num_channels, offset, length);
441 
442  if ((rval == wrong_format) && (al.present("-basic")))
443  {
444  // For HTML audio/basic, it seems to mean headered or ulaw 8k
445  // so try to load it again as ulaw 8k.
446  rval = sig.load_file(fname, "raw", 8000,
447  "mulaw", bo, 1, offset, length);
448  }
449  if (rval != format_ok)
450  {
451  if (in_file == "-") unlink(fname);
452  cerr << "Cannot recognize file format or cannot access file: \"" << in_file << "\"\n";
453  return read_error;
454  }
455 
456  if (al.present("-start") || al.present("-end")
457  || al.present("-to") || al.present("-from"))
458  extract(sig, al);
459 
460  if (in_file == "-") unlink(fname);
461  return read_ok;
462 }
463 
464 EST_write_status write_wave(EST_Wave &sig, const EST_String &out_file,
465  EST_Option &al)
466 {
467  EST_String file_type, sample_type;
468  int bo;
469 
470  if (al.present("-otype"))
471  file_type = al.val("-otype");
472  else
473  file_type = sig.file_type();
474 
475  if (al.present("-ostype"))
476  sample_type = al.val("-ostype");
477  else
478  sample_type = "undef";
479 
480  if (al.present("-oswap"))
481  bo = str_to_bo("swap");
482  else
483  bo = str_to_bo("native");
484 
485  if (al.present("-obo")) // can over ride -oswap
486  bo = str_to_bo(al.val("-obo"));
487 
488  if (sample_type == "undef" || sample_type == "")
489  sample_type = "short";
490 
491  if (sig.save_file(out_file, file_type,
492  sample_type, bo) != write_ok)
493  {
494  cerr << "Cannot write file: \"" << out_file << "\"\n";
495  return write_error;
496  }
497 
498  return write_ok;
499 }
500 
501 EST_String EST_WaveFile::options_short(void)
502 {
503  EST_String s("");
504 
505  for(int n=0; n< EST_WaveFile::map.n() ; n++)
506  {
507  const char *nm = EST_WaveFile::map.name(EST_WaveFile::map.token(n));
508 
509  if (s != "")
510  s += ", ";
511 
512  s += nm;
513 
514  }
515  return s;
516 }
517 
518 EST_String EST_WaveFile::options_supported(void)
519 {
520  EST_String s("Available wave file formats:\n");
521 
522  for(int n=0; n< EST_WaveFile::map.n() ; n++)
523  {
524  const char *nm = EST_WaveFile::map.name(EST_WaveFile::map.token(n));
525  const char *d = EST_WaveFile::map.info(EST_WaveFile::map.token(n)).description;
526 
527  s += EST_String::cat(" ", nm, EST_String(" ")*(12-strlen(nm)), d, "\n");
528  }
529  return s;
530 }
531 
532 typedef struct TInfo {
533  bool recognise;
534  const char *description;
535 } TInfo;
536 
537 // note the order here defines the order in which loads are tried.
538 
539 
540 static
542 {
543  { wff_none, { NULL },
544  { FALSE, NULL, NULL, "unknown track file type"} },
545  { wff_nist, { "nist", "timit" },
546  { TRUE, EST_WaveFile::load_nist, EST_WaveFile::save_nist, "nist/timit" } },
547  { wff_est, { "est"},
548  { TRUE, EST_WaveFile::load_est, EST_WaveFile::save_est, "est" } },
549  { wff_esps, { "esps", "sd"},
550  { TRUE, EST_WaveFile::load_esps, EST_WaveFile::save_esps, "esps SD waveform" } },
551  { wff_audlab, { "audlab", "vox"},
552  { TRUE, EST_WaveFile::load_audlab, EST_WaveFile::save_audlab, "audlab waveform" } },
553  { wff_snd, { "snd", "au"},
554  { TRUE, EST_WaveFile::load_snd, EST_WaveFile::save_snd, "Sun snd file" } },
555  { wff_aiff, { "aiff" },
556  { TRUE, EST_WaveFile::load_aiff, EST_WaveFile::save_aiff, "Apple aiff file" } },
557  { wff_riff, { "riff", "wav" },
558  { TRUE, EST_WaveFile::load_riff, EST_WaveFile::save_riff, "Microsoft wav/riff file" } },
559  { wff_raw, { "raw" },
560  { FALSE, EST_WaveFile::load_raw, EST_WaveFile::save_raw, "Headerless File" } },
561  { wff_ulaw, { "ulaw", "basic" },
562  { FALSE, EST_WaveFile::load_ulaw, EST_WaveFile::save_ulaw, "Headerless 8K ulaw File" } },
563  { wff_none, {NULL} }
564 };
565 
566 EST_TNamedEnumI<EST_WaveFileType, EST_WaveFile::Info> EST_WaveFile::map(wavefile_names);
567 
568 #if defined(INSTANTIATE_TEMPLATES)
569 
570 #include "../base_class/EST_TNamedEnum.cc"
572 template class EST_TValuedEnumI<EST_WaveFileType, const char *,
573 EST_WaveFile::Info>;
574 
575 #endif