Java发送MIDI音符至虚拟端口无响应问题排查
问题描述
我想用Java向虚拟MIDI端口发送中央C(音符编号60)的MIDI音符,编写了如下代码:
public static void main(String[] main) throws MidiUnavailableException, InvalidMidiDataException, InterruptedException { final MidiDevice.Info[] midiDeviceInfo = MidiSystem.getMidiDeviceInfo(); for (MidiDevice.Info info : midiDeviceInfo) { System.out.println(info.getName()); } MidiDevice.Info midiInfo = Arrays.stream(midiDeviceInfo) .filter(midiDefInfo -> main[0].equalsIgnoreCase(midiDefInfo.getName())) .findFirst().orElseThrow(); final MidiDevice midiDevice = MidiSystem.getMidiDevice(midiInfo); midiDevice.open(); Receiver receiver = midiDevice.getReceiver(); final ShortMessage messageOn = new ShortMessage(); final ShortMessage messageOff = new ShortMessage(); messageOn.setMessage(ShortMessage.NOTE_ON, 1, 60, 112); messageOff.setMessage(ShortMessage.NOTE_OFF, 1, 60, 0); receiver.send(messageOn, -1); Thread.sleep(1000L); receiver.send(messageOff, -1); }
在MacOS上通过MIDI Studio创建了名为'MyVirtualPort'的虚拟端口;在Windows上使用loopMidi工具创建虚拟端口。运行程序时,控制台输出可用设备列表:
Gervill Real Time Sequencer MyVirtualPort MyVirtualPort
运行情况:
- 传入参数“Gervill”时,可正常从扬声器听到1秒的中央C音符;
- 选择第二个“MyVirtualPort”时,抛出“MIDI IN不可用”异常;
- 选择第一个“MyVirtualPort”时,程序正常运行且看似发送了消息,但虚拟端口无任何活动反馈;
- Windows平台下也出现同样情况:程序运行正常但虚拟设备无响应,切换至默认设备则可正常发声。
作为MIDI新手,想知道遗漏了什么关键步骤?
解决思路与关键步骤
核心问题:虚拟MIDI端口的成对特性
虚拟MIDI端口会成对创建:一个是输出端口(MIDI OUT,用于发送消息),一个是输入端口(MIDI IN,用于接收消息)。你看到的两个"MyVirtualPort"就是这一对设备。
异常与无反馈的原因
- 选择第二个端口报错:第二个"MyVirtualPort"是输入端口,仅支持接收MIDI消息,无法调用
getReceiver()获取发送消息的接收器,因此抛出"MIDI IN不可用"异常。 - 选择第一个端口无反馈:第一个是输出端口,代码确实发送了MIDI消息,但输出端口需要连接到监听该端口的输入设备/程序才能看到反馈——你只是发送了消息,但没有任何程序在接收这个端口的输入,所以看不到活动。
关键修正步骤
区分设备类型:遍历MIDI设备时,增加类型判断,明确哪个是输出端口:
修改遍历代码如下:for (MidiDevice.Info info : midiDeviceInfo) { MidiDevice device = MidiSystem.getMidiDevice(info); System.out.printf("%s - 可发送消息(输出端口):%b,可接收消息(输入端口):%b%n", info.getName(), device.isReceiver(), device.isTransmitter()); }选择
可发送消息(输出端口)为true的那个"MyVirtualPort"。配对监听程序:
- MacOS:打开MIDI Studio,将"MyVirtualPort"的输出端口拖拽到另一个设备的输入端口上(比如自己的输入端口,或者DAW软件的MIDI输入);
- Windows:使用loopMidi创建端口后,打开支持MIDI输入的程序(比如MIDI监视器、FL Studio等),将该虚拟端口设置为程序的MIDI输入源,这样就能接收到你发送的MIDI消息。
补充资源关闭:程序结束前添加资源释放代码,避免资源泄漏:
receiver.close(); midiDevice.close();
内容的提问来源于stack exchange,提问作者Jos
相关产品推荐
相关产品推荐

