MOTU Midi Timepiece AV


I hooked up a MOTU Midi Timepiece AV to my Linux box.

The context

I've read there is no driver to use the MTP AV with Linux. Well, actually, there was one (mtpav.c) included with the package alsa-driver up to version 1.0.25. But, this package is now obsolete, embedded into the source of kernel.

Since there is a driver for Windows, still available with ClockWork at MOTU site, I wanted to investigate the protocol.

Linux, Windows and Cubase SX

Tools

  1. A computer running Linux and enough memory. Mine is HP XW6600, 8 cores, 16GB, running Ubuntu 20.04.
  2. A MOTU Midi Timepiece AV (MTP AV) USB compatible. Warning: there are 2 EPROM, one for Mac, one for Windows. Mine was the Mac version, but I installed the EPROM for Windows. ordered directly from MOTU website several years ago.
  3. The Windows driver for MTP AV USB MIDI Installer for Windows, available from MOTU site.
  4. Oracle Virtual Box, latest version (currently 6.1.18) and the Extension Pack. Available from VirtualBox site. Do not use the version that comes with Ubuntu. Check this link for details
  5. An installable image of Windows. Mine is Windows 7 32 bits.
  6. A sequencer, or any other tool able to send MIDI data. I used Cubase SX version 2.2.0.
  7. Wireshark, latest version (currently 3.2.3)
  8. Some knowledge of awk, to explore the decoded protocole easily

Preparation

  1. In VirtualBox, create a new VM with enough memory and disk.
  2. Install Windows and boot the VM
  3. Make sure the USB are enabled. Check this link for details.
  4. Install USB MIDI Installer for Windows; this will also install ClockWork. From here, you should be able to see the MTP AV.
  5. Install your favorite sequencer.
  6. Check your MTP AV is recognized. Send some MIDI notes: the USB In LED from the MTP should blink.
  7. In Linux, open a terminal (CTRL+ALT+T)
  8. In Linux terminal, identify yourself, load the monitoring module for USB and add ACL to grant read access to the usbmon interfaces:
    # Load the monitoring module for USB
    $ sudo modprobe usbmon
    
    # Identify yourself
    $ whoami
    francois
    
    # Add ACL to grant read access to the usbmon interfaces
    $ sudo setfacl -m u:francois:r /dev/usbmon*
    
    # Figure out which monitor to use (Bus 001 = usbmon1)
    $ sudo lsusb
    Bus 001 Device 004: ID 07fd:0001 Mark of the Unicorn MIDI Interface
    ...
    
    Check this link for details.
  9. Start Wireshark and configure it to decode the USB protocol. Check this link for details.
  10. In Wireshark, scan the usbmon device you've identified. If it's not the good one, do trials and errors.
  11. Play some notes with your sequencer and scan the USB.

Collected data

To understand how USB protocol works on Linux, please check this link.

Initialization

    To capture the initialization sequence:
  1. Start the capture in Wireshark
  2. Disable the device in VirtualBox before starting the VM
  3. Start the VM
  4. Enable the device; Wireshark should detect the initialization sequence
Here is the data captured (simplified):
No. Time      Destination Length Info
  1 0.000000  host → MTP  64     GET DESCRIPTOR Request DEVICE
  2 0.000504  MTP → host  82     GET DESCRIPTOR Response DEVICE

    DEVICE DESCRIPTOR
      ...
      idVendor: Mark of the Unicorn (0x07fd)
      idProduct: MIDI Interface (0x0001)
      ...

  3 0.000534  host → MTP  64     GET DESCRIPTOR Request CONFIGURATION
  4 0.000986  MTP → host  73     GET DESCRIPTOR Response CONFIGURATION
  
    Configuration bmAttributes: 0x80  NOT SELF-POWERED  NO REMOTE-WAKEUP
    bMaxPower: 50  (100mA)

  5 0.101078  host → MTP  64     GET DESCRIPTOR Request CONFIGURATION
  6 0.103001  MTP → host  201    GET DESCRIPTOR Response CONFIGURATION
The response is 4 INTERFACE DESCRIPTORS (0 to 3), each with 2 ENDPOINT DESCRIPTORS (1 IN, 1 OUT) The last descriptor (UNKNOWN DESCRIPTOR) contains the string "MIDI Time piece AV" (apparently in Unicode).
------------------------------------------------------------
INTERFACE DESCRIPTOR (0.0): class Vendor Specific
      
ENDPOINT DESCRIPTOR
  bEndpointAddress: 0x81  IN  Endpoint:1
  bmAttributes: 0x03
  wMaxPacketSize: 32
  bInterval: 2

ENDPOINT DESCRIPTOR
  bEndpointAddress: 0x02  OUT  Endpoint:2
  bmAttributes: 0x01
  wMaxPacketSize: 14
  bInterval: 1
------------------------------------------------------------
INTERFACE DESCRIPTOR (1.0): class Vendor Specific
ENDPOINT DESCRIPTOR
  ...
ENDPOINT DESCRIPTOR
  ...
------------------------------------------------------------
INTERFACE DESCRIPTOR (2.0): class Vendor Specific
ENDPOINT DESCRIPTOR
  ...
ENDPOINT DESCRIPTOR
  ...
------------------------------------------------------------
INTERFACE DESCRIPTOR (3.0): class Vendor Specific
ENDPOINT DESCRIPTOR
  ...
