shithub: sox

Download patch

ref: 373c331aeb24401d81acb7afd0aecd3ba75da8d9
parent: f31b93dfccbc215a427c75c73b03128815e179cb
author: robs <robs>
date: Wed Jan 10 16:05:55 EST 2007

Nibble & bit ordering.

--- a/src/aiff.c
+++ b/src/aiff.c
@@ -453,7 +453,7 @@
         if (is_sowt)
         {
                 aiff->nsamples -= 4;
-                ft->signal.swap_bytes = !ft->signal.swap_bytes;
+                ft->signal.reverse_bytes = !ft->signal.reverse_bytes;
         }
         
         if (foundmark && !foundinstr)
@@ -695,10 +695,9 @@
             return rc;
 
         aiff->nsamples = 0;
-        if ((ft->signal.encoding == ST_ENCODING_ULAW ||
-             ft->signal.encoding == ST_ENCODING_ALAW) && 
+        if (ft->signal.encoding < ST_ENCODING_SIZE_IS_WORD && 
             ft->signal.size == ST_SIZE_BYTE) {
-                st_report("expanding 8-bit u-law to signed 16 bits");
+                st_report("expanding compressed bytes to signed 16 bits");
                 ft->signal.encoding = ST_ENCODING_SIGN2;
                 ft->signal.size = ST_SIZE_WORD;
         }
@@ -901,10 +900,9 @@
             return rc;
 
         aiff->nsamples = 0;
-        if ((ft->signal.encoding == ST_ENCODING_ULAW ||
-             ft->signal.encoding == ST_ENCODING_ALAW) && 
+        if (ft->signal.encoding < ST_ENCODING_SIZE_IS_WORD && 
             ft->signal.size == ST_SIZE_BYTE) {
-                st_report("expanding 8-bit u-law to signed 16 bits");
+                st_report("expanding compressed bytes to signed 16 bits");
                 ft->signal.encoding = ST_ENCODING_SIGN2;
                 ft->signal.size = ST_SIZE_WORD;
         }
--- a/src/alsa.c
+++ b/src/alsa.c
@@ -381,7 +381,7 @@
         }
         else
         {
-            read_buf(buf+(len*sizeof(st_sample_t)), alsa->buf, err, ft->signal.swap_bytes, &ft->clippedCount);
+            read_buf(buf+(len*sizeof(st_sample_t)), alsa->buf, err, ft->signal.reverse_bytes, &ft->clippedCount);
             len += err * ft->signal.channels;
         }
     }
@@ -486,7 +486,7 @@
       st_size_t len;
       
       osamp = min(nsamp - done, alsa->buf_size / ft->signal.size);
-      write_buf(alsa->buf, buf, osamp, ft->signal.swap_bytes, &ft->clippedCount);
+      write_buf(alsa->buf, buf, osamp, ft->signal.reverse_bytes, &ft->clippedCount);
       buf += osamp;
 
       for (len = 0; len < osamp;) {
--- a/src/au.c
+++ b/src/au.c
@@ -164,11 +164,11 @@
                  * left over from pre-standardize period of testing for
                  * endianess.  Its not hurting though.
                  */
-                ft->signal.swap_bytes = !ft->signal.swap_bytes;
+                ft->signal.reverse_bytes = !ft->signal.reverse_bytes;
                 st_debug("Found inverted DEC magic word.  Swapping bytes.");
         }
         else if (magic == SUN_INV_MAGIC) {
-                ft->signal.swap_bytes = !ft->signal.swap_bytes;
+                ft->signal.reverse_bytes = !ft->signal.reverse_bytes;
                 st_debug("Found inverted Sun/NeXT magic word. Swapping bytes.");
         }
         else if (magic == SUN_MAGIC) {
--- a/src/auto.c
+++ b/src/auto.c
@@ -176,7 +176,7 @@
     }
 
     st_debug("Detected file format type: %s", type);
-    set_swap_if_not_already_set(ft);
+    set_endianness_if_not_already_set(ft);
     return (* ft->h->startread)(ft);
 }
 
--- a/src/cvsd.c
+++ b/src/cvsd.c
@@ -84,7 +84,6 @@
         } bit;
         unsigned bytes_written;
         unsigned cvsd_rate;
-        char swapbits;
 };
 
 static int debug_count = 0;
@@ -120,7 +119,6 @@
         ft->signal.channels = 1;
         ft->signal.size = ST_SIZE_WORD; /* make output format default to words */
         ft->signal.encoding = ST_ENCODING_SIGN2;
-        p->swapbits = ft->signal.reverse_bits;
         /*
          * initialize the decoder
          */
@@ -139,7 +137,7 @@
          * initialize bit shift register
          */
         p->bit.shreg = p->bit.cnt = 0;
-        p->bit.mask = p->swapbits ? 0x80 : 1;
+        p->bit.mask = 1;
         /*
          * count the bytes written
          */
@@ -147,7 +145,7 @@
         p->com.v_min = 1;
         p->com.v_max = -1;
         st_report("cvsd: bit rate %dbit/s, bits from %s", p->cvsd_rate,
-               p->swapbits ? "msb to lsb" : "lsb to msb");
+               ft->signal.reverse_bits ? "msb to lsb" : "lsb to msb");
 }
 
 /* ---------------------------------------------------------------------- */
@@ -239,7 +237,7 @@
                         if (st_readb(ft, &(p->bit.shreg)) == ST_EOF)
                                 return done;
                         p->bit.cnt = 8;
-                        p->bit.mask = p->swapbits ? 0x80 : 1;
+                        p->bit.mask = 1;
                 }
                 /*
                  * handle one bit
@@ -247,10 +245,7 @@
                 p->bit.cnt--;
                 p->com.overload = ((p->com.overload << 1) | 
                                    (!!(p->bit.shreg & p->bit.mask))) & 7;
-                if (p->swapbits)
-                        p->bit.mask >>= 1;
-                else
-                        p->bit.mask <<= 1;
+                p->bit.mask <<= 1;
                 p->com.mla_int *= p->com.mla_tc0;
                 if ((p->com.overload == 0) || (p->com.overload == 7))
                         p->com.mla_int += p->com.mla_tc1;
@@ -334,13 +329,9 @@
                         st_writeb(ft, p->bit.shreg);
                         p->bytes_written++;
                         p->bit.shreg = p->bit.cnt = 0;
-                        p->bit.mask = p->swapbits ? 0x80 : 1;
-                } else {
-                        if (p->swapbits)
-                                p->bit.mask >>= 1;
-                        else
-                                p->bit.mask <<= 1;
-                }
+                        p->bit.mask = 1;
+                } else
+                        p->bit.mask <<= 1;
                 p->com.phase += p->com.phase_inc;
                 st_debug_more("input %d %f\n", debug_count, inval);
                 st_debug_more("recon %d %f\n", debug_count, p->c.enc.recon_int);
@@ -489,7 +480,6 @@
 
 static int st_dvmsstartread(ft_t ft) 
 {
-        struct cvsdpriv *p = (struct cvsdpriv *) ft->priv;
         struct dvms_header hdr;
         int rc;
 
@@ -520,7 +510,6 @@
         if (rc)
             return rc;
 
-        p->swapbits = 0;
         return(ST_SUCCESS);
 }
 
@@ -528,7 +517,6 @@
 
 static int st_dvmsstartwrite(ft_t ft) 
 {
-        struct cvsdpriv *p = (struct cvsdpriv *) ft->priv;
         struct dvms_header hdr;
         int rc;
         
@@ -546,7 +534,6 @@
         if (!ft->seekable)
                st_warn("Length in output .DVMS header will wrong since can't seek to fix it");
 
-        p->swapbits = 0;
         return(ST_SUCCESS);
 }
 
--- a/src/flac.c
+++ b/src/flac.c
@@ -330,10 +330,7 @@
   }
 
   /* FIXME: FLAC should not need to know about this oddity */
-  if (format->signal.encoding == ST_ENCODING_ULAW ||
-      format->signal.encoding == ST_ENCODING_ALAW ||
-      format->signal.encoding == ST_ENCODING_INV_ULAW ||
-      format->signal.encoding == ST_ENCODING_INV_ALAW)
+  if (format->signal.encoding < ST_ENCODING_SIZE_IS_WORD)
     format->signal.size = ST_SIZE_WORD;
 
   encoder->bits_per_sample = (format->signal.size > 4 ? 4 : format->signal.size) << 3;
--- a/src/misc.c
+++ b/src/misc.c
@@ -55,20 +55,23 @@
 
 const char * const st_encodings_str[] = {
         "NONSENSE!",
-        "unsigned",
-        "signed (2's complement)",
+
         "u-law",
         "a-law",
-        "floating point",
-        "ADPCM",
+        "G72x-ADPCM",
+        "MS-ADPCM",
         "IMA-ADPCM",
+        "OKI-ADPCM",
+
+        "",   /* FIXME, see st.h */
+
+        "unsigned",
+        "signed (2's complement)",
+        "floating point",
         "GSM",
-        "inversed u-law",
-        "inversed A-law",
         "MPEG audio (layer I, II or III)",
         "Vorbis",
         "FLAC",
-        "OKI-ADPCM"
 };
 
 assert_static(array_length(st_encodings_str) == ST_ENCODINGS,
@@ -77,6 +80,32 @@
 static const char readerr[] = "Premature EOF while reading sample file.";
 static const char writerr[] = "Error writing sample file.  You are probably out of disk space.";
 
+/* Lookup table to reverse the bit order of a byte. ie MSB become LSB */
+static uint8_t const cswap[256] = {
+  0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0,
+  0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 
+  0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4, 
+  0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
+  0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC,
+  0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 
+  0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA, 
+  0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
+  0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6,
+  0x36, 0xB6, 0x76, 0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 
+  0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81, 0x41, 0xC1, 
+  0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
+  0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9,
+  0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 
+  0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D, 0x8D, 0x4D, 0xCD, 
+  0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
+  0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3,
+  0x33, 0xB3, 0x73, 0xF3, 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 
+  0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7, 
+  0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
+  0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF,
+  0x3F, 0xBF, 0x7F, 0xFF
+};
+
 /* Utilities */
 
 /* Read in a buffer of data of length len and each element is size bytes.
@@ -201,23 +230,29 @@
 /* Read byte. */
 int st_readb(ft_t ft, uint8_t *ub)
 {
-        if (st_readbuf(ft, ub, 1, 1) != 1)
-        {
-            st_fail_errno(ft,errno,readerr);
-            return(ST_EOF);
-        }
-        return ST_SUCCESS;
+  if (st_readbuf(ft, ub, 1, 1) != 1) {
+    st_fail_errno(ft,errno,readerr);
+    return ST_EOF;
+  }
+  if (ft->signal.reverse_bits)
+    *ub = cswap[*ub];
+  if (ft->signal.reverse_nibbles)
+    *ub = ((*ub & 15) << 4) | (*ub >> 4);
+  return ST_SUCCESS;
 }
 
 /* Write byte. */
 int st_writeb(ft_t ft, uint8_t ub)
 {
-        if (st_writebuf(ft, &ub, 1, 1) != 1)
-        {
-                st_fail_errno(ft,errno,writerr);
-                return(ST_EOF);
-        }
-        return(ST_SUCCESS);
+  if (ft->signal.reverse_nibbles)
+    ub = ((ub & 15) << 4) | (ub >> 4);
+  if (ft->signal.reverse_bits)
+    ub = cswap[ub];
+  if (st_writebuf(ft, &ub, 1, 1) != 1) {
+    st_fail_errno(ft,errno,writerr);
+    return ST_EOF;
+  }
+  return ST_SUCCESS;
 }
 
 /* Read word. */
@@ -228,7 +263,7 @@
             st_fail_errno(ft,errno,readerr);
             return (ST_EOF);
         }
-        if (ft->signal.swap_bytes)
+        if (ft->signal.reverse_bytes)
                 *uw = st_swapw(*uw);
         return ST_SUCCESS;
 }
@@ -236,7 +271,7 @@
 /* Write word. */
 int st_writew(ft_t ft, uint16_t uw)
 {
-        if (ft->signal.swap_bytes)
+        if (ft->signal.reverse_bytes)
                 uw = st_swapw(uw);
         if (st_writebuf(ft, &uw, 2, 1) != 1)
         {
@@ -254,7 +289,7 @@
             st_fail_errno(ft,errno,readerr);
             return (ST_EOF);
         }
-        if (ft->signal.swap_bytes)
+        if (ft->signal.reverse_bytes)
                 *u3 = st_swap24(*u3);
         return ST_SUCCESS;
 }
@@ -262,7 +297,7 @@
 /* Write three bytes. */
 int st_write3(ft_t ft, uint24_t u3)
 {
-        if (ft->signal.swap_bytes)
+        if (ft->signal.reverse_bytes)
                 u3 = st_swap24(u3);
         if (st_writebuf(ft, &u3, 3, 1) != 1)
         {
@@ -280,7 +315,7 @@
             st_fail_errno(ft,errno,readerr);
             return (ST_EOF);
         }
-        if (ft->signal.swap_bytes)
+        if (ft->signal.reverse_bytes)
                 *udw = st_swapdw(*udw);
         return ST_SUCCESS;
 }
@@ -288,7 +323,7 @@
 /* Write double word. */
 int st_writedw(ft_t ft, uint32_t udw)
 {
-        if (ft->signal.swap_bytes)
+        if (ft->signal.reverse_bytes)
                 udw = st_swapdw(udw);
         if (st_writebuf(ft, &udw, 4, 1) != 1)
         {
@@ -306,7 +341,7 @@
             st_fail_errno(ft,errno,readerr);
             return(ST_EOF);
         }
-        if (ft->signal.swap_bytes)
+        if (ft->signal.reverse_bytes)
                 *f = st_swapf(*f);
         return ST_SUCCESS;
 }
@@ -316,7 +351,7 @@
 {
         float t = f;
 
-        if (ft->signal.swap_bytes)
+        if (ft->signal.reverse_bytes)
                 t = st_swapf(t);
         if (st_writebuf(ft, &t, sizeof(float), 1) != 1)
         {
@@ -334,7 +369,7 @@
             st_fail_errno(ft,errno,readerr);
             return(ST_EOF);
         }
-        if (ft->signal.swap_bytes)
+        if (ft->signal.reverse_bytes)
                 *d = st_swapd(*d);
         return ST_SUCCESS;
 }
@@ -342,7 +377,7 @@
 /* Write double. */
 int st_writedf(ft_t ft, double d)
 {
-        if (ft->signal.swap_bytes)
+        if (ft->signal.reverse_bytes)
                 d = st_swapd(d);
         if (st_writebuf(ft, &d, sizeof(double), 1) != 1)
         {
--- a/src/oss.c
+++ b/src/oss.c
@@ -132,7 +132,7 @@
     }
 
     if (samplesize == 16)
-      ft->signal.swap_bytes = ST_IS_BIGENDIAN != (sampletype == AFMT_S16_BE);
+      ft->signal.reverse_bytes = ST_IS_BIGENDIAN != (sampletype == AFMT_S16_BE);
 
     if (ft->signal.channels == 2) dsp_stereo = 1;
     else dsp_stereo = 0;
--- a/src/raw.c
+++ b/src/raw.c
@@ -1,8 +1,6 @@
 /*
- * Sound Tools raw format file.
+ * Sound Tools raw file formats
  *
- * Includes .ub, .uw, .sb, .sw, and .ul formats at end
- *
  * July 5, 1991
  * Copyright 1991 Lance Norskog And Sundry Contributors
  * This source code is freely redistributable and may be used for
@@ -11,12 +9,6 @@
  * the consequences of using this software.
  */
 
-/*
- * Notes: most of the headerless formats set their handlers to raw
- * in their startread/write routines.
- *
- */
-
 #include "st_i.h"
 #include "g711.h"
 
@@ -24,49 +16,11 @@
 #include <stdlib.h>
 #include <errno.h>
 
-/* Lookup table to reverse the bit order of a byte. ie MSB become LSB */
-unsigned char cswap[256] = {
-  0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0,
-  0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 
-  0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4, 
-  0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
-  0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC,
-  0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 
-  0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA, 
-  0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
-  0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6,
-  0x36, 0xB6, 0x76, 0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 
-  0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81, 0x41, 0xC1, 
-  0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
-  0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9,
-  0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 
-  0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D, 0x8D, 0x4D, 0xCD, 
-  0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
-  0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3,
-  0x33, 0xB3, 0x73, 0xF3, 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 
-  0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7, 
-  0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
-  0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF,
-  0x3F, 0xBF, 0x7F, 0xFF
-};
-
 #define ST_ULAW_BYTE_TO_SAMPLE(d,clips)   ST_SIGNED_WORD_TO_SAMPLE(st_ulaw2linear16(d),clips)
 #define ST_ALAW_BYTE_TO_SAMPLE(d,clips)   ST_SIGNED_WORD_TO_SAMPLE(st_alaw2linear16(d),clips)
 #define ST_SAMPLE_TO_ULAW_BYTE(d,c) st_14linear2ulaw(ST_SAMPLE_TO_SIGNED_WORD(d,c) >> 2)
 #define ST_SAMPLE_TO_ALAW_BYTE(d,c) st_13linear2alaw(ST_SAMPLE_TO_SIGNED_WORD(d,c) >> 3)
 
-/* Some hardware sends MSB last. These account for that */
-#define ST_INVERT_ULAW_BYTE_TO_SAMPLE(d,clips) \
-    ST_SIGNED_WORD_TO_SAMPLE(st_ulaw2linear16(cswap[d]),clips)
-#define ST_INVERT_ALAW_BYTE_TO_SAMPLE(d,clips) \
-    ST_SIGNED_WORD_TO_SAMPLE(st_alaw2linear16(cswap[d]),clips)
-#define ST_SAMPLE_TO_INVERT_ULAW_BYTE(d,c) \
-    cswap[st_14linear2ulaw(ST_SAMPLE_TO_SIGNED_WORD(d,c) >> 2)]
-#define ST_SAMPLE_TO_INVERT_ALAW_BYTE(d,c) \
-    cswap[st_13linear2alaw(ST_SAMPLE_TO_SIGNED_WORD(d,c) >> 3)]
-
-static void rawdefaults(ft_t ft);
-
 int st_rawseek(ft_t ft, st_size_t offset)
 {
     st_size_t new_offset, channel_block, alignment;
@@ -101,15 +55,48 @@
 
 /* Works nicely for starting read and write; st_rawstart{read,write}
    are #defined in st_i.h */
-int st_rawstart(ft_t ft)
+int st_rawstart(ft_t ft, bool default_rate, bool default_channels, st_encoding_t encoding, signed char size, st_reverse_t rev_bits)
 {
-    ft->eof = 0;
+  if (default_rate && ft->signal.rate == 0) {
+    st_warn("'%s': sample rate not specified; trying 8kHz", ft->filename);
+    ft->signal.rate = 8000;
+  }
 
-    return ST_SUCCESS;
+  if (default_channels && ft->signal.channels == 0) {
+    st_warn("'%s': # channels not specified; trying mono", ft->filename);
+    ft->signal.channels = 1;
+  }
+
+  if (encoding != ST_ENCODING_UNKNOWN) {
+    if (ft->mode == 'r' &&
+        ft->signal.encoding != ST_ENCODING_UNKNOWN &&
+        ft->signal.encoding != encoding)
+      st_report("'%s': Format options overriding file-type encoding", ft->filename);
+    else ft->signal.encoding = encoding;
+  }
+
+  if (size != -1) {
+    if (ft->mode == 'r' &&
+        ft->signal.size != -1 && ft->signal.size != size)
+      st_report("'%s': Format options overriding file-type sample-size", ft->filename);
+    else ft->signal.size = size;
+  }
+
+  if (rev_bits != ST_REVERSE_DEFAULT) {
+    if (ft->mode == 'r' &&
+        ft->signal.reverse_bits != ST_REVERSE_DEFAULT &&
+        ft->signal.reverse_bits != rev_bits)
+      st_report("'%s': Format options overriding file-type bit-order", ft->filename);
+    else ft->signal.reverse_bits = rev_bits;
+  }
+
+  ft->eof = 0;
+  return ST_SUCCESS;
 }
 
 #define READ_FUNC(size, sign, ctype, uctype, cast) \
-  static st_size_t st_ ## sign ## size ## _read_buf(st_sample_t *buf, ft_t ft, st_size_t len, st_size_t *clippedCount UNUSED) \
+  static st_size_t st_ ## sign ## size ## _read_buf( \
+      ft_t ft, st_sample_t *buf, st_size_t len) \
   { \
     st_size_t n; \
     for (n = 0; n < len; n++) { \
@@ -117,7 +104,7 @@
       int ret = st_read ## size(ft, (uctype *)&datum); \
       if (ret != ST_SUCCESS) \
         break; \
-      *buf++ = ST_ ## cast ## _TO_SAMPLE(datum, *clippedCount); \
+      *buf++ = ST_ ## cast ## _TO_SAMPLE(datum, ft->clippedCount); \
     } \
     return n; \
   }
@@ -126,8 +113,6 @@
 READ_FUNC(b, s, int8_t, uint8_t, SIGNED_BYTE)
 READ_FUNC(b, ulaw, uint8_t, uint8_t, ULAW_BYTE)
 READ_FUNC(b, alaw, uint8_t, uint8_t, ALAW_BYTE)
-READ_FUNC(b, inv_ulaw, uint8_t, uint8_t, INVERT_ULAW_BYTE)
-READ_FUNC(b, inv_alaw, uint8_t, uint8_t, INVERT_ALAW_BYTE)
 READ_FUNC(w, u, uint16_t, uint16_t, UNSIGNED_WORD)
 READ_FUNC(w, s, int16_t, uint16_t, SIGNED_WORD)
 READ_FUNC(3, u, uint24_t, uint24_t, UNSIGNED_24BIT)
@@ -138,11 +123,12 @@
 READ_FUNC(df, su, double, double, FLOAT_DDWORD)
 
 #define WRITE_FUNC(size, sign, cast) \
-  static st_size_t st_ ## sign ## size ## _write_buf(st_sample_t *buf, ft_t ft, st_size_t len, st_size_t *clippedCount UNUSED) \
+  static st_size_t st_ ## sign ## size ## _write_buf( \
+      ft_t ft, st_sample_t *buf, st_size_t len) \
   { \
     st_size_t n; \
     for (n = 0; n < len; n++) { \
-      int ret = st_write ## size(ft, ST_SAMPLE_TO_ ## cast(*buf++, *clippedCount)); \
+      int ret = st_write ## size(ft, ST_SAMPLE_TO_ ## cast(*buf++, ft->clippedCount)); \
       if (ret != ST_SUCCESS) \
         break; \
     } \
@@ -153,8 +139,6 @@
 WRITE_FUNC(b, s, SIGNED_BYTE)
 WRITE_FUNC(b, ulaw, ULAW_BYTE)
 WRITE_FUNC(b, alaw, ALAW_BYTE)
-WRITE_FUNC(b, inv_ulaw, INVERT_ULAW_BYTE)
-WRITE_FUNC(b, inv_alaw, INVERT_ALAW_BYTE)
 WRITE_FUNC(w, u, UNSIGNED_WORD)
 WRITE_FUNC(w, s, SIGNED_WORD)
 WRITE_FUNC(3, u, UNSIGNED_24BIT)
@@ -164,7 +148,7 @@
 WRITE_FUNC(f, su, FLOAT_DWORD)
 WRITE_FUNC(df, su, FLOAT_DDWORD)
 
-typedef st_size_t (ft_io_fun)(st_sample_t *buf, ft_t ft, st_size_t len, st_size_t *clippedCount);
+typedef st_size_t (ft_io_fun)(ft_t ft, st_sample_t *buf, st_size_t len);
 
 static ft_io_fun *check_format(ft_t ft, bool write)
 {
@@ -179,10 +163,6 @@
         return write ? st_ulawb_write_buf : st_ulawb_read_buf;
       case ST_ENCODING_ALAW:
         return write ? st_alawb_write_buf : st_alawb_read_buf;
-      case ST_ENCODING_INV_ULAW:
-        return write ? st_inv_ulawb_write_buf : st_inv_ulawb_read_buf;
-      case ST_ENCODING_INV_ALAW:
-        return write ? st_inv_alawb_write_buf : st_inv_alawb_read_buf;
       default:
         break;
       }
@@ -244,10 +224,10 @@
 /* Read a stream of some type into SoX's internal buffer format. */
 st_size_t st_rawread(ft_t ft, st_sample_t *buf, st_size_t nsamp)
 {
-    st_size_t (*read_buf)(st_sample_t *, ft_t, st_size_t, st_size_t *) = check_format(ft, false);
+    ft_io_fun * read_buf = check_format(ft, false);
 
     if (read_buf && nsamp)
-      return read_buf(buf, ft, nsamp, &ft->clippedCount);
+      return read_buf(ft, buf, nsamp);
 
     return 0;
 }
@@ -264,7 +244,7 @@
     ft_io_fun *write_buf = check_format(ft, true);
 
     if (write_buf && nsamp)
-      return write_buf((st_sample_t *)buf, ft, nsamp, &ft->clippedCount);
+      return write_buf(ft, (st_sample_t *)buf, nsamp);
 
     return 0;
 }
@@ -275,389 +255,46 @@
         return ST_SUCCESS;
 }
 
-/*
-* Set parameters to the fixed parameters known for this format,
-* and change format to raw format.
-*/
-
-#define STARTREAD(NAME,SIZE,STYLE) \
-static int NAME(ft_t ft) \
-{ \
-        ft->signal.size = SIZE; \
-        ft->signal.encoding = STYLE; \
-        rawdefaults(ft); \
-        return st_rawstartread(ft); \
+static int raw_start(ft_t ft) {
+  return st_rawstart(ft,false,false,ST_ENCODING_UNKNOWN,-1,ST_REVERSE_DEFAULT);
 }
-
-#define STARTWRITE(NAME,SIZE,STYLE)\
-static int NAME(ft_t ft) \
-{ \
-        ft->signal.size = SIZE; \
-        ft->signal.encoding = STYLE; \
-        rawdefaults(ft); \
-        return st_rawstartwrite(ft); \
+st_format_t const * st_raw_format_fn(void) {
+  static char const * names[] = {"raw", NULL};
+  static st_format_t driver = {
+    names, NULL, ST_FILE_STEREO | ST_FILE_SEEK,
+    raw_start, st_rawread , st_rawstopread,
+    raw_start, st_rawwrite, st_rawstopwrite,
+    st_rawseek
+  };
+  return &driver;
 }
 
-STARTREAD(st_sbstartread,ST_SIZE_BYTE,ST_ENCODING_SIGN2)
-STARTWRITE(st_sbstartwrite,ST_SIZE_BYTE,ST_ENCODING_SIGN2)
-
-STARTREAD(st_ubstartread,ST_SIZE_BYTE,ST_ENCODING_UNSIGNED)
-STARTWRITE(st_ubstartwrite,ST_SIZE_BYTE,ST_ENCODING_UNSIGNED)
-
-STARTREAD(st_uwstartread,ST_SIZE_WORD,ST_ENCODING_UNSIGNED)
-STARTWRITE(st_uwstartwrite,ST_SIZE_WORD,ST_ENCODING_UNSIGNED)
-
-STARTREAD(st_swstartread,ST_SIZE_WORD,ST_ENCODING_SIGN2)
-STARTWRITE(st_swstartwrite,ST_SIZE_WORD,ST_ENCODING_SIGN2)
-
-STARTREAD(st_u3startread,ST_SIZE_24BIT,ST_ENCODING_UNSIGNED)
-STARTWRITE(st_u3startwrite,ST_SIZE_24BIT,ST_ENCODING_UNSIGNED)
-
-STARTREAD(st_s3startread,ST_SIZE_24BIT,ST_ENCODING_SIGN2)
-STARTWRITE(st_s3startwrite,ST_SIZE_24BIT,ST_ENCODING_SIGN2)
-
-STARTREAD(st_u4startread,ST_SIZE_DWORD,ST_ENCODING_UNSIGNED)
-STARTWRITE(st_u4startwrite,ST_SIZE_DWORD,ST_ENCODING_UNSIGNED)
-
-STARTREAD(st_slstartread,ST_SIZE_DWORD,ST_ENCODING_SIGN2)
-STARTWRITE(st_slstartwrite,ST_SIZE_DWORD,ST_ENCODING_SIGN2)
-
-STARTREAD(st_ulstartread,ST_SIZE_BYTE,ST_ENCODING_ULAW)
-STARTWRITE(st_ulstartwrite,ST_SIZE_BYTE,ST_ENCODING_ULAW)
-
-STARTREAD(st_alstartread,ST_SIZE_BYTE,ST_ENCODING_ALAW)
-STARTWRITE(st_alstartwrite,ST_SIZE_BYTE,ST_ENCODING_ALAW)
-
-STARTREAD(st_lustartread,ST_SIZE_BYTE,ST_ENCODING_INV_ULAW)
-STARTWRITE(st_lustartwrite,ST_SIZE_BYTE,ST_ENCODING_INV_ULAW)
-
-STARTREAD(st_lastartread,ST_SIZE_BYTE,ST_ENCODING_INV_ALAW)
-STARTWRITE(st_lastartwrite,ST_SIZE_BYTE,ST_ENCODING_INV_ALAW)
-
-void rawdefaults(ft_t ft)
-{
-        if (ft->signal.rate == 0)
-                ft->signal.rate = 8000;
-        if (ft->signal.channels == 0)
-                ft->signal.channels = 1;
+#define RAW_FORMAT(id,alt1,alt2,size,rev_bits,encoding) \
+static int id##_start(ft_t ft) { \
+  return st_rawstart(ft,true,true,ST_ENCODING_##encoding,ST_SIZE_##size,ST_REVERSE_##rev_bits); \
+} \
+st_format_t const * st_##id##_format_fn(void) { \
+  static char const * names[] = {#id, alt1, alt2, NULL}; \
+  static st_format_t driver = { \
+    names, NULL, ST_FILE_STEREO, \
+    id##_start, st_rawread , st_rawstopread, \
+    id##_start, st_rawwrite, st_rawstopwrite, \
+    st_format_nothing_seek \
+  }; \
+  return &driver; \
 }
 
-static const char *rawnames[] = {
-  "raw",
-  NULL
-};
-
-static st_format_t st_raw_format = {
-  rawnames,
-  NULL,
-  ST_FILE_STEREO | ST_FILE_SEEK,
-  st_rawstartread,
-  st_rawread,
-  st_rawstopread,
-  st_rawstartwrite,
-  st_rawwrite,
-  st_rawstopwrite,
-  st_rawseek
-};
-
-const st_format_t *st_raw_format_fn(void)
-{
-    return &st_raw_format;
-}
-
-/* a-law byte raw */
-static const char *alnames[] = {
-  "al",
-  NULL
-};
-
-static st_format_t st_al_format = {
-  alnames,
-  NULL,
-  ST_FILE_STEREO,
-  st_alstartread,
-  st_rawread,
-  st_rawstopread,
-  st_alstartwrite,
-  st_rawwrite,
-  st_rawstopwrite,
-  st_format_nothing_seek
-};
-
-const st_format_t *st_al_format_fn(void)
-{
-    return &st_al_format;
-}
-
-/* inverse a-law byte raw */
-static const char *lanames[] = {
-  "la",
-  NULL
-};
-
-static st_format_t st_la_format = {
-  lanames,
-  NULL,
-  ST_FILE_STEREO,
-  st_lastartread,
-  st_rawread,
-  st_rawstopread,
-  st_lastartwrite,
-  st_rawwrite,
-  st_rawstopwrite,
-  st_format_nothing_seek
-};
-
-const st_format_t *st_la_format_fn(void)
-{
-    return &st_la_format;
-}
-
-/* inverse u-law byte raw */
-static const char *lunames[] = {
-  "lu",
-  NULL
-};
-
-static st_format_t st_lu_format = {
-  lunames,
-  NULL,
-  ST_FILE_STEREO,
-  st_lustartread,
-  st_rawread,
-  st_rawstopread,
-  st_lustartwrite,
-  st_rawwrite,
-  st_rawstopwrite,
-  st_format_nothing_seek
-};
-
-const st_format_t *st_lu_format_fn(void)
-{
-    return &st_lu_format;
-}
-
-static const char *sbnames[] = {
-  "sb",
-  NULL
-};
-
-static st_format_t st_sb_format = {
-  sbnames,
-  NULL,
-  ST_FILE_STEREO,
-  st_sbstartread,
-  st_rawread,
-  st_rawstopread,
-  st_sbstartwrite,
-  st_rawwrite,
-  st_rawstopwrite,
-  st_format_nothing_seek
-};
-
-const st_format_t *st_sb_format_fn(void)
-{
-    return &st_sb_format;
-}
-
-
-
-/* Unsigned 4 byte raw; used for testing only; not documented in the man page */
-
-static const char *u4names[] = {
-  "u4",
-  NULL,
-};
-
-static st_format_t st_u4_format = {
-  u4names,
-  NULL,
-  ST_FILE_STEREO,
-  st_u4startread,
-  st_rawread,
-  st_rawstopread,
-  st_u4startwrite,
-  st_rawwrite,
-  st_rawstopwrite,
-  st_format_nothing_seek
-};
-
-const st_format_t *st_u4_format_fn(void)
-{
-    return &st_u4_format;
-}
-
-
-
-static const char *slnames[] = {
-  "sl",
-  NULL,
-};
-
-static st_format_t st_sl_format = {
-  slnames,
-  NULL,
-  ST_FILE_STEREO,
-  st_slstartread,
-  st_rawread,
-  st_rawstopread,
-  st_slstartwrite,
-  st_rawwrite,
-  st_rawstopwrite,
-  st_format_nothing_seek
-};
-
-const st_format_t *st_sl_format_fn(void)
-{
-    return &st_sl_format;
-}
-
-static const char *swnames[] = {
-  "sw",
-  NULL
-};
-
-static st_format_t st_sw_format = {
-  swnames,
-  NULL,
-  ST_FILE_STEREO,
-  st_swstartread,
-  st_rawread,
-  st_rawstopread,
-  st_swstartwrite,
-  st_rawwrite,
-  st_rawstopwrite,
-  st_format_nothing_seek
-};
-
-const st_format_t *st_sw_format_fn(void)
-{
-    return &st_sw_format;
-}
-
-
-
-/* Signed 3 byte raw; used for testing only; not documented in the man page */
-
-static const char *s3names[] = {
-  "s3",
-  NULL
-};
-
-static st_format_t st_s3_format = {
-  s3names,
-  NULL,
-  ST_FILE_STEREO,
-  st_s3startread,
-  st_rawread,
-  st_rawstopread,
-  st_s3startwrite,
-  st_rawwrite,
-  st_rawstopwrite,
-  st_format_nothing_seek
-};
-
-const st_format_t *st_s3_format_fn(void)
-{
-    return &st_s3_format;
-}
-
-
-
-static const char *ubnames[] = {
-  "ub",
-  "sou",
-  "fssd",
-  NULL
-};
-
-static st_format_t st_ub_format = {
-  ubnames,
-  NULL,
-  ST_FILE_STEREO,
-  st_ubstartread,
-  st_rawread,
-  st_rawstopread,
-  st_ubstartwrite,
-  st_rawwrite,
-  st_rawstopwrite,
-  st_format_nothing_seek
-};
-
-const st_format_t *st_ub_format_fn(void)
-{
-    return &st_ub_format;
-}
-
-static const char *ulnames[] = {
-  "ul",
-  NULL
-};
-
-static st_format_t st_ul_format = {
-  ulnames,
-  NULL,
-  ST_FILE_STEREO,
-  st_ulstartread,
-  st_rawread,
-  st_rawstopread,
-  st_ulstartwrite,
-  st_rawwrite,
-  st_rawstopwrite,
-  st_format_nothing_seek
-};
-
-const st_format_t *st_ul_format_fn(void)
-{
-    return &st_ul_format;
-}
-
-static const char *uwnames[] = {
-  "uw",
-  NULL
-};
-
-static st_format_t st_uw_format = {
-  uwnames,
-  NULL,
-  ST_FILE_STEREO,
-  st_uwstartread,
-  st_rawread,
-  st_rawstopread,
-  st_uwstartwrite,
-  st_rawwrite,
-  st_rawstopwrite,
-  st_format_nothing_seek
-};
-
-const st_format_t *st_uw_format_fn(void)
-{
-    return &st_uw_format;
-}
-
-
-
-/* Unsigned 3 byte raw; used for testing only; not documented in the man page */
-
-static const char *u3names[] = {
-  "u3",
-  NULL
-};
-
-static st_format_t st_u3_format = {
-  u3names,
-  NULL,
-  ST_FILE_STEREO,
-  st_u3startread,
-  st_rawread,
-  st_rawstopread,
-  st_u3startwrite,
-  st_rawwrite,
-  st_rawstopwrite,
-  st_format_nothing_seek
-};
-
-const st_format_t *st_u3_format_fn(void)
-{
-    return &st_u3_format;
-}
+RAW_FORMAT(sb,NULL ,NULL  ,BYTE ,DEFAULT,SIGN2)
+RAW_FORMAT(sl,NULL ,NULL  ,DWORD,DEFAULT,SIGN2)
+RAW_FORMAT(s3,NULL ,NULL  ,24BIT,DEFAULT,SIGN2)
+RAW_FORMAT(sw,NULL ,NULL  ,WORD ,DEFAULT,SIGN2)
+                   
+RAW_FORMAT(ub,"sou","fssd",BYTE ,DEFAULT,UNSIGNED)
+RAW_FORMAT(uw,NULL ,NULL  ,WORD ,DEFAULT,UNSIGNED)
+RAW_FORMAT(u3,NULL ,NULL  ,24BIT,DEFAULT,UNSIGNED)
+RAW_FORMAT(u4,NULL ,NULL  ,DWORD,DEFAULT,UNSIGNED)
+                   
+RAW_FORMAT(al,NULL ,NULL  ,BYTE ,NO     ,ALAW)
+RAW_FORMAT(ul,NULL ,NULL  ,BYTE ,NO     ,ULAW)
+RAW_FORMAT(la,NULL ,NULL  ,BYTE ,YES    ,ALAW)
+RAW_FORMAT(lu,NULL ,NULL  ,BYTE ,YES    ,ULAW)
--- a/src/sf.c
+++ b/src/sf.c
@@ -39,7 +39,7 @@
         sfcodep = (SFCODE *) &sfcodes(sfhead);
         do {
                 sfcharp = (char *) sfcodep + sizeof(SFCODE);
-                if (ft->signal.swap_bytes) {
+                if (ft->signal.reverse_bytes) {
                         sfcodep->bsize = st_swapdw(sfcodep->bsize);
                         sfcodep->code = st_swapdw(sfcodep->code);
                 }
@@ -103,7 +103,7 @@
                 return(ST_EOF);
         }
         memcpy(&sf->info, &sfhead.sfinfo, sizeof(struct sfinfo));
-        if (ft->signal.swap_bytes) {
+        if (ft->signal.reverse_bytes) {
                 sf->info.sf_srate = st_swapf(sf->info.sf_srate);
                 sf->info.sf_packmode = st_swapdw(sf->info.sf_packmode);
                 sf->info.sf_chans = st_swapdw(sf->info.sf_chans);
--- a/src/sox.c
+++ b/src/sox.c
@@ -108,6 +108,7 @@
 /* Arrays tracking input and output files */
 static file_info_t file_opts[MAX_FILES];
 static ft_t file_desc[MAX_FILES];
+#define ofile file_desc[file_count - 1]
 static size_t file_count = 0;
 static size_t input_count = 0;
 
@@ -174,7 +175,7 @@
 static void cleanup(void) 
 {
   size_t i;
-  ft_t ft = file_desc[file_count - 1];
+  ft_t ft = ofile;
 
   /* Close the input and output files before exiting. */
   for (i = 0; i < input_count; i++)
@@ -212,7 +213,9 @@
   fo->signal.size = -1;
   fo->signal.encoding = ST_ENCODING_UNKNOWN;
   fo->signal.channels = 0;
-  fo->signal.swap_bytes = ST_SWAP_DEFAULT;
+  fo->signal.reverse_bytes = ST_REVERSE_DEFAULT;
+  fo->signal.reverse_nibbles = ST_REVERSE_DEFAULT;
+  fo->signal.reverse_bits = ST_REVERSE_DEFAULT;
   fo->signal.compression = HUGE_VAL;
   fo->volume = HUGE_VAL;
   fo->volume_clips = 0;
@@ -413,7 +416,7 @@
   return result;
 }
 
-static char *getoptstr = "+r:v:t:c:C:hsuUAaig1b2w34lf8dxV::SqoenmMRLBX";
+static char *getoptstr = "+abc:defghilmnoqr:st:uv:wxABC:DLMNRSUV::X12348";
 
 static struct option long_options[] =
   {
@@ -433,6 +436,7 @@
     {"no-show-progress",       no_argument, NULL, 'q'},
     {"rate"            , required_argument, NULL, 'r'},
     {"reverse-bits"    ,       no_argument, NULL, 'X'},
+    {"reverse-nibbles" ,       no_argument, NULL, 'N'},
     {"show-progress"   ,       no_argument, NULL, 'S'},
     {"type"            ,       no_argument, NULL, 't'},
     {"volume"          , required_argument, NULL, 'v'},
@@ -462,11 +466,11 @@
 
       case 2:
         if (!strcmp(optarg, "little"))
-          fo->signal.swap_bytes = ST_IS_BIGENDIAN;
+          fo->signal.reverse_bytes = ST_IS_BIGENDIAN;
         else if (!strcmp(optarg, "big"))
-          fo->signal.swap_bytes = ST_IS_LITTLEENDIAN;
+          fo->signal.reverse_bytes = ST_IS_LITTLEENDIAN;
         else if (!strcmp(optarg, "swap"))
-          fo->signal.swap_bytes = true;
+          fo->signal.reverse_bytes = true;
         break;
 
       case 3:
@@ -558,7 +562,9 @@
     case 'u': fo->signal.encoding = ST_ENCODING_UNSIGNED;  break;
     case 'f': fo->signal.encoding = ST_ENCODING_FLOAT;     break;
     case 'a': fo->signal.encoding = ST_ENCODING_ADPCM;     break;
+    case 'D': fo->signal.encoding = ST_ENCODING_MS_ADPCM;  break; /* WIP */
     case 'i': fo->signal.encoding = ST_ENCODING_IMA_ADPCM; break;
+    case 'o': fo->signal.encoding = ST_ENCODING_OKI_ADPCM; break; /* WIP */
     case 'g': fo->signal.encoding = ST_ENCODING_GSM;       break;
 
     case 'U': fo->signal.encoding = ST_ENCODING_ULAW;
@@ -572,21 +578,25 @@
       break;
 
     case 'L':
-      fo->signal.swap_bytes = ST_IS_BIGENDIAN;
+      fo->signal.reverse_bytes = ST_IS_BIGENDIAN;
       break;
 
     case 'B':
-      fo->signal.swap_bytes = ST_IS_LITTLEENDIAN;
+      fo->signal.reverse_bytes = ST_IS_LITTLEENDIAN;
       break;
 
     case 'x':
-      fo->signal.swap_bytes = ST_SWAP_YES;
+      fo->signal.reverse_bytes = ST_REVERSE_YES;
       break;
 
     case 'X':
-      fo->signal.reverse_bits = true;
+      fo->signal.reverse_bits = ST_REVERSE_YES;
       break;
 
+    case 'N':
+      fo->signal.reverse_nibbles = ST_REVERSE_YES;
+      break;
+
     case 'V':
       if (optarg == NULL)
         ++st_output_verbosity_level;
@@ -622,6 +632,32 @@
   return ST_EOF;
 }
 
+static void report_file(ft_t f)
+{
+  static char const * const no_yes[] = {"no", "yes"};
+
+  st_report("\n\n%s: %s\n"
+    "Sample Size    : %s\n"
+    "Sample Encoding: %s\n"
+    "Channels       : %u\n"
+    "Sample Rate    : %lu\n"
+    "Endian Type    : %s\n"
+    "Reverse Nibbles: %s\n"
+    "Reverse Bits   : %s\n"
+    "Comment        : \"%s%c\n", /* Deliberate \n to get blank line */
+    f->mode == 'r'? "Input Filename " : "Output Filename",
+    f->filename, 
+    st_sizes_str[(unsigned char)f->signal.size],
+    st_encodings_str[(unsigned char)f->signal.encoding],
+    f->signal.channels,
+    f->signal.rate,
+    f->signal.size == 1? "N/A" : 
+      f->signal.reverse_bytes != ST_IS_BIGENDIAN? "big" : "little",
+    no_yes[f->signal.reverse_nibbles],
+    no_yes[f->signal.reverse_bits],
+    f->comment? f->comment : "\bnone", f->comment? '"' : ' ');
+}
+
 /*
  * Process input file -> effect table -> output file one buffer at a time
  */
@@ -634,17 +670,10 @@
   st_sample_t *ibuf[MAX_INPUT_FILES];
 
   for (f = 0; f < input_count; f++) {
-    st_report("Input file %s: using sample rate %lu\n\tsize %s, encoding %s, %d %s, volume %g",
-              file_desc[f]->filename, file_desc[f]->signal.rate,
-              st_sizes_str[(unsigned char)file_desc[f]->signal.size],
-              st_encodings_str[(unsigned char)file_desc[f]->signal.encoding],
-              file_desc[f]->signal.channels,
-              (file_desc[f]->signal.channels > 1) ? "channels" : "channel",
-              file_opts[f]->volume == HUGE_VAL? 1 : file_opts[f]->volume);
-    
-    if (file_desc[f]->comment)
-      st_report("Input file %s: comment \"%s\"",
-                file_desc[f]->filename, file_desc[f]->comment);
+    report_file(file_desc[f]);
+    if (file_opts[f]->volume != HUGE_VAL && file_opts[f]->volume != 1)
+      st_report("%s input level %g",
+              file_desc[f]->filename, file_opts[f]->volume);
   }
 
   for (f = 0; f < input_count; f++) {
@@ -695,8 +724,7 @@
       loops[i].type = file_desc[0]->loops[i].type;
     }
     
-    file_desc[file_count - 1] = 
-      st_open_write(overwrite_permitted,
+    ofile = st_open_write(overwrite_permitted,
                           info->filename,
                           &info->signal, 
                           info->filetype,
@@ -704,7 +732,7 @@
                           &file_desc[0]->instr,
                           loops);
     
-    if (!file_desc[file_count - 1])
+    if (!ofile)
       /* st_open_write() will call st_warn for most errors.
        * Rely on that printing something. */
       exit(2);
@@ -712,23 +740,13 @@
     /* When writing to an audio device, auto turn on the
      * status display to match behavior of ogg123 status,
      * unless the user requested us not to display anything. */
-    if ((strcmp(file_desc[file_count - 1]->filetype, "alsa") == 0 ||
-        strcmp(file_desc[file_count - 1]->filetype, "ossdsp") == 0 ||
-         strcmp(file_desc[file_count - 1]->filetype, "sunau") == 0) &&
+    if ((strcmp(ofile->filetype, "alsa") == 0 ||
+        strcmp(ofile->filetype, "ossdsp") == 0 ||
+         strcmp(ofile->filetype, "sunau") == 0) &&
         !quiet)
       status = 1;
 
-    st_report("Output file %s: using sample rate %lu\n\tsize %s, encoding %s, %d %s",
-              file_desc[file_count-1]->filename, 
-              file_desc[file_count-1]->signal.rate,
-              st_sizes_str[(unsigned char)file_desc[file_count-1]->signal.size],
-              st_encodings_str[(unsigned char)file_desc[file_count-1]->signal.encoding],
-              file_desc[file_count-1]->signal.channels,
-              (file_desc[file_count-1]->signal.channels > 1) ? "channels" : "channel");
-    
-    if (file_desc[file_count - 1]->comment)
-      st_report("Output file: comment \"%s\"", 
-                file_desc[file_count - 1]->comment);
+    report_file(ofile);
   }
   
   /* Adjust the input rate for the speed effect */
@@ -914,12 +932,12 @@
         break;
 
       /* If there's an error, don't try to write more. */
-      if (file_desc[file_count - 1]->st_errno)
+      if (ofile->st_errno)
         break;
     } while (flowstatus == 0);
 
     /* Drain the effects; don't write if output is indicating errors. */
-    if (file_desc[file_count - 1]->st_errno == 0)
+    if (ofile->st_errno == 0)
       drain_effect_out();
   }
 
@@ -1001,8 +1019,8 @@
   int effects_mask = 0;
   int status;
 
-  needrate = (file_desc[0]->signal.rate != file_desc[file_count-1]->signal.rate);
-  needchan = (file_desc[0]->signal.channels != file_desc[file_count-1]->signal.channels);
+  needrate = (file_desc[0]->signal.rate != ofile->signal.rate);
+  needchan = (file_desc[0]->signal.channels != ofile->signal.channels);
 
   for (i = 0; i < nuser_effects; i++) {
     if (user_efftab[i].h->flags & ST_EFF_CHAN)
@@ -1027,7 +1045,7 @@
    * after the avg effect.      
    */   
   if (needchan && !(haschan) &&
-      (file_desc[0]->signal.channels > file_desc[file_count-1]->signal.channels))
+      (file_desc[0]->signal.channels > ofile->signal.channels))
   { 
       /* Find effect and update initial pointers */
       st_geteffect(&efftab[neffects], "avg");
@@ -1043,7 +1061,7 @@
       /* Copy format info to effect table */
       effects_mask = st_updateeffect(&efftab[neffects], 
                                      &file_desc[0]->signal,
-                                     &file_desc[file_count-1]->signal,
+                                     &ofile->signal,
                                      effects_mask);
 
       neffects++;
@@ -1053,7 +1071,7 @@
    * after the resample effect. 
    */
   if (needrate && !(hasrate) &&
-      (file_desc[0]->signal.rate > file_desc[file_count-1]->signal.rate)) 
+      (file_desc[0]->signal.rate > ofile->signal.rate)) 
   {
       st_geteffect(&efftab[neffects], "resample");
 
@@ -1068,7 +1086,7 @@
       /* Copy format info to effect table */ 
       effects_mask = st_updateeffect(&efftab[neffects],
                                      &file_desc[0]->signal,
-                                     &file_desc[file_count-1]->signal,
+                                     &ofile->signal,
                                      effects_mask);
 
       /* Rate can't handle multiple channels so be sure and
@@ -1088,7 +1106,7 @@
     /* Copy format info to effect table */
     effects_mask = st_updateeffect(&efftab[neffects], 
                                    &file_desc[0]->signal,
-                                   &file_desc[file_count - 1]->signal, 
+                                   &ofile->signal, 
                                    effects_mask);
     
     /* If this effect can't handle multiple channels then
@@ -1118,7 +1136,7 @@
     /* Copy format info to effect table */
     effects_mask = st_updateeffect(&efftab[neffects], 
                                    &file_desc[0]->signal,
-                                   &file_desc[file_count - 1]->signal, 
+                                   &ofile->signal, 
                                    effects_mask);
 
     /* Rate can't handle multiple channels so be sure and
@@ -1144,7 +1162,7 @@
     /* Copy format info to effect table */
     effects_mask = st_updateeffect(&efftab[neffects], 
                                    &file_desc[0]->signal,
-                                   &file_desc[file_count - 1]->signal, 
+                                   &ofile->signal, 
                                    effects_mask);
     
     neffects++;
@@ -1220,22 +1238,22 @@
         if (user_abort)
           return ST_EOF;
             
-        len = st_write(file_desc[file_count - 1], 
+        len = st_write(ofile, 
                        &efftab[neffects - 1].obuf[total],
                        efftab[neffects - 1].olen - total);
             
-        if (len != efftab[neffects - 1].olen - total || file_desc[file_count - 1]->eof) {
-          st_warn("Error writing: %s", file_desc[file_count - 1]->st_errstr);
+        if (len != efftab[neffects - 1].olen - total || ofile->eof) {
+          st_warn("Error writing: %s", ofile->st_errstr);
           return ST_EOF;
         }
         total += len;
       } while (total < efftab[neffects-1].olen);
-      output_samples += (total / file_desc[file_count - 1]->signal.channels);
+      output_samples += (total / ofile->signal.channels);
       efftab[neffects-1].odone = efftab[neffects-1].olen = 0;
     } else {
       /* Make it look like everything was consumed */
       output_samples += (efftab[neffects-1].olen / 
-                         file_desc[file_count - 1]->signal.channels);
+                         ofile->signal.channels);
       efftab[neffects-1].odone = efftab[neffects-1].olen = 0;
     }
 
@@ -1259,7 +1277,7 @@
          * will cause stereo channels to be inversed.
          */
         if ((efftab[e].olen - efftab[e].odone) >= 
-            file_desc[file_count - 1]->signal.channels)
+            ofile->signal.channels)
           havedata = 1;
         else
           st_warn("Received buffer with incomplete amount of samples.");
@@ -1643,7 +1661,8 @@
          "                Specify file containing comment text for the output file\n"
          "-r rate         sample rate of audio\n"
          "-t filetype     file type of audio\n"
-         "-x              invert auto-detected endianess of data\n"
+         "-x/-N/-X        invert auto-detected endianness/nibble-order/bit-order of data\n"
+         "-B/-L           force endian type to big/little\n"
          "-s/-u/-U/-A/    sample encoding: signed/unsigned/u-law/A-law\n"
          "  -a/-i/-g/-f   ADPCM/IMA_ADPCM/GSM/floating point\n"
          "-1/-2/-3/-4/-8  sample size in bytes\n"
--- a/src/sphere.c
+++ b/src/sphere.c
@@ -105,9 +105,9 @@
             {
                 sscanf(buf, "%53s %15s %127s", fldname, fldtype, fldsval);
                 if (strncmp(fldsval,"01",2) == 0)
-                  ft->signal.swap_bytes = ST_IS_BIGENDIAN; /* Data is little endian. */
+                  ft->signal.reverse_bytes = ST_IS_BIGENDIAN; /* Data is little endian. */
                 else if (strncmp(fldsval,"10",2) == 0)
-                  ft->signal.swap_bytes = ST_IS_LITTLEENDIAN; /* Data is big endian. */
+                  ft->signal.reverse_bytes = ST_IS_LITTLEENDIAN; /* Data is big endian. */
             }
 
             if (st_reads(ft, buf, header_size) == ST_EOF)
@@ -263,7 +263,7 @@
     st_writes(ft, buf);
 
     sprintf(buf, "sample_byte_format -s2 %s\n",
-        ft->signal.swap_bytes != ST_IS_BIGENDIAN ? "10" : "01");
+        ft->signal.reverse_bytes != ST_IS_BIGENDIAN ? "10" : "01");
     st_writes(ft, buf);
 
     rate = ft->signal.rate;
--- a/src/st.h
+++ b/src/st.h
@@ -171,20 +171,23 @@
 
 typedef enum {
   ST_ENCODING_UNKNOWN   ,
-  ST_ENCODING_UNSIGNED  , /* unsigned linear: Sound Blaster */
-  ST_ENCODING_SIGN2     , /* signed linear 2's comp: Mac */
+
   ST_ENCODING_ULAW      , /* u-law signed logs: US telephony, SPARC */
   ST_ENCODING_ALAW      , /* A-law signed logs: non-US telephony */
+  ST_ENCODING_ADPCM     , /* G72x Compressed PCM */
+  ST_ENCODING_MS_ADPCM  , /* Microsoft Compressed PCM */
+  ST_ENCODING_IMA_ADPCM , /* IMA Compressed PCM */
+  ST_ENCODING_OKI_ADPCM , /* Dialogic/OKI Compressed PCM */
+
+  ST_ENCODING_SIZE_IS_WORD, /* FIXME: marks raw types (above) that mis-report size. st_signalinfo_t really needs a precision_in_bits item */
+
+  ST_ENCODING_UNSIGNED  , /* unsigned linear: Sound Blaster */
+  ST_ENCODING_SIGN2     , /* signed linear 2's comp: Mac */
   ST_ENCODING_FLOAT     , /* 32-bit float */
-  ST_ENCODING_ADPCM     , /* Compressed PCM */
-  ST_ENCODING_IMA_ADPCM , /* Compressed PCM */
   ST_ENCODING_GSM       , /* GSM 6.10 33byte frame lossy compression */
-  ST_ENCODING_INV_ULAW  , /* Inversed bit-order u-law */
-  ST_ENCODING_INV_ALAW  , /* Inversed bit-order A-law */
   ST_ENCODING_MP3       , /* MP3 compression */
   ST_ENCODING_VORBIS    , /* Vorbis compression */
   ST_ENCODING_FLAC      , /* FLAC compression */
-  ST_ENCODING_OKI_ADPCM , /* Compressed PCM */
 
   ST_ENCODINGS            /* End of list marker */
 } st_encoding_t;
@@ -197,6 +200,8 @@
     double speed;         /* Gather up all speed changes here, then resample */
 } st_globalinfo_t;
 
+typedef enum {ST_REVERSE_NO, ST_REVERSE_YES, ST_REVERSE_DEFAULT} st_reverse_t;
+
 /* Signal parameters */
 
 typedef struct  st_signalinfo
@@ -205,8 +210,9 @@
     signed char size;     /* word length of data */
     st_encoding_t encoding; /* format of sample numbers */
     unsigned channels;    /* number of sound channels */
-    enum {ST_SWAP_NO, ST_SWAP_YES, ST_SWAP_DEFAULT} swap_bytes; /* endian */
-    bool reverse_bits;
+    st_reverse_t reverse_bytes;    /* endiannesses... */
+    st_reverse_t reverse_nibbles;
+    st_reverse_t reverse_bits;
     double compression;   /* compression factor (where applicable) */
 } st_signalinfo_t;
 
@@ -384,7 +390,7 @@
     char priv[ST_MAX_EFFECT_PRIVSIZE]; /* private area for effect */
 };
 
-void set_swap_if_not_already_set(ft_t ft);
+void set_endianness_if_not_already_set(ft_t ft);
 extern ft_t st_open_read(const char *path, const st_signalinfo_t *info, 
                          const char *filetype);
 ft_t st_open_write(
--- a/src/st_i.h
+++ b/src/st_i.h
@@ -251,10 +251,11 @@
 int st_effect_nothing_drain(eff_t effp, st_sample_t *obuf, st_size_t *osamp);
 int st_effect_nothing_getopts(eff_t effp, int n, char **argv UNUSED);
 
+int st_rawstart(ft_t ft, bool default_rate, bool default_channels, st_encoding_t encoding, signed char size, st_reverse_t rev_bits);
+#define st_rawstartread(ft) st_rawstart(ft, false, false, ST_ENCODING_UNKNOWN, -1, ST_REVERSE_DEFAULT)
+#define st_rawstartwrite st_rawstartread
 #define st_rawstopread st_format_nothing
-int st_rawstart(ft_t ft);
-#define st_rawstartread st_rawstart
-#define st_rawstartwrite st_rawstart
+
 
 /*=============================================================================
  * Effects
--- a/src/stio.c
+++ b/src/stio.c
@@ -25,14 +25,18 @@
 #define SET_BINARY_MODE(file)
 #endif
 
-void set_swap_if_not_already_set(ft_t ft)
+void set_endianness_if_not_already_set(ft_t ft)
 {
-  if (ft->signal.swap_bytes == ST_SWAP_DEFAULT) {
+  if (ft->signal.reverse_bytes == ST_REVERSE_DEFAULT) {
     if (ft->h->flags & ST_FILE_ENDIAN)
-      ft->signal.swap_bytes = ST_IS_LITTLEENDIAN != !(ft->h->flags & ST_FILE_ENDBIG);
+      ft->signal.reverse_bytes = ST_IS_LITTLEENDIAN != !(ft->h->flags & ST_FILE_ENDBIG);
     else
-      ft->signal.swap_bytes = ST_SWAP_NO;
+      ft->signal.reverse_bytes = ST_REVERSE_NO;
   }
+  if (ft->signal.reverse_nibbles == ST_REVERSE_DEFAULT)
+    ft->signal.reverse_nibbles = ST_REVERSE_NO;
+  if (ft->signal.reverse_bits == ST_REVERSE_DEFAULT)
+    ft->signal.reverse_bits = ST_REVERSE_NO;
 }
 
 static int is_seekable(ft_t ft)
@@ -132,7 +136,7 @@
     }
 
     if (filetype)
-      set_swap_if_not_already_set(ft);
+      set_endianness_if_not_already_set(ft);
 
     /* Read and write starters can change their formats. */
     if ((*ft->h->startread)(ft) != ST_SUCCESS)
@@ -268,7 +272,7 @@
     if (instr)
         ft->instr = *instr;
 
-    set_swap_if_not_already_set(ft);
+    set_endianness_if_not_already_set(ft);
 
     /* Read and write starters can change their formats. */
     if ((*ft->h->startwrite)(ft) != ST_SUCCESS)
--- a/src/wav.c
+++ b/src/wav.c
@@ -408,7 +408,7 @@
     if (strncmp("RIFX", magic, 4) == 0) 
     {
         st_debug("Found RIFX header, swapping bytes");
-        ft->signal.swap_bytes = ST_IS_LITTLEENDIAN;
+        ft->signal.reverse_bytes = ST_IS_LITTLEENDIAN;
     }
 
     st_readdw(ft, &dwRiffLength);
@@ -1457,7 +1457,7 @@
     /* If user specified opposite swap then we think, assume they are
      * asking to write a RIFX file.
      */
-    if (ft->signal.swap_bytes != ST_IS_BIGENDIAN)
+    if (ft->signal.reverse_bytes != ST_IS_BIGENDIAN)
     {
         if (!second_header)
             st_report("Requested to swap bytes so writing  RIFX header");
--- a/src/wve.c
+++ b/src/wve.c
@@ -79,7 +79,7 @@
                  * testing for endianess was standardized.  Leaving since
                  * it doesn't hurt.
                  */
-                ft->signal.swap_bytes = !ft->signal.swap_bytes;
+                ft->signal.reverse_bytes = !ft->signal.reverse_bytes;
                 st_debug("Found inverted PSION magic word.  Swapping bytes.");
         }
         else if (version == PSION_VERSION)