Logo Search packages:      
Sourcecode: speech-tools version File versions  Download package

EST_WaveFile.cc

 /*************************************************************************/
 /*                                                                       */
 /*                Centre for Speech Technology Research                  */
 /*                     University of Edinburgh, UK                       */
 /*                      Copyright (c) 1995,1996                          */
 /*                        All Rights Reserved.                           */
 /*                                                                       */
 /*  Permission is hereby granted, free of charge, to use and distribute  */
 /*  this software and its documentation without restriction, including   */
 /*  without limitation the rights to use, copy, modify, merge, publish,  */
 /*  distribute, sublicense, and/or sell copies of this work, and to      */
 /*  permit persons to whom this work is furnished to do so, subject to   */
 /*  the following conditions:                                            */
 /*   1. The code must retain the above copyright notice, this list of    */
 /*      conditions and the following disclaimer.                         */
 /*   2. Any modifications must be clearly marked as such.                */
 /*   3. Original authors' names are not deleted.                         */
 /*   4. The authors' names are not used to endorse or promote products   */
 /*      derived from this software without specific prior written        */
 /*      permission.                                                      */
 /*                                                                       */
 /*  THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK        */
 /*  DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING      */
 /*  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT   */
 /*  SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE     */
 /*  FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES    */
 /*  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN   */
 /*  AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,          */
 /*  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF       */
 /*  THIS SOFTWARE.                                                       */
 /*                                                                       */
 /*************************************************************************/
 /*                                                                       */
 /*             Author : Richard Caley <rjc@cstr.ed.ac.uk>                */
 /* -------------------------------------------------------------------   */
 /* Wave file input and output.                                           */
 /*                                                                       */
 /*************************************************************************/
#include <stdlib.h>
#include "EST_Wave.h"
#include "EST_WaveFile.h"
#include "waveP.h"
#include "EST_cutils.h"
#include "EST_Option.h"
#include "EST_io_aux.h"
#include "stdio.h"
#include "math.h"

void extract(EST_Wave &sig, EST_Option &al);

typedef 
EST_read_status (*standard_load_fn_fp)(EST_TokenStream &ts,
                            short **data, int *nsamp, int *nchan, 
                            int *wsize, 
                            int *srate, 
                            EST_sample_type_t *stype, int *bo,
                            int offset, int length);

typedef 
EST_write_status (*standard_save_fn_fp)(FILE *fp,
                            const short *data,
                            int offset, int nsamp,
                            int nchan, int srate,
                            EST_sample_type_t stype, int bo);
                            
  
static 
EST_read_status load_using(standard_load_fn_fp fn,
                     EST_TokenStream &ts,
                          EST_Wave &wv,
                          int rate,
                            EST_sample_type_t stype, int bo, int nchan,
                          int offset, int length)
{
  short *data;
  int nsamp;
  int wsize;
  int srate = rate;

  EST_read_status status =  (*fn)(ts, 
                          &data, &nsamp, &nchan, 
                          &wsize, 
                          &srate, &stype, &bo,
                          offset, length);

  if (status == read_ok)
    {
      wv.values().set_memory(data, 0, nsamp, nchan, TRUE);
      wv.set_sample_rate(srate);
    }

  return status;
}

static
EST_write_status save_using(standard_save_fn_fp fn,
                      FILE *fp, const EST_Wave wv,
                      EST_sample_type_t stype, int bo)
{
EST_write_status status =  (*fn)(fp,
                        wv.values().memory(), 
                        0, wv.num_samples(), wv.num_channels(),
                        wv.sample_rate(),
                        stype, bo);

return status; 
}

EST_read_status EST_WaveFile::load_nist(EST_TokenStream &ts,
                    EST_Wave &wv,
                    int rate,
                    EST_sample_type_t stype, int bo, int nchan,
                    int offset, int length)
{
  return load_using(load_wave_nist,
                ts, wv, rate,
                stype, bo, nchan,
                offset, length);
}

EST_write_status EST_WaveFile::save_nist(FILE *fp,
                               const EST_Wave &wv,
                               EST_sample_type_t stype, int bo)
{
  return save_using(save_wave_nist, fp, wv, stype, bo);
}

EST_read_status EST_WaveFile::load_est(EST_TokenStream &ts,
                    EST_Wave &wv,
                    int rate,
                    EST_sample_type_t stype, int bo, int nchan,
                    int offset, int length)
{
    (void) ts;
    return load_using(load_wave_est,
                ts, wv, rate,
                stype, bo, nchan,
                offset, length);

}

