shithub: sox

Download patch

ref: ff89831f6f212180a15d1dfca0e95c8a31e91b8a
parent: 48282e9cf5e3ed139bdf5b355213d22623e6c300
author: robs <robs>
date: Sun Jun 10 13:48:43 EDT 2007

Peter Samuelson's rabbit streaming support.
Fix a couple of bugs in the effects chain.
A few clean-ups.

--- a/src/biquad.c
+++ b/src/biquad.c
@@ -44,10 +44,8 @@
       (n > fc_pos    && (sscanf(argv[fc_pos], "%lf %c", &p->fc, &dummy) != 1 || p->fc <= 0)) ||
       (n > width_pos && ((unsigned)(sscanf(argv[width_pos], "%lf%c %c", &p->width, &width_type, &dummy)-1) > 1 || p->width <= 0)) ||
       (n > gain_pos  && sscanf(argv[gain_pos], "%lf %c", &p->gain, &dummy) != 1) ||
-      !strchr(allowed_width_types, width_type) || (width_type == 's' && p->width > 1)) {
-    sox_fail(effp->handler.usage);
-    return SOX_EOF;
-  }
+      !strchr(allowed_width_types, width_type) || (width_type == 's' && p->width > 1))
+    return sox_usage(effp);
   p->width_type = strchr(all_width_types, width_type) - all_width_types;
   if (p->width_type >= strlen(all_width_types))
     p->width_type = 0;
--- a/src/biquads.c
+++ b/src/biquads.c
@@ -314,7 +314,7 @@
 #define BIQUAD_EFFECT(name,group,usage,flags) \
 sox_effect_handler_t const * sox_##name##_effect_fn(void) { \
   static sox_effect_handler_t handler = { \
-    #name, "Usage: " #name " " usage, flags, \
+    #name, usage, flags, \
     group##_getopts, start, sox_biquad_flow, 0, 0, 0, \
   }; \
   return &handler; \
@@ -331,4 +331,4 @@
 BIQUAD_EFFECT(treble,    tone,     "gain [frequency [width[s|h|q|o]]]", 0)
 BIQUAD_EFFECT(equalizer, equalizer,"frequency width[q|o|h] gain", 0)
 BIQUAD_EFFECT(band,      band,     "[-n] center [width[h|q|o]]", 0)
-BIQUAD_EFFECT(deemph,    deemph,   "takes no options", 0)
+BIQUAD_EFFECT(deemph,    deemph,   NULL, 0)
--- a/src/chorus.c
+++ b/src/chorus.c
@@ -99,10 +99,7 @@
         i = 0;
 
         if ( ( n < 7 ) || (( n - 2 ) % 5 ) )
-        {
-            sox_fail(effp->handler.usage);
-            return (SOX_EOF);
-        }
+          return sox_usage(effp);
 
         sscanf(argv[i++], "%f", &chorus->in_gain);
         sscanf(argv[i++], "%f", &chorus->out_gain);
@@ -121,10 +118,7 @@
                 else if ( ! strcmp(argv[i], "-t"))
                         chorus->modulation[chorus->num_chorus] = MOD_TRIANGLE;
                 else
-                {
-                        sox_fail(effp->handler.usage);
-                        return (SOX_EOF);
-                }
+                  return sox_usage(effp);
                 i++;
                 chorus->num_chorus++;
         }
