Search code examples
javamidijavax.sound.midi

Receiving com.sun.media.sound.FastShortMessage from MIDI Controller in Java, how to decode?


I have a java program set up that takes MIDI input from a controller and ideally does different things (not necessarily related to playing synthesizer output) depending on which midi note is sent.

My code is heavily based on the code in this SO question: Java getting input from MIDI keyboard, specifically I'm using the entire MidiInputReceiver class. I've modified it to do System.out.println(msg) as well as printing "MIDI received, and it appears to work in as far as every time I press a key from my controller it detects the MIDI and prints the midi msg, but I don't know how to decode the output into something I can decipher, if that's even possible.

The output i'm getting is:

midi received
com.sun.media.sound.FastShortMessage@75b0e2c3
midi received
com.sun.media.sound.FastShortMessage@2ff7ac92
midi received
com.sun.media.sound.FastShortMessage@2d62bdd8
midi received
com.sun.media.sound.FastShortMessage@2d9dc72f

I've been trying to use this Java class http://www.jsresources.org/examples/DumpReceiver.java.html to decode the message, but it only decodes ShortMessages, not FastShortMessages, and I can't find any documentation online about what a FastShortMessage is, much less how to convert from an FSM to an SM. Does anybody have any ideas? Is there an easier way than what I'm doing?

Edit: This might not be the best way, but I just came up with a way that works, I can't answer my own post for 8 hours but I'll post it here in case anybody else needs it.

I just managed to solve my own problem, with the code below.

public void send(MidiMessage msg, long timeStamp) {
    // Print to confirm signal arrival
    System.out.println("midi received");

    byte[] aMsg = msg.getMessage();
    // take the MidiMessage msg and store it in a byte array

    // msg.getLength() returns the length of the message in bytes
    for(int i=0;i<msg.getLength();i++){
        System.out.println(aMsg[i]);
        // aMsg[0] is something, velocity maybe? Not 100% sure.
        // aMsg[1] is the note value as an int. This is the important one.
        // aMsg[2] is pressed or not (0/100), it sends 100 when they key goes down,  
        // and 0 when the key is back up again. With a better keyboard it could maybe
        // send continuous values between then for how quickly it's pressed? 
        // I'm only using VMPK for testing on the go, so it's either 
        // clicked or not.
    }
    System.out.println();
}

Sample output for two keys pressed:

midi received 
-103
71
100

midi received
-119
71
0

midi received
-103
52
100

midi received
-119
52
0

So aMsg[1] holds the Midi number for each note, which can be referenced anywhere online, I can't post a link due to rep.

The getMessage() and getLength() methods come from http://docs.oracle.com/javase/7/docs/api/javax/sound/midi/MidiMessage.html, I still haven't figured out what a FastShortMessage is, but it might just be leftover legacy code or something? It's com.sun stuff so it's got to be pretty old.

From here I can do a switch() statement on the aMsg[1] with a different case depending on which key is pressed, which is exactly what I was aiming to do, which will be backwards compatible to 1.6 since it's an integer.


Solution

  • FastShortMessage is (indirectly) derived from MidiMessage; just handle it like one.

    When you have a ShortMessage, you should use the getCommand/getChannel/getData1/2 functions, which are easier to use than a temporary byte array.