shithub: sox

Download patch

ref: 8b360a4b6a348b39abee0ec67f014269ba056d7a
parent: 6dc1e9a8f6d2325513083c003a8de04467b09d10
author: robs <robs>
date: Sun Jan 28 14:22:28 EST 2007

Reinstate effects nullification.

--- a/ChangeLog
+++ b/ChangeLog
@@ -91,6 +91,9 @@
   o Fixed a bug introduced in 12.18.2 that stopped the draining
     of effects from occuring.  This had stopped the reverse effect,
     among others, from working.  (Reuben Thomas)
+  o Several effects are now optimised out in situations where they need
+    do nothing, e.g. changing rate from 8000 to 8000, or changing volume
+    by 0dB [Bug# 1395781].  (robs)
   o Fix rounding error when reading command-line time
     parameters. (robs)
   o Fix nul file hander ignoring other format options if rate
--- a/src/biquads.c
+++ b/src/biquads.c
@@ -227,6 +227,8 @@
       break;
 
     case filter_peakingEQ: /* H(s) = (s^2 + s*(A/Q) + 1) / (s^2 + s/(A*Q) + 1) */
+      if (A == 1)
+        return ST_EFF_NULL;
       p->b0 =   1 + alpha*A;
       p->b1 =  -2*cos(w0);
       p->b2 =   1 - alpha*A;
@@ -236,6 +238,8 @@
       break;
 
     case filter_lowShelf: /* H(s) = A * (s^2 + (sqrt(A)/Q)*s + A)/(A*s^2 + (sqrt(A)/Q)*s + 1) */
+      if (A == 1)
+        return ST_EFF_NULL;
       p->b0 =    A*( (A+1) - (A-1)*cos(w0) + 2*sqrt(A)*alpha );
       p->b1 =  2*A*( (A-1) - (A+1)*cos(w0)                   );
       p->b2 =    A*( (A+1) - (A-1)*cos(w0) - 2*sqrt(A)*alpha );
@@ -245,6 +249,8 @@
       break;
 
     case filter_highShelf: /* H(s) = A * (A*s^2 + (sqrt(A)/Q)*s + 1)/(s^2 + (sqrt(A)/Q)*s + A) */
+      if (!A)
+        return ST_EFF_NULL;
       p->b0 =    A*( (A+1) + (A-1)*cos(w0) + 2*sqrt(A)*alpha );
       p->b1 = -2*A*( (A-1) + (A+1)*cos(w0)                   );
       p->b2 =    A*( (A+1) + (A-1)*cos(w0) - 2*sqrt(A)*alpha );
--- a/src/dcshift.c
+++ b/src/dcshift.c
@@ -76,6 +76,9 @@
 {
     dcs_t dcs = (dcs_t) effp->priv;
 
+    if (dcs->dcshift == 0)
+      return ST_EFF_NULL;
+
     if (effp->outinfo.channels != effp->ininfo.channels) {
         st_fail("DCSHIFT cannot handle different channels (in=%d, out=%d)"
              " use avg or pan", effp->ininfo.channels, effp->outinfo.channels);
--- a/src/dither.c
+++ b/src/dither.c
@@ -61,19 +61,10 @@
     return ST_SUCCESS;
   } else if (effp->outinfo.size == ST_SIZE_16BIT)
     return ST_SUCCESS;
-  else if (effp->outinfo.size == ST_SIZE_24BIT) {
-    dither->amount /= 256;
-    return ST_SUCCESS;
-  } else if (effp->outinfo.size == ST_SIZE_64BIT) {
-    dither->amount /= 16384;
-    return ST_SUCCESS;
-  }
 
-  st_fail("Invalid size %d", effp->outinfo.size);
-  return ST_EOF;
+  return ST_EFF_NULL;   /* Dithering not needed at >= 24 bits */
 }
 
-/* FIXME: Scale noise more sensibly for sizes >= 24 bits */
 static int flow(eff_t effp, const st_sample_t * ibuf,
     st_sample_t * obuf, st_size_t * isamp, st_size_t * osamp)
 {
--- a/src/fade.c
+++ b/src/fade.c
@@ -187,6 +187,9 @@
 
     st_debug("fade: in_start = %d in_stop = %d out_start = %d out_stop = %d", fade->in_start, fade->in_stop, fade->out_start, fade->out_stop);
 
+    if (fade->in_start == fade->in_stop && fade->out_start == fade->out_stop)
+      return ST_EFF_NULL;
+
     return ST_SUCCESS;
 }
 
--- a/src/mixer.c
+++ b/src/mixer.c
@@ -206,10 +206,8 @@
      /* Handle the special-case flags */
      switch (mixer->mix) {
          case MIX_CENTER:
-             if (ichan == ochan) {
-                 st_fail("Output must have different number of channels to use mixer effect");
-                 return(ST_EOF);
-             }
+             if (ichan == ochan)
+               return ST_EFF_NULL;
              break;             /* Code below will handle this case */
          case MIX_LEFT:
              if (ichan == 2 && ochan == 1)
@@ -500,7 +498,19 @@
          return ST_EOF;
      }
 
+#if 0  /* TODO: test the following: */
+     if (effp->ininfo.channels != effp->outinfo.channels)
+       return ST_SUCCESS;
+
+     for (i = 0; i < (int)effp->ininfo.channels; ++i)
+       for (j = 0; j < (int)effp->outinfo.channels; ++j)
+         if (avg->sources[i][j] != (i == j))
+           return ST_SUCCESS;
+
+     return ST_EFF_NULL;
+#else
      return ST_SUCCESS;
+#endif
 }
 
 /*
--- a/src/pad.c
+++ b/src/pad.c
@@ -72,10 +72,14 @@
 static int start(eff_t effp)
 {
   pad_t p = (pad_t) effp->priv;
+  int i;
 
   parse(effp, 0, effp->ininfo.rate); /* Re-parse now rate is known */
   p->in_pos = p->pad_pos = p->pads_pos = 0;
-  return ST_SUCCESS;
+  for (i = 0; i < p->npads; ++i)
+    if (p->pads[i].pad)
+      return ST_SUCCESS;
+  return ST_EFF_NULL;
 }
 
 static int flow(eff_t effp, const st_sample_t * ibuf, st_sample_t * obuf,
--- a/src/pitch.c
+++ b/src/pitch.c
@@ -433,6 +433,9 @@
         return ST_EOF;
     }
 
+    if (pitch->shift == 0)
+      return ST_EFF_NULL;
+
     return ST_SUCCESS;
 }
 
--- a/src/polyphas.c
+++ b/src/polyphas.c
@@ -346,6 +346,9 @@
     int total, size, uprate;
     int k;
 
+    if (effp->ininfo.rate == effp->outinfo.rate)
+      return ST_EFF_NULL;
+
     rate->lcmrate = st_lcm((st_sample_t)effp->ininfo.rate,
                            (st_sample_t)effp->outinfo.rate);
 
--- a/src/rabbit.c
+++ b/src/rabbit.c
@@ -92,6 +92,9 @@
   double in_rate = floor(effp->ininfo.rate / effp->globalinfo->speed + .5)
     * effp->globalinfo->speed;
 
+  if (in_rate == effp->outinfo.rate)
+    return ST_EFF_NULL;
+          
   if (effp->ininfo.channels != effp->outinfo.channels) {
     st_fail("number of Input and Output channels must be equal to use rabbit effect");
     return ST_EOF;
--- a/src/repeat.c
+++ b/src/repeat.c
@@ -59,6 +59,9 @@
 {
         repeat_t repeat = (repeat_t)effp->priv;
 
+        if (repeat->repeats == 0)
+          return ST_EFF_NULL;
+
         if ((repeat->fp = tmpfile()) == NULL) {
                 st_fail("repeat: could not create temporary file");
                 return (ST_EOF);
--- a/src/resample.c
+++ b/src/resample.c
@@ -204,6 +204,9 @@
   double in_rate = floor(effp->ininfo.rate / effp->globalinfo->speed + .5)
     * effp->globalinfo->speed;
 
+  if (in_rate == effp->outinfo.rate)
+    return ST_EFF_NULL;
+          
   r->Factor = (double) effp->outinfo.rate / in_rate;
 
   gcdrate = st_gcd((long) effp->ininfo.rate, (long) effp->outinfo.rate);
--- a/src/sox.c
+++ b/src/sox.c
@@ -1108,10 +1108,6 @@
     memcpy(&efftabR[neffects], e, sizeof(*e));
   else memset(&efftabR[neffects], 0, sizeof(*e));
 
-  st_report("Effects chain: %-10s %-6s %uHz", e->name,
-      e->ininfo.channels < 2? "mono" :
-      (e->h->flags & ST_EFF_MCHAN)? "multi" : "stereo", e->ininfo.rate);
-
   ++neffects;
 }
 
@@ -1198,21 +1194,48 @@
 
 static int start_all_effects(void)
 {
-  int e, ret = ST_SUCCESS;
+  int i, j, ret = ST_SUCCESS;
 
-  for (e = 1; e < neffects; e++) {
-    int (*start)(eff_t effp) =
-       efftab[e].h->start? efftab[e].h->start : st_effect_nothing;
-    efftab[e].clips = 0;
-    if ((ret = start(&efftab[e])) == ST_EOF)
-      break;
-    if (efftabR[e].name) {
-      efftabR[e].clips = 0;
-      if ((ret = start(&efftabR[e])) != ST_SUCCESS)
-        break;
+  for (i = 1; i < neffects; i++) {
+    struct st_effect * e = &efftab[i];
+    st_bool is_always_null = (e->h->flags & ST_EFF_NULL) != 0;
+    int (*start)(eff_t effp) = e->h->start? e->h->start : st_effect_nothing;
+
+    if (is_always_null)
+      st_report("'%s' has no effect (is a proxy effect)", e->name);
+    else {
+      e->clips = 0;
+      ret = start(e);
+      if (ret == ST_EFF_NULL)
+        st_warn("'%s' has no effect in this configuration", e->name);
+      else if (ret != ST_SUCCESS)
+        return ST_EOF;
     }
+    if (is_always_null || ret == ST_EFF_NULL) { /* remove from the chain */
+      int (*delete)(eff_t effp) = e->h->delete? e->h->delete: st_effect_nothing;
+
+      /* No left & right delete as there is no left & right getopts */
+      delete(e);
+      --neffects;
+      for (j = i--; j < neffects; ++j) {
+        efftab[j] = efftab[j + 1];
+        efftabR[j] = efftabR[j + 1];
+      }
+    }
+    /* No null checks here; the left channel looks after this */
+    else if (efftabR[i].name) {
+      efftabR[i].clips = 0;
+      if (start(&efftabR[i]) != ST_SUCCESS)
+        return ST_EOF;
+    }
   }
-  return ret;
+  for (i = 1; i < neffects; ++i) {
+    struct st_effect * e = &efftab[i];
+    st_report("Effects chain: %-10s %-6s %uHz", e->name,
+        e->ininfo.channels < 2 ? "mono" :
+        (e->h->flags & ST_EFF_MCHAN)? "multi" : "stereo", e->ininfo.rate);
+  }
+  return ST_SUCCESS;
 }
 
 static int flow_effect_out(void)
@@ -1545,15 +1568,16 @@
 
     stop(&efftab[e]);
     clips = efftab[e].clips;
-    delete(&efftab[e]);
 
     if (efftabR[e].name) {
       stop(&efftabR[e]);
       clips += efftab[e].clips;
-      delete(&efftabR[e]);
     }
     if (clips != 0)
-      st_warn("%s clipped %u samples; decrease volume?", efftab[e].name, clips);
+      st_warn("'%s' clipped %u samples; decrease volume?",efftab[e].name,clips);
+
+    /* No left & right delete as there is no left & right getopts */
+    delete(&efftab[e]);
   }
 }
 
--- a/src/speed.c
+++ b/src/speed.c
@@ -54,14 +54,6 @@
 st_effect_t const *st_speed_effect_fn(void)
 {
   static st_effect_t driver = {
-    "speed", "Usage: speed factor[c]",
-    ST_EFF_MCHAN,
-    getopts,
-    st_effect_nothing,
-    st_effect_nothing_flow,
-    st_effect_nothing_drain,
-    st_effect_nothing,
-    st_effect_nothing
-  };
+    "speed", "Usage: speed factor[c]", ST_EFF_NULL, getopts, 0, 0, 0, 0, 0};
   return &driver;
 }
--- a/src/st.h
+++ b/src/st.h
@@ -342,6 +342,7 @@
 #define ST_EFF_MCHAN    4           /* Effect can handle multi-channel */
 #define ST_EFF_REPORT   8           /* Effect does not affect the audio */
 #define ST_EFF_DEPRECATED 16        /* Effect is living on borrowed time */
+#define ST_EFF_NULL     32          /* Effect does nothing */
 
 /*
  * Handler structure for each effect.
--- a/src/stretch.c
+++ b/src/stretch.c
@@ -155,6 +155,9 @@
   stretch_t stretch = (stretch_t)effp->priv;
   st_size_t i;
 
+  if (stretch->factor == 1)
+    return ST_EFF_NULL;
+
   /* FIXME: not necessary. taken care by effect processing? */
   if (effp->outinfo.channels != effp->ininfo.channels) {
     st_fail("stretch cannot handle different channels (in=%d, out=%d)"
--- a/src/swap.c
+++ b/src/swap.c
@@ -65,6 +65,7 @@
 static int st_swap_start(eff_t effp)
 {
     swap_t swap = (swap_t) effp->priv;
+    int i;
 
     if (effp->outinfo.channels == 1)
     {
@@ -121,7 +122,11 @@
 
     }
 
-    return ST_SUCCESS;
+    for (i = 0; i < (int)effp->outinfo.channels; ++i)
+      if (swap->order[i] != i)
+        return ST_SUCCESS;
+
+    return ST_EFF_NULL;
 }
 
 /*
--- a/src/vol.c
+++ b/src/vol.c
@@ -93,6 +93,9 @@
 {
     vol_t vol = (vol_t) effp->priv;
     
+    if (vol->gain == 1)
+      return ST_EFF_NULL;
+
     if (effp->outinfo.channels != effp->ininfo.channels) {
         st_fail("vol cannot handle different channels (in %d, out %d)"
              " use avg or pan", effp->ininfo.channels, effp->outinfo.channels);