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...",