import array import binascii import usb.core import usb.util import time class USBMIDIConfiguration: def __init__(self, cfg, ifno, ifalt): self.cfg = cfg self.ifno = ifno self.ifalt = ifalt def __str__(self): return "cfg=%d ifno=%d ifalt=%d" % (self.cfg, self.ifno, self.ifalt) def __repr__(self): return "USBMIDIConfiguration(%d,%d,%d)" % (self.cfg, self.ifno, self.ifalt) class USBMIDIDeviceDescriptor: def __init__(self, vendorID, productID, interfaces = None): self.vendorID = vendorID self.productID = productID if interfaces is None: self.interfaces = [] else: self.interfaces = interfaces def add_interface(self, config, ifno, ifalt): self.interfaces.append(USBMIDIConfiguration(config, ifno, ifalt)) def has_interfaces(self): return len(self.interfaces) def __str__(self): return "vid=%04x pid=%04x" % (self.vendorID, self.productID) def __repr__(self): return "USBMIDIDeviceDescriptor(0x%04x, 0x%04x, %s)" % (self.vendorID, self.productID, self.interfaces) class USBMIDI: cin_sizes = [None, None, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1] def __init__(self, mididev, midicfg, debug = False): dev = usb.core.find(idVendor = mididev.vendorID, idProduct = mididev.productID) self.dev = dev intf = None for cfgo in dev: if cfgo.bConfigurationValue == midicfg.cfg: cfgo.set() intf = cfgo[(midicfg.ifno, midicfg.ifalt)] if not intf: raise ValueError, "Configuration %d not found" % midicfg.cfg print intf.bNumEndpoints self.epIn = None self.epOut = None for ep in intf: if debug: print "endpoint %x" % ep.bEndpointAddress if ep.bEndpointAddress > 0x80: if self.epIn is None: self.epIn = ep else: if self.epOut is None: self.epOut = ep def read(self): try: data = self.epIn.read(self.epIn.wMaxPacketSize) if data is None: return None return array.array('B', data) except usb.core.USBError, e: return None def encode(self, port, msg): a = array.array('B') a.append(16 * port + (msg[0] >> 4)) a.fromlist(msg) return a def write(self, data): self.epOut.write(data) def parse(self, data): i = 0 msgs = [] while i < len(data): if data[i] == 0: break cin, cable_id = data[i] & 15, data[i] >> 4 msgs.append(data[i + 1 : i + 1 + KeyRig25.cin_sizes[cin]]) i += 4 return msgs @staticmethod def findall(vendorID = None, productID = None, debug = False): dev_list = [] devices = usb.core.find(find_all = True) for dev in devices: if vendorID is not None and dev.idVendor != vendorID: continue if productID is not None and dev.idProduct != productID: continue thisdev = USBMIDIDeviceDescriptor(dev.idVendor, dev.idProduct) if debug: print "Device %04x:%04x, class %d" % (dev.idVendor, dev.idProduct, dev.bDeviceClass) if dev.bDeviceClass == 0: # device defined at interface level for cfg in dev: if debug: print "Configuration ", cfg.bConfigurationValue for intf in cfg: if debug: print "Interface %d alternate-setting %d" % (intf.bInterfaceNumber, intf.bAlternateSetting) print "Class %d subclass %d" % (intf.bInterfaceClass, intf.bInterfaceSubClass) if intf.bInterfaceClass == 1 and intf.bInterfaceSubClass == 3: if debug: print "(%d,%d,%d): This is USB MIDI" % (cfg.bConfigurationValue, intf.bInterfaceNumber, intf.bAlternateSetting) thisdev.add_interface(cfg.bConfigurationValue, intf.bInterfaceNumber, intf.bAlternateSetting) if thisdev.has_interfaces(): dev_list.append(thisdev) return dev_list #print devices class KnownUSBMIDI(USBMIDI): def __init__(self, vendorID, productID): devlist = USBMIDI.findall(vendorID, productID, debug = False) if not devlist: raise ValueError USBMIDI.__init__(self, devlist[0], devlist[0].interfaces[0]) class KeyRig25(KnownUSBMIDI): def __init__(self): KnownUSBMIDI.__init__(self, vendorID = 0x763, productID = 0x115) class XMidi2x2(KnownUSBMIDI): def __init__(self): KnownUSBMIDI.__init__(self, vendorID = 0x41e, productID = 0x3f08) class LexiconOmega(KnownUSBMIDI): def __init__(self): KnownUSBMIDI.__init__(self, vendorID = 0x1210, productID = 2) print USBMIDI.findall() xmidi = XMidi2x2() xmidi.write(xmidi.encode(1, [0x90, 36, 100])) xmidi.write(xmidi.encode(1, [0x80, 36, 100])) #krig = KeyRig25() krig = LexiconOmega() while True: data = krig.read() if data is not None: decoded = krig.parse(data) reencoded = array.array('B') for msg in decoded: reencoded.extend(xmidi.encode(1, list(msg))) xmidi.write(reencoded) print decoded