Как использовать Tkinter OptionMenu для выбора входа микрофона - PullRequest
0 голосов
/ 18 июня 2020

В моем коде я использую Tkinter, PyAudio и библиотеку SpeechRecognition. Библиотека распознавания речи использует PyAudio для взаимодействия с микрофонами P C (im на Win 10) и позволяет вам выбирать вход микрофона для использования через значение индекса. Этот индекс относится к списку доступных в системе микрофонов. Этот список содержит несколько словарей, каждый из которых содержит информацию о каждом аудиоустройстве, подключенном к системе. Каждый из этих словарей содержит поле, называемое «индекс», в котором хранится целочисленное значение, представляющее, где этот словарь находится в общем списке. Этот список извлекается библиотекой SpeechRecognition через библиотеку PyAudio.

Я могу использовать тот же метод, что и библиотека распознавания речи с библиотекой PyAudio, чтобы сгенерировать свой собственный список микрофонов, используя

def getMicrophones(self):
        import pyaudio
        p = pyaudio.PyAudio()
        temp = []
        for i in range(p.get_device_count()):
            if p.get_device_info_by_index(i).get("maxInputChannels") > 0: #if maxInputChannels > 0, then device is a microphone
                temp.append(p.get_device_info_by_index(i).get("name"))
        return temp

Эта функция извлекает каждый словарь отдельно из этого списка, и, если поле maxInputChannels имеет значение> 0, значение поля name сохраняется в отдельном списке. Затем я могу отобразить этот список в OptionMenu tkinter с помощью следующего кода:

self.micOptions = self.getMicrophones()
self.selectedMicrophone = tk.StringVar() #Tkinter variable needs to be made so that the dropdown can hold a value
self.selectedMicrophone.set(self.micOptions[0]) #Set default OptionMenu value
self.micDropDown = tk.OptionMenu(self, self.selectedMicrophone, *self.micOptions)

Вот проблема: эти имена микрофонов взяты из словаря, который возвращается p.get_device_info_by_index(i) с использованием .get ("name" ), как показано выше. Затем имена помещаются в список, который будет использоваться, как описано. исходный словарь, из которого он был взят, чтобы затем я мог получить доступ к его полю index для использования позже. Любая помощь приветствуется, так как я чувствую, что для этого определенно есть несколько лучших практик.

1 Ответ

1 голос
/ 18 июня 2020

Расширяет tk.OptionMenu для возврата выбранного аудиоустройства.

return self._devices.get(self.selected.get(), None)

Core Point :

Вместо сохранения индекса устройства, которое не синхронизировано c с get_device_count(), сохраните все устройство в dict с key == device['name'].

                device = p.get_device_info_by_index(i)
                devices[device.get("name")] = device

Импорт, имитация PyAudio :

import tkinter as tk


# Simulating PyAudio
class PyAudio:
    def __init__(self):
        self._devices = [{'name': 'Device 1', 'maxInputChannels': 0},
                         {'name': 'Device 2', 'maxInputChannels': 1},
                         {'name': 'Device 3', 'maxInputChannels': 0},
                         {'name': 'Device 4', 'maxInputChannels': 2},
                         {'name': 'Device 5', 'maxInputChannels': 3},
                         ]

    def get_device_count(self):
        return len(self._devices)

    def get_device_info_by_index(self, i):
        return self._devices[i]

Расширяет tk.OptionMenu:

class Microphones(tk.OptionMenu):
    def __init__(self, parent, **kwargs):
        self.selected = tk.StringVar()
        self._devices = kwargs.pop('devices', ())
        options = tuple(self._devices.keys())

        super().__init__(parent, self.selected, *options, **kwargs)
        self.selected.set(options[0])

    @property
    def device(self):
        return self._devices.get(self.selected.get(), None)

Использование :

class App(tk.Tk):
    def __init__(self):
        super().__init__()

        self.micDropDown = Microphones(self, devices=self.getMicrophones(), command=self.on_selected)
        self.micDropDown.pack()

    def on_selected(self, event):
        print(f'on_selected({self.micDropDown.selected.get()}, '
              f'device={self.micDropDown.device})')

    def getMicrophones(self):
        """
        import pyaudio
        p = pyaudio.PyAudio()
        """
        p = PyAudio()
        devices = {}
        for i in range(p.get_device_count()):
            # if maxInputChannels > 0, then device is a microphone
            if p.get_device_info_by_index(i).get("maxInputChannels") > 0:
                device = p.get_device_info_by_index(i)
                devices[device.get("name")] = device
        return devices


if __name__ == '__main__':
    App().mainloop()
...