Beispiel #1
0
    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_()
Beispiel #2
0
    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()
Beispiel #4
0
    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
Beispiel #5
0
    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
Beispiel #6
0
    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>>')
Beispiel #7
0
    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
Beispiel #8
0
    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
Beispiel #9
0
    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
Beispiel #10
0
    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]
Beispiel #11
0
Datei: app.py Projekt: jkjh8/lmd
 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)
Beispiel #12
0
 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', '')
Beispiel #13
0
    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')
Beispiel #14
0
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})"
    )
Beispiel #16
0
    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
Beispiel #17
0
 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>>')
Beispiel #18
0
    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)
Beispiel #19
0
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)
Beispiel #20
0
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]
Beispiel #21
0
    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
Beispiel #23
0
 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))
Beispiel #25
0
    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
Beispiel #26
0
    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
Beispiel #27
0
    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))
Beispiel #28
0
    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)
Beispiel #30
0
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
Beispiel #31
0
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
Beispiel #32
0
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