Skip to content

Commit 55dbdbb

Browse files
committed
default for each hostapi
1 parent 45842ee commit 55dbdbb

File tree

1 file changed

+174
-143
lines changed

1 file changed

+174
-143
lines changed

sounddevice.py

Lines changed: 174 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -2143,188 +2143,195 @@ def __repr__(self):
21432143
return '[{0[0]!r}, {0[1]!r}]'.format(self)
21442144

21452145

2146-
class default(object):
2147-
"""Get/set defaults for the *sounddevice* module.
2146+
def _create_default():
2147+
class default(object):
2148+
"""Get/set defaults for the *sounddevice* module.
21482149
2149-
The attributes `device`, `channels`, `dtype`, `latency` and
2150-
`extra_settings` accept single values which specify the given
2151-
property for both input and output. However, if the property
2152-
differs between input and output, pairs of values can be used, where
2153-
the first value specifies the input and the second value specifies
2154-
the output. All other attributes are always single values.
2150+
The attributes `device`, `channels`, `dtype`, `latency` and
2151+
`extra_settings` accept single values which specify the given
2152+
property for both input and output. However, if the property
2153+
differs between input and output, pairs of values can be used, where
2154+
the first value specifies the input and the second value specifies
2155+
the output. All other attributes are always single values.
21552156
2156-
Examples
2157-
--------
2157+
Examples
2158+
--------
21582159
2159-
>>> import sounddevice as sd
2160-
>>> sd.default.samplerate = 48000
2161-
>>> sd.default.dtype
2162-
['float32', 'float32']
2160+
>>> import sounddevice as sd
2161+
>>> sd.default.samplerate = 48000
2162+
>>> sd.default.dtype
2163+
['float32', 'float32']
21632164
2164-
Different values for input and output:
2165+
Different values for input and output:
21652166
2166-
>>> sd.default.channels = 1, 2
2167+
>>> sd.default.channels = 1, 2
21672168
2168-
A single value sets both input and output at the same time:
2169+
A single value sets both input and output at the same time:
21692170
2170-
>>> sd.default.device = 5
2171-
>>> sd.default.device
2172-
[5, 5]
2171+
>>> sd.default.device = 5
2172+
>>> sd.default.device
2173+
[5, 5]
21732174
2174-
An attribute can be set to the "factory default" by assigning
2175-
``None``:
2175+
An attribute can be set to the "factory default" by assigning
2176+
``None``:
21762177
2177-
>>> sd.default.samplerate = None
2178-
>>> sd.default.device = None, 4
2178+
>>> sd.default.samplerate = None
2179+
>>> sd.default.device = None, 4
21792180
2180-
Use `reset()` to reset all attributes:
2181+
Use `reset()` to reset all attributes:
21812182
2182-
>>> sd.default.reset()
2183+
>>> sd.default.reset()
21832184
2184-
"""
2185-
_pairs = 'device', 'channels', 'dtype', 'latency', 'extra_settings'
2186-
# The class attributes listed in _pairs are only provided here for static
2187-
# analysis tools and for the docs. They're overwritten in __init__().
2188-
device = None, None
2189-
"""Index or query string of default input/output device.
2185+
"""
2186+
_pairs = 'device', 'channels', 'dtype', 'latency', 'extra_settings'
2187+
# The class attributes listed in _pairs are only provided here for static
2188+
# analysis tools and for the docs. They're overwritten in __init__().
2189+
device = None, None
2190+
"""Index or query string of default input/output device.
21902191
2191-
If not overwritten, this is queried from PortAudio.
2192+
If not overwritten, this is queried from PortAudio.
21922193
2193-
If a string is given, the device is selected which contains all
2194-
space-separated parts in the right order. Each device string
2195-
contains the name of the corresponding host API in the end.
2196-
The string comparison is case-insensitive.
2194+
If a string is given, the device is selected which contains all
2195+
space-separated parts in the right order. Each device string
2196+
contains the name of the corresponding host API in the end.
2197+
The string comparison is case-insensitive.
21972198
2198-
See Also
2199-
--------
2200-
:func:`query_devices`
2199+
See Also
2200+
--------
2201+
:func:`query_devices`
22012202
2202-
"""
2203-
channels = _default_channels = None, None
2204-
"""Number of input/output channels.
2203+
"""
2204+
channels = _default_channels = None, None
2205+
"""Number of input/output channels.
22052206
2206-
The maximum number of channels for a given device can be found out
2207-
with `query_devices()`.
2207+
The maximum number of channels for a given device can be found out
2208+
with `query_devices()`.
22082209
2209-
"""
2210-
dtype = _default_dtype = 'float32', 'float32'
2211-
"""Data type used for input/output samples.
2210+
"""
2211+
dtype = _default_dtype = 'float32', 'float32'
2212+
"""Data type used for input/output samples.
22122213
2213-
The types ``'float32'``, ``'int32'``, ``'int16'``, ``'int8'`` and
2214-
``'uint8'`` can be used for all streams and functions.
2215-
Additionally, `play()`, `rec()` and `playrec()` support
2216-
``'float64'`` (for convenience, data is merely converted from/to
2217-
``'float32'``) and `RawInputStream`, `RawOutputStream` and
2218-
`RawStream` support ``'int24'`` (packed 24 bit format, which is
2219-
*not* supported in NumPy!).
2214+
The types ``'float32'``, ``'int32'``, ``'int16'``, ``'int8'`` and
2215+
``'uint8'`` can be used for all streams and functions.
2216+
Additionally, `play()`, `rec()` and `playrec()` support
2217+
``'float64'`` (for convenience, data is merely converted from/to
2218+
``'float32'``) and `RawInputStream`, `RawOutputStream` and
2219+
`RawStream` support ``'int24'`` (packed 24 bit format, which is
2220+
*not* supported in NumPy!).
22202221
2221-
If NumPy is available, the corresponding `numpy.dtype` objects can
2222-
be used as well.
2222+
If NumPy is available, the corresponding `numpy.dtype` objects can
2223+
be used as well.
22232224
2224-
The floating point representations ``'float32'`` and ``'float64'``
2225-
use +1.0 and -1.0 as the maximum and minimum values, respectively.
2226-
``'uint8'`` is an unsigned 8 bit format where 128 is considered
2227-
"ground".
2225+
The floating point representations ``'float32'`` and ``'float64'``
2226+
use +1.0 and -1.0 as the maximum and minimum values, respectively.
2227+
``'uint8'`` is an unsigned 8 bit format where 128 is considered
2228+
"ground".
22282229
2229-
"""
2230-
latency = _default_latency = 'high', 'high'
2231-
"""Suggested input/output latency in seconds.
2230+
"""
2231+
latency = _default_latency = 'high', 'high'
2232+
"""Suggested input/output latency in seconds.
22322233
2233-
The special values ``'low'`` and ``'high'`` can be used to select
2234-
the default low/high latency of the chosen device.
2235-
``'high'`` is typically more robust (i.e. buffer under-/overflows
2236-
are less likely), but the latency may be too large for interactive
2237-
applications.
2234+
The special values ``'low'`` and ``'high'`` can be used to select
2235+
the default low/high latency of the chosen device.
2236+
``'high'`` is typically more robust (i.e. buffer under-/overflows
2237+
are less likely), but the latency may be too large for interactive
2238+
applications.
22382239
2239-
See Also
2240-
--------
2241-
:func:`query_devices`
2240+
See Also
2241+
--------
2242+
:func:`query_devices`
22422243
2243-
"""
2244-
extra_settings = _default_extra_settings = None, None
2245-
"""Host-API-specific input/output settings.
2244+
"""
2245+
extra_settings = _default_extra_settings = None, None
2246+
"""Host-API-specific input/output settings.
22462247
2247-
See Also
2248-
--------
2249-
AsioSettings, CoreAudioSettings, WasapiSettings
2248+
See Also
2249+
--------
2250+
AsioSettings, CoreAudioSettings, WasapiSettings
22502251
2251-
"""
2252-
samplerate = None
2253-
"""Sampling frequency in Hertz (= frames per second).
2252+
"""
2253+
samplerate = None
2254+
"""Sampling frequency in Hertz (= frames per second).
22542255
2255-
See Also
2256-
--------
2257-
:func:`query_devices`
2256+
See Also
2257+
--------
2258+
:func:`query_devices`
22582259
2259-
"""
2260-
blocksize = _lib.paFramesPerBufferUnspecified
2261-
"""See the *blocksize* argument of `Stream`."""
2262-
clip_off = False
2263-
"""Disable clipping.
2260+
"""
2261+
blocksize = _lib.paFramesPerBufferUnspecified
2262+
"""See the *blocksize* argument of `Stream`."""
2263+
clip_off = False
2264+
"""Disable clipping.
22642265
2265-
Set to ``True`` to disable default clipping of out of range samples.
2266+
Set to ``True`` to disable default clipping of out of range samples.
22662267
2267-
"""
2268-
dither_off = False
2269-
"""Disable dithering.
2268+
"""
2269+
dither_off = False
2270+
"""Disable dithering.
22702271
2271-
Set to ``True`` to disable default dithering.
2272+
Set to ``True`` to disable default dithering.
22722273
2273-
"""
2274-
never_drop_input = False
2275-
"""Set behavior for input overflow of full-duplex streams.
2276-
2277-
Set to ``True`` to request that where possible a full duplex stream
2278-
will not discard overflowed input samples without calling the stream
2279-
callback. This flag is only valid for full-duplex callback streams
2280-
(i.e. only `Stream` and `RawStream` and only if *callback* was
2281-
specified; this includes `playrec()`) and only when used in
2282-
combination with ``blocksize=0`` (the default). Using this flag
2283-
incorrectly results in an error being raised. See also
2284-
http://www.portaudio.com/docs/proposals/001-UnderflowOverflowHandling.html.
2274+
"""
2275+
never_drop_input = False
2276+
"""Set behavior for input overflow of full-duplex streams.
2277+
2278+
Set to ``True`` to request that where possible a full duplex stream
2279+
will not discard overflowed input samples without calling the stream
2280+
callback. This flag is only valid for full-duplex callback streams
2281+
(i.e. only `Stream` and `RawStream` and only if *callback* was
2282+
specified; this includes `playrec()`) and only when used in
2283+
combination with ``blocksize=0`` (the default). Using this flag
2284+
incorrectly results in an error being raised. See also
2285+
http://www.portaudio.com/docs/proposals/001-UnderflowOverflowHandling.html.
22852286
2286-
"""
2287-
prime_output_buffers_using_stream_callback = False
2288-
"""How to fill initial output buffers.
2287+
"""
2288+
prime_output_buffers_using_stream_callback = False
2289+
"""How to fill initial output buffers.
22892290
2290-
Set to ``True`` to call the stream callback to fill initial output
2291-
buffers, rather than the default behavior of priming the buffers
2292-
with zeros (silence). This flag has no effect for input-only
2293-
(`InputStream` and `RawInputStream`) and blocking read/write streams
2294-
(i.e. if *callback* wasn't specified). See also
2295-
http://www.portaudio.com/docs/proposals/020-AllowCallbackToPrimeStream.html.
2291+
Set to ``True`` to call the stream callback to fill initial output
2292+
buffers, rather than the default behavior of priming the buffers
2293+
with zeros (silence). This flag has no effect for input-only
2294+
(`InputStream` and `RawInputStream`) and blocking read/write streams
2295+
(i.e. if *callback* wasn't specified). See also
2296+
http://www.portaudio.com/docs/proposals/020-AllowCallbackToPrimeStream.html.
22962297
2297-
"""
2298+
"""
22982299

2299-
def __init__(self):
2300-
for attr in self._pairs:
2301-
# __setattr__() must be avoided here
2302-
vars(self)[attr] = _InputOutputPair(self, '_default_' + attr)
2303-
2304-
def __setattr__(self, name, value):
2305-
"""Only allow setting existing attributes."""
2306-
if name in self._pairs:
2307-
getattr(self, name)._pair[:] = _split(value)
2308-
elif name in dir(self) and name != 'reset':
2309-
object.__setattr__(self, name, value)
2310-
else:
2311-
raise AttributeError(
2312-
"'default' object has no attribute " + repr(name))
2300+
def __init__(self):
2301+
for attr in self._pairs:
2302+
# __setattr__() must be avoided here
2303+
vars(self)[attr] = _InputOutputPair(self, '_default_' + attr)
2304+
2305+
def __setattr__(self, name, value):
2306+
"""Only allow setting existing attributes."""
2307+
if name in self._pairs:
2308+
getattr(self, name)._pair[:] = _split(value)
2309+
elif name in dir(self) and name != 'reset':
2310+
object.__setattr__(self, name, value)
2311+
else:
2312+
raise AttributeError(
2313+
"'default' object has no attribute " + repr(name))
23132314

2314-
@property
2315-
def _default_device(self):
2316-
return (_lib.Pa_GetDefaultInputDevice(),
2317-
_lib.Pa_GetDefaultOutputDevice())
2315+
@property
2316+
def _default_device(self):
2317+
return (_lib.Pa_GetDefaultInputDevice(),
2318+
_lib.Pa_GetDefaultOutputDevice())
23182319

2319-
@property
2320-
def hostapi(self):
2321-
"""Index of the default host API (read-only)."""
2322-
return _check(_lib.Pa_GetDefaultHostApi())
2320+
@property
2321+
def hostapi(self):
2322+
"""Index of the default host API (read-only)."""
2323+
return _check(_lib.Pa_GetDefaultHostApi())
2324+
2325+
def reset(self):
2326+
"""Reset all attributes to their "factory default"."""
2327+
vars(self).clear()
2328+
self.__init__()
2329+
2330+
return default
2331+
2332+
2333+
default = _create_default()
23232334

2324-
def reset(self):
2325-
"""Reset all attributes to their "factory default"."""
2326-
vars(self).clear()
2327-
self.__init__()
23282335

23292336
if not hasattr(_ffi, 'I_AM_FAKE'):
23302337
# This object shadows the 'default' class, except when building the docs.
@@ -2450,7 +2457,8 @@ def _populate_hostapis():
24502457
_HostAPI = _namedtuple('_HostAPI', ('name', 'devices',
24512458
'default_input_device',
24522459
'default_output_device',
2453-
'apiname', 'api'))
2460+
'apiname', 'api', 'default'))
2461+
24542462
class HostAPIs(_namedtuple('HostAPIs', (h['apiname'] for h in hostapi_list))):
24552463
"""Access to PortAudio Host API's"""
24562464
__slots__ = ()
@@ -2460,6 +2468,8 @@ class HostAPIs(_namedtuple('HostAPIs', (h['apiname'] for h in hostapi_list))):
24602468
for apiname in missing_apinames:
24612469
setattr(HostAPIs, apiname, None)
24622470

