shithub: sox

Download patch

ref: 3d4cdf3d163b9d8c6a4241ff412b785178af4865
parent: cc62528640ac1659ebdde9437fdae61710a1362e
author: robs <robs>
date: Mon Mar 3 14:20:07 EST 2008

Restructuring some internals; let me know what I've broken...

--- a/AUTHORS
+++ b/AUTHORS
@@ -15,7 +15,7 @@
 		format support, libao playback, Secret Rabbit Code
 		resampling; many fixes and much cleanup.
 	Rob Sykes		[email protected]
-                Formats: M3U, PLS, FLAC, AMR, 24bit support for popular
+                Formats: M3U, PLS, FLAC, AMR, HTK, 24bit support for popular
                 formats.
 		Effects: key, tempo, pad, bass, treble, new reverb, new
 		flanger, soft-knee companding, speed via resampling, filters
--- a/ChangeLog
+++ b/ChangeLog
@@ -24,30 +24,41 @@
 
 File formats:
 
-  o None new.
+  o New htk format.  (robs)
+  o Fix [1864216] comments mangled when writing ogg-vorbis.  (robs)
+  o Fix short noise at end of alsa playback.  (Morita Sho)
+  o Fix wve seek accuracy.  (robs)
+  o Fix lpc10 not working.  (robs)
+  o For wav & au, fix [548256] size in header wrong when piping out.  (robs)
+  o Writing aiff, aifc & cvsd now repeatable with -R.  (robs)
+  o Writing hcom no longer fails with unsupported rate--chooses
+    best match.  (robs)
+  o Au/snd: added support for 32-bit integer and 64-bit float PCM
+    encoding/decoding; display name of unsupported encoding.  (robs)
 
 Effects:
 
-  o Added effect to splice together audio sections.  (robs)
-  o Added remix effect (complements the mixer effect).  (robs)
-  o Added norm (normalise) effect.  (robs)
+  o New `splice' effect; splice together audio sections.  (robs)
+  o New `remix' effect; complements the mixer effect.  (robs)
+  o New `norm' (normalise) effect.  (robs)
+  o Fix crash on 64-bit arch. with tempo & key effects.  (Sami Liedes)
+  o Fix synth max. level setting for some output encodings.  (robs)
 
 Other new features:
 
   o Command line support for multiple file comments.  (robs)
-  o Added soxi utility to extract/display file header fields.  (robs)
-  o Added pkg-config support. (Pascal Giard)
-  o Added basic VU meter.  (robs)
-  o Added simple heuristic to detect when playing an album and set
+  o Soxi utility to extract/display file header fields.  (robs)
+  o Pkg-config support. (Pascal Giard)
+  o Basic VU meter.  (robs)
+  o Simple heuristic to detect when playing an album and set
     the default replay-gain mode to `album'.  (robs)
+  o More intelligent choice of output file format parameters when
+    type is different to that of input file.  (robs)
 
-Bug fixes:
+Other bug fixes:
 
-  o Fix [1864216] comments mangled when writing ogg-vorbis.  (robs)
-  o Fix crash on 64-bit arch. with tempo & key effects.  (Sami Liedes)
   o Fix [1890983] rec shortcut should apply bit depth (8-bit,
     16-bit, etc.) to input handler.  (robs)
-  o Fix short noise at end of alsa playback.  (Morita Sho)
 
 Internal improvements:
 
--- a/soxformat.7
+++ b/soxformat.7
@@ -295,6 +295,10 @@
 Mac users will need their usual arsenal of file converters
 to deal with an HCOM file on other systems.
 .TP
+.B .htk
+Single channel 16-bit PCM format used by HTK,
+a toolkit for building Hidden Markov Model speech processing tools.
+.TP
 .B .ircam (also with \-t sndfile)
 Another name for
 .BR .sf .
--- a/src/8svx.c
+++ b/src/8svx.c
@@ -26,7 +26,7 @@
 /*                         8SVXSTARTREAD                                */
 /*======================================================================*/
 
-static int sox_svxstartread(sox_format_t * ft)
+static int startread(sox_format_t * ft)
 {
         svx_t p = (svx_t ) ft->priv;
 
@@ -160,8 +160,8 @@
         ft->length = p->nsamples;
         ft->signal.channels = channels;
         ft->signal.rate = rate;
-        ft->signal.encoding = SOX_ENCODING_SIGN2;
-        ft->signal.size = SOX_SIZE_BYTE;
+        ft->encoding.encoding = SOX_ENCODING_SIGN2;
+        ft->encoding.bits_per_sample = 8;
 
         /* open files to channels */
         p->ch[0] = ft->fp;
@@ -193,7 +193,7 @@
 /*======================================================================*/
 /*                         8SVXREAD                                     */
 /*======================================================================*/
-static sox_size_t sox_svxread(sox_format_t * ft, sox_sample_t *buf, sox_size_t nsamp)
+static sox_size_t read_samples(sox_format_t * ft, sox_sample_t *buf, sox_size_t nsamp)
 {
         unsigned char datum;
         size_t done = 0, i;
@@ -217,7 +217,7 @@
 /*======================================================================*/
 /*                         8SVXSTOPREAD                                 */
 /*======================================================================*/
-static int sox_svxstopread(sox_format_t * ft)
+static int stopread(sox_format_t * ft)
 {
         size_t i;
 
@@ -233,7 +233,7 @@
 /*======================================================================*/
 /*                         8SVXSTARTWRITE                               */
 /*======================================================================*/
-static int sox_svxstartwrite(sox_format_t * ft)
+static int startwrite(sox_format_t * ft)
 {
         svx_t p = (svx_t ) ft->priv;
         size_t i;
@@ -249,9 +249,6 @@
         }
 
         /* write header (channel 0) */
-        ft->signal.encoding = SOX_ENCODING_SIGN2;
-        ft->signal.size = SOX_SIZE_BYTE;
-
         p->nsamples = 0;
         svxwriteheader(ft, p->nsamples);
         return(SOX_SUCCESS);
@@ -261,7 +258,7 @@
 /*                         8SVXWRITE                                    */
 /*======================================================================*/
 
-static sox_size_t sox_svxwrite(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len)
+static sox_size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len)
 {
         svx_t p = (svx_t ) ft->priv;
 
@@ -285,7 +282,7 @@
 /*                         8SVXSTOPWRITE                                */
 /*======================================================================*/
 
-static int sox_svxstopwrite(sox_format_t * ft)
+static int stopwrite(sox_format_t * ft)
 {
         svx_t p = (svx_t ) ft->priv;
 
@@ -362,27 +359,15 @@
         sox_writedw(ft, nsamples); /* samples in file */
 }
 
-/* Amiga 8SVX */
-static const char *svxnames[] = {
-  "8svx",
-  NULL
-};
-
-static sox_format_handler_t sox_svx_format = {
-  svxnames,
-  SOX_FILE_BIG_END,
-  sox_svxstartread,
-  sox_svxread,
-  sox_svxstopread,
-  sox_svxstartwrite,
-  sox_svxwrite,
-  sox_svxstopwrite,
-  NULL
-};
-
-const sox_format_handler_t *sox_svx_format_fn(void);
-
-const sox_format_handler_t *sox_svx_format_fn(void)
+SOX_FORMAT_HANDLER(svx)
 {
-    return &sox_svx_format;
+  static char const * const names[] = {"8svx", NULL};
+  static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 8, 0, 0};
+  static sox_format_handler_t const handler = {
+    names, SOX_FILE_BIG_END|SOX_FILE_MONO|SOX_FILE_STEREO|SOX_FILE_QUAD,
+    startread, read_samples, stopread,
+    startwrite, write_samples, stopwrite,
+    NULL, write_encodings, NULL
+  };
+  return &handler;
 }
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -4,6 +4,7 @@
 
 if(CMAKE_COMPILER_IS_GNUCC)
   add_definitions(-Wconversion -Werror)
+  #add_definitions(-Wno-missing-field-initializers)
 endif(CMAKE_COMPILER_IS_GNUCC)
 
 if (NOT EXTERNAL_GSM)
@@ -29,17 +30,17 @@
   echo            mixer           remix           stat
 )
 set(formats_srcs
-  8svx            cvsd            hcom            s1-fmt          u2-fmt
-  adpcm           cvsd-fmt        ima-fmt         s2-fmt          u3-fmt
-  adpcms          dat             ima_rw          s3-fmt          u4-fmt
-  aifc-fmt        dvms-fmt        la-fmt          s4-fmt          ul-fmt
-  aiff            formats         lpc10.c         sf              voc
-  aiff-fmt        g711            lu-fmt          skelform        vox
-  al-fmt          g721            maud            smp             vox-fmt
-  au              g723_24         nulfile         sndrtool        wav
-  auto            g723_40         prc             sphere          wve
-  avr             g72x            raw             tx16w           xa
-  cdr             gsm.c           raw-fmt         u1-fmt
+  8svx            cvsd            hcom            raw-fmt         u1-fmt
+  adpcm           cvsd-fmt        htk             s1-fmt          u2-fmt
+  adpcms          dat             ima-fmt         s2-fmt          u3-fmt
+  aifc-fmt        dvms-fmt        ima_rw          s3-fmt          u4-fmt
+  aiff            formats         la-fmt          s4-fmt          ul-fmt
+  aiff-fmt        g711            lpc10.c         sf              voc
+  al-fmt          g721            lu-fmt          skelform        vox
+  au              g723_24         maud            smp             vox-fmt
+  auto            g723_40         nulfile         sndrtool        wav
+  avr             g72x            prc             sphere          wve
+  cdr             gsm.c           raw             tx16w           xa
 )
 add_library(lib${PROJECT_NAME}
   ${effects_srcs}         misc                    util
--- a/src/FFT.c
+++ b/src/FFT.c
@@ -45,12 +45,12 @@
  * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
  */
 
+#include "sox_i.h"
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <math.h>
 #include <assert.h>
-
-#include "sox_i.h"
 
 #include "FFT.h"
 
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -43,7 +43,8 @@
 	  libsox_fmt_sf.la libsox_fmt_smp.la libsox_fmt_sndrtool.la	\
 	  libsox_fmt_sphere.la libsox_fmt_txw.la libsox_fmt_voc.la	\
 	  libsox_fmt_vox.la libsox_fmt_ima.la libsox_fmt_wav.la		\
-	  libsox_fmt_wve.la libsox_fmt_xa.la libsox_fmt_nul.la
+	  libsox_fmt_wve.la libsox_fmt_xa.la libsox_fmt_nul.la \
+	  libsox_fmt_htk.la
 
 # File format detection
 libsox_fmt_auto_la_SOURCES = auto.c
@@ -98,6 +99,8 @@
 libsox_fmt_gsm_la_LIBADD = libsox.la @GSM_LIBS@ @LIBGSM_LIBADD@
 libsox_fmt_hcom_la_SOURCES = hcom.c
 libsox_fmt_hcom_la_LIBADD = libsox.la
+libsox_fmt_htk_la_SOURCES = htk.c
+libsox_fmt_htk_la_LIBADD = libsox.la
 libsox_fmt_lpc10_la_SOURCES = lpc10.c
 libsox_fmt_lpc10_la_LIBADD = ../lpc10/liblpc10.la libsox.la
 libsox_fmt_maud_la_SOURCES = maud.c
@@ -219,7 +222,7 @@
   libsox_la_SOURCES += auto.c raw-fmt.c s1-fmt.c s2-fmt.c s3-fmt.c \
     s4-fmt.c u1-fmt.c u2-fmt.c u3-fmt.c u4-fmt.c al-fmt.c la-fmt.c ul-fmt.c \
     lu-fmt.c 8svx.c aiff-fmt.c aifc-fmt.c au.c avr.c cdr.c cvsd-fmt.c \
-    dvms-fmt.c dat.c gsm.c hcom.c lpc10.c maud.c prc.c sf.c sfircam.h smp.c \
+    dvms-fmt.c dat.c gsm.c hcom.c htk.c lpc10.c maud.c prc.c sf.c sfircam.h smp.c \
     sndrtool.c sphere.c tx16w.c voc.c vox-fmt.c ima-fmt.c adpcm.c adpcm.h \
     ima_rw.c ima_rw.h wav.c wav.h wve.c xa.c nulfile.c
 libsox_la_LIBADD = @GSM_LIBS@ @LIBGSM_LIBADD@
--- a/src/adpcm.c
+++ b/src/adpcm.c
@@ -32,11 +32,12 @@
  *
  */
 
+#include "sox_i.h"
+#include "adpcm.h"
+
 #include <sys/types.h>
 #include <math.h>
 #include <stdio.h>
-#include "sox_i.h"
-#include "adpcm.h"
 
 typedef struct MsState {
         sox_sample_t  step;      /* step size */
--- a/src/adpcms.c
+++ b/src/adpcms.c
@@ -140,7 +140,7 @@
 
   sox_adpcm_reset(state, type);
   
-  return sox_rawstart(ft, sox_true, sox_false, type, SOX_SIZE_16BIT);
+  return sox_rawstart(ft, sox_true, sox_false, sox_true, type, 4);
 }
 
 int sox_adpcm_oki_start(sox_format_t * ft, adpcm_io_t state)
@@ -155,14 +155,13 @@
 
 /******************************************************************************
  * Function   : sox_adpcm_read 
- * Description: Fills an internal buffer from the VOX file, converts the 
- *              OKI ADPCM 4-bit samples to 12-bit signed PCM and then scales 
- *              the samples to full range 16 bit PCM.
+ * Description: Converts the OKI ADPCM 4-bit samples to 16-bit signed PCM and
+ *              then scales the samples to full sox_sample_t range.
  * Parameters : ft     - file info structure
  *              state  - ADPCM state structure
  *              buffer - output buffer
- *              length - size of output buffer
- * Returns    : int    - number of samples returned in buffer
+ *              len    - size of output buffer
+ * Returns    :        - number of samples returned in buffer
  * Exceptions :
  * Notes      : 
  ******************************************************************************/
--- a/src/aifc-fmt.c
+++ b/src/aifc-fmt.c
@@ -1,38 +1,34 @@
 /*
- * Export module for AIFF-C format, implemented in aiff.c.
+ * File format: AIFF-C (see aiff.c)           (c) 2007-8 SoX contributors
  *
- * Copyright 1991-2007 Guido van Rossum And Sundry Contributors
- * 
- * This source code is freely redistributable and may be used for
- * any purpose.  This copyright notice must be maintained. 
- * Guido van Rossum And Sundry Contributors are not responsible for 
- * the consequences of using this software.
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
  */
 
 #include "sox_i.h"
 #include "aiff.h"
 
-static const char *aifcnames[] = {
-  "aifc",
-  "aiffc",
-  NULL
-};
-
-static sox_format_handler_t sox_aifc_format = {
-  aifcnames,
-  SOX_FILE_LOOPS | SOX_FILE_BIG_END,
-  sox_aiffstartread,
-  sox_aiffread,
-  sox_aiffstopread,
-  sox_aifcstartwrite,
-  sox_aiffwrite,
-  sox_aifcstopwrite,
-  sox_aiffseek
-};
-
-const sox_format_handler_t *sox_aifc_format_fn(void);
-
-const sox_format_handler_t *sox_aifc_format_fn(void)
+SOX_FORMAT_HANDLER(aifc)
 {
-    return &sox_aifc_format;
+  static char const * const names[] = {"aifc", "aiffc", NULL};
+  static unsigned const write_encodings[] = {
+    SOX_ENCODING_SIGN2, 32, 24, 16, 8, 0, 0};
+  static sox_format_handler_t const sox_aifc_format = {
+    names, SOX_FILE_LOOPS | SOX_FILE_BIG_END,
+    sox_aiffstartread, sox_aiffread, sox_aiffstopread,
+    sox_aifcstartwrite, sox_aiffwrite, sox_aifcstopwrite,
+    sox_aiffseek, write_encodings, NULL
+  };
+  return &sox_aifc_format;
 }
--- a/src/aiff-fmt.c
+++ b/src/aiff-fmt.c
@@ -1,38 +1,34 @@
 /*
- * Export module for AIFF format, implemented in aiff.c.
+ * File format: AIFF (see aiff.c)           (c) 2007-8 SoX contributors
  *
- * Copyright 1991-2007 Guido van Rossum And Sundry Contributors
- * 
- * This source code is freely redistributable and may be used for
- * any purpose.  This copyright notice must be maintained. 
- * Guido van Rossum And Sundry Contributors are not responsible for 
- * the consequences of using this software.
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
  */
 
 #include "sox_i.h"
 #include "aiff.h"
 
-static const char *aiffnames[] = {
-  "aiff",
-  "aif",
-  NULL
-};
-
-static sox_format_handler_t sox_aiff_format = {
-  aiffnames,
-  SOX_FILE_LOOPS | SOX_FILE_BIG_END,
-  sox_aiffstartread,
-  sox_aiffread,
-  sox_aiffstopread,
-  sox_aiffstartwrite,
-  sox_aiffwrite,
-  sox_aiffstopwrite,
-  sox_aiffseek
-};
-
-const sox_format_handler_t *sox_aiff_format_fn(void);
-
-const sox_format_handler_t *sox_aiff_format_fn(void)
+SOX_FORMAT_HANDLER(aiff)
 {
-    return &sox_aiff_format;
+  static char const * const names[] = {"aiff", "aif", NULL};
+  static unsigned const write_encodings[] = {
+    SOX_ENCODING_SIGN2, 32, 24, 16, 8, 0, 0};
+  static sox_format_handler_t const sox_aiff_format = {
+    names, SOX_FILE_LOOPS | SOX_FILE_BIG_END,
+    sox_aiffstartread, sox_aiffread, sox_aiffstopread,
+    sox_aiffstartwrite, sox_aiffwrite, sox_aiffstopwrite,
+    sox_aiffseek, write_encodings, NULL
+  };
+  return &sox_aiff_format;
 }
--- a/src/aiff.c
+++ b/src/aiff.c
@@ -51,10 +51,11 @@
 {
     aiff_t aiff = (aiff_t ) ft->priv;
     sox_size_t new_offset, channel_block, alignment;
+    sox_size_t size = ft->encoding.bits_per_sample >> 3;
 
-    new_offset = offset * ft->signal.size;
+    new_offset = offset * size;
     /* Make sure request aligns to a channel block (ie left+right) */
-    channel_block = ft->signal.channels * ft->signal.size;
+    channel_block = ft->signal.channels * size;
     alignment = new_offset % channel_block;
     /* Most common mistaken is to compute something like
      * "skip everthing upto and including this sample" so
@@ -67,7 +68,7 @@
     ft->sox_errno = sox_seeki(ft, (sox_ssize_t)new_offset, SEEK_SET);
 
     if (ft->sox_errno == SOX_SUCCESS)
-        aiff->nsamples = ft->length - (new_offset / ft->signal.size);
+        aiff->nsamples = ft->length - (new_offset / size);
 
     return(ft->sox_errno);
 }
@@ -386,33 +387,17 @@
         if (foundcomm) {
                 ft->signal.channels = channels;
                 ft->signal.rate = rate;
-                if (ft->signal.encoding != SOX_ENCODING_UNKNOWN && ft->signal.encoding != SOX_ENCODING_SIGN2)
+                if (ft->encoding.encoding != SOX_ENCODING_UNKNOWN && ft->encoding.encoding != SOX_ENCODING_SIGN2)
                     sox_report("AIFF only supports signed data.  Forcing to signed.");
-                ft->signal.encoding = SOX_ENCODING_SIGN2;
+                ft->encoding.encoding = SOX_ENCODING_SIGN2;
                 if (bits <= 8)
-                {
-                    ft->signal.size = SOX_SIZE_BYTE;
-                    if (bits < 8)
-                        sox_report("Forcing data size from %d bits to 8 bits",bits);
-                }
+                    ft->encoding.bits_per_sample = 8;
                 else if (bits <= 16)
-                {
-                    ft->signal.size = SOX_SIZE_16BIT;
-                    if (bits < 16)
-                        sox_report("Forcing data size from %d bits to 16 bits",bits);
-                }
+                    ft->encoding.bits_per_sample = 16;
                 else if (bits <= 24)
-                {
-                    ft->signal.size = SOX_SIZE_24BIT;
-                    if (bits < 24)
-                        sox_report("Forcing data size from %d bits to 24 bits",bits);
-                }
+                    ft->encoding.bits_per_sample = 24;
                 else if (bits <= 32)
-                {
-                    ft->signal.size = SOX_SIZE_32BIT;
-                    if (bits < 32)
-                        sox_report("Forcing data size from %d bits to 32 bits",bits);
-                }
+                    ft->encoding.bits_per_sample = 32;
                 else
                 {
                     sox_fail_errno(ft,SOX_EFMT,"unsupported sample size in AIFF header: %d", bits);
@@ -421,8 +406,8 @@
         } else  {
                 if ((ft->signal.channels == 0)
                         || (ft->signal.rate == 0)
-                        || (ft->signal.encoding == SOX_ENCODING_UNKNOWN)
-                        || (ft->signal.size == 0)) {
+                        || (ft->encoding.encoding == SOX_ENCODING_UNKNOWN)
+                        || (ft->encoding.bits_per_sample == 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.");
@@ -431,13 +416,13 @@
 
         }
 
-        aiff->nsamples = ssndsize / ft->signal.size;
+        aiff->nsamples = ssndsize / (ft->encoding.bits_per_sample >> 3);
 
         /* Cope with 'sowt' CD tracks as read on Macs */
         if (is_sowt)
         {
                 aiff->nsamples -= 4;
-                ft->signal.reverse_bytes = !ft->signal.reverse_bytes;
+                ft->encoding.reverse_bytes = !ft->encoding.reverse_bytes;
         }
         
         if (foundmark && !foundinstr)
@@ -680,23 +665,14 @@
             return rc;
 
         aiff->nsamples = 0;
-        if (ft->signal.encoding < SOX_ENCODING_SIZE_IS_WORD && 
-            ft->signal.size == SOX_SIZE_BYTE) {
-                sox_report("expanding compressed bytes to signed 16 bits");
-                ft->signal.encoding = SOX_ENCODING_SIGN2;
-                ft->signal.size = SOX_SIZE_16BIT;
-        }
-        if (ft->signal.encoding != SOX_ENCODING_UNKNOWN && ft->signal.encoding != SOX_ENCODING_SIGN2)
-            sox_report("AIFF only supports signed data.  Forcing to signed.");
-        ft->signal.encoding = SOX_ENCODING_SIGN2; /* We have a fixed encoding */
 
         /* Compute the "very large number" so that a maximum number
            of samples can be transmitted through a pipe without the
            risk of causing overflow when calculating the number of bytes.
-           At 48 kHz, 16 bits stereo, this gives ~3 hours of music.
-           Sorry, the AIFF format does not provide for an "infinite"
+           At 48 kHz, 16 bits stereo, this gives ~3 hours of audio.
+           Sorry, the AIFF format does not provide for an indefinite
            number of samples. */
-        return(aiffwriteheader(ft, 0x7f000000 / (ft->signal.size*ft->signal.channels)));
+        return(aiffwriteheader(ft, 0x7f000000 / ((ft->encoding.bits_per_sample>>3)*ft->signal.channels)));
 }
 
 sox_size_t sox_aiffwrite(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len)
@@ -713,7 +689,7 @@
 
         /* If we've written an odd number of bytes, write a padding
            NUL */
-        if (aiff->nsamples % 2 == 1 && ft->signal.size == SOX_SIZE_8BIT && ft->signal.channels == 1)
+        if (aiff->nsamples % 2 == 1 && ft->encoding.bits_per_sample == 8 && ft->signal.channels == 1)
         {
             sox_sample_t buf = 0;
             sox_rawwrite(ft, &buf, 1);
@@ -749,17 +725,17 @@
           hsize += 8 /* INST hdr */ + 20; /* INST chunk */
         }
 
-        if (ft->signal.encoding == SOX_ENCODING_SIGN2 && 
-            ft->signal.size == SOX_SIZE_BYTE)
+        if (ft->encoding.encoding == SOX_ENCODING_SIGN2 && 
+            ft->encoding.bits_per_sample == 8)
                 bits = 8;
-        else if (ft->signal.encoding == SOX_ENCODING_SIGN2 && 
-                 ft->signal.size == SOX_SIZE_16BIT)
+        else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 && 
+                 ft->encoding.bits_per_sample == 16)
                 bits = 16;
-        else if (ft->signal.encoding == SOX_ENCODING_SIGN2 && 
-                 ft->signal.size == SOX_SIZE_24BIT)
+        else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 && 
+                 ft->encoding.bits_per_sample == 24)
                 bits = 24;
-        else if (ft->signal.encoding == SOX_ENCODING_SIGN2 && 
-                 ft->signal.size == SOX_SIZE_32BIT)
+        else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 && 
+                 ft->encoding.bits_per_sample == 32)
                 bits = 32;
         else
         {
@@ -784,7 +760,7 @@
 
         sox_writes(ft, "FORM"); /* IFF header */
         /* file size */
-        sox_writedw(ft, hsize + nframes * ft->signal.size * ft->signal.channels); 
+        sox_writedw(ft, hsize + nframes * (ft->encoding.bits_per_sample >> 3) * ft->signal.channels); 
         sox_writes(ft, "AIFF"); /* File type */
 
         /* Now we write the COMT comment chunk using the precomputed sizes */
@@ -798,7 +774,7 @@
 
           /* time stamp of comment, Unix knows of time from 1/1/1970,
              Apple knows time from 1/1/1904 */
-          sox_writedw(ft, (unsigned)(time(NULL) + 2082844800));
+          sox_writedw(ft, (unsigned)((sox_globals.repeatable? 0 : time(NULL)) + 2082844800));
 
           /* A marker ID of 0 indicates the comment is not associated
              with a marker */
@@ -869,7 +845,7 @@
         /* SSND chunk -- describes data */
         sox_writes(ft, "SSND");
         /* chunk size */
-        sox_writedw(ft, 8 + nframes * ft->signal.channels * ft->signal.size); 
+        sox_writedw(ft, 8 + nframes * ft->signal.channels * (ft->encoding.bits_per_sample >> 3)); 
         sox_writedw(ft, 0); /* offset */
         sox_writedw(ft, 0); /* block size */
         return(SOX_SUCCESS);
@@ -886,15 +862,6 @@
             return rc;
 
         aiff->nsamples = 0;
-        if (ft->signal.encoding < SOX_ENCODING_SIZE_IS_WORD && 
-            ft->signal.size == SOX_SIZE_BYTE) {
-                sox_report("expanding compressed bytes to signed 16 bits");
-                ft->signal.encoding = SOX_ENCODING_SIGN2;
-                ft->signal.size = SOX_SIZE_16BIT;
-        }
-        if (ft->signal.encoding != SOX_ENCODING_UNKNOWN && ft->signal.encoding != SOX_ENCODING_SIGN2)
-            sox_report("AIFC only supports signed data.  Forcing to signed.");
-        ft->signal.encoding = SOX_ENCODING_SIGN2; /* We have a fixed encoding */
 
         /* Compute the "very large number" so that a maximum number
            of samples can be transmitted through a pipe without the
@@ -902,7 +869,7 @@
            At 48 kHz, 16 bits stereo, this gives ~3 hours of music.
            Sorry, the AIFC format does not provide for an "infinite"
            number of samples. */
-        return(aifcwriteheader(ft, 0x7f000000 / (ft->signal.size*ft->signal.channels)));
+        return(aifcwriteheader(ft, 0x7f000000 / ((ft->encoding.bits_per_sample >> 3)*ft->signal.channels)));
 }
 
 int sox_aifcstopwrite(sox_format_t * ft)
@@ -911,7 +878,7 @@
 
         /* If we've written an odd number of bytes, write a padding
            NUL */
-        if (aiff->nsamples % 2 == 1 && ft->signal.size == SOX_SIZE_8BIT && ft->signal.channels == 1)
+        if (aiff->nsamples % 2 == 1 && ft->encoding.bits_per_sample == 8 && ft->signal.channels == 1)
         {
             sox_sample_t buf = 0;
             sox_rawwrite(ft, &buf, 1);
@@ -937,17 +904,17 @@
                 8 /*SSND hdr*/ + 12 /*SSND chunk*/;
         unsigned bits = 0;
 
-        if (ft->signal.encoding == SOX_ENCODING_SIGN2 && 
-            ft->signal.size == SOX_SIZE_BYTE)
+        if (ft->encoding.encoding == SOX_ENCODING_SIGN2 && 
+            ft->encoding.bits_per_sample == 8)
                 bits = 8;
-        else if (ft->signal.encoding == SOX_ENCODING_SIGN2 && 
-                 ft->signal.size == SOX_SIZE_16BIT)
+        else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 && 
+                 ft->encoding.bits_per_sample == 16)
                 bits = 16;
-        else if (ft->signal.encoding == SOX_ENCODING_SIGN2 && 
-                 ft->signal.size == SOX_SIZE_24BIT)
+        else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 && 
+                 ft->encoding.bits_per_sample == 24)
                 bits = 24;
-        else if (ft->signal.encoding == SOX_ENCODING_SIGN2 && 
-                 ft->signal.size == SOX_SIZE_32BIT)
+        else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 && 
+                 ft->encoding.bits_per_sample == 32)
                 bits = 32;
         else
         {
@@ -957,7 +924,7 @@
 
         sox_writes(ft, "FORM"); /* IFF header */
         /* file size */
-        sox_writedw(ft, hsize + nframes * ft->signal.size * ft->signal.channels); 
+        sox_writedw(ft, hsize + nframes * (ft->encoding.bits_per_sample >> 3) * ft->signal.channels); 
         sox_writes(ft, "AIFC"); /* File type */
 
         /* FVER chunk */
@@ -981,7 +948,7 @@
         /* SSND chunk -- describes data */
         sox_writes(ft, "SSND");
         /* chunk size */
-        sox_writedw(ft, 8 + nframes * ft->signal.channels * ft->signal.size); 
+        sox_writedw(ft, 8 + nframes * ft->signal.channels * (ft->encoding.bits_per_sample >> 3)); 
         sox_writedw(ft, 0); /* offset */
         sox_writedw(ft, 0); /* block size */
 
--- a/src/al-fmt.c
+++ b/src/al-fmt.c
@@ -1,14 +1,22 @@
 /*
- * libSoX al raw file format
+ * File formats: raw         (c) 2007-8 SoX contributors
  *
- * Copyright 2007 Lance Norskog And Sundry Contributors
- * This source code is freely redistributable and may be used for
- * any purpose.  This copyright notice must be maintained.
- * Lance Norskog And Sundry Contributors are not responsible for
- * the consequences of using this software.
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
  */
 
 #include "sox_i.h"
 #include "raw.h"
 
-RAW_FORMAT(al, 8BIT, 0, ALAW)
+RAW_FORMAT(al, 8, 0, ALAW)
--- a/src/alsa.c
+++ b/src/alsa.c
@@ -22,46 +22,46 @@
 
 static int get_format(sox_format_t * ft, snd_pcm_format_mask_t *fmask, int *fmt)
 {
-    if (ft->signal.size != SOX_SIZE_16BIT)
+    if (ft->encoding.bits_per_sample != 16)
     {
         sox_report("trying for word samples.");
-        ft->signal.size = SOX_SIZE_16BIT;
+        ft->encoding.bits_per_sample = 16;
     }
 
-    if (ft->signal.encoding != SOX_ENCODING_SIGN2 &&
-        ft->signal.encoding != SOX_ENCODING_UNSIGNED)
+    if (ft->encoding.encoding != SOX_ENCODING_SIGN2 &&
+        ft->encoding.encoding != SOX_ENCODING_UNSIGNED)
     {
-        if (ft->signal.size == SOX_SIZE_16BIT)
+        if (ft->encoding.bits_per_sample == 16)
         {
-          if (ft->signal.encoding != SOX_ENCODING_UNKNOWN)
+          if (ft->encoding.encoding != SOX_ENCODING_UNKNOWN)
             sox_report("driver supports only signed and unsigned samples.  Changing to signed.");
-            ft->signal.encoding = SOX_ENCODING_SIGN2;
+            ft->encoding.encoding = SOX_ENCODING_SIGN2;
         }
         else
         {
-          if (ft->signal.encoding != SOX_ENCODING_UNKNOWN)
+          if (ft->encoding.encoding != SOX_ENCODING_UNKNOWN)
             sox_report("driver supports only signed and unsigned samples.  Changing to unsigned.");
-            ft->signal.encoding = SOX_ENCODING_UNSIGNED;
+            ft->encoding.encoding = SOX_ENCODING_UNSIGNED;
         }
     }
 
     /* Some hardware only wants to work with 8-bit or 16-bit data */
-    if (ft->signal.size == SOX_SIZE_BYTE)
+    if (ft->encoding.bits_per_sample == 8)
     {
         if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_U8)) && 
             !(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_S8)))
         {
             sox_report("driver doesn't supported byte samples.  Changing to words.");
-            ft->signal.size = SOX_SIZE_16BIT;
+            ft->encoding.bits_per_sample = 16;
         }
     }
-    else if (ft->signal.size == SOX_SIZE_16BIT)
+    else if (ft->encoding.bits_per_sample == 16)
     {
         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 word samples.  Changing to bytes.");
-            ft->signal.size = SOX_SIZE_BYTE;
+            ft->encoding.bits_per_sample = 8;
         }
     }
     else
@@ -69,24 +69,24 @@
         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[ft->signal.size]);
-            ft->signal.size = SOX_SIZE_16BIT;
+            sox_report("driver doesn't supported %u-bit samples.  Changing to 16-bit.", ft->encoding.bits_per_sample);
+            ft->encoding.bits_per_sample = 16;
         }
         else
         {
-            sox_report("driver doesn't supported %s samples.  Changing to bytes.", sox_sizes_str[ft->signal.size]);
-            ft->signal.size = SOX_SIZE_BYTE;
+            sox_report("driver doesn't supported %u-bit samples.  Changing to 8-bit.", ft->encoding.bits_per_sample);
+            ft->encoding.bits_per_sample = 8;
         }
     }
 
-    if (ft->signal.size == SOX_SIZE_BYTE) {
-        switch (ft->signal.encoding)
+    if (ft->encoding.bits_per_sample == 8) {
+        switch (ft->encoding.encoding)
         {
             case SOX_ENCODING_SIGN2:
                 if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_S8)))
                 {
                     sox_report("driver doesn't supported signed byte samples.  Changing to unsigned bytes.");
-                    ft->signal.encoding = SOX_ENCODING_UNSIGNED;
+                    ft->encoding.encoding = SOX_ENCODING_UNSIGNED;
                 }
                 break;
             case SOX_ENCODING_UNSIGNED:
@@ -93,13 +93,13 @@
                 if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_U8)))
                 {
                     sox_report("driver doesn't supported unsigned byte samples.  Changing to signed bytes.");
-                    ft->signal.encoding = SOX_ENCODING_SIGN2;
+                    ft->encoding.encoding = SOX_ENCODING_SIGN2;
                 }
                 break;
             default:
                     break;
         }
-        switch (ft->signal.encoding)
+        switch (ft->encoding.encoding)
         {
             case SOX_ENCODING_SIGN2:
                 if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_S8)))
@@ -121,14 +121,14 @@
                     break;
         }
     }
-    else if (ft->signal.size == SOX_SIZE_16BIT) {
-        switch (ft->signal.encoding)
+    else if (ft->encoding.bits_per_sample == 16) {
+        switch (ft->encoding.encoding)
         {
             case SOX_ENCODING_SIGN2:
                 if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_S16)))
                 {
                     sox_report("driver does not support signed word samples.  Changing to unsigned words.");
-                    ft->signal.encoding = SOX_ENCODING_UNSIGNED;
+                    ft->encoding.encoding = SOX_ENCODING_UNSIGNED;
                 }
                 break;
             case SOX_ENCODING_UNSIGNED:
@@ -135,13 +135,13 @@
                 if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_U16)))
                 {
                     sox_report("driver does not support unsigned word samples.  Changing to signed words.");
-                    ft->signal.encoding = SOX_ENCODING_SIGN2;
+                    ft->encoding.encoding = SOX_ENCODING_SIGN2;
                 }
                 break;
             default:
                     break;
         }
-        switch (ft->signal.encoding)
+        switch (ft->encoding.encoding)
         {
             case SOX_ENCODING_SIGN2:
                 if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_S16)))
@@ -164,14 +164,14 @@
         }
     }
     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[ft->signal.size]);
+        sox_fail_errno(ft,SOX_EFMT,"ALSA driver does not support %s %u-bit output",
+                      sox_encodings_str[(unsigned char)ft->encoding.encoding], ft->encoding.bits_per_sample);
         return SOX_EOF;
     }
     return 0;
 }
 
-static int sox_alsasetup(sox_format_t * ft, snd_pcm_stream_t mode)
+static int setup(sox_format_t * ft, snd_pcm_stream_t mode)
 {
     int fmt = SND_PCM_FORMAT_S16;
     int err;
@@ -293,7 +293,7 @@
     }
 
     /* Have a much larger buffer than sox_globals.bufsiz to avoid underruns */
-    buffer_size = sox_globals.bufsiz * 8 / ft->signal.size / ft->signal.channels;
+    buffer_size = sox_globals.bufsiz * 8 / (ft->encoding.bits_per_sample >> 3) / ft->signal.channels;
 
     if (snd_pcm_hw_params_get_buffer_size_min(hw_params, &buffer_size_min) < 0)
     {
@@ -369,7 +369,7 @@
         goto open_error;
     }
 
-    alsa->buf_size = buffer_size * ft->signal.size * ft->signal.channels;
+    alsa->buf_size = buffer_size * (ft->encoding.bits_per_sample >> 3) * ft->signal.channels;
     alsa->period_size = period_size;
     alsa->frames_this_period = 0;
     alsa->buf = xmalloc(alsa->buf_size);
@@ -424,9 +424,9 @@
  *      size and encoding of samples,
  *      mono/stereo/quad.
  */
-static int sox_alsastartread(sox_format_t * ft)
+static int startread(sox_format_t * ft)
 {
-    return sox_alsasetup(ft, SND_PCM_STREAM_CAPTURE);
+    return setup(ft, SND_PCM_STREAM_CAPTURE);
 }
 
 static void ub_read_buf(sox_sample_t *buf1, char const * buf2, sox_size_t len, sox_bool swap UNUSED, sox_size_t * clips UNUSED)
@@ -467,15 +467,15 @@
     }
 }
 
-static sox_size_t sox_alsaread(sox_format_t * ft, sox_sample_t *buf, sox_size_t nsamp)
+static sox_size_t read_samples(sox_format_t * ft, sox_sample_t *buf, sox_size_t nsamp)
 {
     alsa_priv_t alsa = (alsa_priv_t)ft->priv;
     void (*read_buf)(sox_sample_t *, char const *, sox_size_t, sox_bool, sox_size_t *) = 0;
     sox_size_t len;
 
-    switch(ft->signal.size) {
-      case SOX_SIZE_BYTE:
-        switch(ft->signal.encoding) {
+    switch(ft->encoding.bits_per_sample) {
+      case 8:
+        switch(ft->encoding.encoding) {
           case SOX_ENCODING_SIGN2:    read_buf = sb_read_buf; break;
           case SOX_ENCODING_UNSIGNED: read_buf = ub_read_buf; break;
           default:
@@ -483,8 +483,8 @@
             return 0;
         }
         break;
-      case SOX_SIZE_16BIT:
-        switch(ft->signal.encoding) {
+      case 16:
+        switch(ft->encoding.encoding) {
           case SOX_ENCODING_SIGN2:    read_buf = sw_read_buf; break;
           case SOX_ENCODING_UNSIGNED: read_buf = uw_read_buf; break;
           default:
@@ -498,8 +498,8 @@
     }
 
     /* Prevent overflow */
-    if (nsamp > alsa->buf_size/ft->signal.size)
-      nsamp = (alsa->buf_size/ft->signal.size);
+    if (nsamp > alsa->buf_size/(ft->encoding.bits_per_sample >> 3))
+      nsamp = (alsa->buf_size/(ft->encoding.bits_per_sample >> 3));
 
     len = 0;
     while (len < nsamp) {
@@ -512,7 +512,7 @@
         }
       } else {
         n *= ft->signal.channels;
-        read_buf(buf + len, alsa->buf, n, ft->signal.reverse_bytes, &ft->clips);
+        read_buf(buf + len, alsa->buf, n, ft->encoding.reverse_bytes, &ft->clips);
         len += n;
       }
     }
@@ -519,7 +519,7 @@
     return len;
 }
 
-static int sox_alsastopread(sox_format_t * ft)
+static int stopread(sox_format_t * ft)
 {
     alsa_priv_t alsa = (alsa_priv_t)ft->priv;
 
@@ -530,9 +530,9 @@
     return SOX_SUCCESS;
 }
 
-static int sox_alsastartwrite(sox_format_t * ft)
+static int startwrite(sox_format_t * ft)
 {
-    return sox_alsasetup(ft, SND_PCM_STREAM_PLAYBACK);
+    return setup(ft, SND_PCM_STREAM_PLAYBACK);
 }
 
 static void sox_ub_write_buf(char* buf1, sox_sample_t const * buf2, sox_size_t len, sox_bool swap UNUSED, sox_size_t * clips)
@@ -571,15 +571,15 @@
     }
 }
 
-static sox_size_t sox_alsawrite(sox_format_t * ft, const sox_sample_t *buf, sox_size_t nsamp)
+static sox_size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, sox_size_t nsamp)
 {
     sox_size_t osamp, done;
     alsa_priv_t alsa = (alsa_priv_t)ft->priv;
     void (*write_buf)(char *, const sox_sample_t *, sox_size_t, sox_bool, sox_size_t *) = 0;
 
-    switch(ft->signal.size) {
-        case SOX_SIZE_BYTE:
-            switch (ft->signal.encoding)
+    switch(ft->encoding.bits_per_sample) {
+        case 8:
+            switch (ft->encoding.encoding)
             {
                 case SOX_ENCODING_SIGN2:
                     write_buf = sox_sb_write_buf;
@@ -592,8 +592,8 @@
                     return 0;
             }
             break;
-        case SOX_SIZE_16BIT:
-            switch (ft->signal.encoding)
+        case 16:
+            switch (ft->encoding.encoding)
             {
                 case SOX_ENCODING_SIGN2:
                     write_buf = sox_sw_write_buf;
@@ -615,13 +615,13 @@
       int err;
       sox_size_t len;
       
-      osamp = min(nsamp - done, alsa->buf_size / ft->signal.size);
-      write_buf(alsa->buf, buf, osamp, ft->signal.reverse_bytes, &ft->clips);
+      osamp = min(nsamp - done, alsa->buf_size / (ft->encoding.bits_per_sample >> 3));
+      write_buf(alsa->buf, buf, osamp, ft->encoding.reverse_bytes, &ft->clips);
       buf += osamp;
 
       for (len = 0; len < osamp;) {
         err = snd_pcm_writei(alsa->pcm_handle, 
-                             alsa->buf + (len * ft->signal.size), 
+                             alsa->buf + (len * (ft->encoding.bits_per_sample >> 3)), 
                              (osamp - len) / ft->signal.channels);
         if (errno == EAGAIN) /* Happens naturally; don't report it */
           errno = 0;
@@ -642,7 +642,7 @@
 }
 
 
-static int sox_alsastopwrite(sox_format_t * ft)
+static int stopwrite(sox_format_t * ft)
 {
     alsa_priv_t alsa = (alsa_priv_t)ft->priv;
 
@@ -650,7 +650,7 @@
      * whole periods to the hardware */
     snd_pcm_uframes_t frames_of_silence = alsa->period_size - alsa->frames_this_period;
 
-    memset(alsa->buf, 0, frames_of_silence * ft->signal.size * ft->signal.channels);
+    memset(alsa->buf, 0, frames_of_silence * (ft->encoding.bits_per_sample >> 3) * ft->signal.channels);
 
     sox_debug("padding output with %u silent samples", (unsigned)frames_of_silence);
     while (frames_of_silence > 0) {
@@ -676,26 +676,18 @@
     return SOX_SUCCESS;
 }
 
-static const char *alsanames[] = {
-  "alsa",
-  NULL
-};
-
-static sox_format_handler_t sox_alsa_format = {
-  alsanames,
-  SOX_FILE_DEVICE | SOX_FILE_NOSTDIO,
-  sox_alsastartread,
-  sox_alsaread,
-  sox_alsastopread,
-  sox_alsastartwrite,
-  sox_alsawrite,
-  sox_alsastopwrite,
-  NULL
-};
-
-const sox_format_handler_t *sox_alsa_format_fn(void);
-
-const sox_format_handler_t *sox_alsa_format_fn(void)
+SOX_FORMAT_HANDLER(alsa)
 {
-    return &sox_alsa_format;
+  static char const * const names[] = { "alsa", NULL };
+  static unsigned const write_encodings[] = {
+    SOX_ENCODING_SIGN2, 16, 8, 0,
+    SOX_ENCODING_UNSIGNED, 16, 8, 0,
+    0};
+  static sox_format_handler_t const handler = {
+    names, SOX_FILE_DEVICE | SOX_FILE_NOSTDIO,
+    startread, read_samples, stopread,
+    startwrite, write_samples, stopwrite,
+    NULL, write_encodings, NULL
+  };
+  return &handler;
 }
--- a/src/amr-nb.c
+++ b/src/amr-nb.c
@@ -21,6 +21,8 @@
  * or install equivalent package(s) e.g. marillat.
  */
 
+#include "sox_i.h"
+
 #include "amrnb/typedef.h"
 #include "amrnb/interf_dec.h"
 #include "amrnb/sp_dec.h"
--- a/src/amr-wb.c
+++ b/src/amr-wb.c
@@ -21,6 +21,8 @@
  * or install equivalent package(s) e.g. marillat.
  */
 
+#include "sox_i.h"
+
 #include "amrwb/typedef.h"
 #include "amrwb/enc_if.h"
 #include "amrwb/dec_if.h"
--- a/src/amr.h
+++ b/src/amr.h
@@ -16,7 +16,6 @@
  * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
  */
 
-#include "sox_i.h"
 #include <string.h>
 #include <math.h>
 
@@ -56,14 +55,6 @@
   return result;
 }
 
-static void set_format(sox_format_t * ft)
-{
-  ft->signal.rate = AMR_RATE;
-  ft->signal.size = SOX_SIZE_16BIT;
-  ft->signal.encoding = AMR_ENCODING;
-  ft->signal.channels = 1;
-}
-
 static int startread(sox_format_t * ft)
 {
   amr_t amr = (amr_t) ft->priv;
@@ -80,7 +71,9 @@
     sox_fail_errno(ft, SOX_EHDR, "invalid magic number");
     return SOX_EOF;
   }
-  set_format(ft);
+  ft->signal.rate = AMR_RATE;
+  ft->encoding.encoding = AMR_ENCODING;
+  ft->signal.channels = 1;
   return SOX_SUCCESS;
 }
 
@@ -110,9 +103,9 @@
 {
   amr_t amr = (amr_t) ft->priv;
 
-  if (ft->signal.compression != HUGE_VAL) {
-    amr->mode = ft->signal.compression;
-    if (amr->mode != ft->signal.compression || amr->mode > AMR_MODE_MAX) {
+  if (ft->encoding.compression != HUGE_VAL) {
+    amr->mode = ft->encoding.compression;
+    if (amr->mode != ft->encoding.compression || amr->mode > AMR_MODE_MAX) {
       sox_fail_errno(ft, SOX_EINVAL, "compression level must be a whole number from 0 to %i", AMR_MODE_MAX);
       return SOX_EOF;
     }
@@ -119,7 +112,6 @@
   }
   else amr->mode = 0;
 
-  set_format(ft);
 #include "amr2.h"
   sox_writes(ft, magic);
   amr->pcm_index = 0;
@@ -158,16 +150,17 @@
   return result;
 }
 
-const sox_format_handler_t *AMR_FORMAT_FN(void);
-
-const sox_format_handler_t *AMR_FORMAT_FN(void)
+sox_format_handler_t const * AMR_FORMAT_FN(void);
+sox_format_handler_t const * AMR_FORMAT_FN(void)
 {
-  static char const * names[] = {AMR_NAMES, NULL};
+  static char const * const names[] = {AMR_NAMES, NULL};
+  static sox_rate_t   const write_rates[] = {AMR_RATE, 0};
+  static unsigned const write_encodings[] = {AMR_ENCODING, 0, 0};
   static sox_format_handler_t handler = {
-    names, 0,
+    names, SOX_FILE_MONO,
     startread, read, stopread,
     startwrite, write, stopwrite,
-    NULL
+    NULL, write_encodings, write_rates
   };
   return &handler;
 }
--- a/src/ao.c
+++ b/src/ao.c
@@ -38,16 +38,8 @@
   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)
-  {
-      sox_report("Forcing to signed 16 bit samples for ao driver");
-      ft->signal.size = SOX_SIZE_16BIT;
-      ft->signal.encoding = SOX_ENCODING_SIGN2;
-  }
-
-  ao->buf_size = sox_globals.bufsiz - (sox_globals.bufsiz % ft->signal.size);
-  ao->buf_size *= ft->signal.size;
+  ao->buf_size = sox_globals.bufsiz - (sox_globals.bufsiz % (ft->encoding.bits_per_sample >> 3));
+  ao->buf_size *= (ft->encoding.bits_per_sample >> 3);
   ao->buf = xmalloc(ao->buf_size);
 
   if (!ao->buf)
@@ -73,7 +65,7 @@
       }
   }
 
-  ao->format.bits = ft->signal.size * 8;
+  ao->format.bits = ft->encoding.bits_per_sample;
   ao->format.rate = ft->signal.rate;
   ao->format.channels = ft->signal.channels;
   ao->format.byte_format = AO_FMT_NATIVE;
@@ -97,17 +89,17 @@
     }
 }
 
-static sox_size_t write(sox_format_t *ft, const sox_sample_t *buf, sox_size_t len)
+static sox_size_t write_samples(sox_format_t *ft, const sox_sample_t *buf, sox_size_t len)
 {
   ao_priv_t ao = (ao_priv_t)ft->priv;
   sox_size_t aobuf_size;
 
-  if (len > ao->buf_size / ft->signal.size)
-      len = ao->buf_size / ft->signal.size;
+  if (len > ao->buf_size / (ft->encoding.bits_per_sample >> 3))
+      len = ao->buf_size / (ft->encoding.bits_per_sample >> 3);
 
-  aobuf_size = ft->signal.size * len;
+  aobuf_size = (ft->encoding.bits_per_sample >> 3) * len;
 
-  sox_sw_write_buf((char *)ao->buf, buf, len, ft->signal.reverse_bytes,
+  sox_sw_write_buf((char *)ao->buf, buf, len, ft->encoding.reverse_bytes,
                    &(ft->clips));
   if (ao_play(ao->device, (void *)ao->buf, aobuf_size) == 0)
     return 0;
@@ -130,22 +122,15 @@
   return SOX_SUCCESS;
 }
 
-/* libao player */
-static const char *aonames[] = {
-  "ao",
-  NULL
-};
-
-static sox_format_handler_t sox_ao_format = {
-  aonames, SOX_FILE_DEVICE | SOX_FILE_NOSTDIO,
-  NULL, NULL, NULL,
-  startwrite, write, stopwrite,
-  NULL
-};
-
-const sox_format_handler_t *sox_ao_format_fn(void);
-
-const sox_format_handler_t *sox_ao_format_fn(void)
+SOX_FORMAT_HANDLER(ao)
 {
-    return &sox_ao_format;
+  static char const * const names[] = {"ao", NULL};
+  static unsigned const encodings[] = {SOX_ENCODING_SIGN2, 16, 0, 0};
+  static sox_format_handler_t const handler = {
+    names, SOX_FILE_DEVICE | SOX_FILE_NOSTDIO,
+    NULL, NULL, NULL,
+    startwrite, write_samples, stopwrite,
+    NULL, encodings, NULL
+  };
+  return &handler;
 }
--- a/src/au.c
+++ b/src/au.c
@@ -1,313 +1,94 @@
 /*
  * Copyright 1991, 1992, 1993 Guido van Rossum And Sundry Contributors.
  * This source code is freely redistributable and may be used for
- * any purpose.  This copyright notice must be maintained. 
- * Guido van Rossum And Sundry Contributors are not responsible for 
+ * any purpose.  This copyright notice must be maintained.
+ * Guido van Rossum And Sundry Contributors are not responsible for
  * the consequences of using this software.
  *
  * October 7, 1998 - [email protected]
  *   G.723 was using incorrect # of bits.  Corrected to 3 and 5 bits.
- */
-
-/*
+ *
  * libSoX Sun format with header (SunOS 4.1; see /usr/demo/SOUND).
  * NeXT uses this format also, but has more format codes defined.
  * DEC uses a slight variation and swaps bytes.
- * We only support the common formats.
- * CCITT G.721 (32 kbit/s) and G.723 (24/40 kbit/s) are also supported,
- * courtesy Sun's public domain implementation.
+ * We support only the common formats, plus
+ * CCITT G.721 (32 kbit/s) and G.723 (24/40 kbit/s),
+ * courtesy of Sun's public domain implementation.
  * Output is always in big-endian (Sun/NeXT) order.
  */
 
 #include "sox_i.h"
 #include "g72x.h"
-#include <stdlib.h>
 #include <string.h>
-#include <errno.h>
 
 /* Magic numbers used in Sun and NeXT audio files */
-#define SUN_MAGIC       0x2e736e64              /* Really '.snd' */
-#define SUN_INV_MAGIC   0x646e732e              /* '.snd' upside-down */
-#define DEC_MAGIC       0x2e736400              /* Really '\0ds.' (for DEC) */
-#define DEC_INV_MAGIC   0x0064732e              /* '\0ds.' upside-down */
-#define SUN_HDRSIZE     24                      /* Size of minimal header */
-#define SUN_UNSPEC      ((unsigned)(~0))        /* Unspecified data size */
-#define SUN_ENCODING_UNKNOWN 0
-#define SUN_ULAW        1                       /* u-law encoding */
-#define SUN_LIN_8       2                       /* Linear 8 bits */
-#define SUN_LIN_16      3                       /* Linear 16 bits */
-#define SUN_LIN_24      4                       /* Linear 24 bits */
-#define SUN_LIN_32      5                       /* Linear 32 bits */
-#define SUN_FLOAT       6                       /* IEEE FP 32 bits */
-#define SUN_DOUBLE      7                       /* IEEE FP 64 bits */
-#define SUN_G721        23                      /* CCITT G.721 4-bits ADPCM */
-#define SUN_G723_3      25                      /* CCITT G.723 3-bits ADPCM */
-#define SUN_G723_5      26                      /* CCITT G.723 5-bits ADPCM */
-#define SUN_ALAW        27                      /* a-law encoding */
-/* The other formats are not supported by sox at the moment */
+#define SUN_MAGIC     0x2e736e64  /* Really '.snd' */
+#define SUN_INV_MAGIC 0x646e732e  /* '.snd' reversed bytes */
+#define DEC_MAGIC     0x2e736400  /* Really '\0ds.' (for DEC) */
+#define DEC_INV_MAGIC 0x0064732e  /* '\0ds.' reversed bytes */
+#define SUN_HDRSIZE   24          /* Size of minimal header */
+#define SUN_UNSPEC    ~0u         /* Unspecified data size (this is legal) */
 
-/* Private data */
-typedef struct aupriv {
-        /* For writer: size in bytes */
-        sox_size_t data_size;
-        /* For seeking */
-        sox_size_t dataStart;
-        /* For G72x decoding: */
-        struct g72x_state state;
-        int (*dec_routine)(int i, int out_coding, struct g72x_state *state_ptr);
-        int dec_bits;
-        unsigned int in_buffer;
-        int in_bits;
-} *au_t;
+typedef enum {
+  Unspecified, Mulaw_8, Linear_8, Linear_16, Linear_24, Linear_32, Float,
+  Double, Indirect, Nested, Dsp_core, Dsp_data_8, Dsp_data_16, Dsp_data_24,
+  Dsp_data_32, Unknown, Display, Mulaw_squelch, Emphasized, Compressed,
+  Compressed_emphasized, Dsp_commands, Dsp_commands_samples, Adpcm_g721,
+  Adpcm_g722, Adpcm_g723_3, Adpcm_g723_5, Alaw_8, Unknown_other} sun_encoding_t;
+static char const * const str[] = {
+  "Unspecified", "8-bit mu-law", "8-bit signed linear", "16-bit signed linear",
+  "24-bit signed linear", "32-bit signed linear", "Floating-point",
+  "Double precision float", "Fragmented sampled data", "Unknown", "DSP program",
+  "8-bit fixed-point", "16-bit fixed-point", "24-bit fixed-point",
+  "32-bit fixed-point", "Unknown", "Non-audio data", "Mu-law squelch",
+  "16-bit linear with emphasis", "16-bit linear with compression",
+  "16-bit linear with emphasis and compression", "Music Kit DSP commands",
+  "Music Kit DSP samples", "4-bit G.721 ADPCM", "G.722 ADPCM",
+  "3-bit G.723 ADPCM", "5-bit G.723 ADPCM", "8-bit a-law", "Unknown"};
 
-static void auwriteheader(sox_format_t * ft, sox_size_t data_size);
-
-static int sox_auencodingandsize(uint32_t sun_encoding, sox_encoding_t * encoding, unsigned * size)
+static sun_encoding_t sun_enc(unsigned size, sox_encoding_t sox_enc)
 {
-    switch (sun_encoding) {
-    case SUN_ULAW:
-            *encoding = SOX_ENCODING_ULAW;
-            *size = SOX_SIZE_BYTE;
-            break;
-    case SUN_ALAW:
-            *encoding = SOX_ENCODING_ALAW;
-            *size = SOX_SIZE_BYTE;
-            break;
-    case SUN_LIN_8:
-            *encoding = SOX_ENCODING_SIGN2;
-            *size = SOX_SIZE_BYTE;
-            break;
-    case SUN_LIN_16:
-            *encoding = SOX_ENCODING_SIGN2;
-            *size = SOX_SIZE_16BIT;
-            break;
-    case SUN_LIN_24:
-            *encoding = SOX_ENCODING_SIGN2;
-            *size = SOX_SIZE_24BIT;
-            break;
-    case SUN_G721:
-            *encoding = SOX_ENCODING_SIGN2;
-            *size = SOX_SIZE_16BIT;
-            break;
-    case SUN_G723_3:
-            *encoding = SOX_ENCODING_SIGN2;
-            *size = SOX_SIZE_16BIT;
-            break;
-    case SUN_G723_5:
-            *encoding = SOX_ENCODING_SIGN2;
-            *size = SOX_SIZE_16BIT;
-            break;
-    case SUN_FLOAT:
-            *encoding = SOX_ENCODING_FLOAT;
-            *size = SOX_SIZE_32BIT;
-            break;
-    default:
-            sox_debug("encoding: 0x%x", sun_encoding);
-            return(SOX_EOF);
-    }
-    return(SOX_SUCCESS);
+  sun_encoding_t result = Unspecified;
+  if      (sox_enc == SOX_ENCODING_ULAW  && size ==  8) result = Mulaw_8;
+  else if (sox_enc == SOX_ENCODING_ALAW  && size ==  8) result = Alaw_8;
+  else if (sox_enc == SOX_ENCODING_SIGN2 && size ==  8) result = Linear_8;
+  else if (sox_enc == SOX_ENCODING_SIGN2 && size == 16) result = Linear_16;
+  else if (sox_enc == SOX_ENCODING_SIGN2 && size == 24) result = Linear_24;
+  else if (sox_enc == SOX_ENCODING_SIGN2 && size == 32) result = Linear_32;
+  else if (sox_enc == SOX_ENCODING_FLOAT && size == 32) result = Float;
+  else if (sox_enc == SOX_ENCODING_FLOAT && size == 64) result = Double;
+  return result;
 }
 
-static int sox_auseek(sox_format_t * ft, sox_size_t offset) 
+static int sox_enc(
+    uint32_t sun_encoding, sox_encoding_t * encoding, unsigned * size)
 {
-    au_t au = (au_t ) ft->priv;
-
-    if (au->dec_routine != NULL)
-    {
-        sox_fail_errno(ft,SOX_ENOTSUP,"Sorry, DEC unsupported");
-    }
-    else 
-    {
-        sox_size_t new_offset, channel_block, alignment;
-
-        new_offset = offset * ft->signal.size;
-        /* Make sure request aligns to a channel block (ie left+right) */
-        channel_block = ft->signal.channels * ft->signal.size;
-        alignment = new_offset % channel_block;
-        /* Most common mistaken is to compute something like
-         * "skip everthing upto and including this sample" so
-         * advance to next sample block in this case.
-         */
-        if (alignment != 0)
-            new_offset += (channel_block - alignment);
-        new_offset += au->dataStart;
-
-        ft->sox_errno = sox_seeki(ft, (sox_ssize_t)new_offset, SEEK_SET);
-    }
-
-    return(ft->sox_errno);
-}
-
-static int sox_austartread(sox_format_t * ft) 
-{
-        /* The following 6 variables represent a Sun sound header on disk.
-           The numbers are written as big-endians.
-           Any extra bytes (totalling hdr_size - 24) are an
-           "info" field of unspecified nature, usually a string.
-           By convention the header size is a multiple of 4. */
-        uint32_t magic;
-        uint32_t hdr_size;
-        uint32_t data_size;
-        uint32_t encoding;
-        uint32_t sample_rate;
-        uint32_t channels;
-
-        unsigned int i;
-        char *buf;
-        au_t p = (au_t ) ft->priv;
-
-        int rc;
-
-        /* Check the magic word */
-        sox_readdw(ft, &magic);
-        if (magic == DEC_INV_MAGIC) {
-            sox_debug("Found inverted DEC magic word.");
-            /* Inverted headers are not standard.  Code was probably
-             * left over from pre-standardize period of testing for
-             * endianess.  Its not hurting though.
-             */
-            ft->signal.reverse_bytes = SOX_IS_BIGENDIAN;
-        }
-        else if (magic == SUN_INV_MAGIC) {
-            sox_debug("Found inverted Sun/NeXT magic word.");
-            ft->signal.reverse_bytes = SOX_IS_BIGENDIAN;
-        }
-        else if (magic == SUN_MAGIC) {
-            sox_debug("Found Sun/NeXT magic word");
-            ft->signal.reverse_bytes = SOX_IS_LITTLEENDIAN;
-        }
-        else if (magic == DEC_MAGIC) {
-            sox_debug("Found DEC magic word");
-            ft->signal.reverse_bytes = SOX_IS_LITTLEENDIAN;
-        }
-        else
-        {
-                sox_fail_errno(ft,SOX_EHDR,"Did not detect valid Sun/NeXT/DEC magic number in header.");
-                return(SOX_EOF);
-        }
-
-        /* Read the header size */
-        sox_readdw(ft, &hdr_size);
-        if (hdr_size < SUN_HDRSIZE)
-        {
-                sox_fail_errno(ft,SOX_EHDR,"Sun/NeXT header size too small.");
-                return(SOX_EOF);
-        }
-
-        /* Read the data size; may be ~0 meaning unspecified */
-        sox_readdw(ft, &data_size);
-
-        /* Read the encoding; there are some more possibilities */
-        sox_readdw(ft, &encoding);
-
-
-        /* Translate the encoding into encoding and size parameters */
-        /* (Or, for G.72x, set the decoding routine and parameters) */
-        p->dec_routine = NULL;
-        p->in_buffer = 0;
-        p->in_bits = 0;
-        if(sox_auencodingandsize(encoding, &(ft->signal.encoding),
-                             &(ft->signal.size)) == SOX_EOF)
-        {
-            sox_fail_errno(ft,SOX_EFMT,"Unsupported encoding in Sun/NeXT header.\nOnly U-law, signed bytes, signed words, ADPCM, and 32-bit floats are supported.");
-            return(SOX_EOF);
-        }
-        switch (encoding) {
-        case SUN_G721:
-                g72x_init_state(&p->state);
-                p->dec_routine = g721_decoder;
-                p->dec_bits = 4;
-                break;
-        case SUN_G723_3:
-                g72x_init_state(&p->state);
-                p->dec_routine = g723_24_decoder;
-                p->dec_bits = 3;
-                break;
-        case SUN_G723_5:
-                g72x_init_state(&p->state);
-                p->dec_routine = g723_40_decoder;
-                p->dec_bits = 5;
-                break;
-        }
-
-
-        /* Read the sampling rate */
-        sox_readdw(ft, &sample_rate);
-        if (ft->signal.rate == 0 || ft->signal.rate == sample_rate)
-            ft->signal.rate = sample_rate;
-        else
-            sox_report("User options overriding rate read in .au header");
+  switch (sun_encoding) {
+    case Mulaw_8     : *encoding = SOX_ENCODING_ULAW ; *size =  8; break;
+    case Alaw_8      : *encoding = SOX_ENCODING_ALAW ; *size =  8; break;
+    case Linear_8    : *encoding = SOX_ENCODING_SIGN2; *size =  8; break;
+    case Linear_16   : *encoding = SOX_ENCODING_SIGN2; *size = 16; break;
+    case Linear_24   : *encoding = SOX_ENCODING_SIGN2; *size = 24; break;
+    case Linear_32   : *encoding = SOX_ENCODING_SIGN2; *size = 32; break;
+    case Float       : *encoding = SOX_ENCODING_FLOAT; *size = 32; break;
+    case Double      : *encoding = SOX_ENCODING_FLOAT; *size = 64; break;
+    /* Sun encodings that SoX can read, but not write: */
+    case Adpcm_g721  : *encoding = SOX_ENCODING_G721 ; *size =  4; break;
+    case Adpcm_g723_3: *encoding = SOX_ENCODING_G723 ; *size =  3; break;
+    case Adpcm_g723_5: *encoding = SOX_ENCODING_G723 ; *size =  5; break;
 
-        /* Read the number of channels */
-        sox_readdw(ft, &channels);
-        if (ft->signal.channels == 0 || ft->signal.channels == channels)
-            ft->signal.channels = channels;
-        else
-            sox_report("User options overriding channels read in .au header");
-
-
-        /* Skip the info string in header; print it if verbose */
-        hdr_size -= SUN_HDRSIZE; /* #bytes already read */
-        if (hdr_size > 0) {
-                /* Allocate comment buffer */
-                buf = (char *) xmalloc(hdr_size+1);
-                
-                for(i = 0; i < hdr_size; i++) {
-                        sox_readb(ft, (unsigned char *)&(buf[i]));
-                        if (sox_eof(ft))
-                        {
-                                sox_fail_errno(ft,SOX_EOF,"Unexpected EOF in Sun/NeXT header info.");
-                                return(SOX_EOF);
-                        }
-                }
-                /* Buffer should already be null terminated but
-                 * just in case we xmalloced an extra byte and 
-                 * force the last byte to be 0 anyways.
-                 * This should help work with a greater array of
-                 * software.
-                 */
-                buf[hdr_size] = '\0';
+    default: sox_debug("encoding: 0x%x", sun_encoding); return SOX_EOF;
+  }
+  return SOX_SUCCESS;
+}
 
-                append_comments(&ft->comments, buf);
-                free(buf);
-        }
-        /* Needed for seeking */
-        ft->length = data_size/ft->signal.size;
-        if(ft->seekable)
-                p->dataStart = sox_tell(ft);
+typedef struct {        /* For G72x decoding: */
+  struct g72x_state state;
+  int (*dec_routine)(int i, int out_coding, struct g72x_state *state_ptr);
+  unsigned int in_buffer;
+  int in_bits;
+} priv_t;
 
-        /* Needed for rawread() */
-        rc = sox_rawstartread(ft);
-        if (rc)
-            return rc;
-
-        return(SOX_SUCCESS);
-}
-
-/* When writing, the header is supposed to contain the number of
-   data bytes written, unless it is written to a pipe.
-   Since we don't know how many bytes will follow until we're done,
-   we first write the header with an unspecified number of bytes,
-   and at the end we rewind the file and write the header again
-   with the right size.  This only works if the file is seekable;
-   if it is not, the unspecified size remains in the header
-   (this is legal). */
-
-static int sox_austartwrite(sox_format_t * ft) 
-{
-        au_t p = (au_t ) ft->priv;
-        int rc;
-
-        /* Needed because of rawwrite(); */
-        rc = sox_rawstartwrite(ft);
-        if (rc)
-            return rc;
-
-        p->data_size = 0;
-        auwriteheader(ft, SUN_UNSPEC);
-        return(SOX_SUCCESS);
-}
-
 /*
  * Unpack input codes and pass them back as bytes.
  * Returns 1 if there is residual input, returns -1 if eof, else returns 0.
@@ -315,181 +96,149 @@
  */
 static int unpack_input(sox_format_t * ft, unsigned char *code)
 {
-        au_t p = (au_t ) ft->priv;
-        unsigned char           in_byte;
+  priv_t * p = (priv_t * ) ft->priv;
+  unsigned char           in_byte;
 
-        if (p->in_bits < p->dec_bits) {
-                if (sox_readb(ft, &in_byte) == SOX_EOF) {
-                        *code = 0;
-                        return (-1);
-                }
-                p->in_buffer |= (in_byte << p->in_bits);
-                p->in_bits += 8;
-        }
-        *code = p->in_buffer & ((1 << p->dec_bits) - 1);
-        p->in_buffer >>= p->dec_bits;
-        p->in_bits -= p->dec_bits;
-        return (p->in_bits > 0);
-}
+  if (p->in_bits < (int)ft->encoding.bits_per_sample) {
+    if (sox_readb(ft, &in_byte) == SOX_EOF) {
+      *code = 0;
+      return -1;
+    }
+    p->in_buffer |= (in_byte << p->in_bits);
+    p->in_bits += 8;
+  }
+  *code = p->in_buffer & ((1 << ft->encoding.bits_per_sample) - 1);
+  p->in_buffer >>= ft->encoding.bits_per_sample;
+  p->in_bits -= ft->encoding.bits_per_sample;
+  return p->in_bits > 0;
+}
 
-static sox_size_t sox_auread(sox_format_t * ft, sox_sample_t *buf, sox_size_t samp)
+static sox_size_t dec_read(sox_format_t *ft, sox_sample_t *buf, sox_size_t samp)
 {
-        au_t p = (au_t ) ft->priv;
-        unsigned char code;
-        int done;
-        if (p->dec_routine == NULL)
-                return sox_rawread(ft, buf, samp);
-        done = 0;
-        while (samp > 0 && unpack_input(ft, &code) >= 0) {
-                *buf++ = SOX_SIGNED_16BIT_TO_SAMPLE(
-                        (*p->dec_routine)(code, AUDIO_ENCODING_LINEAR,
-                                          &p->state),);
-                samp--;
-                done++;
-        }
-        return done;
-}
+  priv_t * p = (priv_t *)ft->priv;
+  unsigned char code;
+  sox_size_t done;
 
-static sox_size_t sox_auwrite(sox_format_t * ft, const sox_sample_t *buf, sox_size_t samp)
-{
-        au_t p = (au_t ) ft->priv;
-        p->data_size += samp * ft->signal.size;
-        return(sox_rawwrite(ft, buf, samp));
+  for (done = 0; samp > 0 && unpack_input(ft, &code) >= 0; ++done, --samp)
+    *buf++ = SOX_SIGNED_16BIT_TO_SAMPLE(
+        (*p->dec_routine)(code, AUDIO_ENCODING_LINEAR, &p->state),);
+  return done;
 }
 
-static int sox_austopwrite(sox_format_t * ft)
+static int startread(sox_format_t * ft)
 {
-        au_t p = (au_t ) ft->priv;
+  priv_t * p = (priv_t * ) ft->priv;
+  uint32_t magic;        /* These 6 uint32_t variables represent a Sun sound */
+  uint32_t hdr_size;     /* header on disk.  The numbers are written as */
+  uint32_t data_size;    /* big-endians.  Any extra bytes (totalling */
+  uint32_t sun_encoding; /* hdr_size - 24) are an "info" field of */
+  uint32_t sample_rate;  /* unspecified nature, usually a string.  By */
+  uint32_t channels;     /* convention the header size is a multiple of 4. */
+  unsigned bits_per_sample;
+  sox_encoding_t sox_encoding;
 
-        /* Attempt to update header */
-        if (ft->seekable)
-        {
-          if (sox_seeki(ft, 0, 0) != 0)
-          {
-                sox_fail_errno(ft,errno,"Can't rewind output file to rewrite Sun header.");
-                return(SOX_EOF);
-          }
-          auwriteheader(ft, p->data_size);
-        }
-        return(SOX_SUCCESS);
-}
+  sox_readdw(ft, &magic);
+  if (magic == DEC_INV_MAGIC) {
+    sox_debug("Found inverted DEC magic word.");
+    /* Inverted headers are not standard.  Code was probably
+     * left over from pre-standardize period of testing for
+     * endianess.  Its not hurting though.
+     */
+    ft->encoding.reverse_bytes = SOX_IS_BIGENDIAN;
+  }
+  else if (magic == SUN_INV_MAGIC) {
+    sox_debug("Found inverted Sun/NeXT magic word.");
+    ft->encoding.reverse_bytes = SOX_IS_BIGENDIAN;
+  }
+  else if (magic == SUN_MAGIC) {
+    sox_debug("Found Sun/NeXT magic word");
+    ft->encoding.reverse_bytes = SOX_IS_LITTLEENDIAN;
+  }
+  else if (magic == DEC_MAGIC) {
+    sox_debug("Found DEC magic word");
+    ft->encoding.reverse_bytes = SOX_IS_LITTLEENDIAN;
+  }
+  else {
+    sox_fail_errno(ft,SOX_EHDR,"Did not detect valid Sun/NeXT/DEC magic number in header.");
+    return SOX_EOF;
+  }
 
-static unsigned sox_ausunencoding(unsigned size, sox_encoding_t encoding)
-{
-        unsigned sun_encoding;
+  sox_readdw(ft, &hdr_size);
+  if (hdr_size < SUN_HDRSIZE) {
+    sox_fail_errno(ft, SOX_EHDR, "Sun/NeXT header size too small.");
+    return SOX_EOF;
+  }
+  sox_readdw(ft, &data_size);     /* Can be SUN_UNSPEC */
+  sox_readdw(ft, &sun_encoding);
+  sox_readdw(ft, &sample_rate);
+  sox_readdw(ft, &channels);
 
-        if (encoding == SOX_ENCODING_ULAW && size == SOX_SIZE_BYTE)
-                sun_encoding = SUN_ULAW;
-        else if (encoding == SOX_ENCODING_ALAW && size == SOX_SIZE_BYTE)
-                sun_encoding = SUN_ALAW;
-        else if (encoding == SOX_ENCODING_SIGN2 && size == SOX_SIZE_BYTE)
-                sun_encoding = SUN_LIN_8;
-        else if (encoding == SOX_ENCODING_SIGN2 && size == SOX_SIZE_16BIT)
-                sun_encoding = SUN_LIN_16;
-        else if (encoding == SOX_ENCODING_SIGN2 && size == SOX_SIZE_24BIT)
-                sun_encoding = SUN_LIN_24;
-        else if (encoding == SOX_ENCODING_FLOAT && size == SOX_SIZE_32BIT)
-                sun_encoding = SUN_FLOAT;
-        else sun_encoding = SUN_ENCODING_UNKNOWN;
-        return sun_encoding;
-}
-
-static void auwriteheader(sox_format_t * ft, sox_size_t data_size)
-{
-        uint32_t magic;
-        uint32_t hdr_size;
-        uint32_t encoding;
-        uint32_t sample_rate;
-        uint32_t channels;
-        int   x;
-        int   comment_size;
-        char * comment = cat_comments(ft->comments);
-
-        encoding = sox_ausunencoding(ft->signal.size, ft->signal.encoding);
-        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 > 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 == SOX_SIZE_16BIT) {
-            sox_report("Defaulting to signed 16 bit");
-            ft->signal.encoding = SOX_ENCODING_SIGN2;
-            encoding = SUN_LIN_16;
-          }
-          else {
-            sox_report("Defaulting to 8khz u-law");
-            encoding = SUN_ULAW;
-            ft->signal.encoding = SOX_ENCODING_ULAW;
-            ft->signal.size = SOX_SIZE_BYTE;
-            ft->signal.rate = 8000;  /* strange but true */
-          }
-        }
+  if (sox_enc(sun_encoding, &sox_encoding, &bits_per_sample) == SOX_EOF) {
+    int n = min(sun_encoding, Unknown_other);
+    sox_fail_errno(ft, SOX_EFMT, "unsupported encoding `%s' (%u)", str[n], sun_encoding);
+    return SOX_EOF;
+  }
+  switch (sun_encoding) {
+    case Adpcm_g721  : p->dec_routine = g721_decoder   ; break;
+    case Adpcm_g723_3: p->dec_routine = g723_24_decoder; break;
+    case Adpcm_g723_5: p->dec_routine = g723_40_decoder; break;
+  }
+  if (p->dec_routine) {
+    g72x_init_state(&p->state);
+    ft->handler.seek = NULL;
+    ft->handler.read = dec_read;
+  }
 
-        magic = SUN_MAGIC;
-        sox_writedw(ft, magic);
+  hdr_size -= SUN_HDRSIZE; /* # bytes already read */
+  if (hdr_size > 0) {
+    char * buf = xcalloc(1, hdr_size + 1); /* +1 ensures null-terminated */
+    if (sox_readbuf(ft, buf, hdr_size) != hdr_size) {
+      sox_fail_errno(ft, SOX_EOF, "Unexpected EOF in Sun/NeXT header info.");
+      free(buf);
+      return SOX_EOF;
+    }
+    append_comments(&ft->comments, buf);
+    free(buf);
+  }
+  if (data_size == SUN_UNSPEC)
+    data_size = 0;  /* SoX uses 0 for unspecified */
+  return sox_check_read_params( ft, channels, (sox_rate_t)sample_rate,
+      sox_encoding, bits_per_sample, div_bits(data_size, bits_per_sample));
+}
 
-        hdr_size = SUN_HDRSIZE;
-
-        comment_size = strlen(comment) + 1; /*+1 = null-term. */
-        if (comment_size < 4)
-            comment_size = 4; /* minimum size */
-
-        hdr_size += comment_size;
-
-        sox_writedw(ft, hdr_size);
-
-        sox_writedw(ft, data_size);
-
-        sox_writedw(ft, encoding);
-
-        sample_rate = ft->signal.rate;
-        sox_writedw(ft, sample_rate);
-
-        channels = ft->signal.channels;
-        sox_writedw(ft, channels);
-
-        sox_writes(ft, comment);
-
-        /* Info must be 4 bytes at least and null terminated. */
-        x = strlen(comment);
-        free(comment);
-        for (;x < 3; x++)
-            sox_writeb(ft, 0);
-
-        sox_writeb(ft, 0);
+static int write_header(sox_format_t * ft)
+{
+  char   *comment = cat_comments(ft->comments);
+  size_t len      = strlen(comment) + 1;     /* Write out null-terminated */
+  size_t info_len = max(4, (len + 3) & ~3u); /* Minimum & multiple of 4 bytes */
+  size_t size     = ft->olength? ft->olength : ft->length;
+  sox_bool error  = sox_false
+  ||sox_writedw(ft, SUN_MAGIC)
+  ||sox_writedw(ft, SUN_HDRSIZE + info_len)
+  ||sox_writedw(ft, size? size*(ft->encoding.bits_per_sample >> 3) : SUN_UNSPEC)
+  ||sox_writedw(ft, sun_enc(ft->encoding.bits_per_sample,ft->encoding.encoding))
+  ||sox_writedw(ft, (unsigned)(ft->signal.rate + .5))
+  ||sox_writedw(ft, ft->signal.channels)
+  ||sox_writebuf(ft, comment, len) != len
+  ||sox_padbytes(ft, info_len - len);
+  free(comment);
+  return error? SOX_EOF: SOX_SUCCESS;
 }
 
-/* SPARC .au w/header */
-static const char *aunames[] = {
-  "au",
-  "snd",
-  NULL
-};
-
-/* Purposely did not specify format as big endian because
- * it can handle both.  This means we must set our own
- * default values for reverse_bytes when not specified
- * since we didn't give the hint to soxio.
- */
-static sox_format_handler_t sox_au_format = {
-  aunames,
-  SOX_FILE_BIG_END,
-  sox_austartread,
-  sox_auread,
-  sox_rawstopread,
-  sox_austartwrite,
-  sox_auwrite,
-  sox_austopwrite,
-  sox_auseek
-};
-
-const sox_format_handler_t *sox_au_format_fn(void);
-
-const sox_format_handler_t *sox_au_format_fn(void)
+SOX_FORMAT_HANDLER(au)
 {
-    return &sox_au_format;
+  static char const * const names[] = {"au", "snd", NULL};
+  static unsigned const write_encodings[] = {
+    SOX_ENCODING_ULAW, 8, 0,
+    SOX_ENCODING_ALAW, 8, 0,
+    SOX_ENCODING_SIGN2, 8, 16, 24, 32, 0,
+    SOX_ENCODING_FLOAT, 32, 64, 0,
+    0};
+  static sox_format_handler_t const handler = {
+    names, SOX_FILE_BIG_END | SOX_FILE_REWIND,
+    startread, sox_rawread, NULL,
+    write_header, sox_rawwrite, NULL,
+    sox_rawseek, write_encodings, NULL
+  };
+  return &handler;
 }
--- a/src/auto.c
+++ b/src/auto.c
@@ -158,17 +158,15 @@
 
     sox_debug("Detected file format type: %s", type);
     set_endianness_if_not_already_set(ft);
-    return ft->handler->startread? (* ft->handler->startread)(ft) : SOX_SUCCESS;
+    return ft->handler.startread? (*ft->handler.startread)(ft) : SOX_SUCCESS;
 }
 
-const sox_format_handler_t *sox_auto_format_fn(void);
-const sox_format_handler_t *sox_auto_format_fn(void)
+SOX_FORMAT_HANDLER(auto)
 {
   static const char *autonames[] = {"magic", NULL};
-
   static sox_format_handler_t sox_auto_format = {
     autonames, SOX_FILE_DEVICE | SOX_FILE_PHONY,
-    sox_autostartread, NULL, NULL, NULL, NULL, NULL, NULL
+    sox_autostartread, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
   };
   return &sox_auto_format;
 }
--- a/src/avr.c
+++ b/src/avr.c
@@ -19,11 +19,11 @@
 
  */
 
+#include "sox_i.h"
+
 #include <stdio.h>
 #include <string.h>
 
-#include "sox_i.h"
-
 #define AVR_MAGIC "2BIT"
 
 /* Taken from the Audio File Formats FAQ */
@@ -63,7 +63,7 @@
  */
 
 
-static int sox_avrstartread(sox_format_t * ft) 
+static int startread(sox_format_t * ft) 
 {
   avr_t avr = (avr_t)ft->priv;
   int rc;
@@ -87,10 +87,10 @@
 
   sox_readw (ft, &(avr->rez));
   if (avr->rez == 8) {
-    ft->signal.size = SOX_SIZE_BYTE;
+    ft->encoding.bits_per_sample = 8;
   }
   else if (avr->rez == 16) {
-    ft->signal.size = SOX_SIZE_16BIT;
+    ft->encoding.bits_per_sample = 16;
   }
   else {
     sox_fail_errno(ft,SOX_EFMT,"AVR: unsupported sample resolution");
@@ -99,10 +99,10 @@
 
   sox_readw (ft, &(avr->sign));
   if (avr->sign) {
-    ft->signal.encoding = SOX_ENCODING_SIGN2;
+    ft->encoding.encoding = SOX_ENCODING_SIGN2;
   }
   else {
-    ft->signal.encoding = SOX_ENCODING_UNSIGNED;
+    ft->encoding.encoding = SOX_ENCODING_UNSIGNED;
   }
 
   sox_readw (ft, &(avr->loop));
@@ -141,7 +141,7 @@
   return(SOX_SUCCESS);
 }
 
-static int sox_avrstartwrite(sox_format_t * ft) 
+static int startwrite(sox_format_t * ft) 
 {
   avr_t avr = (avr_t)ft->priv;
   int rc;
@@ -181,10 +181,10 @@
   }
 
   /* rez */
-  if (ft->signal.size == SOX_SIZE_BYTE) {
+  if (ft->encoding.bits_per_sample == 8) {
     sox_writew (ft, 8);
   }
-  else if (ft->signal.size == SOX_SIZE_16BIT) {
+  else if (ft->encoding.bits_per_sample == 16) {
     sox_writew (ft, 16);
   }
   else {
@@ -193,10 +193,10 @@
   }
 
   /* sign */
-  if (ft->signal.encoding == SOX_ENCODING_SIGN2) {
+  if (ft->encoding.encoding == SOX_ENCODING_SIGN2) {
     sox_writew (ft, 0xffff);
   }
-  else if (ft->signal.encoding == SOX_ENCODING_UNSIGNED) {
+  else if (ft->encoding.encoding == SOX_ENCODING_UNSIGNED) {
     sox_writew (ft, 0);
   }
   else {
@@ -246,7 +246,7 @@
   return(SOX_SUCCESS);
 }
 
-static sox_size_t sox_avrwrite(sox_format_t * ft, const sox_sample_t *buf, sox_size_t nsamp) 
+static sox_size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, sox_size_t nsamp) 
 {
   avr_t avr = (avr_t)ft->priv;
 
@@ -255,7 +255,7 @@
   return (sox_rawwrite (ft, buf, nsamp));
 }
 
-static int sox_avrstopwrite(sox_format_t * ft) 
+static int stopwrite(sox_format_t * ft) 
 {
   avr_t avr = (avr_t)ft->priv;
 
@@ -272,26 +272,19 @@
   return(SOX_SUCCESS);
 }
 
-static const char *avrnames[] = {
-  "avr",
-  NULL
-};
-
-static sox_format_handler_t sox_avr_format = {
-  avrnames,
-  SOX_FILE_BIG_END,
-  sox_avrstartread,
-  sox_rawread,
-  NULL,
-  sox_avrstartwrite,
-  sox_avrwrite,
-  sox_avrstopwrite,
-  NULL
-};
-
-const sox_format_handler_t *sox_avr_format_fn(void);
-
-const sox_format_handler_t *sox_avr_format_fn(void)
+SOX_FORMAT_HANDLER(avr)
 {
-    return &sox_avr_format;
+  static char const * const names[] = { "avr", NULL };
+  static unsigned const write_encodings[] = {
+    SOX_ENCODING_SIGN2, 16, 8, 0,
+    SOX_ENCODING_UNSIGNED, 16, 8, 0,
+    0};
+  static sox_format_handler_t handler = {
+    names,
+    SOX_FILE_BIG_END|SOX_FILE_MONO|SOX_FILE_STEREO,
+    startread, sox_rawread, NULL,
+    startwrite, write_samples, stopwrite,
+    NULL, write_encodings, NULL
+  };
+  return &handler;
 }
--- a/src/band.h
+++ b/src/band.h
@@ -42,8 +42,8 @@
  *   Reference from the SPKit manual.
  */
 
-  p->a2 = exp(-2 * M_PI * bw_Hz / effp->ininfo.rate);
-  p->a1 = -4 * p->a2 / (1 + p->a2) * cos(2 * M_PI * p->fc / effp->ininfo.rate);
+  p->a2 = exp(-2 * M_PI * bw_Hz / effp->in_signal.rate);
+  p->a1 = -4 * p->a2 / (1 + p->a2) * cos(2 * M_PI * p->fc / effp->in_signal.rate);
   if (p->filter_type == filter_BPF_SPK_N)
     p->b0 = sqrt(((1+p->a2) * (1+p->a2) - p->a1*p->a1) * (1-p->a2) / (1+p->a2));
   else
--- a/src/biquad.c
+++ b/src/biquad.c
@@ -79,7 +79,7 @@
       "disp('Hit return to continue')\n"
       "pause\n"
       , effp->handler.name, p->gain, p->fc, width_str[p->width_type], p->width
-      , effp->ininfo.rate, effp->ininfo.rate
+      , effp->in_signal.rate, effp->in_signal.rate
       , p->b0, p->b1, p->b2, p->a1, p->a2
       );
     return SOX_EOF;
@@ -100,7 +100,7 @@
       "plot [f=10:Fs/2] [-35:25] 20*log10(H(f))\n"
       "pause -1 'Hit return to continue'\n"
       , effp->handler.name, p->gain, p->fc, width_str[p->width_type], p->width
-      , effp->ininfo.rate, effp->ininfo.rate
+      , effp->in_signal.rate, effp->in_signal.rate
       , p->b0, p->b1, p->b2, p->a1, p->a2
       );
     return SOX_EOF;
--- a/src/biquads.c
+++ b/src/biquads.c
@@ -141,7 +141,7 @@
 static int start(sox_effect_t * effp)
 {
   biquad_t p = (biquad_t) effp->priv;
-  double w0 = 2 * M_PI * p->fc / effp->ininfo.rate;
+  double w0 = 2 * M_PI * p->fc / effp->in_signal.rate;
   double A  = exp(p->gain / 40 * log(10.));
   double alpha = 0;
 
@@ -172,7 +172,7 @@
       break;
 
     case width_bw_old:
-      alpha = tan(M_PI * p->width / effp->ininfo.rate);
+      alpha = tan(M_PI * p->width / effp->in_signal.rate);
       break;
   }
   switch (p->filter_type) {
@@ -253,7 +253,7 @@
       break;
 
     case filter_deemph:  /* See deemph.plt for documentation */
-      if (effp->ininfo.rate != 44100) {
+      if (effp->in_signal.rate != 44100) {
         sox_fail("Sample rate must be 44100 (audio-CD)");
         return SOX_EOF;
       }
--- a/src/cdr.c
+++ b/src/cdr.c
@@ -1,61 +1,49 @@
 /*
- * CD Digital Audio format handler: pads to integer number of CDDA sectors
+ * File format: cdda   (c) 2006-8 SoX contributors
+ * Based on an original idea by David Elliott
  *
- * David Elliott, Sony Microsystems -  July 5, 1991
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
  *
- * Copyright 1991 David Elliott And Sundry Contributors
- * This source code is freely redistributable and may be used for
- * any purpose.  This copyright notice must be maintained. 
- * David Elliott And Sundry Contributors are not responsible for 
- * the consequences of using this software.
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
  */
 
 #include "sox_i.h"
 
-#define SECTOR_SIZE   (2352 / 2)
-#define samples       (*(sox_size_t *)ft->priv)
-
 static int start(sox_format_t * ft) 
 {
-  ft->signal.rate = 44100;
-  ft->signal.size = SOX_SIZE_16BIT;
-  ft->signal.encoding = SOX_ENCODING_SIGN2;
-  ft->signal.channels = 2;
-
-  if (ft->mode == 'r' && ft->seekable) /* Need length for seeking */
-    ft->length = sox_filelength(ft)/SOX_SIZE_16BIT;
-  
-  return SOX_SUCCESS;
+  return sox_check_read_params(ft, 2, 44100., SOX_ENCODING_SIGN2, 16, (off_t)0);
 }
 
-static sox_size_t write(
-    sox_format_t * ft, const sox_sample_t *buf, sox_size_t len) 
-{
-  samples += len;
-  return sox_rawwrite(ft, buf, len);
-}
-
 static int stopwrite(sox_format_t * ft) 
 {
-  sox_size_t i = samples % SECTOR_SIZE;
+  sox_size_t const sector_num_samples = 588 * ft->signal.channels;
+  sox_size_t i = ft->olength % sector_num_samples;
 
-  if (i) while (i++ < SECTOR_SIZE)     /* Pad with silence to multiple */
-    sox_writew(ft, 0);                 /* of SECTOR_SIZE samples. */
-
+  if (i) while (i++ < sector_num_samples)    /* Pad with silence to multiple */
+    sox_writew(ft, 0);                       /* of 1/75th of a second. */
   return SOX_SUCCESS;
 }
 
-const sox_format_handler_t *sox_cdr_format_fn(void);
-const sox_format_handler_t *sox_cdr_format_fn(void)
+SOX_FORMAT_HANDLER(cdr)
 {
-  static const char * names[] = {"cdda", "cdr", NULL};
-
+  static char const * const names[] = {"cdda", "cdr", NULL};
+  static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 16, 0, 0};
+  static sox_rate_t const write_rates[] = {44100, 0};
   static sox_format_handler_t handler = {
-    names, SOX_FILE_BIG_END,
+    names, SOX_FILE_BIG_END|SOX_FILE_STEREO,
     start, sox_rawread, NULL,
-    start, write, stopwrite,
-    sox_rawseek
+    NULL, sox_rawwrite, stopwrite,
+    sox_rawseek, write_encodings, write_rates
   };
-
   return &handler;
 }
--- a/src/chorus.c
+++ b/src/chorus.c
@@ -62,10 +62,11 @@
  * libSoX chorus effect file.
  */
 
+#include "sox_i.h"
+
 #include <stdlib.h> /* Harmless, and prototypes atof() etc. --dgc */
 #include <math.h>
 #include <string.h>
-#include "sox_i.h"
 
 #define MOD_SINE        0
 #define MOD_TRIANGLE    1
@@ -153,9 +154,9 @@
         }
         for ( i = 0; i < chorus->num_chorus; i++ ) {
                 chorus->samples[i] = (int) ( ( chorus->delay[i] + 
-                        chorus->depth[i] ) * effp->ininfo.rate / 1000.0);
+                        chorus->depth[i] ) * effp->in_signal.rate / 1000.0);
                 chorus->depth_samples[i] = (int) (chorus->depth[i] * 
-                        effp->ininfo.rate / 1000.0);
+                        effp->in_signal.rate / 1000.0);
 
                 if ( chorus->delay[i] < 20.0 )
                 {
@@ -197,7 +198,7 @@
                         sox_fail("chorus: decay must be less that 1.0!" );
                         return (SOX_EOF);
                 }
-                chorus->length[i] = effp->ininfo.rate / chorus->speed[i];
+                chorus->length[i] = effp->in_signal.rate / chorus->speed[i];
                 chorus->lookup_tab[i] = (int *) xmalloc(sizeof (int) * chorus->length[i]);
 
                 if (chorus->modulation[i] == MOD_SINE)
--- a/src/compand.c
+++ b/src/compand.c
@@ -11,6 +11,8 @@
  * the consequences of using this software.
  */
 
+#include "sox_i.h"
+
 #include <string.h>
 #include <stdlib.h>
 #include "compandt.h"
@@ -130,7 +132,7 @@
   unsigned i, j;
 
   sox_debug("%i input channel(s) expected: actually %i",
-      l->expectedChannels, effp->outinfo.channels);
+      l->expectedChannels, effp->out_signal.channels);
   for (i = 0; i < l->expectedChannels; ++i)
     sox_debug("Channel %i: attack = %g decay = %g", i,
         l->channels[i].attack_times[0], l->channels[i].attack_times[1]);
@@ -140,14 +142,14 @@
   /* Convert attack and decay rates using number of samples */
   for (i = 0; i < l->expectedChannels; ++i)
     for (j = 0; j < 2; ++j)
-      if (l->channels[i].attack_times[j] > 1.0/effp->outinfo.rate)
+      if (l->channels[i].attack_times[j] > 1.0/effp->out_signal.rate)
         l->channels[i].attack_times[j] = 1.0 -
-          exp(-1.0/(effp->outinfo.rate * l->channels[i].attack_times[j]));
+          exp(-1.0/(effp->out_signal.rate * l->channels[i].attack_times[j]));
       else
         l->channels[i].attack_times[j] = 1.0;
 
   /* Allocate the delay buffer */
-  l->delay_buf_size = l->delay * effp->outinfo.rate * effp->outinfo.channels;
+  l->delay_buf_size = l->delay * effp->out_signal.rate * effp->out_signal.channels;
   if (l->delay_buf_size > 0)
     l->delay_buf = xcalloc((sox_size_t)l->delay_buf_size, sizeof(*l->delay_buf));
   l->delay_buf_index = 0;
@@ -177,7 +179,7 @@
 {
   compand_t l = (compand_t) effp->priv;
   int len =  (*isamp > *osamp) ? *osamp : *isamp;
-  int filechans = effp->outinfo.channels;
+  int filechans = effp->out_signal.channels;
   int idone,odone;
 
   for (idone = 0,odone = 0; idone < len; ibuf += filechans) {
@@ -241,7 +243,7 @@
   if (l->delay_buf_full == 0)
     l->delay_buf_index = 0;
   while (done < *osamp && l->delay_buf_cnt > 0)
-    for (chan = 0; chan < effp->outinfo.channels; ++chan) {
+    for (chan = 0; chan < effp->out_signal.channels; ++chan) {
       int c = l->expectedChannels > 1 ? chan : 0;
       double level_in_lin = l->channels[c].volume;
       double level_out_lin = sox_compandt(&l->transfer_fn, level_in_lin);
--- a/src/compandt.c
+++ b/src/compandt.c
@@ -16,6 +16,8 @@
  * Compander Transfer Function: (c) 2007 [email protected]
  */
 
+#include "sox_i.h"
+
 #include "compandt.h"
 #include <string.h>
 
--- a/src/compandt.h
+++ b/src/compandt.h
@@ -16,7 +16,6 @@
  * Compander Transfer Function: (c) 2007 [email protected]
  */
 
-#include "sox_i.h"
 #include <math.h>
 
 typedef struct {
--- a/src/cvsd-fmt.c
+++ b/src/cvsd-fmt.c
@@ -1,51 +1,32 @@
 /*
- *      CVSD format module (implementation in cvsd.c)
+ * File format: CVSD (see cvsd.c)        (c) 2007-8 SoX contributors
  *
- *      Copyright (C) 1996-2007 Thomas Sailer and SoX Contributors
- *      Thomas Sailer ([email protected]) (HB9JNX/AE4WA)
- *      Swiss Federal Institute of Technology, Electronics Lab
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
  *
- *   This library is free software; you can redistribute it and/or
- *   modify it under the terms of the GNU Lesser General Public
- *   License as published by the Free Software Foundation; either
- *   version 2 of the License, or (at your option) any later version.
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
+ * General Public License for more details.
  *
- *   This library is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *   Lesser General Public License for more details.
- *
- *   You should have received a copy of the GNU Lesser General Public
- *   License along with this library; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
  */
 
-#include "sox_i.h"
 #include "cvsd.h"
- 
- /* Cont. Variable Slope Delta */
-static const char *cvsdnames[] = {
-  "cvs",
-  "cvsd",
-  NULL
-};
 
-static sox_format_handler_t sox_cvsd_format = {
-  cvsdnames,
-  0,
-  sox_cvsdstartread,
-  sox_cvsdread,
-  sox_cvsdstopread,
-  sox_cvsdstartwrite,
-  sox_cvsdwrite,
-  sox_cvsdstopwrite,
-  NULL
-};
-
-const sox_format_handler_t *sox_cvsd_format_fn(void);
-
-const sox_format_handler_t *sox_cvsd_format_fn(void)
+SOX_FORMAT_HANDLER(cvsd)
 {
-    return &sox_cvsd_format;
+  static char const * const names[] = {"cvsd", "cvs", NULL};
+  static unsigned const write_encodings[] = {SOX_ENCODING_CVSD, 1, 0, 0};
+  static sox_format_handler_t const handler = {
+    names, SOX_FILE_MONO,
+    sox_cvsdstartread, sox_cvsdread, sox_cvsdstopread,
+    sox_cvsdstartwrite, sox_cvsdwrite, sox_cvsdstopwrite,
+    sox_rawseek, write_encodings, NULL
+  };
+  return &handler;
 }
--- a/src/cvsd.c
+++ b/src/cvsd.c
@@ -118,8 +118,7 @@
         p->cvsd_rate = (ft->signal.rate <= 24000) ? 16000 : 32000;
         ft->signal.rate = 8000;
         ft->signal.channels = 1;
-        ft->signal.size = SOX_SIZE_16BIT; /* make output format default to words */
-        ft->signal.encoding = SOX_ENCODING_SIGN2;
+        sox_rawstart(ft, sox_true, sox_false, sox_true, SOX_ENCODING_CVSD, 1);
         /*
          * initialize the decoder
          */
@@ -146,7 +145,7 @@
         p->com.v_min = 1;
         p->com.v_max = -1;
         sox_report("cvsd: bit rate %dbit/s, bits from %s", p->cvsd_rate,
-               ft->signal.reverse_bits ? "msb to lsb" : "lsb to msb");
+               ft->encoding.reverse_bits ? "msb to lsb" : "lsb to msb");
 }
 
 /* ---------------------------------------------------------------------- */
@@ -465,7 +464,7 @@
                 len = sizeof(hdr->Filename)-1;
         memcpy(hdr->Filename, ft->filename, len);
         hdr->Id = hdr->State = 0;
-        hdr->Unixtime = time(NULL);
+        hdr->Unixtime = sox_globals.repeatable? 0 : time(NULL);
         hdr->Usender = hdr->Ureceiver = 0;
         hdr->Length = p->bytes_written;
         hdr->Srate = p->cvsd_rate/100;
--- a/src/cvsd.h
+++ b/src/cvsd.h
@@ -20,6 +20,7 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  */
+#include "sox_i.h"
 
 int sox_cvsdstartread(sox_format_t * ft);
 int sox_cvsdstartwrite(sox_format_t * ft);
--- a/src/dat.c
+++ b/src/dat.c
@@ -52,8 +52,7 @@
     if (ft->signal.channels == 0)
        ft->signal.channels = 1;
 
-    ft->signal.size = SOX_SIZE_64BIT;
-    ft->signal.encoding = SOX_ENCODING_FLOAT;
+    ft->encoding.encoding = SOX_ENCODING_FLOAT_TEXT;
 
     return (SOX_SUCCESS);
 }
@@ -63,8 +62,6 @@
     dat_t dat = (dat_t) ft->priv;
     char s[LINEWIDTH];
 
-    ft->signal.size = SOX_SIZE_64BIT;
-    ft->signal.encoding = SOX_ENCODING_FLOAT;
     dat->timevalue = 0.0;
     dat->deltat = 1.0 / (double)ft->signal.rate;
     /* Write format comments to start of file */
@@ -144,7 +141,7 @@
         sox_writes(ft, s);
         done++;
       }
-      sprintf(s," \015\n");
+      sprintf(s," \r\n");
       sox_writes(ft, s);
       dat->timevalue += dat->deltat;
     }
@@ -151,27 +148,15 @@
     return done;
 }
 
-/* Text data samples */
-static const char *datnames[] = {
-  "dat",
-  NULL
-};
-
-static sox_format_handler_t sox_dat_format = {
-  datnames,
-  0,
-  sox_datstartread,
-  sox_datread,
-  NULL,
-  sox_datstartwrite,
-  sox_datwrite,
-  NULL,
-  NULL
-};
-
-const sox_format_handler_t *sox_dat_format_fn(void);
-
-const sox_format_handler_t *sox_dat_format_fn(void)
+SOX_FORMAT_HANDLER(dat)
 {
-    return &sox_dat_format;
+  static char const * const names[] = {"dat", NULL};
+  static unsigned const write_encodings[] = {SOX_ENCODING_FLOAT_TEXT, 0, 0};
+  static sox_format_handler_t const handler = {
+    names, 0,
+    sox_datstartread, sox_datread, NULL,
+    sox_datstartwrite, sox_datwrite, NULL,
+    NULL, write_encodings, NULL
+  };
+  return &handler;
 }
--- a/src/dither.c
+++ b/src/dither.c
@@ -12,9 +12,10 @@
  *
  */
 
+#include "sox_i.h"
+
 #include <stdlib.h>
 #include <math.h>
-#include "sox_i.h"
 
 typedef struct dither {
   double amount;
@@ -48,17 +49,10 @@
 {
   dither_t dither = (dither_t) effp->priv;
 
-  if (effp->outinfo.encoding == SOX_ENCODING_ULAW ||
-      effp->outinfo.encoding == SOX_ENCODING_ALAW) {
-    dither->amount *= 16;
-    return SOX_SUCCESS;
-  } else if (effp->outinfo.size == SOX_SIZE_BYTE) {
-    dither->amount *= 256;
-    return SOX_SUCCESS;
-  } else if (effp->outinfo.size == SOX_SIZE_16BIT)
-    return SOX_SUCCESS;
-
-  return SOX_EFF_NULL;   /* Dithering not needed at >= 24 bits */
+  if (effp->out_signal.precision > 16)
+    return SOX_EFF_NULL;   /* Dithering not needed at >= 24 bits */
+  dither->amount *= 1 << (16 - effp->out_signal.precision);
+  return SOX_SUCCESS;
 }
 
 static int flow(sox_effect_t * effp, const sox_sample_t * ibuf,
--- a/src/dvms-fmt.c
+++ b/src/dvms-fmt.c
@@ -1,51 +1,32 @@
 /*
- *      DVMS format module (implementation in cvsd.c)
+ * File format: DVMS (see cvsd.c)        (c) 2007-8 SoX contributors
  *
- *      Copyright (C) 1996-2007 Thomas Sailer and SoX Contributors
- *      Thomas Sailer ([email protected]) (HB9JNX/AE4WA)
- *      Swiss Federal Institute of Technology, Electronics Lab
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
  *
- *   This library is free software; you can redistribute it and/or
- *   modify it under the terms of the GNU Lesser General Public
- *   License as published by the Free Software Foundation; either
- *   version 2 of the License, or (at your option) any later version.
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
+ * General Public License for more details.
  *
- *   This library is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *   Lesser General Public License for more details.
- *
- *   You should have received a copy of the GNU Lesser General Public
- *   License along with this library; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
  */
 
-#include "sox_i.h"
 #include "cvsd.h"
- 
-/* Cont. Variable Solot Delta */
-static const char *dvmsnames[] = {
-  "vms",
-  "dvms",
-  NULL
-};
 
-static sox_format_handler_t sox_dvms_format = {
-  dvmsnames,
-  0,
-  sox_dvmsstartread,
-  sox_cvsdread,
-  sox_cvsdstopread,
-  sox_dvmsstartwrite,
-  sox_cvsdwrite,
-  sox_dvmsstopwrite,
-  NULL
-};
-
-const sox_format_handler_t *sox_dvms_format_fn(void);
-
-const sox_format_handler_t *sox_dvms_format_fn(void)
+SOX_FORMAT_HANDLER(dvms)
 {
-    return &sox_dvms_format;
+  static char const * const names[] = {"dvms", "vms", NULL};
+  static unsigned const write_encodings[] = {SOX_ENCODING_CVSD, 1, 0, 0};
+  static sox_format_handler_t const handler = {
+    names, SOX_FILE_MONO,
+    sox_dvmsstartread, sox_cvsdread, sox_cvsdstopread,
+    sox_dvmsstartwrite, sox_cvsdwrite, sox_dvmsstopwrite,
+    NULL, write_encodings, NULL
+  };
+  return &handler;
 }
--- a/src/earwax.c
+++ b/src/earwax.c
@@ -67,7 +67,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) {
+  if (effp->in_signal.rate != 44100 || effp->in_signal.channels != 2) {
     sox_fail("works only with stereo audio sampled at 44100Hz (i.e. CDDA)");
     return SOX_EOF;
   }
--- a/src/echo.c
+++ b/src/echo.c
@@ -55,9 +55,10 @@
  * libSoX reverb effect file.
  */
 
+#include "sox_i.h"
+
 #include <stdlib.h> /* Harmless, and prototypes atof() etc. --dgc */
 #include <math.h>
-#include "sox_i.h"
 
 #define DELAY_BUFSIZ ( 50 * 50U * 1024 )
 #define MAX_ECHOS 7     /* 24 bit x ( 1 + MAX_ECHOS ) = */
@@ -132,7 +133,7 @@
                 return (SOX_EOF);
         }
         for ( i = 0; i < echo->num_delays; i++ ) {
-                echo->samples[i] = echo->delay[i] * effp->ininfo.rate / 1000.0;
+                echo->samples[i] = echo->delay[i] * effp->in_signal.rate / 1000.0;
                 if ( echo->samples[i] < 1 )
                 {
                     sox_fail("echo: delay must be positive!");
@@ -141,7 +142,7 @@
                 if ( echo->samples[i] > (sox_ssize_t)DELAY_BUFSIZ )
                 {
                         sox_fail("echo: delay must be less than %g seconds!",
-                                DELAY_BUFSIZ / effp->ininfo.rate );
+                                DELAY_BUFSIZ / effp->in_signal.rate );
                         return (SOX_EOF);
                 }
                 if ( echo->decay[i] < 0.0 )
--- a/src/echos.c
+++ b/src/echos.c
@@ -46,9 +46,10 @@
  * libSoX reverb effect file.
  */
 
+#include "sox_i.h"
+
 #include <stdlib.h> /* Harmless, and prototypes atof() etc. --dgc */
 #include <math.h>
-#include "sox_i.h"
 
 #define DELAY_BUFSIZ ( 50 * 50U * 1024 )
 #define MAX_ECHOS 7     /* 24 bit x ( 1 + MAX_ECHOS ) = */
@@ -125,7 +126,7 @@
                 return (SOX_EOF);
         }
         for ( i = 0; i < echos->num_delays; i++ ) {
-                echos->samples[i] = echos->delay[i] * effp->ininfo.rate / 1000.0;
+                echos->samples[i] = echos->delay[i] * effp->in_signal.rate / 1000.0;
                 if ( echos->samples[i] < 1 )
                 {
                     sox_fail("echos: delay must be positive!");
@@ -134,7 +135,7 @@
                 if ( echos->samples[i] > (sox_ssize_t)DELAY_BUFSIZ )
                 {
                         sox_fail("echos: delay must be less than %g seconds!",
-                                DELAY_BUFSIZ / effp->ininfo.rate );
+                                DELAY_BUFSIZ / effp->in_signal.rate );
                         return (SOX_EOF);
                 }
                 if ( echos->decay[i] < 0.0 )
--- a/src/effects.c
+++ b/src/effects.c
@@ -92,10 +92,14 @@
 
 /* Effects chain: */
 
-sox_effects_chain_t * sox_create_effects_chain(void)
+sox_effects_chain_t * sox_create_effects_chain(
+    sox_encodinginfo_t const * in_enc,
+    sox_encodinginfo_t const * out_enc)
 {
   sox_effects_chain_t * result = xcalloc(1, sizeof(sox_effects_chain_t));
   result->global_info = sox_effects_globals;
+  result->in_enc = in_enc;
+  result->out_enc = out_enc;
   return result;
 }
 
@@ -117,8 +121,7 @@
  * output rate and channels the effect does produce are written back to *in,
  * ready for the next effect in the chain.
  */
-int sox_add_effect(sox_effects_chain_t * chain, sox_effect_t * effp, sox_signalinfo_t * in, sox_signalinfo_t
-    const * out)
+int sox_add_effect(sox_effects_chain_t * chain, sox_effect_t * effp, sox_signalinfo_t * in, sox_signalinfo_t const * out)
 {
   int ret, (*start)(sox_effect_t * effp) = effp->handler.start;
   unsigned f;
@@ -129,17 +132,19 @@
     return SOX_SUCCESS;
   }
   effp->global_info = &chain->global_info;
-  effp->ininfo = *in;
-  effp->outinfo = *out;
+  effp->in_signal = *in;
+  effp->out_signal = *out;
+  effp->in_encoding = chain->in_enc;
+  effp->out_encoding = chain->out_enc;
   if (!(effp->handler.flags & SOX_EFF_CHAN))
-    effp->outinfo.channels = in->channels;
+    effp->out_signal.channels = in->channels;
   if (!(effp->handler.flags & SOX_EFF_RATE))
-    effp->outinfo.rate = in->rate;
+    effp->out_signal.rate = in->rate;
   if (!(effp->handler.flags & SOX_EFF_PREC))
-    effp->outinfo.size = in->size;
+    effp->out_signal.precision = in->precision;
 
   effp->flows =
-    (effp->handler.flags & SOX_EFF_MCHAN)? 1 : effp->ininfo.channels;
+    (effp->handler.flags & SOX_EFF_MCHAN)? 1 : effp->in_signal.channels;
   effp->clips = 0;
   effp->imin = 0;
   eff0 = *effp;
@@ -151,7 +156,7 @@
   if (ret != SOX_SUCCESS)
     return SOX_EOF;
 
-  *in = effp->outinfo;
+  *in = effp->out_signal;
 
   if (chain->length == SOX_MAX_EFFECTS) {
     sox_fail("Too many effects!");
--- a/src/example1.c
+++ b/src/example1.c
@@ -29,9 +29,9 @@
 
 static int input_drain(sox_effect_t *effp, sox_sample_t * obuf, sox_size_t * osamp)
 {
-  *osamp -= *osamp % effp->outinfo.channels;
+  *osamp -= *osamp % effp->out_signal.channels;
   *osamp = sox_read(in, obuf, *osamp);
-  *osamp -= *osamp % effp->outinfo.channels;
+  *osamp -= *osamp % effp->out_signal.channels;
   if (!*osamp && in->sox_errno)
     fprintf(stderr, "%s: %s\n", in->filename, in->sox_errstr);
   return *osamp? SOX_SUCCESS : SOX_EOF;
@@ -73,7 +73,7 @@
  */
 int main(int argc, char * argv[])
 {
-  sox_effects_chain_t * chain = sox_create_effects_chain();
+  sox_effects_chain_t * chain;
   sox_effect_t e;
   char * vol[] = {"3dB"};
 
@@ -80,7 +80,11 @@
   assert(argc == 3);
   assert(sox_format_init() == SOX_SUCCESS);
 
-  assert(in = sox_open_read(argv[1], NULL, NULL));
+  assert(in = sox_open_read(argv[1], NULL, NULL, NULL));
+  assert(out = sox_open_write(NULL, argv[2], &in->signal, NULL, NULL, NULL, 0, NULL, 0));
+
+  chain = sox_create_effects_chain(&in->encoding, &out->encoding);
+
   sox_create_effect(&e, input_handler());
   assert(sox_add_effect(chain, &e, &in->signal, &in->signal) == SOX_SUCCESS);
 
@@ -92,14 +96,13 @@
   assert(e.handler.getopts(&e, 0, NULL) == SOX_SUCCESS);
   assert(sox_add_effect(chain, &e, &in->signal, &in->signal) == SOX_SUCCESS);
 
-  assert(out = sox_open_write(NULL, argv[2], &in->signal, NULL, NULL, 0, NULL, 0));
   sox_create_effect(&e, output_handler());
   assert(sox_add_effect(chain, &e, &in->signal, &in->signal) == SOX_SUCCESS);
 
-  assert(sox_flow_effects(chain, NULL) == SOX_SUCCESS);
+  sox_flow_effects(chain, NULL);
 
-  sox_close(out);
   sox_delete_effects(chain);
+  sox_close(out);
   sox_close(in);
   sox_format_quit();
   free(chain);
--- a/src/fade.c
+++ b/src/fade.c
@@ -9,6 +9,8 @@
  * the consequences of using this software.
  */
 
+#include "sox_i.h"
+
 /* Fade curves */
 #define FADE_QUARTER    'q'     /* Quarter of sine wave, 0 to pi/2 */
 #define FADE_HALF       'h'     /* Half of sine wave, pi/2 to 1.5 * pi
@@ -21,7 +23,6 @@
 
 #include <math.h>
 #include <string.h>
-#include "sox_i.h"
 
 /* Private data for fade file */
 typedef struct fadestuff
@@ -118,7 +119,7 @@
 
     /* converting time values to samples */
     fade->in_start = 0;
-    if (sox_parsesamples(effp->ininfo.rate, fade->in_stop_str,
+    if (sox_parsesamples(effp->in_signal.rate, fade->in_stop_str,
                         &fade->in_stop, 't') == NULL)
       return sox_usage(effp);
 
@@ -127,7 +128,7 @@
     if (fade->out_stop_str)
     {
         fade->do_out = 1;
-        if (sox_parsesamples(effp->ininfo.rate, fade->out_stop_str,
+        if (sox_parsesamples(effp->in_signal.rate, fade->out_stop_str,
                             &fade->out_stop, 't') == NULL)
           return sox_usage(effp);
 
@@ -134,7 +135,7 @@
         /* See if user wants to fade out. */
         if (fade->out_start_str)
         {
-            if (sox_parsesamples(effp->ininfo.rate, fade->out_start_str,
+            if (sox_parsesamples(effp->in_signal.rate, fade->out_start_str,
                         &fade->out_start, 't') == NULL)
               return sox_usage(effp);
             /* Fade time is relative to stop time. */
@@ -238,7 +239,7 @@
 
         /* Process next channel */
         chcnt++;
-        if (chcnt >= effp->ininfo.channels)
+        if (chcnt >= effp->in_signal.channels)
         { /* all channels of this sample processed */
             chcnt = 0;
             fade->samplesdone += 1;
@@ -281,7 +282,7 @@
         *osamp += 1;
 
         t_chan++;
-        if (t_chan >= effp->ininfo.channels)
+        if (t_chan >= effp->in_signal.channels)
         {
             fade->samplesdone += 1;
             t_chan = 0;
--- a/src/ffmpeg.c
+++ b/src/ffmpeg.c
@@ -153,7 +153,7 @@
   ffmpeg_t ffmpeg = (ffmpeg_t)ft->priv;
   AVFormatParameters params;
   int ret;
-  unsigned i;
+  int i;
 
   ffmpeg->audio_buf = xcalloc(1, AVCODEC_MAX_AUDIO_FRAME_SIZE);
 
@@ -198,8 +198,8 @@
 
   /* Copy format info */
   ft->signal.rate = ffmpeg->audio_st->codec->sample_rate;
-  ft->signal.size = SOX_SIZE_16BIT;
-  ft->signal.encoding = SOX_ENCODING_SIGN2;
+  ft->encoding.bits_per_sample = 16;
+  ft->encoding.encoding = SOX_ENCODING_SIGN2;
   ft->signal.channels = ffmpeg->audio_st->codec->channels;
   ft->length = 0; /* Currently we can't seek; no idea how to get this
                      info from ffmpeg anyway (in time, yes, but not in
@@ -212,7 +212,7 @@
  * Read up to len samples of type sox_sample_t from file into buf[].
  * Return number of samples read.
  */
-static sox_size_t read(sox_format_t * ft, sox_sample_t *buf, sox_size_t len)
+static sox_size_t read_samples(sox_format_t * ft, sox_sample_t *buf, sox_size_t len)
 {
   ffmpeg_t ffmpeg = (ffmpeg_t)ft->priv;
   AVPacket *pkt = &ffmpeg->audio_pkt;
@@ -397,7 +397,7 @@
  * Write up to len samples of type sox_sample_t from buf[] into file.
  * Return number of samples written.
  */
-static sox_size_t write(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len)
+static sox_size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len)
 {
   ffmpeg_t ffmpeg = (ffmpeg_t)ft->priv;
   sox_size_t nread = 0, nwritten = 0;
@@ -443,7 +443,7 @@
 static int stopwrite(sox_format_t * ft)
 {
   ffmpeg_t ffmpeg = (ffmpeg_t)ft->priv;
-  unsigned i;
+  int i;
 
   /* Close CODEC */
   if (ffmpeg->audio_st) {
@@ -472,35 +472,29 @@
   return SOX_SUCCESS;
 }
 
+SOX_FORMAT_HANDLER(ffmpeg)
+{
+  /* Format file suffixes */
+  /* For now, comment out formats built in to SoX */
+  static char const * const names[] = {
+    "ffmpeg", /* special type to force use of ffmpeg */
+    "mp4",
+    "m4a",
+    "avi",
+    "wmv",
+    "mpg",
+    NULL
+  };
 
-/* Format file suffixes */
-/* For now, comment out formats built in to SoX */
-static const char *names[] = {
-  "ffmpeg", /* special type to force use of ffmpeg */
-  "mp4",
-  "m4a",
-  "avi",
-  "wmv",
-  "mpg",
-  NULL
-};
+  static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 16, 0, 0};
 
-/* Format descriptor */
-static sox_format_handler_t sox_ffmpeg_format = {
-  names,
-  SOX_FILE_NOSTDIO,
-  startread,
-  read,
-  stopread,
-  startwrite,
-  write,
-  stopwrite,
-  NULL
-};
+  static sox_format_handler_t handler = {
+    names,
+    SOX_FILE_NOSTDIO,
+    startread, read_samples, stopread,
+    startwrite, write_samples, stopwrite,
+    NULL, write_encodings, NULL
+  };
 
-const sox_format_handler_t *sox_ffmpeg_format_fn(void);
-
-const sox_format_handler_t *sox_ffmpeg_format_fn(void)
-{
-  return &sox_ffmpeg_format;
+  return &handler;
 }
--- a/src/filter.c
+++ b/src/filter.c
@@ -21,12 +21,12 @@
  *
  */
 
+#include "sox_i.h"
+
 #include <math.h>
 #include <string.h>
 #include <stdlib.h>
 
-#include "sox_i.h"
-
 #define ISCALE 0x10000
 #define BUFFSIZE 8192
 
@@ -100,7 +100,7 @@
         long Xh0, Xh1, Xh;
         int i;
 
-        f->rate = effp->ininfo.rate;
+        f->rate = effp->in_signal.rate;
 
         /* adjust upper frequency to Nyquist if necessary */
         if (f->freq1 > (sox_sample_t)f->rate/2 || f->freq1 <= 0)
--- a/src/flac.c
+++ b/src/flac.c
@@ -179,9 +179,9 @@
     return SOX_EOF;
   }
 
-  ft->signal.encoding = SOX_ENCODING_FLAC;
+  ft->encoding.encoding = SOX_ENCODING_FLAC;
   ft->signal.rate = decoder->sample_rate;
-  ft->signal.size = decoder->bits_per_sample >> 3;
+  ft->encoding.bits_per_sample = decoder->bits_per_sample;
   ft->signal.channels = decoder->channels;
   ft->length = decoder->total_samples * decoder->channels;
   return SOX_SUCCESS;
@@ -188,7 +188,7 @@
 }
 
 
-static sox_size_t read(sox_format_t * const ft, sox_sample_t * sampleBuffer, sox_size_t const requested)
+static sox_size_t read_samples(sox_format_t * const ft, sox_sample_t * sampleBuffer, sox_size_t const requested)
 {
   Decoder * decoder = (Decoder *) ft->priv;
   size_t actual = 0;
@@ -305,9 +305,9 @@
   FLAC__StreamEncoderState status;
   unsigned compression_level = MAX_COMPRESSION; /* Default to "best" */
 
-  if (ft->signal.compression != HUGE_VAL) {
-    compression_level = ft->signal.compression;
-    if (compression_level != ft->signal.compression || 
+  if (ft->encoding.compression != HUGE_VAL) {
+    compression_level = ft->encoding.compression;
+    if (compression_level != ft->encoding.compression || 
         compression_level > MAX_COMPRESSION) {
       sox_fail_errno(ft, SOX_EINVAL,
                  "FLAC compression level must be a whole number from 0 to %i",
@@ -324,13 +324,8 @@
   }
   encoder->decoded_samples = xmalloc(sox_globals.bufsiz * sizeof(FLAC__int32));
 
-  /* FIXME: FLAC should not need to know about this oddity */
-  if (ft->signal.encoding < SOX_ENCODING_SIZE_IS_WORD)
-    ft->signal.size = SOX_SIZE_16BIT;
-  ft->signal.encoding = SOX_ENCODING_FLAC;
+  encoder->bits_per_sample = ft->encoding.bits_per_sample;
 
-  encoder->bits_per_sample = (ft->signal.size > 4 ? 4 : ft->signal.size) << 3;
-
   sox_report("encoding at %i bits per sample", encoder->bits_per_sample);
 
   FLAC__stream_encoder_set_channels(encoder->flac, ft->signal.channels);
@@ -455,7 +450,7 @@
 
 
 
-static sox_size_t write(sox_format_t * const ft, sox_sample_t const * const sampleBuffer, sox_size_t const len)
+static sox_size_t write_samples(sox_format_t * const ft, sox_sample_t const * const sampleBuffer, sox_size_t const len)
 {
   Encoder * encoder = (Encoder *) ft->priv;
   unsigned i;
@@ -519,16 +514,15 @@
 }
 
 
-const sox_format_handler_t *sox_flac_format_fn(void);
-
-const sox_format_handler_t *sox_flac_format_fn(void)
+SOX_FORMAT_HANDLER(flac)
 {
   static char const * const names[] = {"flac", NULL};
-  static sox_format_handler_t handler = {
+  static unsigned const encodings[] = {SOX_ENCODING_FLAC, 8, 16, 24, 0, 0};
+  static sox_format_handler_t const handler = {
     names, 0,
-    start_read, read, stop_read,
-    start_write, write, stop_write,
-    seek
+    start_read, read_samples, stop_read,
+    start_write, write_samples, stop_write,
+    seek, encodings, NULL
   };
   return &handler;
 }
--- a/src/flanger.c
+++ b/src/flanger.c
@@ -153,7 +153,7 @@
 static int sox_flanger_start(sox_effect_t * effp)
 {
   flanger_t f = (flanger_t) effp->priv;
-  int c, channels = effp->ininfo.channels;
+  int c, channels = effp->in_signal.channels;
 
   if (channels > MAX_CHANNELS) {
     sox_fail("Can not operate with more than %i channels", MAX_CHANNELS);
@@ -177,7 +177,7 @@
 
   /* Create the delay buffers, one for each channel: */
   f->delay_buf_length =
-    (f->delay_min + f->delay_depth) / 1000 * effp->ininfo.rate + 0.5;
+    (f->delay_min + f->delay_depth) / 1000 * effp->in_signal.rate + 0.5;
   ++f->delay_buf_length;  /* Need 0 to n, i.e. n + 1. */
   ++f->delay_buf_length;  /* Quadratic interpolator needs one more. */
   for (c = 0; c < channels; ++c)
@@ -184,7 +184,7 @@
     f->delay_bufs[c] = xcalloc(f->delay_buf_length, sizeof(*f->delay_bufs[0]));
 
   /* Create the LFO lookup table: */
-  f->lfo_length = effp->ininfo.rate / f->speed;
+  f->lfo_length = effp->in_signal.rate / f->speed;
   f->lfo = xcalloc(f->lfo_length, sizeof(*f->lfo));
   sox_generate_wave_table(
       f->wave_shape,
@@ -191,7 +191,7 @@
       SOX_FLOAT,
       f->lfo,
       f->lfo_length,
-      (double)(sox_size_t)(f->delay_min / 1000 * effp->ininfo.rate + .5),
+      (double)(sox_size_t)(f->delay_min / 1000 * effp->in_signal.rate + .5),
       (double)(f->delay_buf_length - 2),
       3 * M_PI_2);  /* Start the sweep at minimum delay (for mono at least) */
 
@@ -207,7 +207,7 @@
     sox_sample_t * obuf, sox_size_t * isamp, sox_size_t * osamp)
 {
   flanger_t f = (flanger_t) effp->priv;
-  int c, channels = effp->ininfo.channels;
+  int c, channels = effp->in_signal.channels;
   sox_size_t len = (*isamp > *osamp ? *osamp : *isamp) / channels;
 
   *isamp = *osamp = len * channels;
@@ -261,7 +261,7 @@
 static int sox_flanger_stop(sox_effect_t * effp)
 {
   flanger_t f = (flanger_t) effp->priv;
-  int c, channels = effp->ininfo.channels;
+  int c, channels = effp->in_signal.channels;
 
   for (c = 0; c < channels; ++c)
     free(f->delay_bufs[c]);
--- a/src/formats.h
+++ b/src/formats.h
@@ -12,6 +12,7 @@
   FORMAT(dvms)
   FORMAT(gsm)
   FORMAT(hcom)
+  FORMAT(htk)
   FORMAT(ima)
   FORMAT(la)
   FORMAT(lpc10)
--- a/src/gsm.c
+++ b/src/gsm.c
@@ -58,8 +58,7 @@
         struct gsmpriv *p = (struct gsmpriv *) ft->priv;
         unsigned ch;
         
-        ft->signal.encoding = SOX_ENCODING_GSM;
-        ft->signal.size = SOX_SIZE_BYTE;
+        ft->encoding.encoding = SOX_ENCODING_GSM;
         if (!ft->signal.rate)
                 ft->signal.rate = 8000;
 
@@ -235,27 +234,15 @@
         return sox_gsmstopread(ft); /* destroy handles and free buffers */
 }
 
-/* GSM 06.10 */
-static const char *gsmnames[] = {
-  "gsm",
-  NULL
-};
-
-static sox_format_handler_t sox_gsm_format = {
-  gsmnames,
-  0,
-  sox_gsmstartread,
-  sox_gsmread,
-  sox_gsmstopread,
-  sox_gsmstartwrite,
-  sox_gsmwrite,
-  sox_gsmstopwrite,
-  NULL
-};
-
-const sox_format_handler_t *sox_gsm_format_fn(void);
-
-const sox_format_handler_t *sox_gsm_format_fn(void)
+SOX_FORMAT_HANDLER(gsm)
 {
-    return &sox_gsm_format;
+  static char const * const names[] = {"gsm", NULL};
+  static unsigned const write_encodings[] = {SOX_ENCODING_GSM, 0, 0};
+  static sox_format_handler_t handler = {
+    names, 0,
+    sox_gsmstartread, sox_gsmread, sox_gsmstopread,
+    sox_gsmstartwrite, sox_gsmwrite, sox_gsmstopwrite,
+    NULL, write_encodings, NULL
+  };
+  return &handler;
 }
--- a/src/hcom.c
+++ b/src/hcom.c
@@ -2,7 +2,7 @@
  * libSoX Macintosh HCOM format.
  * These are really FSSD type files with Huffman compression,
  * in MacBinary format.
- * To do: make the MacBinary format optional (so that .data files
+ * TODO: make the MacBinary format optional (so that .data files
  * are also acceptable).  (How to do this on output?)
  *
  * September 25, 1991
@@ -54,7 +54,7 @@
         int32_t curword;
 };
 
-static int sox_hcomstartread(sox_format_t * ft)
+static int startread(sox_format_t * ft)
 {
         struct readpriv *p = (struct readpriv *) ft->priv;
         int i;
@@ -116,8 +116,8 @@
         sox_readw(ft, &dictsize);
 
         /* Translate to sox parameters */
-        ft->signal.encoding = SOX_ENCODING_UNSIGNED;
-        ft->signal.size = SOX_SIZE_BYTE;
+        ft->encoding.encoding = SOX_ENCODING_HCOM;
+        ft->encoding.bits_per_sample = 8;
         ft->signal.rate = 22050 / divisor;
         ft->signal.channels = 1;
 
@@ -149,7 +149,7 @@
         return (SOX_SUCCESS);
 }
 
-static sox_size_t sox_hcomread(sox_format_t * ft, sox_sample_t *buf, sox_size_t len)
+static sox_size_t read_samples(sox_format_t * ft, sox_sample_t *buf, sox_size_t len)
 {
         register struct readpriv *p = (struct readpriv *) ft->priv;
         int done = 0;
@@ -213,7 +213,7 @@
         return done;
 }
 
-static int sox_hcomstopread(sox_format_t * ft)
+static int stopread(sox_format_t * ft)
 {
         register struct readpriv *p = (struct readpriv *) ft->priv;
 
@@ -240,31 +240,17 @@
 
 #define BUFINCR (10*BUFSIZ)
 
-static int sox_hcomstartwrite(sox_format_t * ft)
+static int startwrite(sox_format_t * ft)
 {
-        register struct writepriv *p = (struct writepriv *) ft->priv;
+  struct writepriv * p = (struct writepriv *) ft->priv;
 
-        switch ((int)ft->signal.rate) {
-        case 22050:
-        case 22050/2:
-        case 22050/3:
-        case 22050/4:
-                break;
-        default:
-                sox_fail_errno(ft,SOX_EFMT,"unacceptable output rate for HCOM: try 5512, 7350, 11025 or 22050 hertz");
-                return (SOX_EOF);
-        }
-        ft->signal.size = SOX_SIZE_BYTE;
-        ft->signal.encoding = SOX_ENCODING_UNSIGNED;
-        ft->signal.channels = 1;
-
-        p->size = BUFINCR;
-        p->pos = 0;
-        p->data = (unsigned char *) xmalloc(p->size);
-        return (SOX_SUCCESS);
+  p->size = BUFINCR;
+  p->pos = 0;
+  p->data = xmalloc(p->size);
+  return SOX_SUCCESS;
 }
 
-static sox_size_t sox_hcomwrite(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len)
+static sox_size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len)
 {
   struct writepriv *p = (struct writepriv *) ft->priv;
   sox_sample_t datum;
@@ -321,10 +307,10 @@
   }
 }
 
-static void compress(sox_format_t * ft, unsigned char **df, int32_t *dl, sox_rate_t fr)
+static void compress(sox_format_t * ft, unsigned char **df, int32_t *dl)
 {
   struct readpriv *p = (struct readpriv *) ft->priv;
-  int32_t samplerate;
+  int samplerate;
   unsigned char *datafork = *df;
   unsigned char *ddf, *dfp;
   short dictsize;
@@ -416,7 +402,7 @@
   put32_be(&dfp, *dl);
   put32_be(&dfp, p->new_checksum);
   put32_be(&dfp, 1);
-  samplerate = 22050 / fr;
+  samplerate = 22050 / ft->signal.rate + .5;
   put32_be(&dfp, samplerate);
   put16_be(&dfp, dictsize);
   *df = datafork;               /* reassign passed pointer to new datafork */
@@ -425,7 +411,7 @@
 
 /* End of hcom utility routines */
 
-static int sox_hcomstopwrite(sox_format_t * ft)
+static int stopwrite(sox_format_t * ft)
 {
   struct writepriv *p = (struct writepriv *) ft->priv;
   unsigned char *compressed_data = p->data;
@@ -434,7 +420,7 @@
 
   /* Compress it all at once */
   if (compressed_len)
-    compress(ft, &compressed_data, (int32_t *)&compressed_len, ft->signal.rate);
+    compress(ft, &compressed_data, (int32_t *)&compressed_len);
   free((char *)p->data);
 
   /* Write the header */
@@ -462,27 +448,17 @@
   return rc;
 }
 
-/* Mac FSSD/HCOM */
-static const char *hcomnames[] = {
-  "hcom",
-  NULL
-};
-
-static sox_format_handler_t sox_hcom_format = {
-  hcomnames,
-  SOX_FILE_BIG_END,
-  sox_hcomstartread,
-  sox_hcomread,
-  sox_hcomstopread,
-  sox_hcomstartwrite,
-  sox_hcomwrite,
-  sox_hcomstopwrite,
-  NULL
-};
-
-const sox_format_handler_t *sox_hcom_format_fn(void);
-
-const sox_format_handler_t *sox_hcom_format_fn(void)
+SOX_FORMAT_HANDLER(hcom)
 {
-    return &sox_hcom_format;
+  static char const * const names[]       = {"hcom", NULL};
+  static sox_rate_t   const write_rates[] = {22050,22050/2,22050/3,22050/4, 0};
+  static unsigned     const write_encodings[] = {
+    SOX_ENCODING_HCOM, 8, 0, 0};
+  static sox_format_handler_t handler   = {
+    names, SOX_FILE_BIG_END|SOX_FILE_MONO,
+    startread, read_samples, stopread,
+    startwrite, write_samples, stopwrite,
+    NULL, write_encodings, write_rates
+  };
+  return &handler;
 }
--- /dev/null
+++ b/src/htk.c
@@ -1,0 +1,74 @@
+/*
+ * File format: HTK   (c) 2008 [email protected]
+ *
+ * See http://labrosa.ee.columbia.edu/doc/HTKBook21/HTKBook.html
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
+ */
+
+#include "sox_i.h"
+#include <math.h>
+
+typedef enum {
+  Waveform, Lpc, Lprefc, Lpcepstra, Lpdelcep, Irefc,
+  Mfcc, Fbank, Melspec, User, Discrete, Unknown} kind_t;
+static char const * const str[] = {
+  "Sampled waveform", "Linear prediction filter", "Linear prediction",
+  "LPC cepstral", "LPC cepstra plus delta", "LPC reflection coef in",
+  "Mel-frequency cepstral", "Log mel-filter bank", "Linear mel-filter bank",
+  "User defined sample", "Vector quantised data", "Unknown"};
+
+static int start_read(sox_format_t * ft)
+{
+  uint32_t period_100ns, num_samples;
+  uint16_t bytes_per_sample, parmKind;
+
+  if (sox_readdw(ft, &num_samples     ) ||
+      sox_readdw(ft, &period_100ns    ) ||
+      sox_readw (ft, &bytes_per_sample) ||
+      sox_readw (ft, &parmKind        )) return SOX_EOF;
+  if (parmKind != Waveform) {
+    int n = min(parmKind & 077, Unknown);
+    sox_fail_errno(ft, SOX_EFMT, "unsupported HTK type `%s' (0%o)", str[n], parmKind);
+    return SOX_EOF;
+  }
+  return sox_check_read_params(ft, 1, 1e7 / period_100ns,
+      SOX_ENCODING_SIGN2, (unsigned)bytes_per_sample << 3, (off_t)num_samples);
+}
+
+static int write_header(sox_format_t * ft)
+{
+  double period_100ns = 1e7 / ft->signal.rate;
+
+  if (!ft->olength && floor(period_100ns) != period_100ns)
+    sox_warn("rounding sample period %f (x 100ns) to nearest integer", period_100ns);
+  return sox_writedw(ft, ft->olength? ft->olength:ft->length)
+      || sox_writedw(ft, (uint32_t)(period_100ns + .5))
+      || sox_writew(ft, ft->encoding.bits_per_sample >> 3)
+      || sox_writew(ft, Waveform) ? SOX_EOF : SOX_SUCCESS;
+}
+
+SOX_FORMAT_HANDLER(htk)
+{
+  static char const * const names[] = {"htk", NULL};
+  static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 16, 0, 0};
+  static sox_format_handler_t handler = {
+    names, SOX_FILE_BIG_END | SOX_FILE_MONO | SOX_FILE_REWIND,
+    start_read, sox_rawread, NULL,
+    write_header, sox_rawwrite, NULL,
+    sox_rawseek, write_encodings, NULL
+  };
+  return &handler;
+}
--- a/src/ima-fmt.c
+++ b/src/ima-fmt.c
@@ -1,32 +1,33 @@
 /*
- * SOX file format handler for Dialogic/Oki ADPCM VOX files.
+ * File format: raw IMA ADPCM           (c) 2007-8 SoX contributors
  *
- * Copyright 1991-2007 Tony Seebregts And Sundry Contributors
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
  *
- * This source code is freely redistributable and may be used for any
- * purpose.  This copyright notice must be maintained.
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
+ * General Public License for more details.
  *
- * Tony Seebregts And Sundry Contributors are not responsible for the
- * consequences of using this software.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
  */
 
 #include "sox_i.h"
 #include "vox.h"
 
-const sox_format_handler_t *sox_ima_format_fn(void);
-
-const sox_format_handler_t *sox_ima_format_fn(void)
+SOX_FORMAT_HANDLER(ima)
 {
-  static char const * names[] = {"ima", NULL};
+  static char const * const names[] = {"ima", NULL};
+  static unsigned const write_encodings[] = {SOX_ENCODING_IMA_ADPCM, 4, 0, 0};
   static sox_format_handler_t handler = {
-    names, 0,
-    sox_ima_start,
-    sox_vox_read,
-    sox_vox_stopread,
-    sox_ima_start,
-    sox_vox_write,
-    sox_vox_stopwrite,
-    NULL
+    names, SOX_FILE_MONO,
+    sox_ima_start, sox_vox_read, sox_vox_stopread,
+    sox_ima_start, sox_vox_write, sox_vox_stopwrite,
+    sox_rawseek, write_encodings, NULL
   };
   return &handler;
 }
--- a/src/ima_rw.c
+++ b/src/ima_rw.c
@@ -19,12 +19,13 @@
 
 */
 
+#include "sox_i.h"
+#include "ima_rw.h"
+
 #include <sys/types.h>
 #include <math.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include "sox_i.h"
-#include "ima_rw.h"
 /*
  *
  * Lookup tables for IMA ADPCM format
--- a/src/la-fmt.c
+++ b/src/la-fmt.c
@@ -1,14 +1,22 @@
 /*
- * libSoX la raw file format
+ * File formats: raw         (c) 2007-8 SoX contributors
  *
- * Copyright 2007 Lance Norskog And Sundry Contributors
- * This source code is freely redistributable and may be used for
- * any purpose.  This copyright notice must be maintained.
- * Lance Norskog And Sundry Contributors are not responsible for
- * the consequences of using this software.
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
  */
 
 #include "sox_i.h"
 #include "raw.h"
 
-RAW_FORMAT(la, 8BIT, SOX_FILE_BIT_REV, ALAW)
+RAW_FORMAT(la, 8, SOX_FILE_BIT_REV, ALAW)
--- a/src/ladspa.c
+++ b/src/ladspa.c
@@ -198,8 +198,8 @@
   unsigned long i;
 
   /* Instantiate the plugin */
-  sox_debug("rate for plugin is %g", effp->ininfo.rate);
-  l_st->handle = l_st->desc->instantiate(l_st->desc, (unsigned long)effp->ininfo.rate);
+  sox_debug("rate for plugin is %g", effp->in_signal.rate);
+  l_st->handle = l_st->desc->instantiate(l_st->desc, (unsigned long)effp->in_signal.rate);
   if (l_st->handle == NULL) {
     sox_fail("could not instantiate plugin");
     return SOX_EOF;
--- a/src/lpc10.c
+++ b/src/lpc10.c
@@ -127,10 +127,7 @@
     return SOX_EOF;
   }
   lpc->samples = LPC10_SAMPLES_PER_FRAME;
-  ft->signal.size = SOX_SIZE_16BIT;
-  ft->signal.encoding = SOX_ENCODING_SIGN2;
-
-  return SOX_SUCCESS;
+  return sox_check_read_params(ft, 1, 8000., SOX_ENCODING_LPC10, 0, (off_t)0);
 }
 
 static int startwrite(sox_format_t * ft) 
@@ -146,7 +143,7 @@
   return SOX_SUCCESS;
 }
 
-static sox_size_t read(sox_format_t * ft, sox_sample_t *buf, sox_size_t len)
+static sox_size_t read_samples(sox_format_t * ft, sox_sample_t *buf, sox_size_t len)
 {
   lpcpriv_t lpc = (lpcpriv_t)ft->priv;
   sox_size_t nread = 0;
@@ -170,7 +167,7 @@
   return nread;
 }
 
-static sox_size_t write(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len)
+static sox_size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len)
 {
   lpcpriv_t lpc = (lpcpriv_t)ft->priv;
   sox_size_t nwritten = 0;
@@ -211,28 +208,16 @@
   return SOX_SUCCESS;
 }
 
-/* LPC-10 */
-static const char *lpc10names[] = {
-  "lpc",
-  "lpc10",
-  NULL
-};
-
-static sox_format_handler_t sox_lpc10_format = {
-  lpc10names,
-  0,
-  startread,
-  read,
-  stopread,
-  startwrite,
-  write,
-  stopwrite,
-  NULL
-};
-
-const sox_format_handler_t *sox_lpc10_format_fn(void);
-
-const sox_format_handler_t *sox_lpc10_format_fn(void)
+SOX_FORMAT_HANDLER(lpc10)
 {
-  return &sox_lpc10_format;
+  static char const * const names[] = {"lpc10", "lpc", NULL};
+  static sox_rate_t   const write_rates[] = {8000, 0};
+  static unsigned     const write_encodings[] = {SOX_ENCODING_LPC10, 0, 0};
+  static sox_format_handler_t handler = {
+    names, SOX_FILE_MONO,
+    startread, read_samples, stopread,
+    startwrite, write_samples, stopwrite,
+    NULL, write_encodings, write_rates
+  };
+  return &handler;
 }
--- a/src/lu-fmt.c
+++ b/src/lu-fmt.c
@@ -1,14 +1,22 @@
 /*
- * libSoX lu raw file format
+ * File formats: raw         (c) 2007-8 SoX contributors
  *
- * Copyright 2007 Lance Norskog And Sundry Contributors
- * This source code is freely redistributable and may be used for
- * any purpose.  This copyright notice must be maintained.
- * Lance Norskog And Sundry Contributors are not responsible for
- * the consequences of using this software.
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
  */
 
 #include "sox_i.h"
 #include "raw.h"
 
-RAW_FORMAT(lu, 8BIT, SOX_FILE_BIT_REV, ULAW)
+RAW_FORMAT(lu, 8, SOX_FILE_BIT_REV, ULAW)
--- a/src/maud.c
+++ b/src/maud.c
@@ -15,9 +15,6 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <errno.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>     /* For SEEK_* defines if not found in stdio */
-#endif
 
 /* Private data for MAUD file */
 struct maudstuff { /* max. 100 bytes!!!! */
@@ -33,7 +30,7 @@
  *      size and encoding of samples, 
  *      mono/stereo/quad.
  */
-static int sox_maudstartread(sox_format_t * ft) 
+static int startread(sox_format_t * ft) 
 {
         struct maudstuff * p = (struct maudstuff *) ft->priv;
         
@@ -136,20 +133,20 @@
                         sox_readdw(ft, &trash32);
                         
                         if (bitpersam == 8 && chaninf == 0) {
-                                ft->signal.size = SOX_SIZE_BYTE;
-                                ft->signal.encoding = SOX_ENCODING_UNSIGNED;
+                                ft->encoding.bits_per_sample = 8;
+                                ft->encoding.encoding = SOX_ENCODING_UNSIGNED;
                         }
                         else if (bitpersam == 8 && chaninf == 2) {
-                                ft->signal.size = SOX_SIZE_BYTE;
-                                ft->signal.encoding = SOX_ENCODING_ALAW;
+                                ft->encoding.bits_per_sample = 8;
+                                ft->encoding.encoding = SOX_ENCODING_ALAW;
                         }
                         else if (bitpersam == 8 && chaninf == 3) {
-                                ft->signal.size = SOX_SIZE_BYTE;
-                                ft->signal.encoding = SOX_ENCODING_ULAW;
+                                ft->encoding.bits_per_sample = 8;
+                                ft->encoding.encoding = SOX_ENCODING_ULAW;
                         }
                         else if (bitpersam == 16 && chaninf == 0) {
-                                ft->signal.size = SOX_SIZE_16BIT;
-                                ft->signal.encoding = SOX_ENCODING_SIGN2;
+                                ft->encoding.bits_per_sample = 16;
+                                ft->encoding.encoding = SOX_ENCODING_SIGN2;
                         }
                         else 
                         {
@@ -196,7 +193,7 @@
         return(SOX_SUCCESS);
 }
 
-static int sox_maudstartwrite(sox_format_t * ft) 
+static int startwrite(sox_format_t * ft) 
 {
         struct maudstuff * p = (struct maudstuff *) ft->priv;
         int rc;
@@ -212,18 +209,6 @@
             sox_fail_errno(ft,SOX_EOF,"Output .maud file must be a file, not a pipe");
             return (SOX_EOF);
         }
-        
-        if (ft->signal.channels != 1 && ft->signal.channels != 2) {
-                sox_fail_errno(ft,SOX_EFMT,"MAUD: unsupported number of channels, unable to store");
-                return(SOX_EOF);
-        }
-        if (ft->signal.size == SOX_SIZE_16BIT) ft->signal.encoding = SOX_ENCODING_SIGN2;
-        if (ft->signal.encoding == SOX_ENCODING_ULAW || 
-            ft->signal.encoding == SOX_ENCODING_ALAW) ft->signal.size = SOX_SIZE_BYTE;
-        if (ft->signal.size == SOX_SIZE_BYTE && 
-            ft->signal.encoding == SOX_ENCODING_SIGN2) 
-            ft->signal.encoding = SOX_ENCODING_UNSIGNED;
-        
         p->nsamples = 0x7f000000;
         maudwriteheader(ft);
         p->nsamples = 0;
@@ -230,7 +215,7 @@
         return (SOX_SUCCESS);
 }
 
-static sox_size_t sox_maudwrite(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len) 
+static sox_size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len) 
 {
         struct maudstuff * p = (struct maudstuff *) ft->priv;
         
@@ -239,7 +224,7 @@
         return sox_rawwrite(ft, buf, len);
 }
 
-static int sox_maudstopwrite(sox_format_t * ft) 
+static int stopwrite(sox_format_t * ft) 
 {
         /* All samples are already written out. */
         
@@ -259,7 +244,7 @@
         struct maudstuff * p = (struct maudstuff *) ft->priv;
         
         sox_writes(ft, "FORM");
-        sox_writedw(ft, (p->nsamples*ft->signal.size) + MAUDHEADERSIZE);  /* size of file */
+        sox_writedw(ft, (p->nsamples* (ft->encoding.bits_per_sample >> 3)) + MAUDHEADERSIZE);  /* size of file */
         sox_writes(ft, "MAUD"); /* File type */
         
         sox_writes(ft, "MHDR");
@@ -266,7 +251,7 @@
         sox_writedw(ft,  8*4); /* number of bytes to follow */
         sox_writedw(ft, p->nsamples);  /* number of samples stored in MDAT */
         
-        switch (ft->signal.encoding) {
+        switch (ft->encoding.encoding) {
                 
         case SOX_ENCODING_UNSIGNED:
           sox_writew(ft, 8); /* number of bits per sample as stored in MDAT */
@@ -300,7 +285,7 @@
           sox_writew(ft, 2);
         }
         
-        switch (ft->signal.encoding) {
+        switch (ft->encoding.encoding) {
                 
         case SOX_ENCODING_UNSIGNED:
         case SOX_ENCODING_SIGN2:
@@ -328,30 +313,23 @@
         sox_writes(ft, "file create by Sound eXchange ");
         
         sox_writes(ft, "MDAT");
-        sox_writedw(ft, p->nsamples * ft->signal.size ); /* samples in file */
+        sox_writedw(ft, p->nsamples * (ft->encoding.bits_per_sample >> 3)); /* samples in file */
 }
 
-/* Amiga MAUD */
-static const char *maudnames[] = {
-  "maud",
-  NULL,
-};
-
-static sox_format_handler_t sox_maud_format = {
-  maudnames,
-  SOX_FILE_BIG_END,
-  sox_maudstartread,
-  sox_rawread,
-  sox_rawstopread,
-  sox_maudstartwrite,
-  sox_maudwrite,
-  sox_maudstopwrite,
-  NULL
-};
-
-const sox_format_handler_t *sox_maud_format_fn(void);
-
-const sox_format_handler_t *sox_maud_format_fn(void)
+SOX_FORMAT_HANDLER(maud)
 {
-    return &sox_maud_format;
+  static char const * const names[] = {"maud", NULL};
+  static unsigned const write_encodings[] = {
+    SOX_ENCODING_SIGN2, 16, 0,
+    SOX_ENCODING_UNSIGNED, 8, 0,
+    SOX_ENCODING_ULAW, 8, 0,
+    SOX_ENCODING_ALAW, 8, 0,
+    0};
+  static sox_format_handler_t const handler = {
+    names, SOX_FILE_BIG_END | SOX_FILE_MONO | SOX_FILE_STEREO,
+    startread, sox_rawread, sox_rawstopread,
+    startwrite, write_samples, stopwrite,
+    NULL, write_encodings, NULL
+  };
+  return &handler;
 }
--- a/src/mcompand.c
+++ b/src/mcompand.c
@@ -14,6 +14,8 @@
  * the consequences of using this software.
  */
 
+#include "sox_i.h"
+
 #include <string.h>
 #include <stdlib.h>
 #include "compandt.h"
@@ -357,7 +359,7 @@
   
   for (band=0;band<c->nBands;++band) {
     l = &c->bands[band];
-    l->delay_size = c->bands[band].delay * effp->outinfo.rate * effp->outinfo.channels;
+    l->delay_size = c->bands[band].delay * effp->out_signal.rate * effp->out_signal.channels;
     if (l->delay_size > c->delay_buf_size)
       c->delay_buf_size = l->delay_size;
   }
@@ -367,14 +369,14 @@
     /* Convert attack and decay rates using number of samples */
 
     for (i = 0; i < l->expectedChannels; ++i) {
-      if (l->attackRate[i] > 1.0/effp->outinfo.rate)
+      if (l->attackRate[i] > 1.0/effp->out_signal.rate)
         l->attackRate[i] = 1.0 -
-          exp(-1.0/(effp->outinfo.rate * l->attackRate[i]));
+          exp(-1.0/(effp->out_signal.rate * l->attackRate[i]));
       else
         l->attackRate[i] = 1.0;
-      if (l->decayRate[i] > 1.0/effp->outinfo.rate)
+      if (l->decayRate[i] > 1.0/effp->out_signal.rate)
         l->decayRate[i] = 1.0 -
-          exp(-1.0/(effp->outinfo.rate * l->decayRate[i]));
+          exp(-1.0/(effp->out_signal.rate * l->decayRate[i]));
       else
         l->decayRate[i] = 1.0;
     }
@@ -386,7 +388,7 @@
     l->delay_buf_cnt = 0;
 
     if (l->topfreq != 0)
-      lowpass_setup(&l->filter, l->topfreq, effp->outinfo.rate, effp->outinfo.channels);
+      lowpass_setup(&l->filter, l->topfreq, effp->out_signal.rate, effp->out_signal.channels);
   }
   return (SOX_SUCCESS);
 }
@@ -503,7 +505,7 @@
     l = &c->bands[band];
 
     if (l->topfreq)
-      lowpass_flow(effp, &l->filter, effp->outinfo.channels, abuf, bbuf, cbuf, len);
+      lowpass_flow(effp, &l->filter, effp->out_signal.channels, abuf, bbuf, cbuf, len);
     else {
       bbuf = abuf;
       abuf = cbuf;
@@ -510,7 +512,7 @@
     }
     if (abuf == ibuf_copy)
       abuf = c->band_buf3;
-    (void)sox_mcompand_flow_1(effp, c,l,bbuf,abuf,len,effp->outinfo.channels);
+    (void)sox_mcompand_flow_1(effp, c,l,bbuf,abuf,len,effp->out_signal.channels);
     for (i=0;i<len;++i)
     {
       out = obuf[i] + abuf[i];
--- a/src/misc.c
+++ b/src/misc.c
@@ -29,56 +29,119 @@
 #include <byteswap.h>
 #endif
 
-const char * const sox_sizes_str[] = {
-        "NONSENSE!",
-        "1 byte",
-        "2 bytes",
-        "3 bytes",
-        "4 bytes",
-        "NONSENSE",
-        "NONSENSE",
-        "NONSENSE",
-        "8 bytes"
+const char * const sox_encodings_str[] = {
+  "?",
+  "Signed Integer PCM",
+  "Unsigned Integer PCM",
+  "Floating Point PCM",
+  "Floating Point (text) PCM",
+  "FLAC",
+  "HCOM",
+  "", /* Lossless above, lossy below */
+  "u-law",
+  "A-law",
+  "G.721 ADPCM",
+  "G.723 ADPCM",
+  "MS ADPCM",
+  "IMA ADPCM",
+  "OKI ADPCM",
+  "GSM",
+  "MPEG audio (layer I, II or III)",
+  "Vorbis",
+  "AMR-WB",
+  "AMR-NB",
+  "CVSD",
+  "LPC10",
 };
 
-const char * const sox_size_bits_str[] = {
-        "NONSENSE!",
-        "8-bit",
-        "16-bit",
-        "24-bit",
-        "32-bit",
-        "NONSENSE",
-        "NONSENSE",
-        "NONSENSE",
-        "64-bit"
-};
+assert_static(array_length(sox_encodings_str) == SOX_ENCODINGS,
+    SIZE_MISMATCH_BETWEEN_sox_encodings_t_AND_sox_encodings_str);
 
-const char * const sox_encodings_str[] = {
-        "NONSENSE!",
+void sox_init_encodinginfo(sox_encodinginfo_t * e)
+{
+  e->reverse_bytes = SOX_OPTION_DEFAULT;
+  e->reverse_nibbles = SOX_OPTION_DEFAULT;
+  e->reverse_bits = SOX_OPTION_DEFAULT;
+  e->compression = HUGE_VAL;
+}
 
-        "u-law",
-        "A-law",
-        "G72x-ADPCM",
-        "MS-ADPCM",
-        "IMA-ADPCM",
-        "OKI-ADPCM",
+unsigned sox_precision(sox_encoding_t encoding, unsigned bits_per_sample)
+{
+  switch (encoding) {
+    case SOX_ENCODING_HCOM:       return !(bits_per_sample & 7) && (bits_per_sample >> 3) - 1 < 1? bits_per_sample: 0;
+    case SOX_ENCODING_FLAC:       return !(bits_per_sample & 7) && (bits_per_sample >> 3) - 1 < 3? bits_per_sample: 0;
+    case SOX_ENCODING_SIGN2:
+    case SOX_ENCODING_UNSIGNED:   return !(bits_per_sample & 7) && (bits_per_sample >> 3) - 1 < 4? bits_per_sample: 0;
 
-        "",   /* FIXME, see sox.h */
+    case SOX_ENCODING_ALAW:       return bits_per_sample == 8? 13: 0;
+    case SOX_ENCODING_ULAW:       return bits_per_sample == 8? 14: 0;
 
-        "unsigned",
-        "signed (2's complement)",
-        "floating point",
-        "GSM",
-        "MPEG audio (layer I, II or III)",
-        "Vorbis",
-        "FLAC",
-        "AMR-WB",
-        "AMR-NB",
-};
+    case SOX_ENCODING_MS_ADPCM:   return bits_per_sample == 4? 14: 0;
+    case SOX_ENCODING_IMA_ADPCM:  return bits_per_sample == 4? 13: 0;
+    case SOX_ENCODING_OKI_ADPCM:  return bits_per_sample == 4? 12: 0;
+    case SOX_ENCODING_G721:       return bits_per_sample == 4? 12: 0;
+    case SOX_ENCODING_G723:       return bits_per_sample == 3? 8:
+                                         bits_per_sample == 5? 14: 0;
+    case SOX_ENCODING_CVSD:       return bits_per_sample == 1? 16: 0;
 
-assert_static(array_length(sox_encodings_str) == SOX_ENCODINGS,
-    SIZE_MISMATCH_BETWEEN_sox_encodings_t_AND_sox_encodings_str);
+    case SOX_ENCODING_GSM:
+    case SOX_ENCODING_MP3:
+    case SOX_ENCODING_VORBIS:
+    case SOX_ENCODING_AMR_WB:
+    case SOX_ENCODING_AMR_NB:
+    case SOX_ENCODING_LPC10:      return !bits_per_sample? 16: 0;
 
+    case SOX_ENCODING_FLOAT:      return bits_per_sample == 32 ? 24: bits_per_sample == 64 ? 53: 0;
+    case SOX_ENCODING_FLOAT_TEXT: return !bits_per_sample? 53: 0;
+
+    case SOX_ENCODINGS:
+    case SOX_ENCODING_LOSSLESS:
+    case SOX_ENCODING_UNKNOWN:    break;
+  }
+  return 0;
+}
+
+int sox_check_read_params(sox_format_t * ft, unsigned channels,
+    sox_rate_t rate, sox_encoding_t encoding, unsigned bits_per_sample, off_t length)
+{
+  ft->length = length;
+
+  if (ft->seekable)
+    ft->data_start = sox_tell(ft);
+
+  if (channels && ft->signal.channels && ft->signal.channels != channels)
+    sox_warn("'%s': overriding number of channels", ft->filename);
+  else ft->signal.channels = channels;
+
+  if (rate && ft->signal.rate && ft->signal.rate != rate)
+    sox_warn("'%s': overriding sample rate", ft->filename);
+  else ft->signal.rate = rate;
+
+  if (encoding && ft->encoding.encoding && ft->encoding.encoding != encoding)
+    sox_warn("'%s': overriding encoding type", ft->filename);
+  else ft->encoding.encoding = encoding;
+
+  if (bits_per_sample && ft->encoding.bits_per_sample && ft->encoding.bits_per_sample != bits_per_sample)
+    sox_warn("'%s': overriding encoding size", ft->filename);
+  ft->encoding.bits_per_sample = bits_per_sample;
+
+  if (!ft->length && ft->encoding.bits_per_sample && sox_filelength(ft))
+    ft->length = div_bits(sox_filelength(ft) - ft->data_start, ft->encoding.bits_per_sample);
+
+  if ( sox_precision(ft->encoding.encoding, ft->encoding.bits_per_sample))
+    return SOX_SUCCESS;
+  sox_fail_errno(ft, EINVAL, "invalid format for this file type");
+  return SOX_EOF;
+}
+
+sox_sample_t sox_sample_max(sox_encodinginfo_t const * encoding)
+{
+  unsigned precision = encoding->encoding == SOX_ENCODING_FLOAT?
+    SOX_SAMPLE_PRECISION : sox_precision(encoding->encoding, encoding->bits_per_sample);
+  unsigned shift = SOX_SAMPLE_PRECISION - min(precision, SOX_SAMPLE_PRECISION);
+  return (SOX_SAMPLE_MAX >> shift) << shift;
+}
+
 const char sox_readerr[] = "Premature EOF while reading sample file.";
 const char sox_writerr[] = "Error writing sample file.  You are probably out of disk space.";
 
@@ -154,10 +217,9 @@
 sox_size_t sox_filelength(sox_format_t * ft)
 {
   struct stat st;
+  int ret = fstat(fileno(ft->fp), &st);
 
-  fstat(fileno(ft->fp), &st);
-
-  return (sox_size_t)st.st_size;
+  return ret? 0 : (sox_size_t)st.st_size;
 }
 
 int sox_flush(sox_format_t * ft)
@@ -500,6 +562,14 @@
             ft->sox_errno = SOX_SUCCESS;
     }
     return ft->sox_errno;
+}
+
+int sox_offset_seek(sox_format_t * ft, off_t byte_offset, sox_size_t to_sample)
+{
+  double wide_sample = to_sample - (to_sample % ft->signal.channels);
+  double to_d = wide_sample * ft->encoding.bits_per_sample / 8;
+  off_t to = to_d;
+  return (to != to_d)? SOX_EOF : sox_seeki(ft, byte_offset + to, SEEK_SET);
 }
 
 enum_item const * find_enum_text(char const * text, enum_item const * enum_items)
--- a/src/mixer.c
+++ b/src/mixer.c
@@ -167,8 +167,8 @@
      for (i = 0;  i < 16;  i++)
          pans[i] = ((double*)&mixer->sources[0][0])[i];
 
-     ichan = effp->ininfo.channels;
-     ochan = effp->outinfo.channels;
+     ichan = effp->in_signal.channels;
+     ochan = effp->out_signal.channels;
      if (ochan == -1) {
          sox_fail("Output must have known number of channels");
          return(SOX_EOF);
@@ -485,11 +485,11 @@
          }
      }
 
-     if (effp->ininfo.channels != effp->outinfo.channels)
+     if (effp->in_signal.channels != effp->out_signal.channels)
        return SOX_SUCCESS;
 
-     for (i = 0; i < (int)effp->ininfo.channels; ++i)
-       for (j = 0; j < (int)effp->outinfo.channels; ++j)
+     for (i = 0; i < (int)effp->in_signal.channels; ++i)
+       for (j = 0; j < (int)effp->out_signal.channels; ++j)
          if (mixer->sources[i][j] != (i == j))
            return SOX_SUCCESS;
 
@@ -509,8 +509,8 @@
     int i, j;
     double samp;
 
-    ichan = effp->ininfo.channels;
-    ochan = effp->outinfo.channels;
+    ichan = effp->in_signal.channels;
+    ochan = effp->out_signal.channels;
     len = *isamp / ichan;
     if (len > *osamp / ochan)
         len = *osamp / ochan;
--- a/src/mp3.c
+++ b/src/mp3.c
@@ -158,7 +158,7 @@
     return rc;
 }
 
-static int sox_mp3startread(sox_format_t * ft) 
+static int startread(sox_format_t * ft) 
 {
     struct mp3priv *p = (struct mp3priv *) ft->priv;
     size_t ReadSize;
@@ -183,8 +183,7 @@
     mad_synth_init(p->Synth);
     mad_timer_reset(p->Timer);
 
-    ft->signal.encoding = SOX_ENCODING_MP3;
-    ft->signal.size = SOX_SIZE_16BIT;
+    ft->encoding.encoding = SOX_ENCODING_MP3;
 
     /* Decode at least one valid frame to find out the input
      * format.  The decoded frame will be saved off so that it
@@ -330,7 +329,7 @@
     return done;
 }
 
-static int sox_mp3stopread(sox_format_t * ft)
+static int stopread(sox_format_t * ft)
 {
   struct mp3priv *p=(struct mp3priv*) ft->priv;
 
@@ -347,13 +346,13 @@
   return SOX_SUCCESS;
 }
 #else /*HAVE_MAD_H*/
-static int sox_mp3startread(sox_format_t * ft)
+static int startread(sox_format_t * ft)
 {
   sox_fail_errno(ft,SOX_EOF,"SoX was compiled without MP3 decoding support");
   return SOX_EOF;
 }
 #define sox_mp3read NULL
-#define sox_mp3stopread NULL
+#define stopread NULL
 #endif /*HAVE_MAD_H*/
 
 #ifdef HAVE_LAME_LAME_H
@@ -362,14 +361,14 @@
   return;
 }
 
-static int sox_mp3startwrite(sox_format_t * ft)
+static int startwrite(sox_format_t * ft)
 {
   struct mp3priv *p = (struct mp3priv *) ft->priv;
   
-  if (ft->signal.encoding != SOX_ENCODING_MP3) {
-    if(ft->signal.encoding != SOX_ENCODING_UNKNOWN)
+  if (ft->encoding.encoding != SOX_ENCODING_MP3) {
+    if(ft->encoding.encoding != SOX_ENCODING_UNKNOWN)
       sox_report("Encoding forced to MP3");
-    ft->signal.encoding = SOX_ENCODING_MP3;
+    ft->encoding.encoding = SOX_ENCODING_MP3;
   }
 
   p->gfp = lame_init();
@@ -397,7 +396,7 @@
   /* FIXME: Someone who knows about lame could implement adjustable compression
      here.  E.g. by using the -C value as an index into a table of params or
      as a compressed bit-rate. */
-  if (ft->signal.compression != HUGE_VAL)
+  if (ft->encoding.compression != HUGE_VAL)
       sox_warn("-C option not supported for mp3; using default compression rate");
   if (lame_init_params(p->gfp) < 0){
         sox_fail_errno(ft,SOX_EOF,"LAME initialization failed");
@@ -501,7 +500,7 @@
     return done;
 }
 
-static int sox_mp3stopwrite(sox_format_t * ft)
+static int stopwrite(sox_format_t * ft)
 {
   struct mp3priv *p = (struct mp3priv *) ft->priv;
   char mp3buffer[7200];
@@ -508,7 +507,7 @@
   int written;
   size_t written2;
   
-  if ( (written=lame_encode_flush(p->gfp, (unsigned char *)mp3buffer, 7200)) <0){
+  if ((written=lame_encode_flush(p->gfp, (unsigned char *)mp3buffer, 7200)) <0){
     sox_fail_errno(ft,SOX_EOF,"Encoding failed");
   }
   else if (sox_writebuf(ft, mp3buffer, written2 = written) < written2){
@@ -520,37 +519,25 @@
 }
 
 #else /* HAVE_LAME_LAME_H */
-static int sox_mp3startwrite(sox_format_t * ft UNUSED)
+static int startwrite(sox_format_t * ft UNUSED)
 {
   sox_fail_errno(ft,SOX_EOF,"SoX was compiled without MP3 encoding support");
   return SOX_EOF;
 }
 #define sox_mp3write NULL
-#define sox_mp3stopwrite NULL
+#define stopwrite NULL
 #endif /* HAVE_LAME_LAME_H */
 
-/* MP3 */
-static const char *mp3names[] = {
-  "mp3",
-  "mp2",
-  NULL,
-};
-
-static sox_format_handler_t sox_mp3_format = {
-  mp3names,
-  0,
-  sox_mp3startread,
-  sox_mp3read,
-  sox_mp3stopread,
-  sox_mp3startwrite,
-  sox_mp3write,
-  sox_mp3stopwrite,
-  NULL
-};
-
-const sox_format_handler_t *sox_mp3_format_fn(void);
-
-const sox_format_handler_t *sox_mp3_format_fn(void)
+SOX_FORMAT_HANDLER(mp3)
 {
-    return &sox_mp3_format;
+  static char const * const names[] = {"mp3", "mp2", NULL};
+  static unsigned const write_encodings[] = {
+    SOX_ENCODING_GSM, 0, 0};
+  static sox_format_handler_t const handler = {
+    names, 0,
+    startread, sox_mp3read, stopread,
+    startwrite, sox_mp3write, stopwrite,
+    NULL, write_encodings, NULL
+  };
+  return &handler;
 }
--- a/src/noiseprof.c
+++ b/src/noiseprof.c
@@ -56,7 +56,7 @@
 static int sox_noiseprof_start(sox_effect_t * effp)
 {
   profdata_t data = (profdata_t) effp->priv;
-  unsigned channels = effp->ininfo.channels;
+  unsigned channels = effp->in_signal.channels;
   unsigned i;
    
   /* Note: don't fall back to stderr if stdout is unavailable
@@ -111,13 +111,13 @@
 {
     profdata_t data = (profdata_t) effp->priv;
     sox_size_t samp = min(*isamp, *osamp);
-    sox_size_t tracks = effp->ininfo.channels;
+    sox_size_t tracks = effp->in_signal.channels;
     sox_size_t track_samples = samp / tracks;
     int ncopy = 0;
     sox_size_t i;
 
     /* FIXME: Make this automatic for all effects */
-    assert(effp->ininfo.channels == effp->outinfo.channels);
+    assert(effp->in_signal.channels == effp->out_signal.channels);
 
     /* How many samples per track to analyze? */
     ncopy = min(track_samples, WINDOWSIZE-data->bufdata);
@@ -152,7 +152,7 @@
 static int sox_noiseprof_drain(sox_effect_t * effp, sox_sample_t *obuf UNUSED, sox_size_t *osamp)
 {
     profdata_t data = (profdata_t) effp->priv;
-    int tracks = effp->ininfo.channels;
+    int tracks = effp->in_signal.channels;
     int i;
 
     *osamp = 0;
@@ -183,7 +183,7 @@
     profdata_t data = (profdata_t) effp->priv;
     sox_size_t i;
 
-    for (i = 0; i < effp->ininfo.channels; i ++) {
+    for (i = 0; i < effp->in_signal.channels; i ++) {
         int j;
         chandata_t* chan = &(data->chandata[i]);
 
--- a/src/noisered.c
+++ b/src/noisered.c
@@ -62,7 +62,7 @@
 {
     reddata_t data = (reddata_t) effp->priv;
     sox_size_t fchannels = 0;
-    sox_size_t channels = effp->ininfo.channels;
+    sox_size_t channels = effp->in_signal.channels;
     sox_size_t i;
     FILE* ifp;
 
@@ -243,7 +243,7 @@
 {
     reddata_t data = (reddata_t) effp->priv;
     sox_size_t samp = min(*isamp, *osamp);
-    sox_size_t tracks = effp->ininfo.channels;
+    sox_size_t tracks = effp->in_signal.channels;
     sox_size_t track_samples = samp / tracks;
     sox_size_t ncopy = min(track_samples, WINDOWSIZE-data->bufdata);
     sox_size_t whole_window = (ncopy + data->bufdata == WINDOWSIZE);
@@ -251,7 +251,7 @@
     sox_size_t i;
 
     /* FIXME: Make this automatic for all effects */
-    assert(effp->ininfo.channels == effp->outinfo.channels);
+    assert(effp->in_signal.channels == effp->out_signal.channels);
 
     if (whole_window)
         data->bufdata = WINDOWSIZE/2;
@@ -293,7 +293,7 @@
 {
     reddata_t data = (reddata_t)effp->priv;
     unsigned i;
-    unsigned tracks = effp->ininfo.channels;
+    unsigned tracks = effp->in_signal.channels;
     for (i = 0; i < tracks; i ++)
         *osamp = process_window(effp, data, i, tracks, obuf, data->bufdata);
 
@@ -311,7 +311,7 @@
     reddata_t data = (reddata_t) effp->priv;
     sox_size_t i;
 
-    for (i = 0; i < effp->ininfo.channels; i ++) {
+    for (i = 0; i < effp->in_signal.channels; i ++) {
         chandata_t* chan = &(data->chandata[i]);
         free(chan->lastwindow);
         free(chan->window);
--- a/src/normalise.c
+++ b/src/normalise.c
@@ -84,8 +84,7 @@
   int result = SOX_SUCCESS;
 
   if (!p->norm0) {
-    int shift_for_max = (4 - min(effp->outinfo.size, 4)) << 3;
-    double max = (SOX_SAMPLE_MAX >> shift_for_max) << shift_for_max;
+    double max = sox_sample_max(effp->out_encoding);
     p->norm0 = p->level * min(max / p->max, (double)SOX_SAMPLE_MIN / p->min);
     rewind(p->tmp_file);
   }
--- a/src/nulfile.c
+++ b/src/nulfile.c
@@ -26,39 +26,34 @@
     ft->signal.rate = SOX_DEFAULT_RATE;
     sox_report("sample rate not specified; using %g", ft->signal.rate);
   }
-  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_DEFAULT_ENCODING;
-    sox_report("encoding not specified; using %s", sox_encodings_str[ft->signal.encoding]);
-  }
+  ft->signal.precision =
+      ft->encoding.bits_per_sample? ft->encoding.bits_per_sample: SOX_SAMPLE_PRECISION;
   /* Default number of channels is application-dependent */
   return SOX_SUCCESS;
 }
 
-static sox_size_t read(sox_format_t * ft UNUSED, sox_sample_t *buf, sox_size_t len)
+static sox_size_t read_samples(sox_format_t * ft, sox_sample_t * buf, sox_size_t len)
 {
   /* Reading from null generates silence i.e. (sox_sample_t)0. */
+  (void)ft;
   memset(buf, 0, sizeof(sox_sample_t) * len);
   return len; /* Return number of samples "read". */
 }
 
-static sox_size_t write(sox_format_t * ft UNUSED, const sox_sample_t *buf UNUSED, sox_size_t len)
+static sox_size_t write_samples(
+    sox_format_t * ft, sox_sample_t const * buf, sox_size_t len)
 {
   /* Writing to null just discards the samples */
+  (void)ft, (void)buf;
   return len; /* Return number of samples "written". */
 }
 
-const sox_format_handler_t *sox_nul_format_fn(void);
-
-const sox_format_handler_t *sox_nul_format_fn(void)
+SOX_FORMAT_HANDLER(nul)
 {
-  static const char *names[] = {"null", NULL};
-  static sox_format_handler_t handler = {
+  static const char * const names[] = {"null", NULL};
+  static sox_format_handler_t const handler = {
     names, SOX_FILE_DEVICE | SOX_FILE_PHONY | SOX_FILE_NOSTDIO,
-    startread, read, 0, 0, write, 0, 0
+    startread, read_samples, NULL, NULL, write_samples, NULL, NULL, NULL, NULL
   };
   return &handler;
 }
--- a/src/oss.c
+++ b/src/oss.c
@@ -49,41 +49,41 @@
     sox_signalinfo_t client_signal = ft->signal;
 
     set_signal_defaults(&ft->signal);
-    if (ft->signal.size == SOX_SIZE_BYTE) {
+    if (ft->encoding.bits_per_sample == 8) {
         sampletype = AFMT_U8;
         samplesize = 8;
-        if (ft->signal.encoding == SOX_ENCODING_UNKNOWN)
-            ft->signal.encoding = SOX_ENCODING_UNSIGNED;
-        if (ft->signal.encoding != SOX_ENCODING_UNSIGNED) {
+        if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN)
+            ft->encoding.encoding = SOX_ENCODING_UNSIGNED;
+        if (ft->encoding.encoding != SOX_ENCODING_UNSIGNED) {
             sox_report("OSS driver only supports unsigned with bytes");
             sox_report("Forcing to unsigned");
-            ft->signal.encoding = SOX_ENCODING_UNSIGNED;
+            ft->encoding.encoding = SOX_ENCODING_UNSIGNED;
         }
     }
-    else if (ft->signal.size == SOX_SIZE_16BIT) {
+    else if (ft->encoding.bits_per_sample == 16) {
         /* Attempt to use endian that user specified */
-        if (ft->signal.reverse_bytes)
+        if (ft->encoding.reverse_bytes)
             sampletype = (SOX_IS_BIGENDIAN) ? AFMT_S16_LE : AFMT_S16_BE;
         else
             sampletype = (SOX_IS_BIGENDIAN) ? AFMT_S16_BE : AFMT_S16_LE;
         samplesize = 16;
-        if (ft->signal.encoding == SOX_ENCODING_UNKNOWN)
-            ft->signal.encoding = SOX_ENCODING_SIGN2;
-        if (ft->signal.encoding != SOX_ENCODING_SIGN2) {
+        if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN)
+            ft->encoding.encoding = SOX_ENCODING_SIGN2;
+        if (ft->encoding.encoding != SOX_ENCODING_SIGN2) {
             sox_report("OSS driver only supports signed with words");
             sox_report("Forcing to signed linear");
-            ft->signal.encoding = SOX_ENCODING_SIGN2;
+            ft->encoding.encoding = SOX_ENCODING_SIGN2;
         }
     }
     else {
         /* Attempt to use endian that user specified */
-        if (ft->signal.reverse_bytes)
+        if (ft->encoding.reverse_bytes)
             sampletype = (SOX_IS_BIGENDIAN) ? AFMT_S16_LE : AFMT_S16_BE;
         else
             sampletype = (SOX_IS_BIGENDIAN) ? AFMT_S16_BE : AFMT_S16_LE;
         samplesize = 16;
-        ft->signal.size = SOX_SIZE_16BIT;
-        ft->signal.encoding = SOX_ENCODING_SIGN2;
+        ft->encoding.bits_per_sample = 16;
+        ft->encoding.encoding = SOX_ENCODING_SIGN2;
         sox_report("OSS driver only supports bytes and words");
         sox_report("Forcing to signed linear word");
     }
@@ -106,8 +106,8 @@
             if (samplesize == 16 && (tmp & (AFMT_S16_LE|AFMT_S16_BE)) == 0)
             {
                 /* Must not like 16-bits, try 8-bits */
-                ft->signal.size = SOX_SIZE_BYTE;
-                ft->signal.encoding = SOX_ENCODING_UNSIGNED;
+                ft->encoding.bits_per_sample = 8;
+                ft->encoding.encoding = SOX_ENCODING_UNSIGNED;
                 sox_report("OSS driver doesn't like signed words");
                 sox_report("Forcing to unsigned bytes");
                 tmp = sampletype = AFMT_U8;
@@ -116,8 +116,8 @@
             /* is 8-bit supported */
             else if (samplesize == 8 && (tmp & AFMT_U8) == 0)
             {
-                ft->signal.size = SOX_SIZE_16BIT;
-                ft->signal.encoding = SOX_ENCODING_SIGN2;
+                ft->encoding.bits_per_sample = 16;
+                ft->encoding.encoding = SOX_ENCODING_SIGN2;
                 sox_report("OSS driver doesn't like unsigned bytes");
                 sox_report("Forcing to signed words");
                 sampletype = (SOX_IS_BIGENDIAN) ? AFMT_S16_BE : AFMT_S16_LE;
@@ -132,7 +132,7 @@
                  * it supports at least one of the two endians.
                  */
                 sampletype = (sampletype == AFMT_S16_BE) ? AFMT_S16_LE : AFMT_S16_BE;
-                ft->signal.reverse_bytes = !ft->signal.reverse_bytes;
+                ft->encoding.reverse_bytes = !ft->encoding.reverse_bytes;
             }
 
         }
@@ -159,7 +159,7 @@
     if (tmp != dsp_stereo)
     {
       if (client_signal.channels != 0)
-        sox_warn("Sound card appears to only support %d channels.  Overriding format", tmp+1);
+        sox_warn("Sound card appears to support only %d channels.  Overriding format", tmp+1);
         ft->signal.channels = tmp + 1;
     }
 
@@ -206,47 +206,18 @@
     return(SOX_SUCCESS);
 }
 
-/*
- * Do anything required before you start reading samples.
- * Read file header.
- *      Find out sampling rate,
- *      size and encoding of samples,
- *      mono/stereo/quad.
- */
-static int sox_ossstartread(sox_format_t * ft)
+SOX_FORMAT_HANDLER(oss)
 {
-    int rc;
-    rc = ossinit(ft);
-    return rc;
-}
-
-static int sox_ossstartwrite(sox_format_t * ft)
-{
-    return ossinit(ft);
-}
-
-/* OSS /dev/dsp player */
-static const char *ossnames[] = {
-  "ossdsp",
-  "oss",
-  NULL
-};
-
-static sox_format_handler_t sox_oss_format = {
-  ossnames,
-  SOX_FILE_DEVICE,
-  sox_ossstartread,
-  sox_rawread,
-  sox_rawstopread,
-  sox_ossstartwrite,
-  sox_rawwrite,
-  sox_rawstopwrite,
-  NULL
-};
-
-const sox_format_handler_t *sox_oss_format_fn(void);
-
-const sox_format_handler_t *sox_oss_format_fn(void)
-{
-    return &sox_oss_format;
+  static char const * const names[] = {"ossdsp", "oss", NULL};
+  static unsigned const write_encodings[] = {
+    SOX_ENCODING_SIGN2, 16, 0,
+    SOX_ENCODING_UNSIGNED, 8, 0,
+    0};
+  static sox_format_handler_t const handler = {
+    names, SOX_FILE_DEVICE,
+    ossinit, sox_rawread, sox_rawstopread,
+    ossinit, sox_rawwrite, sox_rawstopwrite,
+    NULL, write_encodings, NULL
+  };
+  return &handler;
 }
--- a/src/pad.c
+++ b/src/pad.c
@@ -72,7 +72,7 @@
   pad_t p = (pad_t) effp->priv;
   unsigned i;
 
-  parse(effp, 0, effp->ininfo.rate); /* Re-parse now rate is known */
+  parse(effp, 0, effp->in_signal.rate); /* Re-parse now rate is known */
   p->in_pos = p->pad_pos = p->pads_pos = 0;
   for (i = 0; i < p->npads; ++i)
     if (p->pads[i].pad)
@@ -85,18 +85,18 @@
 {
   pad_t p = (pad_t) effp->priv;
   sox_size_t c, idone = 0, odone = 0;
-  *isamp /= effp->ininfo.channels;
-  *osamp /= effp->ininfo.channels;
+  *isamp /= effp->in_signal.channels;
+  *osamp /= effp->in_signal.channels;
 
   do {
     /* Copying: */
     for (; idone < *isamp && odone < *osamp && !(p->pads_pos != p->npads && p->in_pos == p->pads[p->pads_pos].start); ++idone, ++odone, ++p->in_pos)
-      for (c = 0; c < effp->ininfo.channels; ++c) *obuf++ = *ibuf++;
+      for (c = 0; c < effp->in_signal.channels; ++c) *obuf++ = *ibuf++;
 
     /* Padding: */
     if (p->pads_pos != p->npads && p->in_pos == p->pads[p->pads_pos].start) {
       for (; odone < *osamp && p->pad_pos < p->pads[p->pads_pos].pad; ++odone, ++p->pad_pos)
-        for (c = 0; c < effp->ininfo.channels; ++c) *obuf++ = 0;
+        for (c = 0; c < effp->in_signal.channels; ++c) *obuf++ = 0;
       if (p->pad_pos == p->pads[p->pads_pos].pad) { /* Move to next pad? */
         ++p->pads_pos;
         p->pad_pos = 0;
@@ -104,8 +104,8 @@
     }
   } while (idone < *isamp && odone < *osamp);
 
-  *isamp = idone * effp->ininfo.channels;
-  *osamp = odone * effp->ininfo.channels;
+  *isamp = idone * effp->in_signal.channels;
+  *osamp = odone * effp->in_signal.channels;
   return SOX_SUCCESS;
 }
 
--- a/src/pan.c
+++ b/src/pan.c
@@ -46,7 +46,7 @@
  */
 static int sox_pan_start(sox_effect_t * effp)
 {
-    if (effp->outinfo.channels==1)
+    if (effp->out_signal.channels==1)
         sox_warn("PAN onto a mono channel...");
     return SOX_SUCCESS;
 }
@@ -77,8 +77,8 @@
     left  = 0.5 - hdir; /*  0   <=  left <= 1   */
     right = 0.5 + hdir; /*  0   <= right <= 1   */
 
-    ich = effp->ininfo.channels;
-    och = effp->outinfo.channels;
+    ich = effp->in_signal.channels;
+    och = effp->out_signal.channels;
 
     len = min(*osamp/och,*isamp/ich);
 
--- a/src/phaser.c
+++ b/src/phaser.c
@@ -54,10 +54,11 @@
  * libSoX phaser effect file.
  */
 
+#include "sox_i.h"
+
 #include <stdlib.h> /* Harmless, and prototypes atof() etc. --dgc */
 #include <math.h>
 #include <string.h>
-#include "sox_i.h"
 
 #define MOD_SINE        0
 #define MOD_TRIANGLE    1
@@ -111,7 +112,7 @@
         phaser_t phaser = (phaser_t) effp->priv;
         unsigned int i;
 
-        phaser->maxsamples = phaser->delay * effp->ininfo.rate / 1000.0;
+        phaser->maxsamples = phaser->delay * effp->in_signal.rate / 1000.0;
 
         if ( phaser->delay < 0.0 )
         {
@@ -149,7 +150,7 @@
         if ( phaser->in_gain / ( 1.0 - phaser->decay ) > 1.0 / phaser->out_gain )
                 sox_warn("phaser: warning >>> gain-out can cause saturation or clipping of output <<<");
 
-        phaser->length = effp->ininfo.rate / phaser->speed;
+        phaser->length = effp->in_signal.rate / phaser->speed;
         phaser->phaserbuf = (double *) xmalloc(sizeof (double) * phaser->maxsamples);
         for ( i = 0; i < phaser->maxsamples; i++ )
                 phaser->phaserbuf[i] = 0.0;
--- a/src/pitch.c
+++ b/src/pitch.c
@@ -319,7 +319,7 @@
 static int sox_pitch_start(sox_effect_t * effp)
 {
     pitch_t pitch = (pitch_t) effp->priv;
-    register int sample_rate = effp->outinfo.rate;
+    register int sample_rate = effp->out_signal.rate;
     unsigned int i;
 
     /* computer inner stuff... */
--- a/src/polyphas.c
+++ b/src/polyphas.c
@@ -23,11 +23,12 @@
  *
  */
 
+#include "sox_i.h"
+
 #include <math.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include "sox_i.h"
 
 #define Float float/*double*/
 #define ISCALE 0x10000
@@ -348,13 +349,13 @@
     int total, size, uprate;
     int k;
 
-    if (effp->ininfo.rate == effp->outinfo.rate)
+    if (effp->in_signal.rate == effp->out_signal.rate)
       return SOX_EFF_NULL;
 
-    effp->outinfo.channels = effp->ininfo.channels;
+    effp->out_signal.channels = effp->in_signal.channels;
 
-    rate->lcmrate = sox_lcm((sox_sample_t)effp->ininfo.rate,
-                           (sox_sample_t)effp->outinfo.rate);
+    rate->lcmrate = sox_lcm((sox_sample_t)effp->in_signal.rate,
+                           (sox_sample_t)effp->out_signal.rate);
 
     /* Cursory check for LCM overflow.
      * If both rates are below 65k, there should be no problem.
@@ -361,8 +362,8 @@
      * 16 bits x 16 bits = 32 bits, which we can handle.
      */
 
-    rate->inskip = rate->lcmrate / (sox_sample_t)effp->ininfo.rate;
-    rate->outskip = rate->lcmrate / (sox_sample_t)effp->outinfo.rate;
+    rate->inskip = rate->lcmrate / (sox_sample_t)effp->in_signal.rate;
+    rate->outskip = rate->lcmrate / (sox_sample_t)effp->out_signal.rate;
     rate->Factor = (double)rate->inskip / (double)rate->outskip;
     rate->inpipe = 0;
     {
@@ -377,12 +378,12 @@
     /* l1 and l2 are now lists of the up/down factors for conversion */
 
     sox_debug("Poly:  input rate %g, output rate %g.  %d stages.",
-            effp->ininfo.rate, effp->outinfo.rate,total);
+            effp->in_signal.rate, effp->out_signal.rate,total);
     sox_debug("Poly:  window: %s  size: %d  cutoff: %f.",
             (rate->win_type == 0) ? ("nut") : ("ham"), rate->win_width, rate->cutoff);
 
     /* Create an array of filters and past history */
-    uprate = effp->ininfo.rate;
+    uprate = effp->in_signal.rate;
     for (k = 0; k < total; k++) {
       int j, prod, f_cutoff, f_len;
       polystage *s;
--- a/src/prc.c
+++ b/src/prc.c
@@ -63,7 +63,7 @@
   uint32_t nsamp, nbytes;
   short padding;
   short repeats;
-  sox_size_t data_start;         /* for seeking */
+  off_t data_start;         /* for seeking */
   struct adpcm_io adpcm;
   unsigned frame_samp;     /* samples left to read in current frame */
 } *prc_t;
@@ -72,22 +72,8 @@
 
 static int seek(sox_format_t * ft, sox_size_t offset)
 {
-  prc_t prc = (prc_t)ft->priv;
-  sox_size_t new_offset, channel_block, alignment;
-
-  new_offset = offset * ft->signal.size;
-  /* Make sure request aligns to a channel block (i.e. left+right) */
-  channel_block = ft->signal.channels * ft->signal.size;
-  alignment = new_offset % channel_block;
-  /* Most common mistake is to compute something like
-   * "skip everthing up to and including this sample" so
-   * advance to next sample block in this case.
-   */
-  if (alignment != 0)
-    new_offset += (channel_block - alignment);
-  new_offset += prc->data_start;
-
-  return sox_seeki(ft, (sox_ssize_t)new_offset, SEEK_SET);
+  prc_t p = (prc_t)ft->priv;
+  return sox_offset_seek(ft, p->data_start, offset);
 }
 
 static int startread(sox_format_t * ft)
@@ -129,9 +115,9 @@
   sox_readdw(ft, &encoding);
   sox_debug("Encoding of samples: %x", encoding);
   if (encoding == 0)
-    ft->signal.encoding = SOX_ENCODING_ALAW;
+    ft->encoding.encoding = SOX_ENCODING_ALAW;
   else if (encoding == 0x100001a1)
-    ft->signal.encoding = SOX_ENCODING_IMA_ADPCM;
+    ft->encoding.encoding = SOX_ENCODING_IMA_ADPCM;
   else {
     sox_fail_errno(ft, SOX_EHDR, "Unrecognised encoding");
     return SOX_EOF;
@@ -164,11 +150,11 @@
   p->data_start = sox_tell(ft);
   ft->length = p->nsamp / ft->signal.channels;
 
-  if (ft->signal.encoding == SOX_ENCODING_ALAW) {
-    ft->signal.size = SOX_SIZE_BYTE;
+  if (ft->encoding.encoding == SOX_ENCODING_ALAW) {
+    ft->encoding.bits_per_sample = 8;
     if (sox_rawstartread(ft))
       return SOX_EOF;
-  } else if (ft->signal.encoding == SOX_ENCODING_IMA_ADPCM) {
+  } else if (ft->encoding.encoding == SOX_ENCODING_IMA_ADPCM) {
     p->frame_samp = 0;
     if (sox_adpcm_ima_start(ft, &p->adpcm))
       return SOX_EOF;
@@ -214,13 +200,13 @@
   return a;
 }
 
-static sox_size_t read(sox_format_t * ft, sox_sample_t *buf, sox_size_t samp)
+static sox_size_t read_samples(sox_format_t * ft, sox_sample_t *buf, sox_size_t samp)
 {
   prc_t p = (prc_t)ft->priv;
 
   sox_debug_more("length now = %d", p->nsamp);
 
-  if (ft->signal.encoding == SOX_ENCODING_IMA_ADPCM) {
+  if (ft->encoding.encoding == SOX_ENCODING_IMA_ADPCM) {
     sox_size_t nsamp, read;
 
     if (p->frame_samp == 0) {
@@ -240,7 +226,7 @@
       sox_debug_more("list length %d", trash);
 
       /* Reset CODEC for start of frame */
-      sox_adpcm_reset(&p->adpcm, ft->signal.encoding);
+      sox_adpcm_reset(&p->adpcm, ft->encoding.encoding);
     }
     nsamp = min(p->frame_samp, samp);
     p->nsamp += nsamp;
@@ -258,7 +244,7 @@
 {
   prc_t p = (prc_t)ft->priv;
 
-  if (ft->signal.encoding == SOX_ENCODING_IMA_ADPCM)
+  if (ft->encoding.encoding == SOX_ENCODING_IMA_ADPCM)
     return sox_adpcm_stopread(ft, &p->adpcm);
   else
     return SOX_SUCCESS;
@@ -277,16 +263,10 @@
 {
   prc_t p = (prc_t)ft->priv;
 
-  if (ft->signal.encoding != SOX_ENCODING_ALAW &&
-      ft->signal.encoding != SOX_ENCODING_IMA_ADPCM) {
-    sox_report("PRC only supports A-law and ADPCM encoding; choosing A-law");
-    ft->signal.encoding = SOX_ENCODING_ALAW;
-  }
-        
-  if (ft->signal.encoding == SOX_ENCODING_ALAW) {
+  if (ft->encoding.encoding == SOX_ENCODING_ALAW) {
     if (sox_rawstartwrite(ft))
       return SOX_EOF;
-  } else if (ft->signal.encoding == SOX_ENCODING_IMA_ADPCM) {
+  } else if (ft->encoding.encoding == SOX_ENCODING_IMA_ADPCM) {
     if (sox_adpcm_ima_start(ft, &p->adpcm))
       return SOX_EOF;
   }
@@ -296,16 +276,6 @@
   if (p->repeats == 0)
     p->repeats = 1;
 
-  if (ft->signal.rate != 0 && ft->signal.rate != 8000)
-    sox_report("PRC only supports 8 kHz sample rate; overriding.");
-  ft->signal.rate = 8000;
-
-  if (ft->signal.channels != 1 && ft->signal.channels != 0)
-    sox_report("PRC only supports 1 channel; overriding.");
-  ft->signal.channels = 1;
-
-  ft->signal.size = SOX_SIZE_BYTE;
-
   prcwriteheader(ft);
 
   p->data_start = sox_tell(ft);
@@ -344,7 +314,7 @@
   }
 }
 
-static sox_size_t write(sox_format_t * ft, const sox_sample_t *buf, sox_size_t samp)
+static sox_size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, sox_size_t samp)
 {
   prc_t p = (prc_t)ft->priv;
   /* Psion Record seems not to be able to handle frames > 800 samples */
@@ -351,7 +321,7 @@
   samp = min(samp, 800);
   p->nsamp += samp;
   sox_debug_more("length now = %d", p->nsamp);
-  if (ft->signal.encoding == SOX_ENCODING_IMA_ADPCM) {
+  if (ft->encoding.encoding == SOX_ENCODING_IMA_ADPCM) {
     sox_size_t written;
 
     write_cardinal(ft, samp);
@@ -360,7 +330,7 @@
     /* Write length again (seems to be a BListL) */
     sox_debug_more("list length %d", samp);
     sox_writedw(ft, samp);
-    sox_adpcm_reset(&p->adpcm, ft->signal.encoding);
+    sox_adpcm_reset(&p->adpcm, ft->encoding.encoding);
     written = sox_adpcm_write(ft, &p->adpcm, buf, samp);
     sox_adpcm_flush(ft, &p->adpcm);
     return written;
@@ -397,7 +367,7 @@
   sox_debug("Number of samples: %d",p->nsamp);
   sox_writedw(ft, p->nsamp);
 
-  if (ft->signal.encoding == SOX_ENCODING_ALAW)
+  if (ft->encoding.encoding == SOX_ENCODING_ALAW)
     sox_writedw(ft, 0);
   else
     sox_writedw(ft, 0x100001a1); /* ADPCM */
@@ -411,27 +381,19 @@
   sox_writedw(ft, p->nbytes);    /* Number of bytes of data */
 }
 
-/* Psion .prc */
-static const char *prcnames[] = {
-  "prc",
-  NULL
-};
-
-static sox_format_handler_t sox_prc_format = {
-  prcnames,
-  SOX_FILE_LIT_END,
-  startread,
-  read,
-  stopread,
-  startwrite,
-  write,
-  stopwrite,
-  seek
-};
-
-const sox_format_handler_t *sox_prc_format_fn(void);
-
-const sox_format_handler_t *sox_prc_format_fn(void)
+SOX_FORMAT_HANDLER(prc)
 {
-  return &sox_prc_format;
+  static char const * const names[]           = {"prc", NULL};
+  static sox_rate_t   const write_rates[]     = {8000, 0};
+  static unsigned     const write_encodings[] = {
+    SOX_ENCODING_ALAW, 8, 0,
+    SOX_ENCODING_IMA_ADPCM, 4, 0,
+    0};
+  static sox_format_handler_t const handler = {
+    names, SOX_FILE_LIT_END | SOX_FILE_MONO,
+    startread, read_samples, stopread,
+    startwrite, write_samples, stopwrite,
+    seek, write_encodings, write_rates
+  };
+  return &handler;
 }
--- a/src/rabbit.c
+++ b/src/rabbit.c
@@ -82,18 +82,18 @@
 {
   rabbit_t r = (rabbit_t) effp->priv;
   int err = 0;
-  double out_rate = r->out_rate != HUGE_VAL? r->out_rate : effp->outinfo.rate;
+  double out_rate = r->out_rate != HUGE_VAL? r->out_rate : effp->out_signal.rate;
 
-  if (effp->ininfo.rate == out_rate)
+  if (effp->in_signal.rate == out_rate)
     return SOX_EFF_NULL;
           
-  effp->outinfo.channels = effp->ininfo.channels;
-  effp->outinfo.rate = out_rate;
+  effp->out_signal.channels = effp->in_signal.channels;
+  effp->out_signal.rate = out_rate;
 
   r->data = (SRC_DATA *)xcalloc(1, sizeof(SRC_DATA));
-  r->data->src_ratio = out_rate / effp->ininfo.rate;
+  r->data->src_ratio = out_rate / effp->in_signal.rate;
   r->i_alloc = r->o_alloc = 0;
-  r->state = src_new(r->converter_type, (int)effp->ininfo.channels, &err);
+  r->state = src_new(r->converter_type, (int)effp->in_signal.channels, &err);
   if (err) {
     free(r->data);
     sox_fail("cannot initialise rabbit: %s", src_strerror(err));
@@ -111,7 +111,7 @@
 {
   rabbit_t r = (rabbit_t) effp->priv;
   SRC_DATA *d = r->data;
-  unsigned int channels = effp->ininfo.channels;
+  unsigned int channels = effp->in_signal.channels;
   sox_size_t i;
   sox_size_t isamples0 = d->input_frames * channels;
   sox_size_t isamples = isamples0 + *isamp;
--- a/src/raw-fmt.c
+++ b/src/raw-fmt.c
@@ -1,29 +1,42 @@
 /*
- * libSoX raw file format
+ * File formats: raw         (c) 2007-8 SoX contributors
  *
- * Copyright 1991-2007 Lance Norskog And Sundry Contributors
- * This source code is freely redistributable and may be used for
- * any purpose.  This copyright notice must be maintained.
- * Lance Norskog And Sundry Contributors are not responsible for
- * the consequences of using this software.
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
  */
 
 #include "sox_i.h"
  
 static int raw_start(sox_format_t * ft) {
-  return sox_rawstart(ft, sox_false, sox_false, SOX_ENCODING_UNKNOWN, 0);
+  return sox_rawstart(ft, sox_false, sox_false, sox_true, SOX_ENCODING_UNKNOWN, 0);
 }
 
-const sox_format_handler_t *sox_raw_format_fn(void);
-
-const sox_format_handler_t *sox_raw_format_fn(void)
+SOX_FORMAT_HANDLER(raw)
 {
-  static char const * names[] = {"raw", NULL};
-  static sox_format_handler_t handler = {
+  static char const * const names[] = {"raw", NULL};
+  static unsigned const encodings[] = {
+    SOX_ENCODING_SIGN2, 32, 24, 16, 8, 0,
+    SOX_ENCODING_UNSIGNED, 32, 24, 16, 8, 0,
+    SOX_ENCODING_ULAW, 8, 0,
+    SOX_ENCODING_ALAW, 8, 0,
+    SOX_ENCODING_FLOAT, 64, 32, 0,
+    0};
+  static sox_format_handler_t const handler = {
     names, 0,
     raw_start, sox_rawread , NULL,
     raw_start, sox_rawwrite, NULL,
-    sox_rawseek
+    sox_rawseek, encodings, NULL
   };
   return &handler;
 }
--- a/src/raw.c
+++ b/src/raw.c
@@ -22,39 +22,12 @@
 
 int sox_rawseek(sox_format_t * ft, sox_size_t offset)
 {
-    sox_size_t new_offset, channel_block, alignment;
-
-    switch(ft->signal.size) {
-        case SOX_SIZE_BYTE:
-        case SOX_SIZE_16BIT:
-        case SOX_SIZE_24BIT:
-        case SOX_SIZE_32BIT:
-        case SOX_SIZE_64BIT:
-            break;
-        default:
-            sox_fail_errno(ft,SOX_ENOTSUP,"Can't seek this data size");
-            return ft->sox_errno;
-    }
-
-    new_offset = offset * ft->signal.size;
-    /* Make sure request aligns to a channel block (ie left+right) */
-    channel_block = ft->signal.channels * ft->signal.size;
-    alignment = new_offset % channel_block;
-    /* Most common mistaken is to compute something like
-     * "skip everthing upto and including this sample" so
-     * advance to next sample block in this case.
-     */
-    if (alignment != 0)
-        new_offset += (channel_block - alignment);
-
-    ft->sox_errno = sox_seeki(ft, (sox_ssize_t)new_offset, SEEK_SET);
-
-    return ft->sox_errno;
+  return sox_offset_seek(ft, ft->data_start, offset);
 }
 
 /* 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, unsigned size)
+int sox_rawstart(sox_format_t * ft, sox_bool default_rate, sox_bool default_channels, sox_bool default_length, sox_encoding_t encoding, unsigned size)
 {
   if (default_rate && ft->signal.rate == 0) {
     sox_warn("'%s': sample rate not specified; trying 8kHz", ft->filename);
@@ -68,18 +41,21 @@
 
   if (encoding != SOX_ENCODING_UNKNOWN) {
     if (ft->mode == 'r' &&
-        ft->signal.encoding != SOX_ENCODING_UNKNOWN &&
-        ft->signal.encoding != encoding)
+        ft->encoding.encoding != SOX_ENCODING_UNKNOWN &&
+        ft->encoding.encoding != encoding)
       sox_report("'%s': Format options overriding file-type encoding", ft->filename);
-    else ft->signal.encoding = encoding;
+    else ft->encoding.encoding = encoding;
   }
 
   if (size != 0) {
-    if (ft->mode == 'r' && ft->signal.size != 0 && ft->signal.size != size)
+    if (ft->mode == 'r' && ft->encoding.bits_per_sample != 0 && ft->encoding.bits_per_sample != size)
       sox_report("'%s': Format options overriding file-type sample-size", ft->filename);
-    else ft->signal.size = size;
+    else ft->encoding.bits_per_sample = size;
   }
 
+  if (ft->mode == 'r' && default_length && ft->encoding.bits_per_sample)
+    ft->length = div_bits(sox_filelength(ft), ft->encoding.bits_per_sample);
+
   return SOX_SUCCESS;
 }
 
@@ -141,9 +117,9 @@
 
 static ft_io_fun *check_format(sox_format_t * ft, sox_bool write)
 {
-    switch (ft->signal.size) {
-    case SOX_SIZE_BYTE:
-      switch (ft->signal.encoding) {
+    switch (ft->encoding.bits_per_sample) {
+    case 8:
+      switch (ft->encoding.encoding) {
       case SOX_ENCODING_SIGN2:
         return write ? sox_write_sb_samples : sox_read_sb_samples;
       case SOX_ENCODING_UNSIGNED:
@@ -157,8 +133,8 @@
       }
       break;
       
-    case SOX_SIZE_16BIT: 
-      switch (ft->signal.encoding) {
+    case 16: 
+      switch (ft->encoding.encoding) {
       case SOX_ENCODING_SIGN2:
         return write ? sox_write_sw_samples : sox_read_sw_samples;
       case SOX_ENCODING_UNSIGNED:
@@ -168,8 +144,8 @@
       }
       break;
 
-    case SOX_SIZE_24BIT:
-      switch (ft->signal.encoding) {
+    case 24:
+      switch (ft->encoding.encoding) {
       case SOX_ENCODING_SIGN2:
         return write ? sox_write_s3_samples : sox_read_s3_samples;
       case SOX_ENCODING_UNSIGNED:
@@ -179,8 +155,8 @@
       }
       break;
       
-    case SOX_SIZE_32BIT:
-      switch (ft->signal.encoding) {
+    case 32:
+      switch (ft->encoding.encoding) {
       case SOX_ENCODING_SIGN2:
         return write ? sox_write_sdw_samples : sox_read_sdw_samples;
       case SOX_ENCODING_UNSIGNED:
@@ -192,8 +168,8 @@
       }
       break;
       
-    case SOX_SIZE_64BIT:
-      switch (ft->signal.encoding) {
+    case 64:
+      switch (ft->encoding.encoding) {
       case SOX_ENCODING_FLOAT:
         return write ? sox_write_sudf_samples : sox_read_sudf_samples;
       default:
--- a/src/raw.h
+++ b/src/raw.h
@@ -1,25 +1,34 @@
 /*
- * libSoX raw file formats
+ * File formats: raw         (c) 2007-8 SoX contributors
  *
- * July 5, 1991
- * Copyright 1991 Lance Norskog And Sundry Contributors
- * This source code is freely redistributable and may be used for
- * any purpose.  This copyright notice must be maintained.
- * Lance Norskog And Sundry Contributors are not responsible for
- * the consequences of using this software.
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
  */
 
 #define RAW_FORMAT0(id, size, flags, encoding) \
 static int id ## _start(sox_format_t * ft) { \
-  return sox_rawstart(ft, sox_true, sox_true, SOX_ENCODING_ ## encoding, SOX_SIZE_ ## size); \
+  return sox_rawstart(ft, sox_true, sox_true, sox_true, SOX_ENCODING_ ## encoding, size); \
 } \
 const sox_format_handler_t *sox_ ## id ## _format_fn(void); \
 const sox_format_handler_t *sox_ ## id ## _format_fn(void) { \
+  static unsigned const write_encodings[] = { \
+    SOX_ENCODING_ ## encoding, size, 0, 0}; \
   static sox_format_handler_t handler = { \
     names, flags, \
     id ## _start, sox_rawread , NULL, \
     id ## _start, sox_rawwrite, NULL, \
-    NULL \
+    NULL, write_encodings, NULL \
   }; \
   return &handler; \
 }
--- a/src/remix.c
+++ b/src/remix.c
@@ -98,7 +98,7 @@
       if (p->out_specs[i].in_specs[j].multiplier == HUGE_VAL)
         p->out_specs[i].in_specs[j].multiplier = (p->mode == automatic || (p->mode == semi && !mul_spec)) ?  1. / p->out_specs[i].num_in_channels : 1;
   }
-  effp->outinfo.channels = p->num_out_channels;
+  effp->out_signal.channels = p->num_out_channels;
   return SOX_SUCCESS;
 }
 
@@ -114,8 +114,8 @@
 static int start(sox_effect_t * effp)
 {
   remix_t p = (remix_t) effp->priv;
-  parse(effp, NULL, effp->ininfo.channels);
-  if (effp->ininfo.channels < p->min_in_channels) {
+  parse(effp, NULL, effp->in_signal.channels);
+  if (effp->in_signal.channels < p->min_in_channels) {
     sox_fail("too few input channels");
     return SOX_EOF;
   }
@@ -127,11 +127,11 @@
 {
   remix_t p = (remix_t) effp->priv;
   unsigned i, j, len;
-  len =  min(*isamp / effp->ininfo.channels, *osamp / effp->outinfo.channels);
-  *isamp = len * effp->ininfo.channels;
-  *osamp = len * effp->outinfo.channels;
+  len =  min(*isamp / effp->in_signal.channels, *osamp / effp->out_signal.channels);
+  *isamp = len * effp->in_signal.channels;
+  *osamp = len * effp->out_signal.channels;
 
-  for (; len--; ibuf += effp->ininfo.channels) for (j = 0; j < effp->outinfo.channels; j++) {
+  for (; len--; ibuf += effp->in_signal.channels) for (j = 0; j < effp->out_signal.channels; j++) {
     double out = 0;
     for (i = 0; i < p->out_specs[j].num_in_channels; i++)
       out += ibuf[p->out_specs[j].in_specs[i].channel_num] * p->out_specs[j].in_specs[i].multiplier;
--- a/src/resample.c
+++ b/src/resample.c
@@ -37,12 +37,12 @@
  * Various changes, bugfixes(?), increased precision, by Stan Brooks.
  */
 
+#include "sox_i.h"
+
 #include <math.h>
 #include <stdlib.h>
 #include <string.h>
-#include "sox_i.h"
 
-
 /* Conversion constants */
 #define Lc        7
 #define Nc       (1<<Lc)
@@ -195,16 +195,16 @@
   long Xoff, gcdrate;
   int i;
 
-  if (effp->ininfo.rate == effp->outinfo.rate)
+  if (effp->in_signal.rate == effp->out_signal.rate)
     return SOX_EFF_NULL;
           
-  effp->outinfo.channels = effp->ininfo.channels;
+  effp->out_signal.channels = effp->in_signal.channels;
 
-  r->Factor = effp->outinfo.rate / effp->ininfo.rate;
+  r->Factor = effp->out_signal.rate / effp->in_signal.rate;
 
-  gcdrate = sox_gcd((long) effp->ininfo.rate, (long) effp->outinfo.rate);
-  r->a = effp->ininfo.rate / gcdrate;
-  r->b = effp->outinfo.rate / gcdrate;
+  gcdrate = sox_gcd((long) effp->in_signal.rate, (long) effp->out_signal.rate);
+  r->a = effp->in_signal.rate / gcdrate;
+  r->b = effp->out_signal.rate / gcdrate;
 
   if (r->a <= r->b && r->b <= NQMAX) {
     r->quadr = -1;      /* exact coeffs */
--- a/src/reverb.c
+++ b/src/reverb.c
@@ -202,19 +202,19 @@
   size_t i;
   
   p->ichannels = p->ochannels = 1;
-  effp->outinfo.rate = effp->ininfo.rate;
-  if (effp->ininfo.channels > 2 && p->stereo_depth) {
+  effp->out_signal.rate = effp->in_signal.rate;
+  if (effp->in_signal.channels > 2 && p->stereo_depth) {
     sox_warn("stereo-depth not applicable with >2 channels");
     p->stereo_depth = 0;
   }
-  if (effp->ininfo.channels == 1 && p->stereo_depth)
-    effp->outinfo.channels = p->ochannels = 2;
-  else effp->outinfo.channels = effp->ininfo.channels;
-  if (effp->ininfo.channels == 2 && p->stereo_depth)
+  if (effp->in_signal.channels == 1 && p->stereo_depth)
+    effp->out_signal.channels = p->ochannels = 2;
+  else effp->out_signal.channels = effp->in_signal.channels;
+  if (effp->in_signal.channels == 2 && p->stereo_depth)
     p->ichannels = p->ochannels = 2;
-  else effp->flows = effp->ininfo.channels;
+  else effp->flows = effp->in_signal.channels;
   for (i = 0; i < p->ichannels; ++i) reverb_create(
-    &p->chan[i].reverb, effp->ininfo.rate, p->wet_gain_dB, p->room_scale,
+    &p->chan[i].reverb, effp->in_signal.rate, p->wet_gain_dB, p->room_scale,
     p->reverberance, p->hf_damping, p->pre_delay_ms, p->stereo_depth,
     effp->global_info->global_info->bufsiz / p->ochannels, p->chan[i].wet);
   return SOX_SUCCESS;
--- a/src/s1-fmt.c
+++ b/src/s1-fmt.c
@@ -1,14 +1,22 @@
 /*
- * libSoX s1 raw file format
+ * File formats: raw         (c) 2007-8 SoX contributors
  *
- * Copyright 2007 Lance Norskog And Sundry Contributors
- * This source code is freely redistributable and may be used for
- * any purpose.  This copyright notice must be maintained.
- * Lance Norskog And Sundry Contributors are not responsible for
- * the consequences of using this software.
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
  */
 
 #include "sox_i.h"
 #include "raw.h"
 
-RAW_FORMAT1(s1, "sb", 8BIT, 0, SIGN2)
+RAW_FORMAT1(s1, "sb", 8, 0, SIGN2)
--- a/src/s2-fmt.c
+++ b/src/s2-fmt.c
@@ -1,14 +1,22 @@
 /*
- * libSoX s2 raw file format
+ * File formats: raw         (c) 2007-8 SoX contributors
  *
- * Copyright 2007 Lance Norskog And Sundry Contributors
- * This source code is freely redistributable and may be used for
- * any purpose.  This copyright notice must be maintained.
- * Lance Norskog And Sundry Contributors are not responsible for
- * the consequences of using this software.
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
  */
 
 #include "sox_i.h"
 #include "raw.h"
 
-RAW_FORMAT1(s2, "sw", 16BIT, 0, SIGN2)
+RAW_FORMAT1(s2, "sw", 16, 0, SIGN2)
--- a/src/s3-fmt.c
+++ b/src/s3-fmt.c
@@ -1,14 +1,22 @@
 /*
- * libSoX s3 raw file format
+ * File formats: raw         (c) 2007-8 SoX contributors
  *
- * Copyright 2007 Lance Norskog And Sundry Contributors
- * This source code is freely redistributable and may be used for
- * any purpose.  This copyright notice must be maintained.
- * Lance Norskog And Sundry Contributors are not responsible for
- * the consequences of using this software.
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
  */
 
 #include "sox_i.h"
 #include "raw.h"
 
-RAW_FORMAT(s3, 24BIT, 0, SIGN2)
+RAW_FORMAT(s3, 24, 0, SIGN2)
--- a/src/s4-fmt.c
+++ b/src/s4-fmt.c
@@ -1,14 +1,22 @@
 /*
- * libSoX s4 raw file format
+ * File formats: raw         (c) 2007-8 SoX contributors
  *
- * Copyright 2007 Lance Norskog And Sundry Contributors
- * This source code is freely redistributable and may be used for
- * any purpose.  This copyright notice must be maintained.
- * Lance Norskog And Sundry Contributors are not responsible for
- * the consequences of using this software.
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
  */
 
 #include "sox_i.h"
 #include "raw.h"
 
-RAW_FORMAT1(s4, "sl", 32BIT, 0, SIGN2)
+RAW_FORMAT1(s4, "sl", 32, 0, SIGN2)
--- a/src/sf.c
+++ b/src/sf.c
@@ -40,7 +40,7 @@
         sfcodep = (SFCODE *) (&sfhead->sfinfo + 1);
         do {
                 sfcharp = (char *) sfcodep + sizeof(SFCODE);
-                if (ft->signal.reverse_bytes) {
+                if (ft->encoding.reverse_bytes) {
                         sfcodep->bsize = sox_swapdw(sfcodep->bsize);
                         sfcodep->code = sox_swapdw(sfcodep->code);
                 }
@@ -61,14 +61,14 @@
         free(commentbuf);
 }
 
-static int sox_sfseek(sox_format_t * ft, sox_size_t offset)
+static int seek(sox_format_t * ft, sox_size_t offset)
 {
     sox_size_t new_offset, channel_block, alignment;
 
     sf_t sf = (sf_t ) ft->priv;
-    new_offset = offset * ft->signal.size;
+    new_offset = offset * (ft->encoding.bits_per_sample >> 3);
     /* Make sure request aligns to a channel block (ie left+right) */
-    channel_block = ft->signal.channels * ft->signal.size;
+    channel_block = ft->signal.channels * (ft->encoding.bits_per_sample >> 3);
     alignment = new_offset % channel_block;
     /* Most common mistaken is to compute something like
      * "skip everthing upto and including this sample" so
@@ -88,7 +88,7 @@
  *      size and encoding of samples,
  *      mono/stereo/quad.
  */
-static int sox_sfstartread(sox_format_t * ft)
+static int startread(sox_format_t * ft)
 {
         sf_t sf = (sf_t) ft->priv;
         SFHEADER sfhead;
@@ -101,7 +101,7 @@
                 return(SOX_EOF);
         }
         memcpy(&sf->info, &sfhead.sfinfo, sizeof(struct sfinfo));
-        if (ft->signal.reverse_bytes) {
+        if (ft->encoding.reverse_bytes) {
                 sox_swapf(&sf->info.sf_srate);
                 sf->info.sf_packmode = sox_swapdw(sf->info.sf_packmode);
                 sf->info.sf_chans = sox_swapdw(sf->info.sf_chans);
@@ -120,13 +120,13 @@
         ft->signal.rate = sf->info.sf_srate;
         switch(sf->info.sf_packmode) {
                 case SF_SHORT:
-                        ft->signal.size = SOX_SIZE_16BIT;
-                        ft->signal.encoding = SOX_ENCODING_SIGN2;
-                        samplesize = ft->signal.size;
+                        ft->encoding.bits_per_sample = 16;
+                        ft->encoding.encoding = SOX_ENCODING_SIGN2;
+                        samplesize = 2;
                         break;
                 case SF_FLOAT:
-                        ft->signal.size = SOX_SIZE_32BIT;
-                        ft->signal.encoding = SOX_ENCODING_FLOAT;
+                        ft->encoding.bits_per_sample = 16;
+                        ft->encoding.encoding = SOX_ENCODING_FLOAT;
                         samplesize = sizeof(float);
                         break;
                 default:
@@ -156,7 +156,7 @@
         return(rc);
 }
 
-static int sox_sfstartwrite(sox_format_t * ft)
+static int startwrite(sox_format_t * ft)
 {
         sf_t sf = (sf_t) ft->priv;
         SFHEADER sfhead;
@@ -181,14 +181,14 @@
             sf->info.magic_union._magic_bytes.sf_machine = SF_SUN;
 
         sf->info.sf_srate = ft->signal.rate;
-        if (ft->signal.size == SOX_SIZE_32BIT &&
-            ft->signal.encoding == SOX_ENCODING_FLOAT) {
+        if (ft->encoding.bits_per_sample == 32 &&
+            ft->encoding.encoding == SOX_ENCODING_FLOAT) {
                 sf->info.sf_packmode = SF_FLOAT;
         } else {
                 sf->info.sf_packmode = SF_SHORT;
                 /* Default to signed words */
-                ft->signal.size = SOX_SIZE_16BIT;
-                ft->signal.encoding = SOX_ENCODING_SIGN2;
+                ft->encoding.bits_per_sample = 16;
+                ft->encoding.encoding = SOX_ENCODING_SIGN2;
         }
 
         sf->info.sf_chans = ft->signal.channels;
@@ -216,29 +216,18 @@
         return(SOX_SUCCESS);
 }
 
-/* Read and write are supplied by raw.c */
-/* IRCAM Sound File */
-static const char *sfnames[] = {
-  "sf",
-  "ircam",
-  NULL
-};
-
-static sox_format_handler_t sox_sf_format = {
-  sfnames,
-  0,
-  sox_sfstartread,
-  sox_rawread,
-  sox_rawstopread,
-  sox_sfstartwrite,
-  sox_rawwrite,
-  sox_rawstopwrite,
-  sox_sfseek
-};
-
-const sox_format_handler_t *sox_sf_format_fn(void);
-
-const sox_format_handler_t *sox_sf_format_fn(void)
+SOX_FORMAT_HANDLER(sf)
 {
-    return &sox_sf_format;
+  static char const * const names[] = {"sf", "ircam", NULL};
+  static unsigned const encodings[] = {
+    SOX_ENCODING_SIGN2, 16, 0,
+    SOX_ENCODING_FLOAT, 32, 0,
+    0};
+  static sox_format_handler_t const handler = {
+    names, 0,
+    startread, sox_rawread, sox_rawstopread,
+    startwrite, sox_rawwrite, sox_rawstopwrite,
+    seek, encodings, NULL
+  };
+  return &handler;
 }
--- a/src/silence.c
+++ b/src/silence.c
@@ -13,10 +13,10 @@
  * Thesholds can be given as either a percentage or in decibels.
  */
 
+#include "sox_i.h"
 
 #include <string.h>
 #include <math.h>
-#include "sox_i.h"
 
 /* Private data for silence effect. */
 
@@ -228,8 +228,8 @@
          * better or else RMS will look like non-silence at
          * aburpt changes from load to silence.
          */
-        silence->window_size = (effp->ininfo.rate / 50) * 
-                               effp->ininfo.channels;
+        silence->window_size = (effp->in_signal.rate / 50) * 
+                               effp->in_signal.channels;
         silence->window = (double *)xmalloc(silence->window_size *
                                            sizeof(double));
 
@@ -238,13 +238,13 @@
         /* Now that we know sample rate, reparse duration. */
         if (silence->start)
         {
-            if (sox_parsesamples(effp->ininfo.rate, silence->start_duration_str,
+            if (sox_parsesamples(effp->in_signal.rate, silence->start_duration_str,
                                 &silence->start_duration, 's') == NULL)
               return sox_usage(effp);
         }
         if (silence->stop)
         {
-            if (sox_parsesamples(effp->ininfo.rate,silence->stop_duration_str,
+            if (sox_parsesamples(effp->in_signal.rate,silence->stop_duration_str,
                                 &silence->stop_duration,'s') == NULL)
               return sox_usage(effp);
         }
@@ -275,21 +275,21 @@
 
     /* When scaling low bit data, noise values got scaled way up */
     /* Only consider the original bits when looking for silence */
-    switch(effp->ininfo.size)
+    switch(effp->in_signal.precision)
     {
-        case SOX_SIZE_BYTE:
+        case 8:
             value = SOX_SAMPLE_TO_SIGNED_8BIT(value, dummy_clipped_count);
             ratio = (double)abs(value) / (double)SOX_INT8_MAX;
             break;
-        case SOX_SIZE_16BIT:
+        case 16:
             value = SOX_SAMPLE_TO_SIGNED_16BIT(value, dummy_clipped_count);
             ratio = (double)abs(value) / (double)SOX_INT16_MAX;
             break;
-        case SOX_SIZE_24BIT:
+        case 24:
             value = SOX_SAMPLE_TO_SIGNED_24BIT(value, dummy_clipped_count);
             ratio = (double)abs(value) / (double)SOX_INT24_MAX;
             break;
-        case SOX_SIZE_32BIT:
+        case 32:
             value = SOX_SAMPLE_TO_SIGNED_32BIT(value,);
             ratio = (double)labs(value) / (double)SOX_INT32_MAX;
             break;
@@ -359,11 +359,11 @@
 silence_trim:
             nrOfTicks = min((*isamp-nrOfInSamplesRead), 
                             (*osamp-nrOfOutSamplesWritten)) / 
-                           effp->ininfo.channels;
+                           effp->in_signal.channels;
             for(i = 0; i < nrOfTicks; i++)
             {
                 threshold = 0;
-                for (j = 0; j < effp->ininfo.channels; j++)
+                for (j = 0; j < effp->in_signal.channels; j++)
                 {
                     threshold |= aboveThreshold(effp,
                                                 compute_rms(effp, ibuf[j]),
@@ -374,7 +374,7 @@
                 if (threshold)
                 {
                     /* Add to holdoff buffer */
-                    for (j = 0; j < effp->ininfo.channels; j++)
+                    for (j = 0; j < effp->in_signal.channels; j++)
                     {
                         update_rms(effp, *ibuf);
                         silence->start_holdoff[
@@ -401,12 +401,12 @@
                 else /* !above Threshold */
                 {
                     silence->start_holdoff_end = 0;
-                    for (j = 0; j < effp->ininfo.channels; j++)
+                    for (j = 0; j < effp->in_signal.channels; j++)
                     {
                         update_rms(effp, ibuf[j]);
                     }
-                    ibuf += effp->ininfo.channels; 
-                    nrOfInSamplesRead += effp->ininfo.channels;
+                    ibuf += effp->in_signal.channels; 
+                    nrOfInSamplesRead += effp->in_signal.channels;
                 }
             } /* for nrOfTicks */
             break;
@@ -474,7 +474,7 @@
 silence_copy:
             nrOfTicks = min((*isamp-nrOfInSamplesRead), 
                             (*osamp-nrOfOutSamplesWritten)) / 
-                           effp->ininfo.channels;
+                           effp->in_signal.channels;
             if (silence->stop)
             {
                 /* Case A */
@@ -481,7 +481,7 @@
                 for(i = 0; i < nrOfTicks; i++)
                 {
                     threshold = 1;
-                    for (j = 0; j < effp->ininfo.channels; j++)
+                    for (j = 0; j < effp->in_signal.channels; j++)
                     {
                         threshold &= aboveThreshold(effp, 
                                                     compute_rms(effp, ibuf[j]),
@@ -510,7 +510,7 @@
                     else if (threshold)
                     {
                         /* Not holding off so copy into output buffer */
-                        for (j = 0; j < effp->ininfo.channels; j++)
+                        for (j = 0; j < effp->in_signal.channels; j++)
                         {
                             update_rms(effp, *ibuf);
                             *obuf++ = *ibuf++;
@@ -522,7 +522,7 @@
                     else if (!threshold)
                     {
                         /* Add to holdoff buffer */
-                        for (j = 0; j < effp->ininfo.channels; j++)
+                        for (j = 0; j < effp->in_signal.channels; j++)
                         {
                             update_rms(effp, *ibuf);
                             if (silence->leave_silence) {
@@ -584,9 +584,9 @@
             {
                 /* Case B */
                 memcpy(obuf, ibuf, sizeof(sox_sample_t)*nrOfTicks*
-                                   effp->ininfo.channels);
-                nrOfInSamplesRead += (nrOfTicks*effp->ininfo.channels);
-                nrOfOutSamplesWritten += (nrOfTicks*effp->ininfo.channels);
+                                   effp->in_signal.channels);
+                nrOfInSamplesRead += (nrOfTicks*effp->in_signal.channels);
+                nrOfOutSamplesWritten += (nrOfTicks*effp->in_signal.channels);
             }
             break;
 
--- a/src/skeleff.c
+++ b/src/skeleff.c
@@ -30,7 +30,7 @@
 
 /*
  * Process command-line options but don't do other
- * initialization now: effp->ininfo & effp->outinfo are not
+ * initialization now: effp->in_signal & effp->out_signal are not
  * yet filled in.
  */
 static int getopts(sox_effect_t * effp, int n, char UNUSED **argv)
@@ -49,7 +49,7 @@
  */
 static int start(sox_effect_t * effp)
 {
-  if (effp->outinfo.channels == 1) {
+  if (effp->out_signal.channels == 1) {
     sox_fail("Can't run on mono data.");
     return SOX_EOF;
   }
@@ -67,7 +67,7 @@
   skeleff_t UNUSED skeleff = (skeleff_t)effp->priv;
   sox_size_t len, done;
 
-  switch (effp->outinfo.channels) {
+  switch (effp->out_signal.channels) {
   case 2:
     /* Length to process will be buffer length / 2 since we
      * work with two samples at a time.
--- a/src/skelform.c
+++ b/src/skelform.c
@@ -59,15 +59,15 @@
    * then you should set it here.
    */
   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 */
+  ft->signal.channels = 1; /* or 2 or 3 ... */
+  ft->encoding.bits_per_sample = 8; /* or 16 ... */
+  ft->encoding.encoding = SOX_ENCODING_UNSIGNED; /* or SIGN2 ... */
   append_comment(&ft->comments, "any comment in file header.");
 
   /* If your format doesn't have a header then samples_in_file
    * can be determined by the file size.
    */
-  samples_in_file = sox_filelength(ft) / ft->signal.size;
+  samples_in_file = sox_filelength(ft) / (ft->encoding.bits_per_sample >> 3);
 
   /* If you can detect the length of your file, record it here. */
   ft->length = samples_in_file;
@@ -80,7 +80,7 @@
  * Read up to len samples of type sox_sample_t from file into buf[].
  * Return number of samples read, or 0 if at end of file.
  */
-static sox_size_t read(sox_format_t * ft, sox_sample_t *buf, sox_size_t len)
+static sox_size_t read_samples(sox_format_t * ft, sox_sample_t *buf, sox_size_t len)
 {
   skelform_t UNUSED sk = (skelform_t)ft->priv;
   sox_size_t done;
@@ -90,9 +90,9 @@
     if (feof(ft->fp)) /* no more samples */
       break;
     sample = fgetc(ft->fp);
-    switch (ft->signal.size) {
-    case SOX_SIZE_8BIT:
-      switch (ft->signal.encoding) {
+    switch (ft->encoding.bits_per_sample) {
+    case 8:
+      switch (ft->encoding.encoding) {
       case SOX_ENCODING_UNSIGNED:
         *buf++ = SOX_UNSIGNED_8BIT_TO_SAMPLE(sample,);
         break;
@@ -136,12 +136,12 @@
   if (ft->signal.rate != 44100)
     sox_fail("Output .skel file must have a sample rate of 44100Hz");
 
-  if (ft->signal.size == 0) {
+  if (ft->encoding.bits_per_sample == 0) {
     sox_fail("Did not specify a size for .skel output file");
     return SOX_EOF;
   }
 
-  /* error check ft->signal.encoding */
+  /* error check ft->encoding.encoding */
   /* error check ft->signal.channels */
 
   /* Write file header, if any */
@@ -155,13 +155,13 @@
  * Write len samples of type sox_sample_t from buf[] to file.
  * Return number of samples written.
  */
-static sox_size_t write(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len)
+static sox_size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len)
 {
   skelform_t UNUSED sk = (skelform_t)ft->priv;
 
-  switch (ft->signal.size) {
-  case SOX_SIZE_8BIT:
-    switch (ft->signal.encoding) {
+  switch (ft->encoding.bits_per_sample) {
+  case 8:
+    switch (ft->encoding.encoding) {
     case SOX_ENCODING_UNSIGNED:
       while (len--) {
         len = sox_writeb(ft, SOX_SAMPLE_TO_UNSIGNED_8BIT(*buf++, ft->clips));
@@ -196,32 +196,28 @@
   return SOX_SUCCESS;
 }
 
-/* Format file suffixes */
-static const char *names[] = {
-  "skel",
-  NULL
-};
+SOX_FORMAT_HANDLER(skel)
+{
+  /* Format file suffixes */
+  static const char *names[] = {"skel",NULL };
 
-/* Format descriptor
- * If no specific processing is needed for any of
- * the 7 functions, then the function above can be deleted
- * and 0 used in place of the its name below.
- */
-static sox_format_handler_t sox_skel_format = {
-  names,
-  0,
-  startread,
-  read,
-  stopread,
-  startwrite,
-  write,
-  stopwrite,
-  seek
-};
+  /* Encoding types and sizes that this handler can write */
+  static unsigned encodings[] = {
+    SOX_ENCODING_SIGN2, 16, 0,
+    SOX_ENCODING_UNSIGNED, 8, 0,
+    0};
 
-const sox_format_handler_t *sox_skel_format_fn(void);
+  /* Format descriptor
+   * If no specific processing is needed for any of
+   * the 7 functions, then the function above can be deleted
+   * and NULL used in place of the its name below.
+   */
+  static sox_format_handler_t handler = {
+    names, 0,
+    startread, read_samples, stopread,
+    startwrite, write_samples, stopwrite,
+    seek, encodings, NULL
+  };
 
-const sox_format_handler_t *sox_skel_format_fn(void)
-{
-  return &sox_skel_format;
+  return &handler;
 }
--- a/src/smp.c
+++ b/src/smp.c
@@ -174,9 +174,9 @@
     sox_size_t new_offset, channel_block, alignment;
     smp_t smp = (smp_t) ft->priv;
 
-    new_offset = offset * ft->signal.size;
+    new_offset = offset * (ft->encoding.bits_per_sample >> 3);
     /* Make sure request aligns to a channel block (ie left+right) */
-    channel_block = ft->signal.channels * ft->signal.size;
+    channel_block = ft->signal.channels * (ft->encoding.bits_per_sample >> 3);
     alignment = new_offset % channel_block;
     /* Most common mistaken is to compute something like
      * "skip everthing upto and including this sample" so
@@ -189,7 +189,7 @@
     ft->sox_errno = sox_seeki(ft, (sox_ssize_t)new_offset, SEEK_SET);
 
     if( ft->sox_errno == SOX_SUCCESS )
-        smp->NoOfSamps = ft->length - (new_offset / ft->signal.size);
+        smp->NoOfSamps = ft->length - (new_offset / (ft->encoding.bits_per_sample >> 3));
 
     return(ft->sox_errno);
 }
@@ -271,8 +271,8 @@
         }
 
         ft->signal.rate = (int) trailer.rate;
-        ft->signal.size = SOX_SIZE_16BIT;
-        ft->signal.encoding = SOX_ENCODING_SIGN2;
+        ft->encoding.bits_per_sample = 16;
+        ft->encoding.encoding = SOX_ENCODING_SIGN2;
         ft->signal.channels = 1;
         smp->dataStart = samplestart;
         ft->length = smp->NoOfSamps;
@@ -344,11 +344,6 @@
                 return(SOX_EOF);
         }
 
-        /* If your format specifies any of the following info. */
-        ft->signal.size = SOX_SIZE_16BIT;
-        ft->signal.encoding = SOX_ENCODING_SIGN2;
-        ft->signal.channels = 1;
-
         memcpy(header.Id, SVmagic, sizeof(header.Id));
         memcpy(header.version, SVvers, sizeof(header.version));
         sprintf(header.comments, "%-*s", COMMENTLEN - 1, "Converted using Sox.");
@@ -401,27 +396,15 @@
         return(SOX_SUCCESS);
 }
 
-/* SampleVision sound */
-static const char *smpnames[] = {
-  "smp",
-  NULL,
-};
-
-static sox_format_handler_t sox_smp_format = {
-  smpnames,
-  SOX_FILE_LOOPS | SOX_FILE_LIT_END,
-  sox_smpstartread,
-  sox_smpread,
-  NULL,
-  sox_smpstartwrite,
-  sox_smpwrite,
-  sox_smpstopwrite,
-  sox_smpseek
-};
-
-const sox_format_handler_t *sox_smp_format_fn(void);
-
-const sox_format_handler_t *sox_smp_format_fn(void)
+SOX_FORMAT_HANDLER(smp)
 {
-    return &sox_smp_format;
+  static char const * const names[] = {"smp", NULL};
+  static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 16, 0, 0};
+  static sox_format_handler_t handler = {
+    names, SOX_FILE_LOOPS | SOX_FILE_LIT_END | SOX_FILE_MONO,
+    sox_smpstartread, sox_smpread, NULL,
+    sox_smpstartwrite, sox_smpwrite, sox_smpstopwrite,
+    sox_smpseek, write_encodings, NULL
+  };
+  return &handler;
 }
--- a/src/sndfile.c
+++ b/src/sndfile.c
@@ -84,43 +84,43 @@
   
   switch (format) {
   case SF_FORMAT_PCM_S8:
-    *size = SOX_SIZE_8BIT;
+    *size = 8;
     return SOX_ENCODING_SIGN2;
   case SF_FORMAT_PCM_16:
-    *size = SOX_SIZE_16BIT;
+    *size = 16;
     return SOX_ENCODING_SIGN2;
   case SF_FORMAT_PCM_24:
-    *size = SOX_SIZE_24BIT;
+    *size = 24;
     return SOX_ENCODING_SIGN2;
   case SF_FORMAT_PCM_32:
-    *size = SOX_SIZE_32BIT;
+    *size = 32;
     return SOX_ENCODING_SIGN2;
   case SF_FORMAT_PCM_U8:
-    *size = SOX_SIZE_8BIT;
+    *size = 8;
     return SOX_ENCODING_UNSIGNED;
   case SF_FORMAT_FLOAT:
-    *size = SOX_SIZE_32BIT;
+    *size = 32;
     return SOX_ENCODING_FLOAT;
   case SF_FORMAT_DOUBLE:
-    *size = SOX_SIZE_64BIT;
+    *size = 64;
     return SOX_ENCODING_FLOAT;
   case SF_FORMAT_ULAW:
-    *size = SOX_SIZE_8BIT;
+    *size = 8;
     return SOX_ENCODING_ULAW;
   case SF_FORMAT_ALAW:
-    *size = SOX_SIZE_8BIT;
+    *size = 8;
     return SOX_ENCODING_ALAW;
   case SF_FORMAT_IMA_ADPCM:
-    *size = SOX_SIZE_16BIT;
+    *size = 16;
     return SOX_ENCODING_IMA_ADPCM;
   case SF_FORMAT_MS_ADPCM:
-    *size = SOX_SIZE_16BIT;
+    *size = 16;
     return SOX_ENCODING_MS_ADPCM;
   case SF_FORMAT_GSM610:
-    *size = SOX_SIZE_16BIT;
+    *size = 16;
     return SOX_ENCODING_GSM;
   case SF_FORMAT_VOX_ADPCM:
-    *size = SOX_SIZE_16BIT;
+    *size = 16;
     return SOX_ENCODING_OKI_ADPCM;
 
   /* For encodings we can't represent, have a sensible default */
@@ -210,13 +210,12 @@
 /* Make libsndfile subtype from sample encoding and size */
 static int sndfile_format(sox_encoding_t encoding, unsigned size)
 {
-  if (encoding < SOX_ENCODING_SIZE_IS_WORD) {
-    switch (encoding) {
+  size = (size + 7) & ~7u;
+  switch (encoding) {
     case SOX_ENCODING_ULAW:
       return SF_FORMAT_ULAW;
     case SOX_ENCODING_ALAW:
       return SF_FORMAT_ALAW;
-    case SOX_ENCODING_ADPCM:
     case SOX_ENCODING_MS_ADPCM:
       return SF_FORMAT_MS_ADPCM;
     case SOX_ENCODING_IMA_ADPCM:
@@ -223,13 +222,8 @@
       return SF_FORMAT_IMA_ADPCM;
     case SOX_ENCODING_OKI_ADPCM:
       return SF_FORMAT_VOX_ADPCM;
-    default: /* Should be impossible */
-      return 0;
-    }
-  } else {
-    switch (encoding) {
     case SOX_ENCODING_UNSIGNED:
-      if (size == SOX_SIZE_8BIT)
+      if (size == 8)
         return SF_FORMAT_PCM_U8;
       else
         return 0;
@@ -239,13 +233,13 @@
 #ifdef HAVE_SNDFILE_1_0_12
     case SOX_ENCODING_FLAC:
       switch (size) {
-      case SOX_SIZE_8BIT:
+      case 8:
         return SF_FORMAT_PCM_S8;
-      case SOX_SIZE_16BIT:
+      case 16:
         return SF_FORMAT_PCM_16;
-      case SOX_SIZE_24BIT:
+      case 24:
         return SF_FORMAT_PCM_24;
-      case SOX_SIZE_32BIT:
+      case 32:
         return SF_FORMAT_PCM_32;
       default: /* invalid size */
         return 0;
@@ -258,7 +252,6 @@
       return SF_FORMAT_GSM610;
     default: /* Bad encoding */
       return 0;
-    }
   }
 }
 
@@ -265,7 +258,7 @@
 static void start(sox_format_t * ft)
 {
   sndfile_t sf = (sndfile_t)ft->priv;
-  int subtype = sndfile_format(ft->signal.encoding, ft->signal.size);
+  int subtype = sndfile_format(ft->encoding.encoding, ft->encoding.bits_per_sample? ft->encoding.bits_per_sample : ft->signal.precision);
   sf->log_buffer_ptr = sf->log_buffer = xmalloc(LOG_MAX);
   sf->sf_info = (SF_INFO *)xcalloc(1, sizeof(SF_INFO));
 
@@ -304,7 +297,7 @@
   }
 
   /* Copy format info */
-  ft->signal.encoding = sox_encoding_and_size((unsigned)sf->sf_info->format, &ft->signal.size);
+  ft->encoding.encoding = sox_encoding_and_size((unsigned)sf->sf_info->format, &ft->encoding.bits_per_sample);
   ft->signal.channels = sf->sf_info->channels;
   ft->length = sf->sf_info->frames * sf->sf_info->channels;
 
@@ -324,7 +317,7 @@
  * Read up to len samples of type sox_sample_t from file into buf[].
  * Return number of samples read.
  */
-static sox_size_t read(sox_format_t * ft, sox_sample_t *buf, sox_size_t len)
+static sox_size_t read_samples(sox_format_t * ft, sox_sample_t *buf, sox_size_t len)
 {
   sndfile_t sf = (sndfile_t)ft->priv;
 
@@ -391,7 +384,7 @@
  * Write len samples of type sox_sample_t from buf[] to file.
  * Return number of samples written.
  */
-static sox_size_t write(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len)
+static sox_size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len)
 {
   sndfile_t sf = (sndfile_t)ft->priv;
 
@@ -418,56 +411,60 @@
   return SOX_SUCCESS;
 }
 
-/* Format file suffixes */
-/* For now, comment out formats built in to SoX */
-static const char *names[] = {
-  "sndfile", /* special type to force use of sndfile */
-  /* "aif", */
-  /* "wav", */
-  /* "au", */
+SOX_FORMAT_HANDLER(sndfile)
+{
+  /* Format file suffixes */
+  /* For now, comment out formats built in to SoX */
+  static char const * const names[] = {
+    "sndfile", /* special type to force use of sndfile */
+    /* "aif", */
+    /* "wav", */
+    /* "au", */
 #ifdef HAVE_SNDFILE_1_0_12
-  "caf",
+    "caf",
 #endif
-  /* "flac", */
-  /* "snd", */
-  /* "svx", */
-  "paf",
-  "fap",
-  /* "gsm", */
-  /* "nist", */
-  /* "ircam", */
-  /* "sf", */
-  /* "voc", */
-  "w64",
-  /* "raw", */
-  "mat4",
-  "mat5",
-  "mat",
-  "pvf",
-  "sds",
-  "sd2",
-  /* "vox", */
-  "xi",
-  NULL
-};
+    /* "flac", */
+    /* "snd", */
+    /* "svx", */
+    "paf",
+    "fap",
+    /* "gsm", */
+    /* "nist", */
+    /* "ircam", */
+    /* "sf", */
+    /* "voc", */
+    "w64",
+    /* "raw", */
+    "mat4",
+    "mat5",
+    "mat",
+    "pvf",
+    "sds",
+    "sd2",
+    /* "vox", */
+    "xi",
+    NULL
+  };
 
-/* Format descriptor */
-static sox_format_handler_t format = {
-  names,
-  SOX_FILE_NOSTDIO,
-  startread,
-  read,
-  stopread,
-  startwrite,
-  write,
-  stopwrite,
-  seek
-};
+  static unsigned const write_encodings[] = {
+    SOX_ENCODING_SIGN2, 16, 24, 32, 8, 0,
+    SOX_ENCODING_UNSIGNED, 8, 0,
+    SOX_ENCODING_FLOAT, 32, 64, 0,
+    SOX_ENCODING_ALAW, 8, 0,
+    SOX_ENCODING_ULAW, 8, 0,
+    SOX_ENCODING_IMA_ADPCM, 4, 0,
+    SOX_ENCODING_MS_ADPCM, 4, 0,
+    SOX_ENCODING_OKI_ADPCM, 4, 0,
+    SOX_ENCODING_GSM, 0,
+    0};
 
-const sox_format_handler_t *sox_sndfile_format_fn(void);
+  static sox_format_handler_t const format = {
+    names, SOX_FILE_NOSTDIO,
+    startread, read_samples, stopread,
+    startwrite, write_samples, stopwrite,
+    seek, write_encodings, NULL
+  };
 
-const sox_format_handler_t *sox_sndfile_format_fn(void)
-{
   return &format;
 }
 
--- a/src/sndrtool.c
+++ b/src/sndrtool.c
@@ -40,14 +40,14 @@
   sox_writebuf(ft, name_buf, 96);
 }
 
-static int sox_sndseek(sox_format_t * ft, sox_size_t offset)
+static int seek(sox_format_t * ft, sox_size_t offset)
 {
   sox_size_t new_offset, channel_block, alignment;
   snd_t snd = (snd_t) ft->priv;
 
-  new_offset = offset * ft->signal.size;
+  new_offset = offset * (ft->encoding.bits_per_sample >> 3);
   /* Make sure request aligns to a channel block (ie left+right) */
-  channel_block = ft->signal.channels * ft->signal.size;
+  channel_block = ft->signal.channels * (ft->encoding.bits_per_sample >> 3);
   alignment = new_offset % channel_block;
   /* Most common mistaken is to compute something like
    * "skip everthing upto and including this sample" so
@@ -60,7 +60,7 @@
   return sox_seeki(ft, (sox_ssize_t) new_offset, SEEK_SET);
 }
 
-static int sox_sndtstartread(sox_format_t * ft)
+static int startread(sox_format_t * ft)
 {
   snd_t snd = (snd_t) ft->priv;
 
@@ -113,8 +113,8 @@
 
   ft->signal.channels = 1;
   ft->signal.rate = rate;
-  ft->signal.encoding = SOX_ENCODING_UNSIGNED;
-  ft->signal.size = SOX_SIZE_BYTE;
+  ft->encoding.encoding = SOX_ENCODING_UNSIGNED;
+  ft->encoding.bits_per_sample = 8;
 
   snd->dataStart = sox_tell(ft);
   ft->length = sox_filelength(ft) - snd->dataStart;
@@ -122,7 +122,7 @@
   return (SOX_SUCCESS);
 }
 
-static int sox_sndtstartwrite(sox_format_t * ft)
+static int startwrite(sox_format_t * ft)
 {
   snd_t p = (snd_t) ft->priv;
   int rc;
@@ -133,9 +133,6 @@
     return rc;
 
   /* write header */
-  ft->signal.channels = 1;
-  ft->signal.encoding = SOX_ENCODING_UNSIGNED;
-  ft->signal.size = SOX_SIZE_BYTE;
   p->nsamples = 0;
   sndtwriteheader(ft, 0);
 
@@ -142,7 +139,7 @@
   return (SOX_SUCCESS);
 }
 
-static sox_size_t sox_sndtwrite(sox_format_t * ft, const sox_sample_t * buf,
+static sox_size_t write_samples(sox_format_t * ft, const sox_sample_t * buf,
                                 sox_size_t len)
 {
   snd_t p = (snd_t) ft->priv;
@@ -151,7 +148,7 @@
   return sox_rawwrite(ft, buf, len);
 }
 
-static int sox_sndtstopwrite(sox_format_t * ft)
+static int stopwrite(sox_format_t * ft)
 {
   snd_t p = (snd_t) ft->priv;
 
@@ -161,34 +158,19 @@
                    "can't rewind output file to rewrite SND header");
     return SOX_EOF;
   }
-
   sndtwriteheader(ft, p->nsamples);
-
-
   return (SOX_SUCCESS);
 }
 
-/* Sndtool Sound File */
-static const char *sndtnames[] = {
-  "sndt",
-  NULL
-};
-
-static const sox_format_handler_t sox_snd_format = {
-  sndtnames,
-  SOX_FILE_LIT_END,
-  sox_sndtstartread,
-  sox_rawread,
-  sox_rawstopread,
-  sox_sndtstartwrite,
-  sox_sndtwrite,
-  sox_sndtstopwrite,
-  sox_sndseek
-};
-
-const sox_format_handler_t *sox_sndrtool_format_fn(void);
-
-const sox_format_handler_t *sox_sndrtool_format_fn(void)
+SOX_FORMAT_HANDLER(sndrtool)
 {
-  return &sox_snd_format;
+  static char const * const names[] = {"sndt", NULL};
+  static unsigned const write_encodings[] = {SOX_ENCODING_UNSIGNED, 8, 0, 0};
+  static sox_format_handler_t const handler = {
+    names, SOX_FILE_LIT_END | SOX_FILE_MONO,
+    startread, sox_rawread, sox_rawstopread,
+    startwrite, write_samples, stopwrite,
+    seek, write_encodings, NULL
+  };
+  return &handler;
 }
--- a/src/sox.c
+++ b/src/sox.c
@@ -72,7 +72,6 @@
 
 static enum {sox_sequence, sox_concatenate, sox_mix, sox_merge}
     combine_method = sox_concatenate;
-static sox_bool repeatable_random = sox_false;  /* Whether to invoke srand. */
 static sox_bool interactive = sox_false;
 static sox_bool uservolume = sox_false;
 typedef enum {RG_off, RG_track, RG_album} rg_mode;
@@ -94,6 +93,7 @@
   /* fopts */
   char const * filetype;
   sox_signalinfo_t signal;
+  sox_encodinginfo_t encoding;
   double volume;
   double replay_gain;
   rg_mode replay_gain_mode;
@@ -131,7 +131,8 @@
 
 /* Flowing */
 
-static sox_signalinfo_t combiner, ofile_signal;
+static sox_signalinfo_t combiner_signal, ofile_signal;
+static sox_encodinginfo_t combiner_encoding, ofile_encoding;
 static sox_size_t mixing_clips = 0;
 static size_t current_input = 0;
 static unsigned long input_wide_samples = 0;
@@ -158,7 +159,7 @@
 
   if (file_count) {
     if (ofile->ft) {
-      if (!(ofile->ft->handler->flags & SOX_FILE_NOSTDIO)) {
+      if (!(ofile->ft->handler.flags & SOX_FILE_NOSTDIO)) {
         struct stat st;
         fstat(fileno(ofile->ft->fp), &st);
 
@@ -193,24 +194,17 @@
 
   fprintf(output, "\n%s: '%s'",
     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]);
+  if (strcmp(ft->filename, "-") == 0 || (ft->handler.flags & SOX_FILE_DEVICE))
+    fprintf(output, " (%s)", ft->handler.names[0]);
   fprintf(output, "\n");
 
-  if (ft->signal.size)
-    fprintf(output, "Sample Size    : %s (%s)\n",
-        sox_size_bits_str[ft->signal.size],
-        sox_sizes_str[ft->signal.size]);
-
-  if (ft->signal.encoding)
-    fprintf(output, "Sample Encoding: %s\n",
-        sox_encodings_str[ft->signal.encoding]);
-
   fprintf(output,
     "Channels       : %u\n"
-    "Sample Rate    : %g\n",
+    "Sample Rate    : %g\n"
+    "Precision      : %u-bit\n",
     ft->signal.channels,
-    ft->signal.rate);
+    ft->signal.rate,
+    ft->signal.precision);
 
   if (ft->length && ft->signal.channels && ft->signal.rate) {
     sox_size_t ws = ft->length / ft->signal.channels;
@@ -220,16 +214,25 @@
       ws, "~="[ft->signal.rate == 44100],
       (double)ws/ ft->signal.rate * 44100 / 588);
   }
+  if (ft->encoding.encoding) {
+    char buffer[20] = {'\0'};
+    if (ft->encoding.bits_per_sample)
+      sprintf(buffer, "%u-bit ", ft->encoding.bits_per_sample);
+
+    fprintf(output, "Sample Encoding: %s%s\n", buffer,
+        sox_encodings_str[ft->encoding.encoding]);
+  }
+
   if (full) {
-    if (ft->signal.size > 1)
+    if (ft->encoding.bits_per_sample > 8)
       fprintf(output, "Endian Type    : %s\n",
-          ft->signal.reverse_bytes != SOX_IS_BIGENDIAN ? "big" : "little");
-    if (ft->signal.size)
+          ft->encoding.reverse_bytes != SOX_IS_BIGENDIAN ? "big" : "little");
+    if (ft->encoding.bits_per_sample)
       fprintf(output,
         "Reverse Nibbles: %s\n"
         "Reverse Bits   : %s\n",
-        no_yes[ft->signal.reverse_nibbles],
-        no_yes[ft->signal.reverse_bits]);
+        no_yes[ft->encoding.reverse_nibbles],
+        no_yes[ft->encoding.reverse_bits]);
   }
 
   if (f && f->replay_gain != HUGE_VAL)
@@ -238,7 +241,7 @@
   if (f && f->volume != HUGE_VAL)
     fprintf(output, "Level adjust   : %g (linear gain)\n" , f->volume);
 
-  if (!(ft->handler->flags & SOX_FILE_DEVICE) && 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");
@@ -293,7 +296,7 @@
 
 static sox_size_t sox_read_wide(sox_format_t * ft, sox_sample_t * buf, sox_size_t max)
 {
-  sox_size_t len = max / combiner.channels;
+  sox_size_t len = max / combiner_signal.channels;
   len = sox_read(ft, buf, len * ft->signal.channels) / ft->signal.channels;
   if (!len && ft->sox_errno)
     display_error(ft);
@@ -374,7 +377,7 @@
     }
     for (ws = 0; ws < olen; ++ws) /* wide samples */
       if (combine_method == sox_mix) {          /* sum samples together */
-        for (s = 0; s < effp->ininfo.channels; ++s, ++p) {
+        for (s = 0; s < effp->in_signal.channels; ++s, ++p) {
           *p = 0;
           for (i = 0; i < input_count; ++i)
             if (ws < ilen[i] && s < files[i]->ft->signal.channels) {
@@ -390,7 +393,7 @@
     }
   }
   read_wide_samples += olen;
-  olen *= effp->ininfo.channels;
+  olen *= effp->in_signal.channels;
   *osamp = olen;
   return olen? SOX_SUCCESS : SOX_EOF;
 }
@@ -422,10 +425,10 @@
 {
   size_t len;
 
-  if (show_progress) for (len = 0; len < *isamp; len += effp->ininfo.channels) {
+  if (show_progress) for (len = 0; len < *isamp; len += effp->in_signal.channels) {
     omax[0] = max(omax[0], ibuf[len]);
     omin[0] = min(omin[0], ibuf[len]);
-    if (effp->ininfo.channels > 1) {
+    if (effp->in_signal.channels > 1) {
       omax[1] = max(omax[1], ibuf[len + 1]);
       omin[1] = min(omin[1], ibuf[len + 1]);
     }
@@ -471,7 +474,7 @@
 /* If needed effects are not given, auto-add at (performance) optimal point. */
 static void add_effects(sox_effects_chain_t * chain)
 {
-  sox_signalinfo_t signal = combiner;
+  sox_signalinfo_t signal = combiner_signal;
   unsigned i, min_chan = 0, min_rate = 0;
   sox_effect_t eff;
 
@@ -482,7 +485,7 @@
     if (user_efftab[i].handler.flags & SOX_EFF_RATE)
       min_rate = i + 1;
   }
-  /* 1st `effect' in the chain is the input combiner */
+  /* 1st `effect' in the chain is the input combiner_signal */
   sox_create_effect(&eff, input_combiner_effect_fn());
   sox_add_effect(chain, &eff, &signal, &ofile->ft->signal);
 
@@ -515,7 +518,7 @@
   for (i = 0; i < chain->length; ++i) {
     sox_effect_t const * effp = &chain->effects[i][0];
     sox_report("effects chain: %-10s %gHz %u channels %u bits %s",
-        effp->handler.name, effp->ininfo.rate, effp->ininfo.channels, effp->ininfo.size * 8,
+        effp->handler.name, effp->in_signal.rate, effp->in_signal.channels, effp->in_signal.precision,
         (effp->handler.flags & SOX_EFF_MCHAN)? "(multi)" : "");
   }
 }
@@ -617,11 +620,11 @@
   if (!show_progress)
     return;
   if (all_done || since(&then, .1, sox_false)) {
-    double read_time = (double)read_wide_samples / combiner.rate;
+    double read_time = (double)read_wide_samples / combiner_signal.rate;
     double left_time = 0, in_time = 0, percentage = 0;
 
     if (input_wide_samples) {
-      in_time = (double)input_wide_samples / combiner.rate;
+      in_time = (double)input_wide_samples / combiner_signal.rate;
       left_time = max(in_time - read_time, 0);
       percentage = max(100. * read_wide_samples / input_wide_samples, 0);
     }
@@ -653,7 +656,7 @@
    * gigs of audio data into managable chunks
    */ 
   if (input_count == 1 && ofile_effects_chain.length > 1 && strcmp(ofile_effects_chain.effects[1][0].handler.name, "trim") == 0) {
-    if (files[0]->ft->handler->seek && files[0]->ft->seekable){
+    if (files[0]->ft->handler.seek && files[0]->ft->seekable){
       sox_size_t offset = sox_trim_get_start(&ofile_effects_chain.effects[1][0]);
       if (offset && sox_seek(files[0]->ft, offset, SOX_SEEK_SET) == SOX_SUCCESS) { 
         read_wide_samples = offset / files[0]->ft->signal.channels;
@@ -662,6 +665,7 @@
          * trim so that it thinks user didn't request a skip.
          */ 
         sox_trim_clear_start(&ofile_effects_chain.effects[1][0]);
+        sox_debug("optimize_trim successful");
       }    
     }        
   }    
@@ -708,7 +712,7 @@
    * FIXME: This doesn't work for multi-file processing or
    * effects that change file length.
    */
-  factor = (double) ofile->signal.rate / combiner.rate;
+  factor = (double) ofile->signal.rate / combiner_signal.rate;
   for (i = 0; i < SOX_MAX_NLOOPS; i++) {
     loops[i].start = files[0]->ft->loops[i].start * factor;
     loops[i].length = files[0]->ft->loops[i].length * factor;
@@ -719,6 +723,7 @@
   ofile->ft = sox_open_write(overwrite_permitted,
                         ofile->filename,
                         &ofile->signal,
+                        &ofile->encoding,
                         ofile->filetype,
                         comments,
                         olen,
@@ -735,8 +740,8 @@
    * progress display to match behavior of ogg123,
    * unless the user requested us not to display anything. */
   if (show_progress == SOX_OPTION_DEFAULT)
-    show_progress = (ofile->ft->handler->flags & SOX_FILE_DEVICE) != 0 &&
-                    (ofile->ft->handler->flags & SOX_FILE_PHONY) == 0;
+    show_progress = (ofile->ft->handler.flags & SOX_FILE_DEVICE) != 0 &&
+                    (ofile->ft->handler.flags & SOX_FILE_PHONY) == 0;
 
   report_file_info(ofile);
 }
@@ -760,7 +765,8 @@
   sox_bool known_length = combine_method != sox_sequence;
   sox_size_t olen = 0;
 
-  combiner = files[current_input]->ft->signal;
+  combiner_signal = files[current_input]->ft->signal;
+  combiner_encoding = files[current_input]->ft->encoding;
   if (combine_method == sox_sequence) {
     if (!current_input) for (i = 0; i < input_count; i++)
       report_file_info(files[i]);
@@ -796,27 +802,34 @@
     if (min_rate != max_rate)
       exit(1);
 
-    combiner.channels = 
+    combiner_signal.channels = 
       combine_method == sox_merge? total_channels : max_channels;
   }
 
   ofile->signal = ofile_signal;
   if (ofile->signal.rate == 0)
-    ofile->signal.rate = combiner.rate;
-  if (ofile->signal.size == 0)
-    ofile->signal.size = combiner.size;
-  if (ofile->signal.encoding == SOX_ENCODING_UNKNOWN)
-    ofile->signal.encoding = combiner.encoding;
+    ofile->signal.rate = combiner_signal.rate;
   if (ofile->signal.channels == 0) {
     unsigned j;
     for (j = 0; j < nuser_effects && !ofile->signal.channels; ++j)
-      ofile->signal.channels = user_efftab[nuser_effects - 1 - j].outinfo.channels;
+      ofile->signal.channels = user_efftab[nuser_effects - 1 - j].out_signal.channels;
     if (ofile->signal.channels == 0)
-      ofile->signal.channels = combiner.channels;
+      ofile->signal.channels = combiner_signal.channels;
   }
+  ofile->signal.precision = combiner_signal.precision;
 
-  combiner.rate *= sox_effects_globals.speed;
+  combiner_signal.rate *= sox_effects_globals.speed;
 
+  ofile->encoding = ofile_encoding; {
+    sox_encodinginfo_t t = ofile->encoding;
+    if (!t.encoding)
+      t.encoding = combiner_encoding.encoding;
+    if (!t.bits_per_sample)
+      t.bits_per_sample = combiner_encoding.bits_per_sample;
+    if (sox_format_supports_encoding(ofile->filename, ofile->filetype, &t))
+      ofile->encoding = t;
+  }
+
   for (i = 0; i < nuser_effects; i++)
     known_length = known_length && !(user_efftab[i].handler.flags & SOX_EFF_LENGTH);
 
@@ -823,9 +836,11 @@
   if (!known_length)
     olen = 0;
 
-  open_output_file((sox_size_t)(olen * ofile->signal.channels * ofile->signal.rate / combiner.rate + .5));
+  open_output_file((sox_size_t)(olen * ofile->signal.channels * ofile->signal.rate / combiner_signal.rate + .5));
 
   ofile_effects_chain.global_info = sox_effects_globals;
+  ofile_effects_chain.in_enc = &combiner_encoding;
+  ofile_effects_chain.out_enc = &ofile->ft->encoding;
   add_effects(&ofile_effects_chain);
 
   optimize_trim();
@@ -1028,7 +1043,7 @@
   free(text);
 }
 
-static char *getoptstr = "+ac:fghimnoqr:st:uv:xABC:DLMNRSUV::X12348";
+static char *getoptstr = "+ac:fghimnoqr:st:uv:xABC:LMNRSUV::X12348";
 
 static struct option long_options[] =
   {
@@ -1141,9 +1156,9 @@
 
       case 5:
         switch (enum_option(option_index, endian_options)) {
-          case ENDIAN_little: f->signal.reverse_bytes = SOX_IS_BIGENDIAN; break;
-          case ENDIAN_big: f->signal.reverse_bytes = SOX_IS_LITTLEENDIAN; break;
-          case ENDIAN_swap: f->signal.reverse_bytes = sox_true; break;
+          case ENDIAN_little: f->encoding.reverse_bytes = SOX_IS_BIGENDIAN; break;
+          case ENDIAN_big: f->encoding.reverse_bytes = SOX_IS_LITTLEENDIAN; break;
+          case ENDIAN_swap: f->encoding.reverse_bytes = sox_true; break;
         }
         break;
 
@@ -1179,7 +1194,7 @@
       break;
 
     case 'R':                   /* Useful for regression testing. */
-      repeatable_random = sox_true;
+      sox_globals.repeatable = sox_true;
       break;
 
     case 'n':
@@ -1223,42 +1238,41 @@
       break;
 
     case 'C':
-      if (sscanf(optarg, "%lf %c", &f->signal.compression, &dummy) != 1) {
+      if (sscanf(optarg, "%lf %c", &f->encoding.compression, &dummy) != 1) {
         sox_fail("Compression value `%s' is not a number", optarg);
         exit(1);
       }
       break;
 
-    case '1': f->signal.size = SOX_SIZE_BYTE;  break;
-    case '2': f->signal.size = SOX_SIZE_16BIT; break;
-    case '3': f->signal.size = SOX_SIZE_24BIT; break;
-    case '4': f->signal.size = SOX_SIZE_32BIT; break;
-    case '8': f->signal.size = SOX_SIZE_64BIT; break;
+    case '1': f->encoding.bits_per_sample = 8;  break;
+    case '2': f->encoding.bits_per_sample = 16; break;
+    case '3': f->encoding.bits_per_sample = 24; break;
+    case '4': f->encoding.bits_per_sample = 32; break;
+    case '8': f->encoding.bits_per_sample = 64; break;
 
-    case 's': f->signal.encoding = SOX_ENCODING_SIGN2;     break;
-    case 'u': f->signal.encoding = SOX_ENCODING_UNSIGNED;  break;
-    case 'f': f->signal.encoding = SOX_ENCODING_FLOAT;     break;
-    case 'a': f->signal.encoding = SOX_ENCODING_ADPCM;     break;
-    case 'D': f->signal.encoding = SOX_ENCODING_MS_ADPCM;  break;
-    case 'i': f->signal.encoding = SOX_ENCODING_IMA_ADPCM; break;
-    case 'o': f->signal.encoding = SOX_ENCODING_OKI_ADPCM; break;
-    case 'g': f->signal.encoding = SOX_ENCODING_GSM;       break;
+    case 's': f->encoding.encoding = SOX_ENCODING_SIGN2;     break;
+    case 'u': f->encoding.encoding = SOX_ENCODING_UNSIGNED;  break;
+    case 'f': f->encoding.encoding = SOX_ENCODING_FLOAT;     break;
+    case 'a': f->encoding.encoding = SOX_ENCODING_MS_ADPCM;  break;
+    case 'i': f->encoding.encoding = SOX_ENCODING_IMA_ADPCM; break;
+    case 'o': f->encoding.encoding = SOX_ENCODING_OKI_ADPCM; break;
+    case 'g': f->encoding.encoding = SOX_ENCODING_GSM;       break;
 
-    case 'U': f->signal.encoding = SOX_ENCODING_ULAW;
-      if (f->signal.size == 0)
-        f->signal.size = SOX_SIZE_BYTE;
+    case 'U': f->encoding.encoding = SOX_ENCODING_ULAW;
+      if (f->encoding.bits_per_sample == 0)
+        f->encoding.bits_per_sample = 8;
       break;
 
-    case 'A': f->signal.encoding = SOX_ENCODING_ALAW;
-      if (f->signal.size == 0)
-        f->signal.size = SOX_SIZE_BYTE;
+    case 'A': f->encoding.encoding = SOX_ENCODING_ALAW;
+      if (f->encoding.bits_per_sample == 0)
+        f->encoding.bits_per_sample = 8;
       break;
 
-    case 'L': f->signal.reverse_bytes   = SOX_IS_BIGENDIAN;    break;
-    case 'B': f->signal.reverse_bytes   = SOX_IS_LITTLEENDIAN; break;
-    case 'x': f->signal.reverse_bytes   = SOX_OPTION_YES;      break;
-    case 'X': f->signal.reverse_bits    = SOX_OPTION_YES;      break;
-    case 'N': f->signal.reverse_nibbles = SOX_OPTION_YES;      break;
+    case 'L': f->encoding.reverse_bytes   = SOX_IS_BIGENDIAN;    break;
+    case 'B': f->encoding.reverse_bytes   = SOX_IS_LITTLEENDIAN; break;
+    case 'x': f->encoding.reverse_bytes   = SOX_OPTION_YES;      break;
+    case 'X': f->encoding.reverse_bits    = SOX_OPTION_YES;      break;
+    case 'N': f->encoding.reverse_nibbles = SOX_OPTION_YES;      break;
 
     case 'S': show_progress = SOX_OPTION_YES; break;
     case 'q': show_progress = SOX_OPTION_NO;  break;
@@ -1327,10 +1341,7 @@
 static void init_file(file_t f)
 {
   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;
-  f->signal.compression = HUGE_VAL;
+  sox_init_encodinginfo(&f->encoding);
   f->volume = HUGE_VAL;
   f->replay_gain = HUGE_VAL;
 }
@@ -1394,7 +1405,7 @@
 static int soxi1(soxi_t * type, char * filename)
 {
   sox_size_t ws;
-  sox_format_t * ft = sox_open_read(filename, NULL, NULL);
+  sox_format_t * ft = sox_open_read(filename, NULL, NULL, NULL);
 
   if (!ft)
     return 1;
@@ -1404,8 +1415,8 @@
     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 bits: printf("%u\n", ft->encoding.bits_per_sample); break;
+    case encoding: printf("%s\n", sox_encodings_str[ft->encoding.encoding]); break;
     case annotation: if (ft->comments) {
       comments_t p = ft->comments;
       do printf("%s\n", *p); while (*++p);
@@ -1504,7 +1515,7 @@
 
   /* Check for misplaced input/output-specific options */
   for (i = 0; i < input_count; ++i) {
-    if (files[i]->signal.compression != HUGE_VAL)
+    if (files[i]->encoding.compression != HUGE_VAL)
       usage("A compression factor can be given only for an output file");
     if (files[i]->comments != NULL)
       usage("Comments can be given only for an output file");
@@ -1529,14 +1540,14 @@
         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);
+    files[j]->ft = sox_open_read(f->filename, &f->signal, &f->encoding, f->filetype);
     if (!files[j]->ft)
       /* sox_open_read() will call sox_warn for most errors.
        * Rely on that printing something. */
       exit(2);
     if (show_progress == SOX_OPTION_DEFAULT &&
-        (files[j]->ft->handler->flags & SOX_FILE_DEVICE) != 0 &&
-        (files[j]->ft->handler->flags & SOX_FILE_PHONY) == 0)
+        (files[j]->ft->handler.flags & SOX_FILE_DEVICE) != 0 &&
+        (files[j]->ft->handler.flags & SOX_FILE_PHONY) == 0)
       show_progress = SOX_OPTION_YES;
   }
   /* Simple heuristic to determine if replay-gain should be in album mode */
@@ -1567,12 +1578,12 @@
   for (i = 0; i < input_count; i++) {
     unsigned j;
     for (j =0; j < nuser_effects && !files[i]->ft->signal.channels; ++j)
-      files[i]->ft->signal.channels = user_efftab[j].ininfo.channels;
+      files[i]->ft->signal.channels = user_efftab[j].in_signal.channels;
     if (!files[i]->ft->signal.channels)
       ++files[i]->ft->signal.channels;
   }
 
-  if (repeatable_random)
+  if (sox_globals.repeatable)
     sox_debug("Not reseeding PRNG; randomness is repeatable");
   else {
     time_t t;
@@ -1582,6 +1593,7 @@
   }
 
   ofile_signal = ofile->signal;
+  ofile_encoding = ofile->encoding;
   if (combine_method == sox_sequence) do {
     if (ofile->ft)
       sox_close(ofile->ft);
@@ -1592,8 +1604,8 @@
     if (files[i]->ft->clips != 0)
       sox_warn(i < input_count?"%s: input clipped %u samples" :
                               "%s: output clipped %u samples; decrease volume?",
-          (files[i]->ft->handler->flags & SOX_FILE_DEVICE)?
-                       files[i]->ft->handler->names[0] : files[i]->ft->filename,
+          (files[i]->ft->handler.flags & SOX_FILE_DEVICE)?
+                       files[i]->ft->handler.names[0] : files[i]->ft->filename,
           files[i]->ft->clips);
 
   if (mixing_clips > 0)
--- a/src/sox.h
+++ b/src/sox.h
@@ -68,6 +68,7 @@
 typedef int32_t sox_sample_t;
 
 /* Minimum and maximum values a sample can hold. */
+#define SOX_SAMPLE_PRECISION 32
 #define SOX_SAMPLE_MAX (sox_sample_t)SOX_INT_MAX(32)
 #define SOX_SAMPLE_MIN (sox_sample_t)SOX_INT_MIN(32)
 
@@ -173,26 +174,30 @@
 
 typedef enum {
   SOX_ENCODING_UNKNOWN   ,
+  
+  SOX_ENCODING_SIGN2     , /* signed linear 2's comp: Mac */
+  SOX_ENCODING_UNSIGNED  , /* unsigned linear: Sound Blaster */
+  SOX_ENCODING_FLOAT     , /* floating point (binary format) */
+  SOX_ENCODING_FLOAT_TEXT, /* floating point (text format) */
+  SOX_ENCODING_FLAC      , /* FLAC compression */
+  SOX_ENCODING_HCOM      , /*  */
 
+  SOX_ENCODING_LOSSLESS  , /* Lossless above, lossy below */
+
   SOX_ENCODING_ULAW      , /* u-law signed logs: US telephony, SPARC */
   SOX_ENCODING_ALAW      , /* A-law signed logs: non-US telephony */
-  SOX_ENCODING_ADPCM     , /* G72x Compressed PCM */
+  SOX_ENCODING_G721      , /* G.721 4-bit ADPCM */
+  SOX_ENCODING_G723      , /* G.723 3 or 5 bit ADPCM */
   SOX_ENCODING_MS_ADPCM  , /* Microsoft Compressed PCM */
   SOX_ENCODING_IMA_ADPCM , /* IMA Compressed PCM */
   SOX_ENCODING_OKI_ADPCM , /* Dialogic/OKI Compressed PCM */
-
-  SOX_ENCODING_SIZE_IS_WORD, /* FIXME: marks raw types (above) that mis-report size. sox_signalinfo_t really needs a precision_in_bits item */
-
-  SOX_ENCODING_UNSIGNED  , /* unsigned linear: Sound Blaster */
-  SOX_ENCODING_SIGN2     , /* signed linear 2's comp: Mac */
-  SOX_ENCODING_FLOAT     , /* 32-bit float */
   SOX_ENCODING_GSM       , /* GSM 6.10 33byte frame lossy compression */
   SOX_ENCODING_MP3       , /* MP3 compression */
   SOX_ENCODING_VORBIS    , /* Vorbis compression */
-  SOX_ENCODING_FLAC      , /* FLAC compression */
   SOX_ENCODING_AMR_WB    , /* AMR-WB compression */
   SOX_ENCODING_AMR_NB    , /* AMR-NB compression */
-
+  SOX_ENCODING_CVSD      , /*  */
+  SOX_ENCODING_LPC10     , /*  */
   SOX_ENCODINGS            /* End of list marker */
 } sox_encoding_t;
 
@@ -199,38 +204,41 @@
 typedef enum {sox_plot_off, sox_plot_octave, sox_plot_gnuplot} sox_plot_t;
 typedef enum {SOX_OPTION_NO, SOX_OPTION_YES, SOX_OPTION_DEFAULT} sox_option_t;
 
-/* Signal parameters */
 
-typedef struct sox_signalinfo
-{
-    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 */
-    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
-     * them up (could be done in libSoX, or by the libSoX client) and
-     * using them (in libSoX).  libSoX's logic to set them up includes
-     * knowledge of the machine default and the format default.  (The
-     * sox client logic adds to this a layer of overridability via user
-     * options.)  The physical delineation is in the somewhat
-     * snappily-named libSoX function `set_endianness_if_not_already_set'
-     * which is called at the right times (as files are openned) by the
-     * libSoX core, not by the file handlers themselves.  The file handlers
-     * indicate to the libSoX core if they have a preference using
-     * SOX_FILE_xxx flags.
-     */
-    sox_option_t reverse_bytes;    /* endiannesses... */
-    sox_option_t reverse_nibbles;
-    sox_option_t reverse_bits;
+typedef struct { /* Signal parameters; 0 if unknown */
+  sox_rate_t rate;         /* sampling rate */
+  unsigned channels;       /* number of sound channels */
+  unsigned precision;      /* in bits */
 } sox_signalinfo_t;
 
+
+typedef struct { /* Encoding parameters */
+  sox_encoding_t encoding; /* format of sample numbers */
+  unsigned bits_per_sample;  /* 0 if unknown or variable; uncompressed value if lossless; compressed value if lossy */
+  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
+   * them up (could be done in libSoX, or by the libSoX client) and
+   * using them (in libSoX).  libSoX's logic to set them up includes
+   * knowledge of the machine default and the format default.  (The
+   * sox client logic adds to this a layer of overridability via user
+   * options.)  The physical delineation is in the somewhat
+   * snappily-named libSoX function `set_endianness_if_not_already_set'
+   * which is called at the right times (as files are openned) by the
+   * libSoX core, not by the file handlers themselves.  The file handlers
+   * indicate to the libSoX core if they have a preference using
+   * SOX_FILE_xxx flags.
+   */
+  sox_option_t reverse_bytes;    /* endiannesses... */
+  sox_option_t reverse_nibbles;
+  sox_option_t reverse_bits;
+} sox_encodinginfo_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_PRECISION      16
 #define SOX_DEFAULT_ENCODING  SOX_ENCODING_SIGN2
 
 /* Loop parameters */
@@ -290,6 +298,8 @@
     sox_size_t   (*write)(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len);
     int          (*stopwrite)(sox_format_t * ft);
     int          (*seek)(sox_format_t * ft, sox_size_t offset);
+    unsigned     const * write_formats;
+    sox_rate_t   const * write_rates;
 } sox_format_handler_t;
 
 /*
@@ -307,11 +317,13 @@
   char   priv[SOX_MAX_FILE_PRIVSIZE];    /* format's private data area */
 
   sox_signalinfo_t signal;               /* signal specifications */
+  sox_encodinginfo_t encoding;               /* encoding specifications */
   sox_instrinfo_t  instr;                /* instrument specification */
   sox_loopinfo_t   loops[SOX_MAX_NLOOPS];/* Looping specification */
   sox_bool         seekable;             /* can seek on this file */
   char             mode;                 /* read or write mode */
-  sox_size_t       length;               /* frames in file, or 0 if unknown. */
+  sox_size_t       length;        /* samples * channels in file; 0 if unknown */
+  sox_size_t       olength;       /* samples * channels in file; 0 if unknown */
   sox_size_t       clips;                /* increment if clipping occurs */
   char             *filename;            /* file name */
   char             *filetype;            /* type of file */
@@ -319,7 +331,8 @@
   FILE             *fp;                  /* File stream pointer */
   int              sox_errno;            /* Failure error codes */
   char             sox_errstr[256];      /* Extend Failure text */
-  const sox_format_handler_t * handler;  /* format struct for this file */
+  off_t            data_start;
+  sox_format_handler_t handler;  /* format struct for this file */
 };
 
 /* file flags field */
@@ -334,35 +347,37 @@
 /* These two for use by libSoX handlers: */
 #define SOX_FILE_LIT_END  (0   + 64)
 #define SOX_FILE_BIG_END  (128 + 64)
-#define SOX_FILE_BIT_REV 256
-#define SOX_FILE_NIB_REV 512
+#define SOX_FILE_BIT_REV 0x0100
+#define SOX_FILE_NIB_REV 0x0200
+#define SOX_FILE_CHANS   0x1C00
+#define SOX_FILE_MONO    0x0400
+#define SOX_FILE_STEREO  0x0800
+#define SOX_FILE_QUAD    0x1000
+#define SOX_FILE_REWIND  0x2000
 
-/* Size field */
-#define SOX_SIZE_BYTE    1
-#define SOX_SIZE_8BIT    1
-#define SOX_SIZE_16BIT   2
-#define SOX_SIZE_24BIT   3
-#define SOX_SIZE_32BIT   4
-#define SOX_SIZE_64BIT   8
-#define SOX_INFO_SIZE_MAX     8
-
 /* declared in misc.c */
-extern const char * const sox_sizes_str[];
-extern const char * const sox_size_bits_str[];
 extern const char * const sox_encodings_str[];
 
 int sox_format_init(void);
-sox_format_t * sox_open_read(const char *path, const sox_signalinfo_t *info, 
-                         const char *filetype);
+sox_format_t * sox_open_read(
+    char               const * path,
+    sox_signalinfo_t   const * signal,
+    sox_encodinginfo_t const * encoding,
+    char               const * filetype);
+sox_bool sox_format_supports_encoding(
+    char               const * path,
+    char               const * filetype,
+    sox_encodinginfo_t const * encoding);
 sox_format_t * sox_open_write(
     sox_bool (*overwrite_permitted)(const char *filename),
-    const char *path,
-    const sox_signalinfo_t *info,
-    const char *filetype,
-    comments_t comments,
-    sox_size_t length,
-    const sox_instrinfo_t *instr,
-    const sox_loopinfo_t *loops);
+    char               const * path,
+    sox_signalinfo_t   const * signal,
+    sox_encodinginfo_t const * encoding,
+    char               const * filetype,
+    comments_t                 comments,
+    sox_size_t                 length,
+    sox_instrinfo_t    const * instr,
+    sox_loopinfo_t     const * loops);
 sox_size_t sox_read(sox_format_t * ft, sox_sample_t *buf, sox_size_t len);
 sox_size_t sox_write(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len);
 int sox_close(sox_format_t * ft);
@@ -410,16 +425,18 @@
    * in memory in the optimal way for any structure to be cast over it. */
   char priv[SOX_MAX_EFFECT_PRIVSIZE];    /* private area for effect */
 
-  sox_effects_globals_t    *global_info; /* global parameters */
-  struct sox_signalinfo    ininfo;       /* input signal specifications */
-  struct sox_signalinfo    outinfo;      /* output signal specifications */
+  sox_effects_globals_t    * global_info; /* global parameters */
+  sox_signalinfo_t         in_signal;
+  sox_signalinfo_t         out_signal;
+  sox_encodinginfo_t       const * in_encoding;
+  sox_encodinginfo_t       const * out_encoding;
   sox_effect_handler_t     handler;
-  sox_sample_t            *obuf;        /* output buffer */
-  sox_size_t               obeg, oend;   /* consumed, total length */
-  sox_size_t               imin;         /* minimum input buffer size */
-  sox_size_t               clips;        /* increment if clipping occurs */
-  sox_size_t               flows;        /* 1 if MCHAN, # chans otherwise */
-  sox_size_t               flow;         /* flow # */
+  sox_sample_t             * obuf;        /* output buffer */
+  sox_size_t               obeg, oend;    /* consumed, total length */
+  sox_size_t               imin;          /* minimum input buffer size */
+  sox_size_t               clips;         /* increment if clipping occurs */
+  sox_size_t               flows;         /* 1 if MCHAN, # chans otherwise */
+  sox_size_t               flow;          /* flow # */
 };
 
 sox_effect_handler_t const *sox_find_effect(char const * name);
@@ -431,9 +448,10 @@
 
 struct sox_effects_chain;
 typedef struct sox_effects_chain sox_effects_chain_t;
-sox_effects_chain_t * sox_create_effects_chain(void);
-
-int sox_add_effect(sox_effects_chain_t *, sox_effect_t * effp, sox_signalinfo_t * in, sox_signalinfo_t const * out);
+sox_effects_chain_t * sox_create_effects_chain(
+    sox_encodinginfo_t const * in_enc,
+    sox_encodinginfo_t const * out_enc);
+int sox_add_effect( sox_effects_chain_t * chain, sox_effect_t * effp, sox_signalinfo_t * in, sox_signalinfo_t const * out);
 int sox_flow_effects(sox_effects_chain_t *, int (* callback)(sox_bool all_done));
 sox_size_t sox_effects_clips(sox_effects_chain_t *);
 sox_size_t sox_stop_effect(sox_effects_chain_t *, sox_size_t e);
--- a/src/sox_i.h
+++ b/src/sox_i.h
@@ -104,6 +104,7 @@
 #define ftello ftell
 #define off_t long
 #endif
+assert_static(sizeof(off_t) == _FILE_OFFSET_BITS >> 3, OFF_T_BUILD_PROBLEM);
 
 /* Digitise one cycle of a wave and store it as
  * a table of samples of a specified data-type.
@@ -176,7 +177,8 @@
 int sox_writef(sox_format_t * ft, float f);
 #define sox_readdf(ft, d) (sox_read_df_buf(ft, d, 1) == 1 ? SOX_SUCCESS : SOX_EOF)
 int sox_writedf(sox_format_t * ft, double d);
-int sox_seeki(sox_format_t * ft, sox_ssize_t offset, int whence);
+int sox_seeki(sox_format_t * ft, sox_ssize_t to_sample, int whence);
+int sox_offset_seek(sox_format_t * ft, off_t byte_offset, sox_size_t to_sample);
 sox_size_t sox_filelength(sox_format_t * ft);
 int sox_flush(sox_format_t * ft);
 sox_ssize_t sox_tell(sox_format_t * ft);
@@ -275,7 +277,7 @@
   char const * stdout_in_use_by;
   sox_output_message_handler_t output_message_handler;
   char const * subsystem;
-
+  sox_bool     repeatable;
 } sox_globals_t;
 
 struct sox_effects_globals /* Global parameters (for effects) */
@@ -302,6 +304,17 @@
 
 /*------------------------------ File Handlers -------------------------------*/
 
+void sox_init_encodinginfo(sox_encodinginfo_t * e);
+unsigned sox_precision(sox_encoding_t encoding, unsigned pcm_size);
+int sox_check_read_params(sox_format_t * ft, unsigned channels,
+    sox_rate_t rate, sox_encoding_t encoding, unsigned bits_per_sample,
+    off_t num_samples);
+sox_sample_t sox_sample_max(sox_encodinginfo_t const * encoding);
+#define SOX_FORMAT_HANDLER(name) \
+sox_format_handler_t const * sox_##name##_format_fn(void); \
+sox_format_handler_t const * sox_##name##_format_fn(void)
+#define div_bits(size, bits) (off_t)((double)(size) * 8 / bits)
+
 /* Psion record header check, defined in misc.c and used in prc.c and auto.c */
 extern const char prc_header[41];
 int prc_checkheader(sox_format_t * ft, char *head);
@@ -323,8 +336,8 @@
 int sox_rawstartwrite(sox_format_t * ft);
 sox_size_t sox_rawwrite(sox_format_t * ft, const sox_sample_t *buf, sox_size_t nsamp);
 int sox_rawseek(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, unsigned size);
-#define sox_rawstartread(ft) sox_rawstart(ft, sox_false, sox_false, SOX_ENCODING_UNKNOWN, 0)
+int sox_rawstart(sox_format_t * ft, sox_bool default_rate, sox_bool default_channels, sox_bool default_length, sox_encoding_t encoding, unsigned size);
+#define sox_rawstartread(ft) sox_rawstart(ft, sox_false, sox_false, sox_false, SOX_ENCODING_UNKNOWN, 0)
 #define sox_rawstartwrite sox_rawstartread
 #define sox_rawstopread NULL
 #define sox_rawstopwrite NULL
@@ -371,6 +384,8 @@
   unsigned length;
   sox_sample_t **ibufc, **obufc; /* Channel interleave buffers */
   sox_effects_globals_t global_info;
+  sox_encodinginfo_t const * in_enc;
+  sox_encodinginfo_t const * out_enc;
 };
 
 #endif
--- a/src/soxconfig.h.cmake
+++ b/src/soxconfig.h.cmake
@@ -36,3 +36,4 @@
 #cmakedefine HAVE_UNISTD_H            1
 #cmakedefine HAVE_VSNPRINTF           1
 #cmakedefine WORDS_BIGENDIAN          1
+#define _FILE_OFFSET_BITS 32
--- a/src/soxio.c
+++ b/src/soxio.c
@@ -1,5 +1,6 @@
 #include "sox_i.h"
 
+#include <assert.h>
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -19,7 +20,7 @@
 
 static void output_message(unsigned level, const char *filename, const char *fmt, va_list ap);
 
-sox_globals_t sox_globals = {2, 8192, NULL, NULL, output_message, NULL};
+sox_globals_t sox_globals = {2, 8192, NULL, NULL, output_message, NULL, sox_false};
 
 static void output_message(unsigned level, const char *filename, const char *fmt, va_list ap)
 {
@@ -87,20 +88,23 @@
  */
 int sox_gettype(sox_format_t * ft, sox_bool is_file_extension)
 {
+  sox_format_handler_t const * handler;
+
   if (!ft->filetype) {
     sox_fail_errno(ft, SOX_EFMT, "unknown file type");
     return SOX_EFMT;
   }
-  ft->handler = sox_find_format(ft->filetype, is_file_extension);
-  if (!ft->handler) {
+  handler = sox_find_format(ft->filetype, is_file_extension);
+  if (!handler) {
     sox_fail_errno(ft, SOX_EFMT, "unknown file type `%s'", ft->filetype);
     return SOX_EFMT;
   }
-  if (ft->mode == 'r' && !ft->handler->startread && !ft->handler->read) {
+  ft->handler = *handler;
+  if (ft->mode == 'r' && !ft->handler.startread && !ft->handler.read) {
     sox_fail_errno(ft, SOX_EFMT, "file type `%s' isn't readable", ft->filetype);
     return SOX_EFMT;
   }
-  if (ft->mode == 'w' && !ft->handler->startwrite && !ft->handler->write) {
+  if (ft->mode == 'w' && !ft->handler.startwrite && !ft->handler.write) {
     sox_fail_errno(ft, SOX_EFMT, "file type `%s' isn't writable", ft->filetype);
     return SOX_EFMT;
   }
@@ -125,34 +129,34 @@
 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->precision    ) signal->precision     = SOX_DEFAULT_PRECISION;
   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) {
-    if (ft->handler->flags & SOX_FILE_ENDIAN)
+  if (ft->encoding.reverse_bytes == SOX_OPTION_DEFAULT) {
+    if (ft->handler.flags & SOX_FILE_ENDIAN)
     {
         /* Set revere_bytes if we are running on opposite endian
          * machine compared to file format.
          */
-        if (ft->handler->flags & SOX_FILE_ENDBIG)
-            ft->signal.reverse_bytes = SOX_IS_LITTLEENDIAN;
+        if (ft->handler.flags & SOX_FILE_ENDBIG)
+            ft->encoding.reverse_bytes = SOX_IS_LITTLEENDIAN;
         else
-            ft->signal.reverse_bytes = SOX_IS_BIGENDIAN;
+            ft->encoding.reverse_bytes = SOX_IS_BIGENDIAN;
     }
     else
-      ft->signal.reverse_bytes = SOX_OPTION_NO;
+      ft->encoding.reverse_bytes = SOX_OPTION_NO;
   }
-  if (ft->signal.reverse_bits == SOX_OPTION_DEFAULT)
-    ft->signal.reverse_bits = !!(ft->handler->flags & SOX_FILE_BIT_REV);
-  else if (ft->signal.reverse_bits != !!(ft->handler->flags & SOX_FILE_BIT_REV))
+  if (ft->encoding.reverse_bits == SOX_OPTION_DEFAULT)
+    ft->encoding.reverse_bits = !!(ft->handler.flags & SOX_FILE_BIT_REV);
+  else if (ft->encoding.reverse_bits != !!(ft->handler.flags & SOX_FILE_BIT_REV))
       sox_report("'%s': Format options overriding file-type bit-order", ft->filename);
 
-  if (ft->signal.reverse_nibbles == SOX_OPTION_DEFAULT)
-    ft->signal.reverse_nibbles = !!(ft->handler->flags & SOX_FILE_NIB_REV);
-  else if (ft->signal.reverse_nibbles != !!(ft->handler->flags & SOX_FILE_NIB_REV))
+  if (ft->encoding.reverse_nibbles == SOX_OPTION_DEFAULT)
+    ft->encoding.reverse_nibbles = !!(ft->handler.flags & SOX_FILE_NIB_REV);
+  else if (ft->encoding.reverse_nibbles != !!(ft->handler.flags & SOX_FILE_NIB_REV))
       sox_report("'%s': Format options overriding file-type nibble-order", ft->filename);
 }
 
@@ -168,51 +172,27 @@
 /* check that all settings have been given */
 static int sox_checkformat(sox_format_t * ft)
 {
+  ft->sox_errno = SOX_SUCCESS;
 
-        ft->sox_errno = SOX_SUCCESS;
-
-        if (ft->signal.rate == 0)
-        {
-                sox_fail_errno(ft,SOX_EFMT,"sampling rate was not specified");
-                return SOX_EOF;
-        }
-
-        if (!ft->signal.size)
-        {
-                sox_fail_errno(ft,SOX_EFMT,"data size was not specified");
-                return SOX_EOF;
-        }
-
-        if (ft->signal.encoding == SOX_ENCODING_UNKNOWN)
-        {
-                sox_fail_errno(ft,SOX_EFMT,"data encoding was not specified");
-                return SOX_EOF;
-        }
-
-        if (ft->signal.size > SOX_INFO_SIZE_MAX)
-        {
-                sox_fail_errno(ft,SOX_EFMT,"data size %u is invalid", ft->signal.size);
-                return SOX_EOF;
-        }
-
-        if (ft->signal.encoding <= 0  || ft->signal.encoding >= SOX_ENCODINGS)
-        {
-                sox_fail_errno(ft,SOX_EFMT,"data encoding %d is invalid", ft->signal.encoding);
-                return SOX_EOF;
-        }
-
-        return SOX_SUCCESS;
+  if (!ft->signal.rate) {
+    sox_fail_errno(ft,SOX_EFMT,"sampling rate was not specified");
+    return SOX_EOF;
+  }
+  if (!ft->signal.precision) {
+    sox_fail_errno(ft,SOX_EFMT,"data encoding was not specified");
+    return SOX_EOF;
+  }
+  return SOX_SUCCESS;
 }
 
-sox_format_t * sox_open_read(const char *path, const sox_signalinfo_t *info,
-                  const char *filetype)
+sox_format_t * sox_open_read(
+    char               const * path,
+    sox_signalinfo_t   const * signal,
+    sox_encodinginfo_t const * encoding,
+    char               const * filetype)
 {
     sox_format_t * ft = xcalloc(sizeof(*ft), 1);
 
-    ft->signal.reverse_bytes =
-    ft->signal.reverse_nibbles =
-    ft->signal.reverse_bits = SOX_OPTION_DEFAULT;
-
     ft->filename = xstrdup(path);
 
     /* Let auto type do the work if user is not overriding. */
@@ -226,14 +206,13 @@
       sox_fail("Can't open input file `%s': %s", ft->filename, ft->sox_errstr);
       goto input_error;
     }
-    ft->signal.size = 0;
-    ft->signal.encoding = SOX_ENCODING_UNKNOWN;
-    ft->signal.channels = 0;
-    ft->signal.compression = HUGE_VAL;
-    if (info)
-        ft->signal = *info;
+    if (signal)
+      ft->signal = *signal;
+    if (encoding)
+      ft->encoding = *encoding;
+    else sox_init_encodinginfo(&ft->encoding);
 
-    if (!(ft->handler->flags & SOX_FILE_NOSTDIO))
+    if (!(ft->handler.flags & SOX_FILE_NOSTDIO))
     {
         /* Open file handler based on input name.  Used stdin file handler
          * if the filename is "-"
@@ -262,17 +241,20 @@
       set_endianness_if_not_already_set(ft);
 
     /* Read and write starters can change their formats. */
-    if (ft->handler->startread && (*ft->handler->startread)(ft) != SOX_SUCCESS)
+    if (ft->handler.startread && (*ft->handler.startread)(ft) != SOX_SUCCESS)
     {
         sox_fail("Can't open input file `%s': %s", ft->filename, ft->sox_errstr);
         goto input_error;
     }
 
+    if (!ft->signal.precision)
+      ft->signal.precision = sox_precision(ft->encoding.encoding, ft->encoding.bits_per_sample);
+
     /* Go ahead and assume 1 channel audio if nothing is detected.
      * This is because libsox usually doesn't set this for mono file
      * formats (for historical reasons).
      */
-    if (!(ft->handler->flags & SOX_FILE_PHONY) && !ft->signal.channels)
+    if (!(ft->handler.flags & SOX_FILE_PHONY) && !ft->signal.channels)
       ft->signal.channels = 1;
 
     if (sox_checkformat(ft) )
@@ -291,150 +273,330 @@
     return NULL;
 }
 
-sox_format_t * sox_open_write(
-    sox_bool (*overwrite_permitted)(const char *filename),
-    const char *path,
-    const sox_signalinfo_t *info,
-    const char *filetype,
-    comments_t comments,
-    sox_size_t length,
-    const sox_instrinfo_t *instr,
-    const sox_loopinfo_t *loops)
+static void set_output_format(sox_format_t * ft)
 {
-    sox_format_t * ft = xcalloc(sizeof(*ft), 1);
-    int i;
-    sox_bool no_filetype_given = filetype == NULL;
+  sox_encoding_t e;
+  unsigned i, s;
+  unsigned const * encodings = ft->handler.write_formats;
+#define enc_arg(T) (T)encodings[i++]
 
-    ft->filename = xstrdup(path);
+  if (ft->handler.write_rates){
+    if (!ft->signal.rate)
+      ft->signal.rate = ft->handler.write_rates[0];
+    else {
+      sox_rate_t r;
+      i = 0;
+      while ((r = ft->handler.write_rates[i++])) {
+        if (r == ft->signal.rate)
+          break;
+      }
+      if (r != ft->signal.rate) {
+        sox_rate_t given = ft->signal.rate, max = 0;
+        ft->signal.rate = HUGE_VAL;
+        i = 0;
+        while ((r = ft->handler.write_rates[i++])) {
+          if (r > given && r < ft->signal.rate)
+            ft->signal.rate = r;
+          else max = max(r, max);
+        }
+        if (ft->signal.rate == HUGE_VAL)
+          ft->signal.rate = max;
+        sox_warn("%s can't encode at %gHz; using %gHz", ft->handler.names[0], given, ft->signal.rate);
+      }
+    }
+  }
+  else if (!ft->signal.rate)
+    ft->signal.rate = SOX_DEFAULT_RATE;
 
-    if (!filetype) {
-      char const * extension = find_file_extension(ft->filename);
-      if (extension)
-        ft->filetype = xstrdup(extension);
+  if (ft->handler.flags & SOX_FILE_CHANS) {
+    if (ft->signal.channels == 1 && !(ft->handler.flags & SOX_FILE_MONO)) {
+      ft->signal.channels = (ft->handler.flags & SOX_FILE_STEREO)? 2 : 4;
+      sox_warn("%s can't encode mono; setting channels to %u", ft->handler.names[0], ft->signal.channels);
     } else
-      ft->filetype = xstrdup(filetype);
+    if (ft->signal.channels == 2 && !(ft->handler.flags & SOX_FILE_STEREO)) {
+      ft->signal.channels = (ft->handler.flags & SOX_FILE_QUAD)? 4 : 1;
+      sox_warn("%s can't encode stereo; setting channels to %u", ft->handler.names[0], ft->signal.channels);
+    } else
+    if (ft->signal.channels == 4 && !(ft->handler.flags & SOX_FILE_QUAD)) {
+      ft->signal.channels = (ft->handler.flags & SOX_FILE_STEREO)? 2 : 1;
+      sox_warn("%s can't encode quad; setting channels to %u", ft->handler.names[0], ft->signal.channels);
+    }
+  } else ft->signal.channels = max(ft->signal.channels, 1);
 
-    ft->mode = 'w';
-    if (sox_gettype(ft, no_filetype_given) != SOX_SUCCESS) {
-      sox_fail("Can't open output file `%s': %s", ft->filename, ft->sox_errstr);
-      goto output_error;
+  if (!encodings)
+    return;
+  /* If an encoding has been given, check if it supported by this handler */
+  if (ft->encoding.encoding) {
+    i = 0;
+    while ((e = enc_arg(sox_encoding_t))) {
+      if (e == ft->encoding.encoding)
+        break;
+      while (enc_arg(unsigned));
     }
-    ft->signal.size = 0;
-    ft->signal.encoding = SOX_ENCODING_UNKNOWN;
-    ft->signal.channels = 0;
-    ft->signal.compression = HUGE_VAL;
-    if (info)
-        ft->signal = *info;
+    if (e != ft->encoding.encoding) {
+      sox_warn("%s can't encode %s", ft->handler.names[0], sox_encodings_str[ft->encoding.encoding]);
+      ft->encoding.encoding = 0;
+    }
+    else {
+      unsigned max_p = 0;
+      unsigned max_p_s = 0;
+      unsigned given_size = 0;
+      sox_bool found = sox_false;
+      if (ft->encoding.bits_per_sample)
+        given_size = ft->encoding.bits_per_sample;
+      ft->encoding.bits_per_sample = 65;
+      while ((s = enc_arg(unsigned))) {
+        if (s == given_size)
+          found = sox_true;
+        if (sox_precision(e, s) >= ft->signal.precision) {
+          if (s < ft->encoding.bits_per_sample)
+            ft->encoding.bits_per_sample = s;
+        }
+        else if (sox_precision(e, s) > max_p) {
+          max_p = sox_precision(e, s);
+          max_p_s = s;
+        }
+      }
+      if (ft->encoding.bits_per_sample == 65)
+        ft->encoding.bits_per_sample = max_p_s;
+      if (given_size) {
+        if (found)
+          ft->encoding.bits_per_sample = given_size;
+        else sox_warn("%s can't encode %s to %u-bit", ft->handler.names[0], sox_encodings_str[ft->encoding.encoding], given_size);
+      }
+    }
+  }
 
-    if (!(ft->handler->flags & SOX_FILE_NOSTDIO))
-    {
-        /* Open file handler based on output name.  Used stdout file handler
-         * if the filename is "-"
-         */
-        if (!strcmp(ft->filename, "-")) {
-          if (sox_globals.stdout_in_use_by) {
-            sox_fail("'-' (stdout) already in use by '%s'", sox_globals.stdout_in_use_by);
-            goto output_error;
-          }
-          sox_globals.stdout_in_use_by = "audio output";
-            SET_BINARY_MODE(stdout);
-            ft->fp = stdout;
+  /* If a size has been given, check if it supported by this handler */
+  if (!ft->encoding.encoding && ft->encoding.bits_per_sample) {
+    i = 0;
+    s= 0;
+    while (s != ft->encoding.bits_per_sample && (e = enc_arg(sox_encoding_t)))
+      while ((s = enc_arg(unsigned)) && s != ft->encoding.bits_per_sample);
+    if (s != ft->encoding.bits_per_sample) {
+      sox_warn("%s can't encode to %u-bit", ft->handler.names[0], ft->encoding.bits_per_sample);
+      ft->encoding.bits_per_sample = 0;
+    }
+    else ft->encoding.encoding = e;
+  }
+
+  /* Find the smallest lossless encoding with precision >= signal.precision */
+  if (!ft->encoding.encoding) {
+    ft->encoding.bits_per_sample = 65;
+    i = 0;
+    while ((e = enc_arg(sox_encoding_t)))
+      while ((s = enc_arg(unsigned)))
+        if (e < SOX_ENCODING_LOSSLESS &&
+            sox_precision(e, s) >= ft->signal.precision && s < ft->encoding.bits_per_sample) {
+          ft->encoding.encoding = e;
+          ft->encoding.bits_per_sample = s;
         }
-        else {
-          struct stat st;
-          if (!stat(ft->filename, &st) && (st.st_mode & S_IFMT) == S_IFREG &&
-              (overwrite_permitted && !overwrite_permitted(ft->filename))) {
-            sox_fail("Permission to overwrite '%s' denied", ft->filename);
-            goto output_error;
+  }
+
+  /* Find the smallest lossy encoding with precision >= signal precision,
+   * or, if none such, the highest precision encoding */
+  if (!ft->encoding.encoding) {
+    unsigned max_p = 0;
+    sox_encoding_t max_p_e = 0;
+    unsigned max_p_s = 0;
+    i = 0;
+    while ((e = enc_arg(sox_encoding_t)))
+      do {
+        s = enc_arg(unsigned);
+        if (sox_precision(e, s) >= ft->signal.precision) {
+          if (s < ft->encoding.bits_per_sample) {
+            ft->encoding.encoding = e;
+            ft->encoding.bits_per_sample = s;
           }
-          if ((ft->fp = fopen(ft->filename, "wb")) == NULL) {
-            sox_fail("Can't open output file `%s': %s", ft->filename,
-                    strerror(errno));
-            goto output_error;
-          }
         }
-
-        /* stdout tends to be line-buffered.  Override this */
-        /* to be Full Buffering. */
-        if (setvbuf (ft->fp, NULL, _IOFBF, sizeof(char) * sox_globals.bufsiz))
-        {
-            sox_fail("Can't set write buffer");
-            goto output_error;
+        else if (sox_precision(e, s) > max_p) {
+          max_p = sox_precision(e, s);
+          max_p_e = e;
+          max_p_s = s;
         }
+      } while (s);
+    if (!ft->encoding.encoding) {
+      ft->encoding.encoding = max_p_e;
+      ft->encoding.bits_per_sample = max_p_s;
+    }
+  }
+  ft->signal.precision = min(ft->signal.precision, sox_precision(ft->encoding.encoding, ft->encoding.bits_per_sample));
+  #undef enc_arg
+}
 
-        /* See if this file is seekable or not */
-        ft->seekable = is_seekable(ft);
+sox_bool sox_format_supports_encoding(
+    char               const * path,
+    char               const * filetype,
+    sox_encodinginfo_t const * encoding)
+{
+  #define enc_arg(T) (T)ft.handler.write_formats[i++]
+  sox_encoding_t e;
+  unsigned i = 0, s;
+  sox_format_t ft;
+  sox_bool no_filetype_given = filetype == NULL;
+
+  assert(path);
+  assert(encoding);
+  ft.filetype = (char *)(filetype? filetype : find_file_extension(path));
+  if (sox_gettype(&ft, no_filetype_given) != SOX_SUCCESS ||
+      !ft.handler.write_formats)
+    return sox_false;
+  while ((e = enc_arg(sox_encoding_t))) {
+    if (e == encoding->encoding) {
+      while ((s = enc_arg(unsigned)))
+        if (s == encoding->bits_per_sample)
+          return sox_true;
+      break;
     }
+    while (enc_arg(unsigned));
+  }
+  return sox_false;
+  #undef enc_arg
+}
 
-    ft->comments = copy_comments(comments);
+sox_format_t * sox_open_write(
+    sox_bool (*overwrite_permitted)(const char *filename),
+    char               const * path,
+    sox_signalinfo_t   const * signal,
+    sox_encodinginfo_t const * encoding,
+    char               const * filetype,
+    comments_t                 comments,
+    sox_size_t                 length,
+    sox_instrinfo_t    const * instr,
+    sox_loopinfo_t     const * loops)
+{
+  sox_bool no_filetype_given = filetype == NULL;
+  sox_format_t * ft = xcalloc(sizeof(*ft), 1);
+  int i;
 
-    if (loops)
-        for (i = 0; i < SOX_MAX_NLOOPS; i++)
-            ft->loops[i] = loops[i];
+  if (!path || !signal) {
+    free(ft);
+    return NULL;
+  }
 
-    /* leave SMPTE # alone since it's absolute */
-    if (instr)
-        ft->instr = *instr;
+  ft->filename = xstrdup(path);
 
-    ft->length = length;
-    set_endianness_if_not_already_set(ft);
+  if (!filetype) {
+    char const * extension = find_file_extension(ft->filename);
+    if (extension)
+      ft->filetype = xstrdup(extension);
+  } else ft->filetype = xstrdup(filetype);
 
-    /* Read and write starters can change their formats. */
-    if (ft->handler->startwrite && (*ft->handler->startwrite)(ft) != SOX_SUCCESS)
-    {
-        sox_fail("Can't open output file `%s': %s", ft->filename, ft->sox_errstr);
-        goto output_error;
-    }
+  ft->mode = 'w';
+  if (sox_gettype(ft, no_filetype_given) != SOX_SUCCESS) {
+    sox_fail("Can't open output file `%s': %s", ft->filename, ft->sox_errstr);
+    goto output_error;
+  }
+  ft->signal = *signal;
+  if (encoding)
+    ft->encoding = *encoding;
+  else sox_init_encodinginfo(&ft->encoding);
 
-    if (sox_checkformat(ft) )
-    {
-        sox_fail("bad output format for file %s: %s", ft->filename,
-                ft->sox_errstr);
-        goto output_error;
-    }
+  if (!(ft->handler.flags & SOX_FILE_NOSTDIO))
+  {
+      /* Open file handler based on output name.  Used stdout file handler
+       * if the filename is "-"
+       */
+      if (!strcmp(ft->filename, "-")) {
+        if (sox_globals.stdout_in_use_by) {
+          sox_fail("'-' (stdout) already in use by '%s'", sox_globals.stdout_in_use_by);
+          goto output_error;
+        }
+        sox_globals.stdout_in_use_by = "audio output";
+          SET_BINARY_MODE(stdout);
+          ft->fp = stdout;
+      }
+      else {
+        struct stat st;
+        if (!stat(ft->filename, &st) && (st.st_mode & S_IFMT) == S_IFREG &&
+            (overwrite_permitted && !overwrite_permitted(ft->filename))) {
+          sox_fail("Permission to overwrite '%s' denied", ft->filename);
+          goto output_error;
+        }
+        if ((ft->fp = fopen(ft->filename, "wb")) == NULL) {
+          sox_fail("Can't open output file `%s': %s", ft->filename,
+                  strerror(errno));
+          goto output_error;
+        }
+      }
 
-    /*
-     * Bit of a hack; doesn't cover the situation where
-     * codec changes audio length (e.g. 8svx, gsm):
-     */
-    if (info)
-      ft->length = ft->length * ft->signal.rate / info->rate * ft->signal.channels / info->channels + .5;
+      /* stdout tends to be line-buffered.  Override this */
+      /* to be Full Buffering. */
+      if (setvbuf (ft->fp, NULL, _IOFBF, sizeof(char) * sox_globals.bufsiz))
+      {
+          sox_fail("Can't set write buffer");
+          goto output_error;
+      }
 
+      /* See if this file is seekable or not */
+      ft->seekable = is_seekable(ft);
+  }
+
+  ft->comments = copy_comments(comments);
+
+  if (loops) for (i = 0; i < SOX_MAX_NLOOPS; i++)
+    ft->loops[i] = loops[i];
+
+  /* leave SMPTE # alone since it's absolute */
+  if (instr)
+    ft->instr = *instr;
+
+  ft->length = length;
+  set_endianness_if_not_already_set(ft);
+  set_output_format(ft);
+
+  /* FIXME: doesn't cover the situation where
+   * codec changes audio length (e.g. 8svx, gsm): */
+  if (signal->rate && signal->channels)
+    ft->length = ft->length * ft->signal.rate / signal->rate *
+      ft->signal.channels / signal->channels + .5;
+
+  if ((ft->handler.flags & SOX_FILE_REWIND) && !ft->length && !ft->seekable)
+    sox_warn("can't seek in output file `%s'; length in file header will be unspecified", ft->filename);
+
+  /* Read and write starters can change their formats. */
+  if (ft->handler.startwrite && (ft->handler.startwrite)(ft) != SOX_SUCCESS){
+    sox_fail("can't open output file `%s': %s", ft->filename, ft->sox_errstr);
+    goto output_error;
+  }
+
+  if (sox_checkformat(ft) == SOX_SUCCESS)
     return ft;
+  sox_fail("bad format for output file `%s': %s", ft->filename, ft->sox_errstr);
 
 output_error:
-
-    free(ft->filename);
-    free(ft->filetype);
-    free(ft);
-    return NULL;
+  free(ft->filename);
+  free(ft->filetype);
+  free(ft);
+  return NULL;
 }
 
 sox_size_t sox_read(sox_format_t * ft, sox_sample_t * buf, sox_size_t len)
 {
-  sox_size_t actual = ft->handler->read? (*ft->handler->read)(ft, buf, len) : 0;
+  sox_size_t actual = ft->handler.read? (*ft->handler.read)(ft, buf, len) : 0;
   return (actual > len? 0 : actual);
 }
 
 sox_size_t sox_write(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len)
 {
-    return ft->handler->write? (*ft->handler->write)(ft, buf, len) : 0;
+  ft->olength += len;
+  return ft->handler.write? (*ft->handler.write)(ft, buf, len) : 0;
 }
 
 #define TWIDDLE_BYTE(ub, type) \
   do { \
-    if (ft->signal.reverse_bits) \
+    if (ft->encoding.reverse_bits) \
       ub = cswap[ub]; \
-    if (ft->signal.reverse_nibbles) \
+    if (ft->encoding.reverse_nibbles) \
       ub = ((ub & 15) << 4) | (ub >> 4); \
   } while (0);
 
 #define TWIDDLE_WORD(uw, type) \
-  if (ft->signal.reverse_bytes) \
+  if (ft->encoding.reverse_bytes) \
     uw = sox_swap ## type(uw);
 
 #define TWIDDLE_FLOAT(f, type) \
-  if (ft->signal.reverse_bytes) \
+  if (ft->encoding.reverse_bytes) \
     sox_swapf(&f);
 
 /* N.B. This macro doesn't work for unaligned types (e.g. 3-byte
@@ -558,21 +720,30 @@
 /* N.B. The file (if any) may already have been deleted. */
 int sox_close(sox_format_t * ft)
 {
-    int rc;
+  int rc = SOX_SUCCESS;
 
-    if (ft->mode == 'r')
-        rc = ft->handler->stopread? (*ft->handler->stopread)(ft) : SOX_SUCCESS;
-    else
-        rc = ft->handler->stopwrite? (*ft->handler->stopwrite)(ft) : SOX_SUCCESS;
+  if (ft->mode == 'r')
+    rc = ft->handler.stopread? (*ft->handler.stopread)(ft) : SOX_SUCCESS;
+  else {
+    if (ft->handler.flags & SOX_FILE_REWIND) {
+      if (ft->olength != ft->length && ft->seekable) {
+        rc = sox_seeki(ft, 0, 0);
+        if (rc == SOX_SUCCESS)
+          rc = ft->handler.stopwrite? (*ft->handler.stopwrite)(ft)
+             : ft->handler.startwrite?(*ft->handler.startwrite)(ft) : SOX_SUCCESS;
+      }
+    }
+    else rc = ft->handler.stopwrite? (*ft->handler.stopwrite)(ft) : SOX_SUCCESS;
+  }
 
-    if (!(ft->handler->flags & SOX_FILE_NOSTDIO))
-        fclose(ft->fp);
-    free(ft->filename);
-    free(ft->filetype);
-    delete_comments(&ft->comments);
+  if (!(ft->handler.flags & SOX_FILE_NOSTDIO))
+    fclose(ft->fp);
+  free(ft->filename);
+  free(ft->filetype);
+  delete_comments(&ft->comments);
 
-    free(ft);
-    return rc;
+  free(ft);
+  return rc;
 }
 
 int sox_seek(sox_format_t * ft, sox_size_t offset, int whence)
@@ -584,8 +755,8 @@
     /* If file is a seekable file and this handler supports seeking,
      * then invoke handler's function.
      */
-    if (ft->seekable && ft->handler->seek)
-      return (*ft->handler->seek)(ft, offset);
+    if (ft->seekable && ft->handler.seek)
+      return (*ft->handler.seek)(ft, offset);
     return SOX_EOF; /* FIXME: return SOX_EBADF */
 }
 
--- a/src/sphere.c
+++ b/src/sphere.c
@@ -26,10 +26,9 @@
  *      size and encoding of samples, 
  *      mono/stereo/quad.
  */
-static int sox_spherestartread(sox_format_t * ft) 
+static int startread(sox_format_t * ft) 
 {
         sphere_t sphere = (sphere_t) ft->priv;
-        int rc;
         char *buf;
         char fldname[64], fldtype[16], fldsval[128];
         int i;
@@ -36,11 +35,6 @@
         sox_size_t header_size, bytes_read;
         long rate;
 
-        /* Needed for rawread() */
-        rc = sox_rawstartread(ft);
-        if (rc)
-            return rc;
-
         /* Magic header */
         if (sox_reads(ft, fldname, 8) == SOX_EOF || strncmp(fldname, "NIST_1A", 7) != 0)
         {
@@ -72,10 +66,10 @@
 
         while (strncmp(buf, "end_head", 8) != 0)
         {
-            if (strncmp(buf, "sample_n_bytes", 14) == 0 && !ft->signal.size)
+            if (strncmp(buf, "sample_n_bytes", 14) == 0 && !ft->encoding.bits_per_sample)
             {
                 sscanf(buf, "%63s %15s %d", fldname, fldtype, &i);
-                ft->signal.size = i;
+                ft->encoding.bits_per_sample = i << 3;
             }
             if (strncmp(buf, "channel_count", 13) == 0 && 
                 ft->signal.channels == 0)
@@ -89,10 +83,10 @@
                 /* Only bother looking for ulaw flag.  All others
                  * should be caught below by default PCM check
                  */
-                if (ft->signal.encoding == SOX_ENCODING_UNKNOWN && 
+                if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN && 
                     strncmp(fldsval,"ulaw",4) == 0)
                 {
-                    ft->signal.encoding = SOX_ENCODING_ULAW;
+                    ft->encoding.encoding = SOX_ENCODING_ULAW;
                 }
             }
             if (strncmp(buf, "sample_rate ", 12) == 0 &&
@@ -105,9 +99,9 @@
             {
                 sscanf(buf, "%53s %15s %127s", fldname, fldtype, fldsval);
                 if (strncmp(fldsval,"01",2) == 0)
-                  ft->signal.reverse_bytes = SOX_IS_BIGENDIAN; /* Data is little endian. */
+                  ft->encoding.reverse_bytes = SOX_IS_BIGENDIAN; /* Data is little endian. */
                 else if (strncmp(fldsval,"10",2) == 0)
-                  ft->signal.reverse_bytes = SOX_IS_LITTLEENDIAN; /* Data is big endian. */
+                  ft->encoding.reverse_bytes = SOX_IS_LITTLEENDIAN; /* Data is big endian. */
             }
 
             if (sox_reads(ft, buf, header_size) == SOX_EOF)
@@ -120,19 +114,19 @@
             header_size -= (strlen(buf) + 1);
         }
 
-        if (!ft->signal.size)
-            ft->signal.size = SOX_SIZE_BYTE;
+        if (!ft->encoding.bits_per_sample)
+            ft->encoding.bits_per_sample = 8;
 
         /* sample_coding is optional and is PCM if missing.
          * This means encoding is signed if size = word or
          * unsigned if size = byte.
          */
-        if (ft->signal.encoding == SOX_ENCODING_UNKNOWN)
+        if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN)
         {
-            if (ft->signal.size == SOX_SIZE_8BIT)
-                ft->signal.encoding = SOX_ENCODING_UNSIGNED;
+            if (ft->encoding.bits_per_sample == 8)
+                ft->encoding.encoding = SOX_ENCODING_UNSIGNED;
             else
-                ft->signal.encoding = SOX_ENCODING_SIGN2;
+                ft->encoding.encoding = SOX_ENCODING_SIGN2;
         }
 
         while (header_size)
@@ -164,10 +158,10 @@
         }
 
         free(buf);
-        return (SOX_SUCCESS);
+        return sox_rawstartread(ft);
 }
 
-static int sox_spherestartwrite(sox_format_t * ft) 
+static int startwrite(sox_format_t * ft) 
 {
     int rc;
     int x;
@@ -179,17 +173,6 @@
         return (SOX_EOF);
     }
 
-    switch (ft->signal.encoding)
-    {
-        case SOX_ENCODING_ULAW:
-        case SOX_ENCODING_SIGN2:
-        case SOX_ENCODING_UNSIGNED:
-            break;
-        default:
-            sox_fail_errno(ft,SOX_EFMT,"SPHERE format only supports ulaw and PCM data.");
-            return(SOX_EOF);
-    }
-
     sphere->numSamples = 0;
 
     /* Needed for rawwrite */
@@ -206,7 +189,7 @@
         
 }
 
-static sox_size_t sox_spherewrite(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len) 
+static sox_size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len) 
 {
     sphere_t sphere = (sphere_t) ft->priv;
 
@@ -214,7 +197,7 @@
     return sox_rawwrite(ft, buf, len);
 }
 
-static int sox_spherestopwrite(sox_format_t * ft) 
+static int stopwrite(sox_format_t * ft) 
 {
     char buf[128];
     sphere_t sphere = (sphere_t) ft->priv;
@@ -222,7 +205,7 @@
 
     if (sox_seeki(ft, 0, 0) != 0)
     {
-        sox_fail_errno(ft,errno,"Could not rewird output file to rewrite sphere header.");
+        sox_fail_errno(ft,errno,"Could not rewind output file to rewrite sphere header.");
         return (SOX_EOF);
     }
 
@@ -233,7 +216,7 @@
     sprintf(buf, "sample_count -i %ld\n", samples);
     sox_writes(ft, buf);
 
-    sprintf(buf, "sample_n_bytes -i %d\n", ft->signal.size);
+    sprintf(buf, "sample_n_bytes -i %d\n", ft->encoding.bits_per_sample >> 3);
     sox_writes(ft, buf);
 
     sprintf(buf, "channel_count -i %d\n", ft->signal.channels);
@@ -240,7 +223,7 @@
     sox_writes(ft, buf);
 
     sprintf(buf, "sample_byte_format -s2 %s\n",
-        ft->signal.reverse_bytes != SOX_IS_BIGENDIAN ? "10" : "01");
+        ft->encoding.reverse_bytes != SOX_IS_BIGENDIAN ? "10" : "01");
     sox_writes(ft, buf);
 
     rate = ft->signal.rate;
@@ -247,7 +230,7 @@
     sprintf(buf, "sample_rate -i %ld\n", rate);
     sox_writes(ft, buf);
 
-    if (ft->signal.encoding == SOX_ENCODING_ULAW)
+    if (ft->encoding.encoding == SOX_ENCODING_ULAW)
         sox_writes(ft, "sample_coding -s4 ulaw\n");
     else
         sox_writes(ft, "sample_coding -s3 pcm\n");
@@ -257,28 +240,19 @@
     return (SOX_SUCCESS);
 }
 
-/* NIST Sphere File */
-static const char *spherenames[] = {
-  "sph",
-  "nist",
-  NULL
-};
-
-static sox_format_handler_t sox_sphere_format = {
-  spherenames,
-  0,
-  sox_spherestartread,
-  sox_rawread,
-  sox_rawstopread,
-  sox_spherestartwrite,
-  sox_spherewrite,
-  sox_spherestopwrite,
-  NULL
-};
-
-const sox_format_handler_t *sox_sphere_format_fn(void);
-
-const sox_format_handler_t *sox_sphere_format_fn(void)
+SOX_FORMAT_HANDLER(sphere)
 {
-    return &sox_sphere_format;
+  static char const * const names[] = {"sph", "nist", NULL};
+  static unsigned const write_encodings[] = {
+    SOX_ENCODING_SIGN2, 8, 16, 24, 32, 0,
+    SOX_ENCODING_UNSIGNED, 8, 16, 24, 32, 0,
+    SOX_ENCODING_ULAW, 8, 0,
+    0};
+  static sox_format_handler_t const handler = {
+    names, 0,
+    startread, sox_rawread, sox_rawstopread,
+    startwrite, write_samples, stopwrite,
+    NULL, write_encodings, NULL
+  };
+  return &handler;
 }
--- a/src/splice.c
+++ b/src/splice.c
@@ -142,8 +142,8 @@
   splice_t p = (splice_t) effp->priv;
   unsigned i;
 
-  parse(effp, 0, effp->ininfo.rate); /* Re-parse now rate is known */
-  p->buffer = xcalloc(p->max_buffer_size * effp->ininfo.channels, sizeof(*p->buffer));
+  parse(effp, 0, effp->in_signal.rate); /* Re-parse now rate is known */
+  p->buffer = xcalloc(p->max_buffer_size * effp->in_signal.channels, sizeof(*p->buffer));
   p->in_pos = p->buffer_pos = p->splices_pos = 0;
   p->state = p->splices_pos != p->nsplices && p->in_pos == p->splices[p->splices_pos].start;
   for (i = 0; i < p->nsplices; ++i)
@@ -157,8 +157,8 @@
 {
   splice_t p = (splice_t) effp->priv;
   sox_size_t c, idone = 0, odone = 0;
-  *isamp /= effp->ininfo.channels;
-  *osamp /= effp->ininfo.channels;
+  *isamp /= effp->in_signal.channels;
+  *osamp /= effp->in_signal.channels;
 
   while (sox_true) {
 copying:
@@ -168,7 +168,7 @@
           p->state = 1;
           goto buffering;
         }
-        for (c = 0; c < effp->ininfo.channels; ++c)
+        for (c = 0; c < effp->in_signal.channels; ++c)
           *obuf++ = *ibuf++;
       }
       break;
@@ -176,18 +176,18 @@
 
 buffering:
     if (p->state == 1) {
-      sox_size_t buffer_size = (2 * p->splices[p->splices_pos].overlap + p->splices[p->splices_pos].search) * effp->ininfo.channels;
+      sox_size_t buffer_size = (2 * p->splices[p->splices_pos].overlap + p->splices[p->splices_pos].search) * effp->in_signal.channels;
       for (; idone < *isamp; ++idone, ++p->in_pos) {
         if (p->buffer_pos == buffer_size) {
           p->buffer_pos = do_splice(p->buffer,
               p->splices[p->splices_pos].overlap,
               p->splices[p->splices_pos].search,
-              effp->ininfo.channels) * effp->ininfo.channels;
+              effp->in_signal.channels) * effp->in_signal.channels;
           p->state = 2;
           goto flushing;
           break;
         }
-        for (c = 0; c < effp->ininfo.channels; ++c)
+        for (c = 0; c < effp->in_signal.channels; ++c)
           p->buffer[p->buffer_pos++] = SOX_SAMPLE_TO_FLOAT_32BIT(*ibuf++, effp->clips);
       }
       break;
@@ -195,7 +195,7 @@
 
 flushing:
     if (p->state == 2) {
-      sox_size_t buffer_size = (2 * p->splices[p->splices_pos].overlap + p->splices[p->splices_pos].search) * effp->ininfo.channels;
+      sox_size_t buffer_size = (2 * p->splices[p->splices_pos].overlap + p->splices[p->splices_pos].search) * effp->in_signal.channels;
       for (; odone < *osamp; ++odone) {
         if (p->buffer_pos == buffer_size) {
           p->buffer_pos = 0;
@@ -203,7 +203,7 @@
           p->state = p->splices_pos != p->nsplices && p->in_pos == p->splices[p->splices_pos].start;
           goto copying;
         }
-        for (c = 0; c < effp->ininfo.channels; ++c)
+        for (c = 0; c < effp->in_signal.channels; ++c)
           *obuf++ = SOX_FLOAT_32BIT_TO_SAMPLE(p->buffer[p->buffer_pos++], effp->clips);
       }
       break;
@@ -210,8 +210,8 @@
     }
   }
 
-  *isamp = idone * effp->ininfo.channels;
-  *osamp = odone * effp->ininfo.channels;
+  *isamp = idone * effp->in_signal.channels;
+  *osamp = odone * effp->in_signal.channels;
   return SOX_SUCCESS;
 }
 
--- a/src/stat.c
+++ b/src/stat.c
@@ -13,9 +13,10 @@
  * the consequences of using this software.
  */
 
+#include "sox_i.h"
+
 #include <math.h>
 #include <string.h>
-#include "sox_i.h"
 #include "FFT.h"
 
 /* Private data for stat effect */
@@ -146,7 +147,7 @@
 
         if (stat->fft_offset >= stat->fft_size) {
           stat->fft_offset = 0;
-          print_power_spectrum(stat->fft_size, effp->ininfo.rate, stat->re_in, stat->re_out);
+          print_power_spectrum(stat->fft_size, effp->in_signal.rate, stat->re_in, stat->re_out);
         }
 
       }
@@ -215,7 +216,7 @@
     for (x = stat->fft_offset; x < stat->fft_size; x++)
       stat->re_in[x] = 0;
       
-    print_power_spectrum(stat->fft_size, effp->ininfo.rate, stat->re_in, stat->re_out);
+    print_power_spectrum(stat->fft_size, effp->in_signal.rate, stat->re_in, stat->re_out);
   }
 
   *osamp = 0;
@@ -266,7 +267,7 @@
     fprintf(stderr, "\n\n");
   /* print out the info */
   fprintf(stderr, "Samples read:      %12u\n", stat->read);
-  fprintf(stderr, "Length (seconds):  %12.6f\n", (double)stat->read/effp->ininfo.rate/effp->ininfo.channels);
+  fprintf(stderr, "Length (seconds):  %12.6f\n", (double)stat->read/effp->in_signal.rate/effp->in_signal.channels);
   if (stat->srms)
     fprintf(stderr, "Scaled by rms:     %12.6f\n", rms);
   else
@@ -282,7 +283,7 @@
   fprintf(stderr, "Minimum delta:     %12.6f\n", stat->dmin);
   fprintf(stderr, "Mean    delta:     %12.6f\n", stat->dsum1/(ct-1));
   fprintf(stderr, "RMS     delta:     %12.6f\n", sqrt(stat->dsum2/(ct-1)));
-  freq = sqrt(stat->dsum2/stat->sum2)*effp->ininfo.rate/(M_PI*2);
+  freq = sqrt(stat->dsum2/stat->sum2)*effp->in_signal.rate/(M_PI*2);
   fprintf(stderr, "Rough   frequency: %12d\n", (int)freq);
 
   if (amp>0)
@@ -295,17 +296,17 @@
     x = (float)(stat->bin[0] + stat->bin[3]) / (float)(stat->bin[1] + stat->bin[2]);
 
     if (x >= 3.0) {             /* use opposite encoding */
-      if (effp->ininfo.encoding == SOX_ENCODING_UNSIGNED)
-        fprintf(stderr,"\nTry: -t raw -b -s \n");
+      if (effp->in_encoding->encoding == SOX_ENCODING_UNSIGNED)
+        fprintf(stderr,"\nTry: -t raw -s -1 \n");
       else
-        fprintf(stderr,"\nTry: -t raw -b -u \n");
+        fprintf(stderr,"\nTry: -t raw -u -1 \n");
     } else if (x <= 1.0 / 3.0)
       ;                         /* correctly decoded */
     else if (x >= 0.5 && x <= 2.0) { /* use ULAW */
-      if (effp->ininfo.encoding == SOX_ENCODING_ULAW)
-        fprintf(stderr,"\nTry: -t raw -b -u \n");
+      if (effp->in_encoding->encoding == SOX_ENCODING_ULAW)
+        fprintf(stderr,"\nTry: -t raw -u -1 \n");
       else
-        fprintf(stderr,"\nTry: -t raw -b -U \n");
+        fprintf(stderr,"\nTry: -t raw -U -1 \n");
     } else
       fprintf(stderr, "\nCan't guess the type\n");
   }
--- a/src/stretch.c
+++ b/src/stretch.c
@@ -150,7 +150,7 @@
 
   stretch->state = input_state;
 
-  stretch->size = (int)(effp->outinfo.rate * 0.001 * stretch->window);
+  stretch->size = (int)(effp->out_signal.rate * 0.001 * stretch->window);
   /* start in the middle of an input to avoid initial fading... */
   stretch->index = stretch->size / 2;
   stretch->ibuf = (sox_sample_t *)xmalloc(stretch->size * sizeof(sox_sample_t));
--- a/src/sunaudio.c
+++ b/src/sunaudio.c
@@ -60,7 +60,7 @@
     file->size = 1024;
     file->buf = xmalloc (file->size);
 
-    if (ft->signal.encoding == SOX_ENCODING_UNKNOWN) ft->signal.encoding = SOX_ENCODING_ULAW;
+    if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN) ft->encoding.encoding = SOX_ENCODING_ULAW;
 
 #ifdef __SVR4
     /* Read in old values, change to what we need and then send back */
@@ -78,33 +78,33 @@
     /* If simple hardware detected in force data to ulaw. */
     if (simple_hw)
     {
-        if (ft->signal.size == SOX_SIZE_BYTE)
+        if (ft->encoding.bits_per_sample == 8)
         {
-            if (ft->signal.encoding != SOX_ENCODING_ULAW &&
-                ft->signal.encoding != SOX_ENCODING_ALAW)
+            if (ft->encoding.encoding != SOX_ENCODING_ULAW &&
+                ft->encoding.encoding != SOX_ENCODING_ALAW)
             {
                 sox_report("Warning: Detected simple hardware.  Forcing output to ULAW");
-                ft->signal.encoding = SOX_ENCODING_ULAW;
+                ft->encoding.encoding = SOX_ENCODING_ULAW;
             }
         }
-        else if (ft->signal.size == SOX_SIZE_16BIT)
+        else if (ft->encoding.bits_per_sample == 16)
         {
             sox_report("Warning: Detected simple hardware.  Forcing output to ULAW");
-            ft->signal.size = SOX_SIZE_BYTE;
-            ft->signal.encoding = SOX_ENCODING_ULAW;
+            ft->encoding.bits_per_sample = 8;
+            ft->encoding.encoding = SOX_ENCODING_ULAW;
         }
     }
 
-    if (ft->signal.size == SOX_SIZE_BYTE) {
+    if (ft->encoding.bits_per_sample == 8) {
         samplesize = 8;
-        if (ft->signal.encoding != SOX_ENCODING_ULAW &&
-            ft->signal.encoding != SOX_ENCODING_ALAW &&
-            ft->signal.encoding != SOX_ENCODING_SIGN2) {
+        if (ft->encoding.encoding != SOX_ENCODING_ULAW &&
+            ft->encoding.encoding != SOX_ENCODING_ALAW &&
+            ft->encoding.encoding != SOX_ENCODING_SIGN2) {
             sox_fail_errno(ft,SOX_EFMT,"Sun audio driver only supports ULAW, ALAW, and signed linear for bytes.");
                 return (SOX_EOF);
         }
-        if ((ft->signal.encoding == SOX_ENCODING_ULAW ||
-             ft->signal.encoding == SOX_ENCODING_ALAW) && 
+        if ((ft->encoding.encoding == SOX_ENCODING_ULAW ||
+             ft->encoding.encoding == SOX_ENCODING_ALAW) && 
             ft->signal.channels == 2)
         {
             sox_report("Warning: only support mono for ULAW and ALAW data.  Forcing to mono.");
@@ -111,9 +111,9 @@
             ft->signal.channels = 1;
         }
     }
-    else if (ft->signal.size == SOX_SIZE_16BIT) {
+    else if (ft->encoding.bits_per_sample == 16) {
         samplesize = 16;
-        if (ft->signal.encoding != SOX_ENCODING_SIGN2) {
+        if (ft->encoding.encoding != SOX_ENCODING_SIGN2) {
             sox_fail_errno(ft,SOX_EFMT,"Sun audio driver only supports signed linear for words.");
             return(SOX_EOF);
         }
@@ -141,9 +141,9 @@
     audio_if.record.precision = samplesize;
     audio_if.record.channels = ft->signal.channels;
     audio_if.record.sample_rate = ft->signal.rate;
-    if (ft->signal.encoding == SOX_ENCODING_ULAW)
+    if (ft->encoding.encoding == SOX_ENCODING_ULAW)
         encoding = AUDIO_ENCODING_ULAW;
-    else if (ft->signal.encoding == SOX_ENCODING_ALAW)
+    else if (ft->encoding.encoding == SOX_ENCODING_ALAW)
         encoding = AUDIO_ENCODING_ALAW;
     else
         encoding = AUDIO_ENCODING_LINEAR;
@@ -211,37 +211,37 @@
 
     if (simple_hw)
     {
-        if (ft->signal.size == SOX_SIZE_BYTE)
+        if (ft->encoding.bits_per_sample == 8)
         {
-            if (ft->signal.encoding != SOX_ENCODING_ULAW &&
-                ft->signal.encoding != SOX_ENCODING_ALAW)
+            if (ft->encoding.encoding != SOX_ENCODING_ULAW &&
+                ft->encoding.encoding != SOX_ENCODING_ALAW)
             {
                 sox_report("Warning: Detected simple hardware.  Forcing output to ULAW");
-                ft->signal.encoding = SOX_ENCODING_ULAW;
+                ft->encoding.encoding = SOX_ENCODING_ULAW;
             }
         }
-        else if (ft->signal.size == SOX_SIZE_16BIT)
+        else if (ft->encoding.bits_per_sample == 16)
         {
             sox_report("Warning: Detected simple hardware.  Forcing output to ULAW");
-            ft->signal.size = SOX_SIZE_BYTE;
-            ft->signal.encoding = SOX_ENCODING_ULAW;
+            ft->encoding.bits_per_sample = 8;
+            ft->encoding.encoding = SOX_ENCODING_ULAW;
         }
     }
 
-    if (ft->signal.size == SOX_SIZE_BYTE) 
+    if (ft->encoding.bits_per_sample == 8) 
     {
         samplesize = 8;
-        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) {
+        if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN) 
+            ft->encoding.encoding = SOX_ENCODING_ULAW;
+        else if (ft->encoding.encoding != SOX_ENCODING_ULAW &&
+            ft->encoding.encoding != SOX_ENCODING_ALAW &&
+            ft->encoding.encoding != SOX_ENCODING_SIGN2) {
             sox_report("Sun Audio driver only supports ULAW, ALAW, and Signed Linear for bytes.");
             sox_report("Forcing to ULAW");
-            ft->signal.encoding = SOX_ENCODING_ULAW;
+            ft->encoding.encoding = SOX_ENCODING_ULAW;
         }
-        if ((ft->signal.encoding == SOX_ENCODING_ULAW ||
-             ft->signal.encoding == SOX_ENCODING_ALAW) && 
+        if ((ft->encoding.encoding == SOX_ENCODING_ULAW ||
+             ft->encoding.encoding == SOX_ENCODING_ALAW) && 
             ft->signal.channels == 2)
         {
             sox_report("Warning: only support mono for ULAW and ALAW data.  Forcing to mono.");
@@ -249,20 +249,20 @@
         }
 
     }
-    else if (ft->signal.size == SOX_SIZE_16BIT) {
+    else if (ft->encoding.bits_per_sample == 16) {
         samplesize = 16;
-        if (ft->signal.encoding == SOX_ENCODING_UNKNOWN) 
-            ft->signal.encoding = SOX_ENCODING_SIGN2;
-        else if (ft->signal.encoding != SOX_ENCODING_SIGN2) {
+        if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN) 
+            ft->encoding.encoding = SOX_ENCODING_SIGN2;
+        else if (ft->encoding.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;
+            ft->encoding.encoding = SOX_ENCODING_SIGN2;
         }
     }
     else {
         sox_report("Sun Audio driver only supports bytes and words");
-        ft->signal.size = SOX_SIZE_16BIT;
-        ft->signal.encoding = SOX_ENCODING_SIGN2;
+        ft->encoding.bits_per_sample = 16;
+        ft->encoding.encoding = SOX_ENCODING_SIGN2;
         samplesize = 16;
     }
 
@@ -276,9 +276,9 @@
     audio_if.play.precision = samplesize;
     audio_if.play.channels = ft->signal.channels;
     audio_if.play.sample_rate = ft->signal.rate;
-    if (ft->signal.encoding == SOX_ENCODING_ULAW)
+    if (ft->encoding.encoding == SOX_ENCODING_ULAW)
         encoding = AUDIO_ENCODING_ULAW;
-    else if (ft->signal.encoding == SOX_ENCODING_ALAW)
+    else if (ft->encoding.encoding == SOX_ENCODING_ALAW)
         encoding = AUDIO_ENCODING_ALAW;
     else
         encoding = AUDIO_ENCODING_LINEAR;
@@ -307,27 +307,19 @@
     return (SOX_SUCCESS);
 }
 
-/* Sun /dev/audio player */
-static const char *names[] = {
-  "sunau",
-  NULL
-};
-
-static sox_format_handler_t sox_sunau_format = {
-  names,
-  SOX_FILE_DEVICE,
-  sox_sunstartread,
-  sox_rawread,
-  sox_rawstopread,
-  sox_sunstartwrite,
-  sox_rawwrite,
-  sox_rawstopwrite,
-  NULL
-};
-
-const sox_format_handler_t *sox_sunau_format_fn(void);
-
-const sox_format_handler_t *sox_sunau_format_fn(void)
+SOX_FORMAT_HANDLER(sunau)
 {
-    return &sox_sunau_format;
+  static char const * const names[] = {"sunau", NULL};
+  static unsigned const write_encodings[] = {
+    SOX_ENCODING_ULAW, 8, 0,
+    SOX_ENCODING_ALAW, 8, 0,
+    SOX_ENCODING_SIGN2, 8, 16, 0,
+    0};
+  static sox_format_handler_t const handler = {
+    names, SOX_FILE_DEVICE,
+    sox_sunstartread, sox_rawread, sox_rawstopread,
+    sox_sunstartwrite, sox_rawwrite, sox_rawstopwrite,
+    NULL, write_encodings
+  };
+  return &handler;
 }
--- a/src/swap.c
+++ b/src/swap.c
@@ -62,13 +62,13 @@
     swap_t swap = (swap_t) effp->priv;
     int i;
 
-    if (effp->outinfo.channels == 1)
+    if (effp->out_signal.channels == 1)
     {
         sox_fail("Can't swap channels on mono data.");
         return (SOX_EOF);
     }
 
-    if (effp->outinfo.channels == 2)
+    if (effp->out_signal.channels == 2)
     {
         if (swap->def_opts)
         {
@@ -90,7 +90,7 @@
         swap->order[1]--;
     }
 
-    if (effp->outinfo.channels == 4)
+    if (effp->out_signal.channels == 4)
     {
         if (swap->def_opts)
         {
@@ -117,7 +117,7 @@
 
     }
 
-    for (i = 0; i < (int)effp->outinfo.channels; ++i)
+    for (i = 0; i < (int)effp->out_signal.channels; ++i)
       if (swap->order[i] != i)
         return SOX_SUCCESS;
 
@@ -134,7 +134,7 @@
     swap_t swap = (swap_t) effp->priv;
     int len, done;
 
-    switch (effp->outinfo.channels)
+    switch (effp->out_signal.channels)
     {
     case 2:
         /* Length to process will be buffer length / 2 since we
--- a/src/synth.c
+++ b/src/synth.c
@@ -9,10 +9,11 @@
  * for the consequences of using this software.
  */
 
+#include "sox_i.h"
+
 #include <string.h>
 #include <math.h>
 #include <ctype.h>
-#include "sox_i.h"
 
 typedef enum {
   synth_sine,
@@ -373,8 +374,8 @@
     create_channel(&synth->getopts_channels[synth->getopts_nchannels++]);
   }
 
-  if (!effp->ininfo.channels)
-    effp->ininfo.channels = synth->getopts_nchannels;
+  if (!effp->in_signal.channels)
+    effp->in_signal.channels = synth->getopts_nchannels;
 
   return SOX_SUCCESS;
 }
@@ -385,16 +386,15 @@
 {
   synth_t synth = (synth_t) effp->priv;
   size_t i;
-  int shift_for_max = (4 - min(effp->outinfo.size, 4)) << 3;
 
-  synth->max = (SOX_SAMPLE_MAX >> shift_for_max) << shift_for_max;
+  synth->max = sox_sample_max(effp->out_encoding);
   synth->samples_done = 0;
 
   if (synth->length_str)
-    if (sox_parsesamples(effp->ininfo.rate, synth->length_str, &synth->samples_to_do, 't') == NULL)
+    if (sox_parsesamples(effp->in_signal.rate, synth->length_str, &synth->samples_to_do, 't') == NULL)
       return sox_usage(effp);
 
-  synth->number_of_channels = effp->ininfo.channels;
+  synth->number_of_channels = effp->in_signal.channels;
   synth->channels = xcalloc(synth->number_of_channels, sizeof(*synth->channels));
   for (i = 0; i < synth->number_of_channels; ++i) {
     channel_t chan = &synth->channels[i];
@@ -558,17 +558,17 @@
     sox_size_t * isamp, sox_size_t * osamp)
 {
   synth_t synth = (synth_t) effp->priv;
-  unsigned len = min(*isamp, *osamp) / effp->ininfo.channels;
+  unsigned len = min(*isamp, *osamp) / effp->in_signal.channels;
   unsigned c, done;
   int result = SOX_SUCCESS;
 
   for (done = 0; done < len && result == SOX_SUCCESS; ++done) {
-    for (c = 0; c < effp->ininfo.channels; c++)
-      *obuf++ = do_synth(*ibuf++, synth, c, effp->ininfo.rate);
+    for (c = 0; c < effp->in_signal.channels; c++)
+      *obuf++ = do_synth(*ibuf++, synth, c, effp->in_signal.rate);
     if (++synth->samples_done == synth->samples_to_do)
       result = SOX_EOF;
   }
-  *isamp = *osamp = done * effp->ininfo.channels;
+  *isamp = *osamp = done * effp->in_signal.channels;
   return result;
 }
 
@@ -596,9 +596,9 @@
 const sox_effect_handler_t *sox_synth_effect_fn(void)
 {
   static sox_effect_handler_t handler = {
-    "synth",
-    "[len] {type [combine] [freq[-freq2] [off [ph [p1 [p2 [p3]]]]]]}",
-    SOX_EFF_MCHAN | SOX_EFF_PREC, getopts, start, flow, 0, stop, kill
+    "synth", "[len] {type [combine] [freq[-freq2] [off [ph [p1 [p2 [p3]]]]]]}",
+    SOX_EFF_MCHAN | SOX_EFF_PREC |SOX_EFF_LENGTH,
+    getopts, start, flow, 0, stop, kill
   };
   return &handler;
 }
--- a/src/tempo.c
+++ b/src/tempo.c
@@ -237,8 +237,8 @@
   if (p->factor == 1)
     return SOX_EFF_NULL;
 
-  p->tempo = tempo_create(effp->ininfo.channels);
-  tempo_setup(p->tempo, effp->ininfo.rate, p->quick_search, p->factor,
+  p->tempo = tempo_create(effp->in_signal.channels);
+  tempo_setup(p->tempo, effp->in_signal.rate, p->quick_search, p->factor,
       p->segment_ms, p->search_ms, p->overlap_ms);
   return SOX_SUCCESS;
 }
@@ -249,14 +249,14 @@
   priv_t * p = (priv_t *) effp->priv;
   sox_size_t i;
   /* odone must be size_t 'cos tempo_output arg. is. (!= sox_size_t on amd64) */
-  size_t odone = *osamp /= effp->ininfo.channels;
+  size_t odone = *osamp /= effp->in_signal.channels;
   float const * s = tempo_output(p->tempo, NULL, &odone);
 
-  for (i = 0; i < odone * effp->ininfo.channels; ++i)
+  for (i = 0; i < odone * effp->in_signal.channels; ++i)
     *obuf++ = SOX_FLOAT_32BIT_TO_SAMPLE(*s++, effp->clips);
 
   if (*isamp && odone < *osamp) {
-    float * t = tempo_input(p->tempo, NULL, *isamp / effp->ininfo.channels);
+    float * t = tempo_input(p->tempo, NULL, *isamp / effp->in_signal.channels);
     for (i = *isamp; i; --i)
       *t++ = SOX_SAMPLE_TO_FLOAT_32BIT(*ibuf++, effp->clips);
     tempo_process(p->tempo);
@@ -263,7 +263,7 @@
   }
   else *isamp = 0;
 
-  *osamp = odone * effp->ininfo.channels;
+  *osamp = odone * effp->in_signal.channels;
   return SOX_SUCCESS;
 }
 
--- a/src/tests.sh
+++ b/src/tests.sh
@@ -2,18 +2,22 @@
 #
 # SoX Regression Test script: Lossless file conversion
 
-# Options:
-#verbose=-V
-#all=all
-
 bindir="."
 builddir="."
 srcdir="."
 
-# Allow user to override paths.  Useful for testing an installed
-# sox.
+# Set options & allow user to override paths.  Useful for testing an
+# installed sox.
 while [ $# -ne 0 ]; do
     case "$1" in
+        -V)
+        verbose=$1
+        ;;
+
+        -a)      # Perform each test up to 3 times with different #s of
+        all=all  # channels; probably enough coverage without this though.
+        ;;
+
         --bindir=*)
         bindir=`echo $1 | sed 's/.*=//'`
         ;;
@@ -60,8 +64,7 @@
     u2 ) formatText="unsigned word" ;;
     raw) formatText="float"; formatFlags="-f -4" ;;
     Raw) formatText="double"; formatFlags="-f -8" ;;
-    au ) formatFlags="-s" ;;
-    Wav) formatFlags="-u -1" ;;
+    wav1u) formatFlags="-1 -u"; formatExt="wav"  ;;
     s1X ) formatText="signed byte (swap bits)"; formatExt="s1"; formatFlags="-X" ;;
     s1N ) formatText="signed byte (swap nibbles)"; formatExt="s1"; formatFlags="-N" ;;
     s1XN ) formatText="signed byte (swap nibbles and bits)"; formatExt="s1"; formatFlags="-X -N" ;;
@@ -68,6 +71,15 @@
   esac
 }
   
+execute() {
+  if [ "${verbose}x" != "x" ] ; then
+    echo $*
+  fi
+  cmd=$1
+  shift
+  echo $* | xargs $cmd
+}
+
 convertToAndFrom () {
   while [ $# != 0 ]; do
       if [ "${skip}x" != "x" ] ; then
@@ -77,12 +89,9 @@
       if [ "${format1_skip}x" = "x" -a "${from_skip}x" = "x" ] ; then
         getFormat ${format1}; format1Ext=$formatExt; format1Text=$formatText; format1Flags=$formatFlags
         getFormat         $1; format2Ext=$formatExt; format2Text=$formatText; format2Flags=$formatFlags
-        echo ${bindir}/sox -c $channels -r $rate -n $format1Flags input.$format1Ext synth $samples's' sin 300-3300 noise trapezium
-        echo ${bindir}/sox $verbose -r $rate -c $channels $format1Flags input.$format1Ext $format2Flags intermediate.$format2Ext
-        echo ${bindir}/sox $verbose -r $rate -c $channels $format2Flags intermediate.$format2Ext $format1Flags output.$format1Ext
-        ${bindir}/sox -R -c $channels -r $rate -n $format1Flags input.$format1Ext synth $samples's' sin 300-3300 noise trapezium
-        ${bindir}/sox $verbose -r $rate -c $channels $format1Flags input.$format1Ext $format2Flags intermediate.$format2Ext
-        ${bindir}/sox $verbose -r $rate -c $channels $format2Flags intermediate.$format2Ext $format1Flags output.$format1Ext
+        execute ${bindir}/sox $verbose -R -r $rate -c $channels -n $format1Flags input.$format1Ext synth $samples's' sin 300-3300 noise trapezium
+        execute ${bindir}/sox $verbose -R -r $rate -c $channels $format1Flags input.$format1Ext $format2Flags intermediate.$format2Ext
+        execute ${bindir}/sox $verbose -R -r $rate -c $channels $format2Flags intermediate.$format2Ext $format1Flags output.$format1Ext
         intermediateReference=intermediate`echo "$channels $rate $format1Flags $format1Ext $format2Flags"|tr " " "_"`.$format2Ext
 
 	# Uncomment to generate new reference files
@@ -91,7 +100,7 @@
 
         if test -f $intermediateReference
         then
-          if ! cmp -s $intermediateReference intermediate.$format2Ext
+          if ! execute cmp -s $intermediateReference intermediate.$format2Ext
           then
             echo "*FAIL* channels=$channels \"$format1Text\" ---> \"$format2Text\"."
             exit 1    # This allows failure inspection.
@@ -98,7 +107,7 @@
           fi
         fi
 
-        if cmp -s input.$format1Ext output.$format1Ext
+        if execute cmp -s input.$format1Ext output.$format1Ext
         then
           echo "ok     channels=$channels \"$format1Text\" <--> \"$format2Text\"."
         else
@@ -130,12 +139,12 @@
   format1=ul
   convertToAndFrom ul s2 u2 s4 raw Raw dat aiff aifc flac caf sph
 
-  format1=Wav
-  convertToAndFrom Wav aiff aifc au dat sf flac caf sph
+  format1=wav1u
+  convertToAndFrom wav1u aiff aifc au dat sf flac caf sph
 }
 
 do_twochannel_formats () {
-  format1=Wav
+  format1=wav1u
   convertToAndFrom avr maud
   (rate=8000; convertToAndFrom voc) || exit 1      # Fixed rate
   (samples=23492; convertToAndFrom 8svx) || exit 1 # Even number of samples only
@@ -148,7 +157,7 @@
   format1=ima
   convertToAndFrom ima s2 u2 s3 u3 s4 u4 raw Raw dat au aiff aifc flac caf # FIXME: vox wav
 
-  format1=Wav
+  format1=wav1u
   convertToAndFrom smp s1 s1X s1N s1XN sndt
   (rate=5512; convertToAndFrom hcom) || exit 1     # Fixed rate
 
@@ -183,9 +192,9 @@
 
 ${builddir}/sox_sample_test || exit 1
 
-# Don't test unsupported stuff
-${bindir}/sox --help | grep -q "^AUDIO FILE.*\<flac\>" || skip="flac $skip"
-${bindir}/sox --help | grep -q "^AUDIO FILE.*\<caf\>" || skip="caf $skip"
+# Don't try to test unsupported stuff
+${bindir}/sox --help|grep "^AUDIO FILE.*\<flac\>">/dev/null || skip="flac $skip"
+${bindir}/sox --help|grep "^AUDIO FILE.*\<caf\>" >/dev/null || skip="caf $skip"
 
 rate=44100
 samples=23493
--- a/src/trim.c
+++ b/src/trim.c
@@ -62,15 +62,15 @@
 {
     trim_t trim = (trim_t) effp->priv;
 
-    if (sox_parsesamples(effp->ininfo.rate, trim->start_str,
+    if (sox_parsesamples(effp->in_signal.rate, trim->start_str,
                         &trim->start, 't') == NULL)
       return sox_usage(effp);
     /* Account for # of channels */
-    trim->start *= effp->ininfo.channels;
+    trim->start *= effp->in_signal.channels;
 
     if (trim->length_str)
     {
-        if (sox_parsesamples(effp->ininfo.rate, trim->length_str,
+        if (sox_parsesamples(effp->in_signal.rate, trim->length_str,
                     &trim->length, 't') == NULL)
           return sox_usage(effp);
     }
@@ -78,7 +78,7 @@
         trim->length = 0;
 
     /* Account for # of channels */
-    trim->length *= effp->ininfo.channels;
+    trim->length *= effp->in_signal.channels;
 
     trim->index = 0;
     trim->trimmed = 0;
--- a/src/tx16w.c
+++ b/src/tx16w.c
@@ -33,12 +33,12 @@
  *
  */
 
-#define TXMAXLEN 0x3FF80
-
+#include "sox_i.h"
 #include <stdio.h>
 #include <string.h>
-#include "sox_i.h"
 
+#define TXMAXLEN 0x3FF80
+
 /* Private data for TX16 file */
 typedef struct txwstuff {
         sox_size_t rest;                 /* bytes remaining in sample file */
@@ -59,7 +59,7 @@
 static const unsigned char magic1[4] = {0, 0x06, 0x10, 0xF6};
 static const unsigned char magic2[4] = {0, 0x52, 0x00, 0x52};
 
-/* SJB: dangerous static variables */
+/* FIXME SJB: dangerous static variables */
 static sox_size_t tx16w_len=0;
 static sox_size_t writedone=0;
 
@@ -70,7 +70,7 @@
  *      size and encoding of samples,
  *      mono/stereo/quad.
  */
-static int sox_txwstartread(sox_format_t * ft)
+static int startread(sox_format_t * ft)
 {
     int c;
     char filetype[7];
@@ -169,8 +169,8 @@
     sox_debug("Sample rate = %g", ft->signal.rate);
 
     ft->signal.channels = 1 ; /* not sure about stereo sample data yet ??? */
-    ft->signal.size = SOX_SIZE_16BIT; /* this is close enough */
-    ft->signal.encoding = SOX_ENCODING_SIGN2;
+    ft->encoding.bits_per_sample = 16; /* this is close enough */
+    ft->encoding.encoding = SOX_ENCODING_SIGN2;
 
     return(SOX_SUCCESS);
 }
@@ -182,7 +182,7 @@
  * Return number of samples read.
  */
 
-static sox_size_t sox_txwread(sox_format_t * ft, sox_sample_t *buf, sox_size_t len)
+static sox_size_t read_samples(sox_format_t * ft, sox_sample_t *buf, sox_size_t len)
 {
     txw_t sk = (txw_t) ft->priv;
     sox_size_t done = 0;
@@ -232,7 +232,7 @@
     return done;
 }
 
-static int sox_txwstartwrite(sox_format_t * ft)
+static int startwrite(sox_format_t * ft)
 {
     struct WaveHeader_ WH;
 
@@ -243,10 +243,6 @@
     if (ft->signal.channels != 1)
         sox_report("tx16w is overriding output format to 1 channel.");
     ft->signal.channels = 1 ; /* not sure about stereo sample data yet ??? */
-    if (ft->signal.size != SOX_SIZE_16BIT || ft->signal.encoding != SOX_ENCODING_SIGN2)
-        sox_report("tx16w is overriding output format to size Signed Word format.");
-    ft->signal.size = SOX_SIZE_16BIT; /* this is close enough */
-    ft->signal.encoding = SOX_ENCODING_SIGN2;
 
     /* If you have to seek around the output file */
     if (! ft->seekable)
@@ -263,30 +259,32 @@
     return(SOX_SUCCESS);
 }
 
-static sox_size_t sox_txwwrite(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len)
+static sox_size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len)
 {
-    sox_size_t i;
-    sox_sample_t w1,w2;
+  sox_size_t i;
+  sox_sample_t w1,w2;
 
-    tx16w_len += len;
-    if (tx16w_len > TXMAXLEN) return 0;
-
-    for (i=0;i<len;i+=2) {
-        w1 =  *buf++ >> 20;
-        if (i+1==len)
-            w2 = 0;
-        else {
-            w2 =  *buf++ >> 20;
-        }
-        sox_writesb(ft, (w1 >> 4) & 0xFF);
-        sox_writesb(ft, (((w1 & 0x0F) << 4) | (w2 & 0x0F)) & 0xFF);
-        sox_writesb(ft, (w2 >> 4) & 0xFF);
-        writedone += 3;
-    }
-    return(len);
+  tx16w_len += len;
+  if (tx16w_len > TXMAXLEN) {
+    sox_fail_errno(ft, SOX_EOF, "Audio too long for TX16W file");
+    return 0;
+  }
+  for (i=0;i<len;i+=2) {
+      w1 =  *buf++ >> 20;
+      if (i+1==len)
+          w2 = 0;
+      else {
+          w2 =  *buf++ >> 20;
+      }
+      sox_writesb(ft, (w1 >> 4) & 0xFF);
+      sox_writesb(ft, (((w1 & 0x0F) << 4) | (w2 & 0x0F)) & 0xFF);
+      sox_writesb(ft, (w2 >> 4) & 0xFF);
+      writedone += 3;
+  }
+  return(len);
 }
 
-static int sox_txwstopwrite(sox_format_t * ft)
+static int stopwrite(sox_format_t * ft)
 {
     struct WaveHeader_ WH;
     int AttackLength, LoopLength, i;
@@ -363,27 +361,15 @@
     return(SOX_SUCCESS);
 }
 
-/* Yamaha TX16W and SY99 waves */
-static const char *txwnames[] = {
-  "txw",
-  NULL
-};
-
-static sox_format_handler_t sox_txw_format = {
-   txwnames,
-   0,
-   sox_txwstartread,
-   sox_txwread,
-   NULL,
-   sox_txwstartwrite,
-   sox_txwwrite,
-   sox_txwstopwrite,
-   NULL
-};
-
-const sox_format_handler_t *sox_txw_format_fn(void);
-
-const sox_format_handler_t *sox_txw_format_fn(void)
+SOX_FORMAT_HANDLER(txw)
 {
-    return &sox_txw_format;
+  static char const * const names[] = {"txw", NULL};
+  static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 16, 0, 0};
+  static sox_format_handler_t const handler = {
+    names, 0,
+    startread, read_samples, NULL,
+    startwrite, write_samples, stopwrite,
+    NULL, write_encodings, NULL
+  };
+  return &handler;
 }
--- a/src/u1-fmt.c
+++ b/src/u1-fmt.c
@@ -1,14 +1,22 @@
 /*
- * libSoX u1 raw file format
+ * File formats: raw         (c) 2007-8 SoX contributors
  *
- * Copyright 2007 Lance Norskog And Sundry Contributors
- * This source code is freely redistributable and may be used for
- * any purpose.  This copyright notice must be maintained.
- * Lance Norskog And Sundry Contributors are not responsible for
- * the consequences of using this software.
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
  */
 
 #include "sox_i.h"
 #include "raw.h"
 
-RAW_FORMAT3(u1, "ub", "sou", "fssd", 8BIT, 0, UNSIGNED)
+RAW_FORMAT3(u1, "ub", "sou", "fssd", 8, 0, UNSIGNED)
--- a/src/u2-fmt.c
+++ b/src/u2-fmt.c
@@ -1,14 +1,22 @@
 /*
- * libSoX u2 raw file format
+ * File formats: raw         (c) 2007-8 SoX contributors
  *
- * Copyright 2007 Lance Norskog And Sundry Contributors
- * This source code is freely redistributable and may be used for
- * any purpose.  This copyright notice must be maintained.
- * Lance Norskog And Sundry Contributors are not responsible for
- * the consequences of using this software.
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
  */
 
 #include "sox_i.h"
 #include "raw.h"
 
-RAW_FORMAT1(u2, "uw", 16BIT, 0, UNSIGNED)
+RAW_FORMAT1(u2, "uw", 16, 0, UNSIGNED)
--- a/src/u3-fmt.c
+++ b/src/u3-fmt.c
@@ -1,14 +1,22 @@
 /*
- * libSoX u3 raw file format
+ * File formats: raw         (c) 2007-8 SoX contributors
  *
- * Copyright 2007 Lance Norskog And Sundry Contributors
- * This source code is freely redistributable and may be used for
- * any purpose.  This copyright notice must be maintained.
- * Lance Norskog And Sundry Contributors are not responsible for
- * the consequences of using this software.
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
  */
 
 #include "sox_i.h"
 #include "raw.h"
 
-RAW_FORMAT(u3, 24BIT, 0, UNSIGNED)
+RAW_FORMAT(u3, 24, 0, UNSIGNED)
--- a/src/u4-fmt.c
+++ b/src/u4-fmt.c
@@ -1,14 +1,22 @@
 /*
- * libSoX u4 raw file format
+ * File formats: raw         (c) 2007-8 SoX contributors
  *
- * Copyright 2007 Lance Norskog And Sundry Contributors
- * This source code is freely redistributable and may be used for
- * any purpose.  This copyright notice must be maintained.
- * Lance Norskog And Sundry Contributors are not responsible for
- * the consequences of using this software.
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
  */
 
 #include "sox_i.h"
 #include "raw.h"
 
-RAW_FORMAT(u4, 32BIT, 0, UNSIGNED)
+RAW_FORMAT(u4, 32, 0, UNSIGNED)
--- a/src/ul-fmt.c
+++ b/src/ul-fmt.c
@@ -1,14 +1,22 @@
 /*
- * libSoX ul raw file format
+ * File formats: raw         (c) 2007-8 SoX contributors
  *
- * Copyright 2007 Lance Norskog And Sundry Contributors
- * This source code is freely redistributable and may be used for
- * any purpose.  This copyright notice must be maintained.
- * Lance Norskog And Sundry Contributors are not responsible for
- * the consequences of using this software.
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
  */
 
 #include "sox_i.h"
 #include "raw.h"
 
-RAW_FORMAT(ul, 8BIT, 0, ULAW)
+RAW_FORMAT(ul, 8, 0, ULAW)
--- a/src/voc.c
+++ b/src/voc.c
@@ -258,12 +258,12 @@
         }
 
         /* setup word length of data */
-        ft->signal.size = v->size;
+        ft->encoding.bits_per_sample = v->size;
 
         /* ANN:  Check VOC format and map to the proper libSoX format value */
         switch (v->format) {
         case VOC_FMT_LIN8U:      /*     0    8 bit unsigned linear PCM */
-            ft->signal.encoding = SOX_ENCODING_UNSIGNED;
+            ft->encoding.encoding = SOX_ENCODING_UNSIGNED;
             break;
         case VOC_FMT_CRLADPCM4:  /*     1    Creative 8-bit to 4-bit ADPCM */
             sox_fail ("Unsupported VOC format CRLADPCM4 %d", v->format);
@@ -278,13 +278,13 @@
             rtn=SOX_EOF;
             break;
         case VOC_FMT_LIN16:      /*     4    16-bit signed PCM */
-            ft->signal.encoding = SOX_ENCODING_SIGN2;
+            ft->encoding.encoding = SOX_ENCODING_SIGN2;
             break;
         case VOC_FMT_ALAW:       /*     6    CCITT a-Law 8-bit PCM */
-            ft->signal.encoding = SOX_ENCODING_ALAW;
+            ft->encoding.encoding = SOX_ENCODING_ALAW;
             break;
         case VOC_FMT_MU255:      /*     7    CCITT u-Law 8-bit PCM */
-            ft->signal.encoding = SOX_ENCODING_ULAW;
+            ft->encoding.encoding = SOX_ENCODING_ULAW;
             break;
         case VOC_FMT_CRLADPCM4A: /*0x200    Creative 16-bit to 4-bit ADPCM */
             sox_fail ("Unsupported VOC format CRLADPCM4A %d", v->format);
@@ -360,7 +360,7 @@
 
                 /* Read the data in the file */
                 switch(v->size) {
-                case SOX_SIZE_BYTE:
+                case 8:
                     if (sox_readb(ft, &uc) == SOX_EOF) {
                         sox_warn("VOC input: short file");
                         v->rest = 0;
@@ -376,7 +376,7 @@
                         *buf++ = SOX_UNSIGNED_8BIT_TO_SAMPLE(uc,);
                     }
                     break;
-                case SOX_SIZE_16BIT:
+                case 16:
                     sox_readw(ft, (unsigned short *)&sw);
                     if (sox_eof(ft))
                         {
@@ -428,10 +428,6 @@
         sox_writew(ft, 0x10a);              /* major/minor version number */
         sox_writew(ft, 0x1129);          /* checksum of version number */
 
-        if (ft->signal.size == SOX_SIZE_BYTE)
-          ft->signal.encoding = SOX_ENCODING_UNSIGNED;
-        else
-          ft->signal.encoding = SOX_ENCODING_SIGN2;
         if (ft->signal.channels == 0)
                 ft->signal.channels = 1;
 
@@ -455,7 +451,7 @@
         }
         v->samples += len;
         while(done < len) {
-          if (ft->signal.size == SOX_SIZE_BYTE) {
+          if (ft->encoding.bits_per_sample == 8) {
             uc = SOX_SAMPLE_TO_UNSIGNED_8BIT(*buf++, ft->clips);
             sox_writeb(ft, uc);
           } else {
@@ -482,17 +478,17 @@
         if (v->silent) {
                 sox_writesw(ft, v->samples);
         } else {
-          if (ft->signal.size == SOX_SIZE_BYTE) {
+          if (ft->encoding.bits_per_sample == 8) {
             if (ft->signal.channels > 1) {
               sox_seeki(ft, 8, 1); /* forward 7 + 1 for new block header */
             }
           }
                 v->samples += 2;                /* adjustment: SBDK pp. 3-5 */
-                datum = (v->samples * ft->signal.size) & 0xff;
+                datum = (v->samples * (ft->encoding.bits_per_sample >> 3)) & 0xff;
                 sox_writesb(ft, datum);       /* low byte of length */
-                datum = ((v->samples * ft->signal.size) >> 8) & 0xff;
+                datum = ((v->samples * (ft->encoding.bits_per_sample >> 3)) >> 8) & 0xff;
                 sox_writesb(ft, datum);  /* middle byte of length */
-                datum = ((v->samples  * ft->signal.size)>> 16) & 0xff;
+                datum = ((v->samples  * (ft->encoding.bits_per_sample >> 3))>> 16) & 0xff;
                 sox_writesb(ft, datum); /* high byte of length */
         }
 }
@@ -587,7 +583,7 @@
                         }
                         v->extended = 0;
                         v->rest = sblen - 2;
-                        v->size = SOX_SIZE_BYTE;
+                        v->size = 8;
                         return (SOX_SUCCESS);
                 case VOC_DATA_16:
                         sox_readdw(ft, &new_rate_32);
@@ -609,8 +605,8 @@
                         sox_readb(ft, &uc);
                         switch (uc)
                         {
-                            case 8:     v->size = SOX_SIZE_BYTE; break;
-                            case 16:    v->size = SOX_SIZE_16BIT; break;
+                            case 8:     v->size = 8; break;
+                            case 16:    v->size = 16; break;
                             default:
                                 sox_fail_errno(ft,SOX_EFMT,
                                               "Don't understand size %d", uc);
@@ -751,7 +747,7 @@
                 sox_writeb(ft, 0);               /* Period length */
                 sox_writesb(ft, v->rate);         /* Rate code */
         } else {
-          if (ft->signal.size == SOX_SIZE_BYTE) {
+          if (ft->encoding.bits_per_sample == 8) {
             /* 8-bit sample section.  By always setting the correct     */
             /* rate value in the DATA block (even when its preceeded    */
             /* by an EXTENDED block) old software can still play stereo */
@@ -793,27 +789,18 @@
         }
 }
 
-/* Sound Blaster .VOC */
-static const char *vocnames[] = {
-  "voc",
-  NULL
-};
-
-static sox_format_handler_t sox_voc_format = {
-  vocnames,
-  SOX_FILE_LIT_END,
-  sox_vocstartread,
-  sox_vocread,
-  NULL,
-  sox_vocstartwrite,
-  sox_vocwrite,
-  sox_vocstopwrite,
-  NULL
-};
-
-const sox_format_handler_t *sox_voc_format_fn(void);
-
-const sox_format_handler_t *sox_voc_format_fn(void)
+SOX_FORMAT_HANDLER(voc)
 {
-    return &sox_voc_format;
+  static char const * const names[] = {"voc", NULL};
+  static unsigned const write_encodings[] = {
+    SOX_ENCODING_SIGN2, 16, 0,
+    SOX_ENCODING_UNSIGNED, 8, 0,
+    0};
+  static sox_format_handler_t const handler = {
+    names, SOX_FILE_LIT_END|SOX_FILE_MONO|SOX_FILE_STEREO,
+    sox_vocstartread, sox_vocread, NULL,
+    sox_vocstartwrite, sox_vocwrite, sox_vocstopwrite,
+    NULL, write_encodings, NULL
+  };
+  return &handler;
 }
--- a/src/vorbis.c
+++ b/src/vorbis.c
@@ -117,8 +117,7 @@
 
   /* Record audio info */
   ft->signal.rate = vi->rate;
-  ft->signal.size = SOX_SIZE_16BIT;
-  ft->signal.encoding = SOX_ENCODING_VORBIS;
+  ft->encoding.encoding = SOX_ENCODING_VORBIS;
   ft->signal.channels = vi->channels;
 
   /* ov_pcm_total doesn't work on non-seekable files so
@@ -178,7 +177,7 @@
  * Return number of samples read.
  */
 
-static sox_size_t read(sox_format_t * ft, sox_sample_t * buf, sox_size_t len)
+static sox_size_t read_samples(sox_format_t * ft, sox_sample_t * buf, sox_size_t len)
 {
   vorbis_t vb = (vorbis_t) ft->priv;
   sox_size_t i;
@@ -281,8 +280,7 @@
   long rate;
   double quality = 3;           /* Default compression quality gives ~112kbps */
 
-  ft->signal.size = SOX_SIZE_16BIT;
-  ft->signal.encoding = SOX_ENCODING_VORBIS;
+  ft->encoding.encoding = SOX_ENCODING_VORBIS;
 
   /* Allocate memory for all of the structures */
   ve = vb->vorbis_enc_data = (vorbis_enc_t *) xmalloc(sizeof(vorbis_enc_t));
@@ -296,13 +294,13 @@
       "Error setting-up Ogg Vorbis encoder; check sample-rate & # of channels");
 
   /* Use encoding to average bit rate of VBR as specified by the -C option */
-  if (ft->signal.compression != HUGE_VAL) {
-    if (ft->signal.compression < -1 || ft->signal.compression > 10) {
+  if (ft->encoding.compression != HUGE_VAL) {
+    if (ft->encoding.compression < -1 || ft->encoding.compression > 10) {
       sox_fail_errno(ft, SOX_EINVAL,
                      "Vorbis compression quality nust be between -1 and 10");
       return SOX_EOF;
     }
-    quality = ft->signal.compression;
+    quality = ft->encoding.compression;
   }
 #include "vorbis1.h"
 
@@ -320,7 +318,7 @@
   return (SOX_SUCCESS);
 }
 
-static sox_size_t write(sox_format_t * ft, const sox_sample_t * buf,
+static sox_size_t write_samples(sox_format_t * ft, const sox_sample_t * buf,
                         sox_size_t len)
 {
   vorbis_t vb = (vorbis_t) ft->priv;
@@ -377,7 +375,7 @@
   vorbis_enc_t *ve = vb->vorbis_enc_data;
 
   /* Close out the remaining data */
-  write(ft, NULL, 0);
+  write_samples(ft, NULL, 0);
 
   ogg_stream_clear(&ve->os);
   vorbis_block_clear(&ve->vb);
@@ -394,16 +392,15 @@
   return ov_pcm_seek(vb->vf, (ogg_int64_t)(offset / ft->signal.channels))? SOX_EOF:SOX_SUCCESS;
 }
 
-const sox_format_handler_t *sox_vorbis_format_fn(void);
-
-const sox_format_handler_t *sox_vorbis_format_fn(void)
+SOX_FORMAT_HANDLER(vorbis)
 {
   static const char *names[] = {"vorbis", "ogg", NULL};
+  static unsigned encodings[] = {SOX_ENCODING_VORBIS, 0, 0};
   static sox_format_handler_t handler = {
     names, 0,
-    startread, read, stopread,
-    startwrite, write, stopwrite,
-    seek
+    startread, read_samples, stopread,
+    startwrite, write_samples, stopwrite,
+    seek, encodings, NULL
   };
   return &handler;
 }
--- a/src/vox-fmt.c
+++ b/src/vox-fmt.c
@@ -1,32 +1,33 @@
 /*
- * SOX file format handler for Dialogic/Oki ADPCM VOX files.
+ * File format: raw Dialogic/OKI ADPCM        (c) 2007-8 SoX contributors
  *
- * Copyright 1991-2007 Tony Seebregts And Sundry Contributors
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
  *
- * This source code is freely redistributable and may be used for any
- * purpose.  This copyright notice must be maintained.
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
+ * General Public License for more details.
  *
- * Tony Seebregts And Sundry Contributors are not responsible for the
- * consequences of using this software.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
  */
 
 #include "sox_i.h"
 #include "vox.h"
- 
-const sox_format_handler_t *sox_vox_format_fn(void);
 
-const sox_format_handler_t *sox_vox_format_fn(void)
+SOX_FORMAT_HANDLER(vox)
 {
-  static char const * names[] = {"vox", NULL};
+  static char const * const names[] = {"vox", NULL};
+  static unsigned const write_encodings[] = {SOX_ENCODING_OKI_ADPCM, 4, 0, 0};
   static sox_format_handler_t handler = {
-    names, 0,
-    sox_vox_start,
-    sox_vox_read,
-    sox_vox_stopread,
-    sox_vox_start,
-    sox_vox_write,
-    sox_vox_stopwrite,
-    NULL
+    names, SOX_FILE_MONO,
+    sox_vox_start, sox_vox_read, sox_vox_stopread,
+    sox_vox_start, sox_vox_write, sox_vox_stopwrite,
+    sox_rawseek, write_encodings, NULL
   };
   return &handler;
 }
--- a/src/vox.c
+++ b/src/vox.c
@@ -1,5 +1,5 @@
 /*
- * SOX file format handler for Dialogic/Oki ADPCM VOX files.
+ * SoX file format handler for Dialogic/Oki ADPCM VOX files.
  *
  * Copyright 1991-2007 Tony Seebregts And Sundry Contributors
  *
--- a/src/vox.h
+++ b/src/vox.h
@@ -1,13 +1,19 @@
 /*
- * SOX file format handler for Dialogic/Oki ADPCM VOX files.
+ * (c) 2007-8 SoX contributors
  *
- * Copyright 1991-2007 Tony Seebregts And Sundry Contributors
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
  *
- * This source code is freely redistributable and may be used for any
- * purpose.  This copyright notice must be maintained.
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
+ * General Public License for more details.
  *
- * Tony Seebregts And Sundry Contributors are not responsible for the
- * consequences of using this software.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
  */
 
 int sox_vox_start(sox_format_t * ft);
--- a/src/wav.c
+++ b/src/wav.c
@@ -11,6 +11,8 @@
  *
  */
 
+#include "sox_i.h"
+
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -19,7 +21,6 @@
 #include <unistd.h>             /* For SEEK_* defines if not found in stdio */
 #endif
 
-#include "sox_i.h"
 #include "wav.h"
 #include "ima_rw.h"
 #include "adpcm.h"
@@ -384,12 +385,11 @@
  *      size and encoding of samples, 
  *      mono/stereo/quad.
  */
-static int sox_wavstartread(sox_format_t * ft) 
+static int startread(sox_format_t * ft) 
 {
     wav_t       wav = (wav_t) ft->priv;
     char        magic[5];
     uint32_t    len;
-    int         rc;
 
     /* wave file characteristics */
     uint32_t      dwRiffLength;
@@ -420,11 +420,11 @@
     if (strncmp("RIFX", magic, 4) == 0) 
     {
         sox_debug("Found RIFX header");
-        ft->signal.reverse_bytes = SOX_IS_LITTLEENDIAN;
+        ft->encoding.reverse_bytes = SOX_IS_LITTLEENDIAN;
     }
     else
     {
-        ft->signal.reverse_bytes = SOX_IS_BIGENDIAN;
+        ft->encoding.reverse_bytes = SOX_IS_BIGENDIAN;
     }
 
     sox_readdw(ft, &dwRiffLength);
@@ -499,68 +499,44 @@
         
     case WAVE_FORMAT_PCM:
         /* Default (-1) depends on sample size.  Set that later on. */
-        if (ft->signal.encoding != SOX_ENCODING_UNKNOWN && ft->signal.encoding != SOX_ENCODING_UNSIGNED &&
-            ft->signal.encoding != SOX_ENCODING_SIGN2)
+        if (ft->encoding.encoding != SOX_ENCODING_UNKNOWN && ft->encoding.encoding != SOX_ENCODING_UNSIGNED &&
+            ft->encoding.encoding != SOX_ENCODING_SIGN2)
             sox_report("User options overriding encoding read in .wav header");
-
-        /* Needed by rawread() functions */
-        rc = sox_rawstartread(ft);
-        if (rc)
-            return rc;
-
         break;
         
     case WAVE_FORMAT_IMA_ADPCM:
-        if (ft->signal.encoding == SOX_ENCODING_UNKNOWN || ft->signal.encoding == SOX_ENCODING_IMA_ADPCM)
-            ft->signal.encoding = SOX_ENCODING_IMA_ADPCM;
+        if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN || ft->encoding.encoding == SOX_ENCODING_IMA_ADPCM)
+            ft->encoding.encoding = SOX_ENCODING_IMA_ADPCM;
         else
             sox_report("User options overriding encoding read in .wav header");
         break;
 
     case WAVE_FORMAT_ADPCM:
-        if (ft->signal.encoding == SOX_ENCODING_UNKNOWN || ft->signal.encoding == SOX_ENCODING_ADPCM)
-            ft->signal.encoding = SOX_ENCODING_ADPCM;
+        if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN || ft->encoding.encoding == SOX_ENCODING_MS_ADPCM)
+            ft->encoding.encoding = SOX_ENCODING_MS_ADPCM;
         else
             sox_report("User options overriding encoding read in .wav header");
         break;
 
     case WAVE_FORMAT_IEEE_FLOAT:
-        if (ft->signal.encoding == SOX_ENCODING_UNKNOWN || ft->signal.encoding == SOX_ENCODING_FLOAT)
-            ft->signal.encoding = SOX_ENCODING_FLOAT;
+        if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN || ft->encoding.encoding == SOX_ENCODING_FLOAT)
+            ft->encoding.encoding = SOX_ENCODING_FLOAT;
         else
             sox_report("User options overriding encoding read in .wav header");
-
-        /* Needed by rawread() functions */
-        rc = sox_rawstartread(ft);
-        if (rc)
-            return rc;
-
         break;
         
     case WAVE_FORMAT_ALAW:
-        if (ft->signal.encoding == SOX_ENCODING_UNKNOWN || ft->signal.encoding == SOX_ENCODING_ALAW)
-            ft->signal.encoding = SOX_ENCODING_ALAW;
+        if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN || ft->encoding.encoding == SOX_ENCODING_ALAW)
+            ft->encoding.encoding = SOX_ENCODING_ALAW;
         else
             sox_report("User options overriding encoding read in .wav header");
-
-        /* Needed by rawread() functions */
-        rc = sox_rawstartread(ft);
-        if (rc)
-            return rc;
-
         break;
         
     case WAVE_FORMAT_MULAW:
-        if (ft->signal.encoding == SOX_ENCODING_UNKNOWN || ft->signal.encoding == SOX_ENCODING_ULAW)
-            ft->signal.encoding = SOX_ENCODING_ULAW;
+        if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN || ft->encoding.encoding == SOX_ENCODING_ULAW)
+            ft->encoding.encoding = SOX_ENCODING_ULAW;
         else
             sox_report("User options overriding encoding read in .wav header");
-
-        /* Needed by rawread() functions */
-        rc = sox_rawstartread(ft);
-        if (rc)
-            return rc;
-
         break;
         
     case WAVE_FORMAT_OKI_ADPCM:
@@ -572,8 +548,8 @@
     case WAVE_FORMAT_DOLBY_AC2:
         return wavfail(ft, "Dolby AC2");
     case WAVE_FORMAT_GSM610:
-        if (ft->signal.encoding == SOX_ENCODING_UNKNOWN || ft->signal.encoding == SOX_ENCODING_GSM )
-            ft->signal.encoding = SOX_ENCODING_GSM;
+        if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN || ft->encoding.encoding == SOX_ENCODING_GSM )
+            ft->encoding.encoding = SOX_ENCODING_GSM;
         else
             sox_report("User options overriding encoding read in .wav header");
         break;
@@ -689,7 +665,7 @@
             if (errct) sox_warn("base iCoefs differ in %d/14 positions",errct);
         }
 
-        bytespersample = SOX_SIZE_16BIT;  /* AFTER de-compression */
+        bytespersample = 2;  /* AFTER de-compression */
         break;
 
     case WAVE_FORMAT_IMA_ADPCM:
@@ -720,7 +696,7 @@
 
         wav->samples = (short *)xmalloc(wChannels*wav->samplesPerBlock*sizeof(short));
 
-        bytespersample = SOX_SIZE_16BIT;  /* AFTER de-compression */
+        bytespersample = 2;  /* AFTER de-compression */
         break;
 
     /* GSM formats have extended fmt chunk.  Check for those cases. */
@@ -745,7 +721,7 @@
                     wav_format_str(wav->formatTag), wav->samplesPerBlock, 320);
             return SOX_EOF;
         }
-        bytespersample = SOX_SIZE_16BIT;  /* AFTER de-compression */
+        bytespersample = 2;  /* AFTER de-compression */
         len -= 2;
         break;
 
@@ -754,57 +730,28 @@
 
     }
 
+    /* User options take precedence */
+    if (!ft->encoding.bits_per_sample || ft->encoding.bits_per_sample == wBitsPerSample)
+      ft->encoding.bits_per_sample = wBitsPerSample;
+    else
+      sox_warn("User options overriding size read in .wav header");
+
+    /* Now we have enough information to set default encodings. */
     switch (bytespersample)
     {
+    case 1:
+      if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN)
+        ft->encoding.encoding = SOX_ENCODING_UNSIGNED;
+      break;
         
-    case SOX_SIZE_BYTE:
-        /* User options take precedence */
-        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");
-
-        /* Now we have enough information to set default encodings. */
-        if (ft->signal.encoding == SOX_ENCODING_UNKNOWN)
-            ft->signal.encoding = SOX_ENCODING_UNSIGNED;
-        break;
+    case 2: case 3: case 4:
+      if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN)
+        ft->encoding.encoding = SOX_ENCODING_SIGN2;
+      break;
         
-    case 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");
-
-        /* Now we have enough information to set default encodings. */
-        if (ft->signal.encoding == SOX_ENCODING_UNKNOWN)
-            ft->signal.encoding = SOX_ENCODING_SIGN2;
-        break;
-        
-    case 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");
-
-        /* Now we have enough information to set default encodings. */
-        if (ft->signal.encoding == SOX_ENCODING_UNKNOWN)
-            ft->signal.encoding = SOX_ENCODING_SIGN2;
-        break;
-        
-    case 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");
-
-        /* Now we have enough information to set default encodings. */
-        if (ft->signal.encoding == SOX_ENCODING_UNKNOWN)
-            ft->signal.encoding = SOX_ENCODING_SIGN2;
-        break;
-        
     default:
-        sox_fail_errno(ft,SOX_EOF,"Sorry, don't understand .wav size");
-        return SOX_EOF;
+      sox_fail_errno(ft,SOX_EFMT,"Sorry, don't understand .wav size");
+      return SOX_EOF;
     }
 
     /* Skip anything left over from fmt chunk */
@@ -855,8 +802,8 @@
         break;
 
     default:
-        wav->numSamples = dwDataLength/ft->signal.size/ft->signal.channels;
-        ft->length = wav->numSamples*ft->signal.channels;
+        wav->numSamples = div_bits(dwDataLength, ft->encoding.bits_per_sample) / ft->signal.channels;
+        ft->length = wav->numSamples * ft->signal.channels;
     }
 
     sox_debug("Reading Wave file: %s format, %d channel%s, %d samp/sec",
@@ -991,7 +938,7 @@
         sox_clearerr(ft);
         sox_seeki(ft,(sox_ssize_t)wav->dataStart,SEEK_SET);
     }   
-    return SOX_SUCCESS;
+    return sox_rawstartread(ft);
 }
 
 
@@ -1002,7 +949,7 @@
  * Return number of samples read.
  */
 
-static sox_size_t sox_wavread(sox_format_t * ft, sox_sample_t *buf, sox_size_t len) 
+static sox_size_t read_samples(sox_format_t * ft, sox_sample_t *buf, sox_size_t len) 
 {
         wav_t   wav = (wav_t) ft->priv;
         sox_size_t done;
@@ -1011,10 +958,10 @@
         
         /* If file is in ADPCM encoding then read in multiple blocks else */
         /* read as much as possible and return quickly. */
-        switch (ft->signal.encoding)
+        switch (ft->encoding.encoding)
         {
         case SOX_ENCODING_IMA_ADPCM:
-        case SOX_ENCODING_ADPCM:
+        case SOX_ENCODING_MS_ADPCM:
 
             if (!wav->ignoreSize && len > (wav->numSamples*ft->signal.channels)) 
                 len = (wav->numSamples*ft->signal.channels);
@@ -1098,7 +1045,7 @@
  * Do anything required when you stop reading samples.  
  * Don't close input file! 
  */
-static int sox_wavstopread(sox_format_t * ft) 
+static int stopread(sox_format_t * ft) 
 {
     wav_t       wav = (wav_t) ft->priv;
 
@@ -1110,13 +1057,13 @@
     free(wav->comment);
     wav->comment = NULL;
 
-    switch (ft->signal.encoding)
+    switch (ft->encoding.encoding)
     {
     case SOX_ENCODING_GSM:
         wavgsmdestroy(ft);
         break;
     case SOX_ENCODING_IMA_ADPCM:
-    case SOX_ENCODING_ADPCM:
+    case SOX_ENCODING_MS_ADPCM:
         break;
     default:
         break;
@@ -1124,7 +1071,7 @@
     return SOX_SUCCESS;
 }
 
-static int sox_wavstartwrite(sox_format_t * ft) 
+static int startwrite(sox_format_t * ft) 
 {
     wav_t wav = (wav_t) ft->priv;
     int rc;
@@ -1131,9 +1078,9 @@
 
     ft->sox_errno = SOX_SUCCESS;
 
-    if (ft->signal.encoding != SOX_ENCODING_ADPCM &&
-        ft->signal.encoding != SOX_ENCODING_IMA_ADPCM &&
-        ft->signal.encoding != SOX_ENCODING_GSM)
+    if (ft->encoding.encoding != SOX_ENCODING_MS_ADPCM &&
+        ft->encoding.encoding != SOX_ENCODING_IMA_ADPCM &&
+        ft->encoding.encoding != SOX_ENCODING_GSM)
     {
         rc = sox_rawstartwrite(ft);
         if (rc)
@@ -1142,8 +1089,9 @@
 
     wav->numSamples = 0;
     wav->dataLength = 0;
-    if (!ft->seekable)
+    if (!ft->length && !ft->seekable)
         sox_warn("Length in output .wav header will be wrong since can't seek to fix it");
+
     rc = wavwritehdr(ft, 0);  /* also calculates various wav->* info */
     if (rc != 0)
         return rc;
@@ -1235,6 +1183,8 @@
 
 */
 
+#define MS_UNSPEC 0x7ffff000  /* Unspecified data size (this is a kludge) */
+
 static int wavwritehdr(sox_format_t * ft, int second_header) 
 {
     wav_t       wav = (wav_t) ft->priv;
@@ -1260,7 +1210,7 @@
     uint32_t dwSamplesWritten=0;  /* windows doesnt seem to use this*/
 
     /* data chunk */
-    uint32_t  dwDataLength=0x7ffff000; /* length of sound data in bytes */
+    uint32_t  dwDataLength = MS_UNSPEC; /* length of sound data in bytes */
     /* end of variables written to header */
 
     /* internal variables, intermediate values etc */
@@ -1270,74 +1220,10 @@
 
     dwSamplesPerSecond = ft->signal.rate;
     wChannels = ft->signal.channels;
-
-    /* Check to see if encoding is ADPCM or not.  If ADPCM
-     * possibly override the size to be bytes.  It isn't needed
-     * by this routine will look nicer (and more correct)
-     * on verbose output.
-     */
-    if ((ft->signal.encoding == SOX_ENCODING_ADPCM ||
-         ft->signal.encoding == SOX_ENCODING_IMA_ADPCM ||
-         ft->signal.encoding == SOX_ENCODING_GSM) &&
-         ft->signal.size != SOX_SIZE_BYTE)
-    {
-        sox_report("Overriding output size to bytes for compressed data.");
-        ft->signal.size = SOX_SIZE_BYTE;
-    }
-
-    switch (ft->signal.size)
-    {
-        case SOX_SIZE_BYTE:
-            wBitsPerSample = 8;
-            if (ft->signal.encoding != SOX_ENCODING_UNSIGNED &&
-                    ft->signal.encoding != SOX_ENCODING_ULAW &&
-                    ft->signal.encoding != SOX_ENCODING_ALAW &&
-                    ft->signal.encoding != SOX_ENCODING_GSM &&
-                    ft->signal.encoding != SOX_ENCODING_ADPCM &&
-                    ft->signal.encoding != SOX_ENCODING_IMA_ADPCM)
-            {
-                sox_report("Do not support %s with 8-bit data.  Forcing to unsigned",sox_encodings_str[(unsigned char)ft->signal.encoding]);
-                ft->signal.encoding = SOX_ENCODING_UNSIGNED;
-            }
-            break;
-        case SOX_SIZE_16BIT:
-            wBitsPerSample = 16;
-            if (ft->signal.encoding != SOX_ENCODING_SIGN2)
-            {
-                sox_report("Do not support %s with 16-bit data.  Forcing to Signed.",sox_encodings_str[(unsigned char)ft->signal.encoding]);
-                ft->signal.encoding = SOX_ENCODING_SIGN2;
-            }
-            break;
-        case SOX_SIZE_24BIT:
-            wBitsPerSample = 24;
-            if (ft->signal.encoding != SOX_ENCODING_SIGN2)
-            {
-                sox_report("Do not support %s with 24-bit data.  Forcing to Signed.",sox_encodings_str[(unsigned char)ft->signal.encoding]);
-                ft->signal.encoding = SOX_ENCODING_SIGN2;
-            }
-            break;
-
-        case SOX_SIZE_32BIT:
-            wBitsPerSample = 32;
-            if (ft->signal.encoding != SOX_ENCODING_SIGN2 &&
-                ft->signal.encoding != SOX_ENCODING_FLOAT)
-            {
-                sox_report("Do not support %s with 32-bit data.  Forcing to Signed.",sox_encodings_str[(unsigned char)ft->signal.encoding]);
-                ft->signal.encoding = SOX_ENCODING_SIGN2;
-            }
-
-            break;
-        default:
-            sox_report("Do not support %s data in WAV files.  Forcing to Signed 16-bit.",sox_sizes_str[(unsigned char)ft->signal.size]);
-            ft->signal.encoding = SOX_ENCODING_SIGN2;
-            ft->signal.size = SOX_SIZE_16BIT;
-            wBitsPerSample = 16;
-            break;
-    }
-
+    wBitsPerSample = ft->encoding.bits_per_sample;
     wSamplesPerBlock = 1;       /* common default for PCM data */
 
-    switch (ft->signal.encoding)
+    switch (ft->encoding.encoding)
     {
         case SOX_ENCODING_UNSIGNED:
         case SOX_ENCODING_SIGN2:
@@ -1370,7 +1256,7 @@
             wExtSize = 2;
             wSamplesPerBlock = ImaSamplesIn(0, wChannels, wBlockAlign, 0);
             break;
-        case SOX_ENCODING_ADPCM:
+        case SOX_ENCODING_MS_ADPCM:
             if (wChannels>16)
             {
                 sox_fail_errno(ft,SOX_EOF,"Channels(%d) must be <= 16",wChannels);
@@ -1386,6 +1272,8 @@
             if (wChannels!=1)
             {
                 sox_report("Overriding GSM audio from %d channel to 1",wChannels);
+                if (!second_header)
+                  ft->length /= max(1, ft->signal.channels);
                 wChannels = ft->signal.channels = 1;
             }
             wFormatTag = WAVE_FORMAT_GSM610;
@@ -1402,12 +1290,12 @@
     wav->blockAlign = wBlockAlign;
     wav->samplesPerBlock = wSamplesPerBlock;
 
-    if (!second_header) {       /* adjust for blockAlign */
+    if (!second_header && !ft->length) {       /* adjust for blockAlign */
         blocksWritten = dwDataLength/wBlockAlign;
         dwDataLength = blocksWritten * wBlockAlign;
         dwSamplesWritten = blocksWritten * wSamplesPerBlock;
     } else {    /* fixup with real length */
-        dwSamplesWritten = wav->numSamples;
+        dwSamplesWritten = second_header? wav->numSamples : ft->length;
         switch(wFormatTag)
         {
             case WAVE_FORMAT_ADPCM:
@@ -1445,7 +1333,7 @@
     /* If user specified opposite swap than we think, assume they are
      * asking to write a RIFX file.
      */
-    if (ft->signal.reverse_bytes && SOX_IS_LITTLEENDIAN)
+    if (ft->encoding.reverse_bytes && SOX_IS_LITTLEENDIAN)
     {
         if (!second_header)
             sox_report("Requested to swap bytes so writing RIFX header");
@@ -1534,7 +1422,7 @@
     return SOX_SUCCESS;
 }
 
-static sox_size_t sox_wavwrite(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len) 
+static sox_size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len) 
 {
         wav_t   wav = (wav_t) ft->priv;
         sox_ssize_t total_len = len;
@@ -1575,7 +1463,7 @@
         }
 }
 
-static int sox_wavstopwrite(sox_format_t * ft) 
+static int stopwrite(sox_format_t * ft) 
 {
         wav_t   wav = (wav_t) ft->priv;
 
@@ -1600,8 +1488,10 @@
         /* All samples are already written out. */
         /* If file header needs fixing up, for example it needs the */
         /* the number of samples in a field, seek back and write them here. */
+        if (ft->length && wav->numSamples == ft->length)
+          return SOX_SUCCESS;
         if (!ft->seekable)
-                return SOX_EOF;
+          return SOX_EOF;
 
         if (sox_seeki(ft, 0, SEEK_SET) != 0)
         {
@@ -1664,7 +1554,7 @@
         }
 }
 
-static int sox_wavseek(sox_format_t * ft, sox_size_t offset) 
+static int seek(sox_format_t * ft, sox_size_t offset) 
 {
     wav_t   wav = (wav_t) ft->priv;
     int new_offset, channel_block, alignment;
@@ -1700,9 +1590,9 @@
             break;
 
         default:
-            new_offset = offset * ft->signal.size;
+            new_offset = offset * (ft->encoding.bits_per_sample >> 3);
             /* Make sure request aligns to a channel block (ie left+right) */
-            channel_block = ft->signal.channels * ft->signal.size;
+            channel_block = ft->signal.channels * (ft->encoding.bits_per_sample >> 3);
             alignment = new_offset % channel_block;
             /* Most common mistaken is to compute something like
              * "skip everthing upto and including this sample" so
@@ -1716,34 +1606,30 @@
 
             if( ft->sox_errno == SOX_SUCCESS )
                 wav->numSamples = (ft->length / ft->signal.channels) -
-                                  (new_offset / ft->signal.size / ft->signal.channels);
+                                  (new_offset / (ft->encoding.bits_per_sample >> 3) / ft->signal.channels);
     }
 
     return(ft->sox_errno);
 }
 
-/* Microsoft RIFF */
-static const char *wavnames[] = {
-  "wav",
-  "wavpcm",
-  NULL
-};
-
-static sox_format_handler_t sox_wav_format = {
-  wavnames,
-  SOX_FILE_LIT_END,
-  sox_wavstartread,
-  sox_wavread,
-  sox_wavstopread,
-  sox_wavstartwrite,
-  sox_wavwrite,
-  sox_wavstopwrite,
-  sox_wavseek
-};
-
-const sox_format_handler_t *sox_wav_format_fn(void);
-
-const sox_format_handler_t *sox_wav_format_fn()
+SOX_FORMAT_HANDLER(wav)
 {
-    return &sox_wav_format;
+  static char const * const names[] = {"wav", "wavpcm", NULL};
+  static unsigned const write_encodings[] = {
+    SOX_ENCODING_SIGN2, 16, 24, 32, 0,
+    SOX_ENCODING_UNSIGNED, 8, 0,
+    SOX_ENCODING_ULAW, 8, 0,
+    SOX_ENCODING_ALAW, 8, 0,
+    SOX_ENCODING_GSM, 0,
+    SOX_ENCODING_MS_ADPCM, 4, 0,
+    SOX_ENCODING_IMA_ADPCM, 4, 0,
+    SOX_ENCODING_FLOAT, 32, 0,
+    0};
+  static sox_format_handler_t const handler = {
+    names, SOX_FILE_LIT_END,
+    startread, read_samples, stopread,
+    startwrite, write_samples, stopwrite,
+    seek, write_encodings, NULL
+  };
+  return &handler;
 }
--- a/src/wve.c
+++ b/src/wve.c
@@ -1,216 +1,61 @@
 /*
- * Psion wve format, based on the au format file. Hacked by
- * Richard Caley ([email protected])
+ * File format: Psion wve   (c) 2008 [email protected]
+ *
+ * See http://filext.com/file-extension/WVE
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library.  If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
  */
 
 #include "sox_i.h"
 #include <string.h>
-#include <errno.h>
 
-/* Magic numbers used in Psion audio files */
-#define PSION_MAGIC     "ALawSoundFile**"
-#define PSION_VERSION   ((short)3856)
-#define PSION_HDRSIZE   32
+static char const ID1[18] = "ALawSoundFile**\0\017\020";
+static char const ID2[] = {0,0,0,1,0,0,0,0,0,0}; /* pad & repeat info: ignore */
 
-typedef struct wvepriv
-    {
-    uint32_t length;
-    short padding;
-    short repeats;
-/* For seeking */
-        sox_size_t dataStart;
-    } *wve_t;
-
-static void wvewriteheader(sox_format_t * ft);
-
-static int sox_wveseek(sox_format_t * ft, sox_size_t offset)
+static int start_read(sox_format_t * ft)
 {
-    int new_offset, channel_block, alignment;
-    wve_t wve = (wve_t)ft->priv;
+  char buf[sizeof(ID1)];
+  uint32_t num_samples;
 
-    new_offset = offset * ft->signal.size;
-    /* Make sure request aligns to a channel block (i.e. left+right) */
-    channel_block = ft->signal.channels * ft->signal.size;
-    alignment = new_offset % channel_block;
-    /* Most common mistake is to compute something like
-     * "skip everthing up to and including this sample" so
-     * advance to next sample block in this case.
-     */
-    if (alignment != 0)
-        new_offset += (channel_block - alignment);
-    new_offset += wve->dataStart;
-
-    return sox_seeki(ft, (sox_ssize_t)offset, SEEK_SET);
+  if (sox_readbuf(ft, buf, sizeof(buf)) != sizeof(buf) ||
+      sox_readdw(ft, &num_samples) || sox_skipbytes(ft, sizeof(ID2)))
+    return SOX_EOF;
+  if (memcmp(ID1, buf, sizeof(buf))) {
+    sox_fail_errno(ft,SOX_EHDR,"wve: can't find Psion identifier");
+    return SOX_EOF;
+  }
+  return sox_check_read_params(ft, 1, 8000., SOX_ENCODING_ALAW, 8, (off_t)num_samples);
 }
 
-static int sox_wvestartread(sox_format_t * ft)
+static int write_header(sox_format_t * ft)
 {
-        wve_t p = (wve_t)ft->priv;
-        char magic[16];
-        short version;
-        int rc;
-
-        uint16_t trash16;
-
-        /* Needed for rawread() */
-        rc = sox_rawstartread(ft);
-        if (rc)
-            return rc;
-
-        /* Check the magic word (null-terminated) */
-        sox_reads(ft, magic, 16);
-        if (strncmp(magic, PSION_MAGIC, 15)==0) {
-                sox_debug("Found Psion magic word");
-        }
-        else
-        {
-                sox_fail_errno(ft,SOX_EHDR,"Psion header doesn't start with magic word\nTry the '.al' file type with '-t al -r 8000 filename'");
-                return (SOX_EOF);
-        }
-
-        sox_readw(ft, (unsigned short *)&version);
-
-        /* Check magic version */
-        if (version == PSION_VERSION)
-            sox_debug("Found Psion magic word");
-        else
-        {
-            sox_fail_errno(ft,SOX_EHDR,"Wrong version in Psion header");
-            return(SOX_EOF);
-        }
-
-        sox_readdw(ft, &(p->length));
-
-        sox_readw(ft, (unsigned short *)&(p->padding));
-
-        sox_readw(ft, (unsigned short *)&(p->repeats));
-
-        sox_readw(ft, (unsigned short *)&trash16);
-        sox_readw(ft, (unsigned short *)&trash16);
-        sox_readw(ft, (unsigned short *)&trash16);
-
-        ft->signal.encoding = SOX_ENCODING_ALAW;
-        ft->signal.size = SOX_SIZE_BYTE;
-
-        if (ft->signal.rate != 0)
-            sox_report("WVE must use 8000 sample rate.  Overriding");
-        ft->signal.rate = 8000;
-
-        if (ft->signal.channels != SOX_ENCODING_UNKNOWN && ft->signal.channels != 1)
-            sox_report("WVE must only supports 1 channel.  Overriding");
-        ft->signal.channels = 1;
-
-        p->dataStart = sox_tell(ft);
-        ft->length = p->length/ft->signal.size;
-
-        return (SOX_SUCCESS);
+  return sox_writebuf(ft, ID1, sizeof(ID1)) != sizeof(ID1)
+      || sox_writedw(ft, ft->olength? ft->olength:ft->length)
+      || sox_writebuf(ft, ID2, sizeof(ID2)) != sizeof(ID2)? SOX_EOF:SOX_SUCCESS;
 }
 
-/* When writing, the header is supposed to contain the number of
-   data bytes written, unless it is written to a pipe.
-   Since we don't know how many bytes will follow until we're done,
-   we first write the header with an unspecified number of bytes,
-   and at the end we rewind the file and write the header again
-   with the right size.  This only works if the file is seekable;
-   if it is not, the unspecified size remains in the header
-   (this is illegal). */
-
-static int sox_wvestartwrite(sox_format_t * ft)
+SOX_FORMAT_HANDLER(wve)
 {
-        wve_t p = (wve_t)ft->priv;
-
-        p->length = 0;
-        if (p->repeats == 0)
-            p->repeats = 1;
-
-        if (ft->signal.rate != 0)
-            sox_report("WVE must use 8000 sample rate.  Overriding");
-
-        if (ft->signal.channels != 0 && ft->signal.channels != 1)
-            sox_report("WVE must only supports 1 channel.  Overriding");
-
-        ft->signal.encoding = SOX_ENCODING_ALAW;
-        ft->signal.size = SOX_SIZE_BYTE;
-        ft->signal.rate = 8000;
-        ft->signal.channels = 1;
-
-        wvewriteheader(ft);
-        return SOX_SUCCESS;
-}
-
-static sox_size_t sox_wvewrite(sox_format_t * ft, const sox_sample_t *buf, sox_size_t samp)
-{
-        wve_t p = (wve_t)ft->priv;
-        p->length += samp * ft->signal.size;
-        return sox_rawwrite(ft, buf, samp);
-}
-
-static int sox_wvestopwrite(sox_format_t * ft)
-{
-
-        if (!ft->seekable)
-        {
-            sox_warn("Header will be have invalid file length since file is not seekable");
-            return SOX_SUCCESS;
-        }
-
-        if (sox_seeki(ft, 0, 0) != 0)
-        {
-                sox_fail_errno(ft,errno,"Can't rewind output file to rewrite Psion header.");
-                return(SOX_EOF);
-        }
-        wvewriteheader(ft);
-        return SOX_SUCCESS;
-}
-
-static void wvewriteheader(sox_format_t * ft)
-{
-
-    char magic[16];
-    short version;
-    short zero;
-    wve_t p = (wve_t)ft->priv;
-
-    strcpy(magic,PSION_MAGIC);
-    version=PSION_VERSION;
-    zero=0;
-
-    sox_writes(ft, magic);
-    /* Null terminate string */
-    sox_writeb(ft, 0);
-
-    sox_writesw(ft, version);
-
-    sox_writedw(ft, p->length);
-    sox_writesw(ft, p->padding);
-    sox_writesw(ft, p->repeats);
-
-    sox_writesw(ft, zero);
-    sox_writesw(ft, zero);
-    sox_writesw(ft, zero);
-}
-
-/* Psion .wve */
-static const char *wvenames[] = {
-  "wve",
-  NULL
-};
-
-static sox_format_handler_t sox_wve_format = {
-  wvenames,
-  SOX_FILE_BIG_END,
-  sox_wvestartread,
-  sox_rawread,
-  sox_rawstopread,
-  sox_wvestartwrite,
-  sox_wvewrite,
-  sox_wvestopwrite,
-  sox_wveseek
-};
-
-const sox_format_handler_t *sox_wve_format_fn(void);
-
-const sox_format_handler_t *sox_wve_format_fn(void)
-{
-    return &sox_wve_format;
+  static char const * const names[] = {"wve", NULL};
+  static sox_rate_t   const write_rates[] = {8000, 0};
+  static unsigned     const write_encodings[] = {SOX_ENCODING_ALAW, 8, 0, 0};
+  static sox_format_handler_t const handler = {
+    names, SOX_FILE_BIG_END | SOX_FILE_MONO | SOX_FILE_REWIND,
+    start_read, sox_rawread, NULL,
+    write_header, sox_rawwrite, NULL,
+    sox_rawseek, write_encodings, write_rates
+  };
+  return &handler;
 }
--- a/src/xa.c
+++ b/src/xa.c
@@ -23,16 +23,12 @@
 /* Thanks to Valery V. Anisimovsky <[email protected]> for the 
  * "Maxis XA Audio File Format Description", dated 5-01-2002. */
 
+#include "sox_i.h"
+
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
 
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>             /* For SEEK_* defines if not found in stdio */
-#endif
-
-#include "sox_i.h"
-
 #define HNIBBLE(byte) (((byte) >> 4) & 0xf)
 #define LNIBBLE(byte) ((byte) & 0xf)
 
@@ -89,7 +85,7 @@
     }
 }
 
-static int sox_xastartread(sox_format_t * ft)
+static int startread(sox_format_t * ft)
 {
     xa_t xa = (xa_t) ft->priv;
     char *magic = xa->header.magic;
@@ -130,10 +126,10 @@
     sox_debug(" wBits:         %u", xa->header.bits);
 
     /* Populate the sox_soundstream structure */
-    ft->signal.encoding = SOX_ENCODING_SIGN2;
+    ft->encoding.encoding = SOX_ENCODING_SIGN2;
     
-    if (!ft->signal.size || ft->signal.size == (xa->header.bits >> 3)) {
-        ft->signal.size = xa->header.bits >> 3;
+    if (!ft->encoding.bits_per_sample || ft->encoding.bits_per_sample == xa->header.bits) {
+        ft->encoding.bits_per_sample = xa->header.bits;
     } else {
         sox_report("User options overriding size read in .xa header");
     }
@@ -151,22 +147,22 @@
     }
     
     /* Check for supported formats */
-    if (ft->signal.size != 2) {
+    if (ft->encoding.bits_per_sample != 16) {
         sox_fail_errno(ft, SOX_EFMT, "%d-bit sample resolution not supported.",
-            ft->signal.size << 3);
+            ft->encoding.bits_per_sample);
         return SOX_EOF;
     }
     
     /* Validate the header */
-    if (xa->header.bits != ft->signal.size << 3) {
+    if (xa->header.bits != ft->encoding.bits_per_sample) {
         sox_report("Invalid sample resolution %d bits.  Assuming %d bits.",
-            xa->header.bits, ft->signal.size << 3);
-        xa->header.bits = ft->signal.size << 3;
+            xa->header.bits, ft->encoding.bits_per_sample);
+        xa->header.bits = ft->encoding.bits_per_sample;
     }
-    if (xa->header.align != ft->signal.size * xa->header.channels) {
+    if (xa->header.align != (ft->encoding.bits_per_sample >> 3) * xa->header.channels) {
         sox_report("Invalid sample alignment value %d.  Assuming %d.",
-            xa->header.align, ft->signal.size * xa->header.channels);
-        xa->header.align = ft->signal.size * xa->header.channels;
+            xa->header.align, (ft->encoding.bits_per_sample >> 3) * xa->header.channels);
+        xa->header.align = (ft->encoding.bits_per_sample >> 3) * xa->header.channels;
     }
     if (xa->header.avgByteRate != (xa->header.align * xa->header.sampleRate)) {
         sox_report("Invalid dwAvgByteRate value %d.  Assuming %d.",
@@ -194,7 +190,7 @@
  * Read up to len samples from a file, converted to signed longs.
  * Return the number of samples read.
  */
-static sox_size_t sox_xaread(sox_format_t * ft, sox_sample_t *buf, sox_size_t len)
+static sox_size_t read_samples(sox_format_t * ft, sox_sample_t *buf, sox_size_t len)
 {
     xa_t xa = (xa_t) ft->priv;
     int32_t sample;
@@ -243,7 +239,7 @@
                 xa->state[i].curSample = sample;
                 
                 buf[done++] = SOX_SIGNED_16BIT_TO_SAMPLE(sample,);
-                xa->bytesDecoded += ft->signal.size;
+                xa->bytesDecoded += (ft->encoding.bits_per_sample >> 3);
             }
             for (i = 0; i < ft->signal.channels && done < len; i++) {
                 /* low nibble */
@@ -257,7 +253,7 @@
                 xa->state[i].curSample = sample;
                 
                 buf[done++] = SOX_SIGNED_16BIT_TO_SAMPLE(sample,);
-                xa->bytesDecoded += ft->signal.size;
+                xa->bytesDecoded += (ft->encoding.bits_per_sample >> 3);
             }
 
             xa->bufPos += ft->signal.channels;
@@ -269,7 +265,7 @@
     return done;
 }
 
-static int sox_xastopread(sox_format_t * ft)
+static int stopread(sox_format_t * ft)
 {
     xa_t xa = (xa_t) ft->priv;
 
@@ -284,45 +280,14 @@
     return SOX_SUCCESS;
 }
 
-static int sox_xastartwrite(sox_format_t * ft)
+SOX_FORMAT_HANDLER(xa)
 {
-    sox_fail_errno(ft, SOX_ENOTSUP, ".XA writing not supported");
-    return SOX_EOF;
-}
-
-static sox_size_t sox_xawrite(sox_format_t * ft, const sox_sample_t *buf UNUSED, sox_size_t len UNUSED)
-{
-    sox_fail_errno(ft, SOX_ENOTSUP, ".XA writing not supported");
-    return 0;
-}
-
-static int sox_xastopwrite(sox_format_t * ft)
-{
-    sox_fail_errno(ft, SOX_ENOTSUP, ".XA writing not supported");
-    return SOX_EOF;
-}
-
-/* Maxis .xa */
-static const char *xanames[] = {
-    "xa",
-    NULL
-};
-
-sox_format_handler_t sox_xa_format = {
-  xanames,
-  SOX_FILE_LIT_END,
-  sox_xastartread,
-  sox_xaread,
-  sox_xastopread,
-  sox_xastartwrite,
-  sox_xawrite,
-  sox_xastopwrite,
-  NULL
-};
-
-const sox_format_handler_t *sox_xa_format_fn(void);
-
-const sox_format_handler_t *sox_xa_format_fn(void)
-{
-  return &sox_xa_format;
+  static char const * const names[] = {"xa", NULL };
+  static sox_format_handler_t const handler = {
+    names, SOX_FILE_LIT_END,
+    startread, read_samples, stopread,
+    NULL, NULL, NULL,
+    NULL, NULL, NULL
+  };
+  return &handler;
 }