Skip to content

Commit f3f0996

Browse files
committed
Allow selecting devices by device name substrings
See #2.
1 parent e6cfef9 commit f3f0996

File tree

1 file changed

+44
-4
lines changed

1 file changed

+44
-4
lines changed

sounddevice.py

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1561,9 +1561,10 @@ def __init__(self, samplerate=None, blocksize=None,
15611561
non-zero `blocksize` value only be used when your
15621562
algorithm requires a fixed number of frames per stream
15631563
callback.
1564-
device : int or pair of int, optional
1565-
Device index specifying the device to be used. The default
1566-
value(s) can be changed with :attr:`default.device`.
1564+
device : int or str or pair thereof, optional
1565+
Device index(es) or query string(s) specifying the device(s)
1566+
to be used. The default value(s) can be changed with
1567+
:attr:`default.device`.
15671568
channels : int or pair of int, optional
15681569
The number of channels of sound to be delivered to the
15691570
stream callback or accessed by :meth:`read` or
@@ -1934,10 +1935,15 @@ class default(object):
19341935
# provided here for static analysis tools and for the docs.
19351936
# They're overwritten in __init__().
19361937
device = None, None
1937-
"""Index of default input/output device.
1938+
"""Index or query string of default input/output device.
19381939
19391940
If not overwritten, this is queried from PortAudio.
19401941
1942+
If a string is given, the device is selected which contains all
1943+
space-separated parts in the right order. Each device string
1944+
contains the name of the corresponding host API in the end.
1945+
The string comparison is case-insensitive.
1946+
19411947
See Also
19421948
--------
19431949
:func:`query_devices`
@@ -2285,6 +2291,8 @@ def _get_stream_parameters(kind, device, channels, dtype, latency, samplerate):
22852291
if samplerate is None:
22862292
samplerate = default.samplerate
22872293

2294+
if not isinstance(device, int):
2295+
device = _find_device_id(kind, device)
22882296
info = query_devices(device)
22892297
if channels is None:
22902298
channels = info['max_' + kind + '_channels']
@@ -2362,6 +2370,38 @@ def _check(err, msg=""):
23622370
return err
23632371

23642372

2373+
def _find_device_id(kind, device):
2374+
"""Return device ID given space-separated substrings."""
2375+
device_list = []
2376+
for i, info in enumerate(query_devices()):
2377+
if info['max_' + kind + '_channels'] > 0:
2378+
hostapi_info = query_hostapis(info['hostapi'])
2379+
name = info['name'] + ', ' + hostapi_info['name']
2380+
device_list.append((i, name))
2381+
2382+
substrings = device.lower().split()
2383+
matches = []
2384+
for i, device_string in device_list:
2385+
lowercase_device_string = device_string.lower()
2386+
pos = 0
2387+
for substring in substrings:
2388+
pos = lowercase_device_string.find(substring, pos)
2389+
if pos < 0:
2390+
break
2391+
pos += len(substring)
2392+
else:
2393+
matches.append((i, device_string))
2394+
2395+
if not matches:
2396+
raise ValueError(
2397+
"No " + kind + " device matching " + repr(device))
2398+
if len(matches) > 1:
2399+
raise ValueError(
2400+
"Multiple " + kind + " devices found for " + repr(device) + ": " +
2401+
'; '.join('[{0}] {1}'.format(id, name) for id, name in matches))
2402+
return matches[0][0]
2403+
2404+
23652405
def _initialize():
23662406
"""Initialize PortAudio."""
23672407
_check(_lib.Pa_Initialize(), "Error initializing PortAudio")

0 commit comments

Comments
 (0)