Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8250667

MIDI sysex over USB scrambled when reply length matches previous message

    XMLWordPrintable

Details

    • b25
    • x86_64
    • windows_10

    Description

      ADDITIONAL SYSTEM INFORMATION :
      Intel or compatible PC, Windows 10 (build 19041 or other), Java 14.0.1 (64 bit AdoptOpenJDK build 14.0.1+7 hotspot, mixed mode, sharing) or Java 1.8.0_191 (32-bit JRE, build 25.191-b12, mixed mode).

      A DESCRIPTION OF THE PROBLEM :
      When sending a sysex message of a certain length n, followed by a sysex message causing a sysex reply of length n (sometimes n+1 or n-1), the next (third) sysex message is totally mixed up. It contains some artifacts from the previous messages and invalid (zero) USB midi headers. The problem is reliably reproducible and the content of the messages sent via USB is always the same, independently of timing. The error does not occur when sending these messages from python using rtmidi.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run the source code below with an Ableton Push 2 attached via USB. Use an USB sniffer like BEAGLE USB 480 for tracing. Analyse the outgoing data. Alternatively, use display brightness setting as third sysex command to see if it works (commented out).

      To repoduce with other hardware: Other USB MIDI hardware sends replies of different length to the device inquiry used as second command. Therefore, to reproduce the issue for other hardware, the length of the first sysex message needs to be adopted - just add or remove bytes. The third sysex should do something observable with that hardware.

      The python program to verify its not a driver issue looks as follows (run with python 2.7, sorry):
      ---- cut here ----
      #!/usr/bin/env python
      import rtmidi
      import re

      def open_push2_midiout():
          pattern = "Ableton Push 2( [0-9]+)*"
          midiio = rtmidi.MidiOut()
          ports = midiio.get_ports()

          for i, port in enumerate(ports):
              if re.match(pattern, port):
                  midiio.open_port(i)
                  return midiio
          return None

      midiout = open_push2_midiout()
      midiout.send_message([0xF0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
                            0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
                            0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0xF7])
      midiout.send_message([0xF0, 0x7E, 0x7F, 0x06, 0x01, 0xF7])
      midiout.send_message([0xF0, 0x00, 0xF7])
      # midiout.send_message([0xF0, 0x00, 0x21, 0x1D, 0x01, 0x01, 0x08, 0x3F, 0x00, 0xF7])


      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Correct sysex transfer (as produced by python script with rtmidi, see below):
      > sysex message f0000102030405060708090a0b0c0d0e0f1011121314f7 <--- 23 MIDI bytes
      sent:
        04 F0 00 01
        04 02 03 04
        04 05 06 07
        04 08 09 0A
        04 0B 0C 0D
        04 0E 0F 10
        04 11 12 13
        06 14 F7 00
      > sysex message f07e7f0601f7
      sent:
        04 F0 7E 7F
        07 06 01 F7
      received: (23 MIDI bytes)
        04 F0 7E 01
        04 06 02 00
        04 21 1D 67
        04 32 02 00
        04 01 00 46
        04 00 16 7A
        04 28 08 00
        06 01 F7 00
      > sysex message f000f7
      sent:
        07 F0 00 F7

      ACTUAL -
      Incorrect sysex transfer (as produced by the given Java program)
      > sysex message f0000102030405060708090a0b0c0d0e0f1011121314f7 <--- 23 MIDI bytes
      sent:
        04 F0 00 01
        04 02 03 04
        04 05 06 07
        04 08 09 0A
        04 0B 0C 0D
        04 0E 0F 10
        04 11 12 13
        06 14 F7 00
      > sysex message f07e7f0601f7
      sent:
        04 F0 7E 7F
        07 06 01 F7
        00 05 06 07 <--- extra bytes with zero headers
        00 08 09 0A
        00 0B 0C 0D
        00 0E 0F 10
        00 11 12 13
      received: (23 MIDI bytes)
        04 F0 7E 01
        04 06 02 00
        04 21 1D 67
        04 32 02 00
        04 01 00 46
        04 00 16 7A
        04 28 08 00
        06 01 F7 00
      > sysex message f000f7
      sent:
        00 14 F7 00 <- no useful sysex from here, zero headers
        00 06 01 06
        00 05 06 05
        00 08 07 08
        00 0B 0A 0B
        00 0E 0D 0E
        00 11 10 11
        00 14 13 14
        05 F7 00 00


      ---------- BEGIN SOURCE ----------
      import javax.sound.midi.*;

      class SysexTest {
          static MidiDevice findOutPort() throws MidiUnavailableException {
              MidiDevice.Info[] infoArray = MidiSystem.getMidiDeviceInfo();
              for (MidiDevice.Info info : infoArray) {
                  if (info.getName().equals("Ableton Push 2")) {
                      MidiDevice port = MidiSystem.getMidiDevice(info);
                      if (port.getMaxReceivers() != 0) {
                          return port;
                      }
                  }
              }
              return null;
          }

          static void sendMessage(MidiDevice outPort, byte[] data) throws Exception {
              SysexMessage msg = new SysexMessage(data, data.length);
              outPort.getReceiver().send(msg, -1l);
          }

          static final byte[] data1 = new byte[] {(byte)0xF0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
                                                  0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
                                                  0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, (byte)0xF7};
          static final byte[] data2 = new byte[] {(byte)0xF0, 0x7E, 0x7F, 0x06, 0x01, (byte)0xF7};
          static final byte[] data3 = new byte[] {(byte)0xF0, 0x00, (byte)0xF7};

          // alternatively, set display backlight brightness to 25%
          // static final byte[] data3 = new byte[] {(byte)0xF0, 0x00, 0x21, 0x1D, 0x01, 0x01,
          // 0x08, 0x3F, 0x00, (byte)0xF7};

          public static void main(String[] args) throws Exception {
              MidiDevice outPort = findOutPort();
              outPort.open();
              sendMessage(outPort, data1); // dummy message of 23 bytes
              sendMessage(outPort, data2); // device inquiry with 23 bytes reponse
              sendMessage(outPort, data3); // this message is sent out scrambled
              System.exit(0);
          }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      no workarounds known

      FREQUENCY : always


      Attachments

        Issue Links

          Activity

            People

              prr Philip Race
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: