shithub: sox

Download patch

ref: 51d22893437c3dcd74d31093e4b0f20d717007b6
parent: af7e8d1b71257abdfc1caf93cce47946a11b606c
author: robs <robs>
date: Wed Dec 6 14:04:36 EST 2006

Improved the accuracy of integer and floating point PCM conversions.

--- a/ChangeLog
+++ b/ChangeLog
@@ -40,7 +40,7 @@
   o Fix wav file handler discarding the last PCM sample in certain
     circumstances. (robs)
   o Add support for 24-bit PCM raw, wav (WAVE_FORMAT_EXTENSIBLE) [FR# 801015],
-    aiff, & flac files. (robs)
+    au, aiff, & flac files. (robs)
   o Added alias -1 (for -b), -2 (for -w), -4 (for -l), -8 (for -d). (robs)
   o Remove old, optional rate change and alaw/ulaw conversion code.
     (Reuben Thomas)
@@ -59,6 +59,8 @@
   o Documented the butterworth filter effects.  (robs)
   o Added command line options for specifying the output file
     comment.  (robs)
+  o Improved the accuracy of integer and floating point PCM
+    conversions.  (robs)
 
 sox-12.18.2
 -----------
--- a/TODO
+++ b/TODO
@@ -83,11 +83,6 @@
     of detecting uint64_t...  Use that when possible to speed up
     math (won't have to convert back and forth from int to float).
 
-  o Fix conversions to and from st_sample_t to floats.  Currently,
-    its an approximation because it doesn't account from negative
-    side having 1 more value then positive side.  That means instead
-    of -1:1 range, its more like -0.999:1 or -1:0.9999.
-
   o WAV handler is not using world alignment for at least the
     main data chunk (expect for GSM).
 
--- a/sox.1
+++ b/sox.1
@@ -53,6 +53,8 @@
 .P
 Exit status is 0 for no error, 1 if there is a problem with the command-line arguments, and 2 if an error occurs during file processing.
 .P
+\fBFile Format Types\fR
+.br
 There are two types of audio file format that
 .I SoX
 can work with.  The first is "self-describing".  Such formats
@@ -59,7 +61,8 @@
 include a header that completely describe the characteristics of
 the audio data that follows.
 The header may also allow the inclusion of textual "comments" that can
-be used to describe the audio in some way.
+be used to describe the audio in some way, e.g. for music, the title,
+the author, etc.
 .P
 The second type is header-less data, often called raw data.
 For this type, a
@@ -82,12 +85,62 @@
 What encoding the data type uses.  Examples are u-law, ADPCM, or signed linear data.
 .TP 10
 channels
-How many channels are contained in the audio data.  Mono (1) and stereo (2) are the two most common.
+The number of audio channels contained in the file.  1 ("mono") and 2
+("stereo") are widely used.
 .P
 Please refer to the
 .B soxexam(1)
 manual page for a long description with examples on how to use SoX with
 various file formats.
+.P
+\fBFormat Conversion\fR
+.br
+Converting an audio file from one format to another with
+.I SoX
+is "lossless"
+(i.e. converting back again would yield an exact copy of the original
+audio signal)
+where it
+can be, i.e. when not using "lossy" compression (e.g. A-law, mp3, etc.)
+and the number of bits used in the destination format is not less than
+in the source format.
+
+E.g. converting from an 8-bit PCM format to a 16-bit PCM format is
+lossless but converting from a 24-bit PCM format to a 16-bit PCM format isn't.
+When performing a lossy conversion,
+.I SoX
+uses rounding to retain as much accuracy as possible in the
+audio signal.
+.P
+\fBClipping\fR
+.br
+Clipping is distortion that occurs when an audio signal
+level exceeds the range of the chosen representation.
+Clipping is rarely desirable and so should usually be corrected by
+adjusting the audio volume prior to the point at which clipping occurs.
+
+In \fISoX\fR, clipping could occur, as you might expect, when using the
+.I vol
+effect to increase the audio volume, but could also occur with many
+other effects, when converting one format to another, and even when
+simply playing the audio.
+
+Playing an audio file often involves reampling, and processing by
+analogue components that can introduce a small DC offset and/or
+amplification, all of which can produce distortion if the audio signal
+level was intially too close to the clipping point.
+
+For these reasons, it is usual to make sure that a digital audio
+file's signal level does not exceed around 70% of the maximum (linear)
+range available, as this will avoid the majority of clipping problems.
+\fISoX\fR's
+.I stat
+effect can assist here by displaying the signal level in an audio file.
+
+If clipping occurrs at any point during processing, then
+.I SoX
+will display a warning message to that effect.
+
 .SH OPTIONS
 The option syntax is somewhat complex, but in essence:
 .P
@@ -1464,7 +1517,7 @@
 
 Multiple channels can be synthesised by specifying the set of
 parameters shown between braces ({}) multiple times;
-the following puts the swept tone in the left channel and "brown"
+the following puts the swept tone in the left channel and adds "brown"
 noise in the right:
 
 	sox -n output.au synth 3 sine 300-3300 brownnoise
--- a/src/8svx.c
+++ b/src/8svx.c
@@ -300,7 +300,7 @@
 
         while(done < len) {
                 for (i = 0; i < ft->info.channels; i++) {
-                        datum = ST_SAMPLE_TO_SIGNED_BYTE(*buf++);
+                        datum = ST_SAMPLE_TO_SIGNED_BYTE(*buf++, ft->clippedCount);
                         /* FIXME: Needs to pass ft struct and not FILE */
                         putc(datum, p->ch[i]);
                 }
--- a/src/au.c
+++ b/src/au.c
@@ -80,6 +80,10 @@
             *encoding = ST_ENCODING_SIGN2;
             *size = ST_SIZE_WORD;
             break;
+    case SUN_LIN_24:
+            *encoding = ST_ENCODING_SIGN2;
+            *size = ST_SIZE_24BIT;
+            break;
     case SUN_G721:
             *encoding = ST_ENCODING_SIGN2;
             *size = ST_SIZE_WORD;
@@ -402,6 +406,8 @@
                 sun_encoding = SUN_LIN_8;
         else if (encoding == ST_ENCODING_SIGN2 && size == ST_SIZE_WORD)
                 sun_encoding = SUN_LIN_16;
+        else if (encoding == ST_ENCODING_SIGN2 && size == ST_SIZE_24BIT)
+                sun_encoding = SUN_LIN_24;
         else if (encoding == ST_ENCODING_FLOAT && size == ST_SIZE_32BIT)
                 sun_encoding = SUN_FLOAT;
         else
@@ -421,7 +427,7 @@
 
         if ((encoding = st_ausunencoding(ft->info.size, ft->info.encoding)) == -1) {
                 st_report("Unsupported output encoding/size for Sun/NeXT header or .AU format not specified.");
-                st_report("Only U-law, A-law signed bytes, and signed words are supported.");
+                st_report("Only U-law, A-law, and signed bytes/words/tri-bytes are supported.");
                 st_report("Defaulting to 8khz u-law");
                 encoding = SUN_ULAW;
                 ft->info.encoding = ST_ENCODING_ULAW;
--- a/src/avg.c
+++ b/src/avg.c
@@ -527,7 +527,7 @@
             samp = 0.0;
             for (i = 0; i < ichan; i++)
                 samp += ibuf[i] * avg->sources[i][j];
-            ST_EFF_SAMPLE_CLIP_COUNT(samp);
+            ST_SAMPLE_CLIP_COUNT(samp, effp->clippedCount);
             obuf[j] = samp;
         }
     }
--- a/src/biquad.c
+++ b/src/biquad.c
@@ -14,7 +14,7 @@
     double o0 = *ibuf*p->b0 +p->i1*p->b1 +p->i2*p->b2 -p->o1*p->a1 -p->o2*p->a2;
     p->i2 = p->i1, p->i1 = *ibuf++;
     p->o2 = p->o1, p->o1 = o0;
-    *obuf++ = ST_EFF_ROUND_CLIP_COUNT(o0);
+    *obuf++ = ST_ROUND_CLIP_COUNT(o0, effp->clippedCount);
   }
   return ST_SUCCESS;
 }
--- a/src/btrworth.c
+++ b/src/btrworth.c
@@ -103,7 +103,7 @@
     butterworth->y [1] = butterworth->y [0];
     butterworth->y [0] = out;
 
-    ST_EFF_SAMPLE_CLIP_COUNT(out);
+    ST_SAMPLE_CLIP_COUNT(out, effp->clippedCount);
 
     *obuf++ = out;
   }
--- a/src/chorus.c
+++ b/src/chorus.c
@@ -276,7 +276,7 @@
                         chorus->maxsamples] * chorus->decay[i];
                 /* Adjust the output volume and size to 24 bit */
                 d_out = d_out * chorus->out_gain;
-                out = ST_EFF_24BIT_CLIP_COUNT((st_sample_t) d_out);
+                out = ST_24BIT_CLIP_COUNT((st_sample_t) d_out, effp->clippedCount);
                 *obuf++ = out * 256;
                 /* Mix decay of delay and input */
                 chorus->chorusbuf[chorus->counter] = d_in;
@@ -313,7 +313,7 @@
                 chorus->maxsamples] * chorus->decay[i];
                 /* Adjust the output volume and size to 24 bit */
                 d_out = d_out * chorus->out_gain;
-                out = ST_EFF_24BIT_CLIP_COUNT((st_sample_t) d_out);
+                out = ST_24BIT_CLIP_COUNT((st_sample_t) d_out, effp->clippedCount);
                 *obuf++ = out * 256;
                 /* Mix decay of delay and input */
                 chorus->chorusbuf[chorus->counter] = d_in;
