实
验
原
理
(
算
法
流
程
)
3.以 Track 和 MidiEvents 类构造出音序 Sequence:
MIDI 文件有着严谨的结构,文件格式清晰,通过学习使用 midi 包的 MidiEvents 类
和 Track 类来构造 MIDI 文件的音序,可以较直观地理解 MIDI 文件是怎么构成的。
先说明下 midi 包对 MIDI 文件解析的结构(比较符号表示等级与包含关系):
Sequence(音序:用定时类型与精度初始化(定义每拍的 Tick 数))>
Track(音轨:事件流) >
MidiChannel(midi 通道:控制通道上的音符状态,可理解为用来连接 Track)>
MidiEvent(midi 事件) >
MidiMessage(midi 信息)= Tick(midi 时间戳,用数字表示时间点)>
ShortMessage(用于控制 midi 信息的状态)
data(midi 信息数据,最小的单位)
首先用 Sequence 类的构造函数创建一个空音序,构造函数中规定了音序的精度类型
的表示方法,以及在这个定时类型的基础上一个节拍的 Tick 数。
接着要将 Track 加到 Sequence 中:Track 对象不能通过调用构造函数来直接创建,却
可以通过 Sequence 对象来创建,所以我们通过调用 Sequence 对象的 CreateTrack()方
法来将音轨自动地连接到音序中去。
有了音轨之后,就要在 Track 之上添加 MidiEvent 了,Track 类的 add()方法返回一个
MIDI 事件,我们通过它将 MIDI 事件添加到音轨中去。
为了添加不同类型的 MIDI 事件,我们使用了两个自定义方法:
createNoteOnEvent() 和 createNoteOffEvent(),而这两个方法又通过调用自定义方法
createNoteEvent()来返回一个 MIDI 事件。
在前面的 MIDI 文件的结构说明中,我们已经知道了 MidiEvent 里 面 包 含 的 是
MidiMessage ( ShortMessage ) 和 Tick , 所 以 在 createNoteEvent() 中 , 首 先 通 过
ShortMessage 类的 setMessage()方法来创建 MIDI 信息,在这里面规定了这个 MIDI 信
息的各种参数(包括操作的是哪个通道、对指定音符做什么控制、这个音符的音
量),之后将这个 MIDI 信息结合相应的 Tick 作为 MidiEvent 构造函数的参数中,创
造出一个 MIDI 事件,作为 createNoteEvent()的返回值。
最后,在添加完了所有想要添加到 Track 中的 MIDI 事件后,我们调用 MidiSystem 类
的 write()方法将创建的音序写入文件中,再使用播放器播放这个文件,就可以听到
由自己创建音序的 midi 音乐了。
至此,将创建音序的流程与原理在结构上从上到下说明了一遍。