【问题标题】:PyGame Re-Initialize USB MIDI Device on ReconnectPyGame 在重新连接时重新初始化 USB MIDI 设备
【发布时间】:2015-01-17 04:43:54
【问题描述】:

我正在使用 PyGame 读取 USB MIDI 设备,与 here 使用的非常相似,只是我将它作为 Raspberry Pi 上的后台服务运行。

我希望能够断开并重新连接 MIDI 设备,并且仍然能够读取它。

我尝试了两种方法:

  1. 使用 pygame.midi.get_count() 和 info() 定期枚举 MIDI 设备。
  2. 使用pyudev监控USB事件,类似于this的例子。

(1) 的问题在于,无论设备是否仍处于连接状态,pygame.midi 似乎总是返回相同的值(get_count 和 info)。

(2) 的问题在于它永远不会调用我为事件注册的异步函数(尽管独立示例工作正常,只需将子系统更改为 USB)。我认为这可能是线程的问题,所以我调用了所有东西来注册来自专用线程的事件,然后运行 ​​glib.MainLoop.run() 到空闲等待,但发现 pygame 将无法读取 midi 设备如果我在运行我的 AMK 类之前启动了 any 线程,即使只是一个打印某些内容并返回的线程。 (我使用 glib,因为 Pi repo 中 pyudev 的版本是 0.13,但我猜更新的方法是 gobject 等价物)。

因此我求助于使用 udevd 来检测连接事件并通过 /etc/udev/rules.d/ 触发器重新启动我的服务,这可以正常工作,但是很笨拙,并且在我的脚本中丢失了状态(我会喜欢保存)。

所以,在我浪费更多时间调试 (2) 之前,我希望有人能指出我正确的方向。

【问题讨论】:

    标签: python pygame midi udev pyudev


    【解决方案1】:

    pygame 使用 PortMidi,它最初是为 Windows MIDI API 设计的,并假设 MIDI 端口集永远不会改变。

    您必须使用单独的监视器进程来在 MIDI 端口更改时重新启动您的程序。

    【讨论】:

    • 很有趣,谢谢。这解释了方法(1)的问题。似乎它表明(2)是正确的方法,但是我想知道是否有必要在注册 USB 监视器后生成一个新线程。如果是,那么我想知道为什么 PyGame 不能很好地处理线程,如果不是,那么为什么在我运行 PyGame 类时没有调用我的偶数处理程序。
    【解决方案2】:

    我尚未对此进行彻底测试,但我相信如果您致电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()
    

    【讨论】:

    • 感谢您的提示。奇怪的是,如果我尝试使用 quit() 和 init() 然后重新初始化设备,随后对 midi_in.poll() 的调用会失败:PortMidi call failed... PortMidi: 'Bad pointer' type ENTER... 而且我验证了新的 midi_in 是一个有效对象 (<pygame.midi.Input object at 0xb4a959d0>)。无论如何,这似乎是一种非常丑陋的方式来做我想做的事。由于我想实时读取 MIDI 设备,因此不断退出和重新启动似乎是个坏主意。
    • 如果您不想求助于外部程序,您可以在主循环中监控系统日志并查找 MIDI 连接/断开事件。例如,使用mesg=commands.getoutput('dmesg | grep -i midi') 并检查mesg 是否与上一次迭代相比发生了变化。只有在这种情况下,您才需要执行 midi 退出和初始化。我现在在办公室,无法检查 midi_in.poll() 的问题,但您是否记得再次重新关联 midi 端口(使用 midi_in=pygame.midi.Input(portnumber)?
    【解决方案3】:

    这就是我监控现有或新添加的 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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多