@@ -338,7 +332,7 @@
 
 static sox_effect_handler_t sox_chorus_effect = {
   "chorus",
-  "Usage: chorus gain-in gain-out delay decay speed depth [ -s | -t ]",
+  "gain-in gain-out delay decay speed depth [ -s | -t ]",
   SOX_EFF_LENGTH,
   sox_chorus_getopts,
   sox_chorus_start,
--- a/src/compand.c
+++ b/src/compand.c
@@ -33,7 +33,7 @@
  *                  -------
  */
 #define compand_usage \
-  "Usage: compand attack1,decay1{,attack2,decay2} [soft-knee-dB:]in-dB1[,out-dB1]{,in-dB2,out-dB2} [gain [initial-volume-dB [delay]]]\n" \
+  "attack1,decay1{,attack2,decay2} [soft-knee-dB:]in-dB1[,out-dB1]{,in-dB2,out-dB2} [gain [initial-volume-dB [delay]]]\n" \
   "\twhere {} means optional and repeatable and [] means optional.\n" \
   "\tdB values are floating point or -inf'; times are in seconds."
 /*
@@ -66,10 +66,8 @@
   char dummy;     /* To check for extraneous chars. */
   unsigned pairs, i, j, commas;
 
-  if (n < 2 || n > 5) {
-    sox_fail(effp->handler.usage);
-    return SOX_EOF;
-  }
+  if (n < 2 || n > 5)
+    return sox_usage(effp);
 
   /* Start by checking the attack and decay rates */
   for (s = argv[0], commas = 0; *s; ++s) if (*s == ',') ++commas;
@@ -131,7 +129,6 @@
   compand_t l = (compand_t) effp->priv;
   unsigned i, j;
 
-  sox_debug("Starting compand effect; rate %i", effp->outinfo.rate);
   sox_debug("%i input channel(s) expected: actually %i",
       l->expectedChannels, effp->outinfo.channels);
   for (i = 0; i < l->expectedChannels; ++i)
--- a/src/dcshift.c
+++ b/src/dcshift.c
@@ -35,24 +35,15 @@
     dcs->uselimiter = 0; /* default is no limiter */
 
     if (n < 1)
-    {
-        sox_fail(effp->handler.usage);
-        return SOX_EOF;
-    }
+      return sox_usage(effp);
 
     if (n && (!sscanf(argv[0], "%lf", &dcs->dcshift)))
-    {
-        sox_fail(effp->handler.usage);
-        return SOX_EOF;
-    }
+      return sox_usage(effp);
 
     if (n>1)
     {
         if (!sscanf(argv[1], "%lf", &dcs->limitergain))
-        {
-                sox_fail(effp->handler.usage);
-                return SOX_EOF;
-        }
+          return sox_usage(effp);
 
         dcs->uselimiter = 1; /* ok, we'll use it */
         /* The following equation is derived so that there is no 
@@ -77,18 +68,6 @@
     if (dcs->dcshift == 0)
       return SOX_EFF_NULL;
 
-    if (effp->outinfo.channels != effp->ininfo.channels) {
-        sox_fail("DCSHIFT cannot handle different channels (in=%d, out=%d)"
-             " use avg or pan", effp->ininfo.channels, effp->outinfo.channels);
-        return SOX_EOF;
-    }
-
-    if (effp->outinfo.rate != effp->ininfo.rate) {
-        sox_fail("DCSHIFT cannot handle different rates (in=%ld, out=%ld)"
-             " use resample or rate", effp->ininfo.rate, effp->outinfo.rate);
-        return SOX_EOF;
-    }
-
     dcs->clipped = 0;
     dcs->limited = 0;
     dcs->totalprocessed = 0;
@@ -193,7 +172,7 @@
 
 static sox_effect_handler_t sox_dcshift_effect = {
    "dcshift",
-   "Usage: dcshift shift [ limitergain ]\n"
+   "shift [ limitergain ]\n"
    "       The peak limiter has a gain much less than 1.0 (ie 0.05 or 0.02) which is only\n"
    "       used on peaks to prevent clipping. (default is no limiter)",
    SOX_EFF_MCHAN,
--- a/src/dither.c
+++ b/src/dither.c
@@ -27,10 +27,8 @@
 {
   dither_t dither = (dither_t) effp->priv;
 
-  if (n > 1) {
-    sox_fail(effp->handler.usage);
-    return SOX_EOF;
-  }
+  if (n > 1)
+    return sox_usage(effp);
   
   dither->amount = sqrt(2.); /* M_SQRT2 missing in some places */   /* Default to half a bit. */
   if (n == 1) {
@@ -39,10 +37,8 @@
     int scanned = sscanf(*argv, "%lf %c", &amount, &dummy);
     if (scanned == 1 && amount > 0)
       dither->amount *= amount;
-    else {
-      sox_fail(effp->handler.usage);
-      return SOX_EOF;
-    }
+    else
+      return sox_usage(effp);
   }
 
   return SOX_SUCCESS;
@@ -83,7 +79,7 @@
 sox_effect_handler_t const * sox_dither_effect_fn(void)
 {
   static sox_effect_handler_t handler = {
-    "dither", "Usage: dither [amount]", SOX_EFF_MCHAN,
+    "dither", "[amount]", SOX_EFF_MCHAN | SOX_EFF_PREC,
     getopts, start, flow, 0, 0, 0
   };
   return &handler;
@@ -92,7 +88,7 @@
 sox_effect_handler_t const * sox_mask_effect_fn(void)
 {
   static sox_effect_handler_t handler = {
-    "mask", "Usage: mask [amount]", SOX_EFF_MCHAN | SOX_EFF_DEPRECATED,
+    "mask", "[amount]", SOX_EFF_MCHAN | SOX_EFF_PREC | SOX_EFF_DEPRECATED,
     getopts, start, flow, 0, 0, 0
   };
   return &handler;
--- a/src/earwax.c
+++ b/src/earwax.c
@@ -164,7 +164,7 @@
 
 static sox_effect_handler_t sox_earwax_effect = {
   "earwax",
-  "Usage: The earwax filtering effect takes no options",
+  NULL,
   SOX_EFF_MCHAN|SOX_EFF_LENGTH,
   NULL,
   sox_earwax_start,
--- a/src/echo.c
+++ b/src/echo.c
@@ -88,10 +88,7 @@
         echo->num_delays = 0;
 
         if ((n < 4) || (n % 2))
-        {
-            sox_fail(effp->handler.usage);
-            return (SOX_EOF);
-        }
+          return sox_usage(effp);
 
         i = 0;
         sscanf(argv[i++], "%f", &echo->in_gain);
@@ -265,7 +262,7 @@
 
 static sox_effect_handler_t sox_echo_effect = {
   "echo",
-  "Usage: echo gain-in gain-out delay decay [ delay decay ... ]",
+  "gain-in gain-out delay decay [ delay decay ... ]",
   SOX_EFF_LENGTH,
   sox_echo_getopts,
   sox_echo_start,
--- a/src/echos.c
+++ b/src/echos.c
@@ -78,10 +78,7 @@
         echos->num_delays = 0;
 
         if ((n < 4) || (n % 2))
-        {
-            sox_fail(effp->handler.usage);
-            return (SOX_EOF);
-        }
+          return sox_usage(effp);
 
         i = 0;
         sscanf(argv[i++], "%f", &echos->in_gain);
@@ -269,7 +266,7 @@
 
 static sox_effect_handler_t sox_echos_effect = {
   "echos",
-  "Usage: echos gain-in gain-out delay decay [ delay decay ... ]",
+  "gain-in gain-out delay decay [ delay decay ... ]",
   SOX_EFF_LENGTH,
   sox_echos_getopts,
   sox_echos_start,
--- a/src/effects.c
+++ b/src/effects.c
@@ -28,6 +28,14 @@
 #define sox_report sox_message_filename=effp->handler.name,sox_report
 
 
+int sox_usage(sox_effect_t * effp)
+{
+  if (effp->handler.usage)
+    sox_fail("usage: %s", effp->handler.usage);
+  else
+    sox_fail("this effect takes no parameters");
+  return SOX_EOF;
+}
 
 /* Default effect handler functions for do-nothing situations: */
 
@@ -54,11 +62,7 @@
 /* Check that no parameters have been given */
 static int default_getopts(sox_effect_t * effp, int argc, char **argv UNUSED)
 {
-  if (argc) {
-    sox_fail("takes no parameters");
-    return SOX_EOF;
-  }
-  return SOX_SUCCESS;
+  return argc? sox_usage(effp) : SOX_SUCCESS;
 }
 
 /* Partially initialise the effect structure; signal info will come later */
@@ -102,22 +106,30 @@
  * ready for the next effect in the chain.
  */
 int sox_add_effect(sox_effect_t * effp, sox_signalinfo_t * in, sox_signalinfo_t
-    const * out) { int ret, (*start)(sox_effect_t * effp) =
-  effp->handler.start; unsigned f;
+    const * out)
+{
+  int ret, (*start)(sox_effect_t * effp) = effp->handler.start;
+  unsigned f;
+  sox_effect_t eff0;  /* Copy of effect for flow 0 before calling start */
 
   if (effp->handler.flags & SOX_EFF_NULL) {
     sox_report("has no effect (is a proxy effect)");
     return SOX_EFF_NULL;
   }
-  effp->outinfo = effp->ininfo = *in;
-  if (effp->handler.flags & SOX_EFF_CHAN)
-    effp->outinfo.channels = out->channels;
-  if (effp->handler.flags & SOX_EFF_RATE)
-    effp->outinfo.rate = out->rate;
+  effp->ininfo = *in;
+  effp->outinfo = *out;
+  if (!(effp->handler.flags & SOX_EFF_CHAN))
+    effp->outinfo.channels = in->channels;
+  if (!(effp->handler.flags & SOX_EFF_RATE))
+    effp->outinfo.rate = in->rate;
+  if (!(effp->handler.flags & SOX_EFF_PREC))
+    effp->outinfo.size = in->size;
+
   effp->flows =
     (effp->handler.flags & SOX_EFF_MCHAN)? 1 : effp->ininfo.channels;
   effp->clips = 0;
   effp->imin = 0;
+  eff0 = *effp;
   ret = start(effp);
   if (ret == SOX_EFF_NULL) {
     sox_report("has no effect in this configuration");
@@ -125,6 +137,7 @@
   }
   if (ret != SOX_SUCCESS)
     return SOX_EOF;
+
   *in = effp->outinfo;
 
   if (sox_neffects == SOX_MAX_EFFECTS) {
@@ -136,7 +149,7 @@
   sox_effects[sox_neffects][0] = *effp;
 
   for (f = 1; f < effp->flows; ++f) {
-    sox_effects[sox_neffects][f] = *effp;
+    sox_effects[sox_neffects][f] = eff0;
     sox_effects[sox_neffects][f].flow = f;
     if (start(&sox_effects[sox_neffects][f]) != SOX_SUCCESS)
       return SOX_EOF;
--- a/src/fade.c
+++ b/src/fade.c
@@ -51,10 +51,7 @@
     int t_argno;
 
     if (n < 1 || n > 4)
-    { /* Wrong number of arguments. */
-        sox_fail(effp->handler.usage);
-        return(SOX_EOF);
-    }
+         return sox_usage(effp);
 
     /* because sample rate is unavailable at this point we store the
      * string off for later computations.
@@ -79,10 +76,7 @@
     strcpy(fade->in_stop_str,argv[0]);
     /* Do a dummy parse to see if it will fail */
     if (sox_parsesamples(0, fade->in_stop_str, &fade->in_stop, 't') == NULL)
-    {
-        sox_fail(effp->handler.usage);
-        return(SOX_EOF);
-    }
+      return sox_usage(effp);
 
     fade->out_start_str = fade->out_stop_str = 0;
 
@@ -96,10 +90,8 @@
 
             /* Do a dummy parse to see if it will fail */
             if (sox_parsesamples(0, fade->out_stop_str, 
-                                &fade->out_stop, 't') == NULL) {
-              sox_fail(effp->handler.usage);
-              return(SOX_EOF);
-            }
+                                &fade->out_stop, 't') == NULL)
+              return sox_usage(effp);
         }
         else
         {
@@ -108,10 +100,8 @@
 
             /* Do a dummy parse to see if it will fail */
             if (sox_parsesamples(0, fade->out_start_str, 
-                                &fade->out_start, 't') == NULL) {
-              sox_fail(effp->handler.usage);
-              return(SOX_EOF);
-            }
+                                &fade->out_start, 't') == NULL)
+              return sox_usage(effp);
         }
     } /* End for(t_argno) */
 
@@ -130,10 +120,7 @@
     fade->in_start = 0;
     if (sox_parsesamples(effp->ininfo.rate, fade->in_stop_str,
                         &fade->in_stop, 't') == NULL)
-    {
-        sox_fail(effp->handler.usage);
-        return(SOX_EOF);
-    }
+      return sox_usage(effp);
 
     fade->do_out = 0;
     /* See if user specified a stop time */
@@ -142,10 +129,7 @@
         fade->do_out = 1;
         if (sox_parsesamples(effp->ininfo.rate, fade->out_stop_str,
                             &fade->out_stop, 't') == NULL)
-        {
-            sox_fail(effp->handler.usage);
-            return(SOX_EOF);
-        }
+          return sox_usage(effp);
 
         /* See if user wants to fade out. */
         if (fade->out_start_str)
@@ -152,10 +136,7 @@
         {
             if (sox_parsesamples(effp->ininfo.rate, fade->out_start_str,
                         &fade->out_start, 't') == NULL)
-            {
-                sox_fail(effp->handler.usage);
-                return(SOX_EOF);
-            }
+              return sox_usage(effp);
             /* Fade time is relative to stop time. */
             fade->out_start = fade->out_stop - fade->out_start;
 
@@ -371,7 +352,7 @@
 
 static sox_effect_handler_t sox_fade_effect = {
   "fade",
-  "Usage: fade [ type ] fade-in-length [ stop-time [ fade-out-length ] ]\n"
+  "[ type ] fade-in-length [ stop-time [ fade-out-length ] ]\n"
   "       Time is in hh:mm:ss.frac format.\n"
   "       Fade type one of q, h, t, l or p.",
   SOX_EFF_MCHAN,
--- a/src/filter.c
+++ b/src/filter.c
@@ -74,16 +74,10 @@
         }
         sox_debug("freq: %d-%d", f->freq0, f->freq1);
         if (f->freq0 == 0 && f->freq1 == 0)
-        {
-                sox_fail(effp->handler.usage);
-                return (SOX_EOF);
-        }
+          return sox_usage(effp);
 
         if ((n >= 2) && !sscanf(argv[1], "%ld", &f->Nwin))
-        {
-                sox_fail(effp->handler.usage);
-                return (SOX_EOF);
-        }
+          return sox_usage(effp);
         else if (f->Nwin < 4) {
                 sox_fail("filter: window length (%ld) <4 is too short", f->Nwin);
                 return (SOX_EOF);
@@ -90,10 +84,7 @@
         }
 
         if ((n >= 3) && !sscanf(argv[2], "%lf", &f->beta))
-        {
-                sox_fail(effp->handler.usage);
-                return (SOX_EOF);
-        }
+          return sox_usage(effp);
 
         sox_debug("filter opts: %d-%d, window-len %d, beta %f", f->freq0, f->freq1, f->Nwin, f->beta);
         return (SOX_SUCCESS);
@@ -311,7 +302,7 @@
 
 static sox_effect_handler_t sox_filter_effect = {
   "filter",
-  "Usage: filter low-high [ windowlength [ beta ] ]",
+  "low-high [ windowlength [ beta ] ]",
   0,
   sox_filter_getopts,
   sox_filter_start,
--- a/src/flanger.c
+++ b/src/flanger.c
@@ -17,7 +17,7 @@
 /* Effect: Stereo Flanger   (c) 2006 robs@users.sourceforge.net */
 
 #define sox_flanger_usage \
-  "Usage: flanger [delay depth regen width speed shape phase interp]\n"
+  "[delay depth regen width speed shape phase interp]\n"
 /*
   "                  .\n" \
   "                 /|regen\n" \
@@ -109,10 +109,8 @@
   if (argc == 0) break; \
   d = strtod(*argv, &end_ptr); \
   if (end_ptr != *argv) { \
-    if (d < min || d > max || *end_ptr != '\0') { \
-      sox_fail(effp->handler.usage); \
-      return SOX_EOF; \
-    } \
+    if (d < min || d > max || *end_ptr != '\0') \
+      return sox_usage(effp); \
     f->p = d; \
     --argc, ++argv; \
   } \
@@ -153,10 +151,8 @@
     TEXTUAL_PARAMETER(interpolation, interp_enum)
   } while (0);
 
-  if (argc != 0) {
-    sox_fail(effp->handler.usage);
-    return SOX_EOF;
-  }
+  if (argc != 0)
+    return sox_usage(effp);
 
   sox_report("parameters:\n"
       "delay = %gms\n"
--- a/src/ladspa.c
+++ b/src/ladspa.c
@@ -176,10 +176,8 @@
         l_st->control[i] = ladspa_default(&(l_st->desc->PortRangeHints[i]));
         sox_debug("default argument for port %d is %f", i, l_st->control[i]);
       } else {
-        if (!sscanf(argv[0], "%lf", &arg)) {
-          sox_fail(effp->handler.usage);
-          return SOX_EOF;
-        }
+        if (!sscanf(argv[0], "%lf", &arg))
+          return sox_usage(effp);
         l_st->control[i] = (LADSPA_Data)arg;
         sox_debug("argument for port %d is %f", i, l_st->control[i]);
         n--; argv++;
@@ -188,12 +186,7 @@
   }
 
   /* Stop if we have any unused arguments */
-  if (n > 0) {
-    sox_fail(sox_ladspa_effect.usage);
-    return SOX_EOF;
-  }
-
-  return SOX_SUCCESS;
+  return n? sox_usage(effp) : SOX_SUCCESS;
 }
 
 /*
@@ -298,7 +291,7 @@
 
 static sox_effect_handler_t sox_ladspa_effect = {
   "ladspa",
-  "Usage: ladspa MODULE [PLUGIN] [ARGUMENT...]",
+  "MODULE [PLUGIN] [ARGUMENT...]",
   0,
   sox_ladspa_getopts,
   sox_ladspa_start,
--- a/src/mcompand.c
+++ b/src/mcompand.c
@@ -624,7 +624,7 @@
 
 static sox_effect_handler_t sox_mcompand_effect = {
   "mcompand",
-  "Usage: mcompand quoted_compand_args [crossover_frequency quoted_compand_args [...]]\n"
+  "quoted_compand_args [crossover_frequency quoted_compand_args [...]]\n"
   "\n"
   "quoted_compand_args are as for the compand effect:\n"
   "\n"
--- a/src/misc.c
+++ b/src/misc.c
@@ -368,6 +368,12 @@
   return str_len >= end_len && !strcasecmp(str + str_len - end_len, end);
 }
 
+sox_bool strends(char const * str, char const * end)
+{
+  size_t str_len = strlen(str), end_len = strlen(end);
+  return str_len >= end_len && !strcmp(str + str_len - end_len, end);
+}
+
 #ifndef HAVE_STRDUP
 /*
  * Portable strdup() function
--- a/src/mixer.c
+++ b/src/mixer.c
@@ -79,10 +79,8 @@
         else if (!strcmp(argv[0], "-4"))
             mixer->mix = MIX_RIGHT_BACK;
         else if (argv[0][0] == '-' && !isdigit((int)argv[0][1])
-                && argv[0][1] != '.') {
-            sox_fail(effp->handler.usage);
-            return (SOX_EOF);
-        }
+                && argv[0][1] != '.')
+          return sox_usage(effp);
         else {
             int commas;
             char *s;
@@ -104,10 +102,8 @@
     else if (n == 0) {
         mixer->mix = MIX_CENTER;
     }
-    else {
-        sox_fail(effp->handler.usage);
-        return SOX_EOF;
-    }
+    else
+      return sox_usage(effp);
 
     return (SOX_SUCCESS);
 }
@@ -540,7 +536,7 @@
 {
   static sox_effect_handler_t handler = {
     "mixer",
-    "Usage: mixer [ -l | -r | -f | -b | -1 | -2 | -3 | -4 | n,n,n...,n ]",
+    "[ -l | -r | -f | -b | -1 | -2 | -3 | -4 | n,n,n...,n ]",
     SOX_EFF_MCHAN | SOX_EFF_CHAN,
     getopts, start, flow, 0, 0, 0
   };
@@ -549,22 +545,17 @@
 
 sox_effect_handler_t const * sox_avg_effect_fn(void)
 {
-  static sox_effect_handler_t handler = {
-    "avg",
-    "Usage: avg [ -l | -r | -f | -b | -1 | -2 | -3 | -4 | n,n,n...,n ]",
-    SOX_EFF_MCHAN | SOX_EFF_CHAN | SOX_EFF_DEPRECATED,
-    getopts, start, flow, 0, 0, 0
-  };
+  static sox_effect_handler_t handler;
+  handler = *sox_mixer_effect_fn();
+  handler.name = "avg";
+  handler.flags |= SOX_EFF_DEPRECATED;
   return &handler;
 }
 
 sox_effect_handler_t const * sox_pick_effect_fn(void)
 {
-  static sox_effect_handler_t handler = {
-    "pick",
-    "Usage: pick [ -l | -r | -f | -b | -1 | -2 | -3 | -4 | n,n,n...,n ]",
-    SOX_EFF_MCHAN | SOX_EFF_CHAN | SOX_EFF_DEPRECATED,
-    getopts, start, flow, 0, 0, 0
-  };
+  static sox_effect_handler_t handler;
+  handler = *sox_avg_effect_fn();
+  handler.name = "pick";
   return &handler;
 }
--- a/src/noiseprof.c
+++ b/src/noiseprof.c
@@ -43,10 +43,8 @@
 
     if (n == 1) {
         data->output_filename = argv[0];
-    } else if (n > 1) {
-        sox_fail(effp->handler.usage);
-        return (SOX_EOF);
-    }
+    } else if (n > 1)
+      return sox_usage(effp);
 
     return (SOX_SUCCESS);
 }
@@ -212,7 +210,7 @@
 
 static sox_effect_handler_t sox_noiseprof_effect = {
   "noiseprof",
-  "Usage: noiseprof [profile-file]",
+  "[profile-file]",
   SOX_EFF_MCHAN,
   sox_noiseprof_getopts,
   sox_noiseprof_start,
--- a/src/noisered.c
+++ b/src/noisered.c
@@ -22,10 +22,8 @@
   if (argc == 0) break; \
   d = strtod(*argv, &end_ptr); \
   if (end_ptr != *argv) { \
-    if (d < min || d > max || *end_ptr != '\0') { \
-      sox_fail(effp->handler.usage); \
-      return SOX_EOF; \
-    } \
+    if (d < min || d > max || *end_ptr != '\0') \
+      return sox_usage(effp); \
     this->p = d; \
     --argc, ++argv; \
   } \
@@ -66,11 +64,7 @@
     NUMERIC_PARAMETER(threshold, 0, 1);
   } while (0);
 
-  if (argc != 0) {
-    sox_fail(effp->handler.usage);
-    return SOX_EOF;
-  }
-  return SOX_SUCCESS;
+  return argc? sox_usage(effp) : SOX_SUCCESS;
 }
 
 /*
@@ -345,7 +339,7 @@
 
 static sox_effect_handler_t sox_noisered_effect = {
   "noisered",
-  "Usage: noisered [profile-file [amount]]",
+  "[profile-file [amount]]",
   SOX_EFF_MCHAN|SOX_EFF_LENGTH,
   sox_noisered_getopts,
   sox_noisered_start,
--- a/src/noisered.h
+++ b/src/noisered.h
@@ -18,4 +18,5 @@
 #include <math.h>
 
 #define WINDOWSIZE 2048
-#define FREQCOUNT (WINDOWSIZE/2+1)
+#define HALFWINDOW (WINDOWSIZE / 2)
+#define FREQCOUNT  (HALFWINDOW + 1)
--- a/src/pad.c
+++ b/src/pad.c
@@ -55,10 +55,8 @@
     }
     if (i > 0 && p->pads[i].start <= p->pads[i-1].start) break;
   }
-  if (i < p->npads) {
-    sox_fail(effp->handler.usage);
-    return SOX_EOF;
-  }
+  if (i < p->npads)
+    return sox_usage(effp);
   return SOX_SUCCESS;
 }
 
@@ -141,7 +139,7 @@
 sox_effect_handler_t const * sox_pad_effect_fn(void)
 {
   static sox_effect_handler_t handler = {
-    "pad", "Usage: pad {length[@position]}", SOX_EFF_MCHAN|SOX_EFF_LENGTH,
+    "pad", "{length[@position]}", SOX_EFF_MCHAN|SOX_EFF_LENGTH,
     create, start, flow, drain, stop, kill
   };
   return &handler;
--- a/src/pan.c
+++ b/src/pan.c
@@ -36,10 +36,7 @@
     
     if (n && (!sscanf(argv[0], "%lf", &pan->dir) || 
               pan->dir < -1.0 || pan->dir > 1.0))
-    {
-        sox_fail(effp->handler.usage);
-        return SOX_EOF;
-    }
+      return sox_usage(effp);
 
     return SOX_SUCCESS;
 }
@@ -51,14 +48,6 @@
 {
     if (effp->outinfo.channels==1)
         sox_warn("PAN onto a mono channel...");
-
-    if (effp->outinfo.rate != effp->ininfo.rate)
-    {
-        sox_fail("PAN cannot handle different rates (in=%ld, out=%ld)"
-             " use resample or rate", effp->ininfo.rate, effp->outinfo.rate);
-        return SOX_EOF;
-    }
-
     return SOX_SUCCESS;
 }
 
@@ -411,7 +400,7 @@
 
 static sox_effect_handler_t sox_pan_effect = {
   "pan",
-  "Usage: pan direction (in [-1.0 .. 1.0])",
+  "direction (in [-1.0 .. 1.0])",
   SOX_EFF_MCHAN | SOX_EFF_CHAN,
   sox_pan_getopts,
   sox_pan_start,
--- a/src/phaser.c
+++ b/src/phaser.c
@@ -84,10 +84,7 @@
         phaser_t phaser = (phaser_t) effp->priv;
 
         if (!((n == 5) || (n == 6)))
-        {
-            sox_fail(effp->handler.usage);
-            return (SOX_EOF);
-        }
+          return sox_usage(effp);
 
         sscanf(argv[0], "%f", &phaser->in_gain);
         sscanf(argv[1], "%f", &phaser->out_gain);
@@ -101,10 +98,7 @@
                 else if ( ! strcmp(argv[5], "-t"))
                         phaser->modulation = MOD_TRIANGLE;
                 else
-                {
-                        sox_fail(effp->handler.usage);
-                        return (SOX_EOF);
-                }
+                  return sox_usage(effp);
         }
         return (SOX_SUCCESS);
 }
@@ -261,7 +255,7 @@
 
 static sox_effect_handler_t sox_phaser_effect = {
   "phaser",
-  "Usage: phaser gain-in gain-out delay decay speed [ -s | -t ]",
+  "gain-in gain-out delay decay speed [ -s | -t ]",
   SOX_EFF_LENGTH,
   sox_phaser_getopts,
   sox_phaser_start,
--- a/src/pitch.c
+++ b/src/pitch.c
@@ -252,18 +252,12 @@
     pitch->shift = 0.0; /* default is no change */
 
     if (n && !sscanf(argv[0], "%lf", &pitch->shift))
-    {
-        sox_fail(effp->handler.usage);
-        return SOX_EOF;
-    }
+      return sox_usage(effp);
 
     /* sweep size in ms */
     pitch->width = PITCH_DEFAULT_WIDTH;
     if (n>1 && !sscanf(argv[1], "%lf", &pitch->width))
-    {
-        sox_fail(effp->handler.usage);
-        return SOX_EOF;
-    }
+      return sox_usage(effp);
 
     /* interpole option */
     pitch->interopt = PITCH_INTERPOLE_DEFAULT;
@@ -280,8 +274,7 @@
             pitch->interopt = PITCH_INTERPOLE_CUB;
             break;
         default:
-            sox_fail(effp->handler.usage);
-            return SOX_EOF;
+            return sox_usage(effp);
         }
     }
 
@@ -308,8 +301,7 @@
             pitch->fadeopt = PITCH_FADE_COS;
             break;
         default:
-            sox_fail(effp->handler.usage);
-            return SOX_EOF;
+            return sox_usage(effp);
         }
     }
     
@@ -316,10 +308,7 @@
     pitch->coef = 0.25;
     if (n>4 && (!sscanf(argv[4], "%lf", &pitch->coef) ||
                 pitch->coef<0.0 || pitch->coef>0.5))
-    {
-        sox_fail(effp->handler.usage);
-        return SOX_EOF;
-    }
+      return sox_usage(effp);
 
     return SOX_SUCCESS;
 }
@@ -333,22 +322,6 @@
     register int sample_rate = effp->outinfo.rate;
     unsigned int i;
 
-    /* check constraints. sox does already take care of that I guess?
-     */
-    if (effp->outinfo.rate != effp->ininfo.rate)
-    {
-        sox_fail("PITCH cannot handle different rates (in=%ld, out=%ld)"
-             " use resample or rate", effp->ininfo.rate, effp->outinfo.rate);
-        return SOX_EOF;
-    }
- 
-    if (effp->outinfo.channels != effp->ininfo.channels)
-    {
-        sox_fail("PITCH cannot handle different channels (in=%ld, out=%ld)"
-             " use avg or pan", effp->ininfo.channels, effp->outinfo.channels);
-        return SOX_EOF;
-    }
-
     /* computer inner stuff... */
 
     pitch->state = pi_input;
@@ -574,7 +547,7 @@
 
 static sox_effect_handler_t sox_pitch_effect = {
   "pitch",
-  "Usage: pitch shift width interpole fade\n"
+  "shift width interpole fade\n"
   "       (in cents, in ms, cub/lin, cos/ham/lin/trap)"
   "       (defaults: 0 20 c c)",
   SOX_EFF_LENGTH,
--- a/src/polyphas.c
+++ b/src/polyphas.c
@@ -619,7 +619,7 @@
 
 static sox_effect_handler_t sox_polyphase_effect = {
   "polyphase",
-  "Usage: -w {nut|ham}   window type\n"
+  "-w {nut|ham}   window type\n"
   "       -width n       window width in samples [default 1024]\n"
   "\n"
   "       -cutoff float  frequency cutoff for base bandwidth [default 0.95]",
--- a/src/rabbit.c
+++ b/src/rabbit.c
@@ -17,15 +17,8 @@
  * Foundation, Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301,
  * USA.  */
 
-/* FIXME: Make more efficient by resampling piece by piece rather than
-   all in one go. The code is as it is at present because before SoX
-   had global clipping detection, rabbit used to do its own based on
-   sndfile-resample. */
- 
 #include "sox_i.h"
 
-#ifdef HAVE_SAMPLERATE_H
-
 #include <limits.h>
 #include <stdlib.h>
 #include <string.h>
@@ -37,14 +30,13 @@
   int converter_type;           /* SRC converter type */
   SRC_STATE *state;             /* SRC state struct */
   SRC_DATA *data;               /* SRC_DATA control struct */
-  sox_size_t samples;            /* Number of samples read so far */
-  sox_size_t outsamp;            /* Next output sample */
+  sox_size_t i_alloc, o_alloc;  /* Samples allocated in data->data_{in,out} */
 } *rabbit_t;
 
 /*
  * Process options
  */
-static int sox_rabbit_getopts(sox_effect_t * effp, int n, char **argv)
+static int getopts(sox_effect_t * effp, int n, char **argv)
 {
   rabbit_t r = (rabbit_t) effp->priv;
 
@@ -69,10 +61,8 @@
     }
   }
 
