MIDI二进制文件格式简析

本文主要参考自Official MIDI Specifications

Chunks

每个MIDI文件由一系列chunk组成,每个chunk的前四个字节为魔数(magic number),是由四个ASCII字符所组成的类型标识。目前标准格式中已定义的chunk类型只有headertrack两种,其魔数分别为"MThd""MTrk",对于类型未被定义的chunk则应该被忽略。

每个chunk在其四字符类型之后紧跟一个32位无符号整数,意味这一chunk后续将要读入的字节个数,每个chunk已经读入的这八个字节不包含在内。

通常来说,一个MIDI文件中首先要存在一个header chunk,然后一系列track chunk紧随其后,格式大致如下:

MThd <length of header data>

<header data>

MTrk <length of track data>

<track data>

MTrk <length of track data>

<track data>

Header Chunks

在目前的标准中,header chunk长度固定为14,其由五个部分所组成:

<Header Chunk> = <chunk type> <length> <format> <ntrks> <division>

其中type固定为"MThd"formatntrksdivision均为16位,因此length固定为0x00000006

format指定了整个文件的组织结构,在当前的标准下,仅支持0x00000x00010x0002这三种可能的值。

0 the file contains a single multi-channel track

1 the file contains one or more simultaneous tracks (or MIDI outputs) of a
sequence

2 the file contains one or more sequentially independent single-track patterns

ntrks表示整个文件中track chunk的总个数,对于format为零的文件来说ntrks的值总是0x0001

最后的division表示了delta-times的含义,有metrical timetime-code-based time这两种形式,这取决于其最高位是否为零。

假如division最高位为零,那么就属于metrical time形式,这个16位无符号整数的意义为每个四分音符的ticks个数。否则属于time-code-based time形式,其低8位表示每帧的ticks个数,高8位为一个8位负数补码,有-24-25-29-30这四种可能的值,其意义与SMPTE有关,以下内容摘抄自维基百科:

Sub-second timecode time values are expressed in terms of frames. Common supported frame rates include:

24 frame/sec (film, ATSC, 2K, 4K, 6K)

25 frame/sec (PAL (Europe, Uruguay, Argentina, Australia), SECAM, DVB, ATSC)

29.97 (30 ÷ 1.001) frame/sec (NTSC American System (US, Canada, Mexico, Colombia, etc.), ATSC, PAL-M (Brazil))

30 frame/sec (ATSC)

在这里可以发现,凭借division是完全不足以描述每个时间间隔的实际长度的。在规范中对此有所说明,在默认情况下,乐曲的节奏为4/4拍,速度为每分钟120拍。这类元数据应该在MIDI文件中被指定,对于format0x0000的文件应处于其track chunk的开始,对于format0x0001的文件应包含在第一个track chunk之内,对于format0x0002的文件应包含在每个track chunk之中。

值得一提的是,未来的标准有可能会定义更多种类的formatchunk,甚至有可能为header chunk添加更多的参数从而使其length不再为0x00000006,因此对于程序的实现者来说,遵守标准是十分必要的。

Track Chunks

无论format的取值是什么,Track Chunks的结构都是一致的:

<Track Chunk> = <chunk type> <length> <MTrk event>+

length后是一串连续的MTrk event,每个MTrk event由两部分组成:

<MTrk event> = <delta-time> <event>

这里的delta-time是一种variable-length quantity,其每个字节仅有7个有效位,最高位若非零则说明后面还有下一字节,最多可占据四个字节,因此其最大值为0x0fffffff。以下为参考示例:

Number(hex) Representation(hex)
00000000 00
00000040 40
0000007F 7F
00000080 81 00
00002000 C0 00
00003FFF FF 7F
00004000 81 80 00
00100000 C0 80 00
001FFFFF FF FF 7F
00200000 81 80 80 00
08000000 C0 80 80 00
0FFFFFFF FF FF FF 7F

delta-time后紧跟的event有三种不同的类型:

<event> = <MIDI event> | <sysex event> | <meta-event>

MIDI event的第一个字节通常表示running status,其最高位必须非零,对于sysex eventmeta-event来说,这个字节分别为0xf00xff

MIDI event

在每个track chunk中出现的第一个MIDI event必须指定running status,而对于后续的MIDI event,假如其紧跟在一个MIDI event后面,并且与前一个MIDI event有着同样的running status,那么这一个MIDI eventrunning status可以被省略。

每个MIDI event根据其running status高4位的不同而存在一个或两个单字节参数,这些参数的最高位均为零,running status的低4位表示channel的编号,每个MIDI event只会在对应的channel上造成影响。举几个例子,以16进制表示:高4位为C意为Program Change,其跟随一个单字节参数,表示修改乐器音色;高4位为9意为Note On,高4位为8意为Note Off,这两者都跟随两个单字节参数,分别表示音高与力度。

