简体   繁体   中英

PyGame Re-Initialize USB MIDI Device on Reconnect

I'm using PyGame to read a USB MIDI device, very similar to what is used here , except I run it as a background service on a Raspberry Pi.

I would like to be able to disconnect and reconnect the MIDI device, and still be able to read it.

I have tried two approaches:

  1. Regularly enumerate the MIDI devices using pygame.midi.get_count() and info().
  2. Use pyudev to monitor USB events, similar to this example.

The problem with (1) is that it seems that pygame.midi always returns the same values (both get_count and info), regardless of whether the device is still connected.

The problem with (2) is that it would never call the asynchronous function I registered for events (though the standalone example works fine, just changing the subsytem to usb). I figured this might be a problem with threading, so I called everything to register for events from a dedicated thread, which then ran glib.MainLoop.run() to idle wait, but discovered the pygame would not be able to read the midi device if I started any thread before running my AMK class, even just a thread that printed something and returned. (I'm using glib since the version of pyudev in the Pi repo is 0.13, but I guess the newer way is the gobject equivalent).

Thus I resorted to using udevd to detect the connect event and restart my service via a /etc/udev/rules.d/ trigger, which works okay, but is kludgy, and loses the state in my script (which I would like to save).

So, before I waste many more hours debugging (2), I was hoping someone could perhaps point me in the right direction.

pygame uses PortMidi, which was originally designed for the Windows MIDI API and assumes that the set of MIDI ports never changes.

You have to use a separate monitor process that restarts your program whenever MIDI ports change.

I haven't tested this thoroughly yet but I believe that if you call quit and then again init , you can then get a properly updated list of MIDI devices. Here is an example:

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()

This is how I monitor for existing or newly added Midi devices - wait_for_midi() will block until a MIDI device appears in the system and returns the /dev/midi* path to it.

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

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM