Issue #12866: The audioop module now supports 24-bit samples.

This commit is contained in:
Serhiy Storchaka 2013-10-19 21:10:46 +03:00
parent c679227e31
commit eaea5e9107
5 changed files with 252 additions and 258 deletions

View file

@ -6,9 +6,12 @@
The :mod:`audioop` module contains some useful operations on sound fragments. The :mod:`audioop` module contains some useful operations on sound fragments.
It operates on sound fragments consisting of signed integer samples 8, 16 or 32 It operates on sound fragments consisting of signed integer samples 8, 16, 24
bits wide, stored in bytes objects. All scalar items are integers, unless or 32 bits wide, stored in bytes objects. All scalar items are integers,
specified otherwise. unless specified otherwise.
.. versionchanged:: 3.4
Support for 24-bit samples was added.
.. index:: .. index::
single: Intel/DVI ADPCM single: Intel/DVI ADPCM
@ -35,7 +38,7 @@ The module defines the following variables and functions:
.. function:: add(fragment1, fragment2, width) .. function:: add(fragment1, fragment2, width)
Return a fragment which is the addition of the two samples passed as parameters. Return a fragment which is the addition of the two samples passed as parameters.
*width* is the sample width in bytes, either ``1``, ``2`` or ``4``. Both *width* is the sample width in bytes, either ``1``, ``2``, ``3`` or ``4``. Both
fragments should have the same length. Samples are truncated in case of overflow. fragments should have the same length. Samples are truncated in case of overflow.
@ -133,19 +136,19 @@ The module defines the following variables and functions:
.. function:: lin2lin(fragment, width, newwidth) .. function:: lin2lin(fragment, width, newwidth)
Convert samples between 1-, 2- and 4-byte formats. Convert samples between 1-, 2-, 3- and 4-byte formats.
.. note:: .. note::
In some audio formats, such as .WAV files, 16 and 32 bit samples are In some audio formats, such as .WAV files, 16, 24 and 32 bit samples are
signed, but 8 bit samples are unsigned. So when converting to 8 bit wide signed, but 8 bit samples are unsigned. So when converting to 8 bit wide
samples for these formats, you need to also add 128 to the result:: samples for these formats, you need to also add 128 to the result::
new_frames = audioop.lin2lin(frames, old_width, 1) new_frames = audioop.lin2lin(frames, old_width, 1)
new_frames = audioop.bias(new_frames, 1, 128) new_frames = audioop.bias(new_frames, 1, 128)
The same, in reverse, has to be applied when converting from 8 to 16 or 32 The same, in reverse, has to be applied when converting from 8 to 16, 24
bit width samples. or 32 bit width samples.
.. function:: lin2ulaw(fragment, width) .. function:: lin2ulaw(fragment, width)

View file

@ -197,6 +197,12 @@ The :meth:`~aifc.getparams` method now returns a namedtuple rather than a
plain tuple. (Contributed by Claudiu Popa in :issue:`17818`.) plain tuple. (Contributed by Claudiu Popa in :issue:`17818`.)
audioop
-------
Added support for 24-bit samples (:issue:`12866`).
codecs codecs
------ ------

View file

@ -6,13 +6,18 @@ from test.support import run_unittest
def pack(width, data): def pack(width, data):
return b''.join(v.to_bytes(width, sys.byteorder, signed=True) for v in data) return b''.join(v.to_bytes(width, sys.byteorder, signed=True) for v in data)
packs = {w: (lambda *data, width=w: pack(width, data)) for w in (1, 2, 4)} def unpack(width, data):
maxvalues = {w: (1 << (8 * w - 1)) - 1 for w in (1, 2, 4)} return [int.from_bytes(data[i: i + width], sys.byteorder, signed=True)
minvalues = {w: -1 << (8 * w - 1) for w in (1, 2, 4)} for i in range(0, len(data), width)]
packs = {w: (lambda *data, width=w: pack(width, data)) for w in (1, 2, 3, 4)}
maxvalues = {w: (1 << (8 * w - 1)) - 1 for w in (1, 2, 3, 4)}
minvalues = {w: -1 << (8 * w - 1) for w in (1, 2, 3, 4)}
datas = { datas = {
1: b'\x00\x12\x45\xbb\x7f\x80\xff', 1: b'\x00\x12\x45\xbb\x7f\x80\xff',
2: packs[2](0, 0x1234, 0x4567, -0x4567, 0x7fff, -0x8000, -1), 2: packs[2](0, 0x1234, 0x4567, -0x4567, 0x7fff, -0x8000, -1),
3: packs[3](0, 0x123456, 0x456789, -0x456789, 0x7fffff, -0x800000, -1),
4: packs[4](0, 0x12345678, 0x456789ab, -0x456789ab, 4: packs[4](0, 0x12345678, 0x456789ab, -0x456789ab,
0x7fffffff, -0x80000000, -1), 0x7fffffff, -0x80000000, -1),
} }
@ -20,6 +25,7 @@ datas = {
INVALID_DATA = [ INVALID_DATA = [
(b'abc', 0), (b'abc', 0),
(b'abc', 2), (b'abc', 2),
(b'ab', 3),
(b'abc', 4), (b'abc', 4),
] ]
@ -27,7 +33,7 @@ INVALID_DATA = [
class TestAudioop(unittest.TestCase): class TestAudioop(unittest.TestCase):
def test_max(self): def test_max(self):
for w in 1, 2, 4: for w in 1, 2, 3, 4:
self.assertEqual(audioop.max(b'', w), 0) self.assertEqual(audioop.max(b'', w), 0)
p = packs[w] p = packs[w]
self.assertEqual(audioop.max(p(5), w), 5) self.assertEqual(audioop.max(p(5), w), 5)
@ -37,7 +43,7 @@ class TestAudioop(unittest.TestCase):
self.assertEqual(audioop.max(datas[w], w), -minvalues[w]) self.assertEqual(audioop.max(datas[w], w), -minvalues[w])
def test_minmax(self): def test_minmax(self):
for w in 1, 2, 4: for w in 1, 2, 3, 4:
self.assertEqual(audioop.minmax(b'', w), self.assertEqual(audioop.minmax(b'', w),
(0x7fffffff, -0x80000000)) (0x7fffffff, -0x80000000))
p = packs[w] p = packs[w]
@ -51,7 +57,7 @@ class TestAudioop(unittest.TestCase):
(minvalues[w], maxvalues[w])) (minvalues[w], maxvalues[w]))
def test_maxpp(self): def test_maxpp(self):
for w in 1, 2, 4: for w in 1, 2, 3, 4:
self.assertEqual(audioop.maxpp(b'', w), 0) self.assertEqual(audioop.maxpp(b'', w), 0)
self.assertEqual(audioop.maxpp(packs[w](*range(100)), 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(packs[w](9, 10, 5, 5, 0, 1), w), 10)
@ -59,7 +65,7 @@ class TestAudioop(unittest.TestCase):
maxvalues[w] - minvalues[w]) maxvalues[w] - minvalues[w])
def test_avg(self): def test_avg(self):
for w in 1, 2, 4: for w in 1, 2, 3, 4:
self.assertEqual(audioop.avg(b'', w), 0) self.assertEqual(audioop.avg(b'', w), 0)
p = packs[w] p = packs[w]
self.assertEqual(audioop.avg(p(5), w), 5) self.assertEqual(audioop.avg(p(5), w), 5)
@ -75,7 +81,7 @@ class TestAudioop(unittest.TestCase):
-0x60000000) -0x60000000)
def test_avgpp(self): def test_avgpp(self):
for w in 1, 2, 4: for w in 1, 2, 3, 4:
self.assertEqual(audioop.avgpp(b'', w), 0) self.assertEqual(audioop.avgpp(b'', w), 0)
self.assertEqual(audioop.avgpp(packs[w](*range(100)), 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(packs[w](9, 10, 5, 5, 0, 1), w), 10)
@ -84,7 +90,7 @@ class TestAudioop(unittest.TestCase):
self.assertEqual(audioop.avgpp(datas[4], 4), 3311897002) self.assertEqual(audioop.avgpp(datas[4], 4), 3311897002)
def test_rms(self): def test_rms(self):
for w in 1, 2, 4: for w in 1, 2, 3, 4:
self.assertEqual(audioop.rms(b'', w), 0) self.assertEqual(audioop.rms(b'', w), 0)
p = packs[w] p = packs[w]
self.assertEqual(audioop.rms(p(*range(100)), w), 57) self.assertEqual(audioop.rms(p(*range(100)), w), 57)
@ -97,7 +103,7 @@ class TestAudioop(unittest.TestCase):
self.assertEqual(audioop.rms(datas[4], 4), 1310854152) self.assertEqual(audioop.rms(datas[4], 4), 1310854152)
def test_cross(self): def test_cross(self):
for w in 1, 2, 4: for w in 1, 2, 3, 4:
self.assertEqual(audioop.cross(b'', w), -1) self.assertEqual(audioop.cross(b'', w), -1)
p = packs[w] p = packs[w]
self.assertEqual(audioop.cross(p(0, 1, 2), w), 0) self.assertEqual(audioop.cross(p(0, 1, 2), w), 0)
@ -107,7 +113,7 @@ class TestAudioop(unittest.TestCase):
self.assertEqual(audioop.cross(p(minvalues[w], maxvalues[w]), w), 1) self.assertEqual(audioop.cross(p(minvalues[w], maxvalues[w]), w), 1)
def test_add(self): def test_add(self):
for w in 1, 2, 4: for w in 1, 2, 3, 4:
self.assertEqual(audioop.add(b'', b'', w), b'') self.assertEqual(audioop.add(b'', b'', w), b'')
self.assertEqual(audioop.add(datas[w], b'\0' * len(datas[w]), w), self.assertEqual(audioop.add(datas[w], b'\0' * len(datas[w]), w),
datas[w]) datas[w])
@ -120,7 +126,7 @@ class TestAudioop(unittest.TestCase):
0x7fffffff, -0x80000000, -2)) 0x7fffffff, -0x80000000, -2))
def test_bias(self): def test_bias(self):
for w in 1, 2, 4: for w in 1, 2, 3, 4:
for bias in 0, 1, -1, 127, -128, 0x7fffffff, -0x80000000: for bias in 0, 1, -1, 127, -128, 0x7fffffff, -0x80000000:
self.assertEqual(audioop.bias(b'', w, bias), b'') self.assertEqual(audioop.bias(b'', w, bias), b'')
self.assertEqual(audioop.bias(datas[1], 1, 1), self.assertEqual(audioop.bias(datas[1], 1, 1),
@ -153,7 +159,7 @@ class TestAudioop(unittest.TestCase):
-1, 0, 0x7fffffff)) -1, 0, 0x7fffffff))
def test_lin2lin(self): def test_lin2lin(self):
for w in 1, 2, 4: for w in 1, 2, 3, 4:
self.assertEqual(audioop.lin2lin(datas[w], w, w), datas[w]) self.assertEqual(audioop.lin2lin(datas[w], w, w), datas[w])
self.assertEqual(audioop.lin2lin(datas[1], 1, 2), self.assertEqual(audioop.lin2lin(datas[1], 1, 2),
@ -181,7 +187,7 @@ class TestAudioop(unittest.TestCase):
-0xb30000), (-179, 40))) -0xb30000), (-179, 40)))
# Very cursory test # Very cursory test
for w in 1, 2, 4: for w in 1, 2, 3, 4:
self.assertEqual(audioop.adpcm2lin(b'\0' * 5, w, None), self.assertEqual(audioop.adpcm2lin(b'\0' * 5, w, None),
(b'\0' * w * 10, (0, 0))) (b'\0' * w * 10, (0, 0)))
@ -194,7 +200,7 @@ class TestAudioop(unittest.TestCase):
(b'\x07\x7f\x7f', (31, 39))) (b'\x07\x7f\x7f', (31, 39)))
# Very cursory test # Very cursory test
for w in 1, 2, 4: for w in 1, 2, 3, 4:
self.assertEqual(audioop.lin2adpcm(b'\0' * w * 10, w, None), self.assertEqual(audioop.lin2adpcm(b'\0' * w * 10, w, None),
(b'\0' * 5, (0, 0))) (b'\0' * 5, (0, 0)))
@ -211,12 +217,12 @@ class TestAudioop(unittest.TestCase):
b'\x80\x83\xa4\xaa\xd1\xd4\xd5\xd8\xeb\xf1\xff' b'\x80\x83\xa4\xaa\xd1\xd4\xd5\xd8\xeb\xf1\xff'
src = [-688, -720, -2240, -4032, -9, -3, -1, -27, -244, -82, -106, src = [-688, -720, -2240, -4032, -9, -3, -1, -27, -244, -82, -106,
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, 4: for w in 1, 2, 3, 4:
self.assertEqual(audioop.alaw2lin(encoded, w), self.assertEqual(audioop.alaw2lin(encoded, w),
packs[w](*(x << (w * 8) >> 13 for x in src))) packs[w](*(x << (w * 8) >> 13 for x in src)))
encoded = bytes(range(256)) encoded = bytes(range(256))
for w in 2, 4: for w in 2, 3, 4:
decoded = audioop.alaw2lin(encoded, w) decoded = audioop.alaw2lin(encoded, w)
self.assertEqual(audioop.lin2alaw(decoded, w), encoded) self.assertEqual(audioop.lin2alaw(decoded, w), encoded)
@ -233,18 +239,18 @@ class TestAudioop(unittest.TestCase):
b'\x80\x8e\xa8\xbf\xd7\xea\xf6\xfc\xfe\xff' b'\x80\x8e\xa8\xbf\xd7\xea\xf6\xfc\xfe\xff'
src = [-8031, -4447, -1471, -495, -163, -53, -18, -6, -2, 0, src = [-8031, -4447, -1471, -495, -163, -53, -18, -6, -2, 0,
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, 4: for w in 1, 2, 3, 4:
self.assertEqual(audioop.ulaw2lin(encoded, w), self.assertEqual(audioop.ulaw2lin(encoded, w),
packs[w](*(x << (w * 8) >> 14 for x in src))) packs[w](*(x << (w * 8) >> 14 for x in src)))
# Current u-law implementation has two codes fo 0: 0x7f and 0xff. # Current u-law implementation has two codes fo 0: 0x7f and 0xff.
encoded = bytes(range(127)) + bytes(range(128, 256)) encoded = bytes(range(127)) + bytes(range(128, 256))
for w in 2, 4: for w in 2, 3, 4:
decoded = audioop.ulaw2lin(encoded, w) decoded = audioop.ulaw2lin(encoded, w)
self.assertEqual(audioop.lin2ulaw(decoded, w), encoded) self.assertEqual(audioop.lin2ulaw(decoded, w), encoded)
def test_mul(self): def test_mul(self):
for w in 1, 2, 4: for w in 1, 2, 3, 4:
self.assertEqual(audioop.mul(b'', w, 2), b'') self.assertEqual(audioop.mul(b'', w, 2), b'')
self.assertEqual(audioop.mul(datas[w], w, 0), self.assertEqual(audioop.mul(datas[w], w, 0),
b'\0' * len(datas[w])) b'\0' * len(datas[w]))
@ -259,7 +265,7 @@ class TestAudioop(unittest.TestCase):
0x7fffffff, -0x80000000, -2)) 0x7fffffff, -0x80000000, -2))
def test_ratecv(self): def test_ratecv(self):
for w in 1, 2, 4: for w in 1, 2, 3, 4:
self.assertEqual(audioop.ratecv(b'', w, 1, 8000, 8000, None), self.assertEqual(audioop.ratecv(b'', w, 1, 8000, 8000, None),
(b'', (-1, ((0, 0),)))) (b'', (-1, ((0, 0),))))
self.assertEqual(audioop.ratecv(b'', w, 5, 8000, 8000, None), self.assertEqual(audioop.ratecv(b'', w, 5, 8000, 8000, None),
@ -273,7 +279,7 @@ class TestAudioop(unittest.TestCase):
d2, state = audioop.ratecv(b'\x00\x01\x02', 1, 1, 8000, 16000, state) d2, state = audioop.ratecv(b'\x00\x01\x02', 1, 1, 8000, 16000, state)
self.assertEqual(d1 + d2, b'\000\000\001\001\002\001\000\000\001\001\002') self.assertEqual(d1 + d2, b'\000\000\001\001\002\001\000\000\001\001\002')
for w in 1, 2, 4: for w in 1, 2, 3, 4:
d0, state0 = audioop.ratecv(datas[w], w, 1, 8000, 16000, None) d0, state0 = audioop.ratecv(datas[w], w, 1, 8000, 16000, None)
d, state = b'', None d, state = b'', None
for i in range(0, len(datas[w]), w): for i in range(0, len(datas[w]), w):
@ -284,13 +290,13 @@ class TestAudioop(unittest.TestCase):
self.assertEqual(state, state0) self.assertEqual(state, state0)
def test_reverse(self): def test_reverse(self):
for w in 1, 2, 4: for w in 1, 2, 3, 4:
self.assertEqual(audioop.reverse(b'', w), b'') self.assertEqual(audioop.reverse(b'', w), b'')
self.assertEqual(audioop.reverse(packs[w](0, 1, 2), w), self.assertEqual(audioop.reverse(packs[w](0, 1, 2), w),
packs[w](2, 1, 0)) packs[w](2, 1, 0))
def test_tomono(self): def test_tomono(self):
for w in 1, 2, 4: for w in 1, 2, 3, 4:
data1 = datas[w] data1 = datas[w]
data2 = bytearray(2 * len(data1)) data2 = bytearray(2 * len(data1))
for k in range(w): for k in range(w):
@ -302,7 +308,7 @@ class TestAudioop(unittest.TestCase):
self.assertEqual(audioop.tomono(data2, w, 0.5, 0.5), data1) self.assertEqual(audioop.tomono(data2, w, 0.5, 0.5), data1)
def test_tostereo(self): def test_tostereo(self):
for w in 1, 2, 4: for w in 1, 2, 3, 4:
data1 = datas[w] data1 = datas[w]
data2 = bytearray(2 * len(data1)) data2 = bytearray(2 * len(data1))
for k in range(w): for k in range(w):
@ -329,7 +335,7 @@ class TestAudioop(unittest.TestCase):
self.assertEqual(audioop.findmax(datas[2], 1), 5) self.assertEqual(audioop.findmax(datas[2], 1), 5)
def test_getsample(self): def test_getsample(self):
for w in 1, 2, 4: for w in 1, 2, 3, 4:
data = packs[w](0, 1, -1, maxvalues[w], minvalues[w]) data = packs[w](0, 1, -1, maxvalues[w], minvalues[w])
self.assertEqual(audioop.getsample(data, w, 0), 0) self.assertEqual(audioop.getsample(data, w, 0), 0)
self.assertEqual(audioop.getsample(data, w, 1), 1) self.assertEqual(audioop.getsample(data, w, 1), 1)
@ -369,7 +375,7 @@ class TestAudioop(unittest.TestCase):
def test_wrongsize(self): def test_wrongsize(self):
data = b'abcdefgh' data = b'abcdefgh'
state = None state = None
for size in (-1, 0, 3, 5, 1024): for size in (-1, 0, 5, 1024):
self.assertRaises(audioop.error, audioop.ulaw2lin, data, size) self.assertRaises(audioop.error, audioop.ulaw2lin, data, size)
self.assertRaises(audioop.error, audioop.alaw2lin, data, size) self.assertRaises(audioop.error, audioop.alaw2lin, data, size)
self.assertRaises(audioop.error, audioop.adpcm2lin, data, size, state) self.assertRaises(audioop.error, audioop.adpcm2lin, data, size, state)

View file

@ -59,6 +59,8 @@ Core and Builtins
Library Library
------- -------
- Issue #12866: The audioop module now supports 24-bit samples.
- Issue #19254: Provide an optimized Python implementation of pbkdf2_hmac. - Issue #19254: Provide an optimized Python implementation of pbkdf2_hmac.
- Issues #19201, #19222, #19223: Add "x" mode (exclusive creation) in opening - Issues #19201, #19222, #19223: Add "x" mode (exclusive creation) in opening

View file

@ -5,18 +5,6 @@
#include "Python.h" #include "Python.h"
#if SIZEOF_INT == 4
typedef int Py_Int32;
typedef unsigned int Py_UInt32;
#else
#if SIZEOF_LONG == 4
typedef long Py_Int32;
typedef unsigned long Py_UInt32;
#else
#error "No 4-byte integral type"
#endif
#endif
typedef short PyInt16; typedef short PyInt16;
#if defined(__CHAR_UNSIGNED__) #if defined(__CHAR_UNSIGNED__)
@ -160,9 +148,6 @@ st_14linear2ulaw(PyInt16 pcm_val) /* 2's complement (14-bit range) */
PyInt16 seg; PyInt16 seg;
unsigned char uval; unsigned char uval;
/* The original sox code does this in the calling function, not here */
pcm_val = pcm_val >> 2;
/* u-law inverts all bits */ /* u-law inverts all bits */
/* Get the sign and the magnitude of the value. */ /* Get the sign and the magnitude of the value. */
if (pcm_val < 0) { if (pcm_val < 0) {
@ -257,9 +242,6 @@ st_linear2alaw(PyInt16 pcm_val) /* 2's complement (13-bit range) */
short seg; short seg;
unsigned char aval; unsigned char aval;
/* The original sox code does this in the calling function, not here */
pcm_val = pcm_val >> 3;
/* A-law using even bit inversion */ /* A-law using even bit inversion */
if (pcm_val >= 0) { if (pcm_val >= 0) {
mask = 0xD5; /* sign (7th) bit = 1 */ mask = 0xD5; /* sign (7th) bit = 1 */
@ -304,19 +286,91 @@ static int stepsizeTable[89] = {
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
}; };
#define CHARP(cp, i) ((signed char *)(cp+i)) #define GETINTX(T, cp, i) (*(T *)((cp) + (i)))
#define SHORTP(cp, i) ((short *)(cp+i)) #define SETINTX(T, cp, i, val) do { \
#define LONGP(cp, i) ((Py_Int32 *)(cp+i)) *(T *)((cp) + (i)) = (T)(val); \
} while (0)
#define GETINT8(cp, i) GETINTX(signed char, (cp), (i))
#define GETINT16(cp, i) GETINTX(short, (cp), (i))
#define GETINT32(cp, i) GETINTX(PY_INT32_T, (cp), (i))
#if WORDS_BIGENDIAN
#define GETINT24(cp, i) ( \
((unsigned char *)(cp) + (i))[2] + \
(((unsigned char *)(cp) + (i))[1] << 8) + \
(((signed char *)(cp) + (i))[0] << 16) )
#else
#define GETINT24(cp, i) ( \
((unsigned char *)(cp) + (i))[0] + \
(((unsigned char *)(cp) + (i))[1] << 8) + \
(((signed char *)(cp) + (i))[2] << 16) )
#endif
#define SETINT8(cp, i, val) SETINTX(signed char, (cp), (i), (val))
#define SETINT16(cp, i, val) SETINTX(short, (cp), (i), (val))
#define SETINT32(cp, i, val) SETINTX(PY_INT32_T, (cp), (i), (val))
#if WORDS_BIGENDIAN
#define SETINT24(cp, i, val) do { \
((unsigned char *)(cp) + (i))[2] = (int)(val); \
((unsigned char *)(cp) + (i))[1] = (int)(val) >> 8; \
((signed char *)(cp) + (i))[0] = (int)(val) >> 16; \
} while (0)
#else
#define SETINT24(cp, i, val) do { \
((unsigned char *)(cp) + (i))[0] = (int)(val); \
((unsigned char *)(cp) + (i))[1] = (int)(val) >> 8; \
((signed char *)(cp) + (i))[2] = (int)(val) >> 16; \
} while (0)
#endif
#define GETRAWSAMPLE(size, cp, i) ( \
(size == 1) ? (int)GETINT8((cp), (i)) : \
(size == 2) ? (int)GETINT16((cp), (i)) : \
(size == 3) ? (int)GETINT24((cp), (i)) : \
(int)GETINT32((cp), (i)))
#define SETRAWSAMPLE(size, cp, i, val) do { \
if (size == 1) \
SETINT8((cp), (i), (val)); \
else if (size == 2) \
SETINT16((cp), (i), (val)); \
else if (size == 3) \
SETINT24((cp), (i), (val)); \
else \
SETINT32((cp), (i), (val)); \
} while(0)
#define GETSAMPLE32(size, cp, i) ( \
(size == 1) ? (int)GETINT8((cp), (i)) << 24 : \
(size == 2) ? (int)GETINT16((cp), (i)) << 16 : \
(size == 3) ? (int)GETINT24((cp), (i)) << 8 : \
(int)GETINT32((cp), (i)))
#define SETSAMPLE32(size, cp, i, val) do { \
if (size == 1) \
SETINT8((cp), (i), (val) >> 24); \
else if (size == 2) \
SETINT16((cp), (i), (val) >> 16); \
else if (size == 3) \
SETINT24((cp), (i), (val) >> 8); \
else \
SETINT32((cp), (i), (val)); \
} while(0)
static PyObject *AudioopError; static PyObject *AudioopError;
static int static int
audioop_check_size(int size) audioop_check_size(int size)
{ {
if (size != 1 && size != 2 && size != 4) { if (size < 1 || size > 4) {
PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); PyErr_SetString(AudioopError, "Size should be 1, 2, 3 or 4");
return 0; return 0;
} }
else else
@ -340,7 +394,7 @@ audioop_getsample(PyObject *self, PyObject *args)
{ {
signed char *cp; signed char *cp;
Py_ssize_t len, i; Py_ssize_t len, i;
int size, val = 0; int size;
if ( !PyArg_ParseTuple(args, "s#in:getsample", &cp, &len, &size, &i) ) if ( !PyArg_ParseTuple(args, "s#in:getsample", &cp, &len, &size, &i) )
return 0; return 0;
@ -350,10 +404,7 @@ audioop_getsample(PyObject *self, PyObject *args)
PyErr_SetString(AudioopError, "Index out of range"); PyErr_SetString(AudioopError, "Index out of range");
return 0; return 0;
} }
if ( size == 1 ) val = (int)*CHARP(cp, i); return PyLong_FromLong(GETRAWSAMPLE(size, cp, i*size));
else if ( size == 2 ) val = (int)*SHORTP(cp, i*2);
else if ( size == 4 ) val = (int)*LONGP(cp, i*4);
return PyLong_FromLong(val);
} }
static PyObject * static PyObject *
@ -361,7 +412,7 @@ audioop_max(PyObject *self, PyObject *args)
{ {
signed char *cp; signed char *cp;
Py_ssize_t len, i; Py_ssize_t len, i;
int size, val = 0; int size;
unsigned int absval, max = 0; unsigned int absval, max = 0;
if ( !PyArg_ParseTuple(args, "s#i:max", &cp, &len, &size) ) if ( !PyArg_ParseTuple(args, "s#i:max", &cp, &len, &size) )
@ -369,9 +420,7 @@ audioop_max(PyObject *self, PyObject *args)
if (!audioop_check_parameters(len, size)) if (!audioop_check_parameters(len, size))
return NULL; return NULL;
for (i = 0; i < len; i += size) { for (i = 0; i < len; i += size) {
if ( size == 1 ) val = (int)*CHARP(cp, i); int val = GETRAWSAMPLE(size, cp, i);
else if ( size == 2 ) val = (int)*SHORTP(cp, i);
else if ( size == 4 ) val = (int)*LONGP(cp, i);
if (val < 0) absval = (-val); if (val < 0) absval = (-val);
else absval = val; else absval = val;
if (absval > max) max = absval; if (absval > max) max = absval;
@ -384,7 +433,7 @@ audioop_minmax(PyObject *self, PyObject *args)
{ {
signed char *cp; signed char *cp;
Py_ssize_t len, i; Py_ssize_t len, i;
int size, val = 0; int size;
int min = 0x7fffffff, max = -0x80000000; int min = 0x7fffffff, max = -0x80000000;
if (!PyArg_ParseTuple(args, "s#i:minmax", &cp, &len, &size)) if (!PyArg_ParseTuple(args, "s#i:minmax", &cp, &len, &size))
@ -392,9 +441,7 @@ audioop_minmax(PyObject *self, PyObject *args)
if (!audioop_check_parameters(len, size)) if (!audioop_check_parameters(len, size))
return NULL; return NULL;
for (i = 0; i < len; i += size) { for (i = 0; i < len; i += size) {
if (size == 1) val = (int) *CHARP(cp, i); int val = GETRAWSAMPLE(size, cp, i);
else if (size == 2) val = (int) *SHORTP(cp, i);
else if (size == 4) val = (int) *LONGP(cp, i);
if (val > max) max = val; if (val > max) max = val;
if (val < min) min = val; if (val < min) min = val;
} }
@ -406,24 +453,20 @@ audioop_avg(PyObject *self, PyObject *args)
{ {
signed char *cp; signed char *cp;
Py_ssize_t len, i; Py_ssize_t len, i;
int size, val = 0; int size, avg;
double avg = 0.0; double sum = 0.0;
if ( !PyArg_ParseTuple(args, "s#i:avg", &cp, &len, &size) ) if ( !PyArg_ParseTuple(args, "s#i:avg", &cp, &len, &size) )
return 0; return 0;
if (!audioop_check_parameters(len, size)) if (!audioop_check_parameters(len, size))
return NULL; return NULL;
for ( i=0; i<len; i+= size) { for (i = 0; i < len; i += size)
if ( size == 1 ) val = (int)*CHARP(cp, i); sum += GETRAWSAMPLE(size, cp, i);
else if ( size == 2 ) val = (int)*SHORTP(cp, i);
else if ( size == 4 ) val = (int)*LONGP(cp, i);
avg += val;
}
if ( len == 0 ) if ( len == 0 )
val = 0; avg = 0;
else else
val = (int)floor(avg / (double)(len/size)); avg = (int)floor(sum / (double)(len/size));
return PyLong_FromLong(val); return PyLong_FromLong(avg);
} }
static PyObject * static PyObject *
@ -431,7 +474,7 @@ audioop_rms(PyObject *self, PyObject *args)
{ {
signed char *cp; signed char *cp;
Py_ssize_t len, i; Py_ssize_t len, i;
int size, val = 0; int size;
unsigned int res; unsigned int res;
double sum_squares = 0.0; double sum_squares = 0.0;
@ -440,10 +483,8 @@ audioop_rms(PyObject *self, PyObject *args)
if (!audioop_check_parameters(len, size)) if (!audioop_check_parameters(len, size))
return NULL; return NULL;
for (i = 0; i < len; i += size) { for (i = 0; i < len; i += size) {
if ( size == 1 ) val = (int)*CHARP(cp, i); double val = GETRAWSAMPLE(size, cp, i);
else if ( size == 2 ) val = (int)*SHORTP(cp, i); sum_squares += val*val;
else if ( size == 4 ) val = (int)*LONGP(cp, i);
sum_squares += (double)val*(double)val;
} }
if ( len == 0 ) if ( len == 0 )
res = 0; res = 0;
@ -637,7 +678,7 @@ audioop_avgpp(PyObject *self, PyObject *args)
{ {
signed char *cp; signed char *cp;
Py_ssize_t len, i; Py_ssize_t len, i;
int size, val = 0, prevval = 0, prevextremevalid = 0, int size, prevval, prevextremevalid = 0,
prevextreme = 0; prevextreme = 0;
double sum = 0.0; double sum = 0.0;
unsigned int avg; unsigned int avg;
@ -649,14 +690,10 @@ audioop_avgpp(PyObject *self, PyObject *args)
return NULL; return NULL;
if (len <= size) if (len <= size)
return PyLong_FromLong(0); return PyLong_FromLong(0);
if ( size == 1 ) prevval = (int)*CHARP(cp, 0); prevval = GETRAWSAMPLE(size, cp, 0);
else if ( size == 2 ) prevval = (int)*SHORTP(cp, 0);
else if ( size == 4 ) prevval = (int)*LONGP(cp, 0);
prevdiff = 17; /* Anything != 0, 1 */ prevdiff = 17; /* Anything != 0, 1 */
for (i = size; i < len; i += size) { for (i = size; i < len; i += size) {
if ( size == 1 ) val = (int)*CHARP(cp, i); int val = GETRAWSAMPLE(size, cp, i);
else if ( size == 2 ) val = (int)*SHORTP(cp, i);
else if ( size == 4 ) val = (int)*LONGP(cp, i);
if (val != prevval) { if (val != prevval) {
diff = val < prevval; diff = val < prevval;
if (prevdiff == !diff) { if (prevdiff == !diff) {
@ -664,7 +701,12 @@ audioop_avgpp(PyObject *self, PyObject *args)
** extreme value and remember. ** extreme value and remember.
*/ */
if (prevextremevalid) { if (prevextremevalid) {
sum += fabs((double)prevval - (double)prevextreme); if (prevval < prevextreme)
sum += (double)((unsigned int)prevextreme -
(unsigned int)prevval);
else
sum += (double)((unsigned int)prevval -
(unsigned int)prevextreme);
nextreme++; nextreme++;
} }
prevextremevalid = 1; prevextremevalid = 1;
@ -686,7 +728,7 @@ audioop_maxpp(PyObject *self, PyObject *args)
{ {
signed char *cp; signed char *cp;
Py_ssize_t len, i; Py_ssize_t len, i;
int size, val = 0, prevval = 0, prevextremevalid = 0, int size, prevval, prevextremevalid = 0,
prevextreme = 0; prevextreme = 0;
unsigned int max = 0, extremediff; unsigned int max = 0, extremediff;
int diff, prevdiff; int diff, prevdiff;
@ -697,14 +739,10 @@ audioop_maxpp(PyObject *self, PyObject *args)
return NULL; return NULL;
if (len <= size) if (len <= size)
return PyLong_FromLong(0); return PyLong_FromLong(0);
if ( size == 1 ) prevval = (int)*CHARP(cp, 0); prevval = GETRAWSAMPLE(size, cp, 0);
else if ( size == 2 ) prevval = (int)*SHORTP(cp, 0);
else if ( size == 4 ) prevval = (int)*LONGP(cp, 0);
prevdiff = 17; /* Anything != 0, 1 */ prevdiff = 17; /* Anything != 0, 1 */
for (i = size; i < len; i += size) { for (i = size; i < len; i += size) {
if ( size == 1 ) val = (int)*CHARP(cp, i); int val = GETRAWSAMPLE(size, cp, i);
else if ( size == 2 ) val = (int)*SHORTP(cp, i);
else if ( size == 4 ) val = (int)*LONGP(cp, i);
if (val != prevval) { if (val != prevval) {
diff = val < prevval; diff = val < prevval;
if (prevdiff == !diff) { if (prevdiff == !diff) {
@ -736,7 +774,7 @@ audioop_cross(PyObject *self, PyObject *args)
{ {
signed char *cp; signed char *cp;
Py_ssize_t len, i; Py_ssize_t len, i;
int size, val = 0; int size;
int prevval; int prevval;
Py_ssize_t ncross; Py_ssize_t ncross;
@ -747,10 +785,7 @@ audioop_cross(PyObject *self, PyObject *args)
ncross = -1; ncross = -1;
prevval = 17; /* Anything <> 0,1 */ prevval = 17; /* Anything <> 0,1 */
for (i = 0; i < len; i += size) { for (i = 0; i < len; i += size) {
if ( size == 1 ) val = ((int)*CHARP(cp, i)) >> 7; int val = GETRAWSAMPLE(size, cp, i) < 0;
else if ( size == 2 ) val = ((int)*SHORTP(cp, i)) >> 15;
else if ( size == 4 ) val = ((int)*LONGP(cp, i)) >> 31;
val = val & 1;
if (val != prevval) ncross++; if (val != prevval) ncross++;
prevval = val; prevval = val;
} }
@ -762,8 +797,8 @@ audioop_mul(PyObject *self, PyObject *args)
{ {
signed char *cp, *ncp; signed char *cp, *ncp;
Py_ssize_t len, i; Py_ssize_t len, i;
int size, val = 0; int size;
double factor, fval, maxval, minval; double factor, maxval, minval;
PyObject *rv; PyObject *rv;
if ( !PyArg_ParseTuple(args, "s#id:mul", &cp, &len, &size, &factor ) ) if ( !PyArg_ParseTuple(args, "s#id:mul", &cp, &len, &size, &factor ) )
@ -779,16 +814,11 @@ audioop_mul(PyObject *self, PyObject *args)
return 0; return 0;
ncp = (signed char *)PyBytes_AsString(rv); ncp = (signed char *)PyBytes_AsString(rv);
for (i = 0; i < len; i += size) { for (i = 0; i < len; i += size) {
if ( size == 1 ) val = (int)*CHARP(cp, i); double val = GETRAWSAMPLE(size, cp, i);
else if ( size == 2 ) val = (int)*SHORTP(cp, i); val *= factor;
else if ( size == 4 ) val = (int)*LONGP(cp, i); val = floor(fbound(val, minval, maxval));
fval = (double)val*factor; SETRAWSAMPLE(size, ncp, i, (int)val);
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;
} }
return rv; return rv;
} }
@ -799,8 +829,8 @@ audioop_tomono(PyObject *self, PyObject *args)
Py_buffer pcp; Py_buffer pcp;
signed char *cp, *ncp; signed char *cp, *ncp;
Py_ssize_t len, i; Py_ssize_t len, i;
int size, val1 = 0, val2 = 0; int size;
double fac1, fac2, fval, maxval, minval; double fac1, fac2, maxval, minval;
PyObject *rv; PyObject *rv;
if ( !PyArg_ParseTuple(args, "s*idd:tomono", if ( !PyArg_ParseTuple(args, "s*idd:tomono",
@ -828,19 +858,12 @@ audioop_tomono(PyObject *self, PyObject *args)
} }
ncp = (signed char *)PyBytes_AsString(rv); ncp = (signed char *)PyBytes_AsString(rv);
for (i = 0; i < len; i += size*2) { for (i = 0; i < len; i += size*2) {
if ( size == 1 ) val1 = (int)*CHARP(cp, i); double val1 = GETRAWSAMPLE(size, cp, i);
else if ( size == 2 ) val1 = (int)*SHORTP(cp, i); double val2 = GETRAWSAMPLE(size, cp, i + size);
else if ( size == 4 ) val1 = (int)*LONGP(cp, i); double val = val1*fac1 + val2*fac2;
if ( size == 1 ) val2 = (int)*CHARP(cp, i+1); val = floor(fbound(val, minval, maxval));
else if ( size == 2 ) val2 = (int)*SHORTP(cp, i+2); SETRAWSAMPLE(size, ncp, i/2, val);
else if ( size == 4 ) val2 = (int)*LONGP(cp, i+4);
fval = (double)val1*fac1 + (double)val2*fac2;
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;
} }
PyBuffer_Release(&pcp); PyBuffer_Release(&pcp);
return rv; return rv;
@ -851,8 +874,8 @@ audioop_tostereo(PyObject *self, PyObject *args)
{ {
signed char *cp, *ncp; signed char *cp, *ncp;
Py_ssize_t len, i; Py_ssize_t len, i;
int size, val1, val2, val = 0; int size;
double fac1, fac2, fval, maxval, minval; double fac1, fac2, maxval, minval;
PyObject *rv; PyObject *rv;
if ( !PyArg_ParseTuple(args, "s#idd:tostereo", if ( !PyArg_ParseTuple(args, "s#idd:tostereo",
@ -875,25 +898,12 @@ audioop_tostereo(PyObject *self, PyObject *args)
return 0; return 0;
ncp = (signed char *)PyBytes_AsString(rv); ncp = (signed char *)PyBytes_AsString(rv);
for (i = 0; i < len; i += size) { for (i = 0; i < len; i += size) {
if ( size == 1 ) val = (int)*CHARP(cp, i); double val = GETRAWSAMPLE(size, cp, i);
else if ( size == 2 ) val = (int)*SHORTP(cp, i); int val1 = (int)floor(fbound(val*fac1, minval, maxval));
else if ( size == 4 ) val = (int)*LONGP(cp, i); int val2 = (int)floor(fbound(val*fac2, minval, maxval));
SETRAWSAMPLE(size, ncp, i*2, val1);
fval = (double)val*fac1; SETRAWSAMPLE(size, ncp, i*2 + size, val2);
val1 = (int)floor(fbound(fval, minval, maxval));
fval = (double)val*fac2;
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;
else if ( size == 4 ) *LONGP(ncp, i*2) = (Py_Int32)val1;
if ( size == 1 ) *CHARP(ncp, i*2+1) = (signed char)val2;
else if ( size == 2 ) *SHORTP(ncp, i*2+2) = (short)val2;
else if ( size == 4 ) *LONGP(ncp, i*2+4) = (Py_Int32)val2;
} }
return rv; return rv;
} }
@ -903,7 +913,7 @@ audioop_add(PyObject *self, PyObject *args)
{ {
signed char *cp1, *cp2, *ncp; signed char *cp1, *cp2, *ncp;
Py_ssize_t len1, len2, i; Py_ssize_t len1, len2, i;
int size, val1 = 0, val2 = 0, minval, maxval, newval; int size, minval, maxval, newval;
PyObject *rv; PyObject *rv;
if ( !PyArg_ParseTuple(args, "s#s#i:add", if ( !PyArg_ParseTuple(args, "s#s#i:add",
@ -925,13 +935,8 @@ audioop_add(PyObject *self, PyObject *args)
ncp = (signed char *)PyBytes_AsString(rv); ncp = (signed char *)PyBytes_AsString(rv);
for (i = 0; i < len1; i += size) { for (i = 0; i < len1; i += size) {
if ( size == 1 ) val1 = (int)*CHARP(cp1, i); int val1 = GETRAWSAMPLE(size, cp1, i);
else if ( size == 2 ) val1 = (int)*SHORTP(cp1, i); int val2 = GETRAWSAMPLE(size, cp2, i);
else if ( size == 4 ) val1 = (int)*LONGP(cp1, i);
if ( size == 1 ) val2 = (int)*CHARP(cp2, i);
else if ( size == 2 ) val2 = (int)*SHORTP(cp2, i);
else if ( size == 4 ) val2 = (int)*LONGP(cp2, i);
if (size < 4) { if (size < 4) {
newval = val1 + val2; newval = val1 + val2;
@ -947,9 +952,7 @@ audioop_add(PyObject *self, PyObject *args)
newval = (int)floor(fbound(fval, minval, maxval)); newval = (int)floor(fbound(fval, minval, maxval));
} }
if ( size == 1 ) *CHARP(ncp, i) = (signed char)newval; SETRAWSAMPLE(size, ncp, i, newval);
else if ( size == 2 ) *SHORTP(ncp, i) = (short)newval;
else if ( size == 4 ) *LONGP(ncp, i) = (Py_Int32)newval;
} }
return rv; return rv;
} }
@ -978,17 +981,27 @@ audioop_bias(PyObject *self, PyObject *args)
mask = masks[size]; mask = masks[size];
for (i = 0; i < len; i += size) { for (i = 0; i < len; i += size) {
if ( size == 1 ) val = (unsigned int)(unsigned char)*CHARP(cp, i); if (size == 1)
else if ( size == 2 ) val = (unsigned int)(unsigned short)*SHORTP(cp, i); val = GETINTX(unsigned char, cp, i);
else if ( size == 4 ) val = (unsigned int)(Py_UInt32)*LONGP(cp, i); else if (size == 2)
val = GETINTX(unsigned short, cp, i);
else if (size == 2)
val = ((unsigned int)GETINT24(cp, i)) & 0xffffffu;
else
val = GETINTX(PY_UINT32_T, cp, i);
val += (unsigned int)bias; val += (unsigned int)bias;
/* wrap around in case of overflow */ /* wrap around in case of overflow */
val &= mask; val &= mask;
if ( size == 1 ) *CHARP(ncp, i) = (signed char)(unsigned char)val; if (size == 1)
else if ( size == 2 ) *SHORTP(ncp, i) = (short)(unsigned short)val; SETINTX(unsigned char, ncp, i, val);
else if ( size == 4 ) *LONGP(ncp, i) = (Py_Int32)(Py_UInt32)val; else if (size == 2)
SETINTX(unsigned short, ncp, i, val);
else if (size == 2)
SETINT24(ncp, i, (int)val);
else
SETINTX(PY_UINT32_T, ncp, i, val);
} }
return rv; return rv;
} }
@ -998,8 +1011,8 @@ audioop_reverse(PyObject *self, PyObject *args)
{ {
signed char *cp; signed char *cp;
unsigned char *ncp; unsigned char *ncp;
Py_ssize_t len, i, j; Py_ssize_t len, i;
int size, val = 0; int size;
PyObject *rv; PyObject *rv;
if ( !PyArg_ParseTuple(args, "s#i:reverse", if ( !PyArg_ParseTuple(args, "s#i:reverse",
@ -1015,15 +1028,8 @@ audioop_reverse(PyObject *self, PyObject *args)
ncp = (unsigned char *)PyBytes_AsString(rv); ncp = (unsigned char *)PyBytes_AsString(rv);
for (i = 0; i < len; i += size) { for (i = 0; i < len; i += size) {
if ( size == 1 ) val = ((int)*CHARP(cp, i)) << 24; int val = GETRAWSAMPLE(size, cp, i);
else if ( size == 2 ) val = ((int)*SHORTP(cp, i)) << 16; SETRAWSAMPLE(size, ncp, len - i - size, val);
else if ( size == 4 ) val = (int)*LONGP(cp, i);
j = len - i - size;
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; return rv;
} }
@ -1034,7 +1040,7 @@ audioop_lin2lin(PyObject *self, PyObject *args)
signed char *cp; signed char *cp;
unsigned char *ncp; unsigned char *ncp;
Py_ssize_t len, i, j; Py_ssize_t len, i, j;
int size, size2, val = 0; int size, size2;
PyObject *rv; PyObject *rv;
if ( !PyArg_ParseTuple(args, "s#ii:lin2lin", if ( !PyArg_ParseTuple(args, "s#ii:lin2lin",
@ -1056,14 +1062,9 @@ audioop_lin2lin(PyObject *self, PyObject *args)
return 0; return 0;
ncp = (unsigned char *)PyBytes_AsString(rv); ncp = (unsigned char *)PyBytes_AsString(rv);
for ( i=0, j=0; i < len; i += size, j += size2 ) { for (i = j = 0; i < len; i += size, j += size2) {
if ( size == 1 ) val = ((int)*CHARP(cp, i)) << 24; int val = GETSAMPLE32(size, cp, i);
else if ( size == 2 ) val = ((int)*SHORTP(cp, i)) << 16; SETSAMPLE32(size2, ncp, j, val);
else if ( size == 4 ) val = (int)*LONGP(cp, i);
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; return rv;
} }
@ -1224,12 +1225,7 @@ audioop_ratecv(PyObject *self, PyObject *args)
} }
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) cur_i[chan] = GETSAMPLE32(size, cp, 0);
cur_i[chan] = ((int)*CHARP(cp, 0)) << 24;
else if (size == 2)
cur_i[chan] = ((int)*SHORTP(cp, 0)) << 16;
else if (size == 4)
cur_i[chan] = (int)*LONGP(cp, 0);
cp += size; cp += size;
/* implements a simple digital filter */ /* implements a simple digital filter */
cur_i[chan] = (int)( cur_i[chan] = (int)(
@ -1245,12 +1241,7 @@ audioop_ratecv(PyObject *self, PyObject *args)
cur_o = (int)(((double)prev_i[chan] * (double)d + cur_o = (int)(((double)prev_i[chan] * (double)d +
(double)cur_i[chan] * (double)(outrate - d)) / (double)cur_i[chan] * (double)(outrate - d)) /
(double)outrate); (double)outrate);
if (size == 1) SETSAMPLE32(size, ncp, 0, cur_o);
*CHARP(ncp, 0) = (signed char)(cur_o >> 24);
else if (size == 2)
*SHORTP(ncp, 0) = (short)(cur_o >> 16);
else if (size == 4)
*LONGP(ncp, 0) = (Py_Int32)(cur_o);
ncp += size; ncp += size;
} }
d -= inrate; d -= inrate;
@ -1268,7 +1259,7 @@ audioop_lin2ulaw(PyObject *self, PyObject *args)
signed char *cp; signed char *cp;
unsigned char *ncp; unsigned char *ncp;
Py_ssize_t len, i; Py_ssize_t len, i;
int size, val = 0; int size;
PyObject *rv; PyObject *rv;
if ( !PyArg_ParseTuple(args, "s#i:lin2ulaw", if ( !PyArg_ParseTuple(args, "s#i:lin2ulaw",
@ -1284,11 +1275,8 @@ audioop_lin2ulaw(PyObject *self, PyObject *args)
ncp = (unsigned char *)PyBytes_AsString(rv); ncp = (unsigned char *)PyBytes_AsString(rv);
for (i = 0; i < len; i += size) { for (i = 0; i < len; i += size) {
if ( size == 1 ) val = ((int)*CHARP(cp, i)) << 8; int val = GETSAMPLE32(size, cp, i);
else if ( size == 2 ) val = (int)*SHORTP(cp, i); *ncp++ = st_14linear2ulaw(val >> 18);
else if ( size == 4 ) val = ((int)*LONGP(cp, i)) >> 16;
*ncp++ = st_14linear2ulaw(val);
} }
return rv; return rv;
} }
@ -1297,10 +1285,9 @@ static PyObject *
audioop_ulaw2lin(PyObject *self, PyObject *args) audioop_ulaw2lin(PyObject *self, PyObject *args)
{ {
unsigned char *cp; unsigned char *cp;
unsigned char cval;
signed char *ncp; signed char *ncp;
Py_ssize_t len, i; Py_ssize_t len, i;
int size, val; int size;
PyObject *rv; PyObject *rv;
if ( !PyArg_ParseTuple(args, "s#i:ulaw2lin", if ( !PyArg_ParseTuple(args, "s#i:ulaw2lin",
@ -1321,12 +1308,8 @@ audioop_ulaw2lin(PyObject *self, PyObject *args)
ncp = (signed char *)PyBytes_AsString(rv); ncp = (signed char *)PyBytes_AsString(rv);
for (i = 0; i < len*size; i += size) { for (i = 0; i < len*size; i += size) {
cval = *cp++; int val = st_ulaw2linear16(*cp++) << 16;
val = st_ulaw2linear16(cval); SETSAMPLE32(size, ncp, i, val);
if ( size == 1 ) *CHARP(ncp, i) = (signed char)(val >> 8);
else if ( size == 2 ) *SHORTP(ncp, i) = (short)(val);
else if ( size == 4 ) *LONGP(ncp, i) = (Py_Int32)(val<<16);
} }
return rv; return rv;
} }
@ -1337,7 +1320,7 @@ audioop_lin2alaw(PyObject *self, PyObject *args)
signed char *cp; signed char *cp;
unsigned char *ncp; unsigned char *ncp;
Py_ssize_t len, i; Py_ssize_t len, i;
int size, val = 0; int size;
PyObject *rv; PyObject *rv;
if ( !PyArg_ParseTuple(args, "s#i:lin2alaw", if ( !PyArg_ParseTuple(args, "s#i:lin2alaw",
@ -1353,11 +1336,8 @@ audioop_lin2alaw(PyObject *self, PyObject *args)
ncp = (unsigned char *)PyBytes_AsString(rv); ncp = (unsigned char *)PyBytes_AsString(rv);
for (i = 0; i < len; i += size) { for (i = 0; i < len; i += size) {
if ( size == 1 ) val = ((int)*CHARP(cp, i)) << 8; int val = GETSAMPLE32(size, cp, i);
else if ( size == 2 ) val = (int)*SHORTP(cp, i); *ncp++ = st_linear2alaw(val >> 19);
else if ( size == 4 ) val = ((int)*LONGP(cp, i)) >> 16;
*ncp++ = st_linear2alaw(val);
} }
return rv; return rv;
} }
@ -1366,7 +1346,6 @@ static PyObject *
audioop_alaw2lin(PyObject *self, PyObject *args) audioop_alaw2lin(PyObject *self, PyObject *args)
{ {
unsigned char *cp; unsigned char *cp;
unsigned char cval;
signed char *ncp; signed char *ncp;
Py_ssize_t len, i; Py_ssize_t len, i;
int size, val; int size, val;
@ -1390,12 +1369,8 @@ audioop_alaw2lin(PyObject *self, PyObject *args)
ncp = (signed char *)PyBytes_AsString(rv); ncp = (signed char *)PyBytes_AsString(rv);
for (i = 0; i < len*size; i += size) { for (i = 0; i < len*size; i += size) {
cval = *cp++; val = st_alaw2linear16(*cp++) << 16;
val = st_alaw2linear16(cval); SETSAMPLE32(size, ncp, i, val);
if ( size == 1 ) *CHARP(ncp, i) = (signed char)(val >> 8);
else if ( size == 2 ) *SHORTP(ncp, i) = (short)(val);
else if ( size == 4 ) *LONGP(ncp, i) = (Py_Int32)(val<<16);
} }
return rv; return rv;
} }
@ -1406,7 +1381,7 @@ audioop_lin2adpcm(PyObject *self, PyObject *args)
signed char *cp; signed char *cp;
signed char *ncp; signed char *ncp;
Py_ssize_t len, i; Py_ssize_t len, i;
int size, val = 0, step, valpred, delta, int size, step, valpred, delta,
index, sign, vpdiff, diff; index, sign, vpdiff, diff;
PyObject *rv, *state, *str; PyObject *rv, *state, *str;
int outputbuffer = 0, bufferstep; int outputbuffer = 0, bufferstep;
@ -1435,14 +1410,17 @@ audioop_lin2adpcm(PyObject *self, PyObject *args)
bufferstep = 1; bufferstep = 1;
for (i = 0; i < len; i += size) { for (i = 0; i < len; i += size) {
if ( size == 1 ) val = ((int)*CHARP(cp, i)) << 8; int val = GETSAMPLE32(size, cp, i) >> 16;
else if ( size == 2 ) val = (int)*SHORTP(cp, i);
else if ( size == 4 ) val = ((int)*LONGP(cp, i)) >> 16;
/* Step 1 - compute difference with previous value */ /* Step 1 - compute difference with previous value */
if (val < valpred) {
diff = valpred - val;
sign = 8;
}
else {
diff = val - valpred; diff = val - valpred;
sign = (diff < 0) ? 8 : 0; sign = 0;
if ( sign ) diff = (-diff); }
/* Step 2 - Divide and clamp */ /* Step 2 - Divide and clamp */
/* Note: /* Note:
@ -1511,7 +1489,7 @@ audioop_adpcm2lin(PyObject *self, PyObject *args)
{ {
signed char *cp; signed char *cp;
signed char *ncp; signed char *ncp;
Py_ssize_t len, i; Py_ssize_t len, i, outlen;
int size, valpred, step, delta, index, sign, vpdiff; int size, valpred, step, delta, index, sign, vpdiff;
PyObject *rv, *str, *state; PyObject *rv, *str, *state;
int inputbuffer = 0, bufferstep; int inputbuffer = 0, bufferstep;
@ -1536,7 +1514,8 @@ audioop_adpcm2lin(PyObject *self, PyObject *args)
"not enough memory for output buffer"); "not enough memory for output buffer");
return 0; return 0;
} }
str = PyBytes_FromStringAndSize(NULL, len*size*2); outlen = len*size*2;
str = PyBytes_FromStringAndSize(NULL, outlen);
if ( str == 0 ) if ( str == 0 )
return 0; return 0;
ncp = (signed char *)PyBytes_AsString(str); ncp = (signed char *)PyBytes_AsString(str);
@ -1544,7 +1523,7 @@ audioop_adpcm2lin(PyObject *self, PyObject *args)
step = stepsizeTable[index]; step = stepsizeTable[index];
bufferstep = 0; bufferstep = 0;
for ( i=0; i < len*size*2; i += size ) { for (i = 0; i < outlen; i += size) {
/* Step 1 - get the delta value and compute next index */ /* Step 1 - get the delta value and compute next index */
if ( bufferstep ) { if ( bufferstep ) {
delta = inputbuffer & 0xf; delta = inputbuffer & 0xf;
@ -1589,9 +1568,7 @@ audioop_adpcm2lin(PyObject *self, PyObject *args)
step = stepsizeTable[index]; step = stepsizeTable[index];
/* Step 6 - Output value */ /* Step 6 - Output value */
if ( size == 1 ) *CHARP(ncp, i) = (signed char)(valpred >> 8); SETSAMPLE32(size, ncp, i, valpred << 16);
else if ( size == 2 ) *SHORTP(ncp, i) = (short)(valpred);
else if ( size == 4 ) *LONGP(ncp, i) = (Py_Int32)(valpred<<16);
} }
rv = Py_BuildValue("(O(ii))", str, valpred, index); rv = Py_BuildValue("(O(ii))", str, valpred, index);