揭秘 MIDI 音乐控制协议
乐理 计算机技术 2

回忆如沙

曾几何时,我沉迷于音乐的世界,任旋律在心中流淌。

时光荏苒,如今我再次与 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 线协议传输数据时,状态值为 0xFFShortMessage 表示系统重置消息。然而,在 MIDI 文件中,相同的状态值表示 MetaMessage。不同类型的元消息通过紧随状态字节 0xFF 后的第一个字节区分。随后的字节是数据字节。与系统排除消息类似,元消息的数据字节数是可变的,具体取决于元消息的类型。

消息Meta 类型数据长度包含内容出现位置
序列号0x002 byte序列号在时间差 0 处
文本0x01variable一些文本任意位置
版权声明0x02variable版权声明在第一个轨道的时间差 0 处
轨道名称0x03variable轨道名称在时间差 0 处
乐器名称0x04variable当前轨道中的乐器名称任意位置
歌词0x05variable歌词,通常是每个四分音符对应一个音节任意位置
标记0x06variable标记文本任意位置
提示点0x07variable提示文本,通常用于提示用户执行某些操作任意位置
通道前缀0x201 byte通道号(后续的元消息将应用于该通道)任意位置
轨道结束0x2F0每个轨道的结尾处
设置速度0x513 byte每拍的微秒数通常在第一个轨道中,但可任意位置
SMPTE 偏移0x545 byteSMPTE 时间,用于表示从开头的播放偏移在文件的第一个轨道或轨道开头处
拍号0x584 byte拍号、节拍器点击数和 32 分音符中的拍子长度任意位置
调号0x592 byte调号任意位置
序列器特定信息0x7FvariableMIDI 设备制造商的特定信息任意位置

参考 MIDI meta messages

调号对照表:

升/降调号数量降大调降小调升大调升小调
0C 大调a 小调C 大调a 小调
1F 大调d 小调G 大调e 小调
2B♭ 大调g 小调D 大调b 小调
3E♭ 大调c 小调A 大调f♯ 小调
4A♭ 大调f 小调E 大调c♯ 小调
5D♭ 大调b♭ 小调B 大调g♯ 小调
6G♭ 大调e♭ 小调F♯ 大调d♯ 小调
7C♭ 大调a♭ 小调C♯ 大调a♯ 小调

参考: Wiki - Circle of fifths

总结:
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 OFF128-143音符编号关音符的力度
Note ON144-159音符编号开音符的力度
Poly Key Pressure160-175音符编号压力值
Control Change176-191控制器编号控制器值
Program Change192-207程序号(乐器号)--
Mono Key Pressure208-223压力值--
Pitch Bend224-239弯音范围低位弯音范围高位
System240-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,常用于制造商自定义命令或全局控制。

参考 MIDI Commands

SysexMessage

SysexMessage 对象表示一个 MIDI 系统排除消息。

当从 MIDI 文件中读取系统排除消息时,它始终具有定义的长度。来自 MIDI 文件的系统排除消息数据应按以下顺序存储在 SysexMessage 的数据数组中:系统排除消息的状态字节(0xF0 或 0xF7)、所有消息数据字节,最后是结束排除标志(0xF7)。因此,SysexMessage 对象报告的长度是系统排除数据的长度加上两个字节:一个用于状态字节,另一个用于结束排除标志。

参考 MIDI System Exclusive message

简单来说是控制特殊设备操作的一种指令(通常 midi 文件中不包含此消息)

揭秘 MIDI 音乐控制协议
https://blog.9991565.xyz/archives/midi-parse
作者
Ayear
发布于
更新于
许可