关于javax.sound.midi包的一些浅层探究(三)

接上篇讲,当顺利捕获了某一时刻的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);

在这个地方,setMessage函数传入的command(代表midi命令)和channel(代表midi轨道)值被进行了一次或运算,一起存入了一个int值当中。

这也就不奇怪为什么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截下来的图:

关于javax.sound.midi包的一些浅层探究(三)_第1张图片

当然,在百度百科的midi介绍页面上也有列出。

有了上面这些基础认识,我们就可以对midi进行一些简单的处理了,我顺便把我做的项目在github上的地址在下面放出,可供参考使用:

https://github.com/Phosphorus15/ExpectedVirus


你可能感兴趣的:(测试,java,midi,测试)