def __init__(self, kind, qsize=16, **kwargs): callback = _ffi.addressof(_lib, 'callback') self._action_q = RingBuffer(_ffi.sizeof('struct action*'), qsize) self._result_q = RingBuffer(_ffi.sizeof('struct action*'), qsize) self._state = _ffi.new( 'struct state*', dict( input_channels=0, output_channels=0, samplerate=0, action_q=self._action_q._ptr, result_q=self._result_q._ptr, actions=_ffi.NULL, )) _sd._StreamBase.__init__(self, kind=kind, dtype='float32', callback=callback, userdata=self._state, **kwargs) self._state.samplerate = self.samplerate self._actions = set() self._temp_action_ptr = _ffi.new('struct action**')
def record_ringbuffer(self, ringbuffer, channels=None, start=0, allow_belated=True): """Send a `RingBuffer` to the callback to be recorded into. By default, the number of channels is obtained from the ring buffer's :attr:`~RingBuffer.elementsize`. """ samplesize, _ = _sd._split(self.samplesize) if channels is None: channels = ringbuffer.elementsize // samplesize channels, mapping = self._check_channels(channels, 'input') if ringbuffer.elementsize != samplesize * channels: raise ValueError('Incompatible elementsize') action = _ffi.new( 'struct action*', dict( type=RECORD_RINGBUFFER, allow_belated=allow_belated, requested_time=start, ringbuffer=ringbuffer._ptr, total_frames=ULONG_MAX, channels=channels, mapping=mapping, )) self._enqueue(action) return action
def stats(self): """Get over-/underflow statistics from an *inactive* stream. To get statistics from an :attr:`~sounddevice.Stream.active` stream, use `fetch_and_reset_stats()`. """ if self.active: raise RuntimeError('Accessing .stats on an active stream') return _ffi.new('struct stats*', self._state.stats)
def fetch_and_reset_stats(self, time=0, allow_belated=True): """Fetch and reset over-/underflow statistics of the stream. """ action = _ffi.new('struct action*', dict( type=FETCH_AND_RESET_STATS, allow_belated=allow_belated, requested_time=time, )) self._enqueue(action) return action
def record_buffer(self, buffer, channels, start=0, allow_belated=True): """Send a buffer to the callback to be recorded into. """ channels, mapping = self._check_channels(channels, 'input') buffer = _ffi.from_buffer(buffer) samplesize, _ = _sd._split(self.samplesize) action = _ffi.new('struct action*', dict( type=RECORD_BUFFER, allow_belated=allow_belated, requested_time=start, buffer=_ffi.cast('float*', buffer), total_frames=len(buffer) // channels // samplesize, channels=channels, mapping=mapping, )) self._enqueue(action) return action
def cancel(self, action, time=0, allow_belated=True): """Initiate stopping a running action. This creates another action that is sent to the callback in order to stop the given *action*. This function typically returns before the *action* is actually stopped. Use `wait()` (on either one of the two actions) to wait until it's done. """ cancel_action = _ffi.new('struct action*', dict( type=CANCEL, allow_belated=allow_belated, requested_time=time, action=action, )) self._enqueue(cancel_action) return cancel_action
def play_buffer(self, buffer, channels, start=0, allow_belated=True): """Send a buffer to the callback to be played back. After that, the *buffer* must not be written to anymore. """ channels, mapping = self._check_channels(channels, 'output') buffer = _ffi.from_buffer(buffer) _, samplesize = _sd._split(self.samplesize) action = _ffi.new('struct action*', dict( type=PLAY_BUFFER, allow_belated=allow_belated, requested_time=start, buffer=_ffi.cast('float*', buffer), total_frames=len(buffer) // channels // samplesize, channels=channels, mapping=mapping, )) self._enqueue(action) return action