接上篇讲,当顺利捕获了某一时刻的MidiMessage之后,我们该怎样对捕获的信息进行处理呢,我们又怎么知道当前产生的这个信息代表什么呢。
我们先来看看MidiMessage提供了哪些方法:
int length = msg.getLength(); // 获取MIDI数据长度
byte[] data = msg.getMessage(); // 获取MIDI信息所包含的数据
int status = msg.getStatus(); // 获取MIDI状态码
如果要判断midi信息的实际作用的话,要用到的就是getStatus()所取得的状态码了,在javax.sound.midi.ShortMessage类下有如下常量定义(只列出常见的)。
public static final int NOTE_OFF = 0x80; // 128 - 终止指定音符的播放
public static final int NOTE_ON = 0x90; // 144 - 开始指定音符的播放
public static final int CONTROL_CHANGE = 0xB0; // 176 - 改变轨道控制
public static final int PROGRAM_CHANGE = 0xC0; // 192 - 变更音色
但在实际的开发过程中,我注意到一点。getStatus()函数返回的经常是一些完全对不上号的值。比如129,147之类。这是怎么一回事呢?
在研读过ShortMessage的源代码之后,我发现了一个有趣的地方:
public void setMessage(int command, int channel, int data1, int data2) throws InvalidMidiDataException {
if (command >= 0xF0 || command < 0x80) {
throw new InvalidMidiDataException("command out of range: 0x" + Integer.toHexString(command));
}
if ((channel & 0xFFFFFFF0) != 0) { // <=> (channel<0 || channel>15)
throw new InvalidMidiDataException("channel out of range: " + channel);
}
setMessage((command & 0xF0) | (channel & 0x0F), data1, data2); // 构造信息
}
以上是ShortMessage当中的setMessage函数,用来设置当前midi信息的属性,稍加观察我们便可以发现这一点:
setMessage((command & 0xF0) | (channel & 0x0F), data1, data2);
这也就不奇怪为什么midi标准当中规定“音轨编号从0-127” 而我们在上面看到的midi状态码第二位(也就是最后的8个比特位)是0了。
于是很容易想到从getStatus()获取的值中提取midi命令和midi轨道的具体值的方式,写作函数:
private int[] decryptStatus(int status) {
int command = status & 0xF0;
int channel = status & 0x0F;
return new int[] { command, channel };
}
接下来,我们专门来看号码为128和144的midi命令,也就是开始/停止播放音符命令。
从上面的setMessage函数就可以明显看出,除了制定命令和音轨以外,还有data1和data2两个整形参数。那么它们分别代表什么呢?
在查阅了midi的标准手册以后,我发现,midi信号的接下来两个数分别代表的是指定的音符和使用的乐器。midi音符的表示方式如下表:
序号 | 音符 | 读音 |
---|---|---|
60 | C5 | duo |
61 | C#5 | duo~ |
59 | A4 | xi* |
62 | D5 | rui |
其中第60号就是我们一般所说的“中央C”,也就是最普遍的“duo”。从它开始数值加一或减一代表升一个半音或者降一个半音。
(如果对此不够清楚可以去稍微了解一下乐谱有关的知识)
而“乐器”则是指midi里规定的标准乐器,关于每个数分别代表什么乐器,底下有一个我从fl studio截下来的图:
当然,在百度百科的midi介绍页面上也有列出。
有了上面这些基础认识,我们就可以对midi进行一些简单的处理了,我顺便把我做的项目在github上的地址在下面放出,可供参考使用:
https://github.com/Phosphorus15/ExpectedVirus