EST_write_status EST_WaveFile::save_est(FILE *fp,
                               const EST_Wave &wv,
                               EST_sample_type_t stype, int bo)
{
  return save_using(save_wave_est,
                fp, wv,
                stype, bo);

}

EST_read_status EST_WaveFile::load_aiff(EST_TokenStream &ts, 
                    EST_Wave &wv,
                    int rate,
                    EST_sample_type_t stype, int bo, int nchan,
                    int offset, int length)
{
  return load_using(load_wave_aiff,
                ts, wv,  rate, 
                stype, bo, nchan,
                offset, length);
}

EST_write_status EST_WaveFile::save_aiff(FILE *fp,
                               const EST_Wave &wv,
                               EST_sample_type_t stype, int bo)
{
  return save_using(save_wave_aiff, fp, wv, stype, bo);
}


EST_read_status EST_WaveFile::load_riff(EST_TokenStream &ts,
                    EST_Wave &wv,
                    int rate,
                    EST_sample_type_t stype, int bo, int nchan,
                    int offset, int length)
{
  return load_using(load_wave_riff,
                ts, wv, rate, 
                stype, bo, nchan,
                offset, length);
}

EST_write_status EST_WaveFile::save_riff(FILE *fp,
                               const EST_Wave &wv,
                               EST_sample_type_t stype, int bo)
{
  return save_using(save_wave_riff, fp, wv, stype, bo);
}


EST_read_status EST_WaveFile::load_esps(EST_TokenStream &ts, 
                    EST_Wave &wv,
                    int rate,
                    EST_sample_type_t stype, int bo, int nchan,
                    int offset, int length)
{
  return load_using(load_wave_sd,
                ts, wv, rate, 
                stype, bo, nchan,
                offset, length);
}

EST_write_status EST_WaveFile::save_esps(FILE *fp,
                               const EST_Wave &wv,
                               EST_sample_type_t stype, int bo)
{
  return save_using(save_wave_sd,
                fp, wv,
                stype, bo);
}


EST_read_status EST_WaveFile::load_audlab(EST_TokenStream &ts, 
                    EST_Wave &wv,
                    int rate,
                    EST_sample_type_t stype, int bo, int nchan,
                    int offset, int length)
{
  return load_using(load_wave_audlab,
                ts, wv, rate, 
                stype, bo, nchan,
                offset, length);
}

EST_write_status EST_WaveFile::save_audlab(FILE *fp,
                               const EST_Wave &wv,
                               EST_sample_type_t stype, int bo)
{
  return save_using(save_wave_audlab, fp, wv, stype, bo);
}


EST_read_status EST_WaveFile::load_snd(EST_TokenStream &ts, 
                    EST_Wave &wv,
                    int rate,
                    EST_sample_type_t stype, int bo, int nchan,
                    int offset, int length)
{
  return load_using(load_wave_snd,
                ts, wv, rate, 
                stype, bo, nchan,
                offset, length);
}

EST_write_status EST_WaveFile::save_snd(FILE *fp,
                              const EST_Wave &wv,
                              EST_sample_type_t stype, int bo)
{
  return save_using(save_wave_snd, fp, wv, stype, bo);
}


EST_read_status EST_WaveFile::load_raw(EST_TokenStream &ts, 
                    EST_Wave &wv,
                    int rate,
                    EST_sample_type_t stype, int bo, int nchan,
                    int offset, int length)
{
  short *data;
  int nsamp;
  int wsize;
  int srate = rate;

  EST_read_status status =  load_wave_raw(ts, 
                                &data, &nsamp, &nchan, 
                                &wsize, 
                                &srate, &stype, &bo,
                                offset, length,
                                rate, stype, bo, nchan);

  if (status == read_ok)
    {
      wv.values().set_memory(data, 0, nsamp, nchan, TRUE);
      wv.set_sample_rate(srate);
    }

  return status;
}

EST_write_status EST_WaveFile::save_raw(FILE *fp,
                               const EST_Wave &wv,
                               EST_sample_type_t stype, int bo)
{
EST_write_status status =  save_wave_raw(fp,
                               (short *)wv.values().memory(), 
                               0, wv.num_samples(), wv.num_channels(),
                               wv.sample_rate(),
                               stype, bo);
return status; 
}


EST_read_status EST_WaveFile::load_ulaw(EST_TokenStream &ts,
                    EST_Wave &wv,
                    int rate,
                    EST_sample_type_t stype, int bo, int nchan,
                    int offset, int length)
{
  return load_using(load_wave_ulaw,
                ts, wv, rate, 
                stype, bo, nchan,
                offset, length);
}

EST_write_status EST_WaveFile::save_ulaw(FILE *fp,
                               const EST_Wave &wv,
                               EST_sample_type_t stype, int bo)
{
    EST_Wave localwv = wv;
    localwv.resample(8000);
    return save_using(save_wave_ulaw, fp, localwv, stype, bo);
}

static int parse_esps_r_option(EST_String arg, int &offset, int &length)
{
    EST_String s, e;

    if (arg.contains("-"))
    {
      s = arg.before("-");
      e = arg.after("-");
    }
    else if (arg.contains(":"))
    {
      s = arg.before(":");
      e = arg.after(":");
    }
    else
    {
      cerr << "Argument to -r is illformed " << arg << endl;
      return -1;
    }
    
    if (!s.matches(RXint))
    {
      cerr << "First argument to -r must be an integer " << arg << endl;
      return -1;
    }

    offset = atoi(s);
    if (e.contains("+"))
    { 
      e = e.after("+");
      length = atoi(e);
    }
    else
      length = atoi(e) - offset;

    if (length <= 0)
    {
      cerr << "length is negative or zero " << arg << endl;
      return -1;
    }

    return 0;
}

EST_read_status read_wave(EST_Wave &sig, const EST_String &in_file, 
                    EST_Option &al)
{
    char *sr;
    EST_String fname, file_type, sample_type;
    int sample_rate;
    EST_read_status rval;
    int num_channels;
    int offset, length;
    int bo;
    
    if (in_file == "-")
      fname = stdin_to_file();
    else
      fname = in_file;

    if (al.present("-n"))
      num_channels = al.ival("-n", 0);
    else 
      num_channels = 1;

    if (al.present("-ulaw"))
    {
      al.add_item("-itype","ulaw");
      al.add_item("-f","8000");
    }
    if (al.present("-iswap"))
      al.add_item("-ibo","other");

    if (al.present("-istype"))
      sample_type = al.val("-istype");
    else 
      sample_type = sig.sample_type(); // else default type;

    if (al.present("-itype"))
      file_type = al.val("-itype");  // else default type;
    else
      file_type = "undef";


    if (al.present("-f"))
      sample_rate = al.ival("-f", 0);
    else if ((sr = getenv("NA_PLAY_SAMPLE_RATE")) != NULL)
    {
      sample_rate = atoi(sr);
      cerr << "Warning: no sample rate specified, " <<
          " using NA_PLAY_SAMPLE_RATE environment variable\n";
    }
    else
    {
      sample_rate = EST_Wave::default_sample_rate;
      if (file_type == "raw")
          cerr << "Warning: no sample rate specified - using default " << 
            sample_rate << endl;
    }
    
    if (file_type == "ulaw")
    {
      sample_rate = 8000;
      sample_type = "mulaw";
    }
      
    if (al.present("-r")) // only load in part of waveform
    {
      if (parse_esps_r_option(al.val("-r"), offset, length) != 0)
          return read_error;
    }
    else
      offset = length = 0;

    if (al.present("-iswap"))
      bo = str_to_bo("swap");
    else
      bo = str_to_bo("native");
    if (al.present("-ibo"))   // can override -iswap
      bo = str_to_bo(al.val("-ibo"));

    if (file_type == "" ||file_type == "undef")
      rval = sig.load(fname, offset, length, sample_rate);
    else
      rval = sig.load_file(fname,file_type, sample_rate,
                     sample_type, bo, num_channels, offset, length);

    if ((rval == wrong_format) && (al.present("-basic")))
    {
      // For HTML audio/basic, it seems to mean headered or ulaw 8k
      // so try to load it again as ulaw 8k.
      rval = sig.load_file(fname, "raw", 8000,
                       "mulaw", bo, 1, offset, length);
    }
    if (rval != format_ok)
    {
      if (in_file == "-") unlink(fname);
      cerr << "Cannot recognize file format or cannot access file: \"" << in_file << "\"\n";
      return read_error;
    }

    if (al.present("-start") || al.present("-end") 
      || al.present("-to") || al.present("-from"))
      extract(sig, al);

    if (in_file == "-") unlink(fname);
    return read_ok;
}

