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

来源:互联网 发布:博世待遇怎么样 知乎 编辑:程序博客网 时间:2024/05/29 17:35

接上篇讲,当顺利捕获了某一时刻的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音符的表示方式如下表:

序号音符读音60C5duo61C#5duo~59A4xi*62D5rui*注 : 其中'*'表示降声调,'~'表示升半音。

其中第60号就是我们一般所说的“中央C”,也就是最普遍的“duo”。从它开始数值加一或减一代表升一个半音或者降一个半音。

(如果对此不够清楚可以去稍微了解一下乐谱有关的知识)

而“乐器”则是指midi里规定的标准乐器,关于每个数分别代表什么乐器,底下有一个我从fl studio截下来的图:

midi 乐器对照

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

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

https://github.com/Phosphorus15/ExpectedVirus


0 0
原创粉丝点击