开发者

Java sound api - Scanning for midi devices

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 开发者_如何学COS's.


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.


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.


I answered this is Update list of Midi Devices in Java as well, but for folks who wind up here, there's now a library that supports this correctly: https://github.com/DerekCook/CoreMidi4J

The library acts a device provider for the MIDI Subsystem, so it's basically a drop-in and all your existing code will work.

I am not the author, but it works well for my needs, and it took a fair bit of searching to find, so I'm posting it here for others who encounter the problem.


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();
    

  }
  
}


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