shithub: sox

Download patch

ref: b6faa22c951f34b6b1c3d983b475c183069cf2ed
parent: abed578324ce19ac81024f2aeb1b5dea8dc74e17
author: cbagwell <cbagwell>
date: Mon Sep 13 19:32:49 EDT 2004

Fix MIN overflow in volume change.

--- a/Changelog
+++ b/Changelog
@@ -36,6 +36,12 @@
     audio files and do a crossfade between them.
   o Fixed bug in fade effect were it was impossible to do a
     fadeout starting from the beginning of the audio file.
+  o Removed rounding error when changing volume of audio with
+    "-v" option.  This error caused doing a "-v -1.0" twice
+    to not result in the original file.
+  o Fixed bug in volume changes (both -v and "vol" effect)
+    were an overflow could occur on the negative side
+    because it wasn't accounting for MIN being (-MAX)-1.
 
 sox-12.17.5
 -----------
--- a/src/vol.c
+++ b/src/vol.c
@@ -21,10 +21,10 @@
 
 /* constants
  */
-#define ZERO	  ((VOL_FLOAT)(0.0e0))
+#define ZERO      ((VOL_FLOAT)(0.0e0))
 #define LOG_10_20 ((VOL_FLOAT)(0.1151292546497022842009e0))
-#define ONE	  ((VOL_FLOAT)(1.0e0))
-#define TWENTY	  ((VOL_FLOAT)(20.0e0))
+#define ONE       ((VOL_FLOAT)(1.0e0))
+#define TWENTY    ((VOL_FLOAT)(20.0e0))
 
 #define VOL_USAGE \
     "Usage: vol gain [ type [ limitergain ] ]" \
@@ -56,50 +56,50 @@
     
     if (n && (!sscanf(argv[0], VOL_FLOAT_SCAN, &vol->gain)))
     {
-	st_fail(VOL_USAGE);
-	return ST_EOF;
+        st_fail(VOL_USAGE);
+        return ST_EOF;
     }
 
     /* 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 > ZERO)
-		vol->gain = sqrt(vol->gain);
-	    else
-		vol->gain = -sqrt(-vol->gain);
-	    break;
-	case 'a': /* amplitude */
-	case 'A':
-	default:
-	    break;
-	}
+        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 > ZERO)
+                vol->gain = sqrt(vol->gain);
+            else
+                vol->gain = -sqrt(-vol->gain);
+            break;
+        case 'a': /* amplitude */
+        case 'A':
+        default:
+            break;
+        }
     }
     
 
     if (n>2)
     {
-    	if ((fabs(vol->gain) < ONE) || !sscanf(argv[2], VOL_FLOAT_SCAN, &vol->limitergain) || !((vol->limitergain > ZERO) && (vol->limitergain < ONE)))
-    	{
-  		st_fail(VOL_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 * (ONE - vol->limitergain) / (fabs(vol->gain) - vol->limitergain);
+        if ((fabs(vol->gain) < ONE) || !sscanf(argv[2], VOL_FLOAT_SCAN, &vol->limitergain) || !((vol->limitergain > ZERO) && (vol->limitergain < ONE)))
+        {
+                st_fail(VOL_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 * (ONE - vol->limitergain) / (fabs(vol->gain) - vol->limitergain);
     }
     
 
@@ -115,15 +115,15 @@
     
     if (effp->outinfo.channels != effp->ininfo.channels)
     {
-	st_warn("VOL cannot handle different channels (in=%d, out=%d)"
-	     " use avg or pan", effp->ininfo.channels, effp->outinfo.channels);
+        st_warn("VOL cannot handle different channels (in=%d, out=%d)"
+             " use avg or pan", effp->ininfo.channels, effp->outinfo.channels);
     }
 
     if (effp->outinfo.rate != effp->ininfo.rate)
     {
-	st_fail("VOL cannot handle different rates (in=%ld, out=%ld)"
-	     " use resample or rate", effp->ininfo.rate, effp->outinfo.rate);
-	return ST_EOF;
+        st_fail("VOL cannot handle different rates (in=%ld, out=%ld)"
+             " use resample or rate", effp->ininfo.rate, effp->outinfo.rate);
+        return ST_EOF;
     }
 
     vol->clipped = 0;
@@ -141,13 +141,13 @@
 {
     if (v > ST_SAMPLE_MAX)
     {
-	 vol->clipped++;
-	 return ST_SAMPLE_MAX;
+         vol->clipped++;
+         return ST_SAMPLE_MAX;
     }
-    else if (v < -ST_SAMPLE_MAX)
+    else if (v < ST_SAMPLE_MIN)
     {
-	vol->clipped++;
-	return -ST_SAMPLE_MAX;
+        vol->clipped++;
+        return ST_SAMPLE_MIN;
     }
     /* else */
     return (st_sample_t) v;
@@ -176,35 +176,41 @@
     
     if (vol->uselimiter)
     {
-	vol->totalprocessed += len;
-	
-	for (;len>0; len--)
-	    {
-	    	sample = *ibuf++;
-	    	
-	    	if (sample > limiterthreshhold)
-	    	{
-	    		sample =  (ST_SAMPLE_MAX - vol->limitergain * (ST_SAMPLE_MAX - sample));
-	    		vol->limited++;
-	    	}
-	    	else if (sample < -limiterthreshhold)
-	    	{
-	    		sample = -(ST_SAMPLE_MAX - vol->limitergain * (ST_SAMPLE_MAX + sample));
-	    		vol->limited++;
-	    	}
-	    	else
-	    	{
-	    		sample = gain * sample;
-	    	}
-
-		*obuf++ = clip(vol, sample);
-	    }
+        vol->totalprocessed += len;
+        
+        for (;len>0; len--)
+            {
+                sample = *ibuf++;
+                
+                if (sample > limiterthreshhold)
+                {
+                        sample =  (ST_SAMPLE_MAX - vol->limitergain * (ST_SAMPLE_MAX - sample));
+                        vol->limited++;
+                }
+                else if (sample < -limiterthreshhold)
+                {
+                        sample = -(ST_SAMPLE_MAX - vol->limitergain * (ST_SAMPLE_MAX + sample));
+                        /* FIXME: MIN is (-MAX)-1 so need to make sure we
+                         * don't go over that.  Probably could do this
+                         * check inside the above equation but I didn't
+                         * think it thru.
+                         */
+                        if (sample < ST_SAMPLE_MIN)
+                            sample = ST_SAMPLE_MIN;
+                        vol->limited++;
+                } else
+                {
+                        sample = gain * sample;
+                }
+
+                *obuf++ = clip(vol, sample);
+            }
     }
     else
     {
-    	/* quite basic, with clipping */
-    	for (;len>0; len--)
-		*obuf++ = clip(vol, gain * *ibuf++);
+        /* quite basic, with clipping */
+        for (;len>0; len--)
+                *obuf++ = clip(vol, gain * *ibuf++);
     }
     return ST_SUCCESS;
 }
@@ -218,13 +224,13 @@
     vol_t vol = (vol_t) effp->priv;
     if (vol->limited)
     {
-	st_warn("VOL limited %d values (%d percent).", 
-	     vol->limited, (int) (vol->limited * 100.0 / vol->totalprocessed));
+        st_warn("VOL limited %d values (%d percent).", 
+             vol->limited, (int) (vol->limited * 100.0 / vol->totalprocessed));
     }
     if (vol->clipped) 
     {
-	st_warn("VOL clipped %d values, amplitude gain=%f too high...", 
-	     vol->clipped, vol->gain);
+        st_warn("VOL clipped %d values, amplitude gain=%f too high...", 
+             vol->clipped, vol->gain);
     }
     return ST_SUCCESS;
 }