shithub: sox

Download patch

ref: bbc06d6285e6a0fb59fbee906c9ce1b1580ecaf3
parent: 4aa76b22c3cdd8ae415bf8f9a1b196e505fa2bae
author: robs <robs>
date: Sat Feb 17 15:43:45 EST 2007

vol parser improvements

--- a/ChangeLog
+++ b/ChangeLog
@@ -18,6 +18,7 @@
 
   o Added soft-knee companding.  (robs)
   o Show (with --octave) compand transfer function.  (robs)
+  o Allow e.g. "vol 6dB" (as well as "vol 6 dB").  (robs)
 
   Other new features:
 
--- a/sox.1
+++ b/sox.1
@@ -2123,7 +2123,7 @@
 it.  A value of 8000s will wait until 8000 samples are read before
 starting to process audio.
 .TP
-\fBvol \fIgain\fR [\fItype\fR [\fIlimitergain\fR]]
+\fBvol \fIgain\fR[[ ]\fItype\fR [\fIlimitergain\fR]]
 Apply an amplification or an attenuation to the audio signal.
 Unlike the
 .B \-v
--- a/src/vol.c
+++ b/src/vol.c
@@ -6,90 +6,100 @@
  * Cannot handle different number of channels.
  * Cannot handle rate change.
  */
+#define vol_usage \
+  "Usage: vol 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 is\n" \
+  "\tonly used on peaks (to prevent clipping); default is no limiter."
 
 #include "st_i.h"
 
 #include <math.h>   /* exp(), sqrt() */
 
-static st_effect_t st_vol_effect;
-
 #define LOG_10_20 ((double)(0.1151292546497022842009e0))
 
 typedef struct {
     double gain; /* amplitude gain. */
     
-    int uselimiter; /* boolean: are we using the limiter? */
+    st_bool uselimiter;
     double limiterthreshhold;
-    double limitergain; /* limiter gain. */
+    double limitergain;
     int limited; /* number of limited values to report. */
     int totalprocessed;
 } * vol_t;
 
+enum {VOL_amplitude, VOL_dB, VOL_power};
+
+static enum_item const vol_types[] = {
+  ENUM_ITEM(VOL_,amplitude)
+  ENUM_ITEM(VOL_,dB)
+  ENUM_ITEM(VOL_,power)
+  {0, 0}};
+
 /*
  * Process options: gain (float) type (amplitude, power, dB)
  */
