@@ -841,14 +841,15 @@ def get_portaudio_version():
841841
842842
843843class _StreamBase (object ):
844- """Base class for Raw{Input,Output}Stream ."""
844+ """Direct or indirect base class for all stream classes ."""
845845
846- def __init__ (self , kind , samplerate = None , blocksize = None , device = None ,
846+ def __init__ (self , kind = None , samplerate = None , blocksize = None , device = None ,
847847 channels = None , dtype = None , latency = None , extra_settings = None ,
848848 callback = None , finished_callback = None , clip_off = None ,
849849 dither_off = None , never_drop_input = None ,
850850 prime_output_buffers_using_stream_callback = None ,
851- userdata = None ):
851+ userdata = None , wrap_callback = None ):
852+ assert wrap_callback in ('array' , 'buffer' , None )
852853 if blocksize is None :
853854 blocksize = default .blocksize
854855 if clip_off is None :
@@ -871,7 +872,7 @@ def __init__(self, kind, samplerate=None, blocksize=None, device=None,
871872 if prime_output_buffers_using_stream_callback :
872873 stream_flags |= _lib .paPrimeOutputBuffersUsingStreamCallback
873874
874- if kind == 'duplex' :
875+ if kind is None :
875876 idevice , odevice = _split (device )
876877 ichannels , ochannels = _split (channels )
877878 idtype , odtype = _split (dtype )
@@ -898,30 +899,86 @@ def __init__(self, kind, samplerate=None, blocksize=None, device=None,
898899 extra_settings , samplerate )
899900 self ._device = parameters .device
900901 self ._channels = parameters .channelCount
901-
902902 if kind == 'input' :
903903 iparameters = parameters
904904 oparameters = _ffi .NULL
905905 elif kind == 'output' :
906906 iparameters = _ffi .NULL
907907 oparameters = parameters
908908
909+ ffi_callback = _ffi .callback ('PaStreamCallback' , error = _lib .paAbort )
910+
909911 if callback is None :
910- callback = _ffi .NULL
911- elif isinstance (callback , _ffi .CData ):
912- # Use cast() to allow CData from different FFI instance:
913- callback = _ffi .cast ('PaStreamCallback*' , callback )
912+ callback_ptr = _ffi .NULL
913+ elif kind == 'input' and wrap_callback == 'buffer' :
914+
915+ @ffi_callback
916+ def callback_ptr (iptr , optr , frames , time , status , _ ):
917+ data = _buffer (iptr , frames , self ._channels , self ._samplesize )
918+ return _wrap_callback (callback , data , frames , time , status )
919+
920+ elif kind == 'input' and wrap_callback == 'array' :
921+
922+ @ffi_callback
923+ def callback_ptr (iptr , optr , frames , time , status , _ ):
924+ data = _array (
925+ _buffer (iptr , frames , self ._channels , self ._samplesize ),
926+ self ._channels , self ._dtype )
927+ return _wrap_callback (callback , data , frames , time , status )
928+
929+ elif kind == 'output' and wrap_callback == 'buffer' :
930+
931+ @ffi_callback
932+ def callback_ptr (iptr , optr , frames , time , status , _ ):
933+ data = _buffer (optr , frames , self ._channels , self ._samplesize )
934+ return _wrap_callback (callback , data , frames , time , status )
935+
936+ elif kind == 'output' and wrap_callback == 'array' :
937+
938+ @ffi_callback
939+ def callback_ptr (iptr , optr , frames , time , status , _ ):
940+ data = _array (
941+ _buffer (optr , frames , self ._channels , self ._samplesize ),
942+ self ._channels , self ._dtype )
943+ return _wrap_callback (callback , data , frames , time , status )
944+
945+ elif kind is None and wrap_callback == 'buffer' :
946+
947+ @ffi_callback
948+ def callback_ptr (iptr , optr , frames , time , status , _ ):
949+ ichannels , ochannels = self ._channels
950+ isize , osize = self ._samplesize
951+ idata = _buffer (iptr , frames , ichannels , isize )
952+ odata = _buffer (optr , frames , ochannels , osize )
953+ return _wrap_callback (
954+ callback , idata , odata , frames , time , status )
955+
956+ elif kind is None and wrap_callback == 'array' :
957+
958+ @ffi_callback
959+ def callback_ptr (iptr , optr , frames , time , status , _ ):
960+ ichannels , ochannels = self ._channels
961+ idtype , odtype = self ._dtype
962+ isize , osize = self ._samplesize
963+ idata = _array (_buffer (iptr , frames , ichannels , isize ),
964+ ichannels , idtype )
965+ odata = _array (_buffer (optr , frames , ochannels , osize ),
966+ ochannels , odtype )
967+ return _wrap_callback (
968+ callback , idata , odata , frames , time , status )
969+
914970 else :
915- callback = _ffi .callback (
916- 'PaStreamCallback' , callback , error = _lib .paAbort )
917- # CFFI callback object is kept alive during stream lifetime:
918- self ._callback = callback
971+ # Use cast() to allow CData from different FFI instance:
972+ callback_ptr = _ffi .cast ('PaStreamCallback*' , callback )
973+
974+ # CFFI callback object must be kept alive during stream lifetime:
975+ self ._callback = callback_ptr
919976 if userdata is None :
920977 userdata = _ffi .NULL
921978 self ._ptr = _ffi .new ('PaStream**' )
922979 _check (_lib .Pa_OpenStream (self ._ptr , iparameters , oparameters ,
923980 samplerate , blocksize , stream_flags ,
924- callback , userdata ),
981+ callback_ptr , userdata ),
925982 'Error opening {0}' .format (self .__class__ .__name__ ))
926983
927984 # dereference PaStream** --> PaStream*
@@ -1207,16 +1264,8 @@ def __init__(self, samplerate=None, blocksize=None,
12071264 RawStream, Stream
12081265
12091266 """
1210-
1211- def callback_wrapper (iptr , optr , frames , time , status , _ ):
1212- data = _buffer (iptr , frames , self ._channels , self ._samplesize )
1213- return _wrap_callback (callback , data , frames , time , status )
1214-
1215- _StreamBase .__init__ (
1216- self , 'input' , samplerate , blocksize , device , channels , dtype ,
1217- latency , extra_settings , callback and callback_wrapper ,
1218- finished_callback , clip_off , dither_off , never_drop_input ,
1219- prime_output_buffers_using_stream_callback )
1267+ _StreamBase .__init__ (self , kind = 'input' , wrap_callback = 'buffer' ,
1268+ ** _remove_self (locals ()))
12201269
12211270 @property
12221271 def read_available (self ):
@@ -1299,16 +1348,8 @@ def __init__(self, samplerate=None, blocksize=None,
12991348 RawStream, Stream
13001349
13011350 """
1302-
1303- def callback_wrapper (iptr , optr , frames , time , status , _ ):
1304- data = _buffer (optr , frames , self ._channels , self ._samplesize )
1305- return _wrap_callback (callback , data , frames , time , status )
1306-
1307- _StreamBase .__init__ (
1308- self , 'output' , samplerate , blocksize , device , channels , dtype ,
1309- latency , extra_settings , callback and callback_wrapper ,
1310- finished_callback , clip_off , dither_off , never_drop_input ,
1311- prime_output_buffers_using_stream_callback )
1351+ _StreamBase .__init__ (self , kind = 'output' , wrap_callback = 'buffer' ,
1352+ ** _remove_self (locals ()))
13121353
13131354 @property
13141355 def write_available (self ):
@@ -1415,19 +1456,8 @@ def __init__(self, samplerate=None, blocksize=None,
14151456 RawInputStream, RawOutputStream, Stream
14161457
14171458 """
1418-
1419- def callback_wrapper (iptr , optr , frames , time , status , _ ):
1420- ichannels , ochannels = self ._channels
1421- isize , osize = self ._samplesize
1422- idata = _buffer (iptr , frames , ichannels , isize )
1423- odata = _buffer (optr , frames , ochannels , osize )
1424- return _wrap_callback (callback , idata , odata , frames , time , status )
1425-
1426- _StreamBase .__init__ (
1427- self , 'duplex' , samplerate , blocksize , device , channels , dtype ,
1428- latency , extra_settings , callback and callback_wrapper ,
1429- finished_callback , clip_off , dither_off , never_drop_input ,
1430- prime_output_buffers_using_stream_callback )
1459+ _StreamBase .__init__ (self , kind = None , wrap_callback = 'buffer' ,
1460+ ** _remove_self (locals ()))
14311461
14321462
14331463class InputStream (RawInputStream ):
@@ -1463,17 +1493,8 @@ def __init__(self, samplerate=None, blocksize=None,
14631493 Stream, RawInputStream
14641494
14651495 """
1466-
1467- def callback_wrapper (iptr , optr , frames , time , status , _ ):
1468- buffer = _buffer (iptr , frames , self ._channels , self ._samplesize )
1469- data = _array (buffer , self ._channels , self ._dtype )
1470- return _wrap_callback (callback , data , frames , time , status )
1471-
1472- _StreamBase .__init__ (
1473- self , 'input' , samplerate , blocksize , device , channels , dtype ,
1474- latency , extra_settings , callback and callback_wrapper ,
1475- finished_callback , clip_off , dither_off , never_drop_input ,
1476- prime_output_buffers_using_stream_callback )
1496+ _StreamBase .__init__ (self , kind = 'input' , wrap_callback = 'array' ,
1497+ ** _remove_self (locals ()))
14771498
14781499 def read (self , frames ):
14791500 """Read samples from the stream into a NumPy array.
@@ -1545,17 +1566,8 @@ def __init__(self, samplerate=None, blocksize=None,
15451566 Stream, RawOutputStream
15461567
15471568 """
1548-
1549- def callback_wrapper (iptr , optr , frames , time , status , _ ):
1550- buffer = _buffer (optr , frames , self ._channels , self ._samplesize )
1551- data = _array (buffer , self ._channels , self ._dtype )
1552- return _wrap_callback (callback , data , frames , time , status )
1553-
1554- _StreamBase .__init__ (
1555- self , 'output' , samplerate , blocksize , device , channels , dtype ,
1556- latency , extra_settings , callback and callback_wrapper ,
1557- finished_callback , clip_off , dither_off , never_drop_input ,
1558- prime_output_buffers_using_stream_callback )
1569+ _StreamBase .__init__ (self , kind = 'output' , wrap_callback = 'array' ,
1570+ ** _remove_self (locals ()))
15591571
15601572 def write (self , data ):
15611573 """Write samples to the stream.
@@ -1842,22 +1854,8 @@ def __init__(self, samplerate=None, blocksize=None,
18421854 See `default.prime_output_buffers_using_stream_callback`.
18431855
18441856 """
1845-
1846- def callback_wrapper (iptr , optr , frames , time , status , _ ):
1847- ichannels , ochannels = self ._channels
1848- idtype , odtype = self ._dtype
1849- isize , osize = self ._samplesize
1850- ibuffer = _buffer (iptr , frames , ichannels , isize )
1851- obuffer = _buffer (optr , frames , ochannels , osize )
1852- idata = _array (ibuffer , ichannels , idtype )
1853- odata = _array (obuffer , ochannels , odtype )
1854- return _wrap_callback (callback , idata , odata , frames , time , status )
1855-
1856- _StreamBase .__init__ (
1857- self , 'duplex' , samplerate , blocksize , device , channels , dtype ,
1858- latency , extra_settings , callback and callback_wrapper ,
1859- finished_callback , clip_off , dither_off , never_drop_input ,
1860- prime_output_buffers_using_stream_callback )
1857+ _StreamBase .__init__ (self , kind = None , wrap_callback = 'array' ,
1858+ ** _remove_self (locals ()))
18611859
18621860
18631861class DeviceList (tuple ):
@@ -2496,6 +2494,13 @@ def wait(self):
24962494 return self .status if self .status else None
24972495
24982496
2497+ def _remove_self (d ):
2498+ """Return a copy of d without the 'self' entry."""
2499+ d = d .copy ()
2500+ del d ['self' ]
2501+ return d
2502+
2503+
24992504def _check_mapping (mapping , channels ):
25002505 """Check mapping, obtain channels."""
25012506 import numpy as np
0 commit comments