中央C在MIDI event中的值为0x3c,每升高半音则加一,每降低半音则减一,通过这种规律可以推断出标准音为0x45

channel最多有16个,每个channel之间是独立的,也就是说不同的channel可以通过Program Change同时使用不同的音色,而又由于Note OnNote Off也是独立的,因此同一个channel中也可以同时播放不止一个音符。不过打击乐通常位于第10号channel

音色对照表见文章末尾。

sysex event

这是一种结构稍显复杂的事件信息,它可以包含一连串的sysex event,其基本结构如下:

F0 <length> <bytes to be transmitted after F0>

这里lengthbytes的长度,如果bytes不以0xf7结尾,那么其后就要跟随一个变长的delta-time,然后在跟随下一个sysex event,就像这样:

F7 <length> <all bytes to be transmitted>

除第一个sysex event之外,后续跟随的sysex event首字节应为0xf7,且最后一个sysex event的最后一字节应为0xf7。以下是一串合法的sysex event示例:

F0 03 43 12 00

81 48

F7 06 43 12 00 43 12 00

64

F7 04 43 12 00 F7

以上部分的0x81480x64分别表示200-tick delta-time和100-tick delta-time

meta-event

这一部分的格式是比较固定的:

FF <type> <length> <bytes>

所有meta-event0xff起始,然后紧跟一个字节的type,再然后跟随一个变长的lengthlength的值即为bytes的长度。

Standard MIDI Files 1.0中已经预定义了一部分meta-event,其中Copyright Notice应作为第一个track的第一个eventSequence NumberSequence/Track Name若存在则必须在任何delta-times非零的event前出现,End of Track必须作为每个track的最后一个event

FF <type> <length> <bytes> meta-event
FF 00 02 ssss Sequence Number
FF 01 len text Text Event
FF 02 len text Copyright Notice
FF 03 len text Sequence/Track Name
FF 04 len text Instrument Name
FF 05 len text Lyric
FF 06 len text Marker
FF 07 len text Cue Point
FF 20 01 cc MIDI Channel Prefix
FF 2F 00 End of Track
FF 51 03 tttttt Set Tempo
FF 54 05 hr mn se fr ff SMPTE Offset
FF 58 04 nn dd cc bb Time Signature
FF 59 02 sf mi Key Signature
FF 7F len data Sequencer-Specific Meta-Event

Set Tempo参数的意义为每个四分音符的微秒数。

Time Signature参数的意义分别为节奏的分子、以二为底取得节奏分母的对数、节拍器每响一次的MIDI clocks个数、每个四分音符所包含的三十二分音符个数(最后这个我也不理解有什么意义),比如以下示例:

Therefore, the complete event for 6/8 time, where the metronome clicks every three eighth-notes, but there are 24 clocks per quarter-note, 72 to the bar, would be (in hex):

FF 58 04 06 03 24 08

That is, 6/8 time (8 is 2 to the 3rd power, so this is 06 03), 36 MIDI clocks per dotted-quarter (24 hex!), and eight notated 32nd-notes per MIDI quarter note.

Key Signature的第一个参数表示乐曲经过了移调所添加的升降号个数,第二个参数取0x000x01意为大调或小调。

以下音色对照表引用自General MIDI System Level 1

General MIDI Sound Set Groupings(all channels except 10)

Prog # Instrument Group Prog # Instrument Group
1-8 Piano 65-72 Reed
9-16 Chromatic Percussion 73-80 Pipe
17-24 Organ 81-88 Synth Lead
25-32 Guitar 89-96 Synth Pad
33-40 Bass 97-104 Synth Effects
41-48 Strings 105-112 Ethnic
49-56 Ensemble 113-120 Percussive
57-64 Brass 121-128 Sound Effects

General MIDI Percussion Map(Channel 10)

MIDI Key Drum Sound MIDI Key Drum Sound MIDI Key Drum Sound
35 Acoustic Bass Drum 51 Ride Cymbal 1 67 High Agogo
36 Bass Drum 1 52 Chinese Cymbal 68 Low Agogo
37 Side Stick 53 Ride Bell 69 Cabasa
38 Acoustic Snare 54 Tambourine 70 Maracas
39 Hand Clap 55 Splash Cymbal 71 Short Whistle
40 Electric Snare 56 Cowbell 72 Long Whistle
41 Low Floor Tom 57 Crash Cymbal 2 73 Short Guiro
42 Closed Hi Hat 58 Vibraslap 74 Long Guiro
43 High Floor Tom 59 Ride Cymbal 2 75 Claves
44 Pedal Hi-Hat 60 Hi Bongo 76 Hi Wood Block
45 Low Tom 61 Low Bongo 77 Low Wood Block
46 Open Hi-Hat 62 Mute Hi Conga 78 Mute Cuica
47 Low-Mid Tom 63 Open Hi Conga 79 Open Cuica
48 Hi Mid Tom 64 Low Conga 80 Mute Triangle
49 Crash Cymbal 1 65 High Timbale 81 Open Triangle
50 High Tom 66 Low Timbale