EST_write_status write_wave(EST_Wave &sig, const EST_String &out_file, 
                      EST_Option &al)
{
    EST_String file_type, sample_type;
    int bo;

    if (al.present("-otype"))
      file_type = al.val("-otype");
    else
      file_type = sig.file_type();

    if (al.present("-ostype"))
      sample_type = al.val("-ostype");
    else
      sample_type = "undef";

    if (al.present("-oswap"))
      bo = str_to_bo("swap");
    else
      bo = str_to_bo("native");

    if (al.present("-obo"))   // can over ride -oswap
      bo = str_to_bo(al.val("-obo"));

    if (sample_type == "undef" || sample_type == "")
      sample_type = "short";

    if (sig.save_file(out_file, file_type,
                  sample_type, bo) != write_ok)
    {
      cerr << "Cannot write file: \"" << out_file << "\"\n";
      return write_error;
    }

    return write_ok;
}

EST_String EST_WaveFile::options_short(void)
{
    EST_String s("");
    
    for(int n=0; n< EST_WaveFile::map.n() ; n++)
    {
      const char *nm = EST_WaveFile::map.name(EST_WaveFile::map.token(n));
      
      if (s != "")
          s += ", ";
      
      s += nm;
      
    }
    return s;
}

EST_String EST_WaveFile::options_supported(void)
{
    EST_String s("Available wave file formats:\n");
    
    for(int n=0; n< EST_WaveFile::map.n() ; n++)
    {
      const char *nm = EST_WaveFile::map.name(EST_WaveFile::map.token(n));
      const char *d = EST_WaveFile::map.info(EST_WaveFile::map.token(n)).description;
      
      s += EST_String::cat("        ", nm, EST_String(" ")*(12-strlen(nm)), d, "\n");
    }
    return s;
}

typedef struct TInfo {
  bool recognise;
  const char *description;
} TInfo;

// note the order here defines the order in which loads are tried.


static 
EST_TValuedEnumDefinition<EST_WaveFileType, const char *, EST_WaveFile::Info> wavefile_names[] =
{
  { wff_none,     { NULL }, 
    { FALSE, NULL, NULL, "unknown track file type"} },
  { wff_nist,     { "nist", "timit" }, 
    { TRUE, EST_WaveFile::load_nist,  EST_WaveFile::save_nist, "nist/timit" } },
  { wff_est,      { "est"}, 
    { TRUE, EST_WaveFile::load_est,  EST_WaveFile::save_est, "est" } },
  { wff_esps,     { "esps", "sd"}, 
    { TRUE,  EST_WaveFile::load_esps,  EST_WaveFile::save_esps, "esps SD waveform" } },
  { wff_audlab, { "audlab", "vox"}, 
    { TRUE,  EST_WaveFile::load_audlab,  EST_WaveFile::save_audlab, "audlab waveform" } },
  { wff_snd,      { "snd", "au"}, 
    { TRUE,  EST_WaveFile::load_snd,  EST_WaveFile::save_snd, "Sun snd file" } },
  { wff_aiff,     { "aiff" }, 
    { TRUE,  EST_WaveFile::load_aiff,  EST_WaveFile::save_aiff, "Apple aiff file" } },
  { wff_riff,     { "riff", "wav" }, 
    { TRUE,  EST_WaveFile::load_riff,  EST_WaveFile::save_riff, "Microsoft wav/riff file" } },
  { wff_raw,      { "raw" }, 
    { FALSE,  EST_WaveFile::load_raw,  EST_WaveFile::save_raw, "Headerless File" } },
  { wff_ulaw,     { "ulaw", "basic" }, 
    { FALSE,  EST_WaveFile::load_ulaw,  EST_WaveFile::save_ulaw, "Headerless 8K ulaw  File" } },
  { wff_none,     {NULL} }
};

EST_TNamedEnumI<EST_WaveFileType, EST_WaveFile::Info> EST_WaveFile::map(wavefile_names);

#if defined(INSTANTIATE_TEMPLATES)

#include "../base_class/EST_TNamedEnum.cc"
template class EST_TNamedEnumI<EST_WaveFileType, EST_WaveFile::Info>;
template class EST_TValuedEnumI<EST_WaveFileType, const char *, 
EST_WaveFile::Info>;

#endif

Generated by  Doxygen 1.6.0   Back to index