You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
153 lines
5.5 KiB
153 lines
5.5 KiB
3 years ago
|
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
|