ENDPOINT DESCRIPTOR
  ...
------------------------------------------------------------
UNKNOWN DESCRIPTOR
  ...
------------------------------------------------------------
    
  7 0.103338  host → MTP  64     SET CONFIGURATION Request
  8 0.103617  MTP → host  64     SET CONFIGURATION Response
From here, the host talks with the internal USB HUB to add new interfaces. A new configuration request is made to the MTP (?), providing the same result. Then, the host sends URB_Interrupt in to the new interface created (1.4.1). It also sends a frame URB_ISOCHRONOUS out to a new interface 1.4.2 with a SYSEX and a filler
f0 00 00 33 02 30 00 f7 ff ff ff ff 01 00
Check the MTP AV SYSEX here

Output and acknowledge

Here are some data I've collected:

  1. When a note is played, the following frame is sent and the MTP replies back:
    No Time      Source  Destination  Protocol Length Info
     1 0.000000  host    1.14.2       USB      94     URB_ISOCHRONOUS out
     2 0.001753  1.14.2  host         USB      80     URB_ISOCHRONOUS out
      

Output frame in details:

USB URB
    [Source: host]
    [Destination: 1.14.2]
    URB id: 0xffff9d97fe5df500
    URB type: URB_SUBMIT ('S')
    URB transfer type: URB_ISOCHRONOUS (0x00)
    Endpoint: 0x02, Direction: OUT
    Device: 14
    URB bus id: 1
    Device setup request: not relevant ('-')
    Data: present (0)
    URB sec: 1614648348
    URB usec: 700796
    URB status: Operation now in progress (-EINPROGRESS) (-115)
    URB length [bytes]: 14
    Data length [bytes]: 30
    [Response in: 2]
    [bInterfaceClass: Unknown (0xffff)]
    ISO error count: 0
    Number of ISO descriptors: 1
    Interval: 1
    Start frame: 0
    Copy of Transfer Flags: 0x00000002, ISO ASAP
    Number of ISO descriptors: 1
    USB isodesc 0 [Cross-device link (-EXDEV)] (14 bytes)
        Status: Cross-device link (-EXDEV) (-18)
        Offset [bytes]: 0
        Length [bytes]: 14
        ISO Data: 903c64ffffffffffffffffff0500
        Padding: 0x00000000
The field ISO Data is 14 bytes and contains the MIDI:
90 3c 64 ff ff ff ff ff ff ff ff ff 05 00
--------
Blue: standard MIDI message (Note On, Channel 1, C4, velocity 100)
Black: filler
Green: exact role not yet determined; it seems to increase gradually.
The reply (frame 2) is 80 bytes long and contains no data.

The ISO Data field

Here are some examples I've collected (all examples on MIDI channel 1):
90 3c 64 ff ff ff ff ff ff ff ff ff 05 00: Note On, C4, vel 100
80 3c 40 ff ff ff ff ff ff ff ff ff 05 00: Note Off, C4, rel 64
Note on and off can be grouped in the same frame:
80 3e 40 90 3f 64 ff ff ff ff ff ff 05 00: 
- 80 3e 40: Note Off Chan 1, note D4, rel 64
- 90 3f 64: Note On, Chan 1, note E4, vel 100
Grouped notes (chords):
90 3c 64 3d 64 3e 64 ff ff ff ff ff 09 00
80 3c 40 3d 40 3e 40 ff ff ff ff ff 09 00
Several frames can be used if one is not sufficient:
90 3c 64 3d 64 3e 64 3f 64 40 64 41 0a 00
64 42 64 43 64 44 64 45 64 46 64 47 0a 00
64 ff ff ff ff ff ff ff ff ff ff ff 0a 00
80 43 40 44 40 45 40 46 40 47 40 ff 0a 00
3c 40 3d 40 3e 40 3f 40 40 40 41 40 0a 00
42 40 ff ff ff ff ff ff ff ff ff ff 0a 00
When another output of MTP AV is selected:
f5 02 90 3c 64 ff ff ff ff ff ff ff 09 00
- select output 2
Possible outputs are:
f5 01 output 1
f5 02 output 2
...
f5 08 output 8
f5 63 ADAT

SYSEX

The MTP AV MIDI Implementation chart is available here: SYSEX COMMANDS FOR Motu - TimepieceAV - MTP AV

Driver

The driver for MTP is called mtpav.ko. Historically, drivers for sound modules were packed with ALSA, in a folder called alsa-driver. However, the source for drivers are now shipped within the kernel source. My kernel did not have this module, so I had to build it.
  1. Go to your home directory (not /usr/src)
  2. Install the source of your kernel (actually, you'll get a tarball with the sources). I also had to install lex/yacc; in Linux world flex and bison (not sure if it is used).
    # apt-get install linux-source
    # apt-get install flex
    # apt-get install bison
    
  3. Untar the sources, configure and build the drivers
    # tar xf linux-source-5.4.0.tar.bz2
    # cd linux-source-5.4.0
    # make oldconfig
    # make prepare
    # make modules-prepare
    # make M=sound/drivers
    # cp sound/drivers/snd-mtpav.ko /lib/modules/5.4.0-66-generic/kernel/sound/drivers
    
    Unfortunatelly, it fails so far...
    # modprobe snd-mtpav
    modprobe: ERROR: could not insert 'snd_mtpav': Exec format error
    
More to come

Comments

Popular Posts