|
1 | 1 | """Reliable low-latency audio playback and recording.""" |
| 2 | + |
2 | 3 | __version__ = '0.0.0' |
3 | 4 |
|
4 | 5 | import sounddevice as _sd |
| 6 | +from pa_ringbuffer import init as _init_ringbuffer |
5 | 7 | from _rtmixer import ffi as _ffi, lib as _lib |
| 8 | +RingBuffer = _init_ringbuffer(_ffi, _lib) |
6 | 9 |
|
7 | 10 |
|
8 | 11 | class _Base(_sd._StreamBase): |
@@ -234,194 +237,3 @@ def __init__(self, **kwargs): |
234 | 237 | _Base.__init__(self, kind='duplex', **kwargs) |
235 | 238 | self._state.input_channels = self.channels[0] |
236 | 239 | self._state.output_channels = self.channels[1] |
237 | | - |
238 | | - |
239 | | -class RingBuffer(object): |
240 | | - """Wrapper for PortAudio's ring buffer. |
241 | | -
|
242 | | - See __init__(). |
243 | | -
|
244 | | - """ |
245 | | - |
246 | | - def __init__(self, elementsize, size): |
247 | | - """Create an instance of PortAudio's ring buffer. |
248 | | -
|
249 | | - Parameters |
250 | | - ---------- |
251 | | - elementsize : int |
252 | | - The size of a single data element in bytes. |
253 | | - size : int |
254 | | - The number of elements in the buffer (must be a power of 2). |
255 | | -
|
256 | | - """ |
257 | | - self._ptr = _ffi.new('PaUtilRingBuffer*') |
258 | | - self._data = _ffi.new('unsigned char[]', size * elementsize) |
259 | | - res = _lib.PaUtil_InitializeRingBuffer( |
260 | | - self._ptr, elementsize, size, self._data) |
261 | | - if res != 0: |
262 | | - assert res == -1 |
263 | | - raise ValueError('size must be a power of 2') |
264 | | - assert self._ptr.bufferSize == size |
265 | | - assert self._ptr.elementSizeBytes == elementsize |
266 | | - |
267 | | - def flush(self): |
268 | | - """Reset buffer to empty. |
269 | | -
|
270 | | - Should only be called when buffer is NOT being read or written. |
271 | | -
|
272 | | - """ |
273 | | - _lib.PaUtil_FlushRingBuffer(self._ptr) |
274 | | - |
275 | | - @property |
276 | | - def write_available(self): |
277 | | - """Number of elements available in the ring buffer for writing.""" |
278 | | - return _lib.PaUtil_GetRingBufferWriteAvailable(self._ptr) |
279 | | - |
280 | | - @property |
281 | | - def read_available(self): |
282 | | - """Number of elements available in the ring buffer for reading.""" |
283 | | - return _lib.PaUtil_GetRingBufferReadAvailable(self._ptr) |
284 | | - |
285 | | - def write(self, data, size=-1): |
286 | | - """Write data to the ring buffer. |
287 | | -
|
288 | | - Parameters |
289 | | - ---------- |
290 | | - data : CData pointer or buffer or bytes |
291 | | - Data to write to the buffer. |
292 | | - size : int, optional |
293 | | - The number of elements to be written. |
294 | | -
|
295 | | - Returns |
296 | | - ------- |
297 | | - int |
298 | | - The number of elements written. |
299 | | -
|
300 | | - """ |
301 | | - try: |
302 | | - data = _ffi.from_buffer(data) |
303 | | - except TypeError: |
304 | | - pass # input is not a buffer |
305 | | - if size < 0: |
306 | | - size, rest = divmod(_ffi.sizeof(data), self._ptr.elementSizeBytes) |
307 | | - if rest: |
308 | | - raise ValueError('data size must be multiple of elementsize') |
309 | | - return _lib.PaUtil_WriteRingBuffer(self._ptr, data, size) |
310 | | - |
311 | | - def read(self, data, size=-1): |
312 | | - """Read data from the ring buffer. |
313 | | -
|
314 | | - Parameters |
315 | | - ---------- |
316 | | - data : CData pointer or buffer |
317 | | - The memory where the data should be stored. |
318 | | - size : int, optional |
319 | | - The number of elements to be read. |
320 | | -
|
321 | | - Returns |
322 | | - ------- |
323 | | - int |
324 | | - The number of elements read. |
325 | | -
|
326 | | - """ |
327 | | - try: |
328 | | - data = _ffi.from_buffer(data) |
329 | | - except TypeError: |
330 | | - pass # input is not a buffer |
331 | | - if size < 0: |
332 | | - size, rest = divmod(_ffi.sizeof(data), self._ptr.elementSizeBytes) |
333 | | - if rest: |
334 | | - raise ValueError('data size must be multiple of elementsize') |
335 | | - return _lib.PaUtil_ReadRingBuffer(self._ptr, data, size) |
336 | | - |
337 | | - def get_write_buffers(self, size): |
338 | | - """Get buffer(s) to which we can write data. |
339 | | -
|
340 | | - Parameters |
341 | | - ---------- |
342 | | - size : int |
343 | | - The number of elements desired. |
344 | | -
|
345 | | - Returns |
346 | | - ------- |
347 | | - int |
348 | | - The room available to be written or the given *size*, |
349 | | - whichever is smaller. |
350 | | - buffer |
351 | | - The first buffer. |
352 | | - buffer |
353 | | - The second buffer. |
354 | | -
|
355 | | - """ |
356 | | - ptr1 = _ffi.new('void**') |
357 | | - ptr2 = _ffi.new('void**') |
358 | | - size1 = _ffi.new('ring_buffer_size_t*') |
359 | | - size2 = _ffi.new('ring_buffer_size_t*') |
360 | | - return (_lib.PaUtil_GetRingBufferWriteRegions( |
361 | | - self._ptr, size, ptr1, size1, ptr2, size2), |
362 | | - _ffi.buffer(ptr1[0], size1[0] * self.elementsize), |
363 | | - _ffi.buffer(ptr2[0], size2[0] * self.elementsize)) |
364 | | - |
365 | | - def advance_write_index(self, size): |
366 | | - """Advance the write index to the next location to be written. |
367 | | -
|
368 | | - Parameters |
369 | | - ---------- |
370 | | - size : int |
371 | | - The number of elements to advance. |
372 | | -
|
373 | | - Returns |
374 | | - ------- |
375 | | - int |
376 | | - The new position. |
377 | | -
|
378 | | - """ |
379 | | - return _lib.PaUtil_AdvanceRingBufferWriteIndex(self._ptr, size) |
380 | | - |
381 | | - def get_read_buffers(self, size): |
382 | | - """Get buffer(s) from which we can read data. |
383 | | -
|
384 | | - Parameters |
385 | | - ---------- |
386 | | - size : int |
387 | | - The number of elements desired. |
388 | | -
|
389 | | - Returns |
390 | | - ------- |
391 | | - int |
392 | | - The number of elements available for reading. |
393 | | - buffer |
394 | | - The first buffer. |
395 | | - buffer |
396 | | - The second buffer. |
397 | | -
|
398 | | - """ |
399 | | - ptr1 = _ffi.new('void**') |
400 | | - ptr2 = _ffi.new('void**') |
401 | | - size1 = _ffi.new('ring_buffer_size_t*') |
402 | | - size2 = _ffi.new('ring_buffer_size_t*') |
403 | | - return (_lib.PaUtil_GetRingBufferReadRegions( |
404 | | - self._ptr, size, ptr1, size1, ptr2, size2), |
405 | | - _ffi.buffer(ptr1[0], size1[0] * self.elementsize), |
406 | | - _ffi.buffer(ptr2[0], size2[0] * self.elementsize)) |
407 | | - |
408 | | - def advance_read_index(self, size): |
409 | | - """Advance the read index to the next location to be read. |
410 | | -
|
411 | | - Parameters |
412 | | - ---------- |
413 | | - size : int |
414 | | - The number of elements to advance. |
415 | | -
|
416 | | - Returns |
417 | | - ------- |
418 | | - int |
419 | | - The new position. |
420 | | -
|
421 | | - """ |
422 | | - return _lib.PaUtil_AdvanceRingBufferReadIndex(self._ptr, size) |
423 | | - |
424 | | - @property |
425 | | - def elementsize(self): |
426 | | - """Element size in bytes.""" |
427 | | - return self._ptr.elementSizeBytes |
0 commit comments