-  if (n >= 1) {
-    sox_fail(effp->handler.usage);
-    return SOX_EOF;
-  }
+  if (n >= 1)
+    return sox_usage(effp);
 
   return SOX_SUCCESS;
 }
@@ -80,9 +70,10 @@
 /*
  * Prepare processing.
  */
-static int sox_rabbit_start(sox_effect_t * effp)
+static int start(sox_effect_t * effp)
 {
   rabbit_t r = (rabbit_t) effp->priv;
+  int err = 0;
 
   /* The next line makes the "speed" effect accurate; it's needed because
    * ininfo.rate (sox_rate_t) isn't floating point (but it's probably not worth
@@ -100,38 +91,79 @@
 
   r->data = (SRC_DATA *)xcalloc(1, sizeof(SRC_DATA));
   r->data->src_ratio = (double)effp->outinfo.rate / in_rate;
-  r->data->input_frames_used = 0;
-  r->data->output_frames_gen = 0;
+  r->i_alloc = r->o_alloc = 0;
+  r->state = src_new(r->converter_type, effp->ininfo.channels, &err);
+  if (err) {
+    free(r->data);
+    sox_fail("cannot initialise rabbit: %s", src_strerror(err));
+    return SOX_EOF;
+  }
 
   return SOX_SUCCESS;
 }
 
 /*
- * Read all the data.
+ * Read, convert, return data.
  */
-static int sox_rabbit_flow(sox_effect_t * effp, const sox_ssample_t *ibuf, sox_ssample_t *obuf UNUSED,
+static int flow(sox_effect_t * effp, const sox_ssample_t *ibuf, sox_ssample_t *obuf UNUSED,
                    sox_size_t *isamp, sox_size_t *osamp)
 {
   rabbit_t r = (rabbit_t) effp->priv;
-  int channels = effp->ininfo.channels;
-  sox_size_t i, newsamples;
+  SRC_DATA *d = r->data;
+  unsigned int channels = effp->ininfo.channels;
+  sox_size_t i;
 
-  newsamples = r->samples + *isamp;
-  if (newsamples / channels > INT_MAX) {
-      sox_fail("input data size %d too large for libsamplerate", newsamples);
-      return SOX_EOF;
+  if (isamp && *isamp > 0) {
+    sox_size_t isamples0 = d->input_frames * channels;
+    sox_size_t isamples = isamples0 + *isamp;
+    sox_size_t osamples = isamples * (d->src_ratio + 0.01) + 8;
+
+    if (osamples > sox_bufsiz) {
+      osamples = sox_bufsiz;
+      isamples = (osamples - 8) / (d->src_ratio + 0.01);
+    }
+
+    if (r->i_alloc < isamples) {
+      d->data_in = xrealloc(d->data_in, isamples * sizeof(float));
+      r->i_alloc = isamples;
+    }
+    if (r->o_alloc < osamples) {
+      d->data_out = xrealloc(d->data_out, osamples * sizeof(float));
+      r->o_alloc = osamples;
+      d->output_frames = osamples / channels;
+    }
+
+    for (i = 0; i < isamples - isamples0; i++)
+      d->data_in[isamples0 + i] = SOX_SAMPLE_TO_FLOAT_32BIT(ibuf[i], effp->clips);
+
+    *isamp = isamples - isamples0;
+    d->input_frames = isamples / channels;
   }
 
-  r->data->data_in = (float *)xrealloc(r->data->data_in, newsamples * sizeof(float));
+  *osamp = 0;
+  while (d->input_frames > 0 || d->end_of_input != 0) {
+    if (src_process(r->state, r->data) != 0) {
+      sox_fail("%s", src_strerror(src_error(r->state)));
+      return SOX_EOF;
+    }
+    if (d->input_frames_used) {
+      d->input_frames -= d->input_frames_used;
+      if (d->input_frames)
+       memcpy(d->data_in,
+              d->data_in + d->input_frames_used * sizeof(float),
+              d->input_frames * sizeof(float));
+    }
 
-  for (i = 0 ; i < *isamp; i++)
-    r->data->data_in[r->samples + i] = SOX_SAMPLE_TO_FLOAT_32BIT(ibuf[i], effp->clips);
+    *osamp = d->output_frames_gen * channels;
+    if (! *osamp)
+      break;
 
-  r->samples = newsamples;
-  r->data->input_frames = r->samples / channels;
-  r->outsamp = 0;
+    for (i = 0; i < (sox_size_t)d->output_frames_gen * channels; i++)
+      obuf[i] = SOX_FLOAT_32BIT_TO_SAMPLE(d->data_out[i], effp->clips);
 
-  *osamp = 0;           /* Signal that we didn't produce any output */
+    if (d->end_of_input)
+      break;
+  }
 
   return SOX_SUCCESS;
 }
@@ -139,52 +171,17 @@
 /*
  * Process samples and write output.
  */
-static int sox_rabbit_drain(sox_effect_t * effp, sox_ssample_t *obuf, sox_size_t *osamp)
+static int drain(sox_effect_t * effp, sox_ssample_t *obuf, sox_size_t *osamp)
 {
   rabbit_t r = (rabbit_t) effp->priv;
-  int channels = effp->ininfo.channels;
-  sox_size_t i, outsamps;
-
-  /* On first call, process the data */
-  if (r->data->data_out == NULL) {
-    /* Guess maximum number of possible output frames */
-    sox_size_t outframes = r->data->input_frames * (r->data->src_ratio + 0.01) + 8;
-    int error;
-
-    if (outframes > INT_MAX) {
-      sox_fail("too many output frames (%d) for libsamplerate", outframes);
-      return SOX_EOF;
-    }
-    r->data->output_frames = outframes;
-    r->data->data_out = (float *)xmalloc(r->data->output_frames * channels * sizeof(float));
-
-    /* Process the data */
-    if ((error = src_simple(r->data, r->converter_type, channels))) {
-      sox_fail("libsamplerate processing failed: %s", src_strerror(error));
-      return SOX_EOF;
-    }
-  }
-
-  /* Return the data one bufferful at a time */
-  if (*osamp > INT_MAX) {
-    sox_fail("output buffer size %d too large for libsamplerate", *osamp);
-    return SOX_EOF;
-  }
-
-  outsamps = min(r->data->output_frames_gen * channels - r->outsamp, *osamp);
-  for (i = 0; i < outsamps; i++)
-    obuf[i] = SOX_FLOAT_32BIT_TO_SAMPLE(r->data->data_out[r->outsamp + i], effp->clips);
-  *osamp = (sox_size_t)outsamps;
-  r->outsamp += outsamps;
-
-  return SOX_SUCCESS;
+  r->data->end_of_input = 1;
+  return flow(effp, NULL, obuf, NULL, osamp);
 }
 
 /*
  * Do anything required when you stop reading samples.
- * Don't close input file!
  */
-static int sox_rabbit_stop(sox_effect_t * effp)
+static int stop(sox_effect_t * effp)
 {
   rabbit_t r = (rabbit_t) effp->priv;
 
@@ -193,21 +190,13 @@
   return SOX_SUCCESS;
 }
 
-static sox_effect_handler_t sox_rabbit_effect = {
-  "rabbit",
-  "Usage: rabbit [-c0|-c1|-c2|-c3|-c4]",
-  SOX_EFF_RATE | SOX_EFF_MCHAN,
-  sox_rabbit_getopts,
-  sox_rabbit_start,
-  sox_rabbit_flow,
-  sox_rabbit_drain,
-  sox_rabbit_stop,
-  NULL
-};
-
 const sox_effect_handler_t *sox_rabbit_effect_fn(void)
 {
-  return &sox_rabbit_effect;
-}
+  static sox_effect_handler_t handler = {
+    "rabbit", "[-c0|-c1|-c2|-c3|-c4]",
+    SOX_EFF_RATE | SOX_EFF_MCHAN,
+    getopts, start, flow, drain, stop, NULL
+  };
 
-#endif /* HAVE_SAMPLERATE */
+  return &handler;
+}
--- a/src/repeat.c
+++ b/src/repeat.c
@@ -36,10 +36,8 @@
 {
         repeat_t repeat = (repeat_t)effp->priv;
 
-        if (n != 1) {
-                sox_fail(effp->handler.usage);
-                return (SOX_EOF);
-        }
+        if (n != 1)
+          return sox_usage(effp);
 
         if (!(sscanf(argv[0], "%i", &repeat->repeats))) {
                 sox_fail("could not parse repeat parameter");
@@ -196,7 +194,7 @@
 
 static sox_effect_handler_t sox_repeat_effect = {
   "repeat",
-  "Usage: repeat count",
+  "count",
   SOX_EFF_MCHAN | SOX_EFF_LENGTH,
   sox_repeat_getopts,
   sox_repeat_start,
--- a/src/resample.c
+++ b/src/resample.c
@@ -169,16 +169,15 @@
         }
 
         if ((n >= 1) && (sscanf(argv[0], "%lf", &r->rolloff) != 1)) {
-          sox_fail(effp->handler.usage);
-          return (SOX_EOF);
+          return sox_usage(effp);
         } else if ((r->rolloff <= 0.01) || (r->rolloff >= 1.0)) {
           sox_fail("rolloff factor (%f) no good, should be 0.01<x<1.0", r->rolloff);
           return(SOX_EOF);
         }
 
+
         if ((n >= 2) && !sscanf(argv[1], "%lf", &r->beta)) {
-        	sox_fail(effp->handler.usage);
-          	return (SOX_EOF);
+          return sox_usage(effp);
         } else if (r->beta <= 2.0) {
         	r->beta = 0;
                 sox_debug("opts: Nuttall window, cutoff %f", r->rolloff);
@@ -724,7 +723,7 @@
 const sox_effect_handler_t *sox_resample_effect_fn(void)
 {
   static sox_effect_handler_t handler = {
-     "resample", "Usage: resample [ -qs | -q | -ql ] [ rolloff [ beta ] ]",
+     "resample", "[ -qs | -q | -ql ] [ rolloff [ beta ] ]",
      SOX_EFF_RATE, getopts, start, flow, drain, stop, NULL
   };
   return &handler;
--- a/src/reverb.c
+++ b/src/reverb.c
@@ -122,10 +122,7 @@
         reverb->maxsamples = 0;
 
         if ( n < 3 )
-        {
-            sox_fail(effp->handler.usage);
-            return (SOX_EOF);
-        }
+          return sox_usage(effp);
 
         if ( n - 2 > MAXREVERBS )
         {
@@ -282,7 +279,7 @@
 
 static sox_effect_handler_t sox_reverb_effect = {
   "reverb",
-  "Usage: reverb gain-out reverb-time delay [ delay ... ]",
+  "gain-out reverb-time delay [ delay ... ]",
   SOX_EFF_LENGTH,
   sox_reverb_getopts,
   sox_reverb_start,
--- a/src/reverse.c
+++ b/src/reverse.c
@@ -131,7 +131,7 @@
 
 static sox_effect_handler_t sox_reverse_effect = {
   "reverse",
-  "Usage: Reverse effect takes no options",
+  NULL,
   0,
   NULL,
   sox_reverse_start,
--- a/src/silence.c
+++ b/src/silence.c
@@ -94,18 +94,12 @@
     }
 
     if (n < 1)
-    {
-        sox_fail(effp->handler.usage);
-        return (SOX_EOF);
-    }
+      return sox_usage(effp);
 
     /* Parse data related to trimming front side */
     silence->start = sox_false;
     if (sscanf(argv[0], "%d", &silence->start_periods) != 1)
-    {
-        sox_fail(effp->handler.usage);
-        return(SOX_EOF);
-    }
+      return sox_usage(effp);
     if (silence->start_periods < 0)
     {
         sox_fail("Periods must not be negative");
@@ -118,10 +112,7 @@
     {
         silence->start = sox_true;
         if (n < 2)
-        {
-            sox_fail(effp->handler.usage);
-            return SOX_EOF;
-        }
+          return sox_usage(effp);
 
         /* We do not know the sample rate so we can not fully
          * parse the duration info yet.  So save argument off
@@ -132,18 +123,12 @@
         /* Perform a fake parse to do error checking */
         if (sox_parsesamples(0,silence->start_duration_str,
                     &silence->start_duration,'s') == NULL)
-        {
-            sox_fail(effp->handler.usage);
-            return(SOX_EOF);
-        }
+          return sox_usage(effp);
 
         parse_count = sscanf(argv[1], "%lf%c", &silence->start_threshold, 
                 &silence->start_unit);
         if (parse_count < 1)
-        {
-            sox_fail(effp->handler.usage);
-            return SOX_EOF;
-        }
+          return sox_usage(effp);
         else if (parse_count < 2)
             silence->start_unit = '%';
 
@@ -156,15 +141,9 @@
     if (n > 0)
     {
         if (n < 3)
-        {
-            sox_fail(effp->handler.usage);
-            return SOX_EOF;
-        }
+          return sox_usage(effp);
         if (sscanf(argv[0], "%d", &silence->stop_periods) != 1)
-        {
-            sox_fail(effp->handler.usage);
-            return SOX_EOF;
-        }
+          return sox_usage(effp);
         if (silence->stop_periods < 0)
         {
             silence->stop_periods = -silence->stop_periods;
@@ -185,18 +164,12 @@
         /* Perform a fake parse to do error checking */
         if (sox_parsesamples(0,silence->stop_duration_str,
                     &silence->stop_duration,'s') == NULL)
-        {
-            sox_fail(effp->handler.usage);
-            return(SOX_EOF);
-        }
+          return sox_usage(effp);
 
         parse_count = sscanf(argv[1], "%lf%c", &silence->stop_threshold, 
                              &silence->stop_unit);
         if (parse_count < 1)
-        {
-            sox_fail(effp->handler.usage);
-            return SOX_EOF;
-        }
+          return sox_usage(effp);
         else if (parse_count < 2)
             silence->stop_unit = '%';
 
@@ -210,8 +183,7 @@
         if ((silence->start_unit != '%') && (silence->start_unit != 'd'))
         {
             sox_fail("Invalid unit specified");
-            sox_fail(effp->handler.usage);
-            return(SOX_EOF);
+            return sox_usage(effp);
         }
         if ((silence->start_unit == '%') && ((silence->start_threshold < 0.0)
             || (silence->start_threshold > 100.0)))
@@ -268,19 +240,13 @@
         {
             if (sox_parsesamples(effp->ininfo.rate, silence->start_duration_str,
                                 &silence->start_duration, 's') == NULL)
-            {
-                sox_fail(effp->handler.usage);
-                return(SOX_EOF);
-            }
+              return sox_usage(effp);
         }
         if (silence->stop)
         {
             if (sox_parsesamples(effp->ininfo.rate,silence->stop_duration_str,
                                 &silence->stop_duration,'s') == NULL)
-            {
-                sox_fail(effp->handler.usage);
-                return(SOX_EOF);
-            }
+              return sox_usage(effp);
         }
 
         if (silence->start)
@@ -714,7 +680,7 @@
 
 static sox_effect_handler_t sox_silence_effect = {
   "silence",
-  "Usage: silence [ -l ] above_periods [ duration thershold[d|%%] ] [ below_periods duration threshold[d|%%]]",
+  "[ -l ] above_periods [ duration thershold[d|%%] ] [ below_periods duration threshold[d|%%]]",
   SOX_EFF_MCHAN,
   sox_silence_getopts,
   sox_silence_start,
--- a/src/skeleff.c
+++ b/src/skeleff.c
@@ -37,10 +37,8 @@
 {
   skeleff_t skeleff = (skeleff_t)effp->priv;
 
-  if (n && n != 1) {
-    sox_fail(effp->handler.usage);
-    return SOX_EOF;
-  }
+  if (n && n != 1)
+    return sox_usage(effp);
 
   return SOX_SUCCESS;
 }
@@ -132,7 +130,7 @@
  */
 static sox_effect_handler_t sox_skel_effect = {
   "skel",
-  "Usage: skel [OPTION]",
+  "[OPTION]",
   SOX_EFF_MCHAN,
   getopts,
   start,
--- a/src/sox.c
+++ b/src/sox.c
@@ -504,17 +504,13 @@
   atexit(cleanup);
   sox_output_message_handler = output_message;
 
-  /* Read command-line and argv[0] options */
-  i = strlen(myname);
-  if (i >= sizeof("play") - 1 &&
-      strcmp(myname + i - (sizeof("play") - 1), "play") == 0) {
+  if (strends(myname, "play")) {
     play = sox_true;
     replay_gain_mode = RG_track;
     combine_method = sox_sequence;
-  } else if (i >= sizeof("rec") - 1 &&
-      strcmp(myname + i - (sizeof("rec") - 1), "rec") == 0) {
-    rec = sox_true;
   }
+  else if (strends(myname, "rec"))
+    rec = sox_true;
 
   parse_options_and_filenames(argc, argv);
 
@@ -631,7 +627,7 @@
   if (show_progress) {
     if (user_abort)
       fprintf(stderr, "Aborted.\n");
-    else if (user_skip)
+    else if (user_skip && !rec)
       fprintf(stderr, "Skipped.\n");
     else
       fprintf(stderr, "Done.\n");
@@ -748,33 +744,6 @@
   return p->value;
 }
 
-static void optimize_trim(void)          
-{
-  /* Speed hack.  If the "trim" effect is the first effect then
-   * peek inside its "effect descriptor" and see what the
-   * start location is.  This has to be done after its start()
-   * is called to have the correct location.
-   * Also, only do this when only working with one input file.
-   * This is because the logic to do it for multiple files is
-   * complex and problably never used.
-   * This hack is a huge time savings when trimming
-   * gigs of audio data into managable chunks
-   */ 
-  if (input_count == 1 && sox_neffects > 1 && strcmp(sox_effects[1][0].handler.name, "trim") == 0) {
-    if ((files[0]->ft->handler->flags & SOX_FILE_SEEK) && files[0]->ft->seekable){
-      sox_size_t offset = sox_trim_get_start(&sox_effects[1][0]);
-      if (sox_seek(files[0]->ft, offset, SOX_SEEK_SET) != SOX_EOF) { 
-        read_wide_samples = offset / files[0]->ft->signal.channels;
-        /* Assuming a failed seek stayed where it was.  If the 
-         * seek worked then reset the start location of 
-         * trim so that it thinks user didn't request a skip.
-         */ 
-        sox_trim_clear_start(&sox_effects[1][0]);
-      }    
-    }        
-  }    
-}
-
 static sox_bool doopts(file_t f, int argc, char **argv)
 {
   while (sox_true) {
@@ -1274,12 +1243,39 @@
 
   for (i = 0; i < sox_neffects; ++i) {
     sox_effect_t * effp = &sox_effects[i][0];
-    sox_report("effects chain: %-10s %uHz %u channels %s",
-        effp->handler.name, effp->ininfo.rate, effp->ininfo.channels,
+    sox_report("effects chain: %-10s %uHz %u channels %u bits %s",
+        effp->handler.name, effp->ininfo.rate, effp->ininfo.channels, effp->ininfo.size * 8,
         (effp->handler.flags & SOX_EFF_MCHAN)? "(multi)" : "");
   }
 }
 
+static void optimize_trim(void)          
+{
+  /* Speed hack.  If the "trim" effect is the first effect then
+   * peek inside its "effect descriptor" and see what the
+   * start location is.  This has to be done after its start()
+   * is called to have the correct location.
+   * Also, only do this when only working with one input file.
+   * This is because the logic to do it for multiple files is
+   * complex and problably never used.
+   * This hack is a huge time savings when trimming
+   * gigs of audio data into managable chunks
+   */ 
+  if (input_count == 1 && sox_neffects > 1 && strcmp(sox_effects[1][0].handler.name, "trim") == 0) {
+    if ((files[0]->ft->handler->flags & SOX_FILE_SEEK) && files[0]->ft->seekable){
+      sox_size_t offset = sox_trim_get_start(&sox_effects[1][0]);
+      if (sox_seek(files[0]->ft, offset, SOX_SEEK_SET) != SOX_EOF) { 
+        read_wide_samples = offset / files[0]->ft->signal.channels;
+        /* Assuming a failed seek stayed where it was.  If the 
+         * seek worked then reset the start location of 
+         * trim so that it thinks user didn't request a skip.
+         */ 
+        sox_trim_clear_start(&sox_effects[1][0]);
+      }    
+    }        
+  }    
+}
+
 static void open_output_file(sox_size_t olen)
 {
   sox_loopinfo_t loops[SOX_MAX_NLOOPS];
@@ -1432,7 +1428,7 @@
 
 static sox_size_t total_clips(void)
 {
-  unsigned i, f;
+  unsigned i;
   sox_size_t clips = 0;
   for (i = 0; i < file_count; ++i)
     clips += files[i]->ft->clips + files[i]->volume_clips;
@@ -1595,7 +1591,6 @@
 static void usage_effect(char *effect)
 {
   int i;
-  const sox_effect_handler_t *e;
 
   printf("%s: ", myname);
   printf("v%s\n\n", PACKAGE_VERSION);
@@ -1603,14 +1598,10 @@
   printf("Effect usage:\n\n");
 
   for (i = 0; sox_effect_fns[i]; i++) {
-    e = sox_effect_fns[i]();
-    if (e && e->name && (!strcmp("all", effect) ||  !strcmp(e->name, effect))) {
-      char *p = strstr(e->usage, "Usage: ");
-      printf("%s\n\n", p ? p + 7 : e->usage);
+    const sox_effect_handler_t *e = sox_effect_fns[i]();
+    if (e && e->name && (!strcmp("all", effect) || !strcmp(e->name, effect))) {
+      printf("%s %s\n\n", e->name, e->usage? e->usage : "");
     }
   }
-
-  if (!effect)
-    printf("see --help-effect=effect for effopts ('all' for effopts of all effects)\n\n");
   exit(1);
 }
--- a/src/sox.h
+++ b/src/sox.h
@@ -81,10 +81,10 @@
  *  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   
+ *  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).
  *
@@ -401,10 +401,11 @@
 
 #define SOX_EFF_CHAN     1           /* Effect can alter # of channels */
 #define SOX_EFF_RATE     2           /* Effect can alter sample rate */
-#define SOX_EFF_LENGTH   4           /* Effect can alter audio length */
-#define SOX_EFF_MCHAN    8           /* Effect can handle multi-channel */
-#define SOX_EFF_NULL     16          /* Effect does nothing */
-#define SOX_EFF_DEPRECATED 32        /* Effect is living on borrowed time */
+#define SOX_EFF_PREC     4           /* Effect can alter sample precision */
+#define SOX_EFF_LENGTH   8           /* Effect can alter audio length */
+#define SOX_EFF_MCHAN    16          /* Effect can handle multi-channel */
+#define SOX_EFF_NULL     32          /* Effect does nothing */
+#define SOX_EFF_DEPRECATED 64        /* Effect is living on borrowed time */
 
 typedef struct sox_effect sox_effect_t;
 
@@ -449,6 +450,8 @@
 int sox_effect_set_imin(sox_effect_t * effp, sox_size_t imin);
 int sox_add_effect(sox_effect_t * effp, sox_signalinfo_t * in, sox_signalinfo_t const * out);
 int sox_flow_effects(int (* callback)(sox_bool all_done));
+sox_size_t sox_effects_clips(void);
+sox_size_t sox_stop_effect(sox_size_t e);
 void sox_delete_effects(void);
 
 char const * sox_parsesamples(sox_rate_t rate, const char *str, sox_size_t *samples, int def);
--- a/src/sox_i.h
+++ b/src/sox_i.h
@@ -124,6 +124,7 @@
 #endif
 
 sox_bool strcaseends(char const * str, char const * end);
+sox_bool strends(char const * str, char const * end);
 
 #ifndef HAVE_STRDUP
 char *strdup(const char *s);
@@ -291,6 +292,7 @@
  *-----------------------------------------------------------------------------
  */
 
+int sox_usage(sox_effect_t * effp);
 typedef const sox_effect_handler_t *(*sox_effect_fn_t)(void);
 extern sox_effect_fn_t sox_effect_fns[];
 #define EFFECT(f) extern sox_effect_handler_t const * sox_##f##_effect_fn(void);
--- a/src/speed.c
+++ b/src/speed.c
@@ -47,14 +47,13 @@
       }
     }
   }
-  sox_fail(effp->handler.usage);
-  return SOX_EOF;
+  return sox_usage(effp);
 }
 
 sox_effect_handler_t const *sox_speed_effect_fn(void)
 {
   static sox_effect_handler_t handler = {
-    "speed", "Usage: speed factor[c]", SOX_EFF_NULL|SOX_EFF_LENGTH,
+    "speed", "factor[c]", SOX_EFF_NULL|SOX_EFF_LENGTH,
     getopts, 0, 0, 0, 0, 0};
   return &handler;
 }
--- a/src/stat.c
+++ b/src/stat.c
@@ -320,7 +320,7 @@
 
 static sox_effect_handler_t sox_stat_effect = {
   "stat",
-  "Usage: [ -s N ] [ -rms ] [-freq] [ -v ] [ -d ]",
+  "[ -s N ] [ -rms ] [-freq] [ -v ] [ -d ]",
   SOX_EFF_MCHAN,
   sox_stat_getopts,
   sox_stat_start,
--- a/src/stretch.c
+++ b/src/stretch.c
@@ -72,7 +72,6 @@
  */
 static int sox_stretch_getopts(sox_effect_t * effp, int n, char **argv) 
 {
-  char usage[1024];
   stretch_t stretch = (stretch_t) effp->priv; 
     
   /* default options */
@@ -81,15 +80,13 @@
   stretch->fade = sox_linear_fading;
 
   if (n > 0 && !sscanf(argv[0], "%lf", &stretch->factor)) {
-    sprintf(usage, "%s\n\terror while parsing factor", effp->handler.usage);
-    sox_fail(usage);
-    return SOX_EOF;
+    sox_fail("error while parsing factor");
+    return sox_usage(effp);
   }
 
   if (n > 1 && !sscanf(argv[1], "%lf", &stretch->window)) {
-    sprintf(usage, "%s\n\terror while parsing window size", effp->handler.usage);
-    sox_fail(usage);
-    return SOX_EOF;
+    sox_fail("error while parsing window size");
+    return sox_usage(effp);
   }
 
   if (n > 2) {
@@ -99,9 +96,8 @@
       stretch->fade = sox_linear_fading;
       break;
     default:
-      sprintf (usage, "%s\n\terror while parsing fade type", effp->handler.usage);
-      sox_fail(usage);
-      return SOX_EOF;
+      sox_fail("error while parsing fade type");
+      return sox_usage(effp);
     }
   }
 
@@ -110,15 +106,13 @@
     DEFAULT_FAST_SHIFT_RATIO: DEFAULT_SLOW_SHIFT_RATIO;
  
   if (n > 3 && !sscanf(argv[3], "%lf", &stretch->shift)) {
-    sprintf (usage, "%s\n\terror while parsing shift ratio", effp->handler.usage);
-    sox_fail(usage);
-    return SOX_EOF;
+    sox_fail("error while parsing shift ratio");
+    return sox_usage(effp);
   }
 
   if (stretch->shift > 1.0 || stretch->shift <= 0.0) {
-    sprintf(usage, "%s\n\terror with shift ratio value", effp->handler.usage);
-    sox_fail(usage);
-    return SOX_EOF;
+    sox_fail("error with shift ratio value");
+    return sox_usage(effp);
   }
 
   /* default fading stuff... 
@@ -131,15 +125,13 @@
     stretch->fading = 0.5;
   
   if (n > 4 && !sscanf(argv[4], "%lf", &stretch->fading)) {
-    sprintf(usage, "%s\n\terror while parsing fading ratio", effp->handler.usage);
-    sox_fail(usage);
-    return SOX_EOF;
+    sox_fail("error while parsing fading ratio");
+    return sox_usage(effp);
   }
 
   if (stretch->fading > 0.5 || stretch->fading < 0.0) {
-    sprintf(usage, "%s\n\terror with fading ratio value", effp->handler.usage);
-    sox_fail(usage);
-    return SOX_EOF;
+    sox_fail("error with fading ratio value");
+    return sox_usage(effp);
   }
   
   return SOX_SUCCESS;
@@ -156,19 +148,6 @@
   if (stretch->factor == 1)
     return SOX_EFF_NULL;
 
-  /* FIXME: not necessary. taken care by effect processing? */
-  if (effp->outinfo.channels != effp->ininfo.channels) {
-    sox_fail("stretch cannot handle different channels (in=%d, out=%d)"
-            " use avg or pan", effp->ininfo.channels, effp->outinfo.channels);
-    return SOX_EOF;
-  }
-
-  if (effp->outinfo.rate != effp->ininfo.rate) {
-    sox_fail("stretch cannot handle different rates (in=%ld, out=%ld)"
-            " use resample or rate", effp->ininfo.rate, effp->outinfo.rate);
-    return SOX_EOF;
-  }
-
   stretch->state = input_state;
 
   stretch->size = (int)(effp->outinfo.rate * 0.001 * stretch->window);
@@ -356,7 +335,7 @@
 
 static sox_effect_handler_t sox_stretch_effect = {
   "stretch",
-  "Usage: stretch factor [window fade shift fading]\n"
+  "factor [window fade shift fading]\n"
   "       (expansion, frame in ms, lin/..., unit<1.0, unit<0.5)\n"
   "       (defaults: 1.0 20 lin ...)",
   SOX_EFF_LENGTH,
--- a/src/swap.c
+++ b/src/swap.c
@@ -33,10 +33,7 @@
     {
         swap->def_opts = 0;
         if (n != 2 && n != 4)
-        {
-            sox_fail(effp->handler.usage);
-            return (SOX_EOF);
-        }
+          return sox_usage(effp);
         else if (n == 2)
         {
             sscanf(argv[0],"%d",&swap->order[0]);
@@ -183,7 +180,7 @@
 
 static sox_effect_handler_t sox_swap_effect = {
   "swap",
-  "Usage: swap [1 2 | 1 2 3 4]",
+  "[1 2 | 1 2 3 4]",
   SOX_EFF_MCHAN,
   sox_swap_getopts,
   sox_swap_start,
--- a/src/synth.c
+++ b/src/synth.c
@@ -290,10 +290,8 @@
     synth->length_str = xmalloc(strlen(argv[argn]) + 1);
     strcpy(synth->length_str, argv[argn]);
     /* Do a dummy parse of to see if it will fail */
-    if (sox_parsesamples(0, synth->length_str, &synth->samples_to_do, 't') == NULL) {
-      sox_fail(effp->handler.usage);
-      return SOX_EOF;
-    }
+    if (sox_parsesamples(0, synth->length_str, &synth->samples_to_do, 't') == NULL)
+      return sox_usage(effp);
     argn++;
   }
 
@@ -392,10 +390,8 @@
   synth->samples_done = 0;
 
   if (synth->length_str)
-    if (sox_parsesamples(effp->ininfo.rate, synth->length_str, &synth->samples_to_do, 't') == NULL) {
-      sox_fail(effp->handler.usage);
-      return SOX_EOF;
-    }
+    if (sox_parsesamples(effp->ininfo.rate, synth->length_str, &synth->samples_to_do, 't') == NULL)
+      return sox_usage(effp);
 
   synth->number_of_channels = effp->ininfo.channels;
   synth->channels = xcalloc(synth->number_of_channels, sizeof(*synth->channels));
@@ -600,8 +596,8 @@
 {
   static sox_effect_handler_t handler = {
     "synth",
-    "Usage: synth [len] {type [combine] [freq[-freq2] [off [ph [p1 [p2 [p3]]]]]]}",
-    SOX_EFF_MCHAN, getopts, start, flow, 0, stop, kill
+    "[len] {type [combine] [freq[-freq2] [off [ph [p1 [p2 [p3]]]]]]}",
+    SOX_EFF_MCHAN | SOX_EFF_PREC, getopts, start, flow, 0, stop, kill
   };
   return &handler;
 }
--- a/src/tremolo.c
+++ b/src/tremolo.c
@@ -28,10 +28,8 @@
   if (n < 1 || n > 2 ||
       sscanf(argv[0], "%lf %c", &speed, &dummy) != 1 || speed < 0 ||
       (n > 1 && sscanf(argv[1], "%lf %c", &depth, &dummy) != 1) ||
-      depth <= 0 || depth > 100) {
-    sox_fail(effp->handler.usage);
-    return SOX_EOF;
-  }
+      depth <= 0 || depth > 100)
+    return sox_usage(effp);
   args[2] = argv[0];
   sprintf(offset, "%g", 100 - depth / 2);
   args[3] = offset;
@@ -43,7 +41,7 @@
   static sox_effect_handler_t handler;
   handler = *sox_synth_effect_fn();
   handler.name = "tremolo";
-  handler.usage = "Usage: tremolo speed_Hz [depth_percent]";
+  handler.usage = "speed_Hz [depth_percent]";
   handler.getopts = getopts;
   return &handler;
 }
--- a/src/trim.c
+++ b/src/trim.c
@@ -40,24 +40,16 @@
             strcpy(trim->length_str,argv[1]);
             /* Do a dummy parse to see if it will fail */
             if (sox_parsesamples(0, trim->length_str, &trim->length, 't') == NULL)
-            {
-                sox_fail(effp->handler.usage);
-                return(SOX_EOF);
-            }
+              return sox_usage(effp);
         case 1:
             trim->start_str = (char *)xmalloc(strlen(argv[0])+1);
             strcpy(trim->start_str,argv[0]);
             /* Do a dummy parse to see if it will fail */
             if (sox_parsesamples(0, trim->start_str, &trim->start, 't') == NULL)
-            {
-                sox_fail(effp->handler.usage);
-                return(SOX_EOF);
-            }
+              return sox_usage(effp);
             break;
         default:
-            sox_fail(effp->handler.usage);
-            return SOX_EOF;
-            break;
+            return sox_usage(effp);
 
     }
     return (SOX_SUCCESS);
@@ -72,10 +64,7 @@
 
     if (sox_parsesamples(effp->ininfo.rate, trim->start_str,
                         &trim->start, 't') == NULL)
-    {
-        sox_fail(effp->handler.usage);
-        return(SOX_EOF);
-    }
+      return sox_usage(effp);
     /* Account for # of channels */
     trim->start *= effp->ininfo.channels;
 
@@ -83,10 +72,7 @@
     {
         if (sox_parsesamples(effp->ininfo.rate, trim->length_str,
                     &trim->length, 't') == NULL)
-        {
-            sox_fail(effp->handler.usage);
-            return(SOX_EOF);
-        }
+          return sox_usage(effp);
     }
     else
         trim->length = 0;
@@ -185,7 +171,7 @@
 
 static sox_effect_handler_t sox_trim_effect = {
   "trim",
-  "Usage: trim start [length]",
+  "start [length]",
   SOX_EFF_MCHAN|SOX_EFF_LENGTH,
   sox_trim_getopts,
   sox_trim_start,
--- a/src/vibro.c
+++ b/src/vibro.c
@@ -28,10 +28,8 @@
   if (n < 1 || n > 2 ||
       sscanf(argv[0], "%lf %c", &speed, &dummy) != 1 || speed < 0 ||
       (n > 1 && sscanf(argv[1], "%lf %c", &depth, &dummy) != 1) ||
-      depth <= 0 || depth > 1) {
-    sox_fail(effp->handler.usage);
-    return SOX_EOF;
-  }
+      depth <= 0 || depth > 1)
+    return sox_usage(effp);
   args[2] = argv[0];
   sprintf(offset, "%g", 100 - 50 * depth);
   args[3] = offset;
@@ -43,7 +41,7 @@
   static sox_effect_handler_t handler;
   handler = *sox_synth_effect_fn();
   handler.name = "vibro";
-  handler.usage = "Usage: vibro speed [depth]";
+  handler.usage = "speed [depth]";
   handler.getopts = getopts;
   handler.flags |= SOX_EFF_DEPRECATED;
   return &handler;
--- a/src/vol.c
+++ b/src/vol.c
@@ -8,7 +8,7 @@
  * FIXME: deprecate or remove the limiter in favour of compand.
  */
 #define vol_usage \
-  "Usage: vol GAIN [TYPE [LIMITERGAIN]]\n" \
+  "GAIN [TYPE [LIMITERGAIN]]\n" \
   "\t(default TYPE=amplitude: 1 is constant, < 0 change phase;\n" \
   "\tTYPE=power 1 is constant; TYPE=dB: 0 is constant, +6 doubles ampl.)\n" \
   "\tThe peak limiter has a gain much less than 1 (e.g. 0.05 or 0.02) and\n" \
@@ -51,10 +51,8 @@
   vol->uselimiter = sox_false; /* Default is no limiter. */
   
   /* Get the vol, and the type if it's in the same arg. */
-  if (!argc || (have_type = sscanf(argv[0], "%lf %10s %c", &vol->gain, type_string, &dummy) - 1) > 1) {
-    sox_fail(effp->handler.usage);
-    return SOX_EOF;
-  }
+  if (!argc || (have_type = sscanf(argv[0], "%lf %10s %c", &vol->gain, type_string, &dummy) - 1) > 1)
+    return sox_usage(effp);
   ++argv, --argc;
 
   /* No type yet? Get it from the next arg: */
@@ -66,10 +64,8 @@
 
   if (have_type) {
     enum_item const * p = find_enum_text(type_ptr, vol_types);
-    if (!p) {
-      sox_fail(effp->handler.usage);
-      return SOX_EOF;
-    }
+    if (!p)
+      return sox_usage(effp);
     switch (p->value) {
       case vol_dB: vol->gain = exp(vol->gain*LOG_10_20); break;
       case vol_power: /* power to amplitude, keep phase change */
@@ -79,10 +75,8 @@
   }
 
   if (argc) {
-    if (fabs(vol->gain) < 1 || sscanf(*argv, "%lf %c", &vol->limitergain, &dummy) != 1 || vol->limitergain <= 0 || vol->limitergain >= 1) {
-      sox_fail(effp->handler.usage);
-      return SOX_EOF;                  
-    }
+    if (fabs(vol->gain) < 1 || sscanf(*argv, "%lf %c", &vol->limitergain, &dummy) != 1 || vol->limitergain <= 0 || vol->limitergain >= 1)
+      return sox_usage(effp);
     
     vol->uselimiter = sox_true;
     /* The following equation is derived so that there is no