Java midi SysEx消息,流卡住,可能的bug?

时间:2017-07-30 19:59:30

标签: java midi sysex

当我一个接一个地以不同的字节长度实时发送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;
    }


}

1 个答案:

答案 0 :(得分:2)

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

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