第一键盘 - 电子琴在线论坛

 找回密码
 现在注册

QQ登录

只需一步,快速开始

查看: 1604|回复: 9
打印 上一主题 下一主题

对于MIDI文件如何选择其中的4分音符的速度

[复制链接]
跳转到指定楼层
1#
发表于 2016-5-30 10:22:15 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本人在MIDI文件提取歌词过程中发现在一个两track的MIDI中,其中一个trac中连续设置无数个4分音符的速度 FF 51 03,十分不解,设置这么多速度是为什么,难道播放速度是变来变去的吗?有时我试选第一个或最后一个速度,提取歌词时间就与专业MIDI软件一样,但我不能每次试着选,这其中有什么规则,该怎么选择速度?F:\midi.JPGC:\Documents
分享到: QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏2 分享分享 支持支持 反对反对
回复

使用道具 举报

2#
发表于 2016-5-30 12:15:40 | 只看该作者
先mark,中午出去买点儿元件,下午回来回复您~
回复 支持 反对

使用道具 举报

3#
发表于 2016-5-30 12:16:00 | 只看该作者
您也是给我发过站内信吧?下午一并回复~
回复 支持 反对

使用道具 举报

4#
发表于 2016-5-30 14:57:53 | 只看该作者
    可以确定的是:MIDI文件的播放速度,确实可以随时改变。任何一个音序器软件中都有改变播放速度的功能。我一直在用cakewalk,现在用cakewalk sonar,里边就有一个所谓的“速度视图”,可以在里边画速度曲线,这样速度就发生变化了。所以一个MIDI文件中有多个FF 51 03是完全正常的

    拿一个MIDI文件举例: JIANGNAN.rar (10.69 KB, 下载次数: 3)

    稍微介绍一下这个MIDI文件,因为这个MIDI曲子及其作者十分值得记住。这个MIDI曲子名为“望江南”,作者“白勺”(bai白,shao勺)。这可以说是使用GM音色实现了中国民乐的最佳典范。关于此神的详细介绍请自行百度。

    说回正题。如果您听这个曲子,然后用cakewalk(不用很高的版本,经典的cakewalk pro audio 9.03即可)打开此MIDI文件,点击“查看”菜单当中的“速度”菜单项,就打开了速度视图,在里边查看这个曲子的速度曲线,注意全曲速度如何变化。

    然后再说回Meta-Event和歌词的Meta-Event事件。

    为什么MIDI文件里,要把Meta-Event事件,单独列出来归为一类呢?因为:Meta-Event事件不同于其他MIDI事件。Meta-Event不会被发送出MIDI端口,它只是给音序器自身用的,用来标记这个MIDI文件中的一些播放信息(如时间码类型、速度等)和文本信息(如歌词、音轨名等)等。而如NoteOn、NoteOff、ProgChg、CtrlChg等等MIDI事件,是要由音序器通过MIDI端口发送给音源的(注意“音序器”和“音源”是两个概念,虽然看起来你在用cakewalk播放midi的时候,cakewalk同样会出声,那是因为cakewalk的MIDI输出端口,默认指定给了windows的软波表合成器。实际上cakewalk并不出声,出声的是系统软波表合成器)。

    既然Meta-Event也作为一个“事件”,所以它在MIDI文件中的排布,也是遵循MIDI文件的格式规范的,也就是“DeltaTime + Event”的形式。不知道您是否了解MIDI文件的文件格式,以及是否了解这个所谓的“DeltaTime + Event”的形式。如果不了解的话,请先参考俺之前写过的几个科普贴:

----> 读书笔记——MIDI文件结构简介(https://www.cndzq.com/bbs/thread-114440-1-1.html
----> 读书笔记:MIDI Tick、Meta-event、变长数表示法、区分MIDI文件中单个字节的含义(https://www.cndzq.com/bbs/thread-117332-1-1.html
----> 研究MIDI文件结构,发个读书笔记~有关MIDI音乐的拍速、MIDI Tick速度和周期等等的转(https://www.cndzq.com/bbs/thread-110934-1-1.html

    好了,相信您现在已经了解了MIDI文件的结构咧。于是,您应该能理解这样一点:

    · 对于绝大多数MIDI文件来说,其MIDI时钟均采用TPQN的方法。所以此时MIDI文件中的歌词Meta-Event出现的时间,只与MIDI Tick有关。而MIDI Tick与绝对时间之间,则与MIDI文件的播放速度Meta-Event、MIDI文件的TPQN数,等等的参数有关。

    于是,怎么从MIDI文件里提取歌词?根据我的理解,思路应该是:一点点地顺序遍历文件,根据TPQN和速度Meta-Event,计算此时的MIDI Tick与绝对时间之间的对应关系,然后再根据歌词Meta-Event和上一Event之间的DeltaTime,计算这个歌词Meta-Event与上一Event之间的绝对时间差,与上一个时刻进行累加,得到当前歌词的绝对时间码。

    如果碰到的是使用SMPTE时间码的MIDI文件,因为SMPTE本身就带有绝对时间(时:分:秒:帧),所以就不需要做以上处理,直接读时间并累加即可。这一条请注意,因为我本人没见过使用SMPTE码的MIDI文件,所以对于这种MIDI文件的歌词时间换算,仅供参考,不保证准确~

    不知道说得是否清晰,反正不是很简洁明了就是咧~

参考资料:

· 陈学煌 刘永志 潘晓利 马俊,“MIDI原理与开发应用”,国防工业出版社,2008年1月第一版
· MMA(The MIDI Manufacturers Association),“Standard MIDI Files 1.0” spec,1996年
· 自引的三个帖子

回复 支持 反对

使用道具 举报

5#
 楼主| 发表于 2016-5-30 18:20:51 | 只看该作者
谢谢辛苦的回复,你写关于的midi的文档是我网上见过的最通俗易懂的了.
MIDI结构我也是通过《MIDI原理与开发应用》一书有一些初步了解除,
现在歌词我也提取出来了,就是四分音符的时长没法选择,我现在没权限上传图片.
比JIANGNAN.MID中无数个 FF 51 03什么时用第1个,什么时候用第2个,3个...
00000000   4D 54 68 64 00 00 00 06  00 01 00 0C 00 78 4D 54   MThd.........xMT
00000016   72 6B 00 00 07 D2 00 FF  58 04 04 02 18 08 00 FF   rk...?壸......
00000032   59 02 FE 00 00 FF 51 03  0D 76 B1 00 FF 06 4E 20   Y.?.凸..v?.N
00000048   57 61 6E 67 20 4A 69 61  6E 67 20 4E 61 6E 20 20   Wang Jiang Nan  
00000064   20 43 6F 70 79 72 69 67  68 74 20 20 28 43 29 20    Copyright  (C)
00000080   20 20 42 79 20 20 53 70  6F 6F 6E 20 53 74 75 64     By  Spoon Stud
00000096   69 6F 20 20 20 20 20 20  20 41 75 74 68 6F 72 20   io       Author
00000112   3A 20 57 68 69 74 65 20  53 70 6F 6F 6E 03 FF 51   : White Spoon.凸
00000128   03 11 46 2B 03 FF 51 03  10 F4 47 07 FF 51 03 10   ..F+.凸..鬐.凸..
00000144   A5 5D 11 FF 51 03 10 0F  D8 03 FF 51 03 0F C8 F3   .凸...?凸..润
00000160   07 FF 51 03 0F 84 75 0D  FF 51 03 0F 42 40 14 FF   .凸..剈.凸..B@.
00000176   51 03 0F 02 37 07 FF 51  03 0E C4 3E 0A FF 51 03   Q...7.凸..?.凸.
00000192   0E 88 3D 1A FF 51 03 0E  4E 1C 04 FF 51 03 0E 15   .?.凸..N..凸...
00000208   C5 0D FF 51 03 0D DF 23  0A FF 51 03 0D AA 22 0D   ?凸..?.凸..?.
00000224   FF 51 03 0D 76 B1 07 FF  51 03 0D 44 BD 46 FF 51   凸..v?凸..D紽凸
00000240   03 0D 14 37 0D FF 51 03  10 0F D8 04 FF 51 03 0F   ...7.凸...?凸..
00000256   C8 F3 03 FF 51 03 0F 84  75 0A FF 51 03 0F 42 40   润.凸..剈.凸..B@
00000272   07 FF 51 03 0F 02 37 1E  FF 51 03 0E 88 3D 03 FF   .凸...7.凸..?.
00000288   51 03 0E 4E 1C 1E FF 51  03 0E 15 C5 14 FF 51 03   Q..N..凸...?凸.
00000304   0D DF 23 03 FF 51 03 0D  AA 22 07 FF 51 03 0D 76   .?.凸..?.凸..v
00000320   B1 07 FF 51 03 0D 44 BD  6E FF 51 03 0E 88 3D 0A   ?凸..D絥凸..?.
00000336   FF 51 03 0E 15 C5 06 FF  51 03 0D DF 23 04 FF 51   凸...?凸..?.凸
00000352   03 0D AA 22 35 FF 51 03  0D 44 BD 03 FF 51 03 0D   ..?5凸..D?凸..
00000368   14 37 0E FF 51 03 0C E5  0E 17 FF 51 03 0C B7 35   .7.凸..?.凸..?
00000384   0A FF 51 03 0E 88 3D 03  FF 51 03 0E 4E 1C 04 FF   .凸..?.凸..N..
00000400   51 03 0E 15 C5 06 FF 51  03 0D DF 23 0A FF 51 03   Q...?凸..?.凸.
00000416   0D 76 B1 04 FF 51 03 0D  44 BD 06 FF 51 03 0D 14   .v?凸..D?凸...
00000432   37 07 FF 51 03 0C E5 0E  07 FF 51 03 0C B7 35 14   7.凸..?.凸..?.
00000448   FF 51 03 0C 5F 3B 0D FF  51 03 0C E5 0E 08 FF 51   凸.._;.凸..?.凸
00000464   03 0D 14 37 0A FF 51 03  0E C4 3E 0A FF 51 03 0F   ...7.凸..?.凸..
00000480   42 40 14 FF 51 03 0E C4  3E 04 FF 51 03 0E 88 3D   B@.凸..?.凸..?

你说的通过cakewalk查看MIDI文件速度视图,我没有看见什么曲线.只看见一条向右移动.
回复 支持 反对

使用道具 举报

6#
发表于 2016-5-31 08:33:36 使用第一键盘发送 | 只看该作者
外行人看着眼晕!一个回复超长,一个问题的更长
回复 支持 反对

使用道具 举报

7#
发表于 2016-5-31 10:43:54 | 只看该作者
oukm 发表于 2016-5-30 18:20
谢谢辛苦的回复,你写关于的midi的文档是我网上见过的最通俗易懂的了.
MIDI结构我也是通过《MIDI原理与开发 ...

· 无数个 FF 51 03什么时用第1个,什么时候用第2个,3个...

    既然您已经了解了MIDI文件,您得知道,对于MIDI 1格式的文件来说(这个JIANGNAN.MID就是MIDI 1格式。怎么看是MIDI 0格式还是MIDI 1格式?见俺那几个帖子~),里边各个MTrk Chunk是在全局统一的时间轴下,各自数着MIDI Tick,顺序播放。

    对任一个MTrk而言,其中的事件,要从同样位于这个MTrk中的上一事件之后,数够了由自己的DeltaTime所规定的足够的MIDI Tick,然后才被执行(对MetaEvent而言)或发送(对普通Event而言)。第一个MTrk里边一堆的速度改变Meta-Event,也是在和其他MTrk一起播放。

    所以第一个MTrk里的某个速度Meta,在全曲播放当中的某个时间点,被执行了之后,每个MIDI Tick的真实时间间隔就被修改了,从此以后各个MTrk再数MIDI Tick时,真实时间就都变了。

    所以为啥俺说“一点点地顺序遍历文件”,因为程序无法预料到什么时候会有什么事情发生,只能一点点地向后读,碰到什么事件就做什么事。

    还是打比方吧。以下例子是基于您十分了解MIDI文件的“DeltaTime + Event”事件结构的。咱就拿JIANGNAN.MID举例子:

    就说您刚才发的呼呼啦啦这一大段Hex,咱们找到第一个MTrk,也就是您这里用红字所标记出的MTrk,里边包含了n个速度改变事件。咱从第一个MTrk开始庖丁解牛:

(以下解释中,dt代表该事件的DeltaTime。注意DeltaTime使用的是“变长度表示法”,小于0x80的DeltaTime可以认为它就是实际的MIDI Tick数;大于0x80的DeltaTime,需要多个字节进行组合,才能得到真正的MIDI Tick数。具体解释请参考俺那三个帖子。咱再写一个GT,GlobalTime,代表全局MIDI TICK时间轴的时间)

4D 54 72 6B  —— ASCII“MTrk”,这个是MTrk Chunk的头标志
00 00 07 D2  —— 这个是当前MTrk Chunk的大小
00 FF 58 04 04 02 18 08 —— dt=0x00,GT=0。这个是曲子的拍号。所以说曲子的拍号也是可以随时改变的喔~
00 FF 59 02 FE 00 —— dt=0x00,GT=0。这个是曲目的调号,也是可以随时改的~
00 FF 51 03 0D 76 B1 —— dt=0x00,GT=0,第一个速度Meta。
00 FF 06 4E 20 ... 6F 6F 6E —— dt=0x00,GT=0,这是一段文本Meta。FF 06是文本Meta的标记,紧接着的04EH(78D)是数据长度。数一数是不是正好到6E这里?
03 FF 51 03 11 46 2B —— dt=0x03, GT=GT+dt=3,第二个速度Meta,但要等全局TICK时间走到3的时候,才执行这一条Meta(也就是改变曲目速度)。
03 FF 51 03 10 F4 47 —— dt=0x03, GT=GT+dt=6,第三个速度Meta,所以从上一个Event之后又过了三个Tick,才执行这一条Meta,又改变一次速度。
07 FF 51 03 10 A5 5D —— dt=0x07,GT=6+7=13,第四个速度Meta,从上一个Event之后过了7个Tick,变速。
11 FF 51 03 10 0F D8 —— dt=0x11,GT=13+0x11=30。第五个速度Meta。以后依此类推。
03 FF 51 03 0F C8 F3 —— dt=0x03,GT=30+3=33
07 FF 51 03 0F 84 75 —— dt=0x07,GT=33+7=40
0D FF 51 03 0F 42 40 —— dt=0x0D,GT=40+0x0D=53
......

    不再写下去了。门道在哪儿?您看,所有MTrk Chunk都在数着全局的MIDI Tick,总的MIDI Tick时间轴(GT)在一直累加着。在其他的MTrk里均包含如NoteOn、NoteOff等演奏信息,它们也在数着MIDI Tick,看着GT,在等待着到时间之后就发送一条信息。所以,在比如某一段时间里,速度是一个值(随便说一个,比如一个MIDI Tick是100us),那么按照如下举例:

----!!! MTrk.1里碰到了一个FF 51 03 xx xx xx,速度被改成了每个MIDI Tick为100us。
-> MTrk.2里的某一个歌词Meta的DeltaTime是3,那么这个歌词距上一个事件的真实时间间隔就是300us。咱们假定这句歌词是第一句。
-> MTrk.2里下一个事件(不一定是MetaEvent了)的DeltaTime是10,就再过1000us;
-> MTrk.2下一个事件又是歌词Meta,DeltaTime是20,于是距上一个事件就间隔2000us,所以这个第二句歌词同第一句之间间隔1000+2000=3000us。
----!!! 这时MTrk.1里碰到了一个FF 51 03 xx xx xx,速度被改成了每个MIDI Tick为133us了,速度改变了。
-> MTrk.2下一个事件的DeltaTime是10,距上一个事件的真实时间间隔就变成1330us,
-> MTrk.2下一个事件又是歌词Meta,DeltaTime是20,距上一事件间隔2660us,而这句歌词同第二句之间间隔1330+2660=3990us,距第一句歌词间隔3990+3000=6990us。
……

    好了,敲个帖子又花了一上午时间……还不明白的话……俺只能说有空再敲咧……MIDI 0格式文件里边只有一个MTrk,所以MIDI 0的解码最简单,只需要类似流媒体那样顺序读取,不需要在各个MTrk当中跳跃取数。MIDI 1文件的解码就麻烦多了,因为它是在全局统一的时间轴下,各个MTrk自行判断什么时候该处理某个事件,并且各个MTrk里的事件还是采用“距离上一个事件的时间间隔(即DeltaTime)”这种相对而非绝对的时间来计时,所以解码程序需要来来回回地跳跃取数,而且每个MTrk都要有自己的MIDI Tick计时机制和与全局时间或绝对时间的转换机制,解码程序的时间和空间复杂度都要更大。早先的手机和弦铃声,以及早年的琴,都只支持MIDI 0格式而不支持MIDI 1格式,原因也在此。


回复 支持 反对

使用道具 举报

8#
发表于 2016-5-31 10:53:30 | 只看该作者
oukm 发表于 2016-5-30 18:20
谢谢辛苦的回复,你写关于的midi的文档是我网上见过的最通俗易懂的了.
MIDI结构我也是通过《MIDI原理与开发 ...

· 你说的通过cakewalk查看MIDI文件速度视图,我没有看见什么曲线.只看见一条向右移动.

    童鞋,我只能说,这个世界上,有种东西,叫做“缩放”……||-_-



    因为这个曲子的速度大概在72bpm,所以您得利用缩放和滚动条,找到72bpm那附近,才能看到这个曲线……缩放按钮在哪里?cakewalk界面右下角,有那个放大镜图标的,垂直滚动条下边那个是垂直缩放;水平滚动条右边那个是水平缩放。

    至于您说的“一条向右移动(您不觉得这句话有语病吗?宾语在哪里?)”,实际您想说“向右移动的竖线”吧?不好意思俺有点儿轻度强迫症,请谅解。总之吧,这个“黑色的向右移动的竖线”,就是我所说的“全局时间轴上的当前时间点”。这个黑线向右移动,代表播放时的时间在走动。这个时间轴的概念可不只是cakewalk里有,所有音频、视频编辑软件里,都有这个东西。


回复 支持 反对

使用道具 举报

9#
 楼主| 发表于 2016-5-31 16:15:55 | 只看该作者
谢谢非常细致的讲解,终于明白MIDI播放速度是怎么回事了。

以前一直困扰于个这个问题,我最初处理的MIDI文件都设置有几个四分音符速度,但值都是一样的,我就取第一个值,把生成的结果与cakewalk事件列表的时间相比较,精确到秒,大致相同,毫秒级不同以为是计算精度的问题。后来一批MIDI文件四分音符速度不一样,我无奈就
取最后一个值来计算,把生成的结果与cakewalk事件列表的时间相比较似乎又对了,于是产生错觉,以为MIDI只需设置一个速度,其余速度是MIDI制作者无聊随机增加设置的。现在要对程序大动手术了。

“只看见一条向右移动”,这种语句是我的不严谨造成的,请原谅。

---------------------------------------------------------------------------------------------------------------------------------------
“稍微预告一下。这阵子正在写一个MIDI文件的入门指导,把我几个月来摸索MIDI文件得出的一些套路方法和经验结论做一个总结~”
---------------------------------------------------------------------------------------------------------------------------------------
这个让我很期待,能否拜读你的大作。
回复 支持 反对

使用道具 举报

10#
发表于 2016-5-31 16:33:44 | 只看该作者
oukm 发表于 2016-5-31 16:15
谢谢非常细致的讲解,终于明白MIDI播放速度是怎么回事了。

以前一直困扰于个这个问题,我最初处理的MIDI ...

““只看见一条向右移动”,这种语句是我的不严谨造成的,请原谅。”

    哈哈,木事木事~俺是技术宅宅久了,就有点儿吹毛求疵了,对语病等等这种不严谨的事儿总是感觉怪怪的,不过语句的意思都能理解~

““稍微预告一下。这阵子正在写一个MIDI文件的入门指导,把我几个月来摸索MIDI文件得出的一些套路方法和经验结论做一个总结~””

    这个……您可以不必期待咧……那三个帖子好像都是四年以前敲的了,当年立下的Flag,现在已经早就……呃……俗称“太监”了……(x_x)
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 现在注册

本版积分规则

关闭

新闻头条上一条 /1 下一条

【重要通知】|申请友链|Archiver|手机版|第一键盘 - 电子琴信息网 - 电子琴在线论坛 ( 粤ICP备14036084号 )

GMT+8, 2024-6-4 09:24 , Processed in 0.150546 second(s), 32 queries .

Powered by Discuz! X3

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表