MIDI二进制文件格式简析相关推荐

  1. android中so文件格式详解,[原创]一 Android ELF系列:ELF文件格式简析到linker的链接so文件原理分析...

    Android ELF系列:ELF文件格式简析和linker的链接so文件原理分析 Android ELF系列:实现一个so文件加载器 Android ELF系列:手写一个so文件(包含两个导出函数) ...

  2. 常见图片文件格式简析

    "常见":此处指BMP JPEG GIF PNG 四种. 软件: Windows 画图(除了Photoshop,我最喜欢的编辑器,简单粗暴) HxD BMP BMP文件分为4部分: ...

  3. Android ART Oat文件格式简析(下)

    在上篇中,我们分析到了OatFile的begin_和end_变量分别被指定到了符号oatdata和oatlastword指定的位置.那么指定的这一段数据到底是什么呢?本文会接下来分析. 首先来看Oat ...

  4. Android ART Oat文件格式简析(上)

    前面写了一篇博客大致描述了一下Image文件的结构,本文将接下来简单描述一下Oat文件的大致结构. 和前面一样,还是来看一下代码,代码非常复杂,为了保证大家不分心,我会尽量去除一些冗余的部分,只留下主 ...

  5. Unity3d资源反编译. AssetBundle格式简析+简单应用+爬坑

    ===================  Unity3d资源反编译工具 DisUnity ================ 源码:https://github.com/ata4/disunity 需要 ...

  6. 静态库调用_静态链接和动态链接对比简析

    0. 简介 在Linux环境下进行开发工作,代码要经过编译链接生成二进制可执行文件,才能被CPU识别并执行:程序的编译过程可以参考另外一篇文章<linux程序编译过程简析>:链接过程分为两 ...

  7. jxl简析[ http://www.emlog.net/fei ]

    <摘自>飞:jxl简析:http://www.emlog.net/fei 最近,完成了一个网上报表系统,刚巧用到了一个 JAVA 操作 excel 表格的 API .闲来无事,就将其大概的 ...

  8. 简析多种编码方式(Hex, Base64, UTF-8)

    简析多种编码方式(Hex, Base64, UTF-8) 首先计算机只认得二进制,0和1,所以我们现在看到的字都是经过二进制数据编码后的:计算机能针对0和1的组合做很多事情,这些规则都是人定义的:然后 ...

  9. grpc通信原理_gRPC原理简析

    gRPC原理简析 gRPC是由谷歌提出并开发的RPC协议,gRPC提供了一套机制,使得应用程序之间可以进行通信. 降级开发者的使用门槛,屏蔽网络协议,调用对端的接口就像是调用本地的函数一样.而gRPC ...

最新文章

  1. 通过打印学习Linux内核之sysfs(0)
  2. Windows下安装PHP开发环境
  3. EM不同气候条件下土壤稀有与丰富微生物类群的分化策略
  4. python编程从入门到精通pdf-Python编程从入门到精通.pdf
  5. 矩阵微积分的一些实用结论与推导
  6. 如何在ubuntu下安装detectron2_Ubuntu下detectron2 的安装使用笔记
  7. 小程序动态设置style,使用内部数据
  8. 02.CSS基础笔记及导入
  9. 当你已经23~男生女生都该看
  10. Dubbo与Zookeeper伪集群部署
  11. 经典的HTML5游戏及其源码分析
  12. 概率论与计算机的关系小论文,概率论与数理统计论文
  13. 51单片机 1.概述及点灯测试
  14. 心跳检测,用oob实现
  15. 微信小程序实现封装处理
  16. 服务器部署jdk,tomcat环境及腾讯云域名解析
  17. python3.0不向后兼容啥意思_为什么Python 3不能向后兼容?
  18. 计算机自动控制论文,精选:计算机在自动控制技术实践中的应用分析论文原稿...
  19. Windows下的远程命令行工具pstools
  20. Unity EasyAR Coloring3D AR绘图原理

热门文章

  1. 洛谷P1039 侦探推理
  2. 在win10基础上安装Ubuntu16.04双系统(双硬盘)
  3. IObit Uninstaller Pro v10.6.0.4 Cracked 安装监视器无法开启或无效的解决方案
  4. 光敏电阻5506主要参数_光敏电阻详细参数?
  5. 基于TCP Socket和Websocket实现的相互即时通信系统
  6. 为何你的浏览器不信任GlobalSign签发的HTTPS证书?
  7. windows系统软件崩溃分析
  8. 【Python】PIL 压缩图片刚好 200KB
  9. html 拓扑图 开源,GitHub - pylixm/zJTopo: 开源拓扑图工具类jTopo的扩展,jtopo是一个不错的拓扑图,基于html5 canvas,功能强大...
  10. android广播内容显示在屏幕上,如何将手机屏幕投影到计算机显示器上?