2

I work on a MIDI-based project in Java and struggle to refresh the list of Midi Devices.

As far as i know MidiSystem.getMidiDeviceInfo(); should give me an Info[] Array. Nothing happens for me however. The Objects inside the Array stay the same when new devices are plugged in or out and so is it's length.

Searching Stackoverflow brought me to this 6 year old question. One of the comments suggests, that being on OSX/macOS might be the issue. I haven't tried my program on Windows or Linux yet, but it should work on OSX/macOS anyways.

Another comment suggests setting the cache time to something short with com.sun.media.sound.JDK13Services.setCachingPeriod(1); manually could fix this. Not on OSX/macOS however.

A further search on Google brought me to a openjdk bug report which claims that this is some bug on Apples side in OSX/macOS.

Below is a shortened version of my Devices class for verification, though i'm sure it should be correct.

private Info[] devices;

public Devices() {
    refreshDeviceList();
    printDeviceList();
}

// DeviceList Functions
public Info[] getDeviceList() {
    return devices;
}

public void printDeviceList() {
    for (int i = 0; i < devices.length; i++) {
        System.out.println("Description: \t" + devices[i].getDescription());
        System.out.println("Name: \t\t" + devices[i].getName());
        System.out.println("Vendor: \t" + devices[i].getVendor());
        System.out.println("Version: \t" + devices[i].getVersion());
        System.out.println();
    }
}

public void refreshDeviceList() {
    devices = MidiSystem.getMidiDeviceInfo();
}

// DeviceFunctions
public String getDeviceDescription(int i) {
    return devices[i].getDescription();
}

public String getDeviceName(int i) {
    return devices[i].getName();
}

public String getDeviceVendor(int i) {
    return devices[i].getVendor();
}

public String getDeviceVersion(int i) {
    return devices[i].getVersion();
}

Note, that calling refreshDevices() for the first time when creating a new Devices Object works and printing gets me a list of available devices. Just not afterwards. Restarting the program after plugging devices in or out returns the correct new number of devices however.

Can anyone provide a solution to this?

Community
  • 1
  • 1
gameshack_
  • 122
  • 9
  • I can't answer your direct question but the code snippet does appear to be correct and functional. I would personally recommend using a setter for `devices` and an enhanced for-loop in your `printDeviceList()` method that iterates over `Info[] devices`, instead of the `.length` way of doing things. But that's just personal preferences. – jseashell Dec 13 '16 at 14:38
  • just some off the cuff ideas since I cant test them in real life- one way is to set up a client server system that is two programs of which one can terminate; one checks - closes if needed- and transmits the data to the other – gpasch Dec 13 '16 at 19:54

3 Answers3

2

There is now a library, CoreMidi4J, that correctly supports hot-plugging (as well as a few other things) on macOS. I am not the author, but it appears to work well for my needs.

https://github.com/DerekCook/CoreMidi4J

Yona Appletree
  • 8,801
  • 6
  • 35
  • 52
  • Thanks a lot! This seems to be a viable solution. I'd upvote, but can't as i'm below the 15 Karma threshold. I'm still disappointed that Apple and Java Support both are pointing fingers at each other leaving me with a meh-ish solution for the longest time. – gameshack_ Jul 26 '18 at 11:30
0

One way is to set up a system as follows:

shell script:

start program with input 1 // that means it's the receiver

while(true) {
  start program with input 2 // that means it's the sender
  wait for an amount of time
}

end shell script

inside the program is the following:

    if code==1:
      while(true) {
      do whatever you have to do
      at specified point in time:
          read file "myfile"
          assemble the info
      }
      if code==2:
        read the device info
        write the info to "myfile"
        exit
gpasch
  • 2,672
  • 3
  • 10
  • 12
0

I found a solution which uses the JavaFX thread. For some reason this works at least on MacOSX. On a normal thread it doesn't work.

import fx.FX_Platform;
import javafx.embed.swing.JFXPanel;
import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiSystem;


public class miditest {
  
  
  static public void main( String[] args ) {
    // **** Just to init FX platform
    new JFXPanel();    
    new Thread( () -> {
      for( int ix=0; ix<1000; ix++ ) {
        try {
          Thread.sleep(2000);
        } catch( InterruptedException e ) {          
        }
        FX_Platform.runLater( () -> {
          MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo();
          System.out.println("FOUND: " + infos.length);
          for( MidiDevice.Info midiinfo : infos ) {
            System.out.println(midiinfo);
          }
        });
      }
    }).start();
    

  }
  
}
Waverick
  • 1,984
  • 1
  • 11
  • 16