shithub: sox

Download patch

ref: 22b6b7d61db4e1e79ce2e4513fa3912048bc67ff
parent: 04652d1e92a99906156e60aac3527f93a708c8ff
author: robs <robs>
date: Tue Feb 12 17:22:07 EST 2008

Various clean-ups; set (modern) sensible default signal params.
Attempt to fix rec bits-per-sample bug.
Pushing playlist stuff into libSoX.

--- a/soxformat.7
+++ b/soxformat.7
@@ -155,7 +155,7 @@
 The filename specified is used to determine which libao plugin to
 us.  Normally, you should specify "default" as the filename.  If that
 doesn't give the desired behavior then you can specify the short name
-for a given plugin (such as pulse for pulse audio plugin).
+for a given plugin (such as \fBpulse\fR for pulse audio plugin).
 .TP
 \&\fB.au\fR, \fB.snd\fR \fB(also with \-t sndfile)\fR
 Sun Microsystems AU files.
@@ -297,7 +297,7 @@
 Mac users will need their usual arsenal of file converters
 to deal with an HCOM file on other systems.
 .TP
-.B ircam (also with \-t sndfile)
+.B .ircam (also with \-t sndfile)
 Another name for
 .BR .sf .
 .TP
--- a/src/aiff.c
+++ b/src/aiff.c
@@ -422,7 +422,7 @@
                 if ((ft->signal.channels == 0)
                         || (ft->signal.rate == 0)
                         || (ft->signal.encoding == SOX_ENCODING_UNKNOWN)
-                        || (ft->signal.size == -1)) {
+                        || (ft->signal.size == 0)) {
                   sox_report("You must specify # channels, sample rate, signed/unsigned,");
                   sox_report("and 8/16 on the command line.");
                   sox_fail_errno(ft,SOX_EFMT,"Bogus AIFF file: no COMM section.");
@@ -716,7 +716,7 @@
 
         /* If we've written an odd number of bytes, write a padding
            NUL */
-        if (aiff->nsamples % 2 == 1 && ft->signal.size == 1 && ft->signal.channels == 1)
+        if (aiff->nsamples % 2 == 1 && ft->signal.size == SOX_SIZE_8BIT && ft->signal.channels == 1)
         {
             sox_sample_t buf = 0;
             sox_rawwrite(ft, &buf, 1);
@@ -922,7 +922,7 @@
 
         /* If we've written an odd number of bytes, write a padding
            NUL */
-        if (aiff->nsamples % 2 == 1 && ft->signal.size == 1 && ft->signal.channels == 1)
+        if (aiff->nsamples % 2 == 1 && ft->signal.size == SOX_SIZE_8BIT && ft->signal.channels == 1)
         {
             sox_sample_t buf = 0;
             sox_rawwrite(ft, &buf, 1);
--- a/src/alsa.c
+++ b/src/alsa.c
@@ -22,9 +22,6 @@
 
 static int get_format(sox_format_t * ft, snd_pcm_format_mask_t *fmask, int *fmt)
 {
-    if (ft->signal.size == -1)
-        ft->signal.size = SOX_SIZE_16BIT;
-
     if (ft->signal.size != SOX_SIZE_16BIT)
     {
         sox_report("trying for word samples.");
@@ -36,11 +33,13 @@
     {
         if (ft->signal.size == SOX_SIZE_16BIT)
         {
+          if (ft->signal.encoding != SOX_ENCODING_UNKNOWN)
             sox_report("driver supports only signed and unsigned samples.  Changing to signed.");
             ft->signal.encoding = SOX_ENCODING_SIGN2;
         }
         else
         {
+          if (ft->signal.encoding != SOX_ENCODING_UNKNOWN)
             sox_report("driver supports only signed and unsigned samples.  Changing to unsigned.");
             ft->signal.encoding = SOX_ENCODING_UNSIGNED;
         }
@@ -70,12 +69,12 @@
         if ((snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_U16)) ||
             (snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_S16)))
         {
-            sox_report("driver doesn't supported %s samples.  Changing to words.", sox_sizes_str[(unsigned char)ft->signal.size]);
+            sox_report("driver doesn't supported %s samples.  Changing to words.", sox_sizes_str[ft->signal.size]);
             ft->signal.size = SOX_SIZE_16BIT;
         }
         else
         {
-            sox_report("driver doesn't supported %s samples.  Changing to bytes.", sox_sizes_str[(unsigned char)ft->signal.size]);
+            sox_report("driver doesn't supported %s samples.  Changing to bytes.", sox_sizes_str[ft->signal.size]);
             ft->signal.size = SOX_SIZE_BYTE;
         }
     }
@@ -166,7 +165,7 @@
     }
     else {
         sox_fail_errno(ft,SOX_EFMT,"ALSA driver does not support %s %s output",
-                      sox_encodings_str[(unsigned char)ft->signal.encoding], sox_sizes_str[(unsigned char)ft->signal.size]);
+                      sox_encodings_str[(unsigned char)ft->signal.encoding], sox_sizes_str[ft->signal.size]);
         return SOX_EOF;
     }
     return 0;
@@ -185,7 +184,10 @@
     snd_pcm_uframes_t period_size, period_size_min, period_size_max;
     int dir;
     snd_pcm_format_mask_t *fmask = NULL;
+    sox_signalinfo_t client_signal = ft->signal;
 
+    set_signal_defaults(&ft->signal);
+
     if ((err = snd_pcm_open(&(alsa->pcm_handle), ft->filename, 
                             mode, 0)) < 0) 
     {
@@ -257,6 +259,7 @@
     rate = range_limit(ft->signal.rate, min_rate, max_rate);
     if (rate != ft->signal.rate)
     {
+      if (client_signal.rate != 0)
         sox_report("hardware does not support sample rate %g; changing to %i.", ft->signal.rate, rate);
         ft->signal.rate = rate;
     }
--- a/src/ao.c
+++ b/src/ao.c
@@ -43,6 +43,7 @@
 {
   ao_priv_t ao = (ao_priv_t)ft->priv;
 
+  set_signal_defaults(&ft->signal);
   if (ft->signal.size != SOX_SIZE_16BIT || 
       ft->signal.encoding != SOX_ENCODING_SIGN2)
   {
--- a/src/au.c
+++ b/src/au.c
@@ -62,7 +62,7 @@
 
 static void auwriteheader(sox_format_t * ft, sox_size_t data_size);
 
-static int sox_auencodingandsize(uint32_t sun_encoding, sox_encoding_t * encoding, int * size)
+static int sox_auencodingandsize(uint32_t sun_encoding, sox_encoding_t * encoding, unsigned * size)
 {
     switch (sun_encoding) {
     case SUN_ULAW:
@@ -417,16 +417,15 @@
         if (encoding == SUN_ENCODING_UNKNOWN) {
           sox_report("Unsupported output encoding/size for Sun/NeXT header or .AU format not specified.");
           sox_report("Only u-law, A-law, and signed 8/16/24 bits are supported.");
-          if (ft->signal.size > 2) {
+          if (ft->signal.size > SOX_SIZE_16BIT) {
             sox_report("Defaulting to signed 24 bit");
             ft->signal.encoding = SOX_ENCODING_SIGN2;
             ft->signal.size = SOX_SIZE_24BIT;
             encoding = SUN_LIN_24;
           }
-          else if (ft->signal.size == 2) {
+          else if (ft->signal.size == SOX_SIZE_16BIT) {
             sox_report("Defaulting to signed 16 bit");
             ft->signal.encoding = SOX_ENCODING_SIGN2;
-            ft->signal.size = SOX_SIZE_16BIT;
             encoding = SUN_LIN_16;
           }
           else {
--- a/src/earwax.c
+++ b/src/earwax.c
@@ -68,7 +68,7 @@
   assert_static(EARWAX_NUMTAPS * sizeof(*taps) <= SOX_MAX_EFFECT_PRIVSIZE,
                 /* else */ earwax_PRIVSIZE_too_big);
   if (effp->ininfo.rate != 44100 || effp->ininfo.channels != 2) {
-    sox_fail("works only with 44.1kHz stereo audio");
+    sox_fail("works only with stereo audio sampled at 44100Hz (i.e. CDDA)");
     return SOX_EOF;
   }
   memset(taps, 0, EARWAX_NUMTAPS * sizeof(*taps)); /* zero tap memory */
--- a/src/nulfile.c
+++ b/src/nulfile.c
@@ -1,5 +1,5 @@
 /*
- * File format: null   (c) 2006-7 SoX contributors
+ * File format: null   (c) 2006-8 SoX contributors
  * Based on an original idea by Carsten Borchardt
  *
  * This library is free software; you can redistribute it and/or modify it
@@ -22,20 +22,19 @@
 
 static int startread(sox_format_t * ft)
 {
-  /* If format parameters are not given, set somewhat arbitrary
-   * (but commonly used) defaults: */
   if (!ft->signal.rate) {
-    ft->signal.rate = 44100;
+    ft->signal.rate = SOX_DEFAULT_RATE;
     sox_report("sample rate not specified; using %g", ft->signal.rate);
   }
-  if (ft->signal.size <= 0) {
-    ft->signal.size = SOX_SIZE_16BIT;
+  if (!ft->signal.size) {
+    ft->signal.size = SOX_DEFAULT_SIZE;
     sox_report("precision not specified; using %s", sox_size_bits_str[ft->signal.size]);
   }
   if (ft->signal.encoding == SOX_ENCODING_UNKNOWN) {
-    ft->signal.encoding = SOX_ENCODING_SIGN2;
+    ft->signal.encoding = SOX_DEFAULT_ENCODING;
     sox_report("encoding not specified; using %s", sox_encodings_str[ft->signal.encoding]);
   }
+  /* Default number of channels is application-dependent */
   return SOX_SUCCESS;
 }
 
--- a/src/oss.c
+++ b/src/oss.c
@@ -46,9 +46,9 @@
     int sampletype, samplesize, dsp_stereo;
     int tmp, rc;
     sox_fileinfo_t *file = (sox_fileinfo_t *)ft->priv;
+    sox_signalinfo_t client_signal = ft->signal;
 
-    if (ft->signal.rate == 0.0) ft->signal.rate = 8000;
-    if (ft->signal.size == -1) ft->signal.size = SOX_SIZE_BYTE;
+    set_signal_defaults(&ft->signal);
     if (ft->signal.size == SOX_SIZE_BYTE) {
         sampletype = AFMT_U8;
         samplesize = 8;
@@ -88,8 +88,7 @@
         sox_report("Forcing to signed linear word");
     }
 
-    if (ft->signal.channels == 0) ft->signal.channels = 1;
-    else if (ft->signal.channels > 2) ft->signal.channels = 2;
+    if (ft->signal.channels > 2) ft->signal.channels = 2;
 
     if (ioctl(fileno(ft->fp), SNDCTL_DSP_RESET, 0) < 0)
     {
@@ -159,6 +158,7 @@
 
     if (tmp != dsp_stereo)
     {
+      if (client_signal.channels != 0)
         sox_warn("Sound card appears to only support %d channels.  Overriding format", tmp+1);
         ft->signal.channels = tmp + 1;
     }
@@ -176,6 +176,7 @@
          */
         if ((int)ft->signal.rate - tmp > (tmp * .01) || 
             tmp - (int)ft->signal.rate > (tmp * .01)) {
+          if (client_signal.rate != 0)
             sox_warn("Unable to set audio speed to %g (set to %d)",
                      ft->signal.rate, tmp);
             ft->signal.rate = tmp;
--- a/src/raw-fmt.c
+++ b/src/raw-fmt.c
@@ -11,7 +11,7 @@
 #include "sox_i.h"
  
 static int raw_start(sox_format_t * ft) {
-  return sox_rawstart(ft,sox_false,sox_false,SOX_ENCODING_UNKNOWN,-1);
+  return sox_rawstart(ft, sox_false, sox_false, SOX_ENCODING_UNKNOWN, 0);
 }
 
 const sox_format_handler_t *sox_raw_format_fn(void);
@@ -21,8 +21,8 @@
   static char const * names[] = {"raw", NULL};
   static sox_format_handler_t handler = {
     names, SOX_FILE_SEEK,
-    raw_start, sox_rawread , sox_format_nothing,
-    raw_start, sox_rawwrite, sox_format_nothing,
+    raw_start, sox_rawread , NULL,
+    raw_start, sox_rawwrite, NULL,
     sox_rawseek
   };
   return &handler;
--- a/src/raw.c
+++ b/src/raw.c
@@ -54,7 +54,7 @@
 
 /* Works nicely for starting read and write; sox_rawstart{read,write}
    are #defined in sox_i.h */
-int sox_rawstart(sox_format_t * ft, sox_bool default_rate, sox_bool default_channels, sox_encoding_t encoding, int size)
+int sox_rawstart(sox_format_t * ft, sox_bool default_rate, sox_bool default_channels, sox_encoding_t encoding, unsigned size)
 {
   if (default_rate && ft->signal.rate == 0) {
     sox_warn("'%s': sample rate not specified; trying 8kHz", ft->filename);
@@ -74,9 +74,8 @@
     else ft->signal.encoding = encoding;
   }
 
-  if (size != -1) {
-    if (ft->mode == 'r' &&
-        ft->signal.size != -1 && ft->signal.size != size)
+  if (size != 0) {
+    if (ft->mode == 'r' && ft->signal.size != 0 && ft->signal.size != size)
       sox_report("'%s': Format options overriding file-type sample-size", ft->filename);
     else ft->signal.size = size;
   }
--- a/src/reverb.c
+++ b/src/reverb.c
@@ -66,7 +66,7 @@
     double scale, double offset)
 {
   size_t i;
-  double r = rate * (1 / 44100.);
+  double r = rate * (1 / 44100.); /* Compensate for actual sample-rate */
 
   for (i = 0; i < array_length(comb_lengths); ++i, offset = -offset)
     filter_create(&p->comb[i], scale * r * (comb_lengths[i] + stereo_adjust * offset) + .5);
--- a/src/skelform.c
+++ b/src/skelform.c
@@ -58,8 +58,8 @@
    * If your format contains a header with format information
    * then you should set it here.
    */
-  ft->signal.rate =  44100;
-  ft->signal.size = SOX_SIZE_BYTE; /* or WORD ... */
+  ft->signal.rate = 44100; /* or 8000, 16000, 32000, 48000, ... */
+  ft->signal.size = SOX_SIZE_8BIT; /* or 16BIT ... */
   ft->signal.encoding = SOX_ENCODING_UNSIGNED; /* or SIGN2 ... */
   ft->signal.channels = 1; /* or 2 or 4 */
   append_comment(&ft->comments, "any comment in file header.");
@@ -91,7 +91,7 @@
       break;
     sample = fgetc(ft->fp);
     switch (ft->signal.size) {
-    case SOX_SIZE_BYTE:
+    case SOX_SIZE_8BIT:
       switch (ft->signal.encoding) {
       case SOX_ENCODING_UNSIGNED:
         *buf++ = SOX_UNSIGNED_8BIT_TO_SAMPLE(sample,);
@@ -136,7 +136,7 @@
   if (ft->signal.rate != 44100)
     sox_fail("Output .skel file must have a sample rate of 44100Hz");
 
-  if (ft->signal.size == -1) {
+  if (ft->signal.size == 0) {
     sox_fail("Did not specify a size for .skel output file");
     return SOX_EOF;
   }
@@ -160,7 +160,7 @@
   skelform_t UNUSED sk = (skelform_t)ft->priv;
 
   switch (ft->signal.size) {
-  case SOX_SIZE_BYTE:
+  case SOX_SIZE_8BIT:
     switch (ft->signal.encoding) {
     case SOX_ENCODING_UNSIGNED:
       while (len--) {
--- a/src/sndfile.c
+++ b/src/sndfile.c
@@ -77,7 +77,7 @@
    is encoding if conversion was made, or SOX_ENCODING_UNKNOWN for
    invalid input. If the libsndfile subtype can't be represented in
    SoX types, use 16-bit signed. */
-static sox_encoding_t sox_encoding_and_size(int format, int *size)
+static sox_encoding_t sox_encoding_and_size(int format, unsigned * size)
 {
   *size = -1;                   /* Default */
   format &= SF_FORMAT_SUBMASK;
--- a/src/sox.c
+++ b/src/sox.c
@@ -25,7 +25,6 @@
 #include "sox_i.h"
 #include "getopt.h"
 
-#include <ctype.h>
 #include <errno.h>
 #include <math.h>
 #include <signal.h>
@@ -124,7 +123,6 @@
 static sox_effects_chain_t ofile_effects_chain;
 
 
-
 /* Flowing */
 
 static sox_signalinfo_t combiner, ofile_signal;
@@ -137,12 +135,12 @@
 static sox_bool user_skip = sox_false;
 static int success = 0;
 
+
 /* local forward declarations */
 
 static sox_bool parse_gopts_and_fopts(file_t, int, char **);
 static int process(void);
 static void display_status(sox_bool all_done);
-static void report_file_info(file_t f);
 
 
 static void display_SoX_version(FILE * file)
@@ -158,28 +156,41 @@
 static void display_supported_formats(void)
 {
   size_t i, formats;
-  const char **format_list;
+  char const * * format_list;
+  char const * const * names;
 
-  printf("SUPPORTED FILE FORMATS:");
   for (i = 0, formats = 0; i < sox_formats; i++) {
     char const * const *names = sox_format_fns[i].fn()->names;
     while (*names++)
       formats++;
   }
-  formats += 2;
   format_list = (const char **)xmalloc(formats * sizeof(char *));
+
+  printf("AUDIO FILE FORMATS:");
   for (i = 0, formats = 0; i < sox_formats; i++) {
-    char const * const *names = sox_format_fns[i].fn()->names;
-    while (*names)
-      format_list[formats++] = *names++;
+    sox_format_handler_t const * handler = sox_format_fns[i].fn();
+    if (!(handler->flags & SOX_FILE_DEVICE))
+      for (names = handler->names; *names; ++names)
+        format_list[formats++] = *names;
   }
-  format_list[formats++] = "m3u";
-  format_list[formats++] = "pls";
   qsort(format_list, formats, sizeof(char *), strcmp_p);
   for (i = 0; i < formats; i++)
     printf(" %s", format_list[i]);
-  free(format_list);
+  putchar('\n');
+
+  printf("PLAYLIST FORMATS: m3u pls\nAUDIO DEVICES:");
+  for (i = 0, formats = 0; i < sox_formats; i++) {
+    sox_format_handler_t const * handler = sox_format_fns[i].fn();
+    if ((handler->flags & SOX_FILE_DEVICE) && !(handler->flags & SOX_FILE_PHONY))
+      for (names = handler->names; *names; ++names)
+        format_list[formats++] = *names;
+  }
+  qsort(format_list, formats, sizeof(char *), strcmp_p);
+  for (i = 0; i < formats; i++)
+    printf(" %s", format_list[i]);
   puts("\n");
+
+  free(format_list);
 }
 
 static void display_supported_effects(void)
@@ -187,7 +198,7 @@
   size_t i;
   const sox_effect_handler_t *e;
 
-  printf("SUPPORTED EFFECTS:");
+  printf("EFFECTS:");
   for (i = 0; sox_effect_fns[i]; i++) {
     e = sox_effect_fns[i]();
     if (e && e->name && !(e->flags & SOX_EFF_DEPRECATED))
@@ -355,65 +366,65 @@
   return string[i];
 }
 
-static void display_file_info(file_t f, sox_bool full)
+static void display_file_info(sox_format_t * ft, file_t f, sox_bool full)
 {
   static char const * const no_yes[] = {"no", "yes"};
   FILE * const output = sox_mode == sox_soxi? stdout : stderr;
 
   fprintf(output, "\n%s: '%s'",
-    f->ft->mode == 'r'? "Input File     " : "Output File    ", f->ft->filename);
-  if (strcmp(f->ft->filename, "-") == 0 || (f->ft->handler->flags & SOX_FILE_DEVICE))
-    fprintf(output, " (%s)", f->ft->handler->names[0]);
+    ft->mode == 'r'? "Input File     " : "Output File    ", ft->filename);
+  if (strcmp(ft->filename, "-") == 0 || (ft->handler->flags & SOX_FILE_DEVICE))
+    fprintf(output, " (%s)", ft->handler->names[0]);
   fprintf(output, "\n");
 
-  if (f->ft->signal.size)
+  if (ft->signal.size)
     fprintf(output, "Sample Size    : %s (%s)\n",
-        sox_size_bits_str[f->ft->signal.size],
-        sox_sizes_str[f->ft->signal.size]);
+        sox_size_bits_str[ft->signal.size],
+        sox_sizes_str[ft->signal.size]);
 
-  if (f->ft->signal.encoding)
+  if (ft->signal.encoding)
     fprintf(output, "Sample Encoding: %s\n",
-        sox_encodings_str[f->ft->signal.encoding]);
+        sox_encodings_str[ft->signal.encoding]);
 
   fprintf(output,
     "Channels       : %u\n"
     "Sample Rate    : %g\n",
-    f->ft->signal.channels,
-    f->ft->signal.rate);
+    ft->signal.channels,
+    ft->signal.rate);
 
-  if (f->ft->length && f->ft->signal.channels && f->ft->signal.rate) {
-    sox_size_t ws = f->ft->length / f->ft->signal.channels;
+  if (ft->length && ft->signal.channels && ft->signal.rate) {
+    sox_size_t ws = ft->length / ft->signal.channels;
     fprintf(output,
       "Duration       : %s = %u samples %c %g CDDA sectors\n",
-      str_time((double)ws / f->ft->signal.rate),
-      ws, "~="[f->ft->signal.rate == 44100],
-      (double)ws/ f->ft->signal.rate * 44100 / 588);
+      str_time((double)ws / ft->signal.rate),
+      ws, "~="[ft->signal.rate == 44100],
+      (double)ws/ ft->signal.rate * 44100 / 588);
   }
   if (full) {
-    if (f->ft->signal.size > 1)
+    if (ft->signal.size > 1)
       fprintf(output, "Endian Type    : %s\n",
-          f->ft->signal.reverse_bytes != SOX_IS_BIGENDIAN ? "big" : "little");
-    if (f->ft->signal.size)
+          ft->signal.reverse_bytes != SOX_IS_BIGENDIAN ? "big" : "little");
+    if (ft->signal.size)
       fprintf(output,
         "Reverse Nibbles: %s\n"
         "Reverse Bits   : %s\n",
-        no_yes[f->ft->signal.reverse_nibbles],
-        no_yes[f->ft->signal.reverse_bits]);
+        no_yes[ft->signal.reverse_nibbles],
+        no_yes[ft->signal.reverse_bits]);
   }
 
-  if (f->replay_gain != HUGE_VAL)
+  if (f && f->replay_gain != HUGE_VAL)
     fprintf(output, "Replay gain    : %+g dB\n" , f->replay_gain);
-  if (f->volume != HUGE_VAL)
+  if (f && f->volume != HUGE_VAL)
     fprintf(output, "Level adjust   : %g (linear gain)\n" , f->volume);
 
-  if (!(f->ft->handler->flags & SOX_FILE_DEVICE) && f->ft->comments) {
-    if (num_comments(f->ft->comments) > 1) {
-      comments_t p = f->ft->comments;
+  if (!(ft->handler->flags & SOX_FILE_DEVICE) && ft->comments) {
+    if (num_comments(ft->comments) > 1) {
+      comments_t p = ft->comments;
       fprintf(output, "Comments       : \n");
       do fprintf(output, "%s\n", *p);
       while (*++p);
     }
-    else fprintf(output, "Comment        : '%s'\n", f->ft->comments[0]);
+    else fprintf(output, "Comment        : '%s'\n", ft->comments[0]);
   }
   fprintf(output, "\n");
 }
@@ -421,7 +432,7 @@
 static void report_file_info(file_t f)
 {
   if (sox_globals.verbosity > 2)
-    display_file_info(f, sox_true);
+    display_file_info(f->ft, f, sox_true);
 }
 
 static void progress_to_file(file_t f)
@@ -434,7 +445,7 @@
   input_wide_samples = f->ft->length / f->ft->signal.channels;
   if (show_progress && (sox_globals.verbosity < 3 ||
                         (combine_method <= sox_concatenate && input_count > 1)))
-    display_file_info(f, sox_false);
+    display_file_info(f->ft, f, sox_false);
   if (f->volume == HUGE_VAL)
     f->volume = 1;
   if (f->replay_gain != HUGE_VAL)
@@ -455,14 +466,9 @@
   return ret;
 }
 
-static file_t new_file(void)
+static void init_file(file_t f)
 {
-  file_t f = xcalloc(sizeof(*f), 1);
-
-  f->signal.size = -1;
-  f->signal.encoding = SOX_ENCODING_UNKNOWN;
-  f->signal.channels = 0;
-  f->signal.rate = 0;
+  memset(f, 0, sizeof(*f));
   f->signal.reverse_bytes = SOX_OPTION_DEFAULT;
   f->signal.reverse_nibbles = SOX_OPTION_DEFAULT;
   f->signal.reverse_bits = SOX_OPTION_DEFAULT;
@@ -469,52 +475,8 @@
   f->signal.compression = HUGE_VAL;
   f->volume = HUGE_VAL;
   f->replay_gain = HUGE_VAL;
-  f->volume_clips = 0;
-
-  return f;
 }
 
-static void set_device(file_t f, sox_bool recording UNUSED)
-{
-#if defined(HAVE_ALSA)
-  if (sox_find_format("alsa", sox_false))
-  {
-    f->filetype = "alsa";
-    f->filename = xstrdup("default");
-    return;
-  }
-#endif
-#if defined(HAVE_SYS_SOUNDCARD_H) || defined(HAVE_MACHINE_SOUNDCARD_H)
-  if (sox_find_format("ossdsp", sox_false))
-  {
-    f->filetype = "ossdsp";
-    f->filename = xstrdup("/dev/dsp");
-    return;
-  }
-#endif
-#if defined(HAVE_SYS_AUDIOIO_H) || defined(HAVE_SUN_AUDIOIO_H)
-  if (sox_find_format("sunau", sox_false))
-  {
-    char *device = getenv("AUDIODEV");
-    f->filetype = "sunau";
-    f->filename = xstrdup(device ? device : "/dev/audio");
-    return;
-  }
-#endif
-#ifdef HAVE_LIBAO
-  if (!recording) {
-    if (sox_find_format("ao", sox_false))
-    {
-        f->filetype = "ao";
-        f->filename = xstrdup("default");
-        return;
-    }
-  }
-#endif
-  sox_fail("Sorry, there is no default audio device configured");
-  exit(1);
-}
-
 static void set_replay_gain(comments_t comments, file_t f)
 {
   rg_mode rg = replay_gain_mode;
@@ -534,118 +496,32 @@
   }
 }
 
-static sox_bool is_playlist(char const * filename)
-{
-  return strcaseends(filename, ".m3u") || strcaseends(filename, ".pls");
-}
-
-typedef int (* playlist_callback_t)(void *, char *);
-
-static void parse_playlist(playlist_callback_t callback, void * p, char const * const listname)
-{
-  sox_bool is_pls = strcaseends(listname, ".pls");
-  int comment_char = "#;"[is_pls];
-  size_t text_length = 100;
-  char * text = xmalloc(text_length + 1);
-  char * dirname = xstrdup(listname);
-  char * slash_pos = LAST_SLASH(dirname);
-  FILE * file = xfopen(listname, "r");
-  char * filename;
-  int c;
-
-  if (!slash_pos)
-    *dirname = '\0';
-  else
-    *slash_pos = '\0';
-
-  if (file == NULL) {
-    sox_fail("Can't open playlist file `%s': %s", listname, strerror(errno));
-    exit(1);
-  }
-
-  do {
-    size_t i = 0;
-    size_t begin = 0, end = 0;
-
-    while (isspace(c = getc(file)));
-    if (c == EOF)
-      break;
-    while (c != EOF && !strchr("\r\n", c) && c != comment_char) {
-      if (i == text_length)
-        text = xrealloc(text, (text_length <<= 1) + 1);
-      text[i++] = c;
-      if (!strchr(" \t\f", c))
-        end = i;
-      c = getc(file);
-    }
-    if (ferror(file))
-      break;
-    if (c == comment_char) {
-      do c = getc(file);
-      while (c != EOF && !strchr("\r\n", c));
-      if (ferror(file))
-        break;
-    }
-    text[end] = '\0';
-    if (is_pls) {
-      char dummy;
-      if (!strncasecmp(text, "file", 4) && sscanf(text + 4, "%*u=%c", &dummy) == 1)
-        begin = strchr(text + 5, '=') - text + 1;
-      else end = 0;
-    }
-    if (begin != end) {
-      char const * id = text + begin;
-
-      if (!dirname[0] || is_uri(id) || IS_ABSOLUTE(id))
-        filename = xstrdup(id);
-      else {
-        filename = xmalloc(strlen(dirname) + strlen(id) + 2); 
-        sprintf(filename, "%s/%s", dirname, id); 
-      }
-      if (is_playlist(filename)) {
-        parse_playlist(callback, p, filename);
-        free(filename);
-      }
-      else if (callback(p, filename))
-        break;
-    }
-  } while (c != EOF);
-  if (ferror(file)) {
-    sox_fail("Error reading playlist file `%s': %s", listname, strerror(errno));
-    exit(1);
-  }
-  fclose(file);
-  free(text);
-  free(dirname);
-}
-
 typedef enum {
   full, rate, channels, samples, duration, bits, encoding, annotation} soxi_t;
 
 static int soxi1(soxi_t * type, char * filename)
 {
-  file_t f = new_file();
-  f->filename = filename;
-  if ((f->ft = sox_open_read(f->filename, NULL, NULL))) {
-    sox_size_t ws = f->ft->length / max(f->ft->signal.channels, 1);
-    switch (*type) {
-      case rate: printf("%g\n", f->ft->signal.rate); break;
-      case channels: printf("%u\n", f->ft->signal.channels); break;
-      case samples: printf("%u\n", ws); break;
-      case duration: printf("%s\n", str_time((double)ws / max(f->ft->signal.rate, 1))); break;
-      case bits: printf("%s\n", sox_size_bits_str[f->ft->signal.size]); break;
-      case encoding: printf("%s\n", sox_encodings_str[f->ft->signal.encoding]); break;
-      case annotation: if (f->ft->comments) {
-        comments_t p = f->ft->comments;
-        do printf("%s\n", *p); while (*++p);
-      }
-      break;
-      case full: display_file_info(f, sox_false); break;
+  sox_size_t ws;
+  sox_format_t * ft = sox_open_read(filename, NULL, NULL);
+
+  if (!ft)
+    return 1;
+  ws = ft->length / max(ft->signal.channels, 1);
+  switch (*type) {
+    case rate: printf("%g\n", ft->signal.rate); break;
+    case channels: printf("%u\n", ft->signal.channels); break;
+    case samples: printf("%u\n", ws); break;
+    case duration: printf("%s\n", str_time((double)ws / max(ft->signal.rate, 1))); break;
+    case bits: printf("%s\n", sox_size_bits_str[ft->signal.size]); break;
+    case encoding: printf("%s\n", sox_encodings_str[ft->signal.encoding]); break;
+    case annotation: if (ft->comments) {
+      comments_t p = ft->comments;
+      do printf("%s\n", *p); while (*++p);
     }
-    sox_close(f->ft);
+    break;
+    case full: display_file_info(ft, NULL, sox_false); break;
   }
-  free(f);
-  return 0;
+  return !!sox_close(ft);
 }
 
 static void soxi(int argc, char * const * argv)
@@ -652,31 +528,61 @@
 {
   static char const opts[] = "rcsdbea?";
   soxi_t type = full;
-  int opt;
+  int opt, num_errors = 0;
 
-  while ((opt = getopt(argc, argv, opts)) > 0)
+  while ((opt = getopt(argc, argv, opts)) > 0) /* act only on last option */
     type = 1 + (strchr(opts, opt) - opts);
   if (type > annotation)
     printf("Usage: soxi [-r|-c|-s|-d|-b|-e|-a] infile1 ...\n");
   else for (; optind < argc; ++optind) {
-    if (is_playlist(argv[optind]))
-      parse_playlist((playlist_callback_t)soxi1, &type, argv[optind]);
-    else soxi1(&type, argv[optind]);
+    if (sox_is_playlist(argv[optind]))
+      num_errors += (sox_parse_playlist((sox_playlist_callback_t)soxi1, &type, argv[optind]) != SOX_SUCCESS);
+    else num_errors += soxi1(&type, argv[optind]);
   }
-  exit(0);
+  exit(num_errors);
 }
 
-static int add_file(file_t f0, char * filename)
+static char const * device_name(char const * const type)
 {
-  file_t f;
+  char * name = NULL, * from_env = getenv("AUDIODEV");
 
+  if (!type)
+    return NULL;
+  if (!strcmp(type, "sunau")) name = "/dev/audio";
+  else if (!strcmp(type, "oss" ) || !strcmp(type, "ossdsp")) name = "/dev/dsp";
+  else if (!strcmp(type, "alsa") || !strcmp(type, "ao"))     name = "default";
+  return name? from_env? from_env : name : NULL;
+}
+
+static char const * set_default_device(file_t f)
+{
+  /* Default audio device type in order of preference: */
+  if (!f->filetype) f->filetype = getenv("AUDIOTYPE");
+  if (!f->filetype && sox_find_format("alsa", sox_false)) f->filetype = "alsa";
+  if (!f->filetype && sox_find_format("oss" , sox_false)) f->filetype = "oss";
+  if (!f->filetype && sox_find_format("sunau",sox_false)) f->filetype = "sunau";
+  if (!f->filetype && sox_find_format("ao"  , sox_false) && file_count) /*!rec*/
+    f->filetype = "ao";
+
+  if (!f->filetype) {
+    sox_fail("Sorry, there is no default audio device configured");
+    exit(1);
+  }
+  return device_name(f->filetype);
+}
+
+static int add_file(struct file_info const * const opts, char const * const filename)
+{
+  file_t f = xmalloc(sizeof(*f));
+
   if (file_count >= MAX_FILES) {
-    sox_fail("Too many filenames; maximum is %d input files and 1 output file", MAX_INPUT_FILES);
+    sox_fail("too many files; maximum is %d input files (and 1 output file)", MAX_INPUT_FILES);
     exit(1);
   }
-  f = new_file();
-  *f = *f0;
-  f->filename = filename;
+  *f = *opts;
+  if (!filename)
+    usage("missing filename"); /* No return */
+  f->filename = xstrdup(filename);
   files[file_count++] = f;
   return 0;
 }
@@ -683,70 +589,30 @@
 
 static void parse_options_and_filenames(int argc, char **argv)
 {
-  file_t f = NULL;
-  struct file_info fi_none;
+  struct file_info opts, opts_none;
+  init_file(&opts), init_file(&opts_none);
 
-  while (optind < argc && !sox_find_effect(argv[optind])) {
-    f = new_file();
-    fi_none = *f;
+  if (sox_mode == sox_rec)
+    add_file(&opts, set_default_device(&opts)), init_file(&opts);
 
-    if (file_count >= MAX_FILES) {
-      sox_fail("Too many filenames; maximum is %d input files and 1 output file", MAX_INPUT_FILES);
-      exit(1);
+  for (; optind < argc && !sox_find_effect(argv[optind]); init_file(&opts)) {
+    if (parse_gopts_and_fopts(&opts, argc, argv)) { /* is null file? */
+      if (opts.filetype != NULL && strcmp(opts.filetype, "null") != 0)
+        sox_warn("Ignoring `-t %s'.", opts.filetype);
+      opts.filetype = "null";
+      add_file(&opts, "");
     }
-
-    if (parse_gopts_and_fopts(f, argc, argv)) { /* is null file? */
-      if (f->filetype != NULL && strcmp(f->filetype, "null") != 0)
-        sox_warn("Ignoring `-t %s'.", f->filetype);
-      f->filetype = "null";
-      f->filename = xstrdup("-n");
-    } else {
-      if (optind >= argc || sox_find_effect(argv[optind]))
-        break;
-      if (is_playlist(argv[optind])) {
-        parse_playlist((playlist_callback_t)add_file, f, argv[optind++]);
-        free(f);
-        f = NULL;
-        continue;
-      }
-      f->filename = xstrdup(argv[optind++]);
-    }
-    files[file_count++] = f;
-    f = NULL;
-  }
-
-  if (sox_mode == sox_play) {
-    if (file_count >= MAX_FILES) {
-      sox_fail("Too many filenames; maximum is %d input files and 1 output file", MAX_INPUT_FILES);
+    else if (optind >= argc || sox_find_effect(argv[optind]))
+      break;
+    else if (!sox_is_playlist(argv[optind]))
+      add_file(&opts, argv[optind++]);
+    else if (sox_parse_playlist((sox_playlist_callback_t)add_file, &opts, argv[optind++]) != SOX_SUCCESS)
       exit(1);
-    }
-
-    f = f ? f : new_file();
-    set_device(f, sox_false);
-    files[file_count++] = f;
   }
-  else if (f) {
-    if (memcmp(f, &fi_none, sizeof(*f)) != 0) /* fopts but no file */
-      usage("missing filename"); /* No return */
-    free(f); /* No file opts and no filename, so that's okay */
-  }
-
-  if (sox_mode == sox_rec) {
-    sox_size_t i;
-
-    if (file_count >= MAX_FILES) {
-      sox_fail("Too many filenames; maximum is %d input files and 1 output file", MAX_INPUT_FILES);
-      exit(1);
-    }
-
-    for (i = file_count; i > 0; i--)
-      files[i] = files[i - 1];
-    file_count++;
-
-    f = new_file();
-    files[0] = f;
-    set_device(f, sox_true);
-  }
+  if (sox_mode == sox_play)
+    add_file(&opts, set_default_device(&opts));
+  else if (memcmp(&opts, &opts_none, sizeof(opts))) /* fopts but no file */
+    add_file(&opts, device_name(opts.filetype));
 }
 
 static void parse_effects(int argc, char **argv)
@@ -830,15 +696,10 @@
     if (combine_method == sox_mix && !uservolume)
       f->volume = 1.0 / input_count;
 
-    if (sox_mode == sox_rec && !j) { /* Set the recording sample rate & # of channels: */
-      if (input_count > 1) {   /* Get them from the next input file: */
-        f->signal.rate = files[1]->ft->signal.rate;
-        f->signal.channels = files[1]->ft->signal.channels;
-      }
-      else { /* Get them from the output file (which is not open yet): */
-        f->signal.rate = files[1]->signal.rate;
-        f->signal.channels = files[1]->signal.channels;
-      }
+    if (sox_mode == sox_rec && !j) {       /* Set the recording parameters: */
+      if (input_count > 1)                 /* from the (just openned) next */
+        f->signal = files[1]->ft->signal;  /* input file, or from the output */
+      else f->signal = files[1]->signal;   /* file (which is not open yet). */
     }
     files[j]->ft = sox_open_read(f->filename, &f->signal, f->filetype);
     if (!files[j]->ft)
@@ -1173,12 +1034,12 @@
     case 'g': f->signal.encoding = SOX_ENCODING_GSM;       break;
 
     case 'U': f->signal.encoding = SOX_ENCODING_ULAW;
-      if (f->signal.size == -1)
+      if (f->signal.size == 0)
         f->signal.size = SOX_SIZE_BYTE;
       break;
 
     case 'A': f->signal.encoding = SOX_ENCODING_ALAW;
-      if (f->signal.size == -1)
+      if (f->signal.size == 0)
         f->signal.size = SOX_SIZE_BYTE;
       break;
 
@@ -1593,7 +1454,7 @@
   ofile->signal = ofile_signal;
   if (ofile->signal.rate == 0)
     ofile->signal.rate = combiner.rate;
-  if (ofile->signal.size == -1)
+  if (ofile->signal.size == 0)
     ofile->signal.size = combiner.size;
   if (ofile->signal.encoding == SOX_ENCODING_UNKNOWN)
     ofile->signal.encoding = combiner.encoding;
--- a/src/sox.h
+++ b/src/sox.h
@@ -208,11 +208,11 @@
 
 typedef struct sox_signalinfo
 {
-    sox_rate_t rate;       /* sampling rate */
-    int size;             /* compressed or uncompressed datum size */
+    sox_rate_t rate;         /* sampling rate */
+    unsigned channels;       /* number of sound channels */
+    unsigned size;           /* compressed or uncompressed datum size */
     sox_encoding_t encoding; /* format of sample numbers */
-    unsigned channels;    /* number of sound channels */
-    double compression;   /* compression factor (where applicable) */
+    double compression;      /* compression factor (where applicable) */
 
     /* There is a delineation between these vars being tri-state and
      * effectively boolean.  Logically the line falls between setting
@@ -232,6 +232,12 @@
     sox_option_t reverse_bits;
 } sox_signalinfo_t;
 
+/* Defaults for common hardware */
+#define SOX_DEFAULT_CHANNELS  2
+#define SOX_DEFAULT_RATE      48000
+#define SOX_DEFAULT_SIZE      SOX_SIZE_16BIT
+#define SOX_DEFAULT_ENCODING  SOX_ENCODING_SIGN2
+
 /* Loop parameters */
 
 typedef struct  sox_loopinfo
@@ -452,5 +458,9 @@
  */
 sox_size_t sox_trim_get_start(sox_effect_t * effp);
 void sox_trim_clear_start(sox_effect_t * effp);
+
+typedef int (* sox_playlist_callback_t)(void *, char *);
+sox_bool sox_is_playlist(char const * filename);
+int sox_parse_playlist(sox_playlist_callback_t callback, void * p, char const * const listname);
 
 #endif
--- a/src/sox_i.h
+++ b/src/sox_i.h
@@ -145,6 +145,7 @@
 size_t sox_writebuf(sox_format_t * ft, void const *buf, sox_size_t len);
 int sox_reads(sox_format_t * ft, char *c, sox_size_t len);
 int sox_writes(sox_format_t * ft, char const * c);
+void set_signal_defaults(sox_signalinfo_t * signal);
 void set_endianness_if_not_already_set(sox_format_t * ft);
 
 sox_size_t sox_read_b_buf(sox_format_t * ft, uint8_t *buf, sox_size_t len);
@@ -328,8 +329,8 @@
 sox_size_t sox_format_nothing_write(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len);
 int sox_format_nothing_seek(sox_format_t * ft, sox_size_t offset);
 
-int sox_rawstart(sox_format_t * ft, sox_bool default_rate, sox_bool default_channels, sox_encoding_t encoding, int size);
-#define sox_rawstartread(ft) sox_rawstart(ft, sox_false, sox_false, SOX_ENCODING_UNKNOWN, -1)
+int sox_rawstart(sox_format_t * ft, sox_bool default_rate, sox_bool default_channels, sox_encoding_t encoding, unsigned size);
+#define sox_rawstartread(ft) sox_rawstart(ft, sox_false, sox_false, SOX_ENCODING_UNKNOWN, 0)
 #define sox_rawstartwrite sox_rawstartread
 #define sox_rawstopread sox_format_nothing
 #define sox_rawstopwrite sox_format_nothing
--- a/src/soxio.c
+++ b/src/soxio.c
@@ -1,5 +1,6 @@
 #include "sox_i.h"
 
+#include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <math.h>
@@ -110,6 +111,13 @@
 #endif
 }
 
+void set_signal_defaults(sox_signalinfo_t * signal)
+{
+  if (!signal->rate    ) signal->rate     = SOX_DEFAULT_RATE;
+  if (!signal->size    ) signal->size     = SOX_DEFAULT_SIZE;
+  if (!signal->channels) signal->channels = SOX_DEFAULT_CHANNELS;
+}
+
 void set_endianness_if_not_already_set(sox_format_t * ft)
 {
   if (ft->signal.reverse_bytes == SOX_OPTION_DEFAULT) {
@@ -158,7 +166,7 @@
                 return SOX_EOF;
         }
 
-        if (ft->signal.size == -1)
+        if (!ft->signal.size)
         {
                 sox_fail_errno(ft,SOX_EFMT,"data size was not specified");
                 return SOX_EOF;
@@ -170,9 +178,9 @@
                 return SOX_EOF;
         }
 
-        if ((ft->signal.size <= 0) || (ft->signal.size > SOX_INFO_SIZE_MAX))
+        if (ft->signal.size > SOX_INFO_SIZE_MAX)
         {
-                sox_fail_errno(ft,SOX_EFMT,"data size %d is invalid", ft->signal.size);
+                sox_fail_errno(ft,SOX_EFMT,"data size %u is invalid", ft->signal.size);
                 return SOX_EOF;
         }
 
@@ -207,7 +215,7 @@
       sox_fail("Can't open input file `%s': %s", ft->filename, ft->sox_errstr);
       goto input_error;
     }
-    ft->signal.size = -1;
+    ft->signal.size = 0;
     ft->signal.encoding = SOX_ENCODING_UNKNOWN;
     ft->signal.channels = 0;
     ft->signal.compression = HUGE_VAL;
@@ -300,7 +308,7 @@
       sox_fail("Can't open output file `%s': %s", ft->filename, ft->sox_errstr);
       goto output_error;
     }
-    ft->signal.size = -1;
+    ft->signal.size = 0;
     ft->signal.encoding = SOX_ENCODING_UNKNOWN;
     ft->signal.channels = 0;
     ft->signal.compression = HUGE_VAL;
@@ -552,3 +560,87 @@
     else
         return SOX_EOF; /* FIXME: return SOX_EBADF */
 }
+
+sox_bool sox_is_playlist(char const * filename)
+{
+  return strcaseends(filename, ".m3u") || strcaseends(filename, ".pls");
+}
+
+int sox_parse_playlist(sox_playlist_callback_t callback, void * p, char const * const listname)
+{
+  sox_bool const is_pls = strcaseends(listname, ".pls");
+  int const comment_char = "#;"[is_pls];
+  size_t text_length = 100;
+  char * text = xmalloc(text_length + 1);
+  char * dirname = xstrdup(listname);
+  char * slash_pos = LAST_SLASH(dirname);
+  FILE * file = xfopen(listname, "r");
+  char * filename;
+  int c, result = SOX_SUCCESS;
+
+  if (!slash_pos)
+    *dirname = '\0';
+  else
+    *slash_pos = '\0';
+
+  if (file == NULL) {
+    sox_fail("Can't open playlist file `%s': %s", listname, strerror(errno));
+    result = SOX_EOF;
+  }
+  else do {
+    size_t i = 0;
+    size_t begin = 0, end = 0;
+
+    while (isspace(c = getc(file)));
+    if (c == EOF)
+      break;
+    while (c != EOF && !strchr("\r\n", c) && c != comment_char) {
+      if (i == text_length)
+        text = xrealloc(text, (text_length <<= 1) + 1);
+      text[i++] = c;
+      if (!strchr(" \t\f", c))
+        end = i;
+      c = getc(file);
+    }
+    if (ferror(file))
+      break;
+    if (c == comment_char) {
+      do c = getc(file);
+      while (c != EOF && !strchr("\r\n", c));
+      if (ferror(file))
+        break;
+    }
+    text[end] = '\0';
+    if (is_pls) {
+      char dummy;
+      if (!strncasecmp(text, "file", 4) && sscanf(text + 4, "%*u=%c", &dummy) == 1)
+        begin = strchr(text + 5, '=') - text + 1;
+      else end = 0;
+    }
+    if (begin != end) {
+      char const * id = text + begin;
+
+      if (!dirname[0] || is_uri(id) || IS_ABSOLUTE(id))
+        filename = xstrdup(id);
+      else {
+        filename = xmalloc(strlen(dirname) + strlen(id) + 2); 
+        sprintf(filename, "%s/%s", dirname, id); 
+      }
+      if (sox_is_playlist(filename))
+        sox_parse_playlist(callback, p, filename);
+      else if (callback(p, filename))
+        c = EOF;
+      free(filename);
+    }
+  } while (c != EOF);
+
+  if (ferror(file)) {
+    sox_fail("Error reading playlist file `%s': %s", listname, strerror(errno));
+    result = SOX_EOF;
+  }
+  if (file) fclose(file);
+  free(text);
+  free(dirname);
+  return result;
+}
+
--- a/src/sphere.c
+++ b/src/sphere.c
@@ -72,7 +72,7 @@
 
         while (strncmp(buf, "end_head", 8) != 0)
         {
-            if (strncmp(buf, "sample_n_bytes", 14) == 0 && ft->signal.size == -1)
+            if (strncmp(buf, "sample_n_bytes", 14) == 0 && !ft->signal.size)
             {
                 sscanf(buf, "%63s %15s %d", fldname, fldtype, &i);
                 ft->signal.size = i;
@@ -120,7 +120,7 @@
             header_size -= (strlen(buf) + 1);
         }
 
-        if (ft->signal.size == -1)
+        if (!ft->signal.size)
             ft->signal.size = SOX_SIZE_BYTE;
 
         /* sample_coding is optional and is PCM if missing.
@@ -129,7 +129,7 @@
          */
         if (ft->signal.encoding == SOX_ENCODING_UNKNOWN)
         {
-            if (ft->signal.size == 1)
+            if (ft->signal.size == SOX_SIZE_8BIT)
                 ft->signal.encoding = SOX_ENCODING_UNSIGNED;
             else
                 ft->signal.encoding = SOX_ENCODING_SIGN2;
--- a/src/sunaudio.c
+++ b/src/sunaudio.c
@@ -52,6 +52,8 @@
 #endif
     char simple_hw=0;
 
+    set_signal_defaults(&ft->signal);
+
     /* Hard-code for now. */
     file->count = 0;
     file->pos = 0;
@@ -58,8 +60,6 @@
     file->size = 1024;
     file->buf = xmalloc (file->size);
 
-    if (ft->signal.rate == 0.0) ft->signal.rate = 8000;
-    if (ft->signal.size == -1) ft->signal.size = SOX_SIZE_BYTE;
     if (ft->signal.encoding == SOX_ENCODING_UNKNOWN) ft->signal.encoding = SOX_ENCODING_ULAW;
 
 #ifdef __SVR4
@@ -188,6 +188,8 @@
 #endif
     char simple_hw=0;
 
+    set_signal_defaults(&ft->signal);
+
     /* Hard-code for now. */
     file->count = 0;
     file->pos = 0;
@@ -226,15 +228,12 @@
         }
     }
 
-    if (ft->signal.rate == 0.0) ft->signal.rate = 8000;
-    if (ft->signal.size == -1) ft->signal.size = SOX_SIZE_BYTE;
-    if (ft->signal.encoding == SOX_ENCODING_UNKNOWN) 
-        ft->signal.encoding = SOX_ENCODING_ULAW;
-
     if (ft->signal.size == SOX_SIZE_BYTE) 
     {
         samplesize = 8;
-        if (ft->signal.encoding != SOX_ENCODING_ULAW &&
+        if (ft->signal.encoding == SOX_ENCODING_UNKNOWN) 
+            ft->signal.encoding = SOX_ENCODING_ULAW;
+        else if (ft->signal.encoding != SOX_ENCODING_ULAW &&
             ft->signal.encoding != SOX_ENCODING_ALAW &&
             ft->signal.encoding != SOX_ENCODING_SIGN2) {
             sox_report("Sun Audio driver only supports ULAW, ALAW, and Signed Linear for bytes.");
@@ -252,7 +251,9 @@
     }
     else if (ft->signal.size == SOX_SIZE_16BIT) {
         samplesize = 16;
-        if (ft->signal.encoding != SOX_ENCODING_SIGN2) {
+        if (ft->signal.encoding == SOX_ENCODING_UNKNOWN) 
+            ft->signal.encoding = SOX_ENCODING_SIGN2;
+        else if (ft->signal.encoding != SOX_ENCODING_SIGN2) {
             sox_report("Sun Audio driver only supports Signed Linear for words.");
             sox_report("Forcing to Signed Linear");
             ft->signal.encoding = SOX_ENCODING_SIGN2;
@@ -261,11 +262,11 @@
     else {
         sox_report("Sun Audio driver only supports bytes and words");
         ft->signal.size = SOX_SIZE_16BIT;
+        ft->signal.encoding = SOX_ENCODING_SIGN2;
         samplesize = 16;
     }
 
-    if (ft->signal.channels == 0) ft->signal.channels = 1;
-    else if (ft->signal.channels > 1) ft->signal.channels = 2;
+    if (ft->signal.channels > 1) ft->signal.channels = 2;
 
     /* Read in old values, change to what we need and then send back */
     if (ioctl(fileno(ft->fp), AUDIO_GETINFO, &audio_if) < 0) {
--- a/src/tests.sh
+++ b/src/tests.sh
@@ -221,7 +221,7 @@
 samples=10000000
 timeIO s1 u1 s2 u2 s3 u3 s4 u4 raw Raw au wav aiff aifc caf sph # FIXME?: flac dat
 
-${bindir}/sox -c 1 -n output.u1 synth .01 vol .5
+${bindir}/sox -c 1 -r 44100 -n output.u1 synth .01 vol .5
 if [ `wc -c <output.u1` = 441 ]; then
   echo "ok     synth size"
 else
--- a/src/wav.c
+++ b/src/wav.c
@@ -759,7 +759,7 @@
         
     case SOX_SIZE_BYTE:
         /* User options take precedence */
-        if (ft->signal.size == -1 || ft->signal.size == SOX_SIZE_BYTE)
+        if (!ft->signal.size || ft->signal.size == SOX_SIZE_BYTE)
             ft->signal.size = SOX_SIZE_BYTE;
         else
             sox_warn("User options overriding size read in .wav header");
@@ -770,7 +770,7 @@
         break;
         
     case SOX_SIZE_16BIT:
-        if (ft->signal.size == -1 || ft->signal.size == SOX_SIZE_16BIT)
+        if (!ft->signal.size || ft->signal.size == SOX_SIZE_16BIT)
             ft->signal.size = SOX_SIZE_16BIT;
         else
             sox_warn("User options overriding size read in .wav header");
@@ -781,7 +781,7 @@
         break;
         
     case SOX_SIZE_24BIT:
-        if (ft->signal.size == -1 || ft->signal.size == SOX_SIZE_24BIT)
+        if (!ft->signal.size || ft->signal.size == SOX_SIZE_24BIT)
             ft->signal.size = SOX_SIZE_24BIT;
         else
             sox_warn("User options overriding size read in .wav header");
@@ -792,7 +792,7 @@
         break;
         
     case SOX_SIZE_32BIT:
-        if (ft->signal.size == -1 || ft->signal.size == SOX_SIZE_32BIT)
+        if (!ft->signal.size || ft->signal.size == SOX_SIZE_32BIT)
             ft->signal.size = SOX_SIZE_32BIT;
         else
             sox_warn("User options overriding size read in .wav header");
--- a/src/xa.c
+++ b/src/xa.c
@@ -132,7 +132,7 @@
     /* Populate the sox_soundstream structure */
     ft->signal.encoding = SOX_ENCODING_SIGN2;
     
-    if (ft->signal.size == -1 || ft->signal.size == (xa->header.bits >> 3)) {
+    if (!ft->signal.size || ft->signal.size == (xa->header.bits >> 3)) {
         ft->signal.size = xa->header.bits >> 3;
     } else {
         sox_report("User options overriding size read in .xa header");