In my code, I am using Tkinter, PyAudio and the SpeechRecognition library. The speech recognition library uses PyAudio for interfacing with the PC's microphones (im on Win 10), and allows you to select the microphone input to use through an index value. This index refers to a list of microphones the system has available. This list contains multiple dictionaries, each dictionary containing information on each audio device connected to the system. Each of these dictionaries contains a field called "index", which stores an integer value representing where that dictionary lays in the overall list. This list is fetched by the SpeechRecognition library through the PyAudio library.
I can use the same method the speech recognition library does with the PyAudio library to generate my own list of microphones using
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
This function fetches each dictionary separately from this list, and, if the maxInputChannels field has a value > 0, the value of the name
field is stored in a separate list. I can then display this list in a tkinter OptionMenu with the below code:
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)
Here's the problem: These microphone names are taken from a dictionary that is returned by p.get_device_info_by_index(i)
using.get("name"), as seen above. The names are then placed into a list to be used, as explained.
Overall, my question would be, how can i use the selected string (name) of the microphone from the OptionMenu in order to get back to the original dictionary it was taken from, so that i can then access its index
field to use later on. Any help is much appreciated, as i feel like there would definitely be some best practices for this.
Extends a tk.OptionMenu
to return a selected audio device.
return self._devices.get(self.selected.get(), None)
Core Point :
Instead of saving the index of a device, which is not in sync with get_device_count()
, store the whole device into a dict
with key == device['name']
.
device = p.get_device_info_by_index(i)
devices[device.get("name")] = device
Imports, Simulated 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]
Extends
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)
Usage :
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()
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.