summaryrefslogtreecommitdiffstats
path: root/Modules/audioop.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/audioop.c')
-rw-r--r--Modules/audioop.c310
1 files changed, 154 insertions, 156 deletions
diff --git a/Modules/audioop.c b/Modules/audioop.c
index 9ab4834..5c69258 100644
--- a/Modules/audioop.c
+++ b/Modules/audioop.c
@@ -26,6 +26,21 @@ typedef short PyInt16;
#endif
#endif
+static const int maxvals[] = {0, 0x7F, 0x7FFF, 0x7FFFFF, 0x7FFFFFFF};
+static const int minvals[] = {0, -0x80, -0x8000, -0x800000, -0x80000000};
+static const unsigned int masks[] = {0, 0xFF, 0xFFFF, 0xFFFFFF, 0xFFFFFFFF};
+
+static int
+fbound(double val, double minval, double maxval)
+{
+ if (val > maxval)
+ val = maxval;
+ else if (val < minval + 1)
+ val = minval;
+ return val;
+}
+
+
/* Code shamelessly stolen from sox, 12.17.7, g711.c
** (c) Craig Reese, Joe Campbell and Jeff Poskanzer 1989 */
@@ -347,7 +362,7 @@ audioop_max(PyObject *self, PyObject *args)
signed char *cp;
Py_ssize_t len, i;
int size, val = 0;
- int max = 0;
+ unsigned int absval, max = 0;
if ( !PyArg_ParseTuple(args, "s#i:max", &cp, &len, &size) )
return 0;
@@ -357,10 +372,11 @@ audioop_max(PyObject *self, PyObject *args)
if ( size == 1 ) val = (int)*CHARP(cp, i);
else if ( size == 2 ) val = (int)*SHORTP(cp, i);
else if ( size == 4 ) val = (int)*LONGP(cp, i);
- if ( val < 0 ) val = (-val);
- if ( val > max ) max = val;
+ if (val < 0) absval = (-val);
+ else absval = val;
+ if (absval > max) max = absval;
}
- return PyLong_FromLong(max);
+ return PyLong_FromUnsignedLong(max);
}
static PyObject *
@@ -369,7 +385,7 @@ audioop_minmax(PyObject *self, PyObject *args)
signed char *cp;
Py_ssize_t len, i;
int size, val = 0;
- int min = 0x7fffffff, max = -0x7fffffff;
+ int min = 0x7fffffff, max = -0x80000000;
if (!PyArg_ParseTuple(args, "s#i:minmax", &cp, &len, &size))
return NULL;
@@ -406,7 +422,7 @@ audioop_avg(PyObject *self, PyObject *args)
if ( len == 0 )
val = 0;
else
- val = (int)(avg / (double)(len/size));
+ val = (int)floor(avg / (double)(len/size));
return PyLong_FromLong(val);
}
@@ -416,6 +432,7 @@ audioop_rms(PyObject *self, PyObject *args)
signed char *cp;
Py_ssize_t len, i;
int size, val = 0;
+ unsigned int res;
double sum_squares = 0.0;
if ( !PyArg_ParseTuple(args, "s#i:rms", &cp, &len, &size) )
@@ -429,10 +446,10 @@ audioop_rms(PyObject *self, PyObject *args)
sum_squares += (double)val*(double)val;
}
if ( len == 0 )
- val = 0;
+ res = 0;
else
- val = (int)sqrt(sum_squares / (double)(len/size));
- return PyLong_FromLong(val);
+ res = (unsigned int)sqrt(sum_squares / (double)(len/size));
+ return PyLong_FromUnsignedLong(res);
}
static double _sum2(short *a, short *b, Py_ssize_t len)
@@ -624,52 +641,46 @@ audioop_avgpp(PyObject *self, PyObject *args)
Py_ssize_t len, i;
int size, val = 0, prevval = 0, prevextremevalid = 0,
prevextreme = 0;
- double avg = 0.0;
- int diff, prevdiff, extremediff, nextreme = 0;
+ double sum = 0.0;
+ unsigned int avg;
+ int diff, prevdiff, nextreme = 0;
if ( !PyArg_ParseTuple(args, "s#i:avgpp", &cp, &len, &size) )
return 0;
if (!audioop_check_parameters(len, size))
return NULL;
- /* Compute first delta value ahead. Also automatically makes us
- ** skip the first extreme value
- */
+ if (len <= size)
+ return PyLong_FromLong(0);
if ( size == 1 ) prevval = (int)*CHARP(cp, 0);
else if ( size == 2 ) prevval = (int)*SHORTP(cp, 0);
else if ( size == 4 ) prevval = (int)*LONGP(cp, 0);
- if ( size == 1 ) val = (int)*CHARP(cp, size);
- else if ( size == 2 ) val = (int)*SHORTP(cp, size);
- else if ( size == 4 ) val = (int)*LONGP(cp, size);
- prevdiff = val - prevval;
-
+ prevdiff = 17; /* Anything != 0, 1 */
for ( i=size; i<len; i+= size) {
if ( size == 1 ) val = (int)*CHARP(cp, i);
else if ( size == 2 ) val = (int)*SHORTP(cp, i);
else if ( size == 4 ) val = (int)*LONGP(cp, i);
- diff = val - prevval;
- if ( diff*prevdiff < 0 ) {
- /* Derivative changed sign. Compute difference to last
- ** extreme value and remember.
- */
- if ( prevextremevalid ) {
- extremediff = prevval - prevextreme;
- if ( extremediff < 0 )
- extremediff = -extremediff;
- avg += extremediff;
- nextreme++;
+ if (val != prevval) {
+ diff = val < prevval;
+ if (prevdiff == !diff) {
+ /* Derivative changed sign. Compute difference to last
+ ** extreme value and remember.
+ */
+ if (prevextremevalid) {
+ sum += fabs((double)prevval - (double)prevextreme);
+ nextreme++;
+ }
+ prevextremevalid = 1;
+ prevextreme = prevval;
}
- prevextremevalid = 1;
- prevextreme = prevval;
- }
- prevval = val;
- if ( diff != 0 )
+ prevval = val;
prevdiff = diff;
+ }
}
if ( nextreme == 0 )
- val = 0;
+ avg = 0;
else
- val = (int)(avg / (double)nextreme);
- return PyLong_FromLong(val);
+ avg = (unsigned int)(sum / (double)nextreme);
+ return PyLong_FromUnsignedLong(avg);
}
static PyObject *
@@ -679,48 +690,47 @@ audioop_maxpp(PyObject *self, PyObject *args)
Py_ssize_t len, i;
int size, val = 0, prevval = 0, prevextremevalid = 0,
prevextreme = 0;
- int max = 0;
- int diff, prevdiff, extremediff;
+ unsigned int max = 0, extremediff;
+ int diff, prevdiff;
if ( !PyArg_ParseTuple(args, "s#i:maxpp", &cp, &len, &size) )
return 0;
if (!audioop_check_parameters(len, size))
return NULL;
- /* Compute first delta value ahead. Also automatically makes us
- ** skip the first extreme value
- */
+ if (len <= size)
+ return PyLong_FromLong(0);
if ( size == 1 ) prevval = (int)*CHARP(cp, 0);
else if ( size == 2 ) prevval = (int)*SHORTP(cp, 0);
else if ( size == 4 ) prevval = (int)*LONGP(cp, 0);
- if ( size == 1 ) val = (int)*CHARP(cp, size);
- else if ( size == 2 ) val = (int)*SHORTP(cp, size);
- else if ( size == 4 ) val = (int)*LONGP(cp, size);
- prevdiff = val - prevval;
-
+ prevdiff = 17; /* Anything != 0, 1 */
for ( i=size; i<len; i+= size) {
if ( size == 1 ) val = (int)*CHARP(cp, i);
else if ( size == 2 ) val = (int)*SHORTP(cp, i);
else if ( size == 4 ) val = (int)*LONGP(cp, i);
- diff = val - prevval;
- if ( diff*prevdiff < 0 ) {
- /* Derivative changed sign. Compute difference to
- ** last extreme value and remember.
- */
- if ( prevextremevalid ) {
- extremediff = prevval - prevextreme;
- if ( extremediff < 0 )
- extremediff = -extremediff;
- if ( extremediff > max )
- max = extremediff;
+ if (val != prevval) {
+ diff = val < prevval;
+ if (prevdiff == !diff) {
+ /* Derivative changed sign. Compute difference to
+ ** last extreme value and remember.
+ */
+ if (prevextremevalid) {
+ if (prevval < prevextreme)
+ extremediff = (unsigned int)prevextreme -
+ (unsigned int)prevval;
+ else
+ extremediff = (unsigned int)prevval -
+ (unsigned int)prevextreme;
+ if ( extremediff > max )
+ max = extremediff;
+ }
+ prevextremevalid = 1;
+ prevextreme = prevval;
}
- prevextremevalid = 1;
- prevextreme = prevval;
- }
- prevval = val;
- if ( diff != 0 )
+ prevval = val;
prevdiff = diff;
+ }
}
- return PyLong_FromLong(max);
+ return PyLong_FromUnsignedLong(max);
}
static PyObject *
@@ -755,7 +765,7 @@ audioop_mul(PyObject *self, PyObject *args)
signed char *cp, *ncp;
Py_ssize_t len, i;
int size, val = 0;
- double factor, fval, maxval;
+ double factor, fval, maxval, minval;
PyObject *rv;
if ( !PyArg_ParseTuple(args, "s#id:mul", &cp, &len, &size, &factor ) )
@@ -763,13 +773,8 @@ audioop_mul(PyObject *self, PyObject *args)
if (!audioop_check_parameters(len, size))
return NULL;
- if ( size == 1 ) maxval = (double) 0x7f;
- else if ( size == 2 ) maxval = (double) 0x7fff;
- else if ( size == 4 ) maxval = (double) 0x7fffffff;
- else {
- PyErr_SetString(AudioopError, "Size should be 1, 2 or 4");
- return 0;
- }
+ maxval = (double) maxvals[size];
+ minval = (double) minvals[size];
rv = PyBytes_FromStringAndSize(NULL, len);
if ( rv == 0 )
@@ -782,9 +787,7 @@ audioop_mul(PyObject *self, PyObject *args)
else if ( size == 2 ) val = (int)*SHORTP(cp, i);
else if ( size == 4 ) val = (int)*LONGP(cp, i);
fval = (double)val*factor;
- if ( fval > maxval ) fval = maxval;
- else if ( fval < -maxval ) fval = -maxval;
- val = (int)fval;
+ val = (int)floor(fbound(fval, minval, maxval));
if ( size == 1 ) *CHARP(ncp, i) = (signed char)val;
else if ( size == 2 ) *SHORTP(ncp, i) = (short)val;
else if ( size == 4 ) *LONGP(ncp, i) = (Py_Int32)val;
@@ -799,7 +802,7 @@ audioop_tomono(PyObject *self, PyObject *args)
signed char *cp, *ncp;
Py_ssize_t len, i;
int size, val1 = 0, val2 = 0;
- double fac1, fac2, fval, maxval;
+ double fac1, fac2, fval, maxval, minval;
PyObject *rv;
if ( !PyArg_ParseTuple(args, "s*idd:tomono",
@@ -817,14 +820,8 @@ audioop_tomono(PyObject *self, PyObject *args)
return NULL;
}
- if ( size == 1 ) maxval = (double) 0x7f;
- else if ( size == 2 ) maxval = (double) 0x7fff;
- else if ( size == 4 ) maxval = (double) 0x7fffffff;
- else {
- PyBuffer_Release(&pcp);
- PyErr_SetString(AudioopError, "Size should be 1, 2 or 4");
- return 0;
- }
+ maxval = (double) maxvals[size];
+ minval = (double) minvals[size];
rv = PyBytes_FromStringAndSize(NULL, len/2);
if ( rv == 0 ) {
@@ -842,9 +839,7 @@ audioop_tomono(PyObject *self, PyObject *args)
else if ( size == 2 ) val2 = (int)*SHORTP(cp, i+2);
else if ( size == 4 ) val2 = (int)*LONGP(cp, i+4);
fval = (double)val1*fac1 + (double)val2*fac2;
- if ( fval > maxval ) fval = maxval;
- else if ( fval < -maxval ) fval = -maxval;
- val1 = (int)fval;
+ val1 = (int)floor(fbound(fval, minval, maxval));
if ( size == 1 ) *CHARP(ncp, i/2) = (signed char)val1;
else if ( size == 2 ) *SHORTP(ncp, i/2) = (short)val1;
else if ( size == 4 ) *LONGP(ncp, i/2)= (Py_Int32)val1;
@@ -859,7 +854,7 @@ audioop_tostereo(PyObject *self, PyObject *args)
signed char *cp, *ncp;
Py_ssize_t len, i;
int size, val1, val2, val = 0;
- double fac1, fac2, fval, maxval;
+ double fac1, fac2, fval, maxval, minval;
PyObject *rv;
if ( !PyArg_ParseTuple(args, "s#idd:tostereo",
@@ -868,13 +863,8 @@ audioop_tostereo(PyObject *self, PyObject *args)
if (!audioop_check_parameters(len, size))
return NULL;
- if ( size == 1 ) maxval = (double) 0x7f;
- else if ( size == 2 ) maxval = (double) 0x7fff;
- else if ( size == 4 ) maxval = (double) 0x7fffffff;
- else {
- PyErr_SetString(AudioopError, "Size should be 1, 2 or 4");
- return 0;
- }
+ maxval = (double) maxvals[size];
+ minval = (double) minvals[size];
if (len > PY_SSIZE_T_MAX/2) {
PyErr_SetString(PyExc_MemoryError,
@@ -894,14 +884,10 @@ audioop_tostereo(PyObject *self, PyObject *args)
else if ( size == 4 ) val = (int)*LONGP(cp, i);
fval = (double)val*fac1;
- if ( fval > maxval ) fval = maxval;
- else if ( fval < -maxval ) fval = -maxval;
- val1 = (int)fval;
+ val1 = (int)floor(fbound(fval, minval, maxval));
fval = (double)val*fac2;
- if ( fval > maxval ) fval = maxval;
- else if ( fval < -maxval ) fval = -maxval;
- val2 = (int)fval;
+ val2 = (int)floor(fbound(fval, minval, maxval));
if ( size == 1 ) *CHARP(ncp, i*2) = (signed char)val1;
else if ( size == 2 ) *SHORTP(ncp, i*2) = (short)val1;
@@ -919,7 +905,7 @@ audioop_add(PyObject *self, PyObject *args)
{
signed char *cp1, *cp2, *ncp;
Py_ssize_t len1, len2, i;
- int size, val1 = 0, val2 = 0, maxval, newval;
+ int size, val1 = 0, val2 = 0, minval, maxval, newval;
PyObject *rv;
if ( !PyArg_ParseTuple(args, "s#s#i:add",
@@ -932,13 +918,8 @@ audioop_add(PyObject *self, PyObject *args)
return 0;
}
- if ( size == 1 ) maxval = 0x7f;
- else if ( size == 2 ) maxval = 0x7fff;
- else if ( size == 4 ) maxval = 0x7fffffff;
- else {
- PyErr_SetString(AudioopError, "Size should be 1, 2 or 4");
- return 0;
- }
+ maxval = maxvals[size];
+ minval = minvals[size];
rv = PyBytes_FromStringAndSize(NULL, len1);
if ( rv == 0 )
@@ -954,12 +935,19 @@ audioop_add(PyObject *self, PyObject *args)
else if ( size == 2 ) val2 = (int)*SHORTP(cp2, i);
else if ( size == 4 ) val2 = (int)*LONGP(cp2, i);
- newval = val1 + val2;
- /* truncate in case of overflow */
- if (newval > maxval) newval = maxval;
- else if (newval < -maxval) newval = -maxval;
- else if (size == 4 && (newval^val1) < 0 && (newval^val2) < 0)
- newval = val1 > 0 ? maxval : - maxval;
+ if (size < 4) {
+ newval = val1 + val2;
+ /* truncate in case of overflow */
+ if (newval > maxval)
+ newval = maxval;
+ else if (newval < minval)
+ newval = minval;
+ }
+ else {
+ double fval = (double)val1 + (double)val2;
+ /* truncate in case of overflow */
+ newval = (int)floor(fbound(fval, minval, maxval));
+ }
if ( size == 1 ) *CHARP(ncp, i) = (signed char)newval;
else if ( size == 2 ) *SHORTP(ncp, i) = (short)newval;
@@ -973,9 +961,9 @@ audioop_bias(PyObject *self, PyObject *args)
{
signed char *cp, *ncp;
Py_ssize_t len, i;
- int size, val = 0;
+ int size, bias;
+ unsigned int val = 0, mask;
PyObject *rv;
- int bias;
if ( !PyArg_ParseTuple(args, "s#ii:bias",
&cp, &len, &size , &bias) )
@@ -989,15 +977,20 @@ audioop_bias(PyObject *self, PyObject *args)
return 0;
ncp = (signed char *)PyBytes_AsString(rv);
+ mask = masks[size];
for ( i=0; i < len; i += size ) {
- if ( size == 1 ) val = (int)*CHARP(cp, i);
- else if ( size == 2 ) val = (int)*SHORTP(cp, i);
- else if ( size == 4 ) val = (int)*LONGP(cp, i);
+ if ( size == 1 ) val = (unsigned int)(unsigned char)*CHARP(cp, i);
+ else if ( size == 2 ) val = (unsigned int)(unsigned short)*SHORTP(cp, i);
+ else if ( size == 4 ) val = (unsigned int)(Py_UInt32)*LONGP(cp, i);
+
+ val += (unsigned int)bias;
+ /* wrap around in case of overflow */
+ val &= mask;
- if ( size == 1 ) *CHARP(ncp, i) = (signed char)(val+bias);
- else if ( size == 2 ) *SHORTP(ncp, i) = (short)(val+bias);
- else if ( size == 4 ) *LONGP(ncp, i) = (Py_Int32)(val+bias);
+ if ( size == 1 ) *CHARP(ncp, i) = (signed char)(unsigned char)val;
+ else if ( size == 2 ) *SHORTP(ncp, i) = (short)(unsigned short)val;
+ else if ( size == 4 ) *LONGP(ncp, i) = (Py_Int32)(Py_UInt32)val;
}
return rv;
}
@@ -1024,15 +1017,15 @@ audioop_reverse(PyObject *self, PyObject *args)
ncp = (unsigned char *)PyBytes_AsString(rv);
for ( i=0; i < len; i += size ) {
- if ( size == 1 ) val = ((int)*CHARP(cp, i)) << 8;
- else if ( size == 2 ) val = (int)*SHORTP(cp, i);
- else if ( size == 4 ) val = ((int)*LONGP(cp, i)) >> 16;
+ if ( size == 1 ) val = ((int)*CHARP(cp, i)) << 24;
+ else if ( size == 2 ) val = ((int)*SHORTP(cp, i)) << 16;
+ else if ( size == 4 ) val = (int)*LONGP(cp, i);
j = len - i - size;
- if ( size == 1 ) *CHARP(ncp, j) = (signed char)(val >> 8);
- else if ( size == 2 ) *SHORTP(ncp, j) = (short)(val);
- else if ( size == 4 ) *LONGP(ncp, j) = (Py_Int32)(val<<16);
+ if ( size == 1 ) *CHARP(ncp, j) = (signed char)(val >> 24);
+ else if ( size == 2 ) *SHORTP(ncp, j) = (short)(val >> 16);
+ else if ( size == 4 ) *LONGP(ncp, j) = (Py_Int32)val;
}
return rv;
}
@@ -1066,13 +1059,13 @@ audioop_lin2lin(PyObject *self, PyObject *args)
ncp = (unsigned char *)PyBytes_AsString(rv);
for ( i=0, j=0; i < len; i += size, j += size2 ) {
- if ( size == 1 ) val = ((int)*CHARP(cp, i)) << 8;
- else if ( size == 2 ) val = (int)*SHORTP(cp, i);
- else if ( size == 4 ) val = ((int)*LONGP(cp, i)) >> 16;
+ if ( size == 1 ) val = ((int)*CHARP(cp, i)) << 24;
+ else if ( size == 2 ) val = ((int)*SHORTP(cp, i)) << 16;
+ else if ( size == 4 ) val = (int)*LONGP(cp, i);
- if ( size2 == 1 ) *CHARP(ncp, j) = (signed char)(val >> 8);
- else if ( size2 == 2 ) *SHORTP(ncp, j) = (short)(val);
- else if ( size2 == 4 ) *LONGP(ncp, j) = (Py_Int32)(val<<16);
+ if ( size2 == 1 ) *CHARP(ncp, j) = (signed char)(val >> 24);
+ else if ( size2 == 2 ) *SHORTP(ncp, j) = (short)(val >> 16);
+ else if ( size2 == 4 ) *LONGP(ncp, j) = (Py_Int32)val;
}
return rv;
}
@@ -1136,6 +1129,10 @@ audioop_ratecv(PyObject *self, PyObject *args)
d = gcd(inrate, outrate);
inrate /= d;
outrate /= d;
+ /* divide weightA and weightB by their greatest common divisor */
+ d = gcd(weightA, weightB);
+ weightA /= d;
+ weightA /= d;
if ((size_t)nchannels > PY_SIZE_MAX/sizeof(int)) {
PyErr_SetString(PyExc_MemoryError,
@@ -1175,7 +1172,9 @@ audioop_ratecv(PyObject *self, PyObject *args)
}
/* str <- Space for the output buffer. */
- {
+ if (len == 0)
+ str = PyBytes_FromStringAndSize(NULL, 0);
+ else {
/* There are len input frames, so we need (mathematically)
ceiling(len*outrate/inrate) output frames, and each frame
requires bytes_per_frame bytes. Computing this
@@ -1190,12 +1189,11 @@ audioop_ratecv(PyObject *self, PyObject *args)
else
str = PyBytes_FromStringAndSize(NULL,
q * outrate * bytes_per_frame);
-
- if (str == NULL) {
- PyErr_SetString(PyExc_MemoryError,
- "not enough memory for output buffer");
- goto exit;
- }
+ }
+ if (str == NULL) {
+ PyErr_SetString(PyExc_MemoryError,
+ "not enough memory for output buffer");
+ goto exit;
}
ncp = PyBytes_AsString(str);
@@ -1229,32 +1227,32 @@ audioop_ratecv(PyObject *self, PyObject *args)
for (chan = 0; chan < nchannels; chan++) {
prev_i[chan] = cur_i[chan];
if (size == 1)
- cur_i[chan] = ((int)*CHARP(cp, 0)) << 8;
+ cur_i[chan] = ((int)*CHARP(cp, 0)) << 24;
else if (size == 2)
- cur_i[chan] = (int)*SHORTP(cp, 0);
+ cur_i[chan] = ((int)*SHORTP(cp, 0)) << 16;
else if (size == 4)
- cur_i[chan] = ((int)*LONGP(cp, 0)) >> 16;
+ cur_i[chan] = (int)*LONGP(cp, 0);
cp += size;
/* implements a simple digital filter */
- cur_i[chan] =
- (weightA * cur_i[chan] +
- weightB * prev_i[chan]) /
- (weightA + weightB);
+ cur_i[chan] = (int)(
+ ((double)weightA * (double)cur_i[chan] +
+ (double)weightB * (double)prev_i[chan]) /
+ ((double)weightA + (double)weightB));
}
len--;
d += outrate;
}
while (d >= 0) {
for (chan = 0; chan < nchannels; chan++) {
- cur_o = (prev_i[chan] * d +
- cur_i[chan] * (outrate - d)) /
- outrate;
+ cur_o = (int)(((double)prev_i[chan] * (double)d +
+ (double)cur_i[chan] * (double)(outrate - d)) /
+ (double)outrate);
if (size == 1)
- *CHARP(ncp, 0) = (signed char)(cur_o >> 8);
+ *CHARP(ncp, 0) = (signed char)(cur_o >> 24);
else if (size == 2)
- *SHORTP(ncp, 0) = (short)(cur_o);
+ *SHORTP(ncp, 0) = (short)(cur_o >> 16);
else if (size == 4)
- *LONGP(ncp, 0) = (Py_Int32)(cur_o<<16);
+ *LONGP(ncp, 0) = (Py_Int32)(cur_o);
ncp += size;
}
d -= inrate;