简体   繁体   English

Java sound api - 扫描midi设备

[英]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.我正在开发一个使用 javax.sound.midi 库从 midi 硬件接收 midi 事件的 java 项目。 In the documentation, it says that MidiSystem.getMidiDeviceInfo() returns a list of all connected midi hardware.在文档中,它说MidiSystem.getMidiDeviceInfo()返回所有连接的 midi 硬件的列表。 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.如果应用程序重新启动,它将重新扫描,但我不希望我的用户在连接新的 MIDI 设备时必须重新启动。

BTW, I'm using Mac OS X... it's been pointed out that behavior may be different for different OS's.顺便说一句,我使用的是 Mac OS X……有人指出,不同操作系统的行为可能会有所不同。

The MidiSystem.getMidiDeviceInfo() gets the full providers list, and extracts the info of the device from each provider. MidiSystem.getMidiDeviceInfo()获取完整的提供者列表,并从每个提供者中提取设备信息。

The MIDIs provider list is recovered from the JDK underlaying class com.sun.media.sound.JDK13Services , through the static method getProviders() MIDIs 提供者列表通过静态方法getProviders()从 JDK 底层类com.sun.media.sound.JDK13Services 中恢复

public static synchronized List getProviders(Class serviceClass) Obtains a List containing installed instances of the providers for the requested service. public static synchronized List getProviders(Class serviceClass)获取一个包含所请求服务的提供者的已安装实例的列表。 The List of providers is cached for the period of time given by cachingPeriod .提供者列表在 cachingPeriod 给定的时间段内缓存。 During this period, the same List instance is returned for the same type of provider.在此期间,为相同类型的提供程序返回相同的 List 实例。 After this period, a new instance is constructed and returned.在此期间之后,将构造并返回一个新实例。 The returned List is immutable.返回的 List 是不可变的。

So, it seems that this class holds thee Providers list in a cache, wich will be reloaded after a certain period.所以,这个类似乎在缓存中保存了 Providers 列表,它会在一段时间后重新加载。 You can set this period to a custom value using the method setCachingPeriod(int seconds) .您可以使用setCachingPeriod(int seconds)方法将此时间段设置为自定义值。 As long as I know, the default caching period is set to 60 seconds.据我所知,默认缓存时间设置为 60 秒。

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.请注意,此解决方案使用了 Sun 专有类,因此它不可能是 100% 可移植的。

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

The MidiSystem class seems to use com.sun.media.sound.JDK13Services.getProviders(Class providerClass) to find the list of devices on the system. MidiSystem 类似乎使用com.sun.media.sound.JDK13Services.getProviders(Class providerClass)来查找系统上的设备列表。 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) . 此类API 文档说明列表是在cachingPeriod之外的连续调用中重新创建的,可以通过调用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.运气好的话,您可以在应用程序开始时调用它一次并将其设置为 5 秒或其他时间,它会神奇地工作。 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我回答这也是Java 中 Midi 设备的更新列表,但是对于在这里结束的人来说,现在有一个正确支持此功能的库: 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.该库充当 MIDI 子系统的设备提供者,因此它基本上是一个插件,您现有的所有代码都可以使用。

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.我找到了一个使用 JavaFX 线程的解决方案。 For some reason this works at least on MacOSX.出于某种原因,这至少适用于 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.在 Java 中,您可以向操作系统运行外部命令。 (A quick google, gave me this example http://www.javafaq.nu/java-example-code-186.html it looks OK and gives you the idea). (一个快速的谷歌,给了我这个例子http://www.javafaq.nu/java-example-code-186.html它看起来不错,给了你这个想法)。

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

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.还要记住,用于查询 MIDI 设备的外部程序不必用 Java 编写,以防 Java 会给您带来更多问题。 Alternatively you could just query the OS for connected devices and use grep to filter the results.或者,您可以查询已连接设备的操作系统并使用 grep 过滤结果。

Hope this helps.希望这会有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM