diff options
-rw-r--r-- | Doc/library/audioop.rst | 8 | ||||
-rw-r--r-- | Lib/test/test_audioop.py | 102 | ||||
-rw-r--r-- | Misc/NEWS | 3 | ||||
-rw-r--r-- | Modules/audioop.c | 666 |
4 files changed, 485 insertions, 294 deletions
diff --git a/Doc/library/audioop.rst b/Doc/library/audioop.rst index 55c58b0..ca6cfb3 100644 --- a/Doc/library/audioop.rst +++ b/Doc/library/audioop.rst @@ -7,12 +7,16 @@ The :mod:`audioop` module contains some useful operations on sound fragments. It operates on sound fragments consisting of signed integer samples 8, 16, 24 -or 32 bits wide, stored in bytes objects. All scalar items are integers, -unless specified otherwise. +or 32 bits wide, stored in :term:`bytes-like object`\ s. All scalar items are +integers, unless specified otherwise. .. versionchanged:: 3.4 Support for 24-bit samples was added. +.. versionchanged:: 3.4 + Any :term:`bytes-like object`\ s are now accepted by all functions in this + module. Strings no more supported. + .. index:: single: Intel/DVI ADPCM single: ADPCM, Intel/DVI diff --git a/Lib/test/test_audioop.py b/Lib/test/test_audioop.py index cf0ef7b..fe96b75 100644 --- a/Lib/test/test_audioop.py +++ b/Lib/test/test_audioop.py @@ -34,6 +34,8 @@ class TestAudioop(unittest.TestCase): def test_max(self): for w in 1, 2, 3, 4: self.assertEqual(audioop.max(b'', w), 0) + self.assertEqual(audioop.max(bytearray(), w), 0) + self.assertEqual(audioop.max(memoryview(b''), w), 0) p = packs[w] self.assertEqual(audioop.max(p(5), w), 5) self.assertEqual(audioop.max(p(5, -8, -1), w), 8) @@ -45,6 +47,10 @@ class TestAudioop(unittest.TestCase): for w in 1, 2, 3, 4: self.assertEqual(audioop.minmax(b'', w), (0x7fffffff, -0x80000000)) + self.assertEqual(audioop.minmax(bytearray(), w), + (0x7fffffff, -0x80000000)) + self.assertEqual(audioop.minmax(memoryview(b''), w), + (0x7fffffff, -0x80000000)) p = packs[w] self.assertEqual(audioop.minmax(p(5), w), (5, 5)) self.assertEqual(audioop.minmax(p(5, -8, -1), w), (-8, 5)) @@ -58,6 +64,8 @@ class TestAudioop(unittest.TestCase): def test_maxpp(self): for w in 1, 2, 3, 4: self.assertEqual(audioop.maxpp(b'', w), 0) + self.assertEqual(audioop.maxpp(bytearray(), w), 0) + self.assertEqual(audioop.maxpp(memoryview(b''), w), 0) self.assertEqual(audioop.maxpp(packs[w](*range(100)), w), 0) self.assertEqual(audioop.maxpp(packs[w](9, 10, 5, 5, 0, 1), w), 10) self.assertEqual(audioop.maxpp(datas[w], w), @@ -66,6 +74,8 @@ class TestAudioop(unittest.TestCase): def test_avg(self): for w in 1, 2, 3, 4: self.assertEqual(audioop.avg(b'', w), 0) + self.assertEqual(audioop.avg(bytearray(), w), 0) + self.assertEqual(audioop.avg(memoryview(b''), w), 0) p = packs[w] self.assertEqual(audioop.avg(p(5), w), 5) self .assertEqual(audioop.avg(p(5, 8), w), 6) @@ -82,6 +92,8 @@ class TestAudioop(unittest.TestCase): def test_avgpp(self): for w in 1, 2, 3, 4: self.assertEqual(audioop.avgpp(b'', w), 0) + self.assertEqual(audioop.avgpp(bytearray(), w), 0) + self.assertEqual(audioop.avgpp(memoryview(b''), w), 0) self.assertEqual(audioop.avgpp(packs[w](*range(100)), w), 0) self.assertEqual(audioop.avgpp(packs[w](9, 10, 5, 5, 0, 1), w), 10) self.assertEqual(audioop.avgpp(datas[1], 1), 196) @@ -92,6 +104,8 @@ class TestAudioop(unittest.TestCase): def test_rms(self): for w in 1, 2, 3, 4: self.assertEqual(audioop.rms(b'', w), 0) + self.assertEqual(audioop.rms(bytearray(), w), 0) + self.assertEqual(audioop.rms(memoryview(b''), w), 0) p = packs[w] self.assertEqual(audioop.rms(p(*range(100)), w), 57) self.assertAlmostEqual(audioop.rms(p(maxvalues[w]) * 5, w), @@ -106,6 +120,8 @@ class TestAudioop(unittest.TestCase): def test_cross(self): for w in 1, 2, 3, 4: self.assertEqual(audioop.cross(b'', w), -1) + self.assertEqual(audioop.cross(bytearray(), w), -1) + self.assertEqual(audioop.cross(memoryview(b''), w), -1) p = packs[w] self.assertEqual(audioop.cross(p(0, 1, 2), w), 0) self.assertEqual(audioop.cross(p(1, 2, -3, -4), w), 1) @@ -116,6 +132,8 @@ class TestAudioop(unittest.TestCase): def test_add(self): for w in 1, 2, 3, 4: self.assertEqual(audioop.add(b'', b'', w), b'') + self.assertEqual(audioop.add(bytearray(), bytearray(), w), b'') + self.assertEqual(audioop.add(memoryview(b''), memoryview(b''), w), b'') self.assertEqual(audioop.add(datas[w], b'\0' * len(datas[w]), w), datas[w]) self.assertEqual(audioop.add(datas[1], datas[1], 1), @@ -133,6 +151,8 @@ class TestAudioop(unittest.TestCase): for w in 1, 2, 3, 4: for bias in 0, 1, -1, 127, -128, 0x7fffffff, -0x80000000: self.assertEqual(audioop.bias(b'', w, bias), b'') + self.assertEqual(audioop.bias(bytearray(), w, bias), b'') + self.assertEqual(audioop.bias(memoryview(b''), w, bias), b'') self.assertEqual(audioop.bias(datas[1], 1, 1), b'\x01\x13\x46\xbc\x80\x81\x00') self.assertEqual(audioop.bias(datas[1], 1, -1), @@ -176,6 +196,10 @@ class TestAudioop(unittest.TestCase): def test_lin2lin(self): for w in 1, 2, 3, 4: self.assertEqual(audioop.lin2lin(datas[w], w, w), datas[w]) + self.assertEqual(audioop.lin2lin(bytearray(datas[w]), w, w), + datas[w]) + self.assertEqual(audioop.lin2lin(memoryview(datas[w]), w, w), + datas[w]) self.assertEqual(audioop.lin2lin(datas[1], 1, 2), packs[2](0, 0x1200, 0x4500, -0x4500, 0x7f00, -0x8000, -0x100)) @@ -211,6 +235,10 @@ class TestAudioop(unittest.TestCase): def test_adpcm2lin(self): self.assertEqual(audioop.adpcm2lin(b'\x07\x7f\x7f', 1, None), (b'\x00\x00\x00\xff\x00\xff', (-179, 40))) + self.assertEqual(audioop.adpcm2lin(bytearray(b'\x07\x7f\x7f'), 1, None), + (b'\x00\x00\x00\xff\x00\xff', (-179, 40))) + self.assertEqual(audioop.adpcm2lin(memoryview(b'\x07\x7f\x7f'), 1, None), + (b'\x00\x00\x00\xff\x00\xff', (-179, 40))) self.assertEqual(audioop.adpcm2lin(b'\x07\x7f\x7f', 2, None), (packs[2](0, 0xb, 0x29, -0x16, 0x72, -0xb3), (-179, 40))) self.assertEqual(audioop.adpcm2lin(b'\x07\x7f\x7f', 3, None), @@ -228,6 +256,10 @@ class TestAudioop(unittest.TestCase): def test_lin2adpcm(self): self.assertEqual(audioop.lin2adpcm(datas[1], 1, None), (b'\x07\x7f\x7f', (-221, 39))) + self.assertEqual(audioop.lin2adpcm(bytearray(datas[1]), 1, None), + (b'\x07\x7f\x7f', (-221, 39))) + self.assertEqual(audioop.lin2adpcm(memoryview(datas[1]), 1, None), + (b'\x07\x7f\x7f', (-221, 39))) for w in 2, 3, 4: self.assertEqual(audioop.lin2adpcm(datas[w], w, None), (b'\x07\x7f\x7f', (31, 39))) @@ -240,6 +272,10 @@ class TestAudioop(unittest.TestCase): def test_lin2alaw(self): self.assertEqual(audioop.lin2alaw(datas[1], 1), b'\xd5\x87\xa4\x24\xaa\x2a\x5a') + self.assertEqual(audioop.lin2alaw(bytearray(datas[1]), 1), + b'\xd5\x87\xa4\x24\xaa\x2a\x5a') + self.assertEqual(audioop.lin2alaw(memoryview(datas[1]), 1), + b'\xd5\x87\xa4\x24\xaa\x2a\x5a') for w in 2, 3, 4: self.assertEqual(audioop.lin2alaw(datas[w], w), b'\xd5\x87\xa4\x24\xaa\x2a\x55') @@ -250,8 +286,10 @@ class TestAudioop(unittest.TestCase): src = [-688, -720, -2240, -4032, -9, -3, -1, -27, -244, -82, -106, 688, 720, 2240, 4032, 9, 3, 1, 27, 244, 82, 106] for w in 1, 2, 3, 4: - self.assertEqual(audioop.alaw2lin(encoded, w), - packs[w](*(x << (w * 8) >> 13 for x in src))) + decoded = packs[w](*(x << (w * 8) >> 13 for x in src)) + self.assertEqual(audioop.alaw2lin(encoded, w), decoded) + self.assertEqual(audioop.alaw2lin(bytearray(encoded), w), decoded) + self.assertEqual(audioop.alaw2lin(memoryview(encoded), w), decoded) encoded = bytes(range(256)) for w in 2, 3, 4: @@ -261,6 +299,10 @@ class TestAudioop(unittest.TestCase): def test_lin2ulaw(self): self.assertEqual(audioop.lin2ulaw(datas[1], 1), b'\xff\xad\x8e\x0e\x80\x00\x67') + self.assertEqual(audioop.lin2ulaw(bytearray(datas[1]), 1), + b'\xff\xad\x8e\x0e\x80\x00\x67') + self.assertEqual(audioop.lin2ulaw(memoryview(datas[1]), 1), + b'\xff\xad\x8e\x0e\x80\x00\x67') for w in 2, 3, 4: self.assertEqual(audioop.lin2ulaw(datas[w], w), b'\xff\xad\x8e\x0e\x80\x00\x7e') @@ -271,8 +313,10 @@ class TestAudioop(unittest.TestCase): src = [-8031, -4447, -1471, -495, -163, -53, -18, -6, -2, 0, 8031, 4447, 1471, 495, 163, 53, 18, 6, 2, 0] for w in 1, 2, 3, 4: - self.assertEqual(audioop.ulaw2lin(encoded, w), - packs[w](*(x << (w * 8) >> 14 for x in src))) + decoded = packs[w](*(x << (w * 8) >> 14 for x in src)) + self.assertEqual(audioop.ulaw2lin(encoded, w), decoded) + self.assertEqual(audioop.ulaw2lin(bytearray(encoded), w), decoded) + self.assertEqual(audioop.ulaw2lin(memoryview(encoded), w), decoded) # Current u-law implementation has two codes fo 0: 0x7f and 0xff. encoded = bytes(range(127)) + bytes(range(128, 256)) @@ -283,6 +327,8 @@ class TestAudioop(unittest.TestCase): def test_mul(self): for w in 1, 2, 3, 4: self.assertEqual(audioop.mul(b'', w, 2), b'') + self.assertEqual(audioop.mul(bytearray(), w, 2), b'') + self.assertEqual(audioop.mul(memoryview(b''), w, 2), b'') self.assertEqual(audioop.mul(datas[w], w, 0), b'\0' * len(datas[w])) self.assertEqual(audioop.mul(datas[w], w, 1), @@ -302,6 +348,10 @@ class TestAudioop(unittest.TestCase): for w in 1, 2, 3, 4: self.assertEqual(audioop.ratecv(b'', w, 1, 8000, 8000, None), (b'', (-1, ((0, 0),)))) + self.assertEqual(audioop.ratecv(bytearray(), w, 1, 8000, 8000, None), + (b'', (-1, ((0, 0),)))) + self.assertEqual(audioop.ratecv(memoryview(b''), w, 1, 8000, 8000, None), + (b'', (-1, ((0, 0),)))) self.assertEqual(audioop.ratecv(b'', w, 5, 8000, 8000, None), (b'', (-1, ((0, 0),) * 5))) self.assertEqual(audioop.ratecv(b'', w, 1, 8000, 16000, None), @@ -326,6 +376,8 @@ class TestAudioop(unittest.TestCase): def test_reverse(self): for w in 1, 2, 3, 4: self.assertEqual(audioop.reverse(b'', w), b'') + self.assertEqual(audioop.reverse(bytearray(), w), b'') + self.assertEqual(audioop.reverse(memoryview(b''), w), b'') self.assertEqual(audioop.reverse(packs[w](0, 1, 2), w), packs[w](2, 1, 0)) @@ -340,6 +392,10 @@ class TestAudioop(unittest.TestCase): for k in range(w): data2[k+w::2*w] = data1[k::w] self.assertEqual(audioop.tomono(data2, w, 0.5, 0.5), data1) + self.assertEqual(audioop.tomono(bytearray(data2), w, 0.5, 0.5), + data1) + self.assertEqual(audioop.tomono(memoryview(data2), w, 0.5, 0.5), + data1) def test_tostereo(self): for w in 1, 2, 3, 4: @@ -352,14 +408,25 @@ class TestAudioop(unittest.TestCase): for k in range(w): data2[k+w::2*w] = data1[k::w] self.assertEqual(audioop.tostereo(data1, w, 1, 1), data2) + self.assertEqual(audioop.tostereo(bytearray(data1), w, 1, 1), data2) + self.assertEqual(audioop.tostereo(memoryview(data1), w, 1, 1), + data2) def test_findfactor(self): self.assertEqual(audioop.findfactor(datas[2], datas[2]), 1.0) + self.assertEqual(audioop.findfactor(bytearray(datas[2]), + bytearray(datas[2])), 1.0) + self.assertEqual(audioop.findfactor(memoryview(datas[2]), + memoryview(datas[2])), 1.0) self.assertEqual(audioop.findfactor(b'\0' * len(datas[2]), datas[2]), 0.0) def test_findfit(self): self.assertEqual(audioop.findfit(datas[2], datas[2]), (0, 1.0)) + self.assertEqual(audioop.findfit(bytearray(datas[2]), + bytearray(datas[2])), (0, 1.0)) + self.assertEqual(audioop.findfit(memoryview(datas[2]), + memoryview(datas[2])), (0, 1.0)) self.assertEqual(audioop.findfit(datas[2], packs[2](1, 2, 0)), (1, 8038.8)) self.assertEqual(audioop.findfit(datas[2][:-2] * 5 + datas[2], datas[2]), @@ -367,11 +434,15 @@ class TestAudioop(unittest.TestCase): def test_findmax(self): self.assertEqual(audioop.findmax(datas[2], 1), 5) + self.assertEqual(audioop.findmax(bytearray(datas[2]), 1), 5) + self.assertEqual(audioop.findmax(memoryview(datas[2]), 1), 5) def test_getsample(self): for w in 1, 2, 3, 4: data = packs[w](0, 1, -1, maxvalues[w], minvalues[w]) self.assertEqual(audioop.getsample(data, w, 0), 0) + self.assertEqual(audioop.getsample(bytearray(data), w, 0), 0) + self.assertEqual(audioop.getsample(memoryview(data), w, 0), 0) self.assertEqual(audioop.getsample(data, w, 1), 1) self.assertEqual(audioop.getsample(data, w, 2), -1) self.assertEqual(audioop.getsample(data, w, 3), maxvalues[w]) @@ -406,6 +477,29 @@ class TestAudioop(unittest.TestCase): self.assertRaises(audioop.error, audioop.lin2alaw, data, size) self.assertRaises(audioop.error, audioop.lin2adpcm, data, size, state) + def test_string(self): + data = 'abcd' + size = 2 + self.assertRaises(TypeError, audioop.getsample, data, size, 0) + self.assertRaises(TypeError, audioop.max, data, size) + self.assertRaises(TypeError, audioop.minmax, data, size) + self.assertRaises(TypeError, audioop.avg, data, size) + self.assertRaises(TypeError, audioop.rms, data, size) + self.assertRaises(TypeError, audioop.avgpp, data, size) + self.assertRaises(TypeError, audioop.maxpp, data, size) + self.assertRaises(TypeError, audioop.cross, data, size) + self.assertRaises(TypeError, audioop.mul, data, size, 1.0) + self.assertRaises(TypeError, audioop.tomono, data, size, 0.5, 0.5) + self.assertRaises(TypeError, audioop.tostereo, data, size, 0.5, 0.5) + self.assertRaises(TypeError, audioop.add, data, data, size) + self.assertRaises(TypeError, audioop.bias, data, size, 0) + self.assertRaises(TypeError, audioop.reverse, data, size) + self.assertRaises(TypeError, audioop.lin2lin, data, size, size) + self.assertRaises(TypeError, audioop.ratecv, data, size, 1, 1, 1, None) + self.assertRaises(TypeError, audioop.lin2ulaw, data, size) + self.assertRaises(TypeError, audioop.lin2alaw, data, size) + self.assertRaises(TypeError, audioop.lin2adpcm, data, size, None) + def test_wrongsize(self): data = b'abcdefgh' state = None @@ -34,6 +34,9 @@ Core and Builtins Library ------- +- Issue #16685: Added support for any bytes-like objects in the audioop module. + Removed support for strings. + - Issue #7171: Add Windows implementation of ``inet_ntop`` and ``inet_pton`` to socket module. Patch by Atsuo Ishimoto. diff --git a/Modules/audioop.c b/Modules/audioop.c index 342f262..df4a524 100644 --- a/Modules/audioop.c +++ b/Modules/audioop.c @@ -393,110 +393,129 @@ audioop_check_parameters(Py_ssize_t len, int size) static PyObject * audioop_getsample(PyObject *self, PyObject *args) { - signed char *cp; - Py_ssize_t len, i; + Py_buffer view; + Py_ssize_t i; int size; + int val; - if ( !PyArg_ParseTuple(args, "s#in:getsample", &cp, &len, &size, &i) ) - return 0; - if (!audioop_check_parameters(len, size)) + if (!PyArg_ParseTuple(args, "y*in:getsample", &view, &size, &i)) return NULL; - if ( i < 0 || i >= len/size ) { + if (!audioop_check_parameters(view.len, size)) + goto error; + if (i < 0 || i >= view.len/size) { PyErr_SetString(AudioopError, "Index out of range"); - return 0; + goto error; } - return PyLong_FromLong(GETRAWSAMPLE(size, cp, i*size)); + val = GETRAWSAMPLE(size, view.buf, i*size); + PyBuffer_Release(&view); + return PyLong_FromLong(val); + + error: + PyBuffer_Release(&view); + return NULL; } static PyObject * audioop_max(PyObject *self, PyObject *args) { - signed char *cp; - Py_ssize_t len, i; + Py_buffer view; + Py_ssize_t i; int size; unsigned int absval, max = 0; - if ( !PyArg_ParseTuple(args, "s#i:max", &cp, &len, &size) ) - return 0; - if (!audioop_check_parameters(len, size)) + if (!PyArg_ParseTuple(args, "y*i:max", &view, &size)) return NULL; - for (i = 0; i < len; i += size) { - int val = GETRAWSAMPLE(size, cp, i); + if (!audioop_check_parameters(view.len, size)) { + PyBuffer_Release(&view); + return NULL; + } + for (i = 0; i < view.len; i += size) { + int val = GETRAWSAMPLE(size, view.buf, i); if (val < 0) absval = (-val); else absval = val; if (absval > max) max = absval; } + PyBuffer_Release(&view); return PyLong_FromUnsignedLong(max); } static PyObject * audioop_minmax(PyObject *self, PyObject *args) { - signed char *cp; - Py_ssize_t len, i; + Py_buffer view; + Py_ssize_t i; int size; /* -1 trick below is needed on Windows to support -0x80000000 without a warning */ int min = 0x7fffffff, max = -0x7FFFFFFF-1; - if (!PyArg_ParseTuple(args, "s#i:minmax", &cp, &len, &size)) + if (!PyArg_ParseTuple(args, "y*i:minmax", &view, &size)) return NULL; - if (!audioop_check_parameters(len, size)) + if (!audioop_check_parameters(view.len, size)) { + PyBuffer_Release(&view); return NULL; - for (i = 0; i < len; i += size) { - int val = GETRAWSAMPLE(size, cp, i); + } + for (i = 0; i < view.len; i += size) { + int val = GETRAWSAMPLE(size, view.buf, i); if (val > max) max = val; if (val < min) min = val; } + PyBuffer_Release(&view); return Py_BuildValue("(ii)", min, max); } static PyObject * audioop_avg(PyObject *self, PyObject *args) { - signed char *cp; - Py_ssize_t len, i; + Py_buffer view; + Py_ssize_t i; int size, avg; double sum = 0.0; - if ( !PyArg_ParseTuple(args, "s#i:avg", &cp, &len, &size) ) - return 0; - if (!audioop_check_parameters(len, size)) + if (!PyArg_ParseTuple(args, "y*i:avg", &view, &size)) return NULL; - for (i = 0; i < len; i += size) - sum += GETRAWSAMPLE(size, cp, i); - if ( len == 0 ) + if (!audioop_check_parameters(view.len, size)) { + PyBuffer_Release(&view); + return NULL; + } + for (i = 0; i < view.len; i += size) + sum += GETRAWSAMPLE(size, view.buf, i); + if (view.len == 0) avg = 0; else - avg = (int)floor(sum / (double)(len/size)); + avg = (int)floor(sum / (double)(view.len/size)); + PyBuffer_Release(&view); return PyLong_FromLong(avg); } static PyObject * audioop_rms(PyObject *self, PyObject *args) { - signed char *cp; - Py_ssize_t len, i; + Py_buffer view; + Py_ssize_t i; int size; unsigned int res; double sum_squares = 0.0; - if ( !PyArg_ParseTuple(args, "s#i:rms", &cp, &len, &size) ) - return 0; - if (!audioop_check_parameters(len, size)) + if (!PyArg_ParseTuple(args, "y*i:rms", &view, &size)) return NULL; - for (i = 0; i < len; i += size) { - double val = GETRAWSAMPLE(size, cp, i); + if (!audioop_check_parameters(view.len, size)) { + PyBuffer_Release(&view); + return NULL; + } + for (i = 0; i < view.len; i += size) { + double val = GETRAWSAMPLE(size, view.buf, i); sum_squares += val*val; } - if ( len == 0 ) + if (view.len == 0) res = 0; else - res = (unsigned int)sqrt(sum_squares / (double)(len/size)); + res = (unsigned int)sqrt(sum_squares / (double)(view.len/size)); + PyBuffer_Release(&view); return PyLong_FromUnsignedLong(res); } -static double _sum2(short *a, short *b, Py_ssize_t len) +static double _sum2(const short *a, const short *b, Py_ssize_t len) { Py_ssize_t i; double sum = 0.0; @@ -542,29 +561,28 @@ static double _sum2(short *a, short *b, Py_ssize_t len) static PyObject * audioop_findfit(PyObject *self, PyObject *args) { - short *cp1, *cp2; + Py_buffer view1; + Py_buffer view2; + const short *cp1, *cp2; Py_ssize_t len1, len2; Py_ssize_t j, best_j; double aj_m1, aj_lm1; double sum_ri_2, sum_aij_2, sum_aij_ri, result, best_result, factor; - /* Passing a short** for an 's' argument is correct only - if the string contents is aligned for interpretation - as short[]. Due to the definition of PyBytesObject, - this is currently (Python 2.6) the case. */ - if ( !PyArg_ParseTuple(args, "s#s#:findfit", - (char**)&cp1, &len1, (char**)&cp2, &len2) ) - return 0; - if ( len1 & 1 || len2 & 1 ) { + if (!PyArg_ParseTuple(args, "y*y*:findfit", &view1, &view2)) + return NULL; + if (view1.len & 1 || view2.len & 1) { PyErr_SetString(AudioopError, "Strings should be even-sized"); - return 0; + goto error; } - len1 >>= 1; - len2 >>= 1; + cp1 = (const short *)view1.buf; + len1 = view1.len >> 1; + cp2 = (const short *)view2.buf; + len2 = view2.len >> 1; - if ( len1 < len2 ) { + if (len1 < len2) { PyErr_SetString(AudioopError, "First sample should be longer"); - return 0; + goto error; } sum_ri_2 = _sum2(cp2, cp2, len2); sum_aij_2 = _sum2(cp1, cp1, len2); @@ -594,7 +612,14 @@ audioop_findfit(PyObject *self, PyObject *args) factor = _sum2(cp1+best_j, cp2, len2) / sum_ri_2; + PyBuffer_Release(&view1); + PyBuffer_Release(&view2); return Py_BuildValue("(nf)", best_j, factor); + + error: + PyBuffer_Release(&view1); + PyBuffer_Release(&view2); + return NULL; } /* @@ -604,28 +629,38 @@ audioop_findfit(PyObject *self, PyObject *args) static PyObject * audioop_findfactor(PyObject *self, PyObject *args) { - short *cp1, *cp2; - Py_ssize_t len1, len2; + Py_buffer view1; + Py_buffer view2; + const short *cp1, *cp2; + Py_ssize_t len; double sum_ri_2, sum_aij_ri, result; - if ( !PyArg_ParseTuple(args, "s#s#:findfactor", - (char**)&cp1, &len1, (char**)&cp2, &len2) ) - return 0; - if ( len1 & 1 || len2 & 1 ) { + if (!PyArg_ParseTuple(args, "y*y*:findfactor", &view1, &view2)) + return NULL; + if (view1.len & 1 || view2.len & 1) { PyErr_SetString(AudioopError, "Strings should be even-sized"); - return 0; + goto error; } - if ( len1 != len2 ) { + if (view1.len != view2.len) { PyErr_SetString(AudioopError, "Samples should be same size"); - return 0; + goto error; } - len2 >>= 1; - sum_ri_2 = _sum2(cp2, cp2, len2); - sum_aij_ri = _sum2(cp1, cp2, len2); + cp1 = (const short *)view1.buf; + cp2 = (const short *)view2.buf; + len = view1.len >> 1; + sum_ri_2 = _sum2(cp2, cp2, len); + sum_aij_ri = _sum2(cp1, cp2, len); result = sum_aij_ri / sum_ri_2; + PyBuffer_Release(&view1); + PyBuffer_Release(&view2); return PyFloat_FromDouble(result); + + error: + PyBuffer_Release(&view1); + PyBuffer_Release(&view2); + return NULL; } /* @@ -635,24 +670,25 @@ audioop_findfactor(PyObject *self, PyObject *args) static PyObject * audioop_findmax(PyObject *self, PyObject *args) { - short *cp1; + Py_buffer view; + const short *cp1; Py_ssize_t len1, len2; Py_ssize_t j, best_j; double aj_m1, aj_lm1; double result, best_result; - if ( !PyArg_ParseTuple(args, "s#n:findmax", - (char**)&cp1, &len1, &len2) ) - return 0; - if ( len1 & 1 ) { + if (!PyArg_ParseTuple(args, "y*n:findmax", &view, &len2)) + return NULL; + if (view.len & 1) { PyErr_SetString(AudioopError, "Strings should be even-sized"); - return 0; + goto error; } - len1 >>= 1; + cp1 = (const short *)view.buf; + len1 = view.len >> 1; - if ( len2 < 0 || len1 < len2 ) { + if (len2 < 0 || len1 < len2) { PyErr_SetString(AudioopError, "Input sample should be longer"); - return 0; + goto error; } result = _sum2(cp1, cp1, len2); @@ -673,30 +709,39 @@ audioop_findmax(PyObject *self, PyObject *args) } + PyBuffer_Release(&view); return PyLong_FromSsize_t(best_j); + + error: + PyBuffer_Release(&view); + return NULL; } static PyObject * audioop_avgpp(PyObject *self, PyObject *args) { - signed char *cp; - Py_ssize_t len, i; + Py_buffer view; + Py_ssize_t i; int size, prevval, prevextremevalid = 0, prevextreme = 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)) + if (!PyArg_ParseTuple(args, "y*i:avgpp", &view, &size)) return NULL; - if (len <= size) + if (!audioop_check_parameters(view.len, size)) { + PyBuffer_Release(&view); + return NULL; + } + if (view.len <= size) { + PyBuffer_Release(&view); return PyLong_FromLong(0); - prevval = GETRAWSAMPLE(size, cp, 0); + } + prevval = GETRAWSAMPLE(size, view.buf, 0); prevdiff = 17; /* Anything != 0, 1 */ - for (i = size; i < len; i += size) { - int val = GETRAWSAMPLE(size, cp, i); + for (i = size; i < view.len; i += size) { + int val = GETRAWSAMPLE(size, view.buf, i); if (val != prevval) { diff = val < prevval; if (prevdiff == !diff) { @@ -723,29 +768,34 @@ audioop_avgpp(PyObject *self, PyObject *args) avg = 0; else avg = (unsigned int)(sum / (double)nextreme); + PyBuffer_Release(&view); return PyLong_FromUnsignedLong(avg); } static PyObject * audioop_maxpp(PyObject *self, PyObject *args) { - signed char *cp; - Py_ssize_t len, i; + Py_buffer view; + Py_ssize_t i; int size, prevval, prevextremevalid = 0, prevextreme = 0; 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)) + if (!PyArg_ParseTuple(args, "y*i:maxpp", &view, &size)) return NULL; - if (len <= size) + if (!audioop_check_parameters(view.len, size)) { + PyBuffer_Release(&view); + return NULL; + } + if (view.len <= size) { + PyBuffer_Release(&view); return PyLong_FromLong(0); - prevval = GETRAWSAMPLE(size, cp, 0); + } + prevval = GETRAWSAMPLE(size, view.buf, 0); prevdiff = 17; /* Anything != 0, 1 */ - for (i = size; i < len; i += size) { - int val = GETRAWSAMPLE(size, cp, i); + for (i = size; i < view.len; i += size) { + int val = GETRAWSAMPLE(size, view.buf, i); if (val != prevval) { diff = val < prevval; if (prevdiff == !diff) { @@ -769,60 +819,67 @@ audioop_maxpp(PyObject *self, PyObject *args) prevdiff = diff; } } + PyBuffer_Release(&view); return PyLong_FromUnsignedLong(max); } static PyObject * audioop_cross(PyObject *self, PyObject *args) { - signed char *cp; - Py_ssize_t len, i; + Py_buffer view; + Py_ssize_t i; int size; int prevval; Py_ssize_t ncross; - if ( !PyArg_ParseTuple(args, "s#i:cross", &cp, &len, &size) ) - return 0; - if (!audioop_check_parameters(len, size)) + if (!PyArg_ParseTuple(args, "y*i:cross", &view, &size)) + return NULL; + if (!audioop_check_parameters(view.len, size)) { + PyBuffer_Release(&view); return NULL; + } ncross = -1; prevval = 17; /* Anything <> 0,1 */ - for (i = 0; i < len; i += size) { - int val = GETRAWSAMPLE(size, cp, i) < 0; + for (i = 0; i < view.len; i += size) { + int val = GETRAWSAMPLE(size, view.buf, i) < 0; if (val != prevval) ncross++; prevval = val; } + PyBuffer_Release(&view); return PyLong_FromSsize_t(ncross); } static PyObject * audioop_mul(PyObject *self, PyObject *args) { - signed char *cp, *ncp; - Py_ssize_t len, i; + Py_buffer view; + signed char *ncp; + Py_ssize_t i; int size; double factor, maxval, minval; - PyObject *rv; + PyObject *rv = NULL; - if ( !PyArg_ParseTuple(args, "s#id:mul", &cp, &len, &size, &factor ) ) - return 0; - if (!audioop_check_parameters(len, size)) + if (!PyArg_ParseTuple(args, "y*id:mul", &view, &size, &factor)) return NULL; + if (!audioop_check_parameters(view.len, size)) + goto exit; maxval = (double) maxvals[size]; minval = (double) minvals[size]; - rv = PyBytes_FromStringAndSize(NULL, len); - if ( rv == 0 ) - return 0; + rv = PyBytes_FromStringAndSize(NULL, view.len); + if (rv == NULL) + goto exit; ncp = (signed char *)PyBytes_AsString(rv); - for (i = 0; i < len; i += size) { - double val = GETRAWSAMPLE(size, cp, i); + for (i = 0; i < view.len; i += size) { + double val = GETRAWSAMPLE(size, view.buf, i); val *= factor; val = floor(fbound(val, minval, maxval)); SETRAWSAMPLE(size, ncp, i, (int)val); } + exit: + PyBuffer_Release(&view); return rv; } @@ -834,31 +891,26 @@ audioop_tomono(PyObject *self, PyObject *args) Py_ssize_t len, i; int size; double fac1, fac2, maxval, minval; - PyObject *rv; + PyObject *rv = NULL; - if ( !PyArg_ParseTuple(args, "s*idd:tomono", - &pcp, &size, &fac1, &fac2 ) ) - return 0; + if (!PyArg_ParseTuple(args, "y*idd:tomono", + &pcp, &size, &fac1, &fac2)) + return NULL; cp = pcp.buf; len = pcp.len; - if (!audioop_check_parameters(len, size)) { - PyBuffer_Release(&pcp); - return NULL; - } + if (!audioop_check_parameters(len, size)) + goto exit; if (((len / size) & 1) != 0) { PyErr_SetString(AudioopError, "not a whole number of frames"); - PyBuffer_Release(&pcp); - return NULL; + goto exit; } maxval = (double) maxvals[size]; minval = (double) minvals[size]; rv = PyBytes_FromStringAndSize(NULL, len/2); - if ( rv == 0 ) { - PyBuffer_Release(&pcp); - return 0; - } + if (rv == NULL) + goto exit; ncp = (signed char *)PyBytes_AsString(rv); for (i = 0; i < len; i += size*2) { @@ -868,6 +920,7 @@ audioop_tomono(PyObject *self, PyObject *args) val = floor(fbound(val, minval, maxval)); SETRAWSAMPLE(size, ncp, i/2, val); } + exit: PyBuffer_Release(&pcp); return rv; } @@ -875,71 +928,76 @@ audioop_tomono(PyObject *self, PyObject *args) static PyObject * audioop_tostereo(PyObject *self, PyObject *args) { - signed char *cp, *ncp; - Py_ssize_t len, i; + Py_buffer view; + signed char *ncp; + Py_ssize_t i; int size; double fac1, fac2, maxval, minval; - PyObject *rv; + PyObject *rv = NULL; - if ( !PyArg_ParseTuple(args, "s#idd:tostereo", - &cp, &len, &size, &fac1, &fac2 ) ) - return 0; - if (!audioop_check_parameters(len, size)) + if (!PyArg_ParseTuple(args, "y*idd:tostereo", + &view, &size, &fac1, &fac2)) return NULL; + if (!audioop_check_parameters(view.len, size)) + goto exit; maxval = (double) maxvals[size]; minval = (double) minvals[size]; - if (len > PY_SSIZE_T_MAX/2) { + if (view.len > PY_SSIZE_T_MAX/2) { PyErr_SetString(PyExc_MemoryError, "not enough memory for output buffer"); - return 0; + goto exit; } - rv = PyBytes_FromStringAndSize(NULL, len*2); - if ( rv == 0 ) - return 0; + rv = PyBytes_FromStringAndSize(NULL, view.len*2); + if (rv == NULL) + goto exit; ncp = (signed char *)PyBytes_AsString(rv); - for (i = 0; i < len; i += size) { - double val = GETRAWSAMPLE(size, cp, i); + for (i = 0; i < view.len; i += size) { + double val = GETRAWSAMPLE(size, view.buf, i); int val1 = (int)floor(fbound(val*fac1, minval, maxval)); int val2 = (int)floor(fbound(val*fac2, minval, maxval)); SETRAWSAMPLE(size, ncp, i*2, val1); SETRAWSAMPLE(size, ncp, i*2 + size, val2); } + exit: + PyBuffer_Release(&view); return rv; } static PyObject * audioop_add(PyObject *self, PyObject *args) { - signed char *cp1, *cp2, *ncp; - Py_ssize_t len1, len2, i; + Py_buffer view1; + Py_buffer view2; + signed char *ncp; + Py_ssize_t i; int size, minval, maxval, newval; - PyObject *rv; + PyObject *rv = NULL; - if ( !PyArg_ParseTuple(args, "s#s#i:add", - &cp1, &len1, &cp2, &len2, &size ) ) - return 0; - if (!audioop_check_parameters(len1, size)) + if (!PyArg_ParseTuple(args, "y*y*i:add", + &view1, &view2, &size)) return NULL; - if ( len1 != len2 ) { + if (!audioop_check_parameters(view1.len, size)) + goto exit; + if (view1.len != view2.len) { PyErr_SetString(AudioopError, "Lengths should be the same"); - return 0; + goto exit; } maxval = maxvals[size]; minval = minvals[size]; - rv = PyBytes_FromStringAndSize(NULL, len1); - if ( rv == 0 ) - return 0; + rv = PyBytes_FromStringAndSize(NULL, view1.len); + if (rv == NULL) + goto exit; ncp = (signed char *)PyBytes_AsString(rv); - for (i = 0; i < len1; i += size) { - int val1 = GETRAWSAMPLE(size, cp1, i); - int val2 = GETRAWSAMPLE(size, cp2, i); + for (i = 0; i < view1.len; i += size) { + int val1 = GETRAWSAMPLE(size, view1.buf, i); + int val2 = GETRAWSAMPLE(size, view2.buf, i); if (size < 4) { newval = val1 + val2; @@ -957,42 +1015,46 @@ audioop_add(PyObject *self, PyObject *args) SETRAWSAMPLE(size, ncp, i, newval); } + exit: + PyBuffer_Release(&view1); + PyBuffer_Release(&view2); return rv; } static PyObject * audioop_bias(PyObject *self, PyObject *args) { - signed char *cp, *ncp; - Py_ssize_t len, i; + Py_buffer view; + signed char *ncp; + Py_ssize_t i; int size, bias; unsigned int val = 0, mask; - PyObject *rv; + PyObject *rv = NULL; - if ( !PyArg_ParseTuple(args, "s#ii:bias", - &cp, &len, &size , &bias) ) - return 0; - - if (!audioop_check_parameters(len, size)) + if (!PyArg_ParseTuple(args, "y*ii:bias", + &view, &size, &bias)) return NULL; - rv = PyBytes_FromStringAndSize(NULL, len); - if ( rv == 0 ) - return 0; + if (!audioop_check_parameters(view.len, size)) + goto exit; + + rv = PyBytes_FromStringAndSize(NULL, view.len); + if (rv == NULL) + goto exit; ncp = (signed char *)PyBytes_AsString(rv); mask = masks[size]; - for (i = 0; i < len; i += size) { + for (i = 0; i < view.len; i += size) { if (size == 1) - val = GETINTX(unsigned char, cp, i); + val = GETINTX(unsigned char, view.buf, i); else if (size == 2) - val = GETINTX(unsigned short, cp, i); + val = GETINTX(unsigned short, view.buf, i); else if (size == 3) - val = ((unsigned int)GETINT24(cp, i)) & 0xffffffu; + val = ((unsigned int)GETINT24(view.buf, i)) & 0xffffffu; else { assert(size == 4); - val = GETINTX(PY_UINT32_T, cp, i); + val = GETINTX(PY_UINT32_T, view.buf, i); } val += (unsigned int)bias; @@ -1010,69 +1072,75 @@ audioop_bias(PyObject *self, PyObject *args) SETINTX(PY_UINT32_T, ncp, i, val); } } + exit: + PyBuffer_Release(&view); return rv; } static PyObject * audioop_reverse(PyObject *self, PyObject *args) { - signed char *cp; + Py_buffer view; unsigned char *ncp; - Py_ssize_t len, i; + Py_ssize_t i; int size; - PyObject *rv; + PyObject *rv = NULL; - if ( !PyArg_ParseTuple(args, "s#i:reverse", - &cp, &len, &size) ) - return 0; - - if (!audioop_check_parameters(len, size)) + if (!PyArg_ParseTuple(args, "y*i:reverse", + &view, &size)) return NULL; - rv = PyBytes_FromStringAndSize(NULL, len); - if ( rv == 0 ) - return 0; + if (!audioop_check_parameters(view.len, size)) + goto exit; + + rv = PyBytes_FromStringAndSize(NULL, view.len); + if (rv == NULL) + goto exit; ncp = (unsigned char *)PyBytes_AsString(rv); - for (i = 0; i < len; i += size) { - int val = GETRAWSAMPLE(size, cp, i); - SETRAWSAMPLE(size, ncp, len - i - size, val); + for (i = 0; i < view.len; i += size) { + int val = GETRAWSAMPLE(size, view.buf, i); + SETRAWSAMPLE(size, ncp, view.len - i - size, val); } + exit: + PyBuffer_Release(&view); return rv; } static PyObject * audioop_lin2lin(PyObject *self, PyObject *args) { - signed char *cp; + Py_buffer view; unsigned char *ncp; - Py_ssize_t len, i, j; + Py_ssize_t i, j; int size, size2; - PyObject *rv; + PyObject *rv = NULL; - if ( !PyArg_ParseTuple(args, "s#ii:lin2lin", - &cp, &len, &size, &size2) ) - return 0; - - if (!audioop_check_parameters(len, size)) + if (!PyArg_ParseTuple(args, "y*ii:lin2lin", + &view, &size, &size2)) return NULL; + + if (!audioop_check_parameters(view.len, size)) + goto exit; if (!audioop_check_size(size2)) - return NULL; + goto exit; - if (len/size > PY_SSIZE_T_MAX/size2) { + if (view.len/size > PY_SSIZE_T_MAX/size2) { PyErr_SetString(PyExc_MemoryError, "not enough memory for output buffer"); - return 0; + goto exit; } - rv = PyBytes_FromStringAndSize(NULL, (len/size)*size2); - if ( rv == 0 ) - return 0; + rv = PyBytes_FromStringAndSize(NULL, (view.len/size)*size2); + if (rv == NULL) + goto exit; ncp = (unsigned char *)PyBytes_AsString(rv); - for (i = j = 0; i < len; i += size, j += size2) { - int val = GETSAMPLE32(size, cp, i); + for (i = j = 0; i < view.len; i += size, j += size2) { + int val = GETSAMPLE32(size, view.buf, i); SETSAMPLE32(size2, ncp, j, val); } + exit: + PyBuffer_Release(&view); return rv; } @@ -1090,6 +1158,7 @@ gcd(int a, int b) static PyObject * audioop_ratecv(PyObject *self, PyObject *args) { + Py_buffer view; char *cp, *ncp; Py_ssize_t len; int size, nchannels, inrate, outrate, weightA, weightB; @@ -1099,15 +1168,15 @@ audioop_ratecv(PyObject *self, PyObject *args) weightA = 1; weightB = 0; - if (!PyArg_ParseTuple(args, "s#iiiiO|ii:ratecv", &cp, &len, &size, + if (!PyArg_ParseTuple(args, "y*iiiiO|ii:ratecv", &view, &size, &nchannels, &inrate, &outrate, &state, &weightA, &weightB)) return NULL; if (!audioop_check_size(size)) - return NULL; + goto exit2; if (nchannels < 1) { PyErr_SetString(AudioopError, "# of channels should be >= 1"); - return NULL; + goto exit2; } if (size > INT_MAX / nchannels) { /* This overflow test is rigorously correct because @@ -1115,21 +1184,21 @@ audioop_ratecv(PyObject *self, PyObject *args) from the docs for the error msg. */ PyErr_SetString(PyExc_OverflowError, "width * nchannels too big for a C int"); - return NULL; + goto exit2; } bytes_per_frame = size * nchannels; if (weightA < 1 || weightB < 0) { PyErr_SetString(AudioopError, "weightA should be >= 1, weightB should be >= 0"); - return NULL; + goto exit2; } - if (len % bytes_per_frame != 0) { + if (view.len % bytes_per_frame != 0) { PyErr_SetString(AudioopError, "not a whole number of frames"); - return NULL; + goto exit2; } if (inrate <= 0 || outrate <= 0) { PyErr_SetString(AudioopError, "sampling rate not > 0"); - return NULL; + goto exit2; } /* divide inrate and outrate by their greatest common divisor */ d = gcd(inrate, outrate); @@ -1143,7 +1212,7 @@ audioop_ratecv(PyObject *self, PyObject *args) if ((size_t)nchannels > PY_SIZE_MAX/sizeof(int)) { PyErr_SetString(PyExc_MemoryError, "not enough memory for output buffer"); - return 0; + goto exit2; } prev_i = (int *) PyMem_Malloc(nchannels * sizeof(int)); cur_i = (int *) PyMem_Malloc(nchannels * sizeof(int)); @@ -1152,7 +1221,7 @@ audioop_ratecv(PyObject *self, PyObject *args) goto exit; } - len /= bytes_per_frame; /* # of frames */ + len = view.len / bytes_per_frame; /* # of frames */ if (state == Py_None) { d = -outrate; @@ -1202,6 +1271,7 @@ audioop_ratecv(PyObject *self, PyObject *args) goto exit; } ncp = PyBytes_AsString(str); + cp = view.buf; for (;;) { while (d < 0) { @@ -1257,152 +1327,166 @@ audioop_ratecv(PyObject *self, PyObject *args) exit: PyMem_Free(prev_i); PyMem_Free(cur_i); + exit2: + PyBuffer_Release(&view); return rv; } static PyObject * audioop_lin2ulaw(PyObject *self, PyObject *args) { - signed char *cp; + Py_buffer view; unsigned char *ncp; - Py_ssize_t len, i; + Py_ssize_t i; int size; - PyObject *rv; + PyObject *rv = NULL; - if ( !PyArg_ParseTuple(args, "s#i:lin2ulaw", - &cp, &len, &size) ) - return 0 ; - - if (!audioop_check_parameters(len, size)) + if (!PyArg_ParseTuple(args, "y*i:lin2ulaw", + &view, &size)) return NULL; - rv = PyBytes_FromStringAndSize(NULL, len/size); - if ( rv == 0 ) - return 0; + if (!audioop_check_parameters(view.len, size)) + goto exit; + + rv = PyBytes_FromStringAndSize(NULL, view.len/size); + if (rv == NULL) + goto exit; ncp = (unsigned char *)PyBytes_AsString(rv); - for (i = 0; i < len; i += size) { - int val = GETSAMPLE32(size, cp, i); + for (i = 0; i < view.len; i += size) { + int val = GETSAMPLE32(size, view.buf, i); *ncp++ = st_14linear2ulaw(val >> 18); } + exit: + PyBuffer_Release(&view); return rv; } static PyObject * audioop_ulaw2lin(PyObject *self, PyObject *args) { + Py_buffer view; unsigned char *cp; signed char *ncp; - Py_ssize_t len, i; + Py_ssize_t i; int size; - PyObject *rv; + PyObject *rv = NULL; - if ( !PyArg_ParseTuple(args, "s#i:ulaw2lin", - &cp, &len, &size) ) - return 0; + if (!PyArg_ParseTuple(args, "y*i:ulaw2lin", + &view, &size)) + return NULL; if (!audioop_check_size(size)) - return NULL; + goto exit; - if (len > PY_SSIZE_T_MAX/size) { + if (view.len > PY_SSIZE_T_MAX/size) { PyErr_SetString(PyExc_MemoryError, "not enough memory for output buffer"); - return 0; + goto exit; } - rv = PyBytes_FromStringAndSize(NULL, len*size); - if ( rv == 0 ) - return 0; + rv = PyBytes_FromStringAndSize(NULL, view.len*size); + if (rv == NULL) + goto exit; ncp = (signed char *)PyBytes_AsString(rv); - for (i = 0; i < len*size; i += size) { + cp = view.buf; + for (i = 0; i < view.len*size; i += size) { int val = st_ulaw2linear16(*cp++) << 16; SETSAMPLE32(size, ncp, i, val); } + exit: + PyBuffer_Release(&view); return rv; } static PyObject * audioop_lin2alaw(PyObject *self, PyObject *args) { - signed char *cp; + Py_buffer view; unsigned char *ncp; - Py_ssize_t len, i; + Py_ssize_t i; int size; - PyObject *rv; + PyObject *rv = NULL; - if ( !PyArg_ParseTuple(args, "s#i:lin2alaw", - &cp, &len, &size) ) - return 0; - - if (!audioop_check_parameters(len, size)) + if (!PyArg_ParseTuple(args, "y*i:lin2alaw", + &view, &size)) return NULL; - rv = PyBytes_FromStringAndSize(NULL, len/size); - if ( rv == 0 ) - return 0; + if (!audioop_check_parameters(view.len, size)) + goto exit; + + rv = PyBytes_FromStringAndSize(NULL, view.len/size); + if (rv == NULL) + goto exit; ncp = (unsigned char *)PyBytes_AsString(rv); - for (i = 0; i < len; i += size) { - int val = GETSAMPLE32(size, cp, i); + for (i = 0; i < view.len; i += size) { + int val = GETSAMPLE32(size, view.buf, i); *ncp++ = st_linear2alaw(val >> 19); } + exit: + PyBuffer_Release(&view); return rv; } static PyObject * audioop_alaw2lin(PyObject *self, PyObject *args) { + Py_buffer view; unsigned char *cp; signed char *ncp; - Py_ssize_t len, i; + Py_ssize_t i; int size, val; - PyObject *rv; + PyObject *rv = NULL; - if ( !PyArg_ParseTuple(args, "s#i:alaw2lin", - &cp, &len, &size) ) - return 0; + if (!PyArg_ParseTuple(args, "y*i:alaw2lin", + &view, &size)) + return NULL; if (!audioop_check_size(size)) - return NULL; + goto exit; - if (len > PY_SSIZE_T_MAX/size) { + if (view.len > PY_SSIZE_T_MAX/size) { PyErr_SetString(PyExc_MemoryError, "not enough memory for output buffer"); - return 0; + goto exit; } - rv = PyBytes_FromStringAndSize(NULL, len*size); - if ( rv == 0 ) - return 0; + rv = PyBytes_FromStringAndSize(NULL, view.len*size); + if (rv == NULL) + goto exit; ncp = (signed char *)PyBytes_AsString(rv); + cp = view.buf; - for (i = 0; i < len*size; i += size) { + for (i = 0; i < view.len*size; i += size) { val = st_alaw2linear16(*cp++) << 16; SETSAMPLE32(size, ncp, i, val); } + exit: + PyBuffer_Release(&view); return rv; } static PyObject * audioop_lin2adpcm(PyObject *self, PyObject *args) { - signed char *cp; + Py_buffer view; signed char *ncp; - Py_ssize_t len, i; + Py_ssize_t i; int size, step, valpred, delta, index, sign, vpdiff, diff; - PyObject *rv, *state, *str; + PyObject *rv = NULL, *state, *str; int outputbuffer = 0, bufferstep; - if ( !PyArg_ParseTuple(args, "s#iO:lin2adpcm", - &cp, &len, &size, &state) ) - return 0; - - if (!audioop_check_parameters(len, size)) + if (!PyArg_ParseTuple(args, "y*iO:lin2adpcm", + &view, &size, &state)) return NULL; - str = PyBytes_FromStringAndSize(NULL, len/(size*2)); - if ( str == 0 ) - return 0; + if (!audioop_check_parameters(view.len, size)) + goto exit; + + str = PyBytes_FromStringAndSize(NULL, view.len/(size*2)); + if (str == NULL) + goto exit; ncp = (signed char *)PyBytes_AsString(str); /* Decode state, should have (value, step) */ @@ -1410,14 +1494,14 @@ audioop_lin2adpcm(PyObject *self, PyObject *args) /* First time, it seems. Set defaults */ valpred = 0; index = 0; - } else if ( !PyArg_ParseTuple(state, "ii", &valpred, &index) ) - return 0; + } else if (!PyArg_ParseTuple(state, "ii", &valpred, &index)) + goto exit; step = stepsizeTable[index]; bufferstep = 1; - for (i = 0; i < len; i += size) { - int val = GETSAMPLE32(size, cp, i) >> 16; + for (i = 0; i < view.len; i += size) { + int val = GETSAMPLE32(size, view.buf, i) >> 16; /* Step 1 - compute difference with previous value */ if (val < valpred) { @@ -1488,44 +1572,48 @@ audioop_lin2adpcm(PyObject *self, PyObject *args) } rv = Py_BuildValue("(O(ii))", str, valpred, index); Py_DECREF(str); + exit: + PyBuffer_Release(&view); return rv; } static PyObject * audioop_adpcm2lin(PyObject *self, PyObject *args) { + Py_buffer view; signed char *cp; signed char *ncp; - Py_ssize_t len, i, outlen; + Py_ssize_t i, outlen; int size, valpred, step, delta, index, sign, vpdiff; - PyObject *rv, *str, *state; + PyObject *rv = NULL, *str, *state; int inputbuffer = 0, bufferstep; - if ( !PyArg_ParseTuple(args, "s#iO:adpcm2lin", - &cp, &len, &size, &state) ) - return 0; + if (!PyArg_ParseTuple(args, "y*iO:adpcm2lin", + &view, &size, &state)) + return NULL; if (!audioop_check_size(size)) - return NULL; + goto exit; /* Decode state, should have (value, step) */ if ( state == Py_None ) { /* First time, it seems. Set defaults */ valpred = 0; index = 0; - } else if ( !PyArg_ParseTuple(state, "ii", &valpred, &index) ) - return 0; + } else if (!PyArg_ParseTuple(state, "ii", &valpred, &index)) + goto exit; - if (len > (PY_SSIZE_T_MAX/2)/size) { + if (view.len > (PY_SSIZE_T_MAX/2)/size) { PyErr_SetString(PyExc_MemoryError, "not enough memory for output buffer"); - return 0; + goto exit; } - outlen = len*size*2; + outlen = view.len*size*2; str = PyBytes_FromStringAndSize(NULL, outlen); - if ( str == 0 ) - return 0; + if (str == NULL) + goto exit; ncp = (signed char *)PyBytes_AsString(str); + cp = view.buf; step = stepsizeTable[index]; bufferstep = 0; @@ -1580,6 +1668,8 @@ audioop_adpcm2lin(PyObject *self, PyObject *args) rv = Py_BuildValue("(O(ii))", str, valpred, index); Py_DECREF(str); + exit: + PyBuffer_Release(&view); return rv; } |