Skip to content

Commit 82c761d

Browse files
committed
Add a base class
1 parent e104b0e commit 82c761d

File tree

1 file changed

+38
-36
lines changed

1 file changed

+38
-36
lines changed

src/rtmixer.py

Lines changed: 38 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,39 +5,55 @@
55
from _rtmixer import ffi as _ffi, lib as _lib
66

77

8-
class Mixer(_sd._StreamBase):
9-
"""PortAudio stream for realtime mixing."""
8+
class _Base(_sd._StreamBase):
9+
"""Base class for Mixer et al."""
1010

11-
def __init__(self, channels, **kwargs):
12-
"""Create a realtime mixer object.
13-
14-
Takes the same keyword arguments as `sounddevice.Stream`, except
15-
*callback* and *dtype*.
16-
17-
In contrast to `sounddevice.Stream`, the *channels* argument is
18-
not optional.
19-
20-
Uses default values from `sounddevice.default`.
21-
22-
"""
11+
def __init__(self, kind, **kwargs):
2312
callback = _ffi.addressof(_lib, 'callback')
2413

2514
# TODO: parameter for ring buffer size
2615
self._action_q = RingBuffer(_ffi.sizeof('struct action*'), 512)
2716
self._userdata = _ffi.new('struct state*', dict(
28-
input_channels=0,
29-
output_channels=channels,
3017
action_q=self._action_q._ptr,
3118
))
3219
_sd._StreamBase.__init__(
33-
self, kind='output', wrap_callback=None, channels=channels,
34-
dtype='float32', callback=callback, userdata=self._userdata,
35-
**kwargs)
36-
# Add a few attributes that are only known after opening the stream:
20+
self, kind=kind, dtype='float32',
21+
callback=callback, userdata=self._userdata, **kwargs)
3722
self._userdata.samplerate = self.samplerate
3823

3924
self._actions = []
4025

26+
def _check_channels(self, channels, kind):
27+
"""Check if number of channels or mapping was given."""
28+
assert kind in ('input', 'output')
29+
try:
30+
channels, mapping = len(channels), channels
31+
except TypeError:
32+
mapping = tuple(range(1, channels + 1))
33+
max_channels = _sd._split(self.channels)[kind == 'output']
34+
if max(mapping) > max_channels:
35+
raise ValueError('Channel number too large')
36+
if min(mapping) < 1:
37+
raise ValueError('Channel numbers start with 1')
38+
return channels, mapping
39+
40+
41+
class Mixer(_Base):
42+
"""PortAudio output stream for realtime mixing."""
43+
44+
def __init__(self, **kwargs):
45+
"""Create a realtime mixer object.
46+
47+
Takes the same keyword arguments as `sounddevice.OutputStream`,
48+
except *callback* and *dtype*.
49+
50+
Uses default values from `sounddevice.default`.
51+
52+
"""
53+
_Base.__init__(self, kind='output', **kwargs)
54+
self._userdata.input_channels = 0
55+
self._userdata.output_channels = self.channels
56+
4157
def play_buffer(self, buffer, channels, start=0):
4258
"""Send a buffer to the callback to be played back.
4359
@@ -93,23 +109,9 @@ def play_ringbuffer(self, ringbuffer, channels=None, start=0):
93109
# TODO: block until playback has finished (optional)?
94110
# TODO: return something that allows stopping playback?
95111

96-
def _check_channels(self, channels, kind):
97-
"""Check if number of channels or mapping was given."""
98-
assert kind in ('input', 'output')
99-
try:
100-
channels, mapping = len(channels), channels
101-
except TypeError:
102-
mapping = tuple(range(1, channels + 1))
103-
max_channels = _sd._split(self.channels)[kind == 'output']
104-
if max(mapping) > max_channels:
105-
raise ValueError('Channel number too large')
106-
if min(mapping) < 1:
107-
raise ValueError('Channel numbers start with 1')
108-
return channels, mapping
109-
110112

111-
class Recorder(_sd._StreamBase):
112-
"""PortAudio stream for realtime recording."""
113+
class Recorder(_Base):
114+
"""PortAudio input stream for realtime recording."""
113115

114116

115117
class MixerAndRecorder(Mixer, Recorder):

0 commit comments

Comments
 (0)