--- a/src/compand.c
+++ b/src/compand.c
@@ -316,7 +316,7 @@
       if (l->delay_buf_size <= 0)
       {
         checkbuf = ibuf[chan]*(outv/v)*l->outgain;
-        ST_EFF_SAMPLE_CLIP_COUNT(checkbuf);
+        ST_SAMPLE_CLIP_COUNT(checkbuf, effp->clippedCount);
         obuf[odone] = checkbuf;
 
         idone++;
@@ -328,7 +328,7 @@
         {
             l->delay_buf_full=1; //delay buffer is now definetly full
             checkbuf = l->delay_buf[l->delay_buf_ptr]*(outv/v)*l->outgain;
-            ST_EFF_SAMPLE_CLIP_COUNT(checkbuf);
+            ST_SAMPLE_CLIP_COUNT(checkbuf, effp->clippedCount);
             obuf[odone] = checkbuf;
 
             odone++;
--- a/src/dat.c
+++ b/src/dat.c
@@ -25,9 +25,6 @@
 #include "st_i.h"
 #include <string.h>
 
-/* float output normalized to approx 1.0 */
-#define FLOATTOLONG (2.147483648e9)
-#define LONGTOFLOAT (1 / FLOATTOLONG)
 #define LINEWIDTH 256
 
 /* Private data for dat file */
@@ -129,7 +126,7 @@
           st_fail_errno(ft,ST_EOF,"Unable to read sample.");
           return (ST_EOF);
         }
-        sampval *= FLOATTOLONG;
+        sampval *= ST_SAMPLE_MAX;
         *buf++ = ST_ROUND_CLIP_COUNT(sampval, ft->clippedCount);
         done++;
       }
@@ -154,8 +151,7 @@
       sprintf(s," %15.8g ",dat->timevalue);
       st_writes(ft, s);
       for (i=0; i<ft->info.channels; i++) {
-        sampval = *buf++ ;
-        sampval = sampval * LONGTOFLOAT;
+        sampval = ST_SAMPLE_TO_FLOAT_DDWORD(*buf++, ft->clippedCount);
         sprintf(s," %15.8g", sampval);
         st_writes(ft, s);
         done++;
--- a/src/echo.c
+++ b/src/echo.c
@@ -208,7 +208,7 @@
                 }
                 /* Adjust the output volume and size to 24 bit */
                 d_out = d_out * echo->out_gain;
-                out = ST_EFF_24BIT_CLIP_COUNT((st_sample_t) d_out);
+                out = ST_24BIT_CLIP_COUNT((st_sample_t) d_out, effp->clippedCount);
                 *obuf++ = out * 256;
                 /* Store input in delay buffer */
                 echo->delay_buf[echo->counter] = d_in;
@@ -242,7 +242,7 @@
                 }
                 /* Adjust the output volume and size to 24 bit */
                 d_out = d_out * echo->out_gain;
-                out = ST_EFF_24BIT_CLIP_COUNT((st_sample_t) d_out);
+                out = ST_24BIT_CLIP_COUNT((st_sample_t) d_out, effp->clippedCount);
                 *obuf++ = out * 256;
                 /* Store input in delay buffer */
                 echo->delay_buf[echo->counter] = d_in;
--- a/src/echos.c
+++ b/src/echos.c
@@ -198,7 +198,7 @@
                 }
                 /* Adjust the output volume and size to 24 bit */
                 d_out = d_out * echos->out_gain;
-                out = ST_EFF_24BIT_CLIP_COUNT((st_sample_t) d_out);
+                out = ST_24BIT_CLIP_COUNT((st_sample_t) d_out, effp->clippedCount);
                 *obuf++ = out * 256;
                 /* Mix decay of delays and input */
                 for ( j = 0; j < echos->num_delays; j++ ) {
@@ -238,7 +238,7 @@
                 }
                 /* Adjust the output volume and size to 24 bit */
                 d_out = d_out * echos->out_gain;
-                out = ST_EFF_24BIT_CLIP_COUNT((st_sample_t) d_out);
+                out = ST_24BIT_CLIP_COUNT((st_sample_t) d_out, effp->clippedCount);
                 *obuf++ = out * 256;
                 /* Mix decay of delays and input */
                 for ( j = 0; j < echos->num_delays; j++ ) {
--- a/src/equalizer.c
+++ b/src/equalizer.c
@@ -173,7 +173,7 @@
            );
     eq->y[0] = out;
 
-    ST_EFF_SAMPLE_CLIP_COUNT(out);
+    ST_SAMPLE_CLIP_COUNT(out, effp->clippedCount);
     *obuf++ = out;
   }
 
--- a/src/flac.c
+++ b/src/flac.c
@@ -432,9 +432,9 @@
   {
     switch (encoder->bits_per_sample)
     {
-      case  8: encoder->decoded_samples[i] = ST_SAMPLE_TO_SIGNED_BYTE(sampleBuffer[i]); break;
-      case 16: encoder->decoded_samples[i] = ST_SAMPLE_TO_SIGNED_WORD(sampleBuffer[i]); break;
-      case 24: encoder->decoded_samples[i] = ST_SAMPLE_TO_SIGNED_24BIT(sampleBuffer[i]); break;
+      case  8: encoder->decoded_samples[i] = ST_SAMPLE_TO_SIGNED_BYTE(sampleBuffer[i], format->clippedCount); break;
+      case 16: encoder->decoded_samples[i] = ST_SAMPLE_TO_SIGNED_WORD(sampleBuffer[i], format->clippedCount); break;
+      case 24: encoder->decoded_samples[i] = ST_SAMPLE_TO_SIGNED_24BIT(sampleBuffer[i],format->clippedCount); break;
       case 32: encoder->decoded_samples[i] = ST_SAMPLE_TO_SIGNED_DWORD(sampleBuffer[i]); break;
     }
   }
--- a/src/flanger.c
+++ b/src/flanger.c
@@ -227,7 +227,7 @@
         flanger->maxsamples] * flanger->decay;
                 /* Adjust the output volume and size to 24 bit */
                 d_out = d_out * flanger->out_gain;
-                out = ST_EFF_24BIT_CLIP_COUNT((st_sample_t) d_out);
+                out = ST_24BIT_CLIP_COUNT((st_sample_t) d_out, effp->clippedCount);
                 *obuf++ = out * 256;
                 /* Mix decay of delay and input */
                 flanger->flangerbuf[flanger->counter] = d_in;
@@ -260,7 +260,7 @@
         flanger->maxsamples] * flanger->decay;
                 /* Adjust the output volume and size to 24 bit */
                 d_out = d_out * flanger->out_gain;
-                out = ST_EFF_24BIT_CLIP_COUNT((st_sample_t) d_out);
+                out = ST_24BIT_CLIP_COUNT((st_sample_t) d_out, effp->clippedCount);
                 *obuf++ = out * 256;
                 /* Mix decay of delay and input */
                 flanger->flangerbuf[flanger->counter] = d_in;
