PyGame повторно инициализирует USB MIDI-устройство при переподключении
Я использую PyGame для чтения USB MIDI-устройства, очень похожего на то, что используется здесь, за исключением того, что я запускаю его в качестве фоновой службы на Raspberry Pi.
Я хотел бы иметь возможность отключить и повторно подключить MIDI-устройство, и все же иметь возможность читать его.
Я попробовал два подхода:
- Регулярно перечисляйте MIDI-устройства, используя pygame.midi.get_count() и info().
- Используйте pyudev для мониторинга событий USB, аналогично этому примеру.
Проблема с (1) заключается в том, что pygame.midi всегда возвращает одинаковые значения (как get_count, так и info), независимо от того, подключено ли устройство.
Проблема с (2) состоит в том, что он никогда не будет вызывать асинхронную функцию, которую я зарегистрировал для событий (хотя автономный пример работает нормально, просто меняя подсистему на usb). Я подумал, что это может быть проблемой с многопоточностью, поэтому я вызвал все для регистрации событий из выделенного потока, который затем запустил glib.MainLoop.run() для ожидания простоя, но обнаружил, что pygame не сможет прочитать устройство midi. если я запустил какой-либо поток перед запуском своего класса AMK, даже просто поток, который что-то напечатал и вернул. (Я использую glib, так как версия pyudev в репозитории Pi равна 0,13, но я думаю, что более новый путь - это эквивалент gobject).
Таким образом, я прибег к использованию udevd для обнаружения события подключения и перезапуска службы с помощью триггера /etc/udev/rules.d/, который работает нормально, но не работает и теряет состояние в моем сценарии (который я хотел бы сохранить).
Поэтому, прежде чем я потратил еще много часов на отладку (2), я надеялся, что кто-то может указать мне правильное направление.
3 ответа
Pygame использует PortMidi, который был изначально разработан для Windows MIDI API и предполагает, что набор портов MIDI никогда не меняется.
Вы должны использовать отдельный процесс мониторинга, который перезапускает вашу программу всякий раз, когда меняются MIDI-порты.
Я еще не проверил это полностью, но я считаю, что если вы позвоните quit
а потом снова init
Затем вы можете получить правильно обновленный список MIDI-устройств. Вот пример:
import pygame, pygame.midi
pygame.midi.init()
print pygame.midi.get_count()
a=raw_input('Connect or disconnect some MIDI devices')
pygame.midi.quit()
pygame.midi.init()
print pygame.midi.get_count()
Вот как я отслеживаю существующие или недавно добавленные устройства Midi -
wait_for_midi()
блокируется до тех пор, пока в системе не появится MIDI-устройство и не вернет
/dev/midi*
путь к нему.
import re
import pyudev
def is_midi_device(dev_path):
if dev_path is None:
return False
if re.match(u"^/dev/midi[0-9]+$", dev_path):
return True
return False
# Return path to a MIDI device when found.
def wait_for_midi():
context = pyudev.Context()
# Check for existing midi devices
for device in context.list_devices():
dev_path = device.device_node
if is_midi_device(dev_path) :
print('Found {}'.format(dev_path))
return dev_path
# Monitor for new midi devices as added
monitor = pyudev.Monitor.from_netlink(context)
monitor.filter_by(subsystem='sound')
for action, device in monitor:
if action != "add":
continue
dev_path = device.device_node
if is_midi_device(dev_path) :
print('Just added: {}'.format(dev_path))
return dev_path