Changes by Sjoerd (reformatted).

add(): better handling of overflow (substitute maxval instead of
throwing away higher order bits).

ratecv(): some bugfixes, Sjoerd says.
This commit is contained in:
Guido van Rossum 1997-02-14 16:14:03 +00:00
parent 6fb6f10a96
commit 1851a67695
1 changed files with 106 additions and 95 deletions

View File

@ -781,7 +781,7 @@ audioop_add(self, args)
PyObject *args; PyObject *args;
{ {
signed char *cp1, *cp2, *ncp; signed char *cp1, *cp2, *ncp;
int len1, len2, size, val1 = 0, val2 = 0; int len1, len2, size, val1 = 0, val2 = 0, maxval, newval;
PyObject *rv; PyObject *rv;
int i; int i;
@ -794,17 +794,19 @@ audioop_add(self, args)
return 0; return 0;
} }
if ( size != 1 && size != 2 && size != 4) { 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"); PyErr_SetString(AudioopError, "Size should be 1, 2 or 4");
return 0; return 0;
} }
rv = PyString_FromStringAndSize(NULL, len1); rv = PyString_FromStringAndSize(NULL, len1);
if ( rv == 0 ) if ( rv == 0 )
return 0; return 0;
ncp = (signed char *)PyString_AsString(rv); ncp = (signed char *)PyString_AsString(rv);
for ( i=0; i < len1; i += size ) { for ( i=0; i < len1; i += size ) {
if ( size == 1 ) val1 = (int)*CHARP(cp1, i); if ( size == 1 ) val1 = (int)*CHARP(cp1, i);
else if ( size == 2 ) val1 = (int)*SHORTP(cp1, i); else if ( size == 2 ) val1 = (int)*SHORTP(cp1, i);
@ -814,9 +816,16 @@ audioop_add(self, args)
else if ( size == 2 ) val2 = (int)*SHORTP(cp2, i); else if ( size == 2 ) val2 = (int)*SHORTP(cp2, i);
else if ( size == 4 ) val2 = (int)*LONGP(cp2, i); else if ( size == 4 ) val2 = (int)*LONGP(cp2, i);
if ( size == 1 ) *CHARP(ncp, i) = (signed char)(val1+val2); newval = val1 + val2;
else if ( size == 2 ) *SHORTP(ncp, i) = (short)(val1+val2); /* truncate in case of overflow */
else if ( size == 4 ) *LONGP(ncp, i) = (long)(val1+val2); 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 == 1 ) *CHARP(ncp, i) = (signed char)newval;
else if ( size == 2 ) *SHORTP(ncp, i) = (short)newval;
else if ( size == 4 ) *LONGP(ncp, i) = (long)newval;
} }
return rv; return rv;
} }
@ -938,119 +947,121 @@ audioop_lin2lin(self, args)
static PyObject * static PyObject *
audioop_ratecv(self, args) audioop_ratecv(self, args)
PyObject *self; PyObject *self;
PyObject *args; PyObject *args;
{ {
signed char *cp; char *cp, *ncp;
unsigned char *ncp; int len, size, nchannels, inrate, outrate, weightA, weightB;
int len, size, nchannels, inrate, outrate, weightA, weightB; int chan, d, *prev_i, *cur_i, cur_o;
int chan, d, *prev_i, *cur_i, cur_o; PyObject *state, *samps, *str, *rv;
PyObject *state, *samps, *str, *rv;
weightA = 1; weightA = 1;
weightB = 0; weightB = 0;
if (!PyArg_ParseTuple(args, "s#iiiiO|ii", &cp, &len, &size, &nchannels, if (!PyArg_ParseTuple(args, "s#iiiiO|ii", &cp, &len, &size, &nchannels,
&inrate, &outrate, &state, &weightA, &weightB)) &inrate, &outrate, &state, &weightA, &weightB))
return NULL; return NULL;
if (size != 1 && size != 2 && size != 4) { if (size != 1 && size != 2 && size != 4) {
PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); PyErr_SetString(AudioopError, "Size should be 1, 2 or 4");
return NULL; return NULL;
} }
if (nchannels < 1) { if (nchannels < 1) {
PyErr_SetString(AudioopError, "# of channels should be >= 1"); PyErr_SetString(AudioopError, "# of channels should be >= 1");
return NULL; return NULL;
} }
if (weightA < 1 || weightB < 0) { if (weightA < 1 || weightB < 0) {
PyErr_SetString(AudioopError, PyErr_SetString(AudioopError,
"weightA should be >= 1, weightB should be >= 0"); "weightA should be >= 1, weightB should be >= 0");
return NULL; return NULL;
} }
prev_i = malloc(nchannels * sizeof(int)); if (len % (size * nchannels) != 0) {
cur_i = malloc(nchannels * sizeof(int)); PyErr_SetString(AudioopError, "not a whole number of frames");
len = len / size; /* # of frames */ return NULL;
}
if (state == Py_None) { prev_i = malloc(nchannels * sizeof(int));
d = -outrate; cur_i = malloc(nchannels * sizeof(int));
for (chan = 0; chan < nchannels; chan++) len /= size * nchannels; /* # of frames */
prev_i[chan] = cur_i[chan] = 0;
} else { if (state == Py_None) {
if (!PyArg_ParseTuple(state, d = -outrate;
"iO!;audioop.ratecv: illegal state argument", for (chan = 0; chan < nchannels; chan++)
&d, &PyTuple_Type, &samps)) prev_i[chan] = cur_i[chan] = 0;
return NULL; } else {
if (PyTuple_Size(samps) != nchannels) { if (!PyArg_ParseTuple(state,
PyErr_SetString(AudioopError, "iO!;audioop.ratecv: illegal state argument",
&d, &PyTuple_Type, &samps))
return NULL;
if (PyTuple_Size(samps) != nchannels) {
PyErr_SetString(AudioopError,
"illegal state argument"); "illegal state argument");
return NULL; return NULL;
} }
for (chan = 0; chan < nchannels; chan++) { for (chan = 0; chan < nchannels; chan++) {
if (!PyArg_ParseTuple(PyTuple_GetItem(samps, chan), if (!PyArg_ParseTuple(PyTuple_GetItem(samps, chan),
"ii",&prev_i[chan],&cur_i[chan])) "ii",&prev_i[chan],&cur_i[chan]))
return NULL; return NULL;
} }
} }
str = PyString_FromStringAndSize(NULL, str = PyString_FromStringAndSize(
size * (len * outrate + inrate - 1) / inrate); NULL, size * nchannels * (len * outrate + inrate - 1) / inrate);
if (str == NULL) if (str == NULL)
return NULL; return NULL;
ncp = PyString_AsString(str); ncp = PyString_AsString(str);
for (;;) { for (;;) {
while (d < 0) { while (d < 0) {
if (len == 0) { if (len == 0) {
samps = PyTuple_New(nchannels); samps = PyTuple_New(nchannels);
for (chan = 0; chan < nchannels; chan++) for (chan = 0; chan < nchannels; chan++)
PyTuple_SetItem(samps, chan, PyTuple_SetItem(samps, chan,
Py_BuildValue("(ii)", Py_BuildValue("(ii)",
prev_i[chan], prev_i[chan],
cur_i[chan])); cur_i[chan]));
if (PyErr_Occurred()) if (PyErr_Occurred())
return NULL; return NULL;
if (_PyString_Resize(&str, if (_PyString_Resize(&str,
ncp - (unsigned char *) ncp - PyString_AsString(str)) < 0)
PyString_AsString(str)) < 0)
return NULL; return NULL;
rv = Py_BuildValue("(O(iO))", str, d, samps); rv = Py_BuildValue("(O(iO))", str, d, samps);
Py_DECREF(samps); Py_DECREF(samps);
Py_DECREF(str); Py_DECREF(str);
return rv; return rv;
} }
for (chan = 0; chan < nchannels; chan++) { for (chan = 0; chan < nchannels; chan++) {
prev_i[chan] = cur_i[chan]; prev_i[chan] = cur_i[chan];
if (size == 1) if (size == 1)
cur_i[chan] = cur_i[chan] = ((int)*CHARP(cp, 0)) << 8;
((int)*CHARP(cp, 0)) << 8;
else if (size == 2) else if (size == 2)
cur_i[chan] = (int)*SHORTP(cp, 0); cur_i[chan] = (int)*SHORTP(cp, 0);
else if (size == 4) else if (size == 4)
cur_i[chan] = cur_i[chan] = ((int)*LONGP(cp, 0)) >> 16;
((int)*LONGP(cp, 0)) >> 16;
cp += size; cp += size;
/* implements a simple digital filter */ /* implements a simple digital filter */
cur_i[chan] = (weightA * cur_i[chan] + cur_i[chan] =
weightB * prev_i[chan]) (weightA * cur_i[chan] +
/ (weightA + weightB); weightB * prev_i[chan]) /
(weightA + weightB);
} }
len--; len--;
d += outrate; d += outrate;
} }
while (d >= 0) { while (d >= 0) {
for (chan = 0; chan < nchannels; chan++) { for (chan = 0; chan < nchannels; chan++) {
cur_o = (prev_i[chan] * d + cur_i[chan] cur_o = (prev_i[chan] * d +
* (outrate - d)) / outrate; cur_i[chan] * (outrate - d)) /
if (size == 1) outrate;
*CHARP(ncp, 0) = if (size == 1)
(signed char)(cur_o >> 8); *CHARP(ncp, 0) = (signed char)(cur_o >> 8);
else if (size == 2) else if (size == 2)
*SHORTP(ncp, 0) = (short)(cur_o); *SHORTP(ncp, 0) = (short)(cur_o);
else if (size == 4) else if (size == 4)
*LONGP(ncp, 0) = (long)(cur_o<<16); *LONGP(ncp, 0) = (long)(cur_o<<16);
ncp += size; ncp += size;
} }
d -= inrate; d -= inrate;
} }
} }
} }
static PyObject * static PyObject *
audioop_lin2ulaw(self, args) audioop_lin2ulaw(self, args)
PyObject *self; PyObject *self;