shithub: sox

Download patch

ref: a55757bb3bd2a5ba60c5b1ae3eb9f2317287563e
parent: 796aea8705015d43aeab9ab5a44f0c3f58aa0a32
author: cbagwell <cbagwell>
date: Thu Sep 7 14:43:04 EDT 2000

Adding volume limiting code.

--- a/Changelog
+++ b/Changelog
@@ -80,6 +80,7 @@
   o Matthias Nutt helped add support for specifying multiple effects
     to SoX on the command line.
   o Curt Zirzow added a trim effect to trim off audio data.
+  o Updated ALSA driver to support new interface. Jimen Ching 
 
 sox-12.16
 ---------
--- a/sox.1
+++ b/sox.1
@@ -116,7 +116,7 @@
 .br
     \fBvibro\fR \fIspeed\fR [ \fIdepth\fR ]
 .br
-    \fBvol\fR \fIgain\fR [ \fItype\fR ]
+    \fBvol\fR \fIgain\fR [ \fItype\fR [ \fIlimitergain\fR ] ] 
 .SH DESCRIPTION
 .I SoX
 is a command line program that can convert most popular audio files
@@ -1026,10 +1026,13 @@
 by the sine wave,
 ranging 0.0 to 1.0 and defaulting to 0.5.
 .TP 10
-vol \fIgain \fB [ \fItype\fB ]
+vol \fIgain\fR [ \fItype\fB [ \fIlimitergain\fR ] ]
 The vol effect is much like the command line option -v.  It allows you to
 adjust the volume of an input file and allows you to specify the adjustment
-in relation to amplitude, power, or dB.  When type is 
+in relation to amplitude, power, or dB.  If \fItype\fR is not specified then
+it defaults to \fIamplitude\fR.
+.br 
+When type is 
 .I amplitude
 then a linear change of the amplitude is performed based on the gain.  Therefore,
 a value of 1.0 will keep the volume the same, 0.0 to < 1.0 will cause the
@@ -1043,8 +1046,15 @@
 .br
 When type is 
 .I dB
-the amplitude is change logarithmically.
+the amplitude is changed logarithmically.
 0.0 is constant while +6 doubles the amplitude.
+.br
+An optional \fIlimitergain\fR value can be specified and should be a
+value much less
+then 1.0 (ie 0.05 or 0.02) and is used only on peaks to prevent clipping.
+Not specifying this parameter will cause no limiter to be used.  In verbose
+mode, this effect will display the percentage of audio data that needed to be
+limited.
 .SH BUGS
 The syntax is horrific.  Thats the breaks when trying to handle all things from the command line.
 .P
--- a/src/vol.c
+++ b/src/vol.c
@@ -28,12 +28,21 @@
 #define TWENTY	  ((VOL_FLOAT)(20.0e0))
 
 #define VOL_USAGE \
-    "Usage: vol gain type" \
+    "Usage: vol gain [ type [ limitergain ] ]" \
     " (default type=amplitude: 1.0 is constant, <0.0 change phase;" \
-    " type=power 1.0 is constant; type=dB: 0.0 is constant, +6 doubles ampl.)"
+    " type=power 1.0 is constant; type=dB: 0.0 is constant, +6 doubles ampl.)" \
+    " The peak limiter has a gain much less than 1.0 (ie 0.05 or 0.02) which is only" \
+    " used on peaks to prevent clipping. (default is no limiter)"
 
 typedef struct {
     VOL_FLOAT gain; /* amplitude gain. */
+    
+    int uselimiter; /* boolean: are we using the limiter? */
+    VOL_FLOAT limiterthreshhold;
+    VOL_FLOAT limitergain; /* limiter gain. */
+    int limited; /* number of limited values to report. */
+    int totalprocessed;
+    
     int clipped;    /* number of clipped values to report. */
 } * vol_t;
 
@@ -46,8 +55,8 @@
 char **argv;
 {
     vol_t vol = (vol_t) effp->priv; 
-    
     vol->gain = ONE; /* default is no change */
+    vol->uselimiter = 0; /* default is no limiter */
     
     if (n && (!sscanf(argv[0], VOL_FLOAT_SCAN, &vol->gain)))
     {
@@ -77,7 +86,24 @@
 	    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 LONG_MAX input always maps to a LONG_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 = LONG_MAX * (ONE - vol->limitergain) / (fabs(vol->gain) - vol->limitergain);
+    }
+    
+
     return ST_SUCCESS;
 }
 
@@ -103,6 +129,8 @@
     }
 
     vol->clipped = 0;
+    vol->limited = 0;
+    vol->totalprocessed = 0;
 
     return ST_SUCCESS;
 }
@@ -141,6 +169,8 @@
 {
     vol_t vol = (vol_t) effp->priv;
     register VOL_FLOAT gain = vol->gain;
+    register VOL_FLOAT limiterthreshhold = vol->limiterthreshhold;
+    register VOL_FLOAT sample;
     register LONG len;
     
     len = MIN(*osamp, *isamp);
@@ -148,10 +178,38 @@
     /* report back dealt with amount. */
     *isamp = len; *osamp = len;
     
-    /* quite basic, with clipping */
-    for (;len>0; len--)
-	*obuf++ = clip(vol, gain * *ibuf++);
+    if (vol->uselimiter)
+    {
+	vol->totalprocessed += len;
+	
+	for (;len>0; len--)
+	    {
+	    	sample = *ibuf++;
+	    	
+	    	if (sample > limiterthreshhold)
+	    	{
+	    		sample =  (LONG_MAX - vol->limitergain * (LONG_MAX - sample));
+	    		vol->limited++;
+	    	}
+	    	else if (sample < -limiterthreshhold)
+	    	{
+	    		sample = -(LONG_MAX - vol->limitergain * (LONG_MAX + sample));
+	    		vol->limited++;
+	    	}
+	    	else
+	    	{
+	    		sample = gain * sample;
+	    	}
 
+		*obuf++ = clip(vol, sample);
+	    }
+    }
+    else
+    {
+    	/* quite basic, with clipping */
+    	for (;len>0; len--)
+		*obuf++ = clip(vol, gain * *ibuf++);
+    }
     return ST_SUCCESS;
 }
 
@@ -163,6 +221,11 @@
 eff_t effp;
 {
     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));
+    }
     if (vol->clipped) 
     {
 	st_warn("VOL clipped %d values, amplitude gain=%f too high...",