Java sound api - 扫描midi设备

时间:2010-09-20 14:21:37

标签: java audio midi midi-instrument

我正在开发一个java项目,它使用javax.sound.midi库从midi硬件接收midi事件。在文档中,它说MidiSystem.getMidiDeviceInfo()返回所有连接的midi硬件的列表。它适用于我,但问题是,它只能工作一次。第一次实际扫描设备需要花费一些时间,但每次在此之后,即使已连接新设备,它也会立即返回相同的列表。有没有办法强迫它重新扫描?如果重新启动应用程序,它将重新扫描,但我不希望我的用户在连接新的midi设备时必须重新启动。

顺便说一下,我正在使用Mac OS X ......有人指出不同操作系统的行为可能会有所不同。

5 个答案:

答案 0 :(得分:7)

MidiSystem.getMidiDeviceInfo()获取完整的提供者列表,并从每个提供者中提取设备的信息。

通过静态方法getProviders()

从JDK底层类com.sun.media.sound.JDK13Services恢复MIDI提供程序列表
  

public static synchronized List getProviders(Class serviceClass)   获得包含已安装的List   提供者的实例   要求的服务。清单   提供程序缓存期间   时间由cachingPeriod给出。中   这个时期,同一个List实例是   返回相同类型的   供应商。在此期间,一个新的   构造并返回实例。   返回的List是不可变的。

因此,似乎这个类在缓存中保存了提供者列表,在一段时间后将重新加载。您可以使用方法setCachingPeriod(int seconds)将此期间设置为自定义值。只要我知道,默认缓存时间设置为60秒。

例如,要每秒刷新此缓存,您可以将此行添加到您的代码中:

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

请注意,此解决方案使用Sun专属类,因此无法100%移植。

答案 1 :(得分:3)

在我的工作PC或任何类型的Mac上缺少任何MIDI设备,我怀疑我是否能够正确测试它,但是...

MidiSystem类似乎使用com.sun.media.sound.JDK13Services.getProviders(Class providerClass)来查找系统上的设备列表。 API docs for this class表示在cachingPeriod之外的连续调用中重新创建列表,可以通过调用setCachingPeriod(int seconds)方便地设置。

运气好的话,你可以在应用程序开始时调用它一次,并将其设置为5秒或者其他东西,它会神奇地起作用。但是,文档还声明“此方法仅用于测试。”因此我不确定这种方法的效果如何。

希望这足以让你开始,在此期间我会继续探索,看看我是否能找到更清洁的方法来做到这一点。

答案 2 :(得分:0)

我也回答了Update list of Midi Devices in Java,但是对于那些热衷于此的人们来说,现在有一个可以正确支持此功能的图书馆:https://github.com/DerekCook/CoreMidi4J

该库充当MIDI子系统的设备提供者,因此它基本上是一个插件,您所有现有的代码都可以使用。

我不是作者,但是它可以很好地满足我的需求,并且经过大量的搜索才能找到,因此我将其发布在这里,供其他遇到此问题的人使用。

答案 3 :(得分:0)

我找到了一个使用 JavaFX 线程的解决方案。出于某种原因,这至少适用于 MacOSX。在普通线程上它不起作用。

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

  }
  
}

答案 4 :(得分:-1)

听起来这可能是一个操作系统特定的bug,但我可以想到一个解决方法。

在java中,您可以对操作系统运行外部命令。 (一个快速的谷歌,给了我这个例子http://www.javafaq.nu/java-example-code-186.html它看起来很好,并给你的想法)。

在检查新设备时,您可以发送外部命令来运行一个简单的java程序,该程序使用MidiSystem.getMidiDeviceInfo()快速查询midi设备并将结果输出到文本文件,或者您可以从BufferedReader对象获取输出

还要记住,用于查询midi设备的外部程序不必用Java编写,因为Java会导致更多问题。或者,您可以只查询连接设备的操作系统,并使用grep过滤结果。

希望这有帮助。