登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  java教程

Java MidiSystem 怎样枚举可用的 MIDI 设备

来源:17golang原创

时间:2026-10-30 16:34:37 172浏览 收藏

我第一次写 Java MIDI 设备选择时,容易把“设备信息”与“设备实例”混为一谈。实际的枚举入口很简单:先调用 MidiSystem.getMidiDeviceInfo() 得到 MidiDevice.Info[],把每个信息对象展示给用户;确定目标后,再把它交给 MidiSystem.getMidiDevice(info)。这样既能先统计候选数量,也能在真正需要时再判断设备能力。

官方资料:https://docs.oracle.com/en/java/javase/25/docs/api/java.desktop/javax/sound/midi/MidiSystem.html

枚举 MIDI 设备不是直接遍历 MidiDevice 实例,而是先遍历 MidiDevice.Info 目录。返回数组长度为 0 时,表示当前 Java MIDI 系统没有可见设备;拿到信息对象后,才用 getMidiDevice 定位具体设备。

先把候选数量和设备信息分开

这篇文章采用三个可观察基线:候选设备数量、四项元数据是否完整、设备能提供的接收器与发送器上限。它们是 API 字段,不是我在某台机器上测出的固定结果,因此不会把“有几个设备”写成所有环境都一样的结论。

import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiSystem;

public class MidiDeviceCatalog {
    public static void main(String[] args) {
        // 先取得信息目录,不在枚举阶段打开任何设备。
        MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo();
        if (infos.length == 0) {
            // 空数组是环境结果,不能简单当作 API 调用失败。
            System.out.println("没有发现可用的 MIDI 设备");
            return;
        }

        // 每个 Info 代表一个可供 MidiSystem 定位的设备条目。
        for (int index = 0; index < infos.length; index++) {
            MidiDevice.Info info = infos[index];
            System.out.printf("[%d] %s%n", index, info.getName());
        }
    }
}
Java MidiSystem 枚举入口与 MidiDevice.Info 设备元数据的静态关系说明图
图1:静态说明图,查看 Java MIDI 枚举入口与设备元数据之间的关系。

这里的关键判断是 infos.length。如果它为零,应先检查操作系统是否安装了 MIDI 设备、驱动是否可用以及当前 Java 运行环境能否看到对应设备,而不是继续对空数组取下标。

读取 Info 的四项元数据

MidiDevice.Info 的职责是描述设备。名称适合做列表主标题,厂商便于区分同名设备,版本和描述用于辅助选择。把这些字段一并展示,往往比只打印一个名称更容易定位“选错设备”的问题。

for (MidiDevice.Info info : infos) {
    // 这些字段来自设备信息对象,不代表设备已经打开。
    String name = info.getName();
    String vendor = info.getVendor();
    String version = info.getVersion();
    String description = info.getDescription();

    // 组合成可记录的目录行,便于后续让用户选择。
    System.out.printf("%s | %s | %s | %s%n",
            name, vendor, version, description);
}

如果应用要保存用户选择,建议保存稳定的业务标识或让用户在启动时重新确认,而不要只依赖数组下标。设备插拔、驱动变化都可能让枚举顺序发生变化。

从 Info 定位 MidiDevice,再看能力

选择某条目录记录后,再调用 MidiSystem.getMidiDevice(info)。此时得到的是 MidiDevice 实例,可以读取设备信息和能力上限。正如第二张图所示,信息对象承担定位职责,设备实例承担能力查询职责,两者不是同一个层次。

import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiUnavailableException;

static void printCapabilities(MidiDevice.Info info) {
    try {
        // 用用户选中的 Info 定位设备实例;资源不足时会抛出异常。
        MidiDevice device = MidiSystem.getMidiDevice(info);

        // -1 通常表示没有固定上限,不能当成“支持 -1 个”。
        System.out.printf("%s: receivers=%d, transmitters=%d%n",
                device.getDeviceInfo().getName(),
                device.getMaxReceivers(),
                device.getMaxTransmitters());
    } catch (MidiUnavailableException ex) {
        // 设备条目存在不等于此刻一定能取得设备资源。
        System.err.println("设备当前不可用:" + ex.getMessage());
    }
}
MidiDevice.Info 定位 MidiDevice 并连接能力查询与异常边界的静态关系说明图
图2:静态说明图,查看设备信息对象、设备实例与能力边界的关系。

这里不要把 getMaxReceivers() 或 getMaxTransmitters() 当成当前已占用数量;它们描述设备支持的最大连接能力,具体语义要以 MidiDevice 的接口约定为准。拿到实例后,如果后续调用会打开设备或取得接收器、发送器,还要设计对应的关闭责任。

三个边界决定枚举是否可用

我会把结果分成三种状态记录:第一,信息数组为空,说明当前环境没有可见候选;第二,信息对象存在但 getMidiDevice 抛出 MidiUnavailableException,说明设备资源在此刻不可取得;第三,设备存在但接收器或发送器能力不符合业务要求,此时应回到候选清单换设备,而不是把异常吞掉。

现象判断处理建议
infos.length == 0没有可见设备检查设备、驱动和运行环境
定位时抛出 MidiUnavailableException设备暂时不可取得记录原因并允许重试或换设备
能力上限不满足候选与业务不匹配按接收器/发送器要求重新筛选

因此,最小可靠流程就是“先枚举信息、再显示元数据、最后定位实例”。如果只是做设备选择页面,停在 MidiDevice.Info 层就够了;只有需要连接 MIDI 数据流时,才继续管理 MidiDevice 的打开和关闭。

相关问题

为什么不直接保存 MidiDevice 对象?

设备实例与资源状态有关,插拔或占用变化后可能失效。保存信息用于重新定位更适合启动时的设备选择。

为什么枚举结果为空却没有异常?

getMidiDeviceInfo() 返回空数组是“没有安装或没有被当前环境识别的设备”,与调用本身抛出资源异常是两种情况。

什么时候才需要打开设备?

仅展示设备目录时不需要打开;要取得接收器、发送器或进行实际 MIDI 通信时,再按生命周期打开并关闭相关资源。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>