我正在使用 Java 播放 MIDI 歌曲 Sequencer .这首歌被设计成连续循环播放,我可以轻松做到这一点
sequencer.<a href="http://download.oracle.com/javase/6/docs/api/javax/sound/midi/Sequencer.html#setLoopCount%28int%29" rel="noreferrer noopener nofollow">setLoopCount</a>(Sequencer.LOOP_CONTINUOUSLY)
当通过内部(声卡)合成器播放时,它工作正常并且(如果需要添加 dummy event)循环计时是正确的。
但是,当通过外部(USB 或串口)合成器播放时,在循环点的输出中存在明显的间隙。这是因为在 .mid 文件的开头有许多设置事件需要一些时间才能通过串行线路发送。
我想尝试的是将一次性设置事件隔离到它们自己的 Sequence
中。当歌曲加载但不在主(循环)之外时发送到设备一次Sequence
.
有没有简单的算法(或库函数)可以区分这两种事件?
它需要提供:
- Registered parameter更改,作为一组相关消息发送。
- 有时, channel 节目更改会在轨道中间发送(并且必须是循环序列的一部分),但在整首歌曲中都保留相同节目的情况下(大多数情况),节目更改应该是设置顺序。这同样适用于速度变化。
最佳答案
看看 javax.sound.midi。序列由轨道组成。轨道包含 MidiEvents。 MidiEvents 是时间戳和 MidiMessage 的组合。
MidiMessage 有子类 ShortMessage、MetaMessage 和 SysexMessage。
最有可能在滴答 0 (MidiEvent.getTick() == 0) 处过滤掉 SysexMessages 将达到目的。如果不是,则尝试在 tick 0 处也过滤 MetaMessages。注意信息、程序更改等是通过 ShortMessages 完成的,不要过滤那些。
for each track in sequence {
for all midievents in track at tick 0 {
remove from track if instanceof SysexMessage or MetaMessage
}
}
另一部分是创建初始化序列。只需创建具有相同 divisionType 和分辨率的序列。一个轨道就足够了,您可以将所有从循环序列中删除的事件添加到初始化序列中的单个轨道。
关于java - 将 MIDI 歌曲事件与初始设置事件分开,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6723606/