Deprecated: parse_url(): Passing null to parameter #1 ($url) of type string is deprecated in /www/wwwroot/blog_qqvbc_com/usr/plugins/Access/Access_Core.php on line 339

Deprecated: parse_url(): Passing null to parameter #1 ($url) of type string is deprecated in /www/wwwroot/blog_qqvbc_com/usr/plugins/Access/Access_Core.php on line 392

Deprecated: parse_url(): Passing null to parameter #1 ($url) of type string is deprecated in /www/wwwroot/blog_qqvbc_com/usr/plugins/Access/Access_Core.php on line 394
midi文件里都记录了哪些信息,是怎么编码的,怎么编码 - Joyber 的博客

MIDI 文件基础:记录什么 + 编码原理

MIDI不是音频!不存声音波形,只存「演奏指令」,这是最核心区别。

一、MIDI文件里面记录哪些信息

1. 核心事件(MIDI Event)

  1. 音符事件(Note On / Note Off)

    • Note On:按下琴键/鼓垫

      • 参数:通道(0~15)、音号(0-127,代表音高)、力度(0-127)
      • 注:力度=0的Note On等价于Note Off
    • Note Off:松开按键

      • 参数:通道、音号、释放力度
  2. 控制器事件 CC(Control Change)

    • 通道音量、声像、踩镲控制、弯音轮、表情、延音踏板等。
    • 例如CC64=延音踏板,CC10=声像,CC7=通道音量
  3. 程序改变 Program Change

    • 切换音色:比如通道1改成钢琴,通道10默认是打击乐通道(鼓组,这就是电鼓DTX用到的)
  4. 弯音 Pitch Wheel:滑音、音高偏移
  5. 通道触后、音符触后:键盘压力感应(手卷鼓一般不用)

2. 元事件(Meta Event,只存在MIDI文件,不发给硬件)

  • 节拍、BPM(速度)、拍号(4/4)、调号
  • 音轨名称、歌曲标题、版权、歌词文本
  • 时间基准(TPQN,每四分音符多少tick):决定时间分辨率,常见480tick/四分音符

3. 时间信息:Tick + Delta-time(增量时间)

MIDI不是记录绝对时间,用Delta-Time(增量tick):

两个事件之间间隔多少tick,而不是“第2秒按下音符”
tick → 根据BPM换算成真实秒数。

4. 文件结构信息

  • 音轨数量(Track):多轨MIDI可以鼓一轨、钢琴一轨分开。
  • 格式:MIDI0(单轨) / MIDI1(多轨同步,最常用) / MIDI2(多轨异步很少用)

二、MIDI文件编码(标准:MIDI 1.0,.mid二进制文件)

MIDI文件由文件头块 + 多个音轨块组成,全部是大端(Big-Endian)二进制存储。

1. 文件头块(Header Chunk)

固定结构:

4字节块标识:MThd
4字节块长度:固定00 00 00 06
2字节:MIDI格式(0/1/2)
2字节:音轨数量
2字节:时间基准 TPQN

示例十六进制:4D 54 68 64 00 00 00 06 00 01 00 02 01 E0

  • 4D546864 = ASCII MThd
  • 后面6字节:格式=1,2条音轨,TPQN=480

2. 音轨块(Track Chunk,每条音轨一个MTrk)

4字节标识:MTrk
4字节:本音轨所有事件的总字节长度
然后:一连串【Delta-Time + MIDI事件】

4D 54 72 6B = ASCII MTrk

重点:Delta-Time 编码 → 可变长度变长整数(VLQ,Variable Length Quantity)

这是MIDI最有特点的编码!

  • 1~4字节,最高位bit7作为标记
  • bit7=1:后面还有下一个字节;bit7=0:这是最后一个字节
  • 每个字节只用低7bit存数值。

举例子:
数字 0x80 (128)
拆成7bit分段:01 0000000
编码:81 00

0x81:最高位=1,低7bit=1;0x00最高位0,低7bit=0

规则:从高位往低位,每7bit一组,除最后一组外,所有字节最高位置1。

MIDI事件编码(状态字节 + 数据字节)

状态字节高4bit=事件类型,低4bit=MIDI通道(0~15)

  • 9x = Note On(x=通道),后面2字节:音号、力度
  • 8x = Note Off,后面2字节:音号、释放力度
  • Ax = 音符触后
  • Bx = CC控制器
  • Cx = Program Change(只1个数据字节,音色号)
  • Dx = 通道触后
  • Ex = 弯音(2字节)
运行状态(Running Status)优化:连续同类型同通道事件,可以省略状态字节,只写数据,减少文件体积,MIDI文件常用。

Meta元事件(FF开头)

状态字节固定0xFF,后面1字节元事件类型,1字节VLQ长度,再是内容。
例:FF 51 03 07 A1 20 → 设置BPM(微秒/四分音符)

三、简化编码流程(写一个MIDI文件的步骤)

  1. 写Header块:MThd + 长度 + 格式、轨道数、TPQN
  2. 对每一条音轨:

    1. 写入MTrk标识 + 预留长度(写完事件后回填)
    2. 遍历所有演奏事件,按时间先后排序
    3. 计算两个事件之间tick差值,用VLQ编码Delta-Time
    4. 写入事件状态+数据(使用running status压缩)
  3. 音轨结束事件:FF 2F 00(元事件:轨道结束)
  4. 回填MTrk块的长度字段

四、补充,和你电鼓相关

MIDI通道10(MIDI协议里是通道9,索引从0开始)固定打击乐通道:
每个音号对应不同鼓件:36底鼓、38军鼓、42闭踩镲、46开踩镲、49叮叮镲等。
所以DTX游戏、手卷鼓输出MIDI,就是输出Note On/Note Off到通道10。

五、举最小样例(极简MIDI示意)

四分音符TPQN=480,一个C4音符按下再松开。

  1. DeltaTime=0,NoteOn 通道1,音号60,力度100
  2. DeltaTime=480,NoteOff 通道1,音号60,力度80

标签: none

添加新评论