使用高级音序器功能

到目前为止,我们已经专注于 MIDI 数据的简单播放和记录。本节将简要描述通过Sequencerinterface和Sequence类的方法提供的一些更高级的功能。

移至序列中的任意位置

有两种Sequencer方法可获取定序器在序列中的当前位置。第一个:

long getTickPosition()

返回从序列开始处以 MIDI 节拍测量的位置。第二种方法:

long getMicrosecondPosition()

返回当前位置(以微秒为单位)。此方法假定序列以 MIDI 文件或Sequence中存储的默认速率播放。如果您按照以下说明更改了播放速度,它不会返回其他值。

您可以根据一个或另一个单位类似地设置音序器的当前位置:

void setTickPosition(long tick)

or

void setMicrosecondPosition(long microsecond)

更改播放速度

如前所述,序列的速度由其速度表示,该速度会随着序列的变化而变化。序列可以包含封装标准 MIDI 速度改变消息的事件。当音序器处理此类事件时,它会更改播放速度以反映所指示的速度。此外,您可以通过调用以下Sequencer方法之一来以编程方式更改速度:

public void setTempoInBPM(float bpm)
    public void setTempoInMPQ(float mpq)
    public void setTempoFactor(float factor)

这些方法中的前两种分别以每分钟节拍或每四分音符微秒为单位设置节奏。速度将保持在指定值,直到再次调用这些方法之一,或者直到序列中遇到速度变化事件为止,此时新的指定速度将覆盖当前速度。

第三种方法setTempoFactor本质上有所不同。它可以缩放为定序器设置的任何速度(无论是通过速度变化事件还是通过上述前两种方法之一)。默认标量为 1.0(不变)。尽管此方法使播放或录制的速度快于或慢于标称速度(除非系数为 1.0),但它不会改变标称速度。换句话说,getTempoInBPMgetTempoInMPQ返回的速度值不受速度因子的影响,即使速度因子确实会影响实际的播放或录制速率。同样,如果通过速度变化事件或前两种方法之一来改变速度,它仍然会根据上次设置的速度因子进行缩放。但是,如果加载新序列,则速度因子会重置为 1.0.

请注意,当序列的分割类型是 SMPTE 类型之一而不是 PPQ 时,所有这些速度变化指令均无效。

序列中的单个音轨静音或独奏

音序器的用户通常可以方便地关闭某些音轨,以更清楚地听到音乐中正在发生的事情。功能齐全的音序器程序使用户可以选择在播放过程中应该播放哪些音轨。 (更准确地说,由于音序器实际上并不自己创建声音,因此用户选择哪些音轨将对音序器产生的 MIDI 消息流作出贡献.)通常,每个音轨上有两种图形控件:静音按钮和* solo *按钮。如果启用了静音按钮,则在禁用静音按钮之前,在任何情况下该音轨都不会发出声音。独奏是鲜为人知的功能。大致与静音相反。如果任何轨道上的独奏按钮被激活,则仅激活了独奏按钮的轨道会发出声音。此功能使用户可以快速试听少量轨道,而不必使所有其他轨道静音。静音按钮通常比独奏按钮优先:如果两个按钮均被激活,则不会发出声音。

使用Sequencer方法,可以轻松地使轨道静音或独奏(以及查询轨道的当前静音或独奏状态)。假设我们已经获得了默认的Sequencer,并且已经将序列数据加载到其中。将序列中的第五条音轨静音可以如下完成:

sequencer.setTrackMute(4, true);
    boolean muted = sequencer.getTrackMute(4);
    if (!muted) { 
        return;         // muting failed
    }

关于上述代码段,需要注意几件事。首先,序列的轨道编号从 0 开始,以轨道总数减去 1 结束。而且,setTrackMute的第二个参数是布尔值。如果为真,则请求将轨道静音;否则,请求取消静音指定的轨道。最后,为了测试静音是否生效,我们调用Sequencer getTrackMute方法,并向其传递正在查询的曲目号。如果它返回true,如我们在这种情况下所期望的,则静音请求有效。如果返回false,则失败。

静音请求可能由于各种原因而失败。例如,在setTrackMute调用中指定的轨道号可能超过轨道总数,或者音序器可能不支持静音。通过调用getTrackMute,我们可以确定请求是成功还是失败。

顺便说一句,由getTrackMute返回的布尔值确实可以告诉我们是否发生了故障,但无法告诉我们为什么发生。我们可以测试一下是否由于将无效的轨道号传递给setTrackMute方法而导致失败。为此,我们将调用SequencegetTracks方法,该方法将返回一个包含序列中所有轨道的数组。如果在setTrackMute调用中指定的轨道号超过了此数组的 Long 度,那么我们知道我们指定了无效的轨道号。

如果静音请求成功,则在我们的示例中,在播放序列时,第五音轨将不会发出声音,而当前已静音的任何其他音轨也不会发出声音。

独奏曲 Object 方法和技术与静音的方法和技术非常相似。要独奏曲目,请调用Sequence:setTrackSolo方法

