mirror of
https://github.com/python/cpython.git
synced 2025-11-07 21:29:26 +00:00
audioop_ratecv() again: settle for a sloppier upper bound that's less
obnoxious to compute and easier to explain. No compromise on safety.
This commit is contained in:
parent
b404145936
commit
eb4b7bad33
1 changed files with 19 additions and 34 deletions
|
|
@ -2,7 +2,6 @@
|
||||||
/* audioopmodule - Module to detect peak values in arrays */
|
/* audioopmodule - Module to detect peak values in arrays */
|
||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#if SIZEOF_INT == 4
|
#if SIZEOF_INT == 4
|
||||||
typedef int Py_Int32;
|
typedef int Py_Int32;
|
||||||
|
|
@ -981,46 +980,32 @@ audioop_ratecv(PyObject *self, PyObject *args)
|
||||||
/* There are len input frames, so we need (mathematically)
|
/* There are len input frames, so we need (mathematically)
|
||||||
ceiling(len*outrate/inrate) output frames, and each frame
|
ceiling(len*outrate/inrate) output frames, and each frame
|
||||||
requires bytes_per_frame bytes. Computing this
|
requires bytes_per_frame bytes. Computing this
|
||||||
without spurious overflow is the challenge. */
|
without spurious overflow is the challenge; we can
|
||||||
int ceiling; /* the number of output frames, eventually */
|
settle for a reasonable upper bound, though. */
|
||||||
|
int ceiling; /* the number of output frames */
|
||||||
int nbytes; /* the number of output bytes needed */
|
int nbytes; /* the number of output bytes needed */
|
||||||
int q = len / inrate;
|
int q = len / inrate;
|
||||||
int r = len - q * inrate;
|
/* Now len = q * inrate + r exactly (with r = len % inrate),
|
||||||
/* Now len = q * inrate + r exactly, so
|
and this is less than q * inrate + inrate = (q+1)*inrate.
|
||||||
len*outrate/inrate =
|
So a reasonable upper bound on len*outrate/inrate is
|
||||||
(q*inrate+r)*outrate/inrate =
|
((q+1)*inrate)*outrate/inrate =
|
||||||
(q*inrate*outrate + r*outrate)/inrate =
|
(q+1)*outrate.
|
||||||
q*outrate + r*outrate/inrate exactly.
|
*/
|
||||||
q*outrate is an exact integer, so the ceiling we're after is
|
ceiling = (q+1) * outrate;
|
||||||
q*outrate + ceiling(r*outrate/inrate). */
|
|
||||||
ceiling = q * outrate;
|
|
||||||
if (ceiling / outrate != q) {
|
|
||||||
PyErr_SetString(PyExc_MemoryError,
|
|
||||||
"not enough memory for output buffer");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
/* Since r = len % inrate, in particular r < inrate. So
|
|
||||||
r * outrate / inrate = (r / inrate) * outrate < outrate,
|
|
||||||
so ceiling(r * outrate / inrate) <= outrate: the final
|
|
||||||
result fits in an int -- it can't overflow. */
|
|
||||||
assert(r < inrate);
|
|
||||||
q = (int)ceil((double)r * (double)outrate / (double)inrate);
|
|
||||||
assert(q <= outrate);
|
|
||||||
ceiling += q;
|
|
||||||
if (ceiling < 0) {
|
|
||||||
PyErr_SetString(PyExc_MemoryError,
|
|
||||||
"not enough memory for output buffer");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
nbytes = ceiling * bytes_per_frame;
|
nbytes = ceiling * bytes_per_frame;
|
||||||
if (nbytes / bytes_per_frame != ceiling) {
|
/* See whether anything overflowed; if not, get the space. */
|
||||||
|
if (q+1 < 0 ||
|
||||||
|
ceiling / outrate != q+1 ||
|
||||||
|
nbytes / bytes_per_frame != ceiling)
|
||||||
|
str = NULL;
|
||||||
|
else
|
||||||
|
str = PyString_FromStringAndSize(NULL, nbytes);
|
||||||
|
|
||||||
|
if (str == NULL) {
|
||||||
PyErr_SetString(PyExc_MemoryError,
|
PyErr_SetString(PyExc_MemoryError,
|
||||||
"not enough memory for output buffer");
|
"not enough memory for output buffer");
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
str = PyString_FromStringAndSize(NULL, nbytes);
|
|
||||||
if (str == NULL)
|
|
||||||
goto exit;
|
|
||||||
}
|
}
|
||||||
ncp = PyString_AsString(str);
|
ncp = PyString_AsString(str);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue