文档

Java™教程
隐藏目录
访问MIDI系统资源
路径:音频

访问MIDI系统资源

Java Sound API提供了一个灵活的模型,用于MIDI系统配置,就像对采样音频系统的配置一样。Java Sound API的实现本身可以提供不同类型的MIDI设备,而且还可以通过服务提供者提供额外的设备,并由用户安装。您可以以这样的方式编写程序,使其对计算机上安装的特定MIDI设备做出很少的假设。相反,程序可以利用MIDI系统的默认设置,或者允许用户从当前可用的设备中进行选择。

本节展示了您的程序如何了解已安装的MIDI资源,以及如何访问所需的资源。在访问和打开设备之后,您可以将它们连接在一起,如后面在传输和接收MIDI消息中所讨论的。

MidiSystem类

Java Sound API的MIDI包中的MidiSystem类的作用与采样音频包中的AudioSystem类直接类似。 MidiSystem充当访问已安装MIDI资源的中转站。

您可以查询MidiSystem以了解安装了哪些类型的设备,然后可以遍历可用设备并获得对所需设备的访问权限。例如,应用程序可以首先询问MidiSystem有哪些合成器可用,然后显示一个列表供用户选择。一个更简单的应用程序可能只使用系统的默认合成器。

MidiSystem类还提供了在MIDI文件和Sequences之间进行转换的方法。它可以报告MIDI文件的文件格式,并可以写入不同类型的文件。

应用程序可以从MidiSystem获取以下资源:

本页面重点介绍了这四种类型的资源。其他类型的资源将在本教程的后面讨论。

获取默认设备

使用Java Sound API的典型MIDI应用程序首先通过获取所需的设备(可能包括一个或多个序列器、合成器、输入端口或输出端口)来开始。

有一个默认的合成器设备、默认的序列器设备、默认的发送设备和默认的接收设备。后两个设备通常代表系统上可用的MIDI输入和输出端口。(在这里很容易混淆方向性。将端口的传输或接收与软件有关,而不是与连接到物理端口的任何外部物理设备有关。一个MIDI输入端口将数据从外部设备传输到Java Sound API的接收器,同样,一个MIDI输出端口从一个软件对象接收数据并将数据中继给外部设备。)

一个简单的应用程序可能只使用默认值而不探索所有已安装的设备。MidiSystem类包括以下方法用于检索默认资源:

static Sequencer getSequencer()
static Synthesizer getSynthesizer()
static Receiver getReceiver()
static Transmitter getTransmitter()

这些方法中的前两个方法获取系统的默认序列和合成资源,它们可以代表物理设备或完全在软件中实现。getReceiver方法获取一个接收器对象,它接收发送到它的MIDI消息并将它们传递给默认的接收设备。类似地,getTransmitter方法获取一个传输器对象,它可以代表默认的发送设备向某个接收器发送MIDI消息。

了解安装的设备

与使用默认设备不同,更彻底的方法是从安装在系统上的所有设备中选择所需的设备。应用程序可以以编程方式选择所需的设备,也可以显示一个可用设备列表,并让用户选择要使用的设备。MidiSystem类提供了一个方法来了解安装了哪些设备,并提供了一个相应的方法来获取给定类型的设备。

这是用于了解安装的设备的方法:

static MidiDevice.Info[] getMidiDeviceInfo()

如你所见,它返回一个信息对象的数组。这些返回的MidiDevice.Info对象中的每一个都标识了一种安装的序列器、合成器、端口或其他设备类型。(通常一个系统最多只有一个给定类型的实例。例如,一个特定厂商的合成器型号只会安装一次。)MidiDevice.Info包括以下字符串来描述设备:

您可以在用户界面中显示这些字符串,以让用户从设备列表中进行选择。

然而,要在编程中使用这些字符串来选择设备(而不是向用户显示字符串),您需要事先知道可能的选择。每个提供设备的公司应该在其文档中包含此信息。需要或优先选择特定设备的应用程序可以使用此信息来定位该设备。这种方法的缺点是将程序限制为事先已知的设备实现。

另一种更通用的方法是继续遍历MidiDevice.Info对象,获取每个相应的设备,并在程序中确定其是否适合使用(或至少适合包含在用户可以选择的列表中)。下一节描述了如何实现此操作。

获取所需的设备

一旦找到适当的设备信息对象,应用程序可以调用以下MidiSystem方法来获取相应的设备本身:

static MidiDevice getMidiDevice(MidiDevice.Info info)

如果您已经找到描述所需设备的信息对象,则可以使用此方法。但是,如果您无法解释getMidiDeviceInfo返回的信息对象以确定您需要的设备,且不想向用户显示所有设备的信息,则可以尝试以下操作:遍历getMidiDeviceInfo返回的所有MidiDevice.Info对象,使用上述方法获取相应的设备,并测试每个设备以查看其是否适合。换句话说,您可以在将设备包含在显示给用户的列表中之前,查询每个设备的类和功能,或者作为在不涉及用户的情况下以编程方式决定设备的一种方式。例如,如果您的程序需要一个合成器,您可以获取所有已安装的设备,查看哪些是实现了Synthesizer接口的类的实例,然后将它们显示在用户可以选择的列表中,如下所示:

// 获取所有已安装合成器的信息。
Vector synthInfos;
MidiDevice device;
MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo();
for (int i = 0; i < infos.length; i++) {
    try {
        device = MidiSystem.getMidiDevice(infos[i]);
    } catch (MidiUnavailableException e) {
          // 处理或抛出异常...
    }
    if (device instanceof Synthesizer) {
        synthInfos.add(infos[i]);
    }
}
// 现在,在GUI中显示synthInfos列表中的字符串。    

作为另一个示例,您可以以编程方式选择设备,而不涉及用户。假设您想要获取能够同时播放最多音符的合成器。您可以按照上述方式遍历所有的MidiDevice.Info对象,但在确定设备为合成器后,通过调用SynthesizergetMaxPolyphony方法查询其功能。您可以保留具有最大多音性的合成器,如下一节所述。即使您不要求用户选择合成器,您可能仍然会显示所选MidiDevice.Info对象的字符串,以供用户参考。

打开设备

上一节介绍了如何获取已安装的设备。然而,设备可能已安装但不可用。例如,另一个应用程序可能独占使用它。要为您的程序实际保留设备,您需要使用MidiDeviceopen方法:

if (!(device.isOpen())) {
    try {
      device.open();
  } catch (MidiUnavailableException e) {
          // 处理或抛出异常...
  }
}

一旦您访问并打开了设备,您可能希望将其连接到一个或多个其他设备,以便让MIDI数据在它们之间流动。这个过程将在后面的传输和接收MIDI消息中描述。

使用完设备后,通过调用MidiDeviceclose方法释放它,以供其他程序使用。


上一页: MIDI包概述
下一页: 传输和接收MIDI消息