void setTrackSolo(int track, boolean bSolo)

setTrackMute一样,第一个参数指定从零开始的音轨号,第二个参数如果为true则指定音轨应处于独奏 Pattern;否则,曲目不应独奏。

默认情况下,曲目既不会静音也不会单独播放。

与其他 MIDI 设备同步

Sequencer具有一个名为Sequencer.SyncMode的内部类。 SyncMode对象表示 MIDI 音序器的时间概念可以与主设备或从设备同步的方式之一。如果音序器正在与主机同步,则音序器会响应于来自主机的某些 MIDI 消息修改其当前时间。如果音序器具有从机,则音序器会类似地发送 MIDI 消息以控制从机的定时。

共有三种 预定义 Pattern,它们为定序器指定可能的母版:INTERNAL_CLOCKMIDI_SYNCMIDI_TIME_CODE。如果音序器从另一台设备接收 MIDI 消息,则后两者可以工作。在这两种 Pattern 下,分别基于系统实时定时时钟消息或 MIDI 时间代码(MTC)消息重置音序器的时间。 (有关这些消息类型的更多信息,请参见 MIDI 规范.)这两种 Pattern 也可以用作从属 Pattern,在这种情况下,音序器会将相应类型的 MIDI 消息发送到其接收器。第四种 PatternNO_SYNC用于指示定序器不应向其接收器发送定时信息。

通过使用支持的SyncMode对象作为参数调用setMasterSyncMode方法,可以指定如何控制音序器的时序。同样,setSlaveSyncMode方法确定定序器将向其接收器发送哪些定时信息。此信息控制使用定序器作为主时序源的设备的时序。

指定特殊事件侦听器

序列的每个轨道可以包含许多不同的MidiEvents。这样的事件包括 Note On 和 Note Off 消息,程序更改,控件更改和元事件。 Java Sound API 为这些事件类型的后两种(控件更改事件和元事件)指定“侦听器”interface。当在序列播放期间发生此类事件时,您可以使用这些interface来接收通知。

Sequencer处理特定的控制更改消息时,支持ControllerEventListenerinterface的对象可以接收通知。控制更改消息是 MIDI 消息的标准类型,它表示 MIDI 控制器(例如弯音轮或数据滑块)的值发生变化。 (有关控制更改消息的完整列表,请参见 MIDI 规范.)在播放序列时处理此类消息时,该消息会指示从定序器接收数据的任何设备(可能是合成器)更新的值。一些参数。该参数通常控制声音合成的某些方面,例如,如果控制器是弯音轮,则当前听起来的音符的音高。当记录序列时,控制更改消息意味着创建该消息的外部物理设备上的控制器已经移动,或者已经用软件模拟了这种移动。

以下是ControllerEventListenerinterface的使用方法。假设您已经开发了一个实现ControllerEventListenerinterface的类,这意味着您的类包含以下方法:

void controlChange(ShortMessage msg)

我们还假设您已经创建了类的实例,并将其分配给名为myListener的变量。如果在程序中的某些位置包含以下语句:

int[] controllersOfInterest = { 1, 2, 4 };
    sequencer.addControllerEventListener(myListener,
        controllersOfInterest);

那么每次音序器处理 MIDI 控制器编号 1、2 或 4 的控制更改消息时,都会调用您类的controlChange方法。换句话说,当Sequencer处理请求设置任何已注册控制器的值的请求时, Sequencer将调用您的类的controlChange方法。 (请注意,在 MIDI 1.0 规范中详细说明了将 MIDI 控制器编号分配给特定控制设备的情况.)

controlChange方法被传递一个ShortMessage,该ShortMessage包含受影响的控制器编号以及设置了控制器的新值。您可以使用ShortMessage.getData1方法获得控制器编号,并使用ShortMessage.getData2方法获得控制器值的新设置。

另一种特殊事件侦听器由MetaEventListenerinterface定义。根据标准 MIDI 文件 1.0 规范,元消息是 MIDI 有线协议中不存在但可以嵌入 MIDI 文件中的消息。它们对合成器没有意义,但可以由音序器解释。元消息包括指令(例如速度改变命令),歌词或其他文本以及其他指示符(例如音轨结尾)。

MetaEventListener机制类似于ControllerEventListener。在定序器处理MetaMessage时需要通知其实例的任何类中都实现MetaEventListenerinterface。这涉及向类添加以下方法:

void meta(MetaMessage msg)

通过将其作为参数传递给Sequencer addMetaEventListener方法来注册此类的实例:

boolean b = sequencer.addMetaEventListener
        (myMetaListener);

这与ControllerEventListenerinterface所采用的方法稍有不同,因为您必须注册才能接收所有MetaMessages,而不只是选定的感兴趣的对象。如果定序器在其序列中遇到MetaMessage,它将调用myMetaListener.meta,并将遇到的MetaMessage传递给它。 meta方法可以在其MetaMessage参数上调用getType以获取从 0 到 127 的整数,该整数指示消息类型,这是标准 MIDI 文件 1.0 规范定义的。