【问题标题】:Java midi SysEx message, stream stuck, possible bug?Java midi SysEx 消息,流卡住,可能的错误?
【发布时间】:2017-07-30 19:59:29
【问题描述】:

当我一个接一个地以不同字节长度实时发送 sysex 消息时,midi 流会卡住。如果我只坚持一个字节长度,但我有 2 条不同的 sysex 消息要传递:一条用于实时参数更改,一条用于完整补丁(备份)。
我已经通过 javaFX 编写了一个示例测试用例来演示这种行为。

import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.geometry.Orientation;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Slider;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Receiver;
import javax.sound.midi.ShortMessage;
import javax.sound.midi.SysexMessage;
import static javax.sound.midi.SysexMessage.SYSTEM_EXCLUSIVE;


public class MidiTestEnvironment extends Application {

    public static MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo();
    public static MidiDevice outputDevice;
    public static Receiver outputReceiver;
    public static final byte DEVICE_NUMBER = 76;

    @Override
    public void start(Stage primaryStage) {

        // Show output devices only. Replace the DEVICE_NUMBER constant with a working
        // output midi device number.
        printOutputDevices();

        // Set the output device and open it first, then set the receiver. 
        try {
            outputDevice = MidiSystem.getMidiDevice(MidiSystem.getMidiDeviceInfo()[DEVICE_NUMBER]);
            if (!(outputDevice.isOpen())){
                outputDevice.open();
            }
            outputReceiver = outputDevice.getReceiver();
            System.out.println("outputreciever: " + outputDevice.getDeviceInfo().getName());
        } catch (MidiUnavailableException ex) {
            Logger.getLogger(MidiTestEnvironment.class.getName()).log(Level.SEVERE, null, ex);
        }

        // Create a Button and send a Message to the defined Midi Out
        Button btn1 = new Button("Send Message 82 bytes !");
        btn1.setOnAction((ActionEvent event) -> {
            try {
                // sendControlMessage(7,50);
                sendSysexMessage(SysexJX8P_APN(), SysexJX8P_APN().length);
                System.out.println("Hello World!");
            } catch (InvalidMidiDataException ex) {
                Logger.getLogger(MidiTestEnvironment.class.getName()).log(Level.SEVERE, null, ex);
            }
        });

        // Create a Slider and send a Message to the defined Midi Out
        Slider sysexSlider = new Slider(0,127,0);
        sysexSlider.setMaxHeight(200);
        sysexSlider.setOrientation(Orientation.VERTICAL);

        sysexSlider.valueProperty().addListener((value,oldValue,newValue)->{
            try {
                sendSysexMessage(SysexJX8P_L1(20,newValue.byteValue()),10);
            } catch (InvalidMidiDataException ex) {
                Logger.getLogger(MidiTestEnvironment.class.getName()).log(Level.SEVERE, null, ex);
            }
        });

        // Cobble the gui together
        HBox root = new HBox();
        root.setSpacing(20);
        root.getChildren().addAll(btn1,sysexSlider);

        Scene scene = new Scene(root, 300, 250);

        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

    //-------------------------------------------------------------------------------------------------------------------------------
    //-- SETUP MIDI MESSAGES
    //-------------------------------------------------------------------------------------------------------------------------------

    public static void sendControlMessage(int controller, int value) throws MidiUnavailableException {
        ShortMessage controlMessage = new ShortMessage();
        try {
            controlMessage.setMessage(ShortMessage.CONTROL_CHANGE, controller, value);
        } catch (InvalidMidiDataException ex) {
           Logger.getLogger(MidiTestEnvironment.class.getName()).log(Level.SEVERE, null, ex);
        }
        outputReceiver.send(controlMessage, -1);
    }



    public static void sendSysexMessage(byte[] data, int length) throws InvalidMidiDataException {
        SysexMessage sysexMessage = new SysexMessage();
        try {
            sysexMessage.setMessage(data, length);
            outputReceiver.send(sysexMessage, -1);
        } catch (InvalidMidiDataException ex) {
            Logger.getLogger(MidiTestEnvironment.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    //-------------------------------------------------------------------------------------------------------------------------------
    // DISPLAY OUTPUT DEVICES ONLY
    public static void printOutputDevices() {
        for (int i = 0; i < MidiSystem.getMidiDeviceInfo().length; i++) {
            try {
                if (MidiSystem.getMidiDevice(infos[i]).getMaxReceivers() == -1
                        && !MidiSystem.getMidiDevice(infos[i]).getDeviceInfo().getName().equals("Gervill")) 
                {
                    System.out.println(infos[i].getName() + " - " + infos[i].getDescription() + " | device Number: " + i);
                }
            } catch (MidiUnavailableException ex) {
                Logger.getLogger(MidiTestEnvironment.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
    //-------------------------------------------------------------------------------------------------------------------------------
    //-- TEST SYSEX MESSAGES
    //-------------------------------------------------------------------------------------------------------------------------------
    public static final byte[] SysexJX8P_L1(int p_byteEight, byte v_byteNine) {
        byte[] sysexStringL1 = new byte[10];
        sysexStringL1[0] = (byte) (SYSTEM_EXCLUSIVE & 0xFF);
        sysexStringL1[1] = 0x41;
        sysexStringL1[2] = 0x36;
        sysexStringL1[3] = 0x00;
        sysexStringL1[4] = 0x21;
        sysexStringL1[5] = 0x20;
        sysexStringL1[6] = 0x01;
        sysexStringL1[7] = (byte) p_byteEight;
        sysexStringL1[8] = v_byteNine;
        sysexStringL1[9] = (byte) (ShortMessage.END_OF_EXCLUSIVE & 0xFF);
        return sysexStringL1;
    }

    public static final byte[] SysexJX8P_APN() {
        byte[] sysExStringAP = {(byte) (SYSTEM_EXCLUSIVE & 0xFF), 0x41, 0x35, 0x00, 0x21, 0x20, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,
            0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,
            0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,
            0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,
            0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, (byte) (ShortMessage.END_OF_EXCLUSIVE & 0xFF)};
        return sysExStringAP;
    }


}

【问题讨论】:

  • 这听起来像是您的 Java 虚拟机或操作系统中的错误,您都没有告诉我们。
  • 我完全忘了告诉你我正在使用 Windows 7 和 Mac OSX 10.11。 Sysex 通信在 OSX 上中断,因此此行为在 Windows 7 上进行了测试。
  • 哪个 Java 虚拟机?
  • JVM 版本 1.8.0_144

标签: java midi sysex


【解决方案1】:

jdk 8 和 jdk 13 都有类似的问题。 通过关闭和打开 sysex 传输周围的 MIDI 设备解决:

midiout.open();
midiout.getReceiver().send(outMsg, timeStamp);
midiout.close();

【讨论】:

  • 是否在 JVM 错误跟踪器中提及或已发布此行为或错误?
猜你喜欢
  • 2018-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多