-static int st_vol_getopts(eff_t effp, int n, char **argv) 
+static int getopts(eff_t effp, int n, char **argv) 
 {
-    vol_t vol = (vol_t) effp->priv; 
-    vol->gain = 1.0; /* default is no change */
-    vol->uselimiter = 0; /* default is no limiter */
-    
-    if (n && (!sscanf(argv[0], "%lf", &vol->gain)))
-    {
-        st_fail(st_vol_effect.usage);
-        return ST_EOF;
-    }
+  vol_t vol = (vol_t) effp->priv; 
+  char string[11];
+  char * q = string;
+  char dummy;          /* To check for extraneous chars. */
+  unsigned have_type;
 
-    /* adjust gain depending on type (what a great parser;-) */
-    if (n>1) 
-    {
-        switch (argv[1][0]) 
-        {
-        case 'd': /* decibels to amplitude */
-        case 'D':
-            vol->gain = exp(vol->gain*LOG_10_20);
-            break;
-        case 'p':
-        case 'P': /* power to amplitude, keep phase change */
-            if (vol->gain > 0.0)
-                vol->gain = sqrt(vol->gain);
-            else
-                vol->gain = -sqrt(-vol->gain);
-            break;
-        case 'a': /* amplitude */
-        case 'A':
-        default:
-            break;
-        }
+  vol->gain = 1;       /* Default is no change. */
+  vol->uselimiter = st_false; /* Default is no limiter. */
+  
+  if (!n || (have_type = sscanf(argv[0], "%lf %10s %c", &vol->gain, string, &dummy) - 1) > 1) {
+    st_fail(effp->h->usage);
+    return ST_EOF;
+  }
+  ++argv, --n;
+
+  if (!have_type && n) {
+    ++have_type;
+    q = *argv;
+    ++argv, --n;
+  }
+
+  if (have_type) {
+    enum_item const * p = find_enum_text(q, vol_types);
+    if (!p) {
+      st_fail(effp->h->usage);
+      return ST_EOF;
     }
-    
+    switch (p->value) {
+      case VOL_dB: vol->gain = exp(vol->gain*LOG_10_20); break;
+      case VOL_power: /* power to amplitude, keep phase change */
+        vol->gain = vol->gain > 0 ? sqrt(vol->gain) : -sqrt(-vol->gain);
+        break;
+    }
+  }
 
-    if (n>2)
-    {
-        if ((fabs(vol->gain) < 1.0) || !sscanf(argv[2], "%lf", &vol->limitergain) || !((vol->limitergain > 0.0) && (vol->limitergain < 1.0)))
-        {
-                st_fail(st_vol_effect.usage);
-                return ST_EOF;                  
-        }
-        
-        vol->uselimiter = 1; /* ok, we'll use it */
-        /* The following equation is derived so that there is no 
-         * discontinuity in output amplitudes */
-        /* and a ST_SAMPLE_MAX input always maps to a ST_SAMPLE_MAX output 
-         * when the limiter is activated. */
-        /* (NOTE: There **WILL** be a discontinuity in the slope 
-         * of the output amplitudes when using the limiter.) */
-        vol->limiterthreshhold = ST_SAMPLE_MAX * (1.0 - vol->limitergain) / (fabs(vol->gain) - vol->limitergain);
+  if (n) {
+    if (fabs(vol->gain) < 1 || sscanf(*argv, "%lf %c", &vol->limitergain, &dummy) != 1 || vol->limitergain <= 0 || vol->limitergain >= 1) {
+      st_fail(effp->h->usage);
+      return ST_EOF;                  
     }
     
-
-    return ST_SUCCESS;
+    vol->uselimiter = st_true;
+    /* The following equation is derived so that there is no 
+     * discontinuity in output amplitudes */
+    /* and a ST_SAMPLE_MAX input always maps to a ST_SAMPLE_MAX output 
+     * when the limiter is activated. */
+    /* (NOTE: There **WILL** be a discontinuity in the slope 
+     * of the output amplitudes when using the limiter.) */
+    vol->limiterthreshhold = ST_SAMPLE_MAX * (1.0 - vol->limitergain) / (fabs(vol->gain) - vol->limitergain);
+  }
+  st_debug("mult=%g limit=%g", vol->gain, vol->limitergain);
+  return ST_SUCCESS;
 }
 
 /*
  * Start processing
  */
-static int st_vol_start(eff_t effp)
+static int start(eff_t effp)
 {
     vol_t vol = (vol_t) effp->priv;
     
@@ -117,7 +127,7 @@
 /*
  * Process data.
  */
-static int st_vol_flow(eff_t effp, const st_sample_t *ibuf, st_sample_t *obuf, 
+static int flow(eff_t effp, const st_sample_t *ibuf, st_sample_t *obuf, 
                 st_size_t *isamp, st_size_t *osamp)
 {
     vol_t vol = (vol_t) effp->priv;
@@ -175,38 +185,20 @@
     return ST_SUCCESS;
 }
 
-/*
- * Do anything required when you stop reading samples.  
- * Don't close input file! 
- */
-static int st_vol_stop(eff_t effp)
+static int stop(eff_t effp)
 {
-    vol_t vol = (vol_t) effp->priv;
-    if (vol->limited)
-    {
-        st_warn("limited %d values (%d percent).", 
-             vol->limited, (int) (vol->limited * 100.0 / vol->totalprocessed));
-    }
-    return ST_SUCCESS;
+  vol_t vol = (vol_t) effp->priv;
+  if (vol->limited) {
+    st_warn("limited %d values (%d percent).", 
+         vol->limited, (int) (vol->limited * 100.0 / vol->totalprocessed));
+  }
+  return ST_SUCCESS;
 }
 
-static st_effect_t st_vol_effect = {
-  "vol",
-  "Usage: vol gain [ type [ limitergain ] ]"
-  "       (default type=amplitude: 1.0 is constant, <0.0 change phase;\n"
-  "       type=power 1.0 is constant; type=dB: 0.0 is constant, +6 doubles ampl.)\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)",
-  ST_EFF_MCHAN,
-  st_vol_getopts,
-  st_vol_start,
-  st_vol_flow,
-  st_effect_nothing_drain,
-  st_vol_stop,
-  st_effect_nothing
-};
-
-const st_effect_t *st_vol_effect_fn(void)
+st_effect_t const * st_vol_effect_fn(void)
 {
-    return &st_vol_effect;
+  static st_effect_t driver = {
+    "vol", vol_usage, ST_EFF_MCHAN, getopts, start, flow, 0, stop, 0
+  };
+  return &driver;
 }