更新 Java 中的 Midi 设备列表

Update list of Midi Devices in Java

我在 Java 从事一个基于 MIDI 的项目,并且努力刷新 Midi 设备列表。

据我所知 MidiSystem.getMidiDeviceInfo(); 应该给我一个 Info[] 数组。然而,我什么也没发生。插入或拔出新设备时,阵列内的对象保持不变,长度也保持不变。

搜索 Whosebug 将我带到 this 6 year old question。其中一条评论表明,在 OSX/macOS 上可能是问题所在。我还没有在 Windows 或 Linux 上尝试我的程序,但无论如何它应该可以在 OSX/macOS 上运行。

另一条评论建议通过 com.sun.media.sound.JDK13Services.setCachingPeriod(1); 手动将缓存时间设置为较短的时间可以解决此问题。但是,不在 OSX/macOS 上。

对 Google 的进一步搜索将我带到 openjdk bug report,它声称这是 OSX/macOS.

中 Apple 方面的一些错误

下面是我的 Devices class 的简化版本以供验证,但我确信它应该是正确的。

private Info[] devices;

public Devices() {
    refreshDeviceList();
    printDeviceList();
}

// DeviceList Functions
public Info[] getDeviceList() {
    return devices;
}

public void printDeviceList() {
    for (int i = 0; i < devices.length; i++) {
        System.out.println("Description: \t" + devices[i].getDescription());
        System.out.println("Name: \t\t" + devices[i].getName());
        System.out.println("Vendor: \t" + devices[i].getVendor());
        System.out.println("Version: \t" + devices[i].getVersion());
        System.out.println();
    }
}

public void refreshDeviceList() {
    devices = MidiSystem.getMidiDeviceInfo();
}

// DeviceFunctions
public String getDeviceDescription(int i) {
    return devices[i].getDescription();
}

public String getDeviceName(int i) {
    return devices[i].getName();
}

public String getDeviceVendor(int i) {
    return devices[i].getVendor();
}

public String getDeviceVersion(int i) {
    return devices[i].getVersion();
}

请注意,在创建新的 Devices 对象时第一次调用 refreshDevices() 可以正常打印并获得可用设备列表。只是不是之后。插入或拔出设备后重新启动程序 returns 但是正确的新设备数量。

任何人都可以提供解决方案吗?

一种方法是按如下方式设置系统:

shell script:

start program with input 1 // that means it's the receiver

while(true) {
  start program with input 2 // that means it's the sender
  wait for an amount of time
}

end shell script

inside the program is the following:

    if code==1:
      while(true) {
      do whatever you have to do
      at specified point in time:
          read file "myfile"
          assemble the info
      }
      if code==2:
        read the device info
        write the info to "myfile"
        exit

现在有一个库 CoreMidi4J,可以正确支持 macOS 上的热插拔(以及其他一些功能)。我不是作者,但它似乎很适合我的需要。

https://github.com/DerekCook/CoreMidi4J

我找到了一个使用 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();
    

  }
  
}