--- a/src/gsm.c
+++ b/src/gsm.c
@@ -192,7 +192,7 @@
         {
                 while ((p->samplePtr < p->sampleTop) && (done < samp))
                         *(p->samplePtr)++ = 
-                            ST_SAMPLE_TO_SIGNED_WORD(buf[done++]);
+                            ST_SAMPLE_TO_SIGNED_WORD(buf[done++], ft->clippedCount);
 
                 if (p->samplePtr == p->sampleTop)
                 {
--- a/src/hcom.c
+++ b/src/hcom.c
@@ -226,10 +226,7 @@
                                 p->sample = 0;
                         p->sample = (p->sample + datum) & 0xff;
                         p->huffcount--;
-                        if (p->sample == 0)
-                                *buf++ = ST_UNSIGNED_BYTE_TO_SAMPLE(1);
-                        else
-                                *buf++ = ST_UNSIGNED_BYTE_TO_SAMPLE(p->sample);
+                        *buf++ = ST_UNSIGNED_BYTE_TO_SAMPLE(p->sample);
                         p->dictentry = 0;
                         done++;
                         len--;
@@ -326,7 +323,7 @@
 
         while (len-- > 0) {
                 datum = *buf++;
-                p->data[p->pos++] = ST_SAMPLE_TO_UNSIGNED_BYTE(datum);
+                p->data[p->pos++] = ST_SAMPLE_TO_UNSIGNED_BYTE(datum, ft->clippedCount);
         }
 
         return (save_len - len);
--- a/src/highp.c
+++ b/src/highp.c
@@ -115,7 +115,7 @@
                 d = highp->A0 * l + 
                     highp->A1 * highp->inm1 + 
                     highp->B1 * highp->outm1;
-                ST_EFF_SAMPLE_CLIP_COUNT(d);
+                ST_SAMPLE_CLIP_COUNT(d, effp->clippedCount);
                 highp->inm1 = l;
                 highp->outm1 = d;
                 *obuf++ = d;
--- a/src/lowp.c
+++ b/src/lowp.c
@@ -109,7 +109,7 @@
         for(done = 0; done < len; done++) {
                 l = *ibuf++;
                 d = lowp->A * l + lowp->B * lowp->outm1;
-                ST_EFF_SAMPLE_CLIP_COUNT(d);
+                ST_SAMPLE_CLIP_COUNT(d, effp->clippedCount);
                 lowp->outm1 = d;
                 *obuf++ = d;
         }
--- a/src/mcompand.c
+++ b/src/mcompand.c
@@ -168,7 +168,7 @@
       butterworth->xy_low[chan].y [1] = butterworth->xy_low[chan].y [0];
       butterworth->xy_low[chan].y [0] = out;
 
-      ST_EFF_SAMPLE_CLIP_COUNT(out);
+      ST_SAMPLE_CLIP_COUNT(out, effp->clippedCount);
 
       *lowbufptr = out;
 
@@ -184,7 +184,7 @@
       butterworth->xy_high[chan].y [1] = butterworth->xy_high[chan].y [0];
       butterworth->xy_high[chan].y [0] = out;
 
-      ST_EFF_SAMPLE_CLIP_COUNT(out);
+      ST_SAMPLE_CLIP_COUNT(out, effp->clippedCount);
 
       /* don't forget polarity reversal of high pass! */
 
@@ -613,7 +613,7 @@
     for (i=0;i<len;++i)
     {
       out = obuf[i] + abuf[i];
-      ST_EFF_SAMPLE_CLIP_COUNT(out);
+      ST_SAMPLE_CLIP_COUNT(out, effp->clippedCount);
       obuf[i] = out;
     }
     oldabuf = abuf;
@@ -638,7 +638,7 @@
    */
   for (done = 0;  done < maxdrain  &&  l->delay_buf_cnt > 0;  done++) {
     out = obuf[done] + l->delay_buf[l->delay_buf_ptr++];
-    ST_EFF_SAMPLE_CLIP_COUNT(out);
+    ST_SAMPLE_CLIP_COUNT(out, effp->clippedCount);
     obuf[done] = out;
     l->delay_buf_ptr %= c->delay_buf_size;
     l->delay_buf_cnt--;
--- a/src/mp3.c
+++ b/src/mp3.c
@@ -482,8 +482,8 @@
         j=0;
         for (i=0; i<nsamples; i++)
         {
-            buffer_l[i]=ST_SAMPLE_TO_SIGNED_WORD(buf[j++]);
-            buffer_r[i]=ST_SAMPLE_TO_SIGNED_WORD(buf[j++]);
+            buffer_l[i]=ST_SAMPLE_TO_SIGNED_WORD(buf[j++], ft->clippedCount);
+            buffer_r[i]=ST_SAMPLE_TO_SIGNED_WORD(buf[j++], ft->clippedCount);
         }
     }
     else
@@ -491,7 +491,7 @@
         j=0;
         for (i=0; i<nsamples; i++)
         {
-            buffer_l[i]=ST_SAMPLE_TO_SIGNED_WORD(buf[j++]); 
+            buffer_l[i]=ST_SAMPLE_TO_SIGNED_WORD(buf[j++], ft->clippedCount); 
         }
     }
 
--- a/src/noiseprof.c
+++ b/src/noiseprof.c
@@ -130,7 +130,7 @@
         int j;
         for (j = 0; j < ncopy; j ++) {
             chan->window[j+data->bufdata] =
-                ST_SAMPLE_TO_FLOAT_DWORD(ibuf[i+j*tracks]);
+                ST_SAMPLE_TO_FLOAT_DWORD(ibuf[i+j*tracks], effp->clippedCount);
         }
         if (ncopy + data->bufdata == WINDOWSIZE) {
             collect_data(data, chan);
--- a/src/noisered.c
+++ b/src/noisered.c
@@ -225,9 +225,8 @@
     if (!first) {
         for (j = 0; j < use; j ++) {
             float s = chan->window[j] + chan->lastwindow[WINDOWSIZE/2 + j];
-            ST_EFF_NORMALIZED_CLIP_COUNT(s);
             obuf[chan_num + num_chans * j] =
-                ST_FLOAT_DWORD_TO_SAMPLE(s);
+                ST_FLOAT_DWORD_TO_SAMPLE(s, effp->clippedCount);
         }
         free(chan->lastwindow);
     } else {
@@ -234,7 +233,7 @@
         for (j = 0; j < use; j ++) {
             assert(chan->window[j] >= -1 && chan->window[j] <= 1);
             obuf[chan_num + num_chans * j] =
-                ST_FLOAT_DWORD_TO_SAMPLE(chan->window[j]);
+                ST_FLOAT_DWORD_TO_SAMPLE(chan->window[j], effp->clippedCount);
         }
     }
     chan->lastwindow = chan->window;
@@ -275,7 +274,7 @@
         
         for (j = 0; j < ncopy; j ++) {
             chan->window[oldbuf + j] =
-                ST_SAMPLE_TO_FLOAT_DWORD(ibuf[i + tracks * j]);
+                ST_SAMPLE_TO_FLOAT_DWORD(ibuf[i + tracks * j], effp->clippedCount);
         }
 
         if (!whole_window)
--- a/src/pan.c
+++ b/src/pan.c
@@ -112,7 +112,7 @@
             {
                 double f;
                 f = 0.5*ibuf_copy[0] + 0.5*ibuf_copy[1];
-                ST_EFF_SAMPLE_CLIP_COUNT(f);
+                ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                 *obuf++ = f;
                 ibuf_copy += 2;
             }
@@ -123,7 +123,7 @@
                 double f;
                 f = 0.25*ibuf_copy[0] + 0.25*ibuf_copy[1] + 
                         0.25*ibuf_copy[2] + 0.25*ibuf_copy[3];
-                ST_EFF_SAMPLE_CLIP_COUNT(f);
+                ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                 *obuf++ = f;
                 ibuf_copy += 4;
             }
@@ -141,10 +141,10 @@
                 double f;
 
                 f = left * ibuf_copy[0];
-                ST_EFF_SAMPLE_CLIP_COUNT(f);
+                ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                 obuf[0] = f;
                 f = right * ibuf_copy[0];
-                ST_EFF_SAMPLE_CLIP_COUNT(f);
+                ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                 obuf[1] = f;
                 obuf += 2;
                 ibuf_copy++;
@@ -167,10 +167,10 @@
                     double f;
 
                     f = cll * ibuf_copy[0] + clr * ibuf_copy[1];
-                    ST_EFF_SAMPLE_CLIP_COUNT(f);
+                    ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                     obuf[0] = f;
                     f = cr * ibuf_copy[1];
-                    ST_EFF_SAMPLE_CLIP_COUNT(f);
+                    ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                     obuf[1] = f;
                     obuf += 2;
                     ibuf_copy += 2;
@@ -190,10 +190,10 @@
                     double f;
 
                     f = cl * ibuf_copy[0];
-                    ST_EFF_SAMPLE_CLIP_COUNT(f);
+                    ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                     obuf[0] = f;
                     f = crl * ibuf_copy[0] + crr * ibuf_copy[1];
-                    ST_EFF_SAMPLE_CLIP_COUNT(f);
+                    ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                     obuf[1] = f;
                     obuf += 2;
                     ibuf_copy += 2;
@@ -220,10 +220,10 @@
 
                     /* pan it */
                     f = cll * ibuf0 + clr * ibuf1;
-                    ST_EFF_SAMPLE_CLIP_COUNT(f);
+                    ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                     obuf[0] = f;
                     f = cr * ibuf1;
-                    ST_EFF_SAMPLE_CLIP_COUNT(f);
+                    ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                     obuf[1] = f;
                     obuf += 2;
                     ibuf_copy += 4;
@@ -246,10 +246,10 @@
                     ibuf1 = 0.5*ibuf_copy[1] + 0.5*ibuf_copy[3];
 
                     f = cl * ibuf0;
-                    ST_EFF_SAMPLE_CLIP_COUNT(f);
+                    ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                     obuf[0] = f;
                     f = crl * ibuf0 + crr * ibuf1;
-                    ST_EFF_SAMPLE_CLIP_COUNT(f);
+                    ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                     obuf[1] = f;
                     obuf += 2;
                     ibuf_copy += 4;
@@ -275,10 +275,10 @@
                     double f;
 
                     f = cl * ibuf_copy[0];
-                    ST_EFF_SAMPLE_CLIP_COUNT(f);
+                    ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                     obuf[2] = obuf[0] = f;
                     f = cr * ibuf_copy[0];
-                    ST_EFF_SAMPLE_CLIP_COUNT(f);
+                    ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                     ibuf_copy[3] = obuf[1] = f;
                     obuf += 4;
                     ibuf_copy++;
@@ -300,10 +300,10 @@
                     double f;
 
                     f = cll * ibuf_copy[0] + clr * ibuf_copy[1];
-                    ST_EFF_SAMPLE_CLIP_COUNT(f);
+                    ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                     obuf[2] = obuf[0] = f;
                     f = cr * ibuf_copy[1];
-                    ST_EFF_SAMPLE_CLIP_COUNT(f);
+                    ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                     ibuf_copy[3] = obuf[1] = f;
                     obuf += 4;
                     ibuf_copy += 2;
@@ -323,10 +323,10 @@
                     double f;
 
                     f = cl * ibuf_copy[0];
-                    ST_EFF_SAMPLE_CLIP_COUNT(f);
+                    ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                     obuf[2] = obuf[0] =f ;
                     f = crl * ibuf_copy[0] + crr * ibuf_copy[1];
-                    ST_EFF_SAMPLE_CLIP_COUNT(f);
+                    ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                     ibuf_copy[3] = obuf[1] = f;
                     obuf += 4;
                     ibuf_copy += 2;
@@ -349,16 +349,16 @@
                     double f;
 
                     f = cown*ibuf_copy[0] + cright*ibuf_copy[1];
-                    ST_EFF_SAMPLE_CLIP_COUNT(f);
+                    ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                     obuf[0] = f;
                     f = cown*ibuf_copy[1] + cright*ibuf_copy[3];
-                    ST_EFF_SAMPLE_CLIP_COUNT(f);
+                    ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                     obuf[1] = f;
                     f = cown*ibuf_copy[2] + cright*ibuf_copy[0];
-                    ST_EFF_SAMPLE_CLIP_COUNT(f);
+                    ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                     obuf[2] = f;
                     f = cown*ibuf_copy[3] + cright*ibuf_copy[2];
-                    ST_EFF_SAMPLE_CLIP_COUNT(f);
+                    ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                     obuf[3] = f;
                     obuf += 4;
                     ibuf_copy += 4;              
@@ -376,16 +376,16 @@
                     double f;
 
                     f = cleft*ibuf_copy[2] + cown*ibuf_copy[0];
-                    ST_EFF_SAMPLE_CLIP_COUNT(f);
+                    ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                     obuf[0] = f;
                     f = cleft*ibuf_copy[0] + cown*ibuf_copy[1];
-                    ST_EFF_SAMPLE_CLIP_COUNT(f);
+                    ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                     obuf[1] = f;
                     f = cleft*ibuf_copy[3] + cown*ibuf_copy[2];
-                    ST_EFF_SAMPLE_CLIP_COUNT(f);
+                    ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                     obuf[2] = f;
                     f = cleft*ibuf_copy[1] + cown*ibuf_copy[3];
-                    ST_EFF_SAMPLE_CLIP_COUNT(f);
+                    ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                     obuf[3] = f;
                     obuf += 4;
                     ibuf_copy += 4;
--- a/src/phaser.c
+++ b/src/phaser.c
@@ -214,7 +214,7 @@
         phaser->maxsamples] * phaser->decay * -1.0;
                 /* Adjust the output volume and size to 24 bit */
                 d_out = d_in * phaser->out_gain;
-                out = ST_EFF_24BIT_CLIP_COUNT((st_sample_t) d_out);
+                out = ST_24BIT_CLIP_COUNT((st_sample_t) d_out, effp->clippedCount);
                 *obuf++ = out * 256;
                 /* Mix decay of delay and input */
                 phaser->phaserbuf[phaser->counter] = d_in;
@@ -247,7 +247,7 @@
         phaser->maxsamples] * phaser->decay * -1.0;
                 /* Adjust the output volume and size to 24 bit */
                 d_out = d_in * phaser->out_gain;
-                out = ST_EFF_24BIT_CLIP_COUNT((st_sample_t) d_out);
+                out = ST_24BIT_CLIP_COUNT((st_sample_t) d_out, effp->clippedCount);
                 *obuf++ = out * 256;
                 /* Mix decay of delay and input */
                 phaser->phaserbuf[phaser->counter] = d_in;
--- a/src/pitch.c
+++ b/src/pitch.c
@@ -496,7 +496,7 @@
                 float f;
 
                 f = pitch->acc[pitch->iacc++];
-                ST_EFF_SAMPLE_CLIP_COUNT(f);
+                ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                 obuf[oindex++] = f;
             }
 
@@ -549,7 +549,7 @@
         float f;
 
         f = pitch->acc[pitch->iacc++];
-        ST_EFF_SAMPLE_CLIP_COUNT(f);
+        ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
         obuf[i++] = f;
     }
 
--- a/src/polyphas.c
+++ b/src/polyphas.c
@@ -603,7 +603,7 @@
     {
         float f;
         f = out_buf[k] * ISCALE; /* should clip-limit */
-        ST_EFF_SAMPLE_CLIP_COUNT(f);
+        ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
         *q++ = f;
     }
 
--- a/src/rabbit.c
+++ b/src/rabbit.c
@@ -123,7 +123,7 @@
   }
 
   for (i = 0 ; i < *isamp; i++)
-    r->data->data_in[r->samples + i] = ST_SAMPLE_TO_FLOAT_DWORD(ibuf[i]);
+    r->data->data_in[r->samples + i] = ST_SAMPLE_TO_FLOAT_DWORD(ibuf[i], effp->clippedCount);
 
   r->samples = newsamples;
   r->data->input_frames = r->samples / channels;
@@ -186,7 +186,7 @@
 
   outsamps = min(r->data->output_frames_gen * channels - r->outsamp, *osamp);
   for (i = 0; i < outsamps; i++)
-    obuf[i] = ST_FLOAT_DWORD_TO_SAMPLE(r->data->data_out[r->outsamp + i]);
+    obuf[i] = ST_FLOAT_DWORD_TO_SAMPLE(r->data->data_out[r->outsamp + i], effp->clippedCount);
   *osamp = (st_size_t)outsamps;
   r->outsamp += outsamps;
 
--- a/src/raw.c
+++ b/src/raw.c
@@ -54,10 +54,10 @@
   0x3F, 0xBF, 0x7F, 0xFF
 };
 
-#define ST_ULAW_BYTE_TO_SAMPLE(d) ST_SIGNED_WORD_TO_SAMPLE(st_ulaw2linear16(d))
-#define ST_ALAW_BYTE_TO_SAMPLE(d) ST_SIGNED_WORD_TO_SAMPLE(st_alaw2linear16(d))
-#define ST_SAMPLE_TO_ULAW_BYTE(d) st_14linear2ulaw(ST_SAMPLE_TO_SIGNED_WORD(d) >> 2)
-#define ST_SAMPLE_TO_ALAW_BYTE(d) st_13linear2alaw(ST_SAMPLE_TO_SIGNED_WORD(d) >> 3)
+#define ST_ULAW_BYTE_TO_SAMPLE(d)   ST_SIGNED_WORD_TO_SAMPLE(st_ulaw2linear16(d))
+#define ST_ALAW_BYTE_TO_SAMPLE(d)   ST_SIGNED_WORD_TO_SAMPLE(st_alaw2linear16(d))
+#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) \
@@ -64,10 +64,10 @@
     ST_SIGNED_WORD_TO_SAMPLE(st_ulaw2linear16(cswap[d]))
 #define ST_INVERT_ALAW_BYTE_TO_SAMPLE(d) \
     ST_SIGNED_WORD_TO_SAMPLE(st_alaw2linear16(cswap[d]))
-#define ST_SAMPLE_TO_INVERT_ULAW_BYTE(d) \
-    cswap[st_14linear2ulaw(ST_SAMPLE_TO_SIGNED_WORD(d) >> 2)]
-#define ST_SAMPLE_TO_INVERT_ALAW_BYTE(d) \
-    cswap[st_13linear2alaw(ST_SAMPLE_TO_SIGNED_WORD(d) >> 3)]
+#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);
 
@@ -134,7 +134,7 @@
     return ST_SUCCESS;
 }
 
-void st_ub_read_buf(st_sample_t *buf1, char const * buf2, st_size_t len, char swap)
+void st_ub_read_buf(st_sample_t *buf1, char const * buf2, st_size_t len, char swap, st_size_t * clippedCount)
 {
     while (len)
     {
@@ -148,7 +148,7 @@
     }
 }
 
-void st_sb_read_buf(st_sample_t *buf1, char const * buf2, st_size_t len, char swap)
+void st_sb_read_buf(st_sample_t *buf1, char const * buf2, st_size_t len, char swap, st_size_t * clippedCount)
 {
     while (len)
     {
@@ -162,8 +162,7 @@
     }
 }
 
-void st_ulaw_read_buf(st_sample_t *buf1, char const * buf2, st_size_t len,
-                      char swap)
+void st_ulaw_read_buf(st_sample_t *buf1, char const * buf2, st_size_t len, char swap, st_size_t * clippedCount)
 {
     while (len)
     {
@@ -177,8 +176,7 @@
     }
 }
 
-void st_alaw_read_buf(st_sample_t *buf1, char const * buf2, st_size_t len,
-                      char swap)
+void st_alaw_read_buf(st_sample_t *buf1, char const * buf2, st_size_t len, char swap, st_size_t * clippedCount)
 {
     while (len)
     {
@@ -192,8 +190,7 @@
     }
 }
 
-void st_inv_ulaw_read_buf(st_sample_t *buf1, char const * buf2, st_size_t len,
-                          char swap)
+void st_inv_ulaw_read_buf(st_sample_t *buf1, char const * buf2, st_size_t len, char swap, st_size_t * clippedCount)
 {
     while (len)
     {
@@ -207,8 +204,7 @@
     }
 }
 
