shithub: sox

Download patch

ref: 2bd648a7378ed4eba107c2ee60392575945ae3f1
parent: 1f70a30a0d51cfd6499c4d76be8a593a91fd5a3d
author: robs <robs>
date: Sat Jan 24 14:44:05 EST 2009

updates for --guard

--- a/ChangeLog
+++ b/ChangeLog
@@ -90,6 +90,7 @@
     header (for simple encodings); instead, read to end of file.  (robs)
   o New `--temp DIRECTORY' option.  (robs)
   o Grouped files, e.g. play -r 6k "*.vox" plays all at 6k.  (robs)
+  o Automatically `dither'; new `--no-dither' option to disable this.  (robs)
   o New bitrate, time in seconds, & total options for soxi.  (robs)
 
 Other bug fixes:
--- a/src/.cvsignore
+++ b/src/.cvsignore
@@ -1,4 +1,5 @@
 Makefile Makefile.in
+sox_sample_test
 example0 example1 example2
 soxconfig.h.in soxconfig.h soxstdint.h
 .deps
--- a/src/8svx.c
+++ b/src/8svx.c
@@ -254,6 +254,7 @@
 static size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, size_t len)
 {
         priv_t * p = (priv_t * ) ft->priv;
+        SOX_SAMPLE_LOCALS;
 
         unsigned char datum;
         size_t done = 0, i;
@@ -262,7 +263,7 @@
 
         while(done < len) {
                 for (i = 0; i < ft->signal.channels; i++) {
-                        datum = SOX_SAMPLE_TO_SIGNED_8BIT(*buf++);
+                        datum = SOX_SAMPLE_TO_SIGNED_8BIT(*buf++, ft->clips);
                         /* FIXME: Needs to pass ft struct and not FILE */
                         putc(datum, p->ch[i]);
                 }
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -62,6 +62,7 @@
 )
 add_executable(${PROJECT_NAME} ${PROJECT_NAME}.c)
 target_link_libraries(${PROJECT_NAME} lib${PROJECT_NAME} lpc10 ${optional_libs})
+add_executable(sox_sample_test sox_sample_test.c)
 add_executable(example0 example0.c)
 target_link_libraries(example0 lib${PROJECT_NAME} lpc10 ${optional_libs})
 add_executable(example1 example1.c)
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -28,7 +28,7 @@
 #########################
 
 bin_PROGRAMS = sox
-EXTRA_PROGRAMS = example0 example1 example2
+EXTRA_PROGRAMS = example0 example1 example2 sox_sample_test
 lib_LTLIBRARIES = libsox.la
 include_HEADERS = sox.h
 nodist_include_HEADERS = soxstdint.h
@@ -37,6 +37,7 @@
 example0_SOURCES = example0.c
 example1_SOURCES = example1.c
 example2_SOURCES = example2.c
+sox_sample_test_SOURCES = sox_sample_test.c sox_sample_test.h
 
 ###############################################
 # libsox - Dynamic Libraries for File Formats #
@@ -399,7 +400,7 @@
 	     CMakeLists.txt soxstdint.h.cmake soxconfig.h.cmake \
 	     tests.sh testall.sh tests.bat testall.bat test-comments
 
-all: sox$(EXEEXT) play rec soxi example0$(EXEEXT) example1$(EXEEXT) example2$(EXEEXT)
+all: sox$(EXEEXT) play rec soxi sox_sample_test$(EXEEXT) example0$(EXEEXT) example1$(EXEEXT) example2$(EXEEXT)
 
 play rec: sox$(EXEEXT)
 	if test "$(PLAYRECLINKS)" = "yes"; then	\
@@ -429,6 +430,7 @@
 
 clean-local:
 	$(RM) play rec soxi
+	$(RM) sox_sample_test$(EXEEXT)
 	$(RM) example0$(EXEEXT) example1$(EXEEXT) example2$(EXEEXT)
 
 distclean-local:
--- a/src/adpcms.c
+++ b/src/adpcms.c
@@ -251,7 +251,8 @@
   short word;
 
   while (count < length) {
-    word = SOX_SAMPLE_TO_SIGNED_16BIT(*buffer++);
+    SOX_SAMPLE_LOCALS;
+    word = SOX_SAMPLE_TO_SIGNED_16BIT(*buffer++, ft->clips);
 
     byte <<= 4;
     byte |= lsx_adpcm_encode(word, &state->encoder) & 0x0F;
--- a/src/alsa.c
+++ b/src/alsa.c
@@ -187,6 +187,7 @@
   priv_t             * p = (priv_t *)ft->priv;
   size_t             done, i, n;
   snd_pcm_sframes_t  actual;
+  SOX_SAMPLE_LOCALS;
 
   for (done = 0; done < len; done += n) {
     i = n = min(len - done, p->buf_len);
@@ -193,38 +194,38 @@
     switch (p->format) {
       case SND_PCM_FORMAT_S8: {
         int8_t * buf1 = (int8_t *)p->buf;
-        while (i--) *buf1++ = SOX_SAMPLE_TO_SIGNED_8BIT(*buf++);
+        while (i--) *buf1++ = SOX_SAMPLE_TO_SIGNED_8BIT(*buf++, ft->clips);
         break;
       }
       case SND_PCM_FORMAT_U8: {
         uint8_t * buf1 = (uint8_t *)p->buf;
-        while (i--) *buf1++ = SOX_SAMPLE_TO_UNSIGNED_8BIT(*buf++);
+        while (i--) *buf1++ = SOX_SAMPLE_TO_UNSIGNED_8BIT(*buf++, ft->clips);
         break;
       }
       case SND_PCM_FORMAT_S16: {
         int16_t * buf1 = (int16_t *)p->buf;
         if (ft->encoding.reverse_bytes) while (i--)
-          *buf1++ = lsx_swapw(SOX_SAMPLE_TO_SIGNED_16BIT(*buf++));
+          *buf1++ = lsx_swapw(SOX_SAMPLE_TO_SIGNED_16BIT(*buf++, ft->clips));
         else
-          while (i--) *buf1++ = SOX_SAMPLE_TO_SIGNED_16BIT(*buf++);
+          while (i--) *buf1++ = SOX_SAMPLE_TO_SIGNED_16BIT(*buf++, ft->clips);
         break;
       }
       case SND_PCM_FORMAT_U16: {
         uint16_t * buf1 = (uint16_t *)p->buf;
         if (ft->encoding.reverse_bytes) while (i--)
-          *buf1++ = lsx_swapw(SOX_SAMPLE_TO_UNSIGNED_16BIT(*buf++));
+          *buf1++ = lsx_swapw(SOX_SAMPLE_TO_UNSIGNED_16BIT(*buf++, ft->clips));
         else
-          while (i--) *buf1++ = SOX_SAMPLE_TO_UNSIGNED_16BIT(*buf++);
+          while (i--) *buf1++ = SOX_SAMPLE_TO_UNSIGNED_16BIT(*buf++, ft->clips);
         break;
       }
       case SND_PCM_FORMAT_S24: {
         int24_t * buf1 = (int24_t *)p->buf;
-        while (i--) *buf1++ = SOX_SAMPLE_TO_SIGNED_24BIT(*buf++);
+        while (i--) *buf1++ = SOX_SAMPLE_TO_SIGNED_24BIT(*buf++, ft->clips);
         break;
       }
       case SND_PCM_FORMAT_U24: {
         uint24_t * buf1 = (uint24_t *)p->buf;
-        while (i--) *buf1++ = SOX_SAMPLE_TO_UNSIGNED_24BIT(*buf++);
+        while (i--) *buf1++ = SOX_SAMPLE_TO_UNSIGNED_24BIT(*buf++, ft->clips);
         break;
       }
     }
--- a/src/amr.h
+++ b/src/amr.h
@@ -117,7 +117,8 @@
   size_t done;
 
   for (done = 0; done < len; ++done) {
-    p->pcm[p->pcm_index++] = SOX_SAMPLE_TO_SIGNED_16BIT(*buf++);
+    SOX_SAMPLE_LOCALS;
+    p->pcm[p->pcm_index++] = SOX_SAMPLE_TO_SIGNED_16BIT(*buf++, ft->clips);
     if (p->pcm_index == AMR_FRAME) {
       p->pcm_index = 0;
       if (!encode_1_frame(ft))
--- a/src/ao.c
+++ b/src/ao.c
@@ -74,11 +74,12 @@
   return SOX_SUCCESS;
 }
 
-static void sox_sw_write_buf(char *buf1, sox_sample_t const * buf2, size_t len, sox_bool swap)
+static void sox_sw_write_buf(char *buf1, sox_sample_t const * buf2, size_t len, sox_bool swap, size_t * clips)
 {
     while (len--)
     {
-        uint16_t datum = SOX_SAMPLE_TO_SIGNED_16BIT(*buf2++);
+        SOX_SAMPLE_LOCALS;
+        uint16_t datum = SOX_SAMPLE_TO_SIGNED_16BIT(*buf2++, *clips);
         if (swap)
             datum = lsx_swapw(datum);
         *(uint16_t *)buf1 = datum;
@@ -96,7 +97,8 @@
 
   aobuf_size = (ft->encoding.bits_per_sample >> 3) * len;
 
-  sox_sw_write_buf(ao->buf, buf, len, ft->encoding.reverse_bytes);
+  sox_sw_write_buf(ao->buf, buf, len, ft->encoding.reverse_bytes,
+                   &(ft->clips));
   if (ao_play(ao->device, (void *)ao->buf, aobuf_size) == 0)
     return 0;
 
--- a/src/bend.c
+++ b/src/bend.c
@@ -154,7 +154,7 @@
     ++p->in_pos;
 
     /* As long as we have not yet collected enough data just read in */
-    p->gInFIFO[p->gRover] = SOX_SAMPLE_TO_FLOAT_32BIT(ibuf[i]);
+    p->gInFIFO[p->gRover] = SOX_SAMPLE_TO_FLOAT_32BIT(ibuf[i], effp->clips);
     obuf[i] = SOX_FLOAT_32BIT_TO_SAMPLE(
         p->gOutFIFO[p->gRover - inFifoLatency], effp->clips);
     p->gRover++;
--- a/src/coreaudio.c
+++ b/src/coreaudio.c
@@ -285,7 +285,7 @@
   p = &ac->buffer[ac->buf_offset];
 
   while (samp_left--)
-    *p++ = SOX_SAMPLE_TO_FLOAT_32BIT(*buf++);
+    *p++ = SOX_SAMPLE_TO_FLOAT_32BIT(*buf++, ft->clips);
 
   ac->buf_offset += len;
 
--- a/src/dat.c
+++ b/src/dat.c
@@ -135,7 +135,8 @@
       sprintf(s," %15.8g ",dat->timevalue);
       lsx_writes(ft, s);
       for (i=0; i<ft->signal.channels; i++) {
-        sampval = SOX_SAMPLE_TO_FLOAT_64BIT(*buf++);
+        SOX_SAMPLE_LOCALS;
+        sampval = SOX_SAMPLE_TO_FLOAT_64BIT(*buf++, ft->clips);
         sprintf(s," %15.8g", sampval);
         lsx_writes(ft, s);
         done++;
--- a/src/delay.c
+++ b/src/delay.c
@@ -119,7 +119,7 @@
 sox_effect_handler_t const * sox_delay_effect_fn(void)
 {
   static sox_effect_handler_t handler = {
-    "delay", "{length}", SOX_EFF_LENGTH,
+    "delay", "{length}", SOX_EFF_LENGTH | SOX_EFF_MODIFY,
     create, start, flow, drain, stop, kill, sizeof(priv_t)
   };
   return &handler;
--- a/src/dft_filter.c
+++ b/src/dft_filter.c
@@ -79,7 +79,7 @@
     p->samples_in += (int)*isamp;
 
     for (i = *isamp; i; --i)
-      *t++ = SOX_SAMPLE_TO_FLOAT_64BIT(*ibuf++);
+      *t++ = SOX_SAMPLE_TO_FLOAT_64BIT(*ibuf++, effp->clips);
     filter(p);
   }
   else *isamp = 0;
--- a/src/dither.c
+++ b/src/dither.c
@@ -23,7 +23,12 @@
 #include "getopt.h"
 #include <assert.h>
 
-#define PREC effp->out_signal.precision
+#undef RANQD1
+#define RANQD1 ranqd1(p->ranqd1)
+#define SOX_ROUND_PREC_CLIP_COUNT(d, clips) \
+  ((d) < 0? (d) <= SOX_SAMPLE_MIN - 0.5? ++(clips), SOX_SAMPLE_MIN: (d) - 0.5 \
+  : (d) >= SOX_SAMPLE_MAX - (1 << (31-p->prec)) + 0.5? \
+  ++(clips), SOX_SAMPLE_MAX - (1 << (31-p->prec)): (d) + 0.5)
 
 typedef enum {Pdf_rectangular, Pdf_triangular, Pdf_gaussian} pdf_type_t;
 static lsx_enum_item const pdf_types[] = {
@@ -130,7 +135,7 @@
   {48000, iir,  4, 21.0, ges48, Shape_gesemann},
   {44100, iir,  4, 21.2, ges44, Shape_gesemann},
   {48000, fir, 16, 28.8, shi48, Shape_shibata},
-  {44100, fir, 20, 32.6, shi44, Shape_shibata},
+  {44100, fir, 20, 32.3, shi44, Shape_shibata},
   {37800, fir, 16, 22.7, shi38, Shape_shibata},
   {32000, fir, 16, 15.7, shi32, Shape_shibata},
   {22050, fir, 15,  9.0, shi22, Shape_shibata},
@@ -145,12 +150,13 @@
 typedef struct {
   pdf_type_t    pdf;
   filter_name_t filter_name;
+  sox_bool      reseed;
   double        am0, am1, depth;
   double        previous_errors[MAX_N * 2];
   double        previous_outputs[MAX_N * 2];
-  size_t        pos;
+  size_t        pos, prec;
+  int32_t       ranqd1;
   double const * coefs;
-  sox_sample_t  offset;
   int           (*flow)(sox_effect_t *, const sox_sample_t *, sox_sample_t *, size_t *, size_t *);
 } priv_t;
 
@@ -186,7 +192,7 @@
   size_t len = *isamp = *osamp = min(*isamp, *osamp);
 
   while (len--) {
-    double d = *ibuf++ + p->offset + floor(p->am0 * RANQD1) + floor(p->am1 * RANQD1);
+    double d = *ibuf++ + floor(p->am0 * RANQD1) + floor(p->am1 * RANQD1);
     SOX_SAMPLE_CLIP_COUNT(d, effp->clips);
     *obuf++ = d;
   }
@@ -199,7 +205,8 @@
   int c;
 
   p->pdf = Pdf_triangular;
-  while ((c = getopt(argc, argv, "+rtsf:")) != -1) switch (c) {
+  while ((c = getopt(argc, argv, "+Rrtsf:")) != -1) switch (c) {
+    case 'R': p->reseed = sox_true; break;
     case 'r': p->pdf = Pdf_rectangular; break;
     case 't': p->pdf = Pdf_triangular ; break;
     case 's': p->filter_name = Shape_shibata; break;
@@ -221,8 +228,10 @@
   priv_t * p = (priv_t *)effp->priv;
   double mult = 1;
 
-  if (PREC > 24)
+  p->prec = effp->out_signal.precision;
+  if (effp->in_signal.precision <= p->prec || p->prec > 24)
     return SOX_EFF_NULL;   /* Dithering not needed at this resolution */
+  effp->out_signal.precision = effp->in_signal.precision;
 
   p->flow = flow_no_shape;
   if (p->filter_name) {
@@ -249,14 +258,12 @@
       mult = dB_to_linear(f->gain);
     }
   }
-  p->am1 = p->depth / (1 << PREC);
+  p->ranqd1 = p->reseed? ranqd1(sox_globals.ranqd1) : 0;
+  p->am1 = p->depth / (1 << p->prec);
   p->am0 = (p->pdf == Pdf_triangular) * p->am1;
-  if (effp->out_encoding->half_bit && PREC < 32)
-    p->offset = 1 << (31 - PREC);
 
-  if (effp->flow == 0 && effp->in_signal.mult)
-    *effp->in_signal.mult *=
-      1 - (p->offset * (1./SOX_SAMPLE_MAX) + p->am0 + p->am1) * mult;
+  if (effp->in_signal.mult)
+    *effp->in_signal.mult *= 1 - (p->am0 + p->am1) * mult;
 
   lsx_debug("pdf=%s filter=%s depth=%g", lsx_find_enum_value(p->pdf, pdf_types)->text, lsx_find_enum_value(p->filter_name, filter_names)->text, p->depth);
   return SOX_SUCCESS;
@@ -273,6 +280,7 @@
 {
   static sox_effect_handler_t handler = {
     "dither", "[-r|-t] [-s|-f filter] [depth]"
+    "\n  -R       Re-seed PRNG"
     "\n  -r       Rectangular PDF"
     "\n  -t       Triangular PDF (default)"
     "\n  -s       Shape noise (with shibata filter)"
--- a/src/dither_fir.h
+++ b/src/dither_fir.h
@@ -7,12 +7,12 @@
 
   while (len--) {
     double r = floor(p->am0 * RANQD1) + floor(p->am1 * RANQD1);
-    double error, d = *ibuf++ + p->offset;
+    double error, d = *ibuf++;
     int j = 0;
     CONVOLVE
     assert(j == N);
-    *obuf = SOX_ROUND_CLIP_COUNT(d + r, effp->clips);
-    error = (*obuf++ & (-1 << (32-PREC))) + (1 << (31-PREC)) - d;
+    *obuf = SOX_ROUND_PREC_CLIP_COUNT(d + r, effp->clips);
+    error = ((*obuf++ + (1 << (31-p->prec))) & (-1 << (32-p->prec))) - d;
     p->pos = p->pos? p->pos - 1 : p->pos - 1 + N;
     p->previous_errors[p->pos + N] = p->previous_errors[p->pos] = error;
   }
--- a/src/dither_iir.h
+++ b/src/dither_iir.h
@@ -12,9 +12,9 @@
     int j = 0;
     CONVOLVE
     assert(j == N);
-    d = *ibuf++ + p->offset - output;
-    *obuf = SOX_ROUND_CLIP_COUNT(d + r, effp->clips);
-    error = (*obuf++ & (-1 << (32-PREC))) + (1 << (31-PREC)) - d;
+    d = *ibuf++ - output;
+    *obuf = SOX_ROUND_PREC_CLIP_COUNT(d + r, effp->clips);
+    error = ((*obuf++ + (1 << (31-p->prec))) & (-1 << (32-p->prec))) - d;
     p->pos = p->pos? p->pos - 1 : p->pos - 1 + N;
     p->previous_errors[p->pos + N] = p->previous_errors[p->pos] = error;
     p->previous_outputs[p->pos + N] = p->previous_outputs[p->pos] = output;
--- a/src/effects.c
+++ b/src/effects.c
@@ -94,7 +94,7 @@
 /* Effects chain: */
 
 sox_effects_chain_t * sox_create_effects_chain(
-    sox_encodinginfo_t const * in_enc, sox_encodinginfo_t * out_enc)
+    sox_encodinginfo_t const * in_enc, sox_encodinginfo_t const * out_enc)
 {
   sox_effects_chain_t * result = lsx_calloc(1, sizeof(sox_effects_chain_t));
   result->global_info = sox_effects_globals;
@@ -144,7 +144,8 @@
   if (!(effp->handler.flags & SOX_EFF_RATE))
     effp->out_signal.rate = in->rate;
   if (!(effp->handler.flags & SOX_EFF_PREC))
-    effp->out_signal.precision = in->precision;
+    effp->out_signal.precision = (effp->handler.flags & SOX_EFF_MODIFY)?
+        in->precision : SOX_SAMPLE_PRECISION;
   if (!(effp->handler.flags & SOX_EFF_GAIN))
     effp->out_signal.mult = in->mult;
 
@@ -152,8 +153,8 @@
     (effp->handler.flags & SOX_EFF_MCHAN)? 1 : effp->in_signal.channels;
   effp->clips = 0;
   effp->imin = 0;
-  eff0 = *effp;
-  eff0.priv = lsx_memdup(eff0.priv, eff0.handler.priv_size);
+  eff0 = *effp, eff0.priv = lsx_memdup(eff0.priv, eff0.handler.priv_size);
+  eff0.in_signal.mult = NULL; /* Only used in channel 0 */
   ret = start(effp);
   if (ret == SOX_EFF_NULL) {
     lsx_report("has no effect in this configuration");
--- a/src/example2.c
+++ b/src/example2.c
@@ -87,9 +87,10 @@
     int l, r;
 
     for (i = 0; i < block_size; ++i) {
+      SOX_SAMPLE_LOCALS;
       /* convert the sample from SoX's internal format to a `double' for
        * processing in this application: */
-      double sample = SOX_SAMPLE_TO_FLOAT_64BIT(buf[i]);
+      double sample = SOX_SAMPLE_TO_FLOAT_64BIT(buf[i],);
 
       /* The samples for each channel are interleaved; in this example
        * we allow only stereo audio, so the left channel audio can be found in
--- a/src/ffmpeg.c
+++ b/src/ffmpeg.c
@@ -406,8 +406,9 @@
   do {
     /* If output frame is not full, copy data into it */
     if (ffmpeg->samples_index < ffmpeg->audio_input_frame_size) {
+      SOX_SAMPLE_LOCALS;
       for (; nread < len && ffmpeg->samples_index < ffmpeg->audio_input_frame_size; nread++)
-        ffmpeg->samples[ffmpeg->samples_index++] = SOX_SAMPLE_TO_SIGNED_16BIT(buf[nread]);
+        ffmpeg->samples[ffmpeg->samples_index++] = SOX_SAMPLE_TO_SIGNED_16BIT(buf[nread], ft->clips);
     }
 
     /* If output frame full or no more data to read, write it out */
--- a/src/flac.c
+++ b/src/flac.c
@@ -441,21 +441,22 @@
   unsigned i;
 
   for (i = 0; i < len; ++i) {
-    long pcm = SOX_SAMPLE_TO_SIGNED_32BIT(sampleBuffer[i]);
+    SOX_SAMPLE_LOCALS;
+    long pcm = SOX_SAMPLE_TO_SIGNED_32BIT(sampleBuffer[i], ft->clips);
     p->decoded_samples[i] = pcm >> (32 - p->bits_per_sample);
     switch (p->bits_per_sample) {
       case  8: p->decoded_samples[i] =
-          SOX_SAMPLE_TO_SIGNED_8BIT(sampleBuffer[i]);
+          SOX_SAMPLE_TO_SIGNED_8BIT(sampleBuffer[i], ft->clips);
         break;
       case 16: p->decoded_samples[i] =
-          SOX_SAMPLE_TO_SIGNED_16BIT(sampleBuffer[i]);
+          SOX_SAMPLE_TO_SIGNED_16BIT(sampleBuffer[i], ft->clips);
         break;
       case 24: p->decoded_samples[i] = /* sign extension: */
-          SOX_SAMPLE_TO_SIGNED_24BIT(sampleBuffer[i]) << 8;
+          SOX_SAMPLE_TO_SIGNED_24BIT(sampleBuffer[i],ft->clips) << 8;
         p->decoded_samples[i] >>= 8;
         break;
       case 32: p->decoded_samples[i] =
-          SOX_SAMPLE_TO_SIGNED_32BIT(sampleBuffer[i]);
+          SOX_SAMPLE_TO_SIGNED_32BIT(sampleBuffer[i],ft->clips);
         break;
     }
   }
--- a/src/formats_i.c
+++ b/src/formats_i.c
@@ -175,6 +175,7 @@
 void lsx_clearerr(sox_format_t * ft)
 {
   clearerr(ft->fp);
+  ft->sox_errno = 0;
 }
 
 int lsx_unreadb(sox_format_t * ft, unsigned b)
--- a/src/gain.c
+++ b/src/gain.c
@@ -21,13 +21,11 @@
 #include <string.h>
 
 typedef struct {
-  sox_bool      do_equalise, do_balance, do_balance_no_clip;
+  sox_bool      do_equalise, do_balance, do_balance_no_clip, do_limiter;
   sox_bool      do_restore, make_headroom, do_normalise, do_scan;
   double        fixed_gain; /* Valid only in channel 0 */
 
-  double        mult;
-  double        restore;
-  double        rms;
+  double        mult, restore, rms, limiter;
   off_t         num_samples;
   sox_sample_t  min, max;
   FILE          * tmp_file;
@@ -46,6 +44,7 @@
       case 'b': p->do_scan = p->do_balance_no_clip = sox_true; break;
       case 'r': p->do_scan = p->do_restore = sox_true; break;
       case 'h': p->make_headroom = sox_true; break;
+      case 'l': p->do_limiter = sox_true; break;
       default: lsx_fail("invalid option `-%c'", *q); return lsx_usage(effp);
     }
   if ((p->do_equalise + p->do_balance + p->do_balance_no_clip + p->do_restore)/ sox_true > 1) {
@@ -56,6 +55,10 @@
     lsx_fail("Only one of -n, -r may be given");
     return SOX_EOF;
   }
+  if (p->do_limiter && p->make_headroom) {
+    lsx_fail("Only one of -l, -h may be given");
+    return SOX_EOF;
+  }
   do {NUMERIC_PARAMETER(fixed_gain, -HUGE_VAL, HUGE_VAL)} while (0);
   p->fixed_gain = dB_to_linear(p->fixed_gain);
   return argc? lsx_usage(effp) : SOX_SUCCESS;
@@ -85,6 +88,10 @@
       return SOX_EOF;
     }
   }
+  if (p->do_limiter)
+    p->limiter = (1 - 1 / p->fixed_gain) * (1. / SOX_SAMPLE_MAX);
+  else if (p->fixed_gain == floor(p->fixed_gain) && !p->do_scan)
+    effp->out_signal.precision = effp->in_signal.precision;
   return SOX_SUCCESS;
 }
 
@@ -92,6 +99,7 @@
     sox_sample_t * obuf, size_t * isamp, size_t * osamp)
 {
   priv_t * p = (priv_t *)effp->priv;
+  SOX_SAMPLE_LOCALS;
   size_t len;
 
   if (p->do_scan) {
@@ -101,13 +109,13 @@
     }
     if (p->do_balance && !p->do_normalise)
       for (len = *isamp; len; --len, ++ibuf) {
-        double d = SOX_SAMPLE_TO_FLOAT_64BIT(*ibuf);
+        double d = SOX_SAMPLE_TO_FLOAT_64BIT(*ibuf, effp->clips);
         p->rms += sqr(d);
         ++p->num_samples;
       }
     else if (p->do_balance || p->do_balance_no_clip)
       for (len = *isamp; len; --len, ++ibuf) {
-        double d = SOX_SAMPLE_TO_FLOAT_64BIT(*ibuf);
+        double d = SOX_SAMPLE_TO_FLOAT_64BIT(*ibuf, effp->clips);
         p->rms += sqr(d);
         ++p->num_samples;
         p->max = max(p->max, *ibuf);
@@ -122,8 +130,13 @@
   else {
     double mult = ((priv_t *)(effp - effp->flow)->priv)->fixed_gain;
     len = *isamp = *osamp = min(*isamp, *osamp);
-    for (; len; --len, ++ibuf)
+    if (!p->do_limiter) for (; len; --len, ++ibuf)
       *obuf++ = SOX_ROUND_CLIP_COUNT(*ibuf * mult, effp->clips);
+    else for (; len; --len, ++ibuf) {
+      double d = *ibuf * mult;
+      *obuf++ = d < 0 ? 1 / (1 / d - p->limiter) - .5 :
+                d > 0 ? 1 / (1 / d + p->limiter) + .5 : 0;
+    }
   }
   return SOX_SUCCESS;
 }
@@ -191,10 +204,13 @@
       lsx_fail("error reading temporary file: %s", strerror(errno));
       result = SOX_EOF;
     }
-    if (p->mult > 1) for (*osamp = len; len; --len, ++obuf)
+    if (!p->do_limiter) for (*osamp = len; len; --len, ++obuf)
       *obuf = SOX_ROUND_CLIP_COUNT(*obuf * p->mult, effp->clips);
-    else for (*osamp = len; len; --len, ++obuf)
-      *obuf = floor(*obuf * p->mult + .5);
+    else for (*osamp = len; len; --len) {
+      double d = *obuf * p->mult;
+      *obuf++ = d < 0 ? 1 / (1 / d - p->limiter) - .5 :
+                d > 0 ? 1 / (1 / d + p->limiter) + .5 : 0;
+    }
   }
   else *osamp = 0;
   return result;
@@ -211,7 +227,7 @@
 sox_effect_handler_t const * sox_gain_effect_fn(void)
 {
   static sox_effect_handler_t handler = {
-    "gain", "[-e|-b|-B|-r] [-n] [-h] [gain-dB]", SOX_EFF_GAIN,
+    "gain", "[-e|-b|-B|-r] [-n] [-l|-h] [gain-dB]", SOX_EFF_GAIN,
     create, start, flow, drain, stop, NULL, sizeof(priv_t)};
   return &handler;
 }
--- a/src/gsm.c
+++ b/src/gsm.c
@@ -195,9 +195,10 @@
 
         while (done < samp)
         {
+                SOX_SAMPLE_LOCALS;
                 while ((p->samplePtr < p->sampleTop) && (done < samp))
                         *(p->samplePtr)++ =
-                            SOX_SAMPLE_TO_SIGNED_16BIT(buf[done++]);
+                            SOX_SAMPLE_TO_SIGNED_16BIT(buf[done++], ft->clips);
 
                 if (p->samplePtr == p->sampleTop)
                 {
--- a/src/hcom.c
+++ b/src/hcom.c
@@ -277,8 +277,9 @@
   }
 
   for (i = 0; i < len; i++) {
+    SOX_SAMPLE_LOCALS;
     datum = *buf++;
-    p->data[p->pos++] = SOX_SAMPLE_TO_UNSIGNED_8BIT(datum);
+    p->data[p->pos++] = SOX_SAMPLE_TO_UNSIGNED_8BIT(datum, ft->clips);
   }
 
   return len;
--- a/src/lpc10.c
+++ b/src/lpc10.c
@@ -179,7 +179,8 @@
 
   while (len > 0) {
     while (len > 0 && lpc->samples < LPC10_SAMPLES_PER_FRAME) {
-      lpc->speech[lpc->samples++] = SOX_SAMPLE_TO_FLOAT_32BIT(buf[nwritten++]);
+      SOX_SAMPLE_LOCALS;
+      lpc->speech[lpc->samples++] = SOX_SAMPLE_TO_FLOAT_32BIT(buf[nwritten++], ft->clips);
       len--;
     }
 
--- a/src/mixer.c
+++ b/src/mixer.c
@@ -546,11 +546,13 @@
   static sox_effect_handler_t handler = {
     "mixer",
     "[ -l | -r | -f | -b | -1 | -2 | -3 | -4 | n,n,n...,n ]",
-    SOX_EFF_MCHAN | SOX_EFF_CHAN,
+    SOX_EFF_MCHAN | SOX_EFF_CHAN | SOX_EFF_GAIN,
     getopts, start, flow, 0, 0, 0, sizeof(priv_t)
   };
   return &handler;
 }
+
+/*------------------------------- oops effect --------------------------------*/
 
 static int oops_getopts(sox_effect_t * effp, int argc, char * * argv)
 {
--- a/src/mp3.c
+++ b/src/mp3.c
@@ -406,6 +406,7 @@
     int i,j;
     ptrdiff_t done = 0;
     size_t written;
+    SOX_SAMPLE_LOCALS;
 
     /* NOTE: This logic assumes that "short int" is 16-bits
      * on all platforms.  It happens to be for all that I know
@@ -434,8 +435,8 @@
         j=0;
         for (i=0; i<nsamples; i++)
         {
-            buffer_l[i]=SOX_SAMPLE_TO_SIGNED_16BIT(buf[j++]);
-            buffer_r[i]=SOX_SAMPLE_TO_SIGNED_16BIT(buf[j++]);
+            buffer_l[i]=SOX_SAMPLE_TO_SIGNED_16BIT(buf[j++], ft->clips);
+            buffer_r[i]=SOX_SAMPLE_TO_SIGNED_16BIT(buf[j++], ft->clips);
         }
     }
     else
@@ -442,7 +443,7 @@
     {
         j=0;
         for (i=0; i<nsamples; i++)
-            buffer_l[i]=SOX_SAMPLE_TO_SIGNED_16BIT(buf[j++]);
+            buffer_l[i]=SOX_SAMPLE_TO_SIGNED_16BIT(buf[j++], ft->clips);
     }
 
     mp3buffer_size = 1.25 * nsamples + 7200;
--- a/src/noiseprof.c
+++ b/src/noiseprof.c
@@ -116,7 +116,7 @@
                     size_t *isamp, size_t *osamp)
 {
   priv_t * p = (priv_t *) effp->priv;
-  size_t samp = min(*isamp, *osamp);
+  size_t samp = min(*isamp, *osamp), dummy = 0; /* No need to clip count */
   size_t chans = effp->in_signal.channels;
   size_t i, j, n = min(samp / chans, WINDOWSIZE - p->bufdata);
 
@@ -125,10 +125,11 @@
 
   /* Collect data for every channel. */
   for (i = 0; i < chans; i ++) {
+    SOX_SAMPLE_LOCALS;
     chandata_t * chan = &(p->chandata[i]);
     for (j = 0; j < n; j ++)
       chan->window[j + p->bufdata] =
-        SOX_SAMPLE_TO_FLOAT_32BIT(ibuf[i + j * chans]);
+        SOX_SAMPLE_TO_FLOAT_32BIT(ibuf[i + j * chans], dummy);
     if (n + p->bufdata == WINDOWSIZE)
       collect_data(chan);
   }
--- a/src/noisered.c
+++ b/src/noisered.c
@@ -285,6 +285,7 @@
 
     /* Reduce noise on every channel. */
     for (i = 0; i < tracks; i ++) {
+        SOX_SAMPLE_LOCALS;
         chandata_t* chan = &(data->chandata[i]);
         size_t j;
 
@@ -293,7 +294,7 @@
 
         for (j = 0; j < ncopy; j ++)
             chan->window[oldbuf + j] =
-                SOX_SAMPLE_TO_FLOAT_32BIT(ibuf[i + tracks * j]);
+                SOX_SAMPLE_TO_FLOAT_32BIT(ibuf[i + tracks * j], effp->clips);
 
         if (!whole_window)
             continue;
--- a/src/overdrive.c
+++ b/src/overdrive.c
@@ -52,7 +52,7 @@
   size_t dummy = 0, len = *isamp = *osamp = min(*isamp, *osamp);
   while (len--) {
     SOX_SAMPLE_LOCALS;
-    double d = SOX_SAMPLE_TO_FLOAT_64BIT(*ibuf++), d0 = d;
+    double d = SOX_SAMPLE_TO_FLOAT_64BIT(*ibuf++, dummy), d0 = d;
     d *= p->gain;
     d += p->colour;
     d = d < -1? -2./3 : d > 1? 2./3 : d - d * d * d * (1./3);
--- a/src/pad.c
+++ b/src/pad.c
@@ -135,7 +135,7 @@
 sox_effect_handler_t const * sox_pad_effect_fn(void)
 {
   static sox_effect_handler_t handler = {
-    "pad", "{length[@position]}", SOX_EFF_MCHAN|SOX_EFF_LENGTH,
+    "pad", "{length[@position]}", SOX_EFF_MCHAN|SOX_EFF_LENGTH|SOX_EFF_MODIFY,
     create, start, flow, drain, stop, kill, sizeof(priv_t)
   };
   return &handler;
--- a/src/rate.c
+++ b/src/rate.c
@@ -516,7 +516,7 @@
 
   if (*isamp && odone < *osamp) {
     sample_t * t = rate_input(&p->rate, NULL, *isamp);
-    for (i = *isamp; i; --i) *t++ = FROM_SOX(*ibuf++);
+    for (i = *isamp; i; --i) *t++ = FROM_SOX(*ibuf++,);
     rate_process(&p->rate);
   }
   else *isamp = 0;
--- a/src/raw.c
+++ b/src/raw.c
@@ -12,10 +12,12 @@
 
 typedef uint16_t uint14_t;
 typedef uint16_t uint13_t;
+typedef int16_t int14_t;
+typedef int16_t int13_t;
 #define SOX_ULAW_BYTE_TO_SAMPLE(d,clips)   SOX_SIGNED_16BIT_TO_SAMPLE(sox_ulaw2linear16(d),clips)
 #define SOX_ALAW_BYTE_TO_SAMPLE(d,clips)   SOX_SIGNED_16BIT_TO_SAMPLE(sox_alaw2linear16(d),clips)
-#define SOX_SAMPLE_TO_ULAW_BYTE(d) sox_14linear2ulaw(SOX_SAMPLE_TO_UNSIGNED(14,d) - 0x2000)
-#define SOX_SAMPLE_TO_ALAW_BYTE(d) sox_13linear2alaw(SOX_SAMPLE_TO_UNSIGNED(13,d) - 0x1000)
+#define SOX_SAMPLE_TO_ULAW_BYTE(d,c) sox_14linear2ulaw(SOX_SAMPLE_TO_UNSIGNED(14,d,c) - 0x2000)
+#define SOX_SAMPLE_TO_ALAW_BYTE(d,c) sox_13linear2alaw(SOX_SAMPLE_TO_UNSIGNED(13,d,c) - 0x1000)
 
 int lsx_rawseek(sox_format_t * ft, uint64_t offset)
 {
@@ -95,10 +97,11 @@
   static size_t sox_write_ ## sign ## type ## _samples( \
       sox_format_t * ft, sox_sample_t const * buf, size_t len) \
   { \
+    SOX_SAMPLE_LOCALS; \
     size_t n, nwritten; \
     ctype *data = lsx_malloc(sizeof(ctype) * len); \
     for (n = 0; n < len; n++) \
-      data[n] = cast(buf[n]); \
+      data[n] = cast(buf[n], ft->clips); \
     nwritten = lsx_write_ ## type ## _buf(ft, (uctype *)data, len); \
     free(data); \
     return nwritten; \
--- a/src/remix.c
+++ b/src/remix.c
@@ -95,19 +95,6 @@
         p->out_specs[i].in_specs[j].multiplier = (p->mode == automatic || (p->mode == semi && !mul_spec)) ? mult : 1;
   }
   effp->out_signal.channels = p->num_out_channels;
-
-  if (effp->in_signal.mult) {
-    double max_sum = 0;
-
-    for (j = 0; j < effp->out_signal.channels; j++) {
-      double sum = 0;
-      for (i = 0; i < p->out_specs[j].num_in_channels; i++)
-        sum += fabs(p->out_specs[j].in_specs[i].multiplier);
-      max_sum = max(max_sum, sum);
-    }
-    if (max_sum > 1)
-      *effp->in_signal.mult /= max_sum;
-  }
   return SOX_SUCCESS;
 }
 
@@ -125,11 +112,29 @@
 static int start(sox_effect_t * effp)
 {
   priv_t * p = (priv_t *)effp->priv;
+  double max_sum = 0;
+  unsigned i, j;
+  int non_integer = 0;
+
   parse(effp, NULL, effp->in_signal.channels);
   if (effp->in_signal.channels < p->min_in_channels) {
     lsx_fail("too few input channels");
     return SOX_EOF;
   }
+
+  for (j = 0; j < effp->out_signal.channels; j++) {
+    double sum = 0;
+    for (i = 0; i < p->out_specs[j].num_in_channels; i++) {
+      double mult = p->out_specs[j].in_specs[i].multiplier;
+      sum += fabs(mult);
+      non_integer += floor(mult) != mult;
+    }
+    max_sum = max(max_sum, sum);
+  }
+  if (effp->in_signal.mult && max_sum > 1)
+    *effp->in_signal.mult /= max_sum;
+  if (!non_integer)
+    effp->out_signal.precision = effp->in_signal.precision;
   return SOX_SUCCESS;
 }
 
@@ -167,7 +172,7 @@
 {
   static sox_effect_handler_t handler = {
     "remix", "[-m|-a] [-p] <0|in-chan[v|d|i volume]{,in-chan[v|d|i volume]}>",
-    SOX_EFF_MCHAN | SOX_EFF_CHAN, create, start, flow, NULL, NULL, kill, sizeof(priv_t)
+    SOX_EFF_MCHAN | SOX_EFF_CHAN | SOX_EFF_GAIN, create, start, flow, NULL, NULL, kill, sizeof(priv_t)
   };
   return &handler;
 }
--- a/src/repeat.c
+++ b/src/repeat.c
@@ -93,7 +93,8 @@
 
 sox_effect_handler_t const * sox_repeat_effect_fn(void)
 {
-  static sox_effect_handler_t effect = {"repeat", "[count]", SOX_EFF_MCHAN |
-    SOX_EFF_LENGTH, create, start, flow, drain, stop, NULL, sizeof(priv_t)};
+  static sox_effect_handler_t effect = {"repeat", "[count]",
+    SOX_EFF_MCHAN | SOX_EFF_LENGTH | SOX_EFF_MODIFY,
+    create, start, flow, drain, stop, NULL, sizeof(priv_t)};
   return &effect;
 }
--- a/src/reverb.c
+++ b/src/reverb.c
@@ -229,7 +229,7 @@
   for (c = 0; c < p->ichannels; ++c)
     p->chan[c].dry = fifo_write(&p->chan[c].reverb.input_fifo, len, 0);
   for (i = 0; i < len; ++i) for (c = 0; c < p->ichannels; ++c)
-    p->chan[c].dry[i] = SOX_SAMPLE_TO_FLOAT_32BIT(*ibuf++);
+    p->chan[c].dry[i] = SOX_SAMPLE_TO_FLOAT_32BIT(*ibuf++, effp->clips);
   for (c = 0; c < p->ichannels; ++c)
     reverb_process(&p->chan[c].reverb, len);
   if (p->ichannels == 2) for (i = 0; i < len; ++i) for (w = 0; w < 2; ++w) {
--- a/src/reverse.c
+++ b/src/reverse.c
@@ -80,7 +80,7 @@
 sox_effect_handler_t const * sox_reverse_effect_fn(void)
 {
   static sox_effect_handler_t handler = {
-    "reverse", NULL, 0, NULL, start, flow, drain, stop, NULL, sizeof(priv_t)
+    "reverse", NULL, SOX_EFF_MODIFY, NULL, start, flow, drain, stop, NULL, sizeof(priv_t)
   };
   return &handler;
 }
--- a/src/silence.c
+++ b/src/silence.c
@@ -275,25 +275,27 @@
 {
     double ratio;
     int rc;
+    sox_sample_t dummy_clipped_count = 0;
 
     /* When scaling low bit data, noise values got scaled way up */
     /* Only consider the original bits when looking for silence */
     switch(effp->in_signal.precision)
     {
+        SOX_SAMPLE_LOCALS;
         case 8:
-            value = SOX_SAMPLE_TO_SIGNED_8BIT(value);
+            value = SOX_SAMPLE_TO_SIGNED_8BIT(value, dummy_clipped_count);
             ratio = (double)abs(value) / (double)SOX_INT8_MAX;
             break;
         case 16:
-            value = SOX_SAMPLE_TO_SIGNED_16BIT(value);
+            value = SOX_SAMPLE_TO_SIGNED_16BIT(value, dummy_clipped_count);
             ratio = (double)abs(value) / (double)SOX_INT16_MAX;
             break;
         case 24:
-            value = SOX_SAMPLE_TO_SIGNED_24BIT(value);
+            value = SOX_SAMPLE_TO_SIGNED_24BIT(value, dummy_clipped_count);
             ratio = (double)abs(value) / (double)SOX_INT24_MAX;
             break;
         case 32:
-            value = SOX_SAMPLE_TO_SIGNED_32BIT(value);
+            value = SOX_SAMPLE_TO_SIGNED_32BIT(value,);
             ratio = (double)abs(value) / (double)SOX_INT32_MAX;
             break;
         default:
@@ -686,7 +688,7 @@
 static sox_effect_handler_t sox_silence_effect = {
   "silence",
   "[ -l ] above_periods [ duration thershold[d|%%] ] [ below_periods duration threshold[d|%%]]",
-  SOX_EFF_MCHAN,
+  SOX_EFF_MCHAN | SOX_EFF_MODIFY,
   sox_silence_getopts,
   sox_silence_start,
   sox_silence_flow,
--- a/src/skelform.c
+++ b/src/skelform.c
@@ -159,8 +159,9 @@
   switch (ft->encoding.bits_per_sample) {
   case 8:
     switch (ft->encoding.encoding) {
+    SOX_SAMPLE_LOCALS;
     case SOX_ENCODING_UNSIGNED:
-      while (done < len && lsx_writeb(ft, SOX_SAMPLE_TO_UNSIGNED_8BIT(*buf++)) == SOX_SUCCESS)
+      while (done < len && lsx_writeb(ft, SOX_SAMPLE_TO_UNSIGNED_8BIT(*buf++, ft->clips)) == SOX_SUCCESS)
         ++done;
       break;
     default:
--- a/src/smp.c
+++ b/src/smp.c
@@ -368,7 +368,8 @@
         size_t done = 0;
 
         while(done < len) {
-                datum = (int) SOX_SAMPLE_TO_SIGNED_16BIT(*buf++);
+                SOX_SAMPLE_LOCALS;
+                datum = (int) SOX_SAMPLE_TO_SIGNED_16BIT(*buf++, ft->clips);
                 lsx_writew(ft, (uint16_t)datum);
                 smp->NoOfSamps++;
                 done++;
--- a/src/sox.c
+++ b/src/sox.c
@@ -133,7 +133,6 @@
   sox_signalinfo_t signal;
   sox_encodinginfo_t encoding;
   double volume;
-  sox_sample_t offset;
   double replay_gain;
   sox_oob_t oob;
   sox_bool no_glob;
@@ -198,7 +197,7 @@
 static struct termios original_termios;
 #endif
 
-static sox_bool stdin_is_a_tty, is_player, is_guarded, do_guarded_norm;
+static sox_bool stdin_is_a_tty, is_player, is_guarded, do_guarded_norm, no_dither;
 
 /* Cleanup atexit() function, hence always called. */
 static void cleanup(void)
@@ -405,8 +404,6 @@
     display_file_info(f->ft, f, sox_false);
   if (f->volume == HUGE_VAL)
     f->volume = 1;
-  if (f->encoding.half_bit && f->ft->signal.precision < 32)
-    f->offset = 1 << (31 - f->ft->signal.precision);
   if (f->replay_gain != HUGE_VAL)
     f->volume *= pow(10.0, f->replay_gain / 20);
   f->ft->sox_errno = errno = 0;
@@ -428,10 +425,8 @@
 {
   size_t s = ws * f->ft->signal.channels;
 
-  if (f->volume == 1 && f->offset !=0 ) while (s--)
-    *buf++ -= f->offset;
-  else if (f->volume != 1 || f->offset !=0 ) while (s--) {
-    double d = f->volume * (*buf - f->offset);
+  if (f->volume != 1) while (s--) {
+    double d = f->volume * *buf;
     *buf++ = SOX_ROUND_CLIP_COUNT(d, f->volume_clips);
   }
 }
@@ -552,8 +547,8 @@
 
 static sox_effect_handler_t const * input_combiner_effect_fn(void)
 {
-  static sox_effect_handler_t handler = {
-    "input", 0, SOX_EFF_MCHAN, 0, combiner_start, 0, combiner_drain,
+  static sox_effect_handler_t handler = { "input", 0, SOX_EFF_MCHAN |
+    SOX_EFF_MODIFY, 0, combiner_start, 0, combiner_drain,
     combiner_stop, 0, sizeof(input_combiner_t)
   };
   return &handler;
@@ -561,9 +556,9 @@
 
 static int ostart(sox_effect_t *effp)
 {
-  (void)effp;
-  if (effp->out_encoding->half_bit && effp->out_signal.precision < 32)
-    ofile->offset = 1 << (31 - ofile->ft->signal.precision);
+  unsigned prec = effp->out_signal.precision;
+  if (effp->in_signal.mult && effp->in_signal.precision > prec)
+    *effp->in_signal.mult *= 1 - (1 << (31 - prec)) * (1. / SOX_SAMPLE_MAX);
   return SOX_SUCCESS;
 }
 
@@ -570,13 +565,9 @@
 static int output_flow(sox_effect_t *effp, sox_sample_t const * ibuf,
     sox_sample_t * obuf, size_t * isamp, size_t * osamp)
 {
-  sox_sample_t const * buf;
   size_t len;
 
   (void)effp, (void)obuf;
-  if (ofile->offset != 0 ) for (buf = ibuf, len = *isamp; len; --len, ++buf)
-    *(sox_sample_t *)buf = *buf >= SOX_SAMPLE_MAX - ofile->offset?
-      SOX_SAMPLE_MAX : *buf + ofile->offset;
   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]);
@@ -604,8 +595,8 @@
 
 static sox_effect_handler_t const * output_effect_fn(void)
 {
-  static sox_effect_handler_t handler = {
-    "output", 0, SOX_EFF_MCHAN, NULL, ostart, output_flow, NULL, NULL, NULL, 0
+  static sox_effect_handler_t handler = {"output", 0, SOX_EFF_MCHAN |
+    SOX_EFF_MODIFY | SOX_EFF_PREC, NULL, ostart, output_flow, NULL, NULL, NULL, 0
   };
   return &handler;
 }
@@ -978,13 +969,15 @@
     guard = 1;
   }
 
+  if (i == nuser_effects[current_eff_chain] && !no_dither && signal.precision >
+      ofile->ft->signal.precision && ofile->ft->signal.precision <= 24)
+    auto_effect(chain, "dither", 0, NULL, &signal, &guard);
+
   /* Add user specified effects from `dither' onwards */
-  for (; i < nuser_effects[current_eff_chain]; i++, guard = 2) {
+  for (; i < nuser_effects[current_eff_chain]; i++, guard = 2)
     if (add_effect(chain, user_efftab[i], &signal, &ofile->ft->signal,
           &guard) != SOX_SUCCESS)
       exit(2); /* Effects chain should have displayed an error message */
-    chain->out_enc->half_bit = sox_false;
-  }
 
   if (!save_output_eff)
   {
@@ -1740,6 +1733,7 @@
 "--combine concatenate    Concatenate multiple input files (default for sox, rec)",
 "--combine sequence       Sequence multiple input files (default for play)",
 "--effects-file FILENAME  File containing effects and options",
+"-D, --no-dither          Don't dither automatically",
 "-G, --guard              Use temporary files to guard against clipping",
 "-h, --help               Display version number and usage information",
 "--help-effect NAME       Show usage of effect NAME, or NAME=all for all",
@@ -1779,7 +1773,6 @@
 "-X|--reverse-bits        Encoded bit-order",
 "--endian little|big|swap Encoded byte-order; swap means opposite to default",
 "-L/-B/-x                 Short options for the above",
-"-0                       PCM encoding is 0 biased (offset by half a bit)",
 "-c|--channels CHANNELS   Number of channels of audio data; e.g. 2 = stereo",
 "-r|--rate RATE           Sample rate of audio",
 "-C|--compression FACTOR  Compression factor for output format",
@@ -1937,7 +1930,7 @@
   free(text);
 }
 
-static char *getoptstr = "+ab:c:de:fghimnopqr:st:uv:xABC:GLMNRSTUV::X012348";
+static char *getoptstr = "+ab:c:de:fghimnopqr:st:uv:xABC:DGLMNRSTUV::X12348";
 
 static struct option long_options[] =
   {
@@ -1966,6 +1959,7 @@
     {"channels"        , required_argument, NULL, 'c'},
     {"compression"     , required_argument, NULL, 'C'},
     {"default-device"  ,       no_argument, NULL, 'd'},
+    {"no-dither"       ,       no_argument, NULL, 'D'},
     {"encoding"        , required_argument, NULL, 'e'},
     {"help"            ,       no_argument, NULL, 'h'},
     {"null"            ,       no_argument, NULL, 'n'},
@@ -2166,8 +2160,6 @@
       break;
     }
 
-    case '0': f->encoding.half_bit = sox_true; break;
-
     case 'v':
       if (sscanf(optarg, "%lf %c", &f->volume, &dummy) != 1) {
         lsx_fail("Volume value `%s' is not a number", optarg);
@@ -2259,6 +2251,7 @@
 
     case 'S': show_progress = SOX_OPTION_YES; break;
     case 'q': show_progress = SOX_OPTION_NO;  break;
+    case 'D': no_dither = sox_true; break;
 
     case 'V':
       if (optarg == NULL)
--- a/src/sox.h
+++ b/src/sox.h
@@ -12,7 +12,6 @@
 #define SOX_H
 
 #include <limits.h>
-#include <math.h>
 #include <stdarg.h>
 #include <stddef.h> /* Ensure NULL etc. are available throughout SoX */
 #include <stdio.h>
@@ -76,32 +75,36 @@
 
 /*                Conversions: Linear PCM <--> sox_sample_t
  *
- *   I/O       I/O     sox_sample_t    I/O     sox_sample_t
- *  Format   Minimum     Minimum     Maximum     Maximum
- *  ------  ---------  ------------  --------  ------------
- *  Float      -1          -1           1       1 - 5e-10
- *  Int8      -128        -127.5       127     127.4999999
- *  Int16    -32768      -32767.5     32767    32767.49998
- *  Int24   -8388608    -8388607.5   8388607   8388607.496
- *  Int32  -2147483648 -2147483648  2147483647 2147483647
+ *   I/O      Input    sox_sample_t Clips?   Input    sox_sample_t Clips?
+ *  Format   Minimum     Minimum     I O    Maximum     Maximum     I O
+ *  ------  ---------  ------------ -- --   --------  ------------ -- --
+ *  Float     -inf         -1        y n      inf      1 - 5e-10    y n
+ *  Int8      -128        -128       n n      127     127.9999999   n y
+ *  Int16    -32768      -32768      n n     32767    32767.99998   n y
+ *  Int24   -8388608    -8388608     n n    8388607   8388607.996   n y
+ *  Int32  -2147483648 -2147483648   n n   2147483647 2147483647    n n
  *
  * Conversions are as accurate as possible (with rounding).
  *
  * Rounding: halves toward +inf, all others to nearest integer.
  *
- * The only possibility of clipping on conversion is when inputting Float.
+ * Clips? shows whether on not there is the possibility of a conversion
+ * clipping to the minimum or maximum value when inputing from or outputing
+ * to a given type.
  *
  * Unsigned integers are converted to and from signed integers by flipping
  * the upper-most bit then treating them as signed integers.
  */
 
-#define SOX_SAMPLE_LOCALS double sox_macro_temp_double UNUSED
+#define SOX_SAMPLE_LOCALS sox_sample_t sox_macro_temp_sample UNUSED; \
+  double sox_macro_temp_double UNUSED
 
 #define SOX_SAMPLE_NEG SOX_INT_MIN(32)
-#define SOX_SAMPLE_TO_UNSIGNED(bits,d) \
-  (uint##bits##_t)(((uint32_t)((d)^SOX_SAMPLE_NEG))>>(32-bits))
-#define SOX_SAMPLE_TO_SIGNED(bits,d) (int##bits##_t)(((uint32_t)(d))>>(32-bits))
-#define SOX_SIGNED_TO_SAMPLE(bits,d)(((sox_sample_t)(d)<<(32-bits))+(1<<(31-bits)))
+#define SOX_SAMPLE_TO_UNSIGNED(bits,d,clips) \
+  (uint##bits##_t)(SOX_SAMPLE_TO_SIGNED(bits,d,clips)^SOX_INT_MIN(bits))
+#define SOX_SAMPLE_TO_SIGNED(bits,d,clips) \
+  (int##bits##_t)(sox_macro_temp_sample=(d),sox_macro_temp_sample>SOX_SAMPLE_MAX-(1<<(31-bits))?++(clips),SOX_INT_MAX(bits):((uint32_t)(sox_macro_temp_sample+(1<<(31-bits))))>>(32-bits))
+#define SOX_SIGNED_TO_SAMPLE(bits,d)((sox_sample_t)(d)<<(32-bits))
 #define SOX_UNSIGNED_TO_SAMPLE(bits,d)(SOX_SIGNED_TO_SAMPLE(bits,d)^SOX_SAMPLE_NEG)
 
 #define SOX_UNSIGNED_8BIT_TO_SAMPLE(d,clips) SOX_UNSIGNED_TO_SAMPLE(8,d)
@@ -112,18 +115,18 @@
 #define SOX_SIGNED_24BIT_TO_SAMPLE(d,clips) SOX_SIGNED_TO_SAMPLE(24,d)
 #define SOX_UNSIGNED_32BIT_TO_SAMPLE(d,clips) ((sox_sample_t)(d)^SOX_SAMPLE_NEG)
 #define SOX_SIGNED_32BIT_TO_SAMPLE(d,clips) (sox_sample_t)(d)
-#define SOX_FLOAT_32BIT_TO_SAMPLE SOX_FLOAT_64BIT_TO_SAMPLE
-#define SOX_FLOAT_64BIT_TO_SAMPLE(d,clips) (sox_macro_temp_double=(d)*(SOX_SAMPLE_MAX+1.)+.5,sox_macro_temp_double<SOX_SAMPLE_MIN?++(clips),SOX_SAMPLE_MIN:sox_macro_temp_double>=SOX_SAMPLE_MAX+1.?sox_macro_temp_double>SOX_SAMPLE_MAX+1.5?++(clips),SOX_SAMPLE_MAX:SOX_SAMPLE_MAX:(sox_sample_t)floor(sox_macro_temp_double))
-#define SOX_SAMPLE_TO_UNSIGNED_8BIT(d) SOX_SAMPLE_TO_UNSIGNED(8,d)
-#define SOX_SAMPLE_TO_SIGNED_8BIT(d) SOX_SAMPLE_TO_SIGNED(8,d)
-#define SOX_SAMPLE_TO_UNSIGNED_16BIT(d) SOX_SAMPLE_TO_UNSIGNED(16,d)
-#define SOX_SAMPLE_TO_SIGNED_16BIT(d) SOX_SAMPLE_TO_SIGNED(16,d)
-#define SOX_SAMPLE_TO_UNSIGNED_24BIT(d) SOX_SAMPLE_TO_UNSIGNED(24,d)
-#define SOX_SAMPLE_TO_SIGNED_24BIT(d) SOX_SAMPLE_TO_SIGNED(24,d)
-#define SOX_SAMPLE_TO_UNSIGNED_32BIT(d) (uint32_t)((d)^SOX_SAMPLE_NEG)
-#define SOX_SAMPLE_TO_SIGNED_32BIT(d) (int32_t)(d)
-#define SOX_SAMPLE_TO_FLOAT_32BIT SOX_SAMPLE_TO_FLOAT_64BIT
-#define SOX_SAMPLE_TO_FLOAT_64BIT(d) ((d)*(1./(SOX_SAMPLE_MAX+1.)))
+#define SOX_FLOAT_32BIT_TO_SAMPLE(d,clips) (sox_sample_t)(sox_macro_temp_double=(d)*(SOX_SAMPLE_MAX+1.),sox_macro_temp_double<SOX_SAMPLE_MIN?++(clips),SOX_SAMPLE_MIN:sox_macro_temp_double>=SOX_SAMPLE_MAX+1.?sox_macro_temp_double>SOX_SAMPLE_MAX+1.?++(clips),SOX_SAMPLE_MAX:SOX_SAMPLE_MAX:sox_macro_temp_double)
+#define SOX_FLOAT_64BIT_TO_SAMPLE(d,clips) (sox_sample_t)(sox_macro_temp_double=(d)*(SOX_SAMPLE_MAX+1.),sox_macro_temp_double<0?sox_macro_temp_double<=SOX_SAMPLE_MIN-.5?++(clips),SOX_SAMPLE_MIN:sox_macro_temp_double-.5:sox_macro_temp_double>=SOX_SAMPLE_MAX+.5?sox_macro_temp_double>SOX_SAMPLE_MAX+1.?++(clips),SOX_SAMPLE_MAX:SOX_SAMPLE_MAX:sox_macro_temp_double+.5)
+#define SOX_SAMPLE_TO_UNSIGNED_8BIT(d,clips) SOX_SAMPLE_TO_UNSIGNED(8,d,clips)
+#define SOX_SAMPLE_TO_SIGNED_8BIT(d,clips) SOX_SAMPLE_TO_SIGNED(8,d,clips)
+#define SOX_SAMPLE_TO_UNSIGNED_16BIT(d,clips) SOX_SAMPLE_TO_UNSIGNED(16,d,clips)
+#define SOX_SAMPLE_TO_SIGNED_16BIT(d,clips) SOX_SAMPLE_TO_SIGNED(16,d,clips)
+#define SOX_SAMPLE_TO_UNSIGNED_24BIT(d,clips) SOX_SAMPLE_TO_UNSIGNED(24,d,clips)
+#define SOX_SAMPLE_TO_SIGNED_24BIT(d,clips) SOX_SAMPLE_TO_SIGNED(24,d,clips)
+#define SOX_SAMPLE_TO_UNSIGNED_32BIT(d,clips) (uint32_t)((d)^SOX_SAMPLE_NEG)
+#define SOX_SAMPLE_TO_SIGNED_32BIT(d,clips) (int32_t)(d)
+#define SOX_SAMPLE_TO_FLOAT_32BIT(d,clips) (sox_macro_temp_sample=(d),sox_macro_temp_sample>SOX_SAMPLE_MAX-128?++(clips),1:(((sox_macro_temp_sample+128)&~255)*(1./(SOX_SAMPLE_MAX+1.))))
+#define SOX_SAMPLE_TO_FLOAT_64BIT(d,clips) ((d)*(1./(SOX_SAMPLE_MAX+1.)))
 
 
 
@@ -243,7 +246,6 @@
 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 */
-  sox_bool half_bit;
   double compression;      /* compression factor (where applicable) */
 
   /* If these 3 variables are set to DEFAULT, then, during
@@ -504,11 +506,11 @@
   sox_sample_t **ibufc, **obufc; /* Channel interleave buffers */
   sox_effects_globals_t global_info;
   sox_encodinginfo_t const * in_enc;
-  sox_encodinginfo_t * out_enc;
+  sox_encodinginfo_t const * out_enc;
 };
 typedef struct sox_effects_chain sox_effects_chain_t;
 sox_effects_chain_t * sox_create_effects_chain(
-    sox_encodinginfo_t const * in_enc, sox_encodinginfo_t * out_enc);
+    sox_encodinginfo_t const * in_enc, sox_encodinginfo_t const * out_enc);
 void sox_delete_effects_chain(sox_effects_chain_t *ecp);
 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));
--- a/src/spectrogram.c
+++ b/src/spectrogram.c
@@ -193,6 +193,7 @@
   *isamp = *osamp = len;
 
   while (sox_true) {
+    SOX_SAMPLE_LOCALS;
     if (p->read == p->step_size) {
       memmove(p->buf, p->buf + p->step_size,
           (p->dft_size - p->step_size) * sizeof(*p->buf));
@@ -199,7 +200,7 @@
       p->read = 0;
     }
     for (; len && p->read < p->step_size; --len, ++p->read, --p->end)
-      p->buf[p->dft_size - p->step_size + p->read] = FROM_SOX(*ibuf++);
+      p->buf[p->dft_size - p->step_size + p->read] = FROM_SOX(*ibuf++,);
     if (p->read != p->step_size)
       break;
 
--- a/src/splice.c
+++ b/src/splice.c
@@ -185,7 +185,7 @@
           break;
         }
         for (c = 0; c < effp->in_signal.channels; ++c)
-          p->buffer[p->buffer_pos++] = SOX_SAMPLE_TO_FLOAT_32BIT(*ibuf++);
+          p->buffer[p->buffer_pos++] = SOX_SAMPLE_TO_FLOAT_32BIT(*ibuf++, effp->clips);
       }
       break;
     }
--- a/src/stat.c
+++ b/src/stat.c
@@ -141,7 +141,8 @@
 
     if (stat->fft) {
       for (x = 0; x < len; x++) {
-        stat->re_in[stat->fft_offset++] = SOX_SAMPLE_TO_FLOAT_32BIT(ibuf[x]);
+        SOX_SAMPLE_LOCALS;
+        stat->re_in[stat->fft_offset++] = SOX_SAMPLE_TO_FLOAT_32BIT(ibuf[x], effp->clips);
 
         if (stat->fft_offset >= stat->fft_size) {
           stat->fft_offset = 0;
--- a/src/swap.c
+++ b/src/swap.c
@@ -181,7 +181,7 @@
 const sox_effect_handler_t *sox_swap_effect_fn(void)
 {
   static sox_effect_handler_t handler = {
-    "swap", "[1 2 | 1 2 3 4]", SOX_EFF_MCHAN,
+    "swap", "[1 2 | 1 2 3 4]", SOX_EFF_MCHAN | SOX_EFF_MODIFY,
     sox_swap_getopts, sox_swap_start, sox_swap_flow,
     NULL, NULL, NULL, sizeof(priv_t)
   };
--- a/src/synth.c
+++ b/src/synth.c
@@ -1,7 +1,7 @@
 /* libSoX synth - Synthesizer Effect.
  *
+ * Copyright (c) 2001-2009 SoX contributors
  * Copyright (c) Jan 2001  Carsten Borchardt
- * Copyright (c) 2001-2008 SoX contributors
  *
  * This source code is freely redistributable and may be used for any purpose.
  * This copyright notice must be maintained.  The authors are not responsible
@@ -166,12 +166,14 @@
 /* Private data for the synthesizer */
 typedef struct {
   char *        length_str;
-  channel_t *      getopts_channels;
-  size_t    getopts_nchannels;
-  size_t    samples_done;
-  size_t    samples_to_do;
-  channel_t *      channels;
-  size_t    number_of_channels;
+  channel_t *   getopts_channels;
+  size_t        getopts_nchannels;
+  size_t        samples_done;
+  size_t        samples_to_do;
+  channel_t *   channels;
+  size_t        number_of_channels;
+  sox_bool      no_headroom;
+  double        gain;
 } priv_t;
 
 
@@ -263,17 +265,19 @@
 
 static int getopts(sox_effect_t * effp, int argc, char **argv)
 {
-  priv_t * synth = (priv_t *) effp->priv;
+  priv_t * p = (priv_t *) effp->priv;
   channel_t master, * chan = &master;
   int argn = 0;
   --argc, ++argv;
 
+  if (argc && !strcmp(*argv, "-n")) p->no_headroom = sox_true, ++argv, --argc;
+
   /* Get duration if given (if first arg starts with digit) */
   if (argc && (isdigit((int)argv[argn][0]) || argv[argn][0] == '.')) {
-    synth->length_str = lsx_malloc(strlen(argv[argn]) + 1);
-    strcpy(synth->length_str, argv[argn]);
+    p->length_str = lsx_malloc(strlen(argv[argn]) + 1);
+    strcpy(p->length_str, argv[argn]);
     /* Do a dummy parse of to see if it will fail */
-    if (lsx_parsesamples(0., synth->length_str, &synth->samples_to_do, 't') == NULL)
+    if (lsx_parsesamples(0., p->length_str, &p->samples_to_do, 't') == NULL)
       return lsx_usage(effp);
     argn++;
   }
@@ -291,23 +295,23 @@
 
   while (argn < argc) { /* type [combine] [f1[-f2] [off [ph [p1 [p2 [p3]]]]]] */
     char * end_ptr;
-    lsx_enum_item const *p = lsx_find_enum_text(argv[argn], synth_type);
+    lsx_enum_item const *enum_p = lsx_find_enum_text(argv[argn], synth_type);
 
-    if (p == NULL) {
+    if (enum_p == NULL) {
       lsx_fail("no type given");
       return SOX_EOF;
     }
-    synth->getopts_channels = lsx_realloc(synth->getopts_channels, sizeof(*synth->getopts_channels) * (synth->getopts_nchannels + 1));
-    chan = &synth->getopts_channels[synth->getopts_nchannels++];
+    p->getopts_channels = lsx_realloc(p->getopts_channels, sizeof(*p->getopts_channels) * (p->getopts_nchannels + 1));
+    chan = &p->getopts_channels[p->getopts_nchannels++];
     memcpy(chan, &master, sizeof(*chan));
-    chan->type = p->value;
+    chan->type = enum_p->value;
     if (++argn == argc)
       break;
 
     /* maybe there is a combine-type in next arg */
-    p = lsx_find_enum_text(argv[argn], combine_type);
-    if (p != NULL) {
-      chan->combine = p->value;
+    enum_p = lsx_find_enum_text(argv[argn], combine_type);
+    if (enum_p != NULL) {
+      chan->combine = enum_p->value;
       if (++argn == argc)
         break;
     }
@@ -329,7 +333,7 @@
           lsx_fail("invalid freq2");
           return SOX_EOF;
         }
-        if (synth->length_str == NULL) {
+        if (p->length_str == NULL) {
           lsx_fail("duration must be given when using freq2");
           return SOX_EOF;
         }
@@ -358,14 +362,14 @@
   }
 
   /* If no channel parameters were given, create one default channel: */
-  if (!synth->getopts_nchannels) {
-    synth->getopts_channels = lsx_malloc(sizeof(*synth->getopts_channels));
-    memcpy(&synth->getopts_channels[0], &master, sizeof(channel_t));
-    ++synth->getopts_nchannels;
+  if (!p->getopts_nchannels) {
+    p->getopts_channels = lsx_malloc(sizeof(*p->getopts_channels));
+    memcpy(&p->getopts_channels[0], &master, sizeof(channel_t));
+    ++p->getopts_nchannels;
   }
 
   if (!effp->in_signal.channels)
-    effp->in_signal.channels = synth->getopts_nchannels;
+    effp->in_signal.channels = p->getopts_nchannels;
 
   return SOX_SUCCESS;
 }
@@ -374,20 +378,20 @@
 
 static int start(sox_effect_t * effp)
 {
-  priv_t * synth = (priv_t *) effp->priv;
+  priv_t * p = (priv_t *)effp->priv;
   size_t i, j;
 
-  synth->samples_done = 0;
+  p->samples_done = 0;
 
-  if (synth->length_str)
-    if (lsx_parsesamples(effp->in_signal.rate, synth->length_str, &synth->samples_to_do, 't') == NULL)
+  if (p->length_str)
+    if (lsx_parsesamples(effp->in_signal.rate, p->length_str, &p->samples_to_do, 't') == NULL)
       return lsx_usage(effp);
 
-  synth->number_of_channels = effp->in_signal.channels;
-  synth->channels = lsx_calloc(synth->number_of_channels, sizeof(*synth->channels));
-  for (i = 0; i < synth->number_of_channels; ++i) {
-    channel_t *  chan = &synth->channels[i];
-    *chan = synth->getopts_channels[i % synth->getopts_nchannels];
+  p->number_of_channels = effp->in_signal.channels;
+  p->channels = lsx_calloc(p->number_of_channels, sizeof(*p->channels));
+  for (i = 0; i < p->number_of_channels; ++i) {
+    channel_t *  chan = &p->channels[i];
+    *chan = p->getopts_channels[i % p->getopts_nchannels];
     set_default_parameters(chan, i);
     if (chan->type == synth_pluck) {
       int32_t r = 0;
@@ -410,20 +414,20 @@
       lsx_debug("a=%g colour=%g", a, 1/colour);
     }
     switch (chan->sweep) {
-      case Linear: chan->mult = synth->samples_to_do?
-          (chan->freq2 - chan->freq) / synth->samples_to_do / 2 : 0;
+      case Linear: chan->mult = p->samples_to_do?
+          (chan->freq2 - chan->freq) / p->samples_to_do / 2 : 0;
         break;
-      case Square: chan->mult = synth->samples_to_do?
-           sqrt(fabs(chan->freq2 - chan->freq)) / synth->samples_to_do / sqrt(3.) : 0;
+      case Square: chan->mult = p->samples_to_do?
+           sqrt(fabs(chan->freq2 - chan->freq)) / p->samples_to_do / sqrt(3.) : 0;
         if (chan->freq > chan->freq2)
           chan->mult = -chan->mult;
         break;
-      case Exp: chan->mult = synth->samples_to_do?
-          log(chan->freq2 / chan->freq) / synth->samples_to_do * effp->in_signal.rate : 1;
+      case Exp: chan->mult = p->samples_to_do?
+          log(chan->freq2 / chan->freq) / p->samples_to_do * effp->in_signal.rate : 1;
         chan->freq /= chan->mult;
         break;
-      case Exp_cycle: chan->mult = synth->samples_to_do?
-          (log(chan->freq2) - log(chan->freq)) / synth->samples_to_do : 1;
+      case Exp_cycle: chan->mult = p->samples_to_do?
+          (log(chan->freq2) - log(chan->freq)) / p->samples_to_do : 1;
         break;
     }
     lsx_debug("type=%s, combine=%s, samples_to_do=%lu, f1=%g, f2=%g, "
@@ -430,18 +434,20 @@
               "offset=%g, phase=%g, p1=%g, p2=%g, p3=%g mult=%g",
         lsx_find_enum_value(chan->type, synth_type)->text,
         lsx_find_enum_value(chan->combine, combine_type)->text,
-        (unsigned long)synth->samples_to_do, chan->freq, chan->freq2,
+        (unsigned long)p->samples_to_do, chan->freq, chan->freq2,
         chan->offset, chan->phase, chan->p1, chan->p2, chan->p3, chan->mult);
   }
+  p->gain = 1;
+  effp->out_signal.mult = p->no_headroom? NULL : &p->gain;
   return SOX_SUCCESS;
 }
 
-#define elapsed_time_s synth->samples_done / effp->in_signal.rate
+#define elapsed_time_s p->samples_done / effp->in_signal.rate
 
 static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, sox_sample_t * obuf,
     size_t * isamp, size_t * osamp)
 {
-  priv_t * synth = (priv_t *) effp->priv;
+  priv_t * p = (priv_t *) effp->priv;
   unsigned len = min(*isamp, *osamp) / effp->in_signal.channels;
   unsigned c, done;
   int result = SOX_SUCCESS;
@@ -449,7 +455,7 @@
   for (done = 0; done < len && result == SOX_SUCCESS; ++done) {
     for (c = 0; c < effp->in_signal.channels; c++) {
       sox_sample_t synth_input = *ibuf++;
-      channel_t *  chan = &synth->channels[c];
+      channel_t *  chan = &p->channels[c];
       double synth_out;              /* [-1, 1] */
 
       if (chan->type < synth_noise) { /* Need to calculate phase: */
@@ -456,18 +462,18 @@
         double phase;            /* [0, 1) */
         switch (chan->sweep) {
           case Linear:
-            phase = (chan->freq + synth->samples_done * chan->mult) *
+            phase = (chan->freq + p->samples_done * chan->mult) *
                 elapsed_time_s;
             break;
           case Square:
             phase = (chan->freq + sign(chan->mult) * 
-                sqr(synth->samples_done * chan->mult)) * elapsed_time_s;
+                sqr(p->samples_done * chan->mult)) * elapsed_time_s;
             break;
           case Exp:
             phase = chan->freq * exp(chan->mult * elapsed_time_s);
             break;
           case Exp_cycle: default: {
-            double f = chan->freq * exp(synth->samples_done * chan->mult);
+            double f = chan->freq * exp(p->samples_done * chan->mult);
             double cycle_elapsed_time_s = elapsed_time_s - chan->cycle_start_time_s;
             if (f * cycle_elapsed_time_s >= 1) {  /* move to next cycle */
               chan->cycle_start_time_s += 1 / f;
@@ -603,13 +609,13 @@
 
       switch (chan->combine) {
         case synth_create: synth_out *=  SOX_SAMPLE_MAX; break;
-        case synth_mix   : synth_out = (synth_out * SOX_SAMPLE_MAX + synth_input) * 0.5; break;
-        case synth_amod  : synth_out = (synth_out + 1) * synth_input * 0.5; break;
+        case synth_mix   : synth_out = (synth_out * SOX_SAMPLE_MAX + synth_input) * .5; break;
+        case synth_amod  : synth_out = (synth_out + 1) * synth_input * .5; break;
         case synth_fmod  : synth_out *=  synth_input; break;
       }
-      *obuf++ = floor(synth_out + .5);
+      *obuf++ = synth_out < 0? synth_out * p->gain - .5 : synth_out * p->gain + .5;
     }
-    if (++synth->samples_done == synth->samples_to_do)
+    if (++p->samples_done == p->samples_to_do)
       result = SOX_EOF;
   }
   *isamp = *osamp = done * effp->in_signal.channels;
@@ -620,12 +626,12 @@
 
 static int stop(sox_effect_t * effp)
 {
-  priv_t * synth = (priv_t *) effp->priv;
+  priv_t * p = (priv_t *) effp->priv;
   size_t i;
 
-  for (i = 0; i < synth->number_of_channels; ++i)
-    free(synth->channels[i].buffer);
-  free(synth->channels);
+  for (i = 0; i < p->number_of_channels; ++i)
+    free(p->channels[i].buffer);
+  free(p->channels);
   return SOX_SUCCESS;
 }
 
@@ -633,9 +639,9 @@
 
 static int kill(sox_effect_t * effp)
 {
-  priv_t * synth = (priv_t *) effp->priv;
-  free(synth->getopts_channels);
-  free(synth->length_str);
+  priv_t * p = (priv_t *) effp->priv;
+  free(p->getopts_channels);
+  free(p->length_str);
   return SOX_SUCCESS;
 }
 
@@ -644,8 +650,8 @@
 const sox_effect_handler_t *sox_synth_effect_fn(void)
 {
   static sox_effect_handler_t handler = {
-    "synth", "[len] {type [combine] [[%]freq[k][:|+|/|-[%]freq2[k]] [off [ph [p1 [p2 [p3]]]]]]}",
-    SOX_EFF_MCHAN | SOX_EFF_PREC |SOX_EFF_LENGTH | SOX_EFF_GAIN,
+    "synth", "[-n] [len] {type [combine] [[%]freq[k][:|+|/|-[%]freq2[k]] [off [ph [p1 [p2 [p3]]]]]]}",
+    SOX_EFF_MCHAN | SOX_EFF_LENGTH | SOX_EFF_GAIN,
     getopts, start, flow, 0, stop, kill, sizeof(priv_t)
   };
   return &handler;
--- a/src/tempo.c
+++ b/src/tempo.c
@@ -272,7 +272,7 @@
   if (*isamp && odone < *osamp) {
     float * t = tempo_input(p->tempo, NULL, *isamp / effp->in_signal.channels);
     for (i = *isamp; i; --i)
-      *t++ = SOX_SAMPLE_TO_FLOAT_32BIT(*ibuf++);
+      *t++ = SOX_SAMPLE_TO_FLOAT_32BIT(*ibuf++, effp->clips);
     tempo_process(p->tempo);
   }
   else *isamp = 0;
--- a/src/tests.sh
+++ b/src/tests.sh
@@ -89,7 +89,7 @@
         getFormat         $1; format2Ext=$formatExt; format2Text=$formatText; format2Flags=$formatFlags
         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
+        execute ${bindir}/sox $verbose -RD -r $rate -c $channels $format2Flags intermediate.$format2Ext $format1Flags output.$format1Ext
         intermediateReference=vectors/intermediate`echo "$channels $rate $format1Flags $format1Ext $format2Flags"|tr " " "_"`.$format2Ext
 
 	# Uncomment to generate new reference files
@@ -172,21 +172,20 @@
 
 # Reading and writing performance test
 timeIO () {
+  ${bindir}/sox -c $channels -r $rate -n tmp.sox synth $samples's' saw 0:`expr $rate / 2` noise brown vol .9
   while [ $# != 0 ]; do
-      if [ "${skip}x" != "x" ] ; then
-        from_skip=`echo ${skip} | grep ${1}`
-      fi
-      if [ "${from_skip}x" = "x" ] ; then
-        getFormat $1;
-        echo ${bindir}/sox -c $channels -r $rate -n $formatFlags input.$1 synth $samples's' sin 300-3300 noise trapezium
-        echo time ${bindir}/sox $verbose -r $rate -c $channels $formatFlags input.$1 $formatFlags output.$1
-        ${bindir}/sox -c $channels -r $rate -n $formatFlags input.$1 synth $samples's' sin 300-3300 noise trapezium
-        time ${bindir}/sox $verbose -r $rate -c $channels $formatFlags input.$1 $formatFlags output.$1
-
-        rm -f input.$1 output.$1
-      fi
-      shift
+    if [ "${skip}x" != "x" ] ; then
+      from_skip=`echo ${skip} | grep ${1}`
+    fi
+    if [ "${from_skip}x" = "x" ] ; then
+      getFormat $1;
+      echo "TIME \"$formatText\" channels=$channels samples=$samples write, read:"
+      time ${bindir}/sox $verbose -D tmp.sox $formatFlags -t $1 - | \
+      time ${bindir}/sox $verbose -t $1 -c $channels -r $rate - -t sox /dev/null
+    fi
+    shift
   done
+  rm tmp.sox
 }
 
 # Don't try to test un-built formats
@@ -200,6 +199,8 @@
 
 # Run tests
 
+${builddir}/sox_sample_test || exit 1
+
 skip_check caf flac mat4 mat5 paf w64 wv
 
 vectors=0
@@ -246,8 +247,8 @@
 echo "Checked $vectors vectors"
 
 channels=2
-samples=10000000
-timeIO s1 u1 s2 u2 s3 u3 s4 u4 f4 f8 au wav aiff aifc caf sph # FIXME?: flac dat
+samples=1e7
+timeIO s1 u1 s2 u2 s3 u3 s4 u4 f4 f8 au wav aiff aifc sph # FIXME?: caf flac dat
 
 test -n "$skip" && echo "Skipped: $skip"
 
binary files a/src/vectors/intermediate1_44100_-u_-1_wav_-N.s1 b/src/vectors/intermediate1_44100_-u_-1_wav_-N.s1 differ
binary files a/src/vectors/intermediate1_44100_-u_-1_wav_-X.s1 b/src/vectors/intermediate1_44100_-u_-1_wav_-X.s1 differ
binary files a/src/vectors/intermediate1_44100_-u_-1_wav_-X_-N.s1 b/src/vectors/intermediate1_44100_-u_-1_wav_-X_-N.s1 differ
binary files a/src/vectors/intermediate1_44100_-u_-1_wav_.s1 b/src/vectors/intermediate1_44100_-u_-1_wav_.s1 differ
--- a/src/voc.c
+++ b/src/voc.c
@@ -347,6 +347,7 @@
       /* Read the data in the file */
       if (v->size <= 4) {
         if (!v->adpcm.setup.sign) {
+          SOX_SAMPLE_LOCALS;
           if (lsx_readb(ft, &uc) == SOX_EOF) {
             lsx_warn("VOC input: short file");
             v->block_remaining = 0;
@@ -353,7 +354,7 @@
             return done;
           }
           *buf = SOX_UNSIGNED_8BIT_TO_SAMPLE(uc,);
-          lsx_adpcm_init(&v->adpcm, 6 - v->size, SOX_SAMPLE_TO_SIGNED_16BIT(*buf));
+          lsx_adpcm_init(&v->adpcm, 6 - v->size, SOX_SAMPLE_TO_SIGNED_16BIT(*buf, ft->clips));
           ++buf;
           --v->block_remaining;
           ++done;
@@ -489,11 +490,12 @@
   }
   v->samples += len;
   while (done < len) {
+    SOX_SAMPLE_LOCALS;
     if (ft->encoding.bits_per_sample == 8) {
-      uc = SOX_SAMPLE_TO_UNSIGNED_8BIT(*buf++);
+      uc = SOX_SAMPLE_TO_UNSIGNED_8BIT(*buf++, ft->clips);
       lsx_writeb(ft, uc);
     } else {
-      sw = (int) SOX_SAMPLE_TO_SIGNED_16BIT(*buf++);
+      sw = (int) SOX_SAMPLE_TO_SIGNED_16BIT(*buf++, ft->clips);
       lsx_writesw(ft, sw);
     }
     done++;
--- a/src/wav.c
+++ b/src/wav.c
@@ -331,9 +331,10 @@
     ft->sox_errno = SOX_SUCCESS;
 
     while (done < len) {
+        SOX_SAMPLE_LOCALS;
         while ((wav->gsmindex < 160*2) && (done < len))
             wav->gsmsample[(wav->gsmindex)++] =
-                SOX_SAMPLE_TO_SIGNED_16BIT(buf[done++]);
+                SOX_SAMPLE_TO_SIGNED_16BIT(buf[done++], ft->clips);
 
         if (wav->gsmindex < 160*2)
             break;
--- a/src/wavpack.c
+++ b/src/wavpack.c
@@ -120,13 +120,14 @@
   int result;
 
   for (i = 0; i < len; ++i) switch (ft->encoding.bits_per_sample) {
-    case  8: obuf[i] = SOX_SAMPLE_TO_SIGNED_8BIT(buf[i]); break;
-    case 16: obuf[i] = SOX_SAMPLE_TO_SIGNED_16BIT(buf[i]); break;
-    case 24: obuf[i] = SOX_SAMPLE_TO_SIGNED_24BIT(buf[i]) << 8;
+    SOX_SAMPLE_LOCALS;
+    case  8: obuf[i] = SOX_SAMPLE_TO_SIGNED_8BIT(buf[i], ft->clips); break;
+    case 16: obuf[i] = SOX_SAMPLE_TO_SIGNED_16BIT(buf[i], ft->clips); break;
+    case 24: obuf[i] = SOX_SAMPLE_TO_SIGNED_24BIT(buf[i], ft->clips) << 8;
              obuf[i] >>= 8; break;
     case 32: obuf[i] = ft->encoding.encoding == SOX_ENCODING_WAVPACKF?
-      SOX_SAMPLE_TO_SIGNED_24BIT(*(float *)&buf[i]) :
-      SOX_SAMPLE_TO_SIGNED_32BIT(buf[i]);
+      SOX_SAMPLE_TO_SIGNED_24BIT(*(float *)&buf[i], ft->clips) :
+      SOX_SAMPLE_TO_SIGNED_32BIT(buf[i], ft->clips);
       break;
   }
   result = WavpackPackSamples(p->codec, obuf, (uint32_t) len / ft->signal.channels);