Java sound api – 扫描midi设备

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

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

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

通过静态方法getProviders()从JDK底层类com.sun.media.sound.JDK13Services恢复MIDI提供程序列表

public static synchronized List getProviders(Class serviceClass)获得一个List,其中包含所请求服务的已提供的提供程序实例。 提供者列表在cachingPeriod给出的时间段内缓存。 在此期间,将为同一类型的提供程序返回相同的List实例。 在此期间之后,构造并返回新实例。 返回的List是不可变的。

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

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

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

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

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

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

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

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

我回答这是Java中Midi设备的更新列表 ,但对于那些结束这里的人来说,现在有一个正确支持它的库: https : //github.com/DerekCook/CoreMidi4J

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

我不是作者,但它可以很好地满足我的需求,并且需要花费一些时间进行搜索才能找到,所以我将其发布在此处供其他遇到问题的人使用。

这听起来像是一个操作系统特定的bug,但我可以想到一个绕过。

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

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

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

希望这可以帮助。