-void st_inv_alaw_read_buf(st_sample_t *buf1, char const * buf2, st_size_t len,
-                          char swap)
+void st_inv_alaw_read_buf(st_sample_t *buf1, char const * buf2, st_size_t len, char swap, st_size_t * clippedCount)
 {
     while (len)
     {
@@ -223,7 +219,7 @@
 }
 
 
-void st_uw_read_buf(st_sample_t *buf1, char const * buf2, st_size_t len, char swap)
+void st_uw_read_buf(st_sample_t *buf1, char const * buf2, st_size_t len, char swap, st_size_t * clippedCount)
 {
     while (len)
     {
@@ -239,7 +235,7 @@
     }
 }
 
-void st_sw_read_buf(st_sample_t *buf1, char const * buf2, st_size_t len, char swap)
+void st_sw_read_buf(st_sample_t *buf1, char const * buf2, st_size_t len, char swap, st_size_t * clippedCount)
 {
     while (len)
     {
@@ -275,7 +271,7 @@
 
 
 
-void st_u24_read_buf(st_sample_t * buf1, char const * buf2, st_size_t len, char const swap)
+void st_u24_read_buf(st_sample_t * buf1, char const * buf2, st_size_t len, char const swap, st_size_t * clippedCount)
 {
   while (len--)
   {
@@ -286,7 +282,7 @@
 
 
 
-void st_s24_read_buf(st_sample_t * buf1, char const * buf2, st_size_t len, char const swap)
+void st_s24_read_buf(st_sample_t * buf1, char const * buf2, st_size_t len, char const swap, st_size_t * clippedCount)
 {
   while (len--)
   {
@@ -297,7 +293,7 @@
 
 
 
-void st_udw_read_buf(st_sample_t *buf1, char const * buf2, st_size_t len, char swap)
+void st_udw_read_buf(st_sample_t *buf1, char const * buf2, st_size_t len, char swap, st_size_t * clippedCount)
 {
     while (len)
     {
@@ -313,7 +309,7 @@
     }
 }
 
-void st_dw_read_buf(st_sample_t *buf1, char const * buf2, st_size_t len, char swap)
+void st_dw_read_buf(st_sample_t *buf1, char const * buf2, st_size_t len, char swap, st_size_t * clippedCount)
 {
     while (len)
     {
@@ -329,7 +325,7 @@
     }
 }
 
-void st_f32_read_buf(st_sample_t *buf1, char const * buf2, st_size_t len, char swap)
+void st_f32_read_buf(st_sample_t *buf1, char const * buf2, st_size_t len, char swap, st_size_t * clippedCount)
 {
     while (len)
     {
@@ -340,12 +336,12 @@
         if (swap)
             datum = st_swapf(datum);
 
-        *buf1++ = ST_FLOAT_DWORD_TO_SAMPLE(datum);
+        *buf1++ = ST_FLOAT_DWORD_TO_SAMPLE(datum, *clippedCount);
         len--;
     }
 }
 
-void st_f64_read_buf(st_sample_t *buf1, char const * buf2, st_size_t len, char swap)
+void st_f64_read_buf(st_sample_t *buf1, char const * buf2, st_size_t len, char swap, st_size_t * clippedCount)
 {
     while (len)
     {
@@ -357,7 +353,7 @@
         if (swap)
             datum = st_swapd(datum);
 
-        *buf1++ = ST_FLOAT_DDWORD_TO_SAMPLE(datum);
+        *buf1++ = ST_FLOAT_DDWORD_TO_SAMPLE(datum, *clippedCount);
         len--;
     }
 }
@@ -373,7 +369,7 @@
 st_ssize_t st_rawread(ft_t ft, st_sample_t *buf, st_size_t nsamp)
 {
     st_size_t len, done = 0;
-    void (*read_buf)(st_sample_t *, char const *, st_size_t, char) = 0;
+    void (*read_buf)(st_sample_t *, char const *, st_size_t, char, st_size_t *) = 0;
     size_t i;
 
     if (nsamp < 0)
@@ -478,7 +474,7 @@
     len = min((st_size_t)nsamp,(ft->file.count-ft->file.pos)/ft->info.size);
     if (len)
     {
-        read_buf(buf + done, ft->file.buf + ft->file.pos, len, ft->swap);
+        read_buf(buf + done, ft->file.buf + ft->file.pos, len, ft->swap, &ft->clippedCount);
         ft->file.pos += (len*ft->info.size);
         done += len;
     }
@@ -510,7 +506,7 @@
         len = min((st_size_t)nsamp - done,(ft->file.count-ft->file.pos)/ft->info.size);
         if (len)
         {
-            read_buf(buf + done, ft->file.buf + ft->file.pos, len, ft->swap);
+            read_buf(buf + done, ft->file.buf + ft->file.pos, len, ft->swap, &ft->clippedCount);
             ft->file.pos += (len*ft->info.size);
             done += len;
         }
@@ -531,71 +527,71 @@
         return ST_SUCCESS;
 }
 
-void st_ub_write_buf(char* buf1, st_sample_t const * buf2, st_size_t len, char swap)
+void st_ub_write_buf(char* buf1, st_sample_t const * buf2, st_size_t len, char swap, st_size_t * clippedCount)
 {
     while (len)
     {
-        *(uint8_t *)buf1++ = ST_SAMPLE_TO_UNSIGNED_BYTE(*buf2++);
+        *(uint8_t *)buf1++ = ST_SAMPLE_TO_UNSIGNED_BYTE(*buf2++, *clippedCount);
         len--;
     }
 }
 
-void st_sb_write_buf(char *buf1, st_sample_t const * buf2, st_size_t len, char swap)
+void st_sb_write_buf(char *buf1, st_sample_t const * buf2, st_size_t len, char swap, st_size_t * clippedCount)
 {
     while (len)
     {
-        *(int8_t *)buf1++ = ST_SAMPLE_TO_SIGNED_BYTE(*buf2++);
+        *(int8_t *)buf1++ = ST_SAMPLE_TO_SIGNED_BYTE(*buf2++, *clippedCount);
         len--;
     }
 }
 
 void st_ulaw_write_buf(char *buf1, st_sample_t const * buf2, st_size_t len,
-                       char swap)
+                       char swap, st_size_t * clippedCount)
 {
     while (len)
     {
-        *(uint8_t *)buf1++ = ST_SAMPLE_TO_ULAW_BYTE(*buf2++);
+        *(uint8_t *)buf1++ = ST_SAMPLE_TO_ULAW_BYTE(*buf2++, *clippedCount);
         len--;
     }
 }
 
 void st_alaw_write_buf(char *buf1, st_sample_t const * buf2, st_size_t len,
-                       char swap)
+                       char swap, st_size_t * clippedCount)
 {
     while (len)
     {
-        *(uint8_t *)buf1++ = ST_SAMPLE_TO_ALAW_BYTE(*buf2++);
+        *(uint8_t *)buf1++ = ST_SAMPLE_TO_ALAW_BYTE(*buf2++, *clippedCount);
         len--;
     }
 }
 
 void st_inv_ulaw_write_buf(char *buf1, st_sample_t const * buf2, st_size_t len,
-                           char swap)
+                           char swap, st_size_t * clippedCount)
 {
     while (len)
     {
-        *(uint8_t *)buf1++ = ST_SAMPLE_TO_INVERT_ULAW_BYTE(*buf2++);
+        *(uint8_t *)buf1++ = ST_SAMPLE_TO_INVERT_ULAW_BYTE(*buf2++, *clippedCount);
         len--;
     }
 }
 
 void st_inv_alaw_write_buf(char *buf1, st_sample_t const * buf2, st_size_t len,
-                           char swap)
+                           char swap, st_size_t * clippedCount)
 {
     while (len)
     {
-        *(uint8_t *)buf1++ = ST_SAMPLE_TO_INVERT_ALAW_BYTE(*buf2++);
+        *(uint8_t *)buf1++ = ST_SAMPLE_TO_INVERT_ALAW_BYTE(*buf2++, *clippedCount);
         len--;
     }
 }
 
-void st_uw_write_buf(char *buf1, st_sample_t const * buf2, st_size_t len, char swap)
+void st_uw_write_buf(char *buf1, st_sample_t const * buf2, st_size_t len, char swap, st_size_t * clippedCount)
 {
     while (len)
     {
         uint16_t datum;
 
-        datum = ST_SAMPLE_TO_UNSIGNED_WORD(*buf2++);
+        datum = ST_SAMPLE_TO_UNSIGNED_WORD(*buf2++, *clippedCount);
         if (swap)
             datum = st_swapw(datum);
         *(uint16_t *)buf1 = datum;
@@ -605,13 +601,13 @@
     }
 }
 
-void st_sw_write_buf(char *buf1, st_sample_t const * buf2, st_size_t len, char swap)
+void st_sw_write_buf(char *buf1, st_sample_t const * buf2, st_size_t len, char swap, st_size_t * clippedCount)
 {
     while (len)
     {
         int16_t datum;
 
-        datum = ST_SAMPLE_TO_SIGNED_WORD(*buf2++);
+        datum = ST_SAMPLE_TO_SIGNED_WORD(*buf2++, *clippedCount);
         if (swap)
             datum = st_swapw(datum);
         *(int16_t *)buf1 = datum;
@@ -643,11 +639,11 @@
 
 
 
-void st_u24_write_buf(char * buf1, st_sample_t const * buf2, st_size_t len, char const swap)
+void st_u24_write_buf(char * buf1, st_sample_t const * buf2, st_size_t len, char const swap, st_size_t * clippedCount)
 {
   while (len--)
   {
-    int24_t datum = ST_SAMPLE_TO_UNSIGNED_24BIT(*buf2++);
+    int24_t datum = ST_SAMPLE_TO_UNSIGNED_24BIT(*buf2++, *clippedCount);
     st_24_write_one(&buf1, datum, swap);
   }
 }
@@ -654,11 +650,11 @@
 
 
 
-void st_s24_write_buf(char * buf1, st_sample_t const * buf2, st_size_t len, char const swap)
+void st_s24_write_buf(char * buf1, st_sample_t const * buf2, st_size_t len, char const swap, st_size_t * clippedCount)
 {
   while (len--)
   {
-    int24_t datum = ST_SAMPLE_TO_SIGNED_24BIT(*buf2++);
+    int24_t datum = ST_SAMPLE_TO_SIGNED_24BIT(*buf2++, *clippedCount);
     st_24_write_one(&buf1, datum, swap);
   }
 }
@@ -665,7 +661,7 @@
 
 
 
-void st_udw_write_buf(char *buf1, st_sample_t const * buf2, st_size_t len, char swap)
+void st_udw_write_buf(char *buf1, st_sample_t const * buf2, st_size_t len, char swap, st_size_t * clippedCount)
 {
     while (len)
     {
@@ -681,7 +677,7 @@
     }
 }
 
-void st_dw_write_buf(char *buf1, st_sample_t const * buf2, st_size_t len, char swap)
+void st_dw_write_buf(char *buf1, st_sample_t const * buf2, st_size_t len, char swap, st_size_t * clippedCount)
 {
     while (len)
     {
@@ -697,13 +693,13 @@
     }
 }
 
-void st_f32_write_buf(char *buf1, st_sample_t const * buf2, st_size_t len, char swap)
+void st_f32_write_buf(char *buf1, st_sample_t const * buf2, st_size_t len, char swap, st_size_t * clippedCount)
 {
     while (len)
     {
         float datum;
 
-        datum = ST_SAMPLE_TO_FLOAT_DWORD(*buf2++);
+        datum = ST_SAMPLE_TO_FLOAT_DWORD(*buf2++, *clippedCount);
         if (swap)
             datum = st_swapf(datum);
         *(float *)buf1 = datum;
@@ -713,13 +709,13 @@
     }
 }
 
-void st_f64_write_buf(char *buf1, st_sample_t const * buf2, st_size_t len, char swap)
+void st_f64_write_buf(char *buf1, st_sample_t const * buf2, st_size_t len, char swap, st_size_t * clippedCount)
 {
     while (len)
     {
         double datum;
 
-        datum = ST_SAMPLE_TO_FLOAT_DDWORD(*buf2++);
+        datum = ST_SAMPLE_TO_FLOAT_DDWORD(*buf2++, *clippedCount);
         if (swap)
             datum = st_swapf(datum);
         *(double *)buf1 = datum;
@@ -751,7 +747,7 @@
 st_ssize_t st_rawwrite(ft_t ft, const st_sample_t *buf, st_size_t nsamp)
 {
     st_size_t len, done = 0;
-    void (*write_buf)(char *, st_sample_t const *, st_size_t, char) = 0;
+    void (*write_buf)(char *, st_sample_t const *, st_size_t, char, st_size_t *) = 0;
 
     switch(ft->info.size) {
         case ST_SIZE_BYTE:
@@ -856,7 +852,7 @@
         len = min(nsamp-done,(ft->file.size-ft->file.pos)/ft->info.size);
         if (len)
         {
-            write_buf(ft->file.buf + ft->file.pos, buf+done, len, ft->swap);
+            write_buf(ft->file.buf + ft->file.pos, buf+done, len, ft->swap, &ft->clippedCount);
             ft->file.pos += (len*ft->info.size);
             done += len;
         }
--- a/src/resample.c
+++ b/src/resample.c
@@ -401,7 +401,7 @@
                 // orig: *obuf++ = r->Y[i] * ISCALE;
                 double ftemp = r->Y[i] * ISCALE;
 
-                ST_EFF_SAMPLE_CLIP_COUNT(ftemp);
+                ST_SAMPLE_CLIP_COUNT(ftemp, effp->clippedCount);
                 *obuf++ = ftemp;
         }
 
--- a/src/reverb.c
+++ b/src/reverb.c
@@ -229,7 +229,7 @@
                         d_in +=
 reverb->reverbbuf[(i + reverb->maxsamples - reverb->samples[j]) % reverb->maxsamples] * reverb->decay[j];
                 d_out = d_in * reverb->out_gain;
-                out = ST_EFF_24BIT_CLIP_COUNT((st_sample_t) d_out);
+                out = ST_24BIT_CLIP_COUNT((st_sample_t) d_out, effp->clippedCount);
                 *obuf++ = out * 256;
                 reverb->reverbbuf[i] = d_in;
                 i++;            /* XXX need a % maxsamples here ? */
@@ -261,10 +261,10 @@
                         d_in += 
 reverb->reverbbuf[(i + reverb->maxsamples - reverb->samples[j]) % reverb->maxsamples] * reverb->decay[j];
                 d_out = d_in * reverb->out_gain;
-                out = ST_EFF_24BIT_CLIP_COUNT((st_sample_t) d_out);
+                out = ST_24BIT_CLIP_COUNT((st_sample_t) d_out, effp->clippedCount);
                 obuf[done++] = out * 256;
                 reverb->reverbbuf[i] = d_in;
-                l = ST_EFF_24BIT_CLIP_COUNT((st_sample_t) d_in);
+                l = ST_24BIT_CLIP_COUNT((st_sample_t) d_in, effp->clippedCount);
                 reverb->pppl = reverb->ppl;
                 reverb->ppl = reverb->pl;
                 reverb->pl = l;
--- a/src/silence.c
+++ b/src/silence.c
@@ -325,6 +325,7 @@
 {
     double ratio;
     int rc;
+    st_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 */
@@ -331,12 +332,16 @@
     switch(effp->ininfo.size)
     {
         case ST_SIZE_BYTE:
-            value = ST_SAMPLE_TO_SIGNED_BYTE(value);
+            value = ST_SAMPLE_TO_SIGNED_BYTE(value, dummy_clipped_count);
             ratio = (double)abs(value) / (double)ST_INT8_MAX;
             break;
         case ST_SIZE_WORD:
-            value = ST_SAMPLE_TO_SIGNED_WORD(value);
+            value = ST_SAMPLE_TO_SIGNED_WORD(value, dummy_clipped_count);
             ratio = (double)abs(value) / (double)ST_INT16_MAX;
+            break;
+        case ST_SIZE_24BIT:
+            value = ST_SAMPLE_TO_SIGNED_24BIT(value, dummy_clipped_count);
+            ratio = (double)abs(value) / (double)ST_INT24_MAX;
             break;
         case ST_SIZE_DWORD:
             value = ST_SAMPLE_TO_SIGNED_DWORD(value);
--- a/src/skel.c
+++ b/src/skel.c
@@ -158,7 +158,7 @@
                 case ST_ENCODING_UNSIGNED:
                     while(len--)
                     {
-                        len = st_writeb(ft, ST_SAMPLE_TO_UNSIGNED_BYTE(*buff++));
+                        len = st_writeb(ft, ST_SAMPLE_TO_UNSIGNED_BYTE(*buff++, ft->clippedCount));
                         if (len == ST_EOF)
                             break;
                     }
--- a/src/smp.c
+++ b/src/smp.c
@@ -397,7 +397,7 @@
         st_ssize_t done = 0;
 
         while(done < len) {
-                datum = (int) ST_SAMPLE_TO_SIGNED_WORD(*buf++);
+                datum = (int) ST_SAMPLE_TO_SIGNED_WORD(*buf++, ft->clippedCount);
                 st_writew(ft, datum);
                 smp->NoOfSamps++;
                 done++;
--- a/src/sox.c
+++ b/src/sox.c
@@ -938,12 +938,17 @@
         {
           /* We no longer have any info about this file as we've just
            * st_close'd it, so just refer to file number: */
-          st_warn("Input file # %i reported an error whilst it was being closed.", f);
+          st_warn("Input file # %i reported an error whilst it was being closed.", f + 1);
         }
     }
 
     if (writing)
     {
+        if (file_desc[f]->clippedCount != 0)
+        {
+          st_warn("%s: %u values clipped on output", file_desc[f]->filename, file_desc[f]->clippedCount);
+        }
+
         /* problem closing output file, just warn user since we
          * are exiting anyways.
          */
--- a/src/speed.c
+++ b/src/speed.c
@@ -173,7 +173,7 @@
         f = cub(speed->cbuf[0], speed->cbuf[1],
                 speed->cbuf[2], speed->cbuf[3], 
                 speed->frac);
-        ST_EFF_SAMPLE_CLIP_COUNT(f);
+        ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
         obuf[i] = f;
     }
     
--- a/src/st.h
+++ b/src/st.h
@@ -15,6 +15,10 @@
 #include <stdlib.h>
 #include "ststdint.h"
 
+#ifndef __GNUC__
+#  define  __attribute__(x)  /*NOTHING*/
+#endif
+
 /* C language enhancements: */
 
 /* Boolean type, compatible with C++ */
@@ -37,43 +41,88 @@
 /* Array-length operator */
 #define array_length(a) (sizeof(a)/sizeof(a[0]))
 
-typedef int32_t st_sample_t;
-typedef uint32_t st_size_t;
-typedef int32_t st_ssize_t;
-typedef uint32_t st_rate_t;
+typedef int32_t int24_t;     /* But beware of the extra byte. */
+typedef uint32_t uint24_t;   /* ditto */
 
-typedef int32_t int24_t;
-typedef uint32_t uint24_t;
+#define ST_INT_MIN(bits) (1L <<((bits)-1))
+#define ST_INT_MAX(bits) (-1UL>>(33-(bits)))
+#define ST_UINT_MAX(bits) (ST_INT_MIN(bits)|ST_INT_MAX(bits))
 
+#define ST_INT8_MAX  ST_INT_MAX(8)
+#define ST_INT16_MAX ST_INT_MAX(16)
+#define ST_INT24_MAX ST_INT_MAX(24)
+#define ST_INT32_MAX ST_INT_MAX(32)
+#define ST_INT64_MAX 0x7fffffffffffffffLL /* Not in use yet */
+
+typedef int32_t st_sample_t;
 /* Minimum and maximum values a sample can hold. */
-#define ST_SAMPLE_MAX 2147483647L
-#define ST_SAMPLE_MIN (-ST_SAMPLE_MAX - 1L)
-#define ST_SAMPLE_FLOAT_SCALE 2147483648.0
+#define ST_SAMPLE_MAX (st_sample_t)ST_INT_MAX(32)
+#define ST_SAMPLE_MIN (st_sample_t)ST_INT_MIN(32)
 
-#define ST_UNSIGNED_BYTE_TO_SAMPLE(d) ((st_sample_t)((d) ^ 0x80) << 24)
-#define ST_SIGNED_BYTE_TO_SAMPLE(d) ((st_sample_t)(d) << 24)
-#define ST_UNSIGNED_WORD_TO_SAMPLE(d) ((st_sample_t)((d) ^ 0x8000) << 16)
-#define ST_SIGNED_WORD_TO_SAMPLE(d) ((st_sample_t)(d) << 16)
-#define ST_UNSIGNED_24BIT_TO_SAMPLE(d) ((st_sample_t)((d) ^ 0x800000L) << 8)
-#define ST_SIGNED_24BIT_TO_SAMPLE(d) ((st_sample_t)(d) << 8)
-#define ST_UNSIGNED_DWORD_TO_SAMPLE(d) ((st_sample_t)((d) ^ 0x80000000L))
-#define ST_SIGNED_DWORD_TO_SAMPLE(d) ((st_sample_t)d)
-#define ST_FLOAT_DWORD_TO_SAMPLE(d) (d==1? ST_SAMPLE_MAX : (st_sample_t)(d*ST_SAMPLE_FLOAT_SCALE))
-#define ST_FLOAT_DDWORD_TO_SAMPLE ST_FLOAT_DWORD_TO_SAMPLE
-#define ST_SAMPLE_TO_UNSIGNED_BYTE(d) ((uint8_t)((d) >> 24) ^ 0x80)
-#define ST_SAMPLE_TO_SIGNED_BYTE(d) ((int8_t)((d) >> 24))
-#define ST_SAMPLE_TO_UNSIGNED_WORD(d) ((uint16_t)((d) >> 16) ^ 0x8000)
-#define ST_SAMPLE_TO_SIGNED_WORD(d) ((int16_t)((d) >> 16))
-#define ST_SAMPLE_TO_UNSIGNED_24BIT(d) ((uint24_t)((d) >> 8) ^ 0x800000L)
-#define ST_SAMPLE_TO_SIGNED_24BIT(d) ((int24_t)((d) >> 8))
-#define ST_SAMPLE_TO_UNSIGNED_DWORD(d) ((uint32_t)(d) ^ 0x80000000L)
-#define ST_SAMPLE_TO_SIGNED_DWORD(d) ((int32_t)(d))
-/* FIXME: This is an approximation because its impossible to
- * to reach 1.
+
+
+/*                Conversions: Linear PCM <--> st_sample_t
+ *
+ *   I/O       I/O     st_sample_t  Clips?    I/O     st_sample_t  Clips? 
+ *  Format   Minimum     Minimum     I O    Maximum     Maximum     I O      
+ *  ------  ---------  ------------ -- --   --------  ------------ -- --  
+ *  Float      -1     -1.00000000047 y y       1           1        y n         
+ *  Byte      -128        -128       n n      127     127.9999999   n y   
+ *  Word     -32768      -32768      n n     32767    32767.99998   n y   
+ *  24bit   -8388608    -8388608     n n    8388607   8388607.996   n y   
+ *  Dword  -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.
+ *
+ * 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 ST_SAMPLE_TO_FLOAT_DWORD(d) ((float)(d/(ST_SAMPLE_FLOAT_SCALE)))
-#define ST_SAMPLE_TO_FLOAT_DDWORD(d) ((double)((double)d/(ST_SAMPLE_FLOAT_SCALE)))
 
+/* Temporary variables to prevent multiple evaluation of macro arguments: */
+static st_sample_t st_macro_temp_sample __attribute__((unused));
+static double st_macro_temp_double __attribute__((unused));
+
+#define ST_SAMPLE_NEG ST_INT_MIN(32)
+#define ST_SAMPLE_TO_UNSIGNED(bits,d,clips) \
+  (uint##bits##_t)( \
+    st_macro_temp_sample=d, \
+    st_macro_temp_sample>(st_sample_t)(ST_SAMPLE_MAX-(1UL<<(31-bits)))? \
+      ++(clips),ST_UINT_MAX(bits): \
+      ((uint32_t)(st_macro_temp_sample^ST_SAMPLE_NEG)+(1UL<<(31-bits)))>>(32-bits))
+#define ST_SAMPLE_TO_SIGNED(bits,d,clips) \
+  (int##bits##_t)(ST_SAMPLE_TO_UNSIGNED(bits,d,clips)^ST_INT_MIN(bits))
+#define ST_SIGNED_TO_SAMPLE(bits,d)((st_sample_t)(d)<<(32-bits))
+#define ST_UNSIGNED_TO_SAMPLE(bits,d)(ST_SIGNED_TO_SAMPLE(bits,d)^ST_SAMPLE_NEG)
+
+#define ST_UNSIGNED_BYTE_TO_SAMPLE(d) ST_UNSIGNED_TO_SAMPLE(8,d)
+#define ST_SIGNED_BYTE_TO_SAMPLE(d) ST_SIGNED_TO_SAMPLE(8,d)
+#define ST_UNSIGNED_WORD_TO_SAMPLE(d) ST_UNSIGNED_TO_SAMPLE(16,d)
+#define ST_SIGNED_WORD_TO_SAMPLE(d) ST_SIGNED_TO_SAMPLE(16,d)
+#define ST_UNSIGNED_24BIT_TO_SAMPLE(d) ST_UNSIGNED_TO_SAMPLE(24,d)
+#define ST_SIGNED_24BIT_TO_SAMPLE(d) ST_SIGNED_TO_SAMPLE(24,d)
+#define ST_UNSIGNED_DWORD_TO_SAMPLE(d) (st_sample_t)((d)^ST_SAMPLE_NEG)
+#define ST_SIGNED_DWORD_TO_SAMPLE(d) (st_sample_t)(d)
+#define ST_FLOAT_DWORD_TO_SAMPLE ST_FLOAT_DDWORD_TO_SAMPLE
+#define ST_FLOAT_DDWORD_TO_SAMPLE(d,clips) (st_macro_temp_double=d,st_macro_temp_double<-1?++(clips),(-ST_SAMPLE_MAX):st_macro_temp_double>1?++(clips),ST_SAMPLE_MAX:(st_sample_t)((uint32_t)((double)(st_macro_temp_double)*ST_SAMPLE_MAX+(ST_SAMPLE_MAX+.5))-ST_SAMPLE_MAX))
+#define ST_SAMPLE_TO_UNSIGNED_BYTE(d,clips) ST_SAMPLE_TO_UNSIGNED(8,d,clips)
+#define ST_SAMPLE_TO_SIGNED_BYTE(d,clips) ST_SAMPLE_TO_SIGNED(8,d,clips)
+#define ST_SAMPLE_TO_UNSIGNED_WORD(d,clips) ST_SAMPLE_TO_UNSIGNED(16,d,clips)
+#define ST_SAMPLE_TO_SIGNED_WORD(d,clips) ST_SAMPLE_TO_SIGNED(16,d,clips)
+#define ST_SAMPLE_TO_UNSIGNED_24BIT(d,clips) ST_SAMPLE_TO_UNSIGNED(24,d,clips)
+#define ST_SAMPLE_TO_SIGNED_24BIT(d,clips) ST_SAMPLE_TO_SIGNED(24,d,clips)
+#define ST_SAMPLE_TO_UNSIGNED_DWORD(d) (uint32_t)((d)^ST_SAMPLE_NEG)
+#define ST_SAMPLE_TO_SIGNED_DWORD(d) (int32_t)(d)
+#define ST_SAMPLE_TO_FLOAT_DWORD (float)ST_SAMPLE_TO_FLOAT_DDWORD
+#define ST_SAMPLE_TO_FLOAT_DDWORD(d,clips) (st_macro_temp_sample=d,st_macro_temp_sample==ST_SAMPLE_MIN?++(clips),-1.0:((double)(st_macro_temp_sample)*(1.0/ST_SAMPLE_MAX)))
+
+
+
 /* MACRO to clip a data type that is greater then st_sample_t to
  * st_sample_t's limits and increment a counter if clipping occurs..
  */
@@ -99,29 +148,22 @@
   ((l) >= ((st_sample_t)1 << 23)? ++(clips), ((st_sample_t)1 << 23) - 1 : \
    (l) <=-((st_sample_t)1 << 23)? ++(clips),-((st_sample_t)1 << 23) + 1 : (l))
 
-/* MACRO to clip a normalized floating point data between 1.0 and -1.0
- * to those limits and increment a counter when clipping occurs.
- */
-#define ST_NORMALIZED_CLIP_COUNT(samp, clips) \
-  do { \
-    if (samp > 1) \
-      { samp = 1; clips++; } \
-    else if (samp < -1) \
-      { samp = -1; clips++; } \
-  } while (0)
 
-/* MACROs for effects where standard clip counting and reporting is used. */
-#define ST_EFF_SAMPLE_CLIP_COUNT(s) ST_SAMPLE_CLIP_COUNT(s, effp->clippedCount)
-#define ST_EFF_24BIT_CLIP_COUNT(s) ST_24BIT_CLIP_COUNT(s, effp->clippedCount)
-#define ST_EFF_ROUND_CLIP_COUNT(s) ST_ROUND_CLIP_COUNT(s, effp->clippedCount)
-#define ST_EFF_NORMALIZED_CLIP_COUNT(s) ST_NORMALIZED_CLIP_COUNT(s, effp->clippedCount)
 
+typedef uint32_t st_size_t;
 /* Maximum value size type can hold. (Minimum is 0). */
 #define ST_SIZE_MAX 0xffffffffL
 
+typedef int32_t st_ssize_t;
 /* Minimum and maximum value signed size type can hold. */
 #define ST_SSIZE_MAX 0x7fffffffL
 #define ST_SSIZE_MIN (-ST_SSIZE_MAX - 1L)
+
+typedef uint32_t st_rate_t;
+/* Warning, this is a MAX value used in the library.  Each format and
+ * effect may have its own limitations of rate.
+ */
+#define ST_MAXRATE      (50UL * 1024) /* maximum sample rate in library */
 
 typedef enum {
   ST_ENCODING_UNKNOWN   ,
--- a/src/st_i.h
+++ b/src/st_i.h
@@ -42,6 +42,7 @@
 
 #ifndef HAVE_STRCASECMP
 int strcasecmp(const char *s1, const char *s2);
+int strncasecmp(char const * s1, char const * s2, size_t n);
 #endif
 
 #ifndef HAVE_STRDUP
@@ -124,11 +125,6 @@
 #define ST_IS_LITTLEENDIAN 1
 #endif
 
-/* Warning, this is a MAX value used in the library.  Each format and
- * effect may have its own limitations of rate.
- */
-#define ST_MAXRATE      50L * 1024 /* maximum sample rate in library */
-
 #ifndef M_PI
 #define M_PI    3.14159265358979323846
 #endif
@@ -135,11 +131,6 @@
 #ifndef M_PI_2
 #define M_PI_2  1.57079632679489661923  /* pi/2 */
 #endif
-
-#define ST_INT8_MAX (127)
-#define ST_INT16_MAX (32676)
-#define ST_INT32_MAX (2147483647)
-#define ST_INT64_MAX (9223372036854775807)
 
 /* The following is used at times in libst when alloc()ing buffers
  * to perform file I/O.  It can be useful to pass in similar sized
--- a/src/stat.c
+++ b/src/stat.c
@@ -170,7 +170,7 @@
         {
             for (x = 0; x < len; x++)
             {
-                stat->re_in[stat->fft_offset++] = ST_SAMPLE_TO_FLOAT_DWORD(ibuf[x]);
+                stat->re_in[stat->fft_offset++] = ST_SAMPLE_TO_FLOAT_DWORD(ibuf[x], effp->clippedCount);
 
                 if (stat->fft_offset >= stat->fft_size)
                 {
--- a/src/stretch.c
+++ b/src/stretch.c
@@ -321,7 +321,7 @@
             {
                 float f;
                 f = stretch->obuf[stretch->oindex++];
-                ST_EFF_SAMPLE_CLIP_COUNT(f);
+                ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
                 obuf[oindex++] = f;
             }
 
@@ -376,7 +376,7 @@
         float f;
 
         f = stretch->obuf[stretch->oindex++];
-        ST_EFF_SAMPLE_CLIP_COUNT(f);
+        ST_SAMPLE_CLIP_COUNT(f, effp->clippedCount);
         obuf[oindex++] = f;
     }
     
--- a/src/synth.c
+++ b/src/synth.c
@@ -270,7 +270,6 @@
     /* set default parameters */
     synth->length = 0; /* use length of input file */
     synth->length_str = 0;
-    synth->max = ST_SAMPLE_MAX;
     for(c=0;c<MAXCHAN;c++){
         synth->freq[c] = 440.0;
         synth->freq2[c] = 440.0;
@@ -398,6 +397,9 @@
     int i;
     int c;
     synth_t synth = (synth_t) effp->priv;
+    int shift_for_max = (4 - min(effp->outinfo.size, 4)) << 3;
+
+    synth->max = (ST_SAMPLE_MAX >> shift_for_max) << shift_for_max;
 
     st_initrand();
 
--- a/src/tests.sh
+++ b/src/tests.sh
@@ -1,8 +1,8 @@
 #!/bin/sh
 #
-# SOX Regression Test script.
+# SoX Regression Test script.
 #
-# This script is just a quick sanity check of SOX on lossless format conversions.
+# This script is just a quick sanity check of SoX on lossless format conversions.
 
 # verbose options
 #verbose=-V
@@ -18,6 +18,7 @@
     ub ) formatText="unsigned byte" ;;
     uw ) formatText="unsigned word" ;;
     raw) formatText="float"; formatFlags="-f -l" ;;
+    Raw) formatText="double"; formatFlags="-f -8" ;;
     au ) formatFlags="-s" ;;
     Wav) formatFlags="-u -b" ;;
   esac
@@ -27,14 +28,14 @@
   while [ $# != 0 ]; do
     getFormat $format1; format1Text=$formatText; format1Flags=$formatFlags
     getFormat       $1; format2Text=$formatText; format2Flags=$formatFlags
-    ./sox $verbose -r $rate monkey.au $format1Flags input.$format1
-    ./sox $verbose -r $rate -c 1 $format1Flags input.$format1 $format2Flags intermediate.$1
-    ./sox $verbose -r $rate -c 1 $format2Flags intermediate.$1 $format1Flags output.$format1
+    ./sox -c $channels -r $rate -n $format1Flags input.$format1 synth $samples's' sin 300-3300 noise
+    ./sox $verbose -r $rate -c $channels $format1Flags input.$format1 $format2Flags intermediate.$1
+    ./sox $verbose -r $rate -c $channels $format2Flags intermediate.$1 $format1Flags output.$format1
     if cmp -s input.$format1 output.$format1
     then
-      echo "ok     convert \"$format1Text\" <--> \"$format2Text\"."
+      echo "ok     channels=$channels \"$format1Text\" <--> \"$format2Text\"."
     else
-      echo "*FAIL* convert \"$format1Text\" <--> \"$format2Text\"."
+      echo "*FAIL* channels=$channels \"$format1Text\" <--> \"$format2Text\"."
       exit 1    # This allows failure inspection.
     fi
     rm -f input.$format1 intermediate.$1 output.$format1
@@ -42,31 +43,45 @@
   done
 }
 
-format1=ub
-rate=8012
-convertToAndFrom sb ub sw uw s3 u3 sl u4 raw dat au wav aiff aifc flac al
+do_multichannel_formats () {
+  format1=ub
+  convertToAndFrom sb ub sw uw s3 u3 sl u4 raw Raw dat au wav aiff aifc flac
 
-format1=sw
-convertToAndFrom sw uw s3 u3 sl u4 raw au wav aiff aifc flac ul
+  format1=sw
+  convertToAndFrom sw uw s3 u3 sl u4 raw Raw dat au wav aiff aifc flac
 
-format1=u3
-convertToAndFrom s3 u3 sl u4 wav flac
+  format1=u3
+  convertToAndFrom s3 u3 sl u4 raw Raw wav aiff aifc flac
 
-format1=sl
-convertToAndFrom sl u4 wav
+  format1=sl
+  convertToAndFrom sl u4 Raw wav
 
-format1=al
-convertToAndFrom al sw uw sl raw dat
+  format1=al
+  convertToAndFrom al sw uw sl raw Raw dat
 
-format1=ul
-convertToAndFrom ul sw uw sl raw dat
+  format1=ul
+  convertToAndFrom ul sw uw sl raw Raw dat
 
-format1=Wav
-convertToAndFrom Wav 8svx aiff aifc au avr dat maud sf smp
-rate=5512
-convertToAndFrom hcom
-rate=8000
-convertToAndFrom voc wve flac
+  format1=Wav
+  convertToAndFrom Wav aiff aifc au avr dat maud sf flac
+  samples=23492 convertToAndFrom 8svx  # Even number of samples only
+  rate=8000 convertToAndFrom voc       # Fixed rate
+
+  format1=wve
+  convertToAndFrom al sw uw sl raw Raw dat
+}
+
+do_singlechannel_formats () {
+  format1=Wav
+  convertToAndFrom smp
+  rate=5512 convertToAndFrom hcom      # Fixed rate
+}
+
+rate=44100
+samples=23493
+channels=2 do_multichannel_formats
+channels=1 do_multichannel_formats
+channels=1 do_singlechannel_formats
 
 ./sox -c 1 -n output.ub synth .01 sine
 if [ `wc -c <output.ub` = 441 ]; then
--- a/src/voc.c
+++ b/src/voc.c
@@ -481,10 +481,10 @@
         v->samples += len;
         while(done < len) {
           if (ft->info.size == ST_SIZE_BYTE) {
-            uc = ST_SAMPLE_TO_UNSIGNED_BYTE(*buf++);
+            uc = ST_SAMPLE_TO_UNSIGNED_BYTE(*buf++, ft->clippedCount);
             st_writeb(ft, uc);
           } else {
-            sw = (int) ST_SAMPLE_TO_SIGNED_WORD(*buf++);
+            sw = (int) ST_SAMPLE_TO_SIGNED_WORD(*buf++, ft->clippedCount);
             st_writew(ft,sw);
           }
           done++;
--- a/src/vox.c
+++ b/src/vox.c
@@ -275,7 +275,7 @@
              short    word;
 
              while (count < length)
-                   { word   = ST_SAMPLE_TO_SIGNED_WORD (*buffer++);
+                   { word   = ST_SAMPLE_TO_SIGNED_WORD (*buffer++, ft->clippedCount);
                      word  /= 16;
 
                      byte <<= 4;
--- a/src/wav.c
+++ b/src/wav.c
@@ -349,7 +349,7 @@
     while (done < len) {
         while ((wav->gsmindex < 160*2) && (done < len))
             wav->gsmsample[(wav->gsmindex)++] = 
-                ST_SAMPLE_TO_SIGNED_WORD(buf[done++]);
+                ST_SAMPLE_TO_SIGNED_WORD(buf[done++], ft->clippedCount);
 
         if (wav->gsmindex < 160*2)
             break;