2471+
for hostapi in hostapi_list:
2472+
hostapi['default'] = _create_default()
24632473
hostapis = HostAPIs(*(_HostAPI(**h) for h in hostapi_list))
24642474

24652475

@@ -3092,6 +3102,14 @@ def _check_dtype(dtype):
30923102
return dtype
30933103

30943104

3105+
def _get_device_hostapi(device):
3106+
"""Find a device's in hostapis"""
3107+
for hostapi in hostapis:
3108+
if device in hostapi.devices:
3109+
return hostapi
3110+
return None
3111+
3112+
30953113
def _get_stream_parameters(kind, device, channels, dtype, latency,
30963114
extra_settings, samplerate):
30973115
"""Get parameters for one direction (input or output) of a stream."""
@@ -3110,6 +3128,19 @@ def _get_stream_parameters(kind, device, channels, dtype, latency,
31103128
samplerate = default.samplerate
31113129

31123130
device = _get_device_id(device, kind, raise_on_error=True)
3131+
hostapi = _get_device_hostapi(device)
3132+
if hostapi:
3133+
if channels is None:
3134+
channels = hostapi.default.channels[kind]
3135+
if dtype is None:
3136+
dtype = hostapi.default.dtype[kind]
3137+
if latency is None:
3138+
latency = hostapi.default.latency[kind]
3139+
if extra_settings is None:
3140+
extra_settings = hostapi.default.extra_settings[kind]
3141+
if samplerate is None:
3142+
samplerate = hostapi.default.samplerate
3143+
31133144
info = query_devices(device)
31143145
if channels is None:
31153146
channels = info['max_' + kind + '_channels']

0 commit comments

Comments
 (0)