回忆如沙
曾几何时,我沉迷于音乐的世界,任旋律在心中流淌。
时光荏苒,如今我再次与 MIDI 相遇,带着更加成熟的思维与理解,开启了对其全新而深入的探索。
本文基于 Java 库
javax.sound.midi.*
进行说明
我们首先认识一些基本概念:MIDI 文件包含多条轨道,每条轨道包含 16 条通道(在 General MIDI 2 中b拓展到 32)。
参考 General MIDI
轨道
轨道就像 Photoshop 中不同的“图层”,每个轨道可以用来记录某种特定的音乐内容,比如一个乐器的音符或者歌词。一个 MIDI 文件可以有很多轨道,每条轨道负责不同部分的音乐,最后所有轨道一起组成完整的音乐作品。
通道
通道更像是音乐中的“通道”或者“路径”,MIDI 标准有 16 个通道,每个通道可以分配给不同的乐器。比如,通道 1 可以分配给钢琴,通道 2 分配给吉他,这样就能让不同的乐器同时演奏。
可以用 Program Change
命令为当前通道指定一个乐器
(通道 10 预留为打击乐用)
MetaMessage
MetaMessage 是一种对合成器没有意义的 MidiMessage,但它可以存储在 MIDI 文件中,并由音序器程序解释。(参见 MidiMessage 类的描述讨论。)标准 MIDI 文件规范定义了多种类型的元事件(meta-events),例如序列号、歌词、提示点和设置速度。此外,还有用于表示歌词、版权、速度指示、时间签名和调号等信息的元事件。欲了解更多信息,请参阅标准 MIDI 文件 1.0 规范,该规范是由 MIDI 制造商协会发布的《MIDI 1.0 详细规范》的一部分。
当使用 MIDI 线协议传输数据时,状态值为 0xFF
的 ShortMessage 表示系统重置消息。然而,在 MIDI 文件中,相同的状态值表示 MetaMessage。不同类型的元消息通过紧随状态字节 0xFF
后的第一个字节区分。随后的字节是数据字节。与系统排除消息类似,元消息的数据字节数是可变的,具体取决于元消息的类型。
消息 | Meta 类型 | 数据长度 | 包含内容 | 出现位置 |
---|---|---|---|---|
序列号 | 0x00 | 2 byte | 序列号 | 在时间差 0 处 |
文本 | 0x01 | variable | 一些文本 | 任意位置 |
版权声明 | 0x02 | variable | 版权声明 | 在第一个轨道的时间差 0 处 |
轨道名称 | 0x03 | variable | 轨道名称 | 在时间差 0 处 |
乐器名称 | 0x04 | variable | 当前轨道中的乐器名称 | 任意位置 |
歌词 | 0x05 | variable | 歌词,通常是每个四分音符对应一个音节 | 任意位置 |
标记 | 0x06 | variable | 标记文本 | 任意位置 |
提示点 | 0x07 | variable | 提示文本,通常用于提示用户执行某些操作 | 任意位置 |
通道前缀 | 0x20 | 1 byte | 通道号(后续的元消息将应用于该通道) | 任意位置 |
轨道结束 | 0x2F | 0 | 每个轨道的结尾处 | |
设置速度 | 0x51 | 3 byte | 每拍的微秒数 | 通常在第一个轨道中,但可任意位置 |
SMPTE 偏移 | 0x54 | 5 byte | SMPTE 时间,用于表示从开头的播放偏移 | 在文件的第一个轨道或轨道开头处 |
拍号 | 0x58 | 4 byte | 拍号、节拍器点击数和 32 分音符中的拍子长度 | 任意位置 |
调号 | 0x59 | 2 byte | 调号 | 任意位置 |
序列器特定信息 | 0x7F | variable | MIDI 设备制造商的特定信息 | 任意位置 |
调号对照表:
升/降调号数量 | 降大调 | 降小调 | 升大调 | 升小调 |
---|---|---|---|---|
0 | C 大调 | a 小调 | C 大调 | a 小调 |
1 | F 大调 | d 小调 | G 大调 | e 小调 |
2 | B♭ 大调 | g 小调 | D 大调 | b 小调 |
3 | E♭ 大调 | c 小调 | A 大调 | f♯ 小调 |
4 | A♭ 大调 | f 小调 | E 大调 | c♯ 小调 |
5 | D♭ 大调 | b♭ 小调 | B 大调 | g♯ 小调 |
6 | G♭ 大调 | e♭ 小调 | F♯ 大调 | d♯ 小调 |
7 | C♭ 大调 | a♭ 小调 | C♯ 大调 | a♯ 小调 |
总结:
byte[5, 0]
和 byte[-4, 0]
在 MetaMessage
类型为 0x59
的消息中表示调号信息:
byte[5, 0]
表示 升 5 大调 B 大调。byte[-4, 1]
表示 降 4 小调 f 小调。
ShortMessage ⭐
敲黑板,这部分非常重要!
一条 ShortMessage 包含一个 MIDI 消息,它的状态字节后面最多跟着两个数据字节。符合此条件的 MIDI 消息类型包括:通道语音消息、通道模式消息、系统共用消息 和 系统实时消息 —— 换句话说,除了 系统排除消息 (SysexMessage) 和 元事件 (MetaMessage) 之外的所有类型。ShortMessage 类提供了获取和设置 MIDI 消息内容的方法。
1. 基本概念:MIDI 命令
MIDI 是一种通过数字信号控制电子乐器的协议。每个 MIDI 命令通过一系列数字来控制乐器,常见的命令有以下几类:
- Note OFF:关闭一个音符。
- Note ON:开启一个音符。
- Polyphonic Key Pressure:多键压力,检测多个按键的压力。
- Control Change:控制参数的改变,比如音量、踏板等。
- Program Change:更改乐器的声音(程序)。
- Monophonic Key Pressure:单键压力。
- Pitch Bend:弯音,调节音高。
- System Exclusive:通常用于全局性命令,影响整个设备。
2. MIDI 命令的结构
MIDI 命令由**状态字节(Status Byte)和数据字节(Data Byte)**组成:
- 状态字节:范围从 128 到 255,用于指示命令类型和通道。
- 数据字节:范围从 0 到 127,用于指定命令的参数。
例如:
144 60 127
:表示在 MIDI 通道 1 上,按下了 音符 60,力度为 127。
字节表示为 byte[-122, 60, 127]
你可能会问,欸这个是 -122 不是 144
当然,我们只需要-112 & 0xF0
就可以得到正确的状态字节 144
144 60 0
:表示在 MIDI 通道 1 上,松开了 音符 60。192 15
:表示在 MIDI 通道 1 上,改变声音为程序号 15。
3. 状态字节和数据字节的划分
不同类型的 MIDI 命令有不同的状态字节范围和数据字节需求。例如:
命令 | 状态字节范围 | 数据字节 1 | 数据字节 2 |
---|---|---|---|
Note OFF | 128-143 | 音符编号 | 关音符的力度 |
Note ON | 144-159 | 音符编号 | 开音符的力度 |
Poly Key Pressure | 160-175 | 音符编号 | 压力值 |
Control Change | 176-191 | 控制器编号 | 控制器值 |
Program Change | 192-207 | 程序号(乐器号) | -- |
Mono Key Pressure | 208-223 | 压力值 | -- |
Pitch Bend | 224-239 | 弯音范围低位 | 弯音范围高位 |
System | 240-255 | 制造商 ID | 型号 ID |
4. 具体示例
Note ON 命令
当按下一个音符时,Note ON
命令启动。其状态字节范围为 144 到 159,对应 16 个通道。举例:
- 144 60 127:在 MIDI 通道 1 上,音符 60(即中央 C)以力度 127(最大)被按下。
- 145 60 127:在 MIDI 通道 2 上,音符 60 被按下。
Program Change 命令
Program Change
命令用于改变乐器的声音。状态字节范围为 192 到 207。示例:
- 192 15:在通道 1 上,切换到程序号 15。
- 193 21:在通道 2 上,切换到程序号 21。
5. 使用十六进制(Hexadecimal)
为了方便表示,MIDI 的状态字节可以使用十六进制。例如:
- $90 表示 Note ON 在通道 1 上。
- $C0 表示 Program Change 在通道 1 上。
6. MIDI 的系统命令
系统命令(System Exclusive)通常影响整个设备,而不是单个通道。这类命令的状态字节范围为 240 到 255,常用于制造商自定义命令或全局控制。
SysexMessage
SysexMessage
对象表示一个 MIDI 系统排除消息。
当从 MIDI 文件中读取系统排除消息时,它始终具有定义的长度。来自 MIDI 文件的系统排除消息数据应按以下顺序存储在 SysexMessage
的数据数组中:系统排除消息的状态字节(0xF0 或 0xF7)、所有消息数据字节,最后是结束排除标志(0xF7)。因此,SysexMessage
对象报告的长度是系统排除数据的长度加上两个字节:一个用于状态字节,另一个用于结束排除标志。
参考 MIDI System Exclusive message
简单来说是控制特殊设备操作的一种指令(通常 midi 文件中不包含此消息)