def __init__(self): super(settings, self).__init__() self.setWindowTitle('Settings') # self.b1 = QPushButton("ok", self) # self.b1.move(50, 50) self.resize(200, 200) # self.move(650, 450) self.setWindowModality(Qt.ApplicationModal) self.layout = QGridLayout() # Create central Widget self.centralWidget = QWidget(self) # Create combobox and add available Host APIs self.host_label = QLabel('Host APis:') self.host = QComboBox(self.centralWidget) self.host_label.setBuddy(self.host) self.host.setToolTip('This are the HOST APIs:') for hostapi in sd.query_hostapis(): self.host.addItem(hostapi['name']) self.layout.addWidget(self.host_label, 0, 0) self.layout.addWidget(self.host, 0, 1) self.host.currentTextChanged.connect(self.host_changed) # create combobox and add available inputs self.inputs_label = QLabel('Input:') self.inputs = QComboBox(self.centralWidget) self.inputs_label.setBuddy(self.inputs) self.inputs.setToolTip('Choose your sound device input channels') self.hostapi = sd.query_hostapis(self.host.currentIndex()) for idx in self.hostapi['devices']: if sd.query_devices(idx)['max_input_channels'] > 0: self.inputs.addItem(sd.query_devices(idx)['name']) self.inputs.currentTextChanged.connect(self.input_changed) self.layout.addWidget(self.inputs_label, 1, 0) self.layout.addWidget(self.inputs, 1, 1) # create combobox and add available outputs self.outputs_label = QLabel('Outputs:') self.outputs = QComboBox(self.centralWidget) self.outputs_label.setBuddy(self.outputs) self.outputs.setToolTip('Choose your sound device output channels') self.hostapi = sd.query_hostapis(self.host.currentIndex()) for idx in self.hostapi['devices']: if sd.query_devices(idx)['max_output_channels'] > 0: self.outputs.addItem(sd.query_devices(idx)['name']) self.layout.addWidget(self.outputs_label, 2, 0) self.layout.addWidget(self.outputs, 2, 1) self.outputs.currentTextChanged.connect(self.output_changed) self.setLayout(self.layout) self.exec_()
def list_sound_input_devices(self, hostapi: str) -> typing.List[SoundDevice]: hostapis = typing.cast(typing.Tuple[typing.Dict[str, typing.Any], ...], sounddevice.query_hostapis()) devices = typing.cast(sounddevice.DeviceList, sounddevice.query_devices()) default_input_id, _ = typing.cast( typing.Tuple[typing.Optional[int], typing.Optional[int]], sounddevice.default.device) for api in hostapis: if api['name'] == hostapi: default_input_id = api['default_input_device'] break else: return [] return [ SoundDevice(typing.cast(str, dev['name']), idx == default_input_id) for idx, dev in enumerate( typing.cast(typing.Iterable[typing.Dict[str, typing.Any]], devices)) if dev['max_input_channels'] > 0 and dev['hostapi'] < len(hostapis) and hostapis[typing.cast(int, dev['hostapi'])]['name'] == hostapi ]
def update_api(self): # update the audio devices matching the API current_api = sd.query_hostapis( self.api_ids[self.api_box.currentIndex()]) sd.default.device = [ max(current_api['default_input_device'], 0), max(current_api['default_output_device'], 0) ] self.input_devices_box.clear() self.input_dev_ids.clear() self.output_devices_box.clear() self.output_dev_ids.clear() for device_id in current_api['devices']: device = sd.query_devices(device_id) display_name = f"{device['name']} ({device['max_input_channels']} in, {device['max_output_channels']} out)" if device['max_input_channels'] > 0: self.input_devices_box.addItem(display_name) self.input_dev_ids.append(device_id) if device_id == sd.default.device[0]: self.input_devices_box.setCurrentText(display_name) if device['max_output_channels'] > 0: self.output_devices_box.addItem(display_name) self.output_dev_ids.append(device_id) if device_id == sd.default.device[1]: self.output_devices_box.setCurrentText(display_name) if device_id == sd.default.device[0]: self.input_devices_box.setCurrentText(display_name) if device_id == sd.default.device[1]: self.output_devices_box.setCurrentText(display_name) self.update_device()
def get_readable_devices_list(self): input_devices = self.get_input_devices() raw_devices = sounddevice.query_devices() try: default_input_device = sounddevice.query_devices(kind='input') default_input_device['index'] = raw_devices.index( default_input_device) except sounddevice.PortAudioError as exception: Logger().push("Failed to query the default input device: %s" % (exception)) default_input_device = None devices_list = [] for device in input_devices: api = sounddevice.query_hostapis(device['hostapi'])['name'] if default_input_device is not None and device[ 'index'] == default_input_device['index']: extra_info = ' (default)' else: extra_info = '' nchannels = device['max_input_channels'] desc = "%s (%d channels) (%s) %s" % (device['name'], nchannels, api, extra_info) devices_list += [desc] return devices_list
def _connect(self, start=None): callback = self.callback def proxy_callback(in_data, frame_count, time_info, status): callback(bytes(in_data)) # Must copy data from temporary C buffer! self.stream = sounddevice.RawInputStream( samplerate=self.SAMPLE_RATE, channels=self.CHANNELS, dtype=self.FORMAT, blocksize=self.BLOCK_SIZE_SAMPLES, # latency=80, device=self.input_device, callback=proxy_callback if not self.self_threaded else None, ) if self.self_threaded: self.thread_cancelled = False self.thread = threading.Thread(target=self._reader_thread, args=(callback, )) self.thread.daemon = True self.thread.start() if start: self.start() device_info = sounddevice.query_devices(self.stream.device) hostapi_info = sounddevice.query_hostapis(device_info['hostapi']) _log.info( "streaming audio from '%s' using %s: %i sample_rate, %i block_duration_ms, %i latency_ms", device_info['name'], hostapi_info['name'], self.stream.samplerate, self.BLOCK_DURATION_MS, int(self.stream.latency * 1000)) self.device_info = device_info
def body(self, master): ttk.Label(master, text='Select host API:').pack(anchor='w') hostapi_list = ttk.Combobox(master, state='readonly', width=50) hostapi_list.pack() hostapi_list['values'] = [hostapi['name'] for hostapi in sd.query_hostapis()] ttk.Label(master, text='Select sound device:').pack(anchor='w') device_ids = [] device_list = ttk.Combobox(master, state='readonly', width=50) device_list.pack() def update_device_list(*args): hostapi = sd.query_hostapis(hostapi_list.current()) nonlocal device_ids device_ids = [ idx for idx in hostapi['devices'] if sd.query_devices(idx)['max_output_channels'] > 0] device_list['values'] = [ sd.query_devices(idx)['name'] for idx in device_ids] default = hostapi['default_output_device'] if default >= 0: device_list.current(device_ids.index(default)) device_list.event_generate('<<ComboboxSelected>>') def select_device(*args): self.result = device_ids[device_list.current()] hostapi_list.bind('<<ComboboxSelected>>', update_device_list) device_list.bind('<<ComboboxSelected>>', select_device) with contextlib.suppress(sd.PortAudioError): hostapi_list.current(sd.default.hostapi) hostapi_list.event_generate('<<ComboboxSelected>>')
def get_readable_output_devices_list(self): output_devices = self.get_output_devices() raw_devices = sounddevice.query_devices() default_output_device = sounddevice.query_devices(kind='output') default_output_device['index'] = raw_devices.index( default_output_device) devices_list = [] for device in output_devices: api = sounddevice.query_hostapis(device['hostapi'])['name'] if default_output_device is not None and device[ 'index'] == default_output_device['index']: extra_info = ' (default)' else: extra_info = '' nchannels = device['max_output_channels'] desc = "%s (%d channels) (%s) %s" % (device['name'], nchannels, api, extra_info) devices_list += [desc] return devices_list
def set_default_channels(self): """Detects and sets the default sounddevice channels Checks the Host APIs of the user's OS audio settings for the default input and output devices. Sets the sounddevice default channels tuple to the capabilities of the input and output devices. On Linux, the default input/output devices are often a "virtual" device using ALSA and can have 32, 64, or even 128 channels. This value is clamped to 2 for what the physical device can support. """ for api in sd.query_hostapis(): input_device = api.get('default_input_device') output_device = api.get('default_output_device') if input_device is not None and input_device >= 0 \ and output_device is not None and output_device >= 0: devices = sd.query_devices() input_channels = devices[input_device]['max_input_channels'] if input_channels > 2: # Clamp value in case of virtual device input_channels = 2 output_channels = devices[output_device]['max_output_channels'] if output_channels > 2: # Clamp value in case of virtual device output_channels = 2 sd.default.channels = input_channels, output_channels break
def __init__(self, device="default", samplerate=44100, channels=[]): self.callbacks = [] self.control = 0 self.status = 0 self.device = device self.samplerate = samplerate self.rq = queue.Queue() self.currentTime = 0 self.channels = channels # Playback parameters self.buffersize = 4 self.blocksize = 2048 # TODO if sd.query_hostapis()[0]['name'] == "Core Audio": ch = self.channels + ([-1] * 14) self.extraInputSettings = sd.CoreAudioSettings(ch, True, True) self.extraOutputSettings = sd.CoreAudioSettings(ch, True, True) self.extraInputSettings = None self.extraOutputSettings = None elif self.device == "ASIO PreSonus FireStudio": self.extraInputSettings = self.extraOutputSettings = sd.AsioSettings( self.channels) else: self.extraOutputSettings = None self.extraInputSettings = None
def single_measurement(self, type=None): # little workaround of a problem with using ASIO from multiple threads # https://stackoverflow.com/questions/39858212/python-sounddevice-play-on-threads default_device = sd.query_devices(sd.default.device[0]) default_api = sd.query_hostapis(default_device['hostapi']) if default_api['name'] == 'ASIO': sd._terminate() sd._initialize() self.recorded_sweep_l = [] self.recorded_sweep_r = [] self.feedback_loop = [] if type is 'hpc': excitation = self.excitation_hpc else: excitation = self.excitation if not self.dummy_debugging: time.sleep(0.3) try: sd.check_input_settings(channels=self.num_input_channels_used) sd.check_output_settings(channels=self.num_output_channels_used) except: print( "Audio hardware error! Too many channels or unsupported samplerate" ) return # do measurement recorded = sd.playrec(excitation, channels=self.num_input_channels_used) sd.wait() # get the recorded signals if self.channel_layout_input[0] >= 0: self.recorded_sweep_l = recorded[:, self.channel_layout_input[0]] else: self.recorded_sweep_l = np.zeros(np.size(recorded, 0)) if self.channel_layout_input[1] >= 0: self.recorded_sweep_r = recorded[:, self.channel_layout_input[1]] else: self.recorded_sweep_r = np.zeros(np.size(recorded, 0)) if self.feedback_loop_used: self.feedback_loop = recorded[:, self.channel_layout_input[2]] if abs(self.feedback_loop.max()) < 0.0001: self.feedback_loop = np.random.random_sample( self.feedback_loop.shape ) * 0.000001 # to avoid zero-division errors else: # if no FB loop, copy from original excitation sweep if type is 'hpc': self.feedback_loop = self.sweep_hpc_mono[:, 0] else: self.feedback_loop = self.sweep_mono[:, 0]
def get_devices(self): self.deviceList = sd.query_devices() self.devices = [] if self.deviceList: for device in self.deviceList: self.devices.append(device['name']) print(sd.query_hostapis(2)) self.audio_devices.emit(self.devices)
def _iter_compatible_output_devices(show_all=False): """ returns (device_name, hostapi_name)""" devs = sd.query_devices() for info in devs: if info['max_output_channels']: hostapi_info = sd.query_hostapis(info['hostapi']) if show_all or ('ASIO' in hostapi_info.get('name', '')): yield info['name'], hostapi_info.get('name', '')
def _get_default_device(category): """ Query the default audio devices. :param category: Device category to query. Can be either input or output :type category: str """ import sounddevice as sd return sd.query_hostapis()[0].get('default_' + category.lower() + '_device')
def get_devices(): all_devices = sd.query_devices() mme_devices = [] mme_id = -1 for idx, device in enumerate(sd.query_hostapis()): if "MME" in device["name"]: mme_id = idx break for device in all_devices: if device["hostapi"] == mme_id and device["max_output_channels"] > 0: mme_devices.append(device["name"]) return mme_devices
def print_details(device) -> None: hostapi_names = [hostapi['name'] for hostapi in sd.query_hostapis()] ha = hostapi_names[device['hostapi']] ins = device['max_input_channels'] outs = device['max_output_channels'] lat_in_hi = device["default_high_input_latency"] lat_in_lo = device["default_low_input_latency"] lat_out_hi = device["default_high_output_latency"] lat_out_lo = device["default_low_output_latency"] print( f"{device['name']}, {ha} ({ins} in, {outs} out), latency in({lat_in_lo:.3f}-{lat_in_hi:.3f}) out({lat_out_lo:.3f}-{lat_out_hi:.3f})" )
def get_device(name='CABLE Input', kind='output', api=0): if isinstance(name, int): return name, sd.query_devices(name) devices = sd.query_devices() matching_devices = [] for device_id in range(len(devices)): if name.lower() in devices[device_id].get('name').lower(): try: if kind == 'input': sd.check_input_settings(device_id) elif kind == 'output': sd.check_output_settings(device_id) else: print('Invalid kind') return None matching_devices.append((device_id, devices[device_id])) except: pass if not matching_devices: print("Unable to find device matching name", name, 'of kind', kind) return None found = False if isinstance(api, int): api = sd.query_hostapis(api).get('name') for device_id, device in matching_devices: if api in sd.query_hostapis(int( device.get('hostapi'))).get('name'): found = True break if not found: print("Unable to find device matching host api", api, 'using first available...') return matching_devices[0] else: return device_id, device
def update_device_list(*args): hostapi = sd.query_hostapis(hostapi_list.current()) nonlocal device_ids device_ids = [ idx for idx in hostapi['devices'] if sd.query_devices(idx)['max_output_channels'] > 0] device_list['values'] = [ sd.query_devices(idx)['name'] for idx in device_ids] default = hostapi['default_output_device'] if default >= 0: device_list.current(device_ids.index(default)) device_list.event_generate('<<ComboboxSelected>>')
def _select_audio_device(self, key): devices = sounddevice.query_devices() hostapi = None valid_devices = [] for api in sounddevice.query_hostapis(): match = re.search('DirectSound', api['name'], re.IGNORECASE) if match: hostapi = api['name'] for device_id in api['devices']: device = sounddevice.query_devices()[device_id] if device['max_output_channels'] > 0: valid_devices.append(device) self.print(f"{len(valid_devices)}. {device['name']}") self.print( f"Current audio device: {self._sound_data.get(key, 'Default')}") def save(prompt): if prompt.strip() == 'c': self.update_status_text() return True if prompt == "-1": if key in self._sound_data: del self._sound_data[key] self.save_module_data(self._sound_data) self.print('Audio device set to default') self.update_status_text() return True if not prompt.isdigit(): return False device_id = int(prompt) if len(valid_devices) < device_id or device_id < 1: self.print('Invalid Selection') return False device = valid_devices[device_id - 1] device_name = f"{device['name']}, {hostapi}" self._sound_data[key] = device_name self.save_module_data(self._sound_data) self.update_status_text() self.print(f"Audio device set to {device['name']}") return True self.update_status_text( 'Select Audio Device. -1 for default. c to cancel.') self.prompt_ident = self.get_prompt('Audio Device> ', save)
def refresh1(init=False): host_apis = {} i = 0 for host in sounddevice.query_hostapis(): host_apis[i] = host['name'] i += 1 host_api_optionmenu['menu'].delete(0, 'end') for host in host_apis.values(): host_api_optionmenu['menu'].add_command(label=host, command=tkinter._setit( host_api, host)) if not host_apis: host_api.set('') elif init and 'Windows DirectSound' in host_apis.values(): host_api.set('Windows DirectSound') elif host_api.get() not in host_apis.values(): host_api.set(host_apis[0]) output_devices = [] input_devices = [] for device in sounddevice.query_devices(): if host_apis[device['hostapi']] == host_api.get(): if device['max_output_channels'] > 0: output_devices.append(device['name']) elif device['max_input_channels'] > 0: input_devices.append(device['name']) output_device_optionmenu['menu'].delete(0, 'end') input_device_optionmenu['menu'].delete(0, 'end') for device in output_devices: output_device_optionmenu['menu'].add_command(label=device, command=tkinter._setit( output_device, device)) for device in input_devices: input_device_optionmenu['menu'].add_command(label=device, command=tkinter._setit( input_device, device)) if not output_devices: output_device.set('') elif output_device.get() not in output_devices: output_device.set(output_devices[0]) if not input_devices: input_device.set('') elif input_device.get() not in input_devices: input_device.set(input_devices[0]) channels_entry.config(state=NORMAL if channels_check.get() else DISABLED)
def get_device_id(device, hostapi, kind="output"): if kind == "output": key = "max_output_channels" elif key == "input": key = "max_input_channels" else: raise ValueError( "Invalid value for 'kind', must be 'input' or 'output'") dct = defaultdict(dict) for i, api in enumerate(sd.query_hostapis()): for dev in api["devices"]: dev_name = sd.query_devices(dev)["name"] if sd.query_devices(dev)["max_output_channels"]: dct[dev_name][i] = dev return dct[device][hostapi]
def log_supported_input_formats(self, device): samplerates = [22050, 44100, 48000, 96000] dtypes = [float32, int16, int8] supported_formats = [] for samplerate in samplerates: for dtype in dtypes: try: sounddevice.check_input_settings( device=device['index'], channels=device['max_input_channels'], dtype=dtype, extra_settings=None, samplerate=samplerate) supported_formats += [f"{samplerate} Hz, {np.dtype(dtype).name}"] except Exception: pass # check_input_settings throws when the format is not supported api = sounddevice.query_hostapis(device['hostapi'])['name'] self.logger.info(f"Supported formats for '{device['name']}' on '{api}': {supported_formats}")
def resfresh_device_list(self): devices = sd.query_devices() self.comboin.clear() self.comboout.clear() self.map_item_to_devicename = {'input': {}, 'output': {}} self.map_devicename_to_item = {'input': {}, 'output': {}} hostapi_names = [hostapi['name'] for hostapi in sd.query_hostapis()] for i, dev in enumerate(devices): hostapi_name = hostapi_names[dev['hostapi']] if dev['max_input_channels'] >= 1: self.comboin.addItem( u'{}: {} # HostAPI:{} # In:{} # Out:{}'.format( i, dev['name'], hostapi_name, dev['max_input_channels'], dev['max_output_channels'], )) self.map_item_to_devicename['input'][self.comboin.count() - 1] = dev['name'] self.map_devicename_to_item['input'][ dev['name']] = self.comboin.count() - 1 if dev['max_output_channels'] >= 1: self.comboout.addItem( u'{}: {} # HostAPI:{} # In:{} # Out:{}'.format( i, dev['name'], hostapi_name, dev['max_input_channels'], dev['max_output_channels'], )) self.map_item_to_devicename['output'][self.comboout.count() - 1] = dev['name'] self.map_devicename_to_item['output'][ dev['name']] = self.comboout.count() - 1
def find_default_output_device(self) -> int: devices = sounddevice.query_devices() # type: ignore apis = sounddevice.query_hostapis() # type: ignore candidates = [] for did, d in reversed(list(enumerate(devices))): if d["max_output_channels"] < 2: continue api = apis[d["hostapi"]] if api["default_output_device"] < 0: continue dname = d["name"].lower() if dname in ("sysdefault", "default", "front") or "built-in" in dname: candidates.append(did) elif "generic" in dname or "speakers" in dname or "mme" in dname: candidates.append(did) if candidates: warnings.warn("chosen output device: " + str(candidates[-1]), category=ResourceWarning) return candidates[-1] return -1
def print_all_devices() -> None: print(f"PortAudio version {sd.get_portaudio_version()}") hostapis = sd.query_hostapis() print(hostapis) devices = sd.query_devices() print(devices) # default output spk_all = sd.query_devices(kind="output") print_details(spk_all) # default input mic_all = sd.query_devices(kind="input") print_details(mic_all) while True: choose = input("Interested in a particular device? Which one? ") choose = int(choose) print_details(sd.query_devices(choose))
def start_recording(self, hostapi: str, device: str) -> None: if self.input_stream is not None: self.input_stream.stop() self.input_stream.close() self.input_stream = None hostapis = typing.cast(typing.Tuple[typing.Dict[str, typing.Any], ...], sounddevice.query_hostapis()) devices = typing.cast(sounddevice.DeviceList, sounddevice.query_devices()) device_id: int for idx, dev in enumerate( typing.cast(typing.Iterable[typing.Dict[str, typing.Any]], devices)): if dev['name'] == device and dev['max_input_channels'] > 0 and dev[ 'hostapi'] < len(hostapis) and hostapis[typing.cast( int, dev['hostapi'])]['name'] == hostapi: device_id = idx break else: return self.input_stream = sounddevice.RawInputStream( samplerate=48000, blocksize=48000 * 20 // 1000, device=device_id, channels=2, dtype='float32', latency='low', callback=self._recording_callback, clip_off=True, dither_off=True, never_drop_input=False) try: self.input_stream.start() except Exception: traceback.print_exc() self.input_stream.close() self.input_stream = None
def getAudioOutputs(cls) -> Tuple[List[Dict]]: host_apis = list(sd.query_hostapis()) devices: sd.DeviceList = cls._getSDAudioDevices() for host_api_id in range(len(host_apis)): # Linux SDL uses PortAudio, which SoundDevice doesn't find. So mark all as unsable. if (isWindows() and host_apis[host_api_id]["name"] not in WINDOWS_APIS) or (isLinux()): host_apis[host_api_id]["usable"] = False else: host_apis[host_api_id]["usable"] = True host_api_devices = (device for device in devices if device["hostapi"] == host_api_id) outputs: List[Dict] = list(filter(cls._isOutput, host_api_devices)) outputs = sorted(outputs, key=lambda k: k["name"]) host_apis[host_api_id]["output_devices"] = outputs return host_apis
def _get_input_device(self, device: Optional[Union[int, str]] = None) -> int: """ Get the index of the input device by index or name. :param device: Device index or name. If None is set then the function will return the index of the default audio input device. :return: Index of the audio input device. """ if not device: device = self.input_device if not device: return sd.query_hostapis()[0].get('default_input_device') if isinstance(device, int): assert device <= len(sd.query_devices()) return device for i, dev in enumerate(sd.query_devices()): if dev['name'] == device: return i raise AssertionError('Device {} not found'.format(device))
def get_readable_output_devices_list(self): output_devices = self.get_output_devices() raw_devices = sounddevice.query_devices() default_output_device = sounddevice.query_devices(kind='output') default_output_device['index'] = raw_devices.index(default_output_device) devices_list = [] for device in output_devices: api = sounddevice.query_hostapis(device['hostapi'])['name'] if default_output_device is not None and device['index'] == default_output_device['index']: extra_info = ' (default)' else: extra_info = '' nchannels = device['max_output_channels'] desc = "%s (%d channels) (%s) %s" % (device['name'], nchannels, api, extra_info) devices_list += [desc] return devices_list
def __init__(self, measurement_ref): #super(AudioDeviceWidget, self).__init__(self) QtWidgets.QWidget.__init__(self) self.measurement_ref = measurement_ref api_list = sd.query_hostapis() textboxwidth = 120 numboxwidth = 55 self.api_box = QtWidgets.QComboBox() self.api_box.setFixedWidth(textboxwidth) self.output_devices_box = QtWidgets.QComboBox() self.output_devices_box.setFixedWidth(textboxwidth) self.input_devices_box = QtWidgets.QComboBox() self.input_devices_box.setFixedWidth(textboxwidth) self.samplerate_box = QtWidgets.QComboBox() self.samplerate_box.setFixedWidth(textboxwidth) self.use_feedback_loop = QtWidgets.QCheckBox() # channel layout as zero indexed channel numbers # output layout: [out_1, out_2, out_fb] # input layout: [in_left, in_right, in_fb] self.channel_layout_output = [0, 1, 2] self.channel_layout_input = [0, 1, 2] self.out_1_channel = QtWidgets.QComboBox() self.out_1_channel.setFixedWidth(numboxwidth) self.out_2_channel = QtWidgets.QComboBox() self.out_2_channel.setFixedWidth(numboxwidth) self.out_fb_channel = QtWidgets.QComboBox() self.out_fb_channel.setFixedWidth(numboxwidth) self.out_1_channel.activated.connect(self.set_output_channel_layout) self.out_2_channel.activated.connect(self.set_output_channel_layout) self.out_fb_channel.activated.connect(self.set_output_channel_layout) self.in_l_channel = QtWidgets.QComboBox() self.in_l_channel.setFixedWidth(numboxwidth) self.in_r_channel = QtWidgets.QComboBox() self.in_r_channel.setFixedWidth(numboxwidth) self.in_fb_channel = QtWidgets.QComboBox() self.in_fb_channel.setFixedWidth(numboxwidth) self.in_l_channel.activated.connect(self.set_input_channel_layout) self.in_r_channel.activated.connect(self.set_input_channel_layout) self.in_fb_channel.activated.connect(self.set_input_channel_layout) self.use_feedback_loop.stateChanged.connect(self.set_channel_layout) self.duplicate_channel_warning = QtWidgets.QLabel( "Warning: Duplicate channel assignment!") self.api_box.activated.connect(self.update_api) self.output_devices_box.activated.connect(self.update_device) self.input_devices_box.activated.connect(self.update_device) self.samplerate_box.activated.connect(self.set_samplerate) self.current_api_id = sd.default.hostapi if self.current_api_id < 0: self.current_api_id = 0 self.api_ids = [] self.input_dev_ids = [] self.output_dev_ids = [] for id, api in enumerate(api_list): if len(api['devices']): #only add when devices are present self.api_box.addItem(api['name']) self.api_ids.append(id) # in case ASIO is available, prefer ASIO! if api['name'] == 'ASIO': self.current_api_id = id self.api_box.setCurrentText( sd.query_hostapis(self.current_api_id)['name']) self.update_api() #self.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding,QtWidgets.QSizePolicy.MinimumExpanding) layout = QtWidgets.QHBoxLayout() left_list = QtWidgets.QFormLayout() right_list = QtWidgets.QFormLayout() left_list.setVerticalSpacing(2) right_list.setVerticalSpacing(2) label1 = QtWidgets.QLabel("Select Audio Device:") headline_font = label1.font() headline_font.setBold(True) label1.setFont(headline_font) left_list.setAlignment(QtCore.Qt.AlignLeading) left_list.addRow(label1) left_list.addRow("Audio API", self.api_box) verticalSpacer = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) left_list.addItem(verticalSpacer) left_list.addRow("Input Device", self.input_devices_box) left_list.addRow("Output Device", self.output_devices_box) left_list.addItem(verticalSpacer) left_list.addRow("Samplerate:", self.samplerate_box) right_list.addRow( QtWidgets.QLabel("Set In/Out Channels:", font=headline_font)) right_list.addRow(QtWidgets.QLabel("Output Excitation:"), self.out_1_channel) right_list.addRow(QtWidgets.QLabel("Output Excitation 2:"), self.out_2_channel) right_list.addRow(QtWidgets.QLabel("Output Feedback Loop:"), self.out_fb_channel) right_list.addRow(QtWidgets.QLabel("Input Left Ear Mic:"), self.in_l_channel) right_list.addRow(QtWidgets.QLabel("Input Right Ear Mic:"), self.in_r_channel) right_list.addRow(QtWidgets.QLabel("Input Feedback Loop:"), self.in_fb_channel) right_list.addItem(verticalSpacer) self.use_feedback_loop.setText("Use Feedback Loop if possible") right_list.addRow(self.use_feedback_loop) right_list.addItem(verticalSpacer) right_list.addItem(verticalSpacer) right_list.addRow(self.duplicate_channel_warning) self.duplicate_channel_warning.setVisible(False) self.duplicate_channel_warning.setFont(QtGui.QFont('Arial', 11)) layout.addLayout(left_list) layout.addLayout(right_list) self.setLayout(layout)
def get_drivers(): driver_device_dict = {} host_api_tuple = sd.query_hostapis() for temp_dict in host_api_tuple: driver_device_dict[temp_dict["name"]] = temp_dict["devices"] return driver_device_dict
def _init_mixer(fs, n_channels, api=None, name=None): """Select the API and device.""" devices = query_devices() if len(devices) == 0: raise OSError('No sound devices found!') apis = query_hostapis() # API if api is None: api = get_config('SOUND_CARD_API', None) if api is None: # Eventually we should maybe allow 'Windows WDM-KS', # 'Windows DirectSound', or 'MME' api = dict( darwin='Core Audio', win32='Windows WASAPI', linux='ALSA', )[sys.platform] for ai, this_api in enumerate(apis): if this_api['name'] == api: api = this_api break else: raise RuntimeError('Could not find host API %s' % (api,)) del this_api # Name if name is None: name = get_config('SOUND_CARD_NAME', None) if name is None: global _DEFAULT_NAME if _DEFAULT_NAME is None: di = api['default_output_device'] _DEFAULT_NAME = devices[di]['name'] logger.exp('Selected default sound device: %r' % (_DEFAULT_NAME,)) name = _DEFAULT_NAME possible = list() for di, device in enumerate(devices): if device['hostapi'] == ai: possible.append(device['name']) if name == device['name']: break else: raise RuntimeError('Could not find device on API %r with name ' 'containing %r, found:\n%s' % (api['name'], name, '\n'.join(possible))) param_str = ('sound card %r (devices[%d]) via %r, %d channels' % (device['name'], di, api['name'], n_channels)) if fs is not None: param_str += ' @ %d Hz' % (fs,) try: mixer = Mixer( samplerate=fs, latency='low', channels=n_channels, dither_off=True, device=di) except Exception as exp: raise RuntimeError('Could not set up %s:\n%s' % (param_str, exp)) assert mixer.channels == n_channels if fs is None: param_str += ' @ %d Hz' % (mixer.samplerate,) else: assert mixer.samplerate == fs mixer.start() try: mixer.start_time = mixer.time except Exception: mixer.start_time = 0 logger.info('Expyfun: using %s, %0.1f ms latency' % (param_str, 1000 * device['default_low_output_latency'])) return mixer
def _init_mixer(fs, n_channels, api, name, api_options=None): devices = sounddevice.query_devices() if len(devices) == 0: raise OSError('No sound devices found!') apis = sounddevice.query_hostapis() for ai, this_api in enumerate(apis): if this_api['name'] == api: api = this_api break else: raise RuntimeError('Could not find host API %s' % (api, )) del this_api # Name if name is None: name = get_config('SOUND_CARD_NAME', None) if name is None: global _DEFAULT_NAME if _DEFAULT_NAME is None: di = api['default_output_device'] _DEFAULT_NAME = devices[di]['name'] logger.exp('Selected default sound device: %r' % (_DEFAULT_NAME, )) name = _DEFAULT_NAME possible = list() for di, device in enumerate(devices): if device['hostapi'] == ai: possible.append(device['name']) if name in device['name']: break else: raise RuntimeError('Could not find device on API %r with name ' 'containing %r, found:\n%s' % (api['name'], name, '\n'.join(possible))) param_str = ('sound card %r (devices[%d]) via %r' % (device['name'], di, api['name'])) extra_settings = None if api_options is not None: if api['name'] == 'Windows WASAPI': # exclusive mode is needed for zero jitter on Windows in testing extra_settings = sounddevice.WasapiSettings(**api_options) else: raise ValueError( 'api_options only supported for "Windows WASAPI" backend, ' 'using %s backend got api_options=%s' % (api['name'], api_options)) param_str += ' with options %s' % (api_options, ) param_str += ', %d channels' % (n_channels, ) if fs is not None: param_str += ' @ %d Hz' % (fs, ) try: mixer = Mixer(samplerate=fs, latency='low', channels=n_channels, dither_off=True, device=di, extra_settings=extra_settings) except Exception as exp: raise RuntimeError('Could not set up %s:\n%s' % (param_str, exp)) assert mixer.channels == n_channels if fs is None: param_str += ' @ %d Hz' % (mixer.samplerate, ) else: assert mixer.samplerate == fs mixer.start() assert mixer.active logger.info('Expyfun: using %s, %0.1f ms nominal latency' % (param_str, 1000 * device['default_low_output_latency'])) atexit.register(lambda: (mixer.abort(), mixer.close())) return mixer