need help diagnosing USB MIDI latency problem with MPD16

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



 Hello,

Some time ago, I wrote the Akai MPD16 protocol handlers (input/output) for the USB MIDI driver. Unfortunately, the kernel driver seems to suffer from a rather embarrassing input latency, it looks like the MIDI event timing granularity is >100ms (so the latency is variable, making the pad practically useless except if a rhythm is played with the rate matching the polling rate!). At the same time, a simple Python based contraption using libusb and bulkRead in a while loop, gets much better results. The same USB MIDI driver in the same kernel and PC doesn't have noticeable problems with class-compliant E-Mu Xboard25 connected to the same USB port.

Both devices use endpoints in bulk mode. I've attached the excerpts of lsusb -v output for both devices - the only differences are:

1) the Akai device isn't class compliant,
2) the E-mu device has one pair of inputs/outputs, the Akai has two (control/configuration and MIDI proper)
3) the maximum packet length is 32 for E-mu, 64 for Akai.

When I enabled logging in midi.c (#define DUMP_PACKETS), it looks like the device is returning data packets rather infrequently, as a single packet often contains multiple events (up to 3) when two pads are pressed in rapid succession. So, it looks like a problem outside of my snd_usbmidi_akai_input.

One thing that *does* help, though, is disabling the 'control' port by adding endpoints[0].in_cables = 0; in Akai quirk handling in snd_usbmidi_create - when input from the control port is not polled, the choppiness disappears completely. I'm guessing that the device itself (or something in between) has some problems having to handle the URBs for both endpoints, and that perhaps the IN/NAK exchange on a "control" endpoint causes the device's microcontroller (or something else?) to stall for a while. However, in that case, a proper solution (one that doesn't involve sacrificing the ability to use control port for configuration) would involve submitting URBs for the control input endpoint only when control port is open on ALSA side, and cancelling them when the port is closed. However, that sounds pretty invasive.

Any hints? The device in question is rather uncommon and hasn't been supported for a while, so refactoring the whole USB MIDI driver to accommodate it doesn't sound like a great idea - but still, the latency thing sucks pretty bad for a drumming-oriented device!

Thanks in advance,
Krzysztof

Bus 005 Device 003: ID 041e:3f00 Creative Technology, Ltd 
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0        64
  idVendor           0x041e Creative Technology, Ltd
  idProduct          0x3f00 
  bcdDevice            0.47
  iManufacturer           1 E-MU Systems, Inc.
  iProduct                2 E-MU Xboard25
  iSerial                 3 E-MU-62-3F00-07D60505-90185-98
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength          101
    bNumInterfaces          2
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0xc0
      Self Powered
    MaxPower              250mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           0
      bInterfaceClass         1 Audio
      bInterfaceSubClass      1 Control Device
      bInterfaceProtocol      0 
      iInterface              0 
      AudioControl Interface Descriptor:
        bLength                 9
        bDescriptorType        36
        bDescriptorSubtype      1 (HEADER)
        bcdADC               1.00
        wTotalLength            9
        bInCollection           1
        baInterfaceNr( 0)       1
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         1 Audio
      bInterfaceSubClass      3 MIDI Streaming
      bInterfaceProtocol      0 
      iInterface              0 
      MIDIStreaming Interface Descriptor:
        bLength                 7
        bDescriptorType        36
        bDescriptorSubtype      1 (HEADER)
        bcdADC               1.00
        wTotalLength           37
      MIDIStreaming Interface Descriptor:
        bLength                 6
        bDescriptorType        36
        bDescriptorSubtype      2 (MIDI_IN_JACK)
        bJackType               1 Embedded
        bJackID                 1
        iJack                   0 
      MIDIStreaming Interface Descriptor:
        bLength                 6
        bDescriptorType        36
        bDescriptorSubtype      2 (MIDI_IN_JACK)
        bJackType               2 External
        bJackID                 2
        iJack                   0 
      MIDIStreaming Interface Descriptor:
        bLength                 9
        bDescriptorType        36
        bDescriptorSubtype      3 (MIDI_OUT_JACK)
        bJackType               1 Embedded
        bJackID                 3
        bNrInputPins            1
        baSourceID( 0)          2
        BaSourcePin( 0)         1
        iJack                   0 
      MIDIStreaming Interface Descriptor:
        bLength                 9
        bDescriptorType        36
        bDescriptorSubtype      3 (MIDI_OUT_JACK)
        bJackType               2 External
        bJackID                 4
        bNrInputPins            1
        baSourceID( 0)          1
        BaSourcePin( 0)         1
        iJack                   0 
      Endpoint Descriptor:
        bLength                 9
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0020  1x 32 bytes
        bInterval               1
        bRefresh                0
        bSynchAddress           0
        MIDIStreaming Endpoint Descriptor:
          bLength                 5
          bDescriptorType        37
          bDescriptorSubtype      1 (GENERAL)
          bNumEmbMIDIJack         1
          baAssocJackID( 0)       1
      Endpoint Descriptor:
        bLength                 9
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0020  1x 32 bytes
        bInterval               1
        bRefresh                0
        bSynchAddress           0
        MIDIStreaming Endpoint Descriptor:
          bLength                 5
          bDescriptorType        37
          bDescriptorSubtype      1 (GENERAL)
          bNumEmbMIDIJack         1
          baAssocJackID( 0)       3
Device Status:     0x0000
  (Bus Powered)

Bus 005 Device 006: ID 09e8:0062 AKAI  Professional M.I. Corp. 
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass          255 Vendor Specific Class
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0         8
  idVendor           0x09e8 AKAI  Professional M.I. Corp.
  idProduct          0x0062 
  bcdDevice            1.00
  iManufacturer           1 
  iProduct                2 
  iSerial                 0 
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           46
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          3 
    bmAttributes         0xa0
      (Bus Powered)
      Remote Wakeup
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           4
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass      0 
      bInterfaceProtocol    255 
      iInterface              0 
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               1
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               1
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x02  EP 2 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               1
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x82  EP 2 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               1

import usb
import alsaseq

mpd16 = None

idVendor = 0x09e8
idProduct = 0x0062

for bus in usb.busses():
    for device in bus.devices:
        if device.idVendor == idVendor and device.idProduct == idProduct:
            mpd16 = device
            break

if mpd16 is None:
    raise ValueError, "No MPD16 found"

conf = mpd16.configurations[0]
iface = conf.interfaces[0][0]

midiept = None
for ept in iface.endpoints:
    if ept.address == 0x82:
        midiept = ept
        break
if midiept is None:
    raise ValueError, "MIDI endpoint not found"
    
dev = mpd16.open()
dev.setConfiguration(mpd16.configurations[0])
dev.claimInterface(0)
dev.setAltInterface(0)
#dev.reset()

#print "MPD16", dir(mpd16)
#print "Config", dir(conf)
#print "Iface", dir(iface)
#print dev.getString(2, 200)
#print midiept.maxPacketSize
alsaseq.client("MPD16", 0, 1, False)
while True:
    data = dev.bulkRead(midiept.address, midiept.maxPacketSize, 0)
    if len(data) == 2:
        continue
    pos = 0
    while pos < len(data):
        elen = data[pos] - 32
        edata = data[pos + 1 : pos + 1 + elen]
        channel = edata[0] & 0x0F
        if edata[0] >= 0x90 and edata[0] <= 0x9F:
            if edata[2] > 0:
                alsaseq.output( (alsaseq.SND_SEQ_EVENT_NOTEON, 1, 0, 253, (0, 0), (0, 0), (0, 0), (channel, edata[1], edata[2], 0, 0)))
            else:
                alsaseq.output( (alsaseq.SND_SEQ_EVENT_NOTEOFF, 1, 0, 253, (0, 0), (0, 0), (0, 0), (channel, edata[1], 0, 0, 0)))
        if edata[0] >= 0xA0 and edata[0] <= 0xAF:
            alsaseq.output( (alsaseq.SND_SEQ_EVENT_KEYPRESS, 1, 0, 253, (0, 0), (0, 0), (0, 0), (channel, edata[1], edata[2], 0, 0)))
        if edata[0] >= 0xB0 and edata[0] <= 0xBF:
            alsaseq.output( (alsaseq.SND_SEQ_EVENT_CONTROLLER, 1, 0, 253, (0, 0), (0, 0), (0, 0), (channel, 0, 0, 0, edata[1], edata[2])))
        pos += 1 + elen
dev.releaseInterface()
_______________________________________________
Alsa-devel mailing list
Alsa-devel@xxxxxxxxxxxxxxxx
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux