MIDI 文件格式解析举例_c# mid文件解析-程序员宅基地

技术标签: CS61B  摘要性笔记  

变长动态字节

    首先学习 MIDI 一个编码约定,MIDI 使用字节流(1bytes)来传输数据,对于小于 127 的数据就用一个字节存储。大于127的数据把字节的高位用来标识长数据,这样方便程序解析(一般情况高位为0认为一个byte是一个数据,如果出现高位为1(most significant bit)就读取多个字节再解析 int或者long),具体解析过程是最后一个字节前都用高位置1声明这是一个长整数的一部分。

    示例图:


文件组成块

    MIDI 是这样组织的:

MThd <length of header data>

<header data>

MTrk <length of track data>

<track data>

MTrk <length of track data>

<track data>

. . .


文件头解析

    先看文件头

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

<chunk type, 32bits>

 is the four ASCII characters 'MThd';

<length, 32bits>

is a 32-bit representation of the number 6 (后面的6bytes)(high byte first).

 <format, 16bits>

 specifies the overall organisation of the file (16bit word).

0

single multi-channel track

1

one or more simultaneous tracks (or MIDI outputs) of a sequence

2

one or more sequentially independent single-track patterns

<ntrks, 16bits>

the number (16bits) of track chunks in the file. It will always be 1 for a format 0 file. 

 <division, 16bits>

bit15 = 0

每个四分音符的 ticks

bit15 = 1

这个涉及一些复杂的指定,今天时间关系就暂时不分析这个

    当然这里 16bit word 是前面说的 most significant bit first 的,如果扩展也是可以的(这样的话 length 就要更新了)。

    然后趁热打铁看一个实例 midi 文件吧。

    可以看到,文件开始是 4bytes 的 MThd,然后接着是一个 4bytes 的 6 指明了头部这里是 6 bytes 长度,接下来就是 3 个 2bytes 的分别是 format 多轨同步格式,8个轨(经过搜索 MTrk 的确只有 8个),以及指定一个 4分音符 是 480 个 ticks. 我们之后解析文件的时候要用到这些数据。

    接下来看每个轨是怎么搞同步轨的,怎么记录音频的信息的。


轨道块解析

<Track Chunk>  直接看下面横向表格

<chunk type>

32bits

<length>

32bits

<MTrk event> 变长

<delta-time>

<event>

<MIDI event>

<sysex event>

<meta-event>

MTrk event ++ …

    这里 delta-time 主要是记录这个事件发生的时间点(用到上述变长字节数据),要实现同步播放同一个音符,我们只需要让两个音符的 delta time 是同一个tick计数就行了。

    然后我们来看怎么做这些 event 的数据格式(主要看会用到的)

    首先看 meta-event 的格式,解析 MIDI 的时候根据程序需求,不需要实现全部的 meta 支持,我们看主要的几个,首先 meta 要用 FF 来标识这是一个 meta event,我们看一些常见的 meta event

FF 05 len text  

A lyric to be sung. Generally, each syllable will be a separate lyric event which begins at the event's time.

FF 2F 00

End of Track. This event is not optional. It is included so that an exact ending point may be specified for the track, so that

an exact length is defined, which is necessary for tracks which are looped or concatenated。

FF 51 03 tttttt

Set Tempo (in microseconds per MIDI quarter-note)

FF 58 04 nn dd cc bb

Time Signature nn 是分子,dd是2的幂分母,cc 是一拍 tick 长,bb 是 一个midi 4分音符有多少个32分音符记谱

FF 03 len text

Sequence/Track Name,实际我分析的 midi 文件第二个 Track 第一条就是 Guitar 的字符串

    所以每个 MTrk event 都是以一个 变长字节数据 + 一个带 flag 的特别命令组成的。我们可以编写函数一次读取一个 MTrk event 把 delta-time 和 even 都解析出来。而且由于 FF 的存在以及 most significant bit 存在,我们不需要编写判断各种指令的变长命令读入,而是通过 FF 来辨析各个 event 段。FF 倒回来一个变长字节数据(delta-time)就是一个 MTrk event 的开始。

    趁热打铁2,我们再来看实际的文件

 4D 54 72 6B  

 00 00 00 17

 00 FF 51 03

 07 0A E2 00

 FF 03 00 00

 FF 58 04 04

 02 07 0A 00

 FF 2F 00

 M T  r k

 ◦ ◦ ◦ ◦

 ◦ ◦ Q ◦

 ◦ ◦ ◦ ◦

 ◦ ◦ ◦ ◦

 ◦ X ◦ ◦

 ◦ ◦ ◦ ◦

 ◦ / ◦

    一个 MTrk 块,lengh 是 23 个 bytes,数一下的确是  23.

    然后依次读取每个 MTrk event

    第一个是 00 FF 51 03 07 0A E2 ,设置 tempo 为一个四分音符为 07 0A E2 毫秒。

    第二个是 00 FF 58 04 04 02 07 0A, 设置 4/4 时值,7 tick 一拍,一个midi 4分音符记谱为一个10个32分音符。

    第三个是 00 FF 2F 00 声明这一个 track 结束。 可以发现这里的全是 meta-event 就单独用一个全部 delta-time 都是 0 的 Track Chunk 来存放了。

    下面就是说明音乐数据的 MIDI event 的格式了:

    前面讲到的都是 Track 下的,我们实际弹奏是需要一个乐器同时弹奏多个音的,把这个叫 Channel 好了。以下X就代表对特定的  Channel 进行设置。

状态字节

功能描述

数据字节描述

8X

松开音符

1字节:音符号(00~7F) / 2字节:力度(00~7F)

9X

按下音符

1字节:音符号(00~7F) / 2字节:力度(00~7F)

AX

触后音符

1字节:音符号(00~7F) / 2字节:力度(00~7F)

BX

控制器变化

1字节:控制器号码(00~79) / 2字节:控制器参数(00~7F),如钢琴踏板

CX

改变乐器

1字节:乐器号码(00~7F)

DX

通道触动压力

1字节:压力(00~7F)

EX

弯音轮变换

1字节:弯音轮变换值的低字节 / 2字节:弯音轮变换值的高字节

   阅读 midi 可以发现 guitar1 音轨下有一堆 00 BX 系列的控制器设置字段,以及一些弯音轮变换。然后转入这个乐器 event,

    00 C1 1D 00 C0 1D

    这一句就是 设置 Channel 1 和 Channel  0 为乐器 1D,乐器 1D 就是 29 失真吉他。好了为了读懂这里的 HW 的需要掌握的MIDI spec 都马克完了,接下来我们就可以读取MIDI实现鼓和不同的特效吉他的效果播放了。我们现在掌握的音频合成有鼓和不太像钢弦吉他的两种合成声,论文还提到竖琴的不过一般midi谱没有用竖琴的吧。为了播放我手头这个midi,可能需要探究一下贝斯的声音合成就够了。

补充打鼓是算在默认 channel 下的:

In GM standard MIDI files, channel 10 is reserved for percussion instruments only.

 所以打鼓另外还有一套音色控制编码,由于他没有音高。

  使用 Java 自带的midi库可以去下载 Oracle 提供的 Audio Demo。

   

附录

先是音高编号,即上面 8X 9X 后面跟着的音符号 00 ~ 7F

下面附上常见的乐器编号:

 钢琴

1 Acoustic Grand Piano大钢琴

2 Bright Acoustic Piano 亮音大钢琴

3 Electric Grand Piano 电钢琴

打击乐器

13 Marimba 马林巴

14 Xylophone 木琴

吉他

25 Acoustic Guitar (nylon)尼龙弦吉他

26 Acoustic Guitar(steel) 钢弦吉他

27 Electric Guitar (jazz) 爵士乐 电吉他

28 Electric Guitar (clean) 清音电吉他

29 Electric Guitar (muted) 弱音电吉他

30 Overdriven Guitar 驱动 音效吉他

31 Distortion Guitar 失真音效吉他

32 Guitar Harmonics 吉他泛音

贝司

33 Acoustic Bass 原声贝司

34 Electric Bass(finger) 指拨电贝司

35 Electric Bass(pick) 拨片拨电贝司

36 Fretless Bass 无品贝司

37 Slap Bass 1 击弦贝司1

38 Slap Bass 2 击弦贝司2

39 Synth Bass 1 合成贝司1

40 Synth Bass 2 合成贝司2

各种鼓

112-120

弦乐独奏

41 Violin 小提琴

42 Viola中提琴

43 Cello 大提琴

44 Contrabass 低音提琴

47 Orchestral Harp 竖琴

铜管乐器组

57 Trumpet 小号

58 Trombone 长号

59 Tuba 大号

61 French Horn 圆号

62 Brass Section 铜管  

鼓的音色(代替音高)

18 voice two 人声“two
19 voice three 人声“three”

27 high q 激光枪声
28 slap 拍击声
29 scratch push 特效处理推音
30 scratch pull 特效处理拉音
31 sticks 鼓槌对敲
32 square click 敲方板
33 metronome click 节拍器
34 metronome bell 节拍器重音
35 acoustic bass drum 低音大鼓
36 bass drum 1 高音大鼓
37 side stick 鼓边
38 acoustic snare 小鼓
39 hand clap 拍手声
40 electric snare 电子小鼓
41 low floor tom 低音落地嗵鼓
42 closed hi-hat 合音踩镲
43 high floor tom 高音落地嗵鼓
44 pedal hi-hat 踏音踩镲
45 low tom 低音嗵鼓
46 open hi-hat 开音踩镲
47 low-mid tom 中低音嗵鼓
48 hi-mid tom 中高音嗵鼓
49 crash cymbal 1 低砸音镲
50 high tom 高音嗵鼓
51 ride cymbal 1 低浮音镲
52 chinese cymbal 中国镲
53 ride bell 浮音镲碗
54 tambourine 铃鼓
55 splash cymbal 溅音镲
56 cowbell 牛铃
57 crash cymbal 2 高砸音镲
58 vibraslap 颤音叉
59 ride cymbal 2 高浮音镲
60 hi bongo 高音邦戈
61 low bongo 低音邦戈
62 mute hi conga 弱音康加
63 open hi conga 高音康加
64 low conga 低音康加
65 high timbale 高音铜鼓
66 low timbale 低音铜鼓
67 high agogo 高音拉丁打铃
68 low agogo 低音拉丁打铃
69 cabasa 沙锤
70 maracas 响葫芦
71 short whistle 短哨
72 long whistle 长哨
73 short guiro 短锯琴
74 long guiro 长锯琴
75 claves 击杆
76 hi wood block 高音木块
77 low wood block 低音木块
78 mute cuica 弱音吉加
79 open cuica 开音吉加
80 mute triangle 弱音三角铁
81 open triangle 开音三角铁
82 shaker 沙锤(比69沙锤高)
83 jingle bell 铃铛
84 bell tree 铃树
85 castanets 响板
86 mute surdo 弱音瑟多
87 open surdo 开音瑟多
88 applause2 欢呼2(roland sc-88pro)
当选用48号orchestra音色的时候,变体音色为:
27 closed hi-hat 敲击闭合踩镲
28 pedal hi-hat 脚踏踩镲
29 open hi-hat 敲击张开踩镲
30 ride cymbal 点镲
35 concert bd 2 管弦乐队大鼓2(声音清晰)
36 concert bd 1 管弦乐队大鼓1(此有巨大响声)
38 concert sd 管弦乐队小军鼓
39 castanets 响板
40 concert sd 管弦乐队小军鼓
41 timpani f f3阶定音鼓
42 timpani f# f#3阶定音鼓
43 timpani g g3阶定音鼓
44 timpani g# g#3阶定音鼓
45 timpani a a3阶定音鼓
46 timpani a# a#3阶定音鼓
47 timpani b b3阶定音鼓
48 timpani c c4阶定音鼓
49 timpani c# c#4阶定音鼓
50 timpani d d4阶定音鼓
51 timpani d# d#4阶定音鼓
52 timpani e e4阶定音鼓
53 timpani f f4阶定音鼓
57 concert cymbal 2 管弦乐队镲2(浊音)
59 concert cymbal 1 管弦乐队镲1(清音)
88 applause 欢呼声(根据时值决定长度)  22 mc-505 beep 1 mc-505信号音1
23 mc-505 beep 2 mc-505信号音2
24 concert sd 大乐队小军鼓
25 snare roll 小军鼓滚奏
26 finger snap 2 响指2
(以上roland sc-88 pro)
27 high q 激光枪声
28 slap 拍击声
29 scratch push 特效处理推音
30 scratch pull 特效处理拉音
31 sticks 鼓槌对敲
32 square click 敲方板
33 metronome click 节拍器
34 metronome bell 节拍器重音
35 acoustic bass drum 低音大鼓
36 bass drum 1 高音大鼓
37 side stick 鼓边
38 acoustic snare 小鼓
39 hand clap 拍手声
40 electric snare 电子小鼓
41 low floor tom 低音落地嗵鼓
42 closed hi-hat 合音踩镲
43 high floor tom 高音落地嗵鼓
44 pedal hi-hat 踏音踩镲
45 low tom 低音嗵鼓
46 open hi-hat 开音踩镲
47 low-mid tom 中低音嗵鼓
48 hi-mid tom 中高音嗵鼓
49 crash cymbal 1 低砸音镲
50 high tom 高音嗵鼓
51 ride cymbal 1 低浮音镲
52 chinese cymbal 中国镲
53 ride bell 浮音镲碗
54 tambourine 铃鼓
55 splash cymbal 溅音镲
56 cowbell 牛铃
57 crash cymbal 2 高砸音镲
58 vibraslap 颤音叉
59 ride cymbal 2 高浮音镲
60 hi bongo 高音邦戈
61 low bongo 低音邦戈
62 mute hi conga 弱音康加
63 open hi conga 高音康加
64 low conga 低音康加
65 high timbale 高音铜鼓
66 low timbale 低音铜鼓
67 high agogo 高音拉丁打铃
68 low agogo 低音拉丁打铃
69 cabasa 沙锤
70 maracas 响葫芦
71 short whistle 短哨
72 long whistle 长哨
73 short guiro 短锯琴
74 long guiro 长锯琴
75 claves 击杆
76 hi wood block 高音木块
77 low wood block 低音木块
78 mute cuica 弱音吉加
79 open cuica 开音吉加
80 mute triangle 弱音三角铁
81 open triangle 开音三角铁
82 shaker 沙锤(比69沙锤高)
83 jingle bell 铃铛
84 bell tree 铃树
85 castanets 响板
86 mute surdo 弱音瑟多
87 open surdo 开音瑟多
88 applause2 欢呼2(roland sc-88pro)
当选用48号orchestra音色的时候,变体音色为:
27 closed hi-hat 敲击闭合踩镲
28 pedal hi-hat 脚踏踩镲
29 open hi-hat 敲击张开踩镲
30 ride cymbal 点镲
35 concert bd 2 管弦乐队大鼓2(声音清晰)
36 concert bd 1 管弦乐队大鼓1(此有巨大响声)
38 concert sd 管弦乐队小军鼓
39 castanets 响板
40 concert sd 管弦乐队小军鼓
41 timpani f f3阶定音鼓
42 timpani f# f#3阶定音鼓
43 timpani g g3阶定音鼓
44 timpani g# g#3阶定音鼓
45 timpani a a3阶定音鼓
46 timpani a# a#3阶定音鼓
47 timpani b b3阶定音鼓
48 timpani c c4阶定音鼓
49 timpani c# c#4阶定音鼓
50 timpani d d4阶定音鼓
51 timpani d# d#4阶定音鼓
52 timpani e e4阶定音鼓
53 timpani f f4阶定音鼓
57 concert cymbal 2 管弦乐队镲2(浊音)
59 concert cymbal 1 管弦乐队镲1(清音)
88 applause 欢呼声(根据时值决定长度)

主要的参考资料是 MIDI 的 Spec  和网络搜索的一些表格

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u010180372/article/details/118697564

智能推荐

什么是内部类?成员内部类、静态内部类、局部内部类和匿名内部类的区别及作用?_成员内部类和局部内部类的区别-程序员宅基地

文章浏览阅读3.4k次,点赞8次,收藏42次。一、什么是内部类?or 内部类的概念内部类是定义在另一个类中的类;下面类TestB是类TestA的内部类。即内部类对象引用了实例化该内部对象的外围类对象。public class TestA{ class TestB {}}二、 为什么需要内部类?or 内部类有什么作用?1、 内部类方法可以访问该类定义所在的作用域中的数据,包括私有数据。2、内部类可以对同一个包中的其他类隐藏起来。3、 当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷。三、 内部类的分类成员内部_成员内部类和局部内部类的区别

分布式系统_分布式系统运维工具-程序员宅基地

文章浏览阅读118次。分布式系统要求拆分分布式思想的实质搭配要求分布式系统要求按照某些特定的规则将项目进行拆分。如果将一个项目的所有模板功能都写到一起,当某个模块出现问题时将直接导致整个服务器出现问题。拆分按照业务拆分为不同的服务器,有效的降低系统架构的耦合性在业务拆分的基础上可按照代码层级进行拆分(view、controller、service、pojo)分布式思想的实质分布式思想的实质是为了系统的..._分布式系统运维工具

用Exce分析l数据极简入门_exce l趋势分析数据量-程序员宅基地

文章浏览阅读174次。1.数据源准备2.数据处理step1:数据表处理应用函数:①VLOOKUP函数; ② CONCATENATE函数终表:step2:数据透视表统计分析(1) 透视表汇总不同渠道用户数, 金额(2)透视表汇总不同日期购买用户数,金额(3)透视表汇总不同用户购买订单数,金额step3:讲第二步结果可视化, 比如, 柱形图(1)不同渠道用户数, 金额(2)不同日期..._exce l趋势分析数据量

宁盾堡垒机双因素认证方案_horizon宁盾双因素配置-程序员宅基地

文章浏览阅读3.3k次。堡垒机可以为企业实现服务器、网络设备、数据库、安全设备等的集中管控和安全可靠运行,帮助IT运维人员提高工作效率。通俗来说,就是用来控制哪些人可以登录哪些资产(事先防范和事中控制),以及录像记录登录资产后做了什么事情(事后溯源)。由于堡垒机内部保存着企业所有的设备资产和权限关系,是企业内部信息安全的重要一环。但目前出现的以下问题产生了很大安全隐患:密码设置过于简单,容易被暴力破解;为方便记忆,设置统一的密码,一旦单点被破,极易引发全面危机。在单一的静态密码验证机制下,登录密码是堡垒机安全的唯一_horizon宁盾双因素配置

谷歌浏览器安装(Win、Linux、离线安装)_chrome linux debian离线安装依赖-程序员宅基地

文章浏览阅读7.7k次,点赞4次,收藏16次。Chrome作为一款挺不错的浏览器,其有着诸多的优良特性,并且支持跨平台。其支持(Windows、Linux、Mac OS X、BSD、Android),在绝大多数情况下,其的安装都很简单,但有时会由于网络原因,无法安装,所以在这里总结下Chrome的安装。Windows下的安装:在线安装:离线安装:Linux下的安装:在线安装:离线安装:..._chrome linux debian离线安装依赖

烤仔TVの尚书房 | 逃离北上广?不如押宝越南“北上广”-程序员宅基地

文章浏览阅读153次。中国发达城市榜单每天都在刷新,但无非是北上广轮流坐庄。北京拥有最顶尖的文化资源,上海是“摩登”的国际化大都市,广州是活力四射的千年商都。GDP和发展潜力是衡量城市的数字指...

随便推点

java spark的使用和配置_使用java调用spark注册进去的程序-程序员宅基地

文章浏览阅读3.3k次。前言spark在java使用比较少,多是scala的用法,我这里介绍一下我在项目中使用的代码配置详细算法的使用请点击我主页列表查看版本jar版本说明spark3.0.1scala2.12这个版本注意和spark版本对应,只是为了引jar包springboot版本2.3.2.RELEASEmaven<!-- spark --> <dependency> <gro_使用java调用spark注册进去的程序

汽车零部件开发工具巨头V公司全套bootloader中UDS协议栈源代码,自己完成底层外设驱动开发后,集成即可使用_uds协议栈 源代码-程序员宅基地

文章浏览阅读4.8k次。汽车零部件开发工具巨头V公司全套bootloader中UDS协议栈源代码,自己完成底层外设驱动开发后,集成即可使用,代码精简高效,大厂出品有量产保证。:139800617636213023darcy169_uds协议栈 源代码

AUTOSAR基础篇之OS(下)_autosar 定义了 5 种多核支持类型-程序员宅基地

文章浏览阅读4.6k次,点赞20次,收藏148次。AUTOSAR基础篇之OS(下)前言首先,请问大家几个小小的问题,你清楚:你知道多核OS在什么场景下使用吗?多核系统OS又是如何协同启动或者关闭的呢?AUTOSAR OS存在哪些功能安全等方面的要求呢?多核OS之间的启动关闭与单核相比又存在哪些异同呢?。。。。。。今天,我们来一起探索并回答这些问题。为了便于大家理解,以下是本文的主题大纲:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JCXrdI0k-1636287756923)(https://gite_autosar 定义了 5 种多核支持类型

VS报错无法打开自己写的头文件_vs2013打不开自己定义的头文件-程序员宅基地

文章浏览阅读2.2k次,点赞6次,收藏14次。原因:自己写的头文件没有被加入到方案的包含目录中去,无法被检索到,也就无法打开。将自己写的头文件都放入header files。然后在VS界面上,右键方案名,点击属性。将自己头文件夹的目录添加进去。_vs2013打不开自己定义的头文件

【Redis】Redis基础命令集详解_redis命令-程序员宅基地

文章浏览阅读3.3w次,点赞80次,收藏342次。此时,可以将系统中所有用户的 Session 数据全部保存到 Redis 中,用户在提交新的请求后,系统先从Redis 中查找相应的Session 数据,如果存在,则再进行相关操作,否则跳转到登录页面。此时,可以将系统中所有用户的 Session 数据全部保存到 Redis 中,用户在提交新的请求后,系统先从Redis 中查找相应的Session 数据,如果存在,则再进行相关操作,否则跳转到登录页面。当数据量很大时,count 的数量的指定可能会不起作用,Redis 会自动调整每次的遍历数目。_redis命令

URP渲染管线简介-程序员宅基地

文章浏览阅读449次,点赞3次,收藏3次。URP的设计目标是在保持高性能的同时,提供更多的渲染功能和自定义选项。与普通项目相比,会多出Presets文件夹,里面包含着一些设置,包括本色,声音,法线,贴图等设置。全局只有主光源和附加光源,主光源只支持平行光,附加光源数量有限制,主光源和附加光源在一次Pass中可以一起着色。URP:全局只有主光源和附加光源,主光源只支持平行光,附加光源数量有限制,一次Pass可以计算多个光源。可编程渲染管线:渲染策略是可以供程序员定制的,可以定制的有:光照计算和光源,深度测试,摄像机光照烘焙,后期处理策略等等。_urp渲染管线