views:

131

answers:

3

I'm working on a java project that receives midi events from midi hardware using the javax.sound.midi library. In the documentation, it says that MidiSystem.getMidiDeviceInfo() returns a list of all connected midi hardware. It works for me, but the problem is, it only works once. It takes a moment the first time to actually scan for the devices, but each time after that it will immediately return that same list even if new devices have been connected. Is there a way to force it to rescan? It will rescan if the application is restarted, but I don't want my users to have to restart if they connect a new midi device.

BTW, I'm using Mac OS X... it's been pointed out that behavior may be different for different OS's.

A: 

This sounds like is could be an OS specifx bug but I can think of a get around.

In java you can run external commands to the OS. (A quick google, gave me this example http://www.javafaq.nu/java-example-code-186.html it looks OK and gives you the idea).

On checking for new devices you could send an external command to run a simple java program that quickly queries the midi devices using MidiSystem.getMidiDeviceInfo() and outputs the results to a text file or you could grab the output from the BufferedReader object.

Also remember that the external program used to query midi devices doesn't have to be written in Java incase Java causes you more problems. Alternatively you could just query the OS for connected devices and use grep to filter the results.

Hope this helps.

Graham
I need java to actually be able to connect to the devices. I can only connect to them from the results of MidiSystem.getMidiDeviceInfo().
tybro0103
This is still possible if you make the returned object/s serializable. I would suggest using something else than Java if you wish to continually call and use more low level OS info, its not the best language to use for this. Especially considering that Macs and Java dont always get along. Have you tried this on a different OS yet?
Graham
I haven't tried on another OS. I need it to work on OS X and in Java.
tybro0103
Have you tried the serialization technique, that should do the trick.
Graham
+1  A: 

Lacking any MIDI devices on my work PC, or indeed any kind of Mac, I doubt I'll be able to test it properly, but...

The MidiSystem class seems to use com.sun.media.sound.JDK13Services.getProviders(Class providerClass) to find the list of devices on the system. The API docs for this class state that the list is recreated on a successive call outside of a cachingPeriod, which can be conveniently set by calling setCachingPeriod(int seconds).

With any luck you can just call this once at the start of your application and set it to 5 seconds or something, and it'll magically work. However, the docs also state "This method is only intended for testing.", so I'm not sure quite how effective this approach will be.

Hopefully this is enough to get you started, and I'll keep poking around in the meantime to see if I can find a cleaner way to do this.

Zetten
+1: we've reached very similar conclusions
Tomas Narros
So we did, at just about exactly the same time :)
Zetten
+4  A: 

The MidiSystem.getMidiDeviceInfo() gets the full providers list, and extracts the info of the device from each provider.

The MIDIs provider list is recovered from the JDK underlaying class com.sun.media.sound.JDK13Services, through the static method getProviders()

public static synchronized List getProviders(Class serviceClass) Obtains a List containing installed instances of the providers for the requested service. The List of providers is cached for the period of time given by cachingPeriod . During this period, the same List instance is returned for the same type of provider. After this period, a new instance is constructed and returned. The returned List is immutable.

So, it seems that this class holds thee Providers list in a cache, wich will be reloaded after a certain period. You can set this period to a custom value using the method setCachingPeriod(int seconds). As long as I know, the default caching period is set to 60 seconds.

As an example, to refresh this cache every second, you coud add this line to your code:

com.sun.media.sound.JDK13Services.setCachingPeriod(1);

Please, note that this solution makes use of a Sun propietary class, so it could not be 100% portable.

Tomas Narros