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:
parent
6fb6f10a96
commit
1851a67695
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue