精华内容
下载资源
问答
  • 制作音乐 MIDI 文件:midifich.mid,使用 MIDI1 规范。 您可以根据需要制作任意数量的音轨每个轨道需要一个矢量时间(增量时间),一个矢量间距,一个矢量速度。 新功能(23/09/2006): 弯音轮程序变更完整教程 ...
  • midi文件解析

    2017-05-22 15:31:50
    简单移动,描述详细,项目中包含测试midi文件
  • 古筝midi文件

    2013-05-15 10:30:49
    很好听的midi文件,还有很多的midi文件,我会陆续上传的
  • paranoia midi文件

    2013-05-12 13:42:04
    paranoia 调教用单音轨midi文件
  • 关于midi文件的结构说明 ,方便用户读写midi文件,并扩展
  • MIDI文件格式分析

    2012-08-20 19:33:31
    MIDI消息和标准MIDI文件格式剖析及应用.
  • MIDI文件信息

    2012-07-20 15:00:26
    详细介绍MIDID文件格式的相关信息,以及MIDI分为头部和音轨块等....
  • MIDI文件结构简介

    2012-08-20 19:34:36
    读书笔记——MIDI文件结构简介
  • midi文件制作钢琴卷动画。 依存关系 需要Python> = 3.8 Python库: 的OpenCVPython的 美度 其他: R绘制框架 FFmpeg添加音频 安装 要在带有Homebrew的MacOS上安装R和FFmpeg,请执行以下操作: brew install r ...
  • Android解析midi文件

    2013-07-02 19:40:18
    android开发midi文件技术,解析midi文件,有详细的代码,很值得参考!
  • MIDI文件格式.pdf

    2021-10-04 21:30:06
    MIDI文件格式.pdf
  • MIDI消息和标准MIDI文件格式剖析及应用
  • 在将数据上传到此处之前,首先(1)使用数据扫描为伪装成MIDI文件的非MIDI文件,然后(2)使用fdupes检查是否存在重复fdupes (这取决于文件的校验和,而不是文件名)。 。 通常,将分类成其类型的MIDI文件比未分类...
  • midi文件分析dll

    2010-03-11 22:11:49
    midi文件分析的dll,大家知道midi的文件分析十分复杂,这个dll也耗费了作者很多精力,十分值得一用啊。
  • midi文件
  • midi文件转换wav

    2020-04-08 17:58:54
    可以批量进行midi文件转换,具体可看博客https://blog.csdn.net/weixin_42763696/article/details/105393158
  • MIDI文件 很好听

    2013-11-07 23:32:33
    很不错的MIDi文件 虽然比较少 但很实用的
  • MIDI文件头:4d 54 68 64 00 00 00 06 ff ff nn nn dd dd 4d 54 68 64:MThd 00 00 00 06:数据区长度六字节 ff ff:00 00-单音轨;00 01-多个同步音轨;00 10-多个不同步音轨 nn nn:音轨数目(含全局音轨和演奏...

    基础知识

    MIDI文件头:4d 54 68 64 00 00 00 06 ff ff nn nn dd dd
    4d 54 68 64:MThd
    00 00 00 06:数据区长度六字节
    ff ff:00 00-单音轨;00 01-多个同步音轨;00 10-多个不同步音轨
    nn nn:音轨数目(含全局音轨和演奏音轨)
    dd dd:最高位为标记位,0为采用ticks计时,后面的数据为一个4分音符的ticks;1为SMPTE格式计时,后面的数值则是定义每秒中SMTPE帧的数量及每个SMTPE帧的tick
    Mido
    一、使用指导:
    通过pip命令安装:

    pip install mido
    

    推荐使用清华镜像源:

    pip install mido -i https://pypi.tuna.tsinghua.edu.cn/simple
    

    使用前import mido即可
    二、打开
    通过

    mid=mido.MidiFile(“绝对路径或同目录下文件名”)
    

    打开指定midi文件
    每个音轨单独读取指令为`

    track_n=mido.MidiTrack(mid.tracks[n])
    

    (n从0开始)
    track.name可直接获取音轨名称,每个消息可按照下标单个读取
    同时MidiTrack()MidiFile()也可用作新音轨和新文件新建命令

    三、遍历读取
    示例代码:

    import mido
    mid = mido.MidiFile(“test.mid”)
    for i, track in enumerate(mid.tracks):#enumerate():创建索引序列,索引初始为0
        print('Track {}: {}'.format(i, track.name))
        for msg in track:#每个音轨的消息遍历
            print(msg)
    

    每个midi文件由多个音轨组成,mido称音轨为Track,其中Track 0 一般是全局音轨,其后跟随演奏音轨。
    每个音轨包含若干条消息,消息可解释为相应音符,一般在全局音轨中放置元消息(mate massages)来指定mid文件的相关参数(速度/音轨数等)

    mid.length=(以秒为单位的演奏总长度,float)
    
    mid.type=(此midi文件类型)
    

    .is_mate可以返回判定是否是元消息

    消息相关:
    Message(type,note=60,velocity=96,time=480)
    

    消息设定代码(示例)

    track.append(mido.Message(type,note=60,velocity=96,time=480))
    

    type 这个参数确定信号的类型(str)。基本的为note_on作为音符开始,note_off作为音符终止。
    note 这个参数确定音符的音高。60代表中央C,每增加12,音高升高一个八度。
    velocity 这个参数确定音符的音量。0表示静音,127表示最大音量。
    time 这个参数确定消息所在的时间。这个时间以tick为单位,而在mido的默认配置中,1拍中有480个tick。所以要想生成一个长度为1拍的音符,应该设置其time值为480,而不是1。
    注:time用480*n来表示会比较省力
    另注:time是指这条消息与上一条消息的时间差(结尾对结尾)
    四、参数设置
    A音色

    track.append(mido.Message('program_change', program=1, time=0))
    

    其中,program参数确定了这个音轨的音色。
    另注:除了打击乐通道以外,音色的默认值为Piano 1。
    B曲速

    track.append(mido.MetaMessage('set_tempo', tempo=500000, time=0))
    

    其中,tempo参数确定了乐曲的速度。
    tempo 值的含义是每一拍为多少微秒。500000表示每一拍为0.5秒(1us=1e6s),即每分钟120拍。bpm和tempo的换算公式为

    bpm=(6×10^7)/tempo
    

    C设置音轨名称
    音轨名称

    track.append(mido.MetaMessage('track_name', name='Piano', time=0))
    

    其中,name参数确定了音轨的名称。
    五、文件保存

    mid.save(‘路径’)
    
    展开全文
  • 是从收集一组最小单元测试用例midi文件开始的,用于测试标准midi文件解析。 这些测试用例听起来并不漂亮。 只是应该测试SMF Midi标准的功能。 希望在每个测试用例中创建包含最少指令集的测试用例,以测试特定功能或...
  • MIDI.jl:用于处理MIDI文件的Julia库
  • V MIDI文件解析器/播放器 感谢@ spaceface777和@spytheman对sinewave Audio Generator的帮助 :red_heart: 如何使用 : 您具有易于访问的界面,用于解析和播放midi文件: import vmidi midi := vmidi. parse (file)...
  • MIDI文件中的隐写术 隐写术正在研究技术的研究和应用,这些技术允许将消息或对象隐藏在其他被称为载体的内部,以使它们的存在不被察觉。 该脚本是用于学术目的。 该程序将消息隐藏在MIDI文件中。 MIDI文件中有事件...
  • midi 文件C++解析库

    2018-04-10 17:54:23
    解析midi文件的c++库,如何使用看main.cpp,src里面的代码用来创建一个静态库
  • MIDI消息和标准MIDI文件格式剖析及应用.
  • MIDI文件研究

    千次阅读 2015-03-28 16:10:36
    MIDI的相关资料在midi.org网站有下载,基本上最有用的是2个: standard midi file format spec 1.1.pdf (记不清是不是有PDF,也许是网页直接打开,可以把它保存为PDF...在MIDI文件格式里面,有以下内容: 0--i

    MIDI的相关资料在midi.org网站有下载,基本上最有用的是2个:

    standard midi file format spec 1.1.pdf (记不清是不是有PDF,也许是网页直接打开,可以把它保存为PDF,方便随时查看)

    midi message table.pdf

    基本上把这2个文件看懂,就可以掌握MIDI的播放控制了。

    在MIDI文件格式里面,有以下内容:

    0--introduction 

    1 - Sequences, Tracks, Chunks: File Block Structure1.1 - Variable Length Quantity
    1.2 - Files
    1.3 - Chunks

    1.4 - Chunk Types2 - Chunk Descriptions

    2.1 - Header Chunks
    2.2 - MIDI File Formats 0,1 and 22.3 - Track Chunks

    3 - Meta-Events
    3.1 - Meta Event Definitions

    Appendix 1 - MIDI Messages
    Appendix 1.1 - Table of Major MIDI Messages
    Appendix 1.2 - Table of MIDI Controller Messages (Data Bytes)Appendix 1.3 - Table of MIDI Note Numbers
    Appendix 1.4 - General MIDI Instrument Patch Map
    Appendix 1.5 - General MIDI Percussion Key Map

    Appendix 2 - Program Fragments and Example MIDI Files 


    在第一章里,主要讲文件头的格式,这部分很好理解,可以同时用ue打开一个MIDI文件进行对比,很容易识别出文件头各个字节的意义。

    对于变长数量的概念,一开始不太习惯,但自己计算一,二次就能理解了,这样的设计是为了尽可能减少传输的字节数,当接收设备识别到最高位为1的时候,就会知道后面还有一个字节的数据进来,而每次进来的数据只会用它的低7位来表示,所以一个字节能表示0--127,2个字节能表示2的14次方,3个字节能表示21位,最大可以用到4个字节,也就是28个位的二进制数。

    chunk就是数据块的意思,我们一般叫轨道,就是有一个header tag,然后有个长度,然后就跟一堆数据,这些数据的长度是可变的。一般MIDI有一个头类型的轨道,然后跟着内容轨道,有可能有1个,也可能多个。这是在header chunk里面定义,header chunk是最简单的,因为它的长度是固定的,而且它的内容很简单,只有6个字节,第一个是格式,MIDI的格式有3种,分别是0,1,2.格式0的文件只有一个轨道,文件1可以有16个轨道。格式2没有研究过。然后是轨道数。然后是一个叫tick的值,它表示一个四分音符里面包含多少个tick。有时候这个里面不是tick,如果最高位是1的情况下,它采用的是另一种表示时间的方式,这种情况我还没有见到过。

    要理解MIDI,还需要懂一些音乐知识。首先关于这个四分音符的概念,音符分根据它的时间长短,一般分为全音符,半音符,四分之一音符和1/8音符,这些音符不同之处就是他们占用的时间不同,一般一个全音符会占用2秒,然后1/4音符就会占用0.5秒。然后刚才说那个tick就是对时间的计算方式,它把一个音符细分成一些小的时间粒度,通常我们看到的MIDI定义的tick值为120.也就是说在描述某个音符的时间时,可以精确到一个音符的1/120,如果假设一个音符为0.5秒的情况下,一个tick值代表的时间大约是4ms。

    但是现在我们还有一个问题没有解决,就是一个四分音符具体是不是永远都是0.5秒呢?在MIDI的规范里,是可变的,是需要在第一个轨道的开始时就定义好的,如果没有定义,我们也要设置一个默认值。有些文件会在文件的多个地方定义这个值,它要求在音乐进行到某个阶段时动态地挑整这个参数。这个参数在MIDI里面名为tempo值。tempo值通常由3个字节构成。它代表的是一个1/4音符有多少us。

    我刚开始把tick和beat per minute搞混了,一开始我以为在header里面定义的ticks数就是每一分钟里面包含多少个1/4音符,其实BPM是由tempo值决定,因为知道一个1/4音符占用多少us,就可以计算出一分钟里面包含多少个1/4音符。


    然后下面讲一下MIDI的一些主要命令:

    通常MIDI的命令最高位都是1,一般一个命令之前会有一个时间值,这个叫delta time,也就是距离上一个命令的时间差,或者差了多少个ticks,因为MIDI最小时间粒度是tick,而不是我们常用的秒。而且这个时间表达时用多少个字节是不固定的,按照变长度值的方式来表示,也就是说如果你看到一个像0x76这样的数,因为它的最高位不是1,所以这个值只有一个字节。而如果你遇到一个0x87这样的,那么你需要继续取下一个,然后把2者合起来,假设下一个的最高位还是1,那么就要取第三个,甚至第四个。

    MIDI的命令在开始提到的2个文档中都有详细介绍,这里只讲一下个人体会比较深的:

    80,81,82---8e

    这些是关闭音符的命令,注意其中低4位表示MIDI的通道,MIDI通常有16个通道,每一个通道有一种乐器,每个乐器可以输出128种音符,然后可以有128种力度。注意一种乐器可以同时输出多个音符,就像我们弹钢琴一样,可以用3个手指同时按下,同样,释放的时候也可以只放开其中一个。这就是为什么在关闭音符的时候也要指出具体关闭哪个音符,而不能只告诉系统关闭通道。

    90,91,9n

    这些是打开音符的命令,后面同样跟2个参数,就是音符和力度。需要注意的是,为了节约字节,当对某个通道要连续进行打开音符操作的时候,可以把第一个命令字节省略,也就是如果看到:

    90 40 50 00 50 60 00时,意思是首选执行

    90 40 50

    00代表时间差

    然后又是90 50 60

    这样对于那些需要同时输出多个音符的情况是比较省事。


    a0,a1,a2,这些是跟按键的复调有关,还没有细看


    b0,bx,也是比较难理解的,有些重要的用途就是能把所有声音关闭,或者调节音量,还有一些调节踏板,滚轮,推子之类的


    cx,改变音色,一开始我不知道program有音色的意思,所以总是不理解。


    dx  跟 ax有点关系,但又不一样


    ex pitch轮子


    f--以f开头的命令是系统命令,包括歌词,各种文本,版权信息,chunk结束点,tempo值的设定,时间标记,key标记,

    我们最常用的是MIDI的歌词,通常MIDI的歌词是有一个独立的轨道,但这个轨道往往也会夹带一些音符,只是这些音符通常都不发出声音。歌词最重要一个是它的文本,第二重要是它保护的对于的时间点,因为要在正确的时间呈现出来。

    然后MIDI的tempo值也很重要,它决定我们要以什么样的节奏来播放这个曲子。

    然后是时间标记,这里面也涉及到一些音乐概念。最常见的时间标记是4/4,其中做分子的4表示一个小节里面有4个音符,而做分母的那个4表示每个音符是1/4音符的长度。最典型的例子是欢乐颂。在5线谱里面,1/4用实心圆圈来表示��,类似于这样。每个小节之间会用竖线分割,我们会看到每个小节里面有4个这样的音符。

    假如时间标记是3/4的话,那就表示每个小节里面有3个音符,然后每个音符是1/4音符的长度。

    如果是6/8,就会有每个小节有6个音符,每个音符是1/8音符长度,1/8音符是在1/4音符的基础上带一个尾巴。1/8音符因为时间短,往往节奏会比较快,变化多,当然也要结合它的tempo值。


    音调标记:

    音调是一个乐谱里面采用的基准音调,在五线谱里面会在开始的地方注明,最常见的是C大调,它的意思是这首曲的do音在中央C这个键。然后以此类推,re音在D,mi ,fa ,so,la,si分别在E,F,G,A,B这些白键上面。

    我以前一直以为do音必须在C键,后来知道了半音和全音之后,才知道,其实do音可以在任何键,只是如果do音不在C的情况下,要想发出re,mi,fa,so,la这些音的时候不能只用白键,而是要在适当的地方用黑键。

    还有一点容易搞错的就是,不要把C大调和弦和C大调音阶搞混了,C大调和谐指的是同时按下C,E,G三个key,因为中间的E和根音C隔了2个全音,所以发出的声音很明亮,欢快。而如果把E换成Eb,就会变成C minor chord,听起来就会很沉闷,忧郁的感觉。但是C大调音阶更多的是指一首曲子的频域活动范围。

    我之前还有一个疑问,对于C major chord而言,C和E之间的音程是2个全音,可是为什么E,G之间并未相隔2个full note?但是我确认major chord只要求root note和3rd note符合2个full note的要求,并没有规定3rd note和5th note要有2个full note。



    在MIDI的通道10根别的通道有点不一样,这个是专门用来控制打击乐器的,而每个表示音符的位置表示一种打击乐器,打击乐器的列表在文档里面有说明。我开始想不通对于格式0的文件只有一个音频轨道怎么办?后来我明白轨道跟通道是不同的概念,其实轨道也就是chunk,可以控制任何通道,轨道可以只有1个,或者5个,16个,有的可能超过16个,但通道就只有16个。




    展开全文
  • MIDI文件唱歌合成 该脚本依赖于名古屋工业大学的网站,该网站实现了基于HMM的唱歌声音合成系统。 您可以找到与乐器音频合并的样本。 要求 musescore:用于将midi转换为musicxml Python3 安装 pip install midi2...
  • MIDI 文件格式分析

    千次阅读 2017-12-08 18:33:39
    MIDI 文件属于二进制文件,这种文件一般都有如下基本结构: 文件头+数据描述 文件头一般包括文件的类型,因为 Midi 文件仅以.mid 为扩展名的就有 0 类和 1 类两种,而大家熟悉的位 图文件的格式就更多了,所以才会出现...

    MIDI 文件属于二进制文件,这种文件一般都有如下基本结构: 文件头+数据描述

    文件头一般包括文件的类型,因为 Midi 文件仅以.mid 为扩展名的就有 0 类和 1 类两种,而大家熟悉的位 图文件的格式就更多了,所以才会出现文件头这种东西。

    而数据描述部份是主体,我们现在来一起分析它的结构:

    在每个 Midi 文件的开头都有如下内容,它们的十六进制代码为:“4d 54 68 64 00 00 00 06 ff ff nn nn dd dd”。

    前四个是 ASCII 字符“MThd”是用来鉴别是否 Midi 文件,而随后的四个字节是指明文件头描述部分的字节 数,它总是 6,所以一定是“00 00 00 06”,以下是剩余部分的含义:

    ff ff

    指定 Midi 的格式

    00 00

    单音轨

    00 01

    多音轨,且同步。这是最常见的

    00 02

    多音轨,但不同步

    nn nn

    指定轨道数

    实际音轨数加上一个全局的音轨

    dd dd

    指定基本时间

    一般为 120(00 78),即一个四分音符的 tick 数,tick 是 MIDI 中的最小时间单位

    以上就是 MIDI 文件头了,后面的所有内容都是真正做事的,我们先来看看它的构成。

    MIDI 的数据是由若干个格式相同的子数据构成的,这些子数据在多音轨的格式中记录了一个轨道的所有信 息。多加一个音轨,就简单地把数据追加在前一音轨的后面就可以了,不过不要忘记更改文件头中的 nn nn(轨道数)。

    先看全局音轨。全局音轨包括歌曲的附加信息(比如标题和版权)、歌曲速度和系统码(Sysx)等内容。

    不管是全局音轨还是含有音符的音轨,都以“4D 54 72 6B”开头,它其实是 ASCII 字符“MTrk”,其后跟 着一个 4 个字节的整数,它标志了该轨道的字节数,这不包括前面的 4 个字节和本身的 4 个字节。这一点, 我们可以在后面的例子中去理解。

    接着就是记录数据的地方了,每一个数据有着相同的结构:时间差+事件。

    所谓时间差,指的是前一个事件到该事件的时间数,它的单位是 tick(MIDI 的最小时间单位)。它的构成比 较特殊,这里要用二进制来说明。

    一个字节有 8 位,如果仅使用 7 位,它可以表示 0~127 这 128 个数,而剩下的一位,则用来作为标志。如 果要表示的数在以上范围,则这个标志为 0,这时,一个 7 位的字节可以表示 0~127tick。如果要表示的数 超出了这个范围(比如 240),则把标志设置成 1,然后记录下高 7 位,剩下的留给下一个字节,在该例中 240 可以分解成 128*1+112,这里的 1 就是第一个字节要记录的,加上标志位,应该为 10000001,即十六

    进制的 81;而 112 是下一个字节记录的,它的十六进制为 70:所以要表示 240 这个时间,要写成 81 70。 同理,如果要表示 65535tick,则可以先计算出 65535=1282*3+1281*127+1280*127,然后得出结果:83 FF 7F。 由此,我们反过来也可以知道如何确定时间差:只要标志位为 0,则表示结束读取时间差。比如 82 C0 03 表示 1282*2+1281*64+1280*3=40963,如果基本时间为 120,则有 341:043 个四分音符。

    以这种方式记录整数的字节称为动态字节,它根据记录的整数改变自身的长度,这在后面还要用到,所以 必须熟练计算。

    看完了这么麻烦的东西,我们再来看个更麻烦的东西:事件。在这些标准的解释后面,我们会通过一些例子 来进一步掌握这些内容。

    事件大体上可以分为音符、控制器和系统信息这几个种类。对于这些事件,都有统一的表达结构:种类+参 数。

    对于一个音符,由于它的有效范围是 0~127,所以直接用 00~7F 作为“种类”,可以认为是个音符,比如 3C 表示中央 C。而一个音符的最重要的参数是力度(也叫速度:velocity)。比如,3C 64 表示一个力度为十 进制100的中央C音符。

    因为一个字节有 8 位,所以剩余的一位如果置 1,再联合其他的 7 位,则可以表示各种信息。我们暂且无 视一个音轨到底是全局的还是用于记录音符的。它们归根结底都是用来记录各种事件的,只不过有些应出 现在全局音轨比较合乎逻辑而已。既然这样,我们就可以从下面的表来看事件:

    下表中,x 表示音轨 0~F,比如 81 表示松开第二轨的音符。

    种类

    参数(十六进制)

    字节

    含义

    8x

    松开音符

    音符(00~7F):松开的音符

    力度:00~7F

    9x

    按下音符

    音符(00~7F):按下的音符

    力度:00~7F

    Ax

    触后音符
    (Key After Touch)

    音符:00~7F

    力度:00~7F

    Bx

    控制器

    控制器号码:00~7F

    控制器参数:00~7F

    Cx

    改变乐器

    乐器号码:00~7F

    Dx

    触后通道

    值:00~7F

    Ex

    滑音

    音高(Pitch)低位:Pitch mod 128

       

    音高高位:Pitch div 128

    F0

    系统码

    系统码字节数:动态字节

    系统码:不含开头的 F0,但包括结尾的 F7

    FF

    其他格式

    程式种类:00~FF

    数据占用的字节数:动态字节

    数据:个数由上一参数确定

    00~7F

    上次激活格式的参数(8x、9x、Ax、Bx、Cx、Dx、Ex)

    下表详细地列出了 FF 的详细情况,对于字节数由数据决定的情况,表中以“--”表示。

    种类 字 节

    字节 含义
    00 设置轨道音序

    数据 数

    02 音序号 00 00~ FF FF

    01

    歌曲备注 文本信息 --

    音轨文本 文本信息

    02 歌曲版权
    歌曲标题 --

    03

    -- 版权信息

    歌曲标题:用于全局音轨,第一次使用表示主标题,第二次表 示副标题

    音轨名称 -- 音轨名

    04 乐器名称

    -- 音轨文本(同 01/2)

    05歌词 --歌词

    1. 06  标记

    2. 07  开始点

    2F 音轨结束标志

    51 速度

    -- 用文本标记(Marker)

    -- 用文本记录开始点(同 01/2)

    00 无

    03 3字节整数,1个四分音符的微秒数

    58节拍 04分子

    分母:00(1),01(2),02(4),03(8)等

         

    节拍器时钟

    一个四分音符包含的三十二分音符的个数

    59

    调号

    02

    升降号数:-7~-1(降号),0(C),1~7(升号)

    大小调:0(大调),1(小调)

    7F

    音序特定信息

    --

    音序特定信息

    这些就是 MIDI 结构的全部内容

    MIDI 文件格式分析——实践篇

    要书写二进制(十六进制)文件,应该准备好一些工具,比如我自己用的是 VC++, 因为学习 MIDI 格式无非是想写它的软件,既然 VC++可以编辑二进制文件,就将 就着用吧。其次,应该找个可以编辑和播放 MIDI 文件的软件,比如 Cakewalk, 这样就可以开始了。

    首先书写文件头“4d 54 68 64 00 00 00 06”,我们直接写同步多音轨的格式, 先写 1 个音轨,并以 120 为一个音符的基本时间。这样,随后的字节是:“00 0 1 00 01 00 78”。

    现在,如果用 Cakewalk 打开会失败,因为我们指定的音轨数为 1,但是并没有 书写任何音轨,如果改成“00 01 00 00 00 78”再打开,就不会出问题了。所 以,今后如果更改了音轨数,千万不要忘记向“上头”汇报。

    把轨道数改回 01,继续我们的实验。先写音轨的头信息:“4D 54 72 6B”(MT rk),因为我们还不能确定后面有多少字节,所以先把它假设成“00 00 00 00”, 以后再回来改。

    我 们先尝试设置歌曲的速度和节拍等基本信息。假设一个四分音符的时间是半 秒,即 0.5*106 微秒。它的十六进制数是 07A120,再看事件表,设置速度是 51, 但是在其前面必须是 FF,然后它须要 3 个字节作为参数,因此字节数为 03,参 数为“07 A1 20”,也就是“FF 51 03 07 A1 20”。这是事件部分,不要忘记 在其之前有个参数——时间差。这是一开始就应该设置的参数,因此时间差为 0 0。所以,完整的事件应该是“00 FF 51 03 07 A1 20”,我们把这一段追加在 Midi 文件末尾。

    这时先不要急着用 Cakewalk 验证,因为我们还没有向“上 级”报告,没错,把 前面表示字节数的“00 00 00 00”改成“00 00 00 07”,如果用 VC++作为二 进制文件的编辑器,选择了事件后,可以在状态栏看到选择的字节长。保存后, 再用 Cakewalk 打开,就可以看见速度是 120。

    我们再来设置节拍和调号,因为一般用 Cakewalk 新建一个 Midi 会默认地设置成 4/4,C 大调,我们就改设成 6/8,A 大 调。查阅事件表知道,58 和 59 是分别用 来设置节拍和调号的。虽然设置节拍的参数很多,但在现在的系统中,后两个参 数是被忽略的,而且 Cakewalk 还 会对其进行修正。因此,我们只要设置好实际 有用的就可以了。分子是 6,分母是 8,所以第一个参数是 06,第二个参数是 0 3(23=8)。 最后,补上前面的时间差和后面的两个被忽略的参数,它应该是“0 0 FF 58 04 06 03 00 00”;再看调号,A 调有 3 个升号,因此可以这样的事件 可以表示为“00 FF 59 02 03 00”。事实上,大小调是个被忽略的参数。我们 统计一下至今为止事件的字节数,然后更改前面的参数,即把“00 00 00 07” 改成“00 00 00 15”。保存后用 Cakewalk 打开,再进入五线谱窗口,就可以马 上验证了。细心的你可能已经发现,进入五线谱窗口前和平常有些延迟,这是因 为我们并没 有设置好那些可以忽略的字节,而 Cakewalk 就是在对其进行重新验 证,这一点,我们以后再讨论。

    用同样的方法,您可以很容易地设置歌曲的标题和版权,这作为一个练习,在这 里就不多写了。我们现在学习写一个含有音符的轨道。首先您应该知道要做哪些 事:1、写新音轨的信息头;2、向上级汇报多了一个音轨。接下来,我们开始写 入一个简单的音符。

    假 设向第一拍写一个中音 A,这里可能要先说明一下,音符是从 C0 开始一起向 上数的,数到中央 C(C5)是十六进制的 3C,则中音 A 应该为 45,在附件中有详 细的计算方法。我们知道在音乐中一个音符通常有三个属性:音高、力度和时值。 可是我们在事件表中并没有看见有什么可以直接设置音符时值的标志。不错,事 实 上,音符的时值是由按下的时间和松开的时间决定的。我们假设要写入一个 八分音符。它的 Tick 数是四分音符的一半,即 60,十六进制表示成 3C。我们先 来 看看与音符有关的标志。

    在事件表中,9x 是用来打开一个音符,我们这里假设使用第 7 个通道(注意到 M IDI 有 16 个通道(Channel),而第 10 个被默认地用作打击乐,所以,我们在这 个阶段(没有学习 Sysx 之前),先不要使用第 10 个通道),则 9x 中的 x 是 6;再 看它的参数,一个是音符,这里我们写入 45,第二个是力度,我们用 70,因为 是一开始就触发的,所以前面的时间差还是 00。这样我们就在第 5 个通道以力 度 112 按下了一个中音 A。对应的字节描述是“00 96 45 70”。它的时值不用 想都知道一定是 0,这取决于什么时候把它松开。

    特 别地,如果一个音符的力度为 0,则 MIDI 认为用户想松开这个键,因为 9x 已经打开了通道,所以我们直接写入一个带 00 力度的同一音符就可以决定这个 音符 的时值了。根据前面的分析,这个时间差应该是 3C,所以我们在写入 3C 后写上音符 45 和它的力度 00,即“3C 45 00”。统计好字节数并向这一轨的头 信息中更新,然后保存到磁盘,用 Cakewalk 打开并进入事件列表窗口便可以验 证了。

    在这个基础 上,我们再尝试在 A 的后面增加一个四分音符中音#G。因为 96 已经 打开了通道,我们没有必要每次都使用 9x,只要输入事件信息即可。对于中音#

    G,它的十 六进制是 44,相对刚才输入 00 力度的 A 来说时间差为 00,因此可以 表示成“00 44 64”,这里我们已经假设力度为 100;然后是松开它,因为是四 分音符,所以时间差是 78H,别忘记力度是 00,它的字节应表示成“78 44 00”, 做好后面的工作,然后验证看对不对。

    我们再做个稍微复杂一点的实验:在原来的基础上,在同一轨的第一拍加上一个 附点四分中音 D。这里就不能再使用追加的方法了,因为前面的事件已经过了 3 个八分音符的时间,无论再加上什么,都只会发生在后面,所以我们要在前面插 入一些字节。

    9x 已经打开了通道,我们直接在 9x 按下的音符后加上一个音符事件“00 3E 6 4”,这里的 00 显然是个时间差,3E 是中音 D,64 是力度,也就是说,在按下 中音 A 的同时按下了中音 D。我们又按下一个键了,要在什么时候,在哪里松 开才能保证输入的是个附点八分音符呢?首先,它的时值是 3 个八分音符,即 1 80,这里还有一点要注意,180 是个大于 128 的数,它的动态字节就应该表示 成“81 34”,在哪里输入才好呢?如果你觉得在按下 D 后输入,或者在任何什 么地方输入这个时间差,然后再写上“3E 00”可以表示松开的话就完全误解了 时间差的概念。其实,我们只要简单地在松开#G 的时候松开 D 就可以了,所以 应该在末尾补上“00 3E 00”。统计好字节数后到 Cakewalk 中去验证验证吧。

    到目前为此,我们应该可以输入任何形式的音符了,不过 MIDI 除了音符以外, 还可以包括各种控制器和系统码,它们的地位不亚于音符,我们现在马上学习如 何使用控制器。

    控 制器比音符要简单多了,我们尝试在#G 前加入相位控制(Pan),它的十进制 代码是 10,十六进制是 0A,我们将参数设置成 111,即十六进制的 6F。首 先查 得控制器是 Bx,这里的 x 和上面一样,也是 6。接下来写入控制器号 0A,然后 是参数 6F,别忘了前面的时间差是 00。所以这段字节是“00 B6 0A 6F”,它应 放在松开#G 的事件之前,与按下#G 同时。不过,一旦使用了非音符,而后面还 有音符事件时,则必须重新通知打开音符,这说起来复杂,做起来还 是比较容 易的,我们只要稍微改写下一个音符事件即可:原本是“时间差+音符+力度”, 我们加入一个打开音符的标志,成为“时间差+9x+音符+力度”即 可。校验过头 信息后,去 Cakewalk 中进行更进一步的检验便知它的可行。

    其实,时间差为 00 的控制事件如果出现的时间也是 00,则在 Cakewalk 中会尽 可能地把它们放在轨道信息中,而不在事件列表中重复。我们可以利用这一点给 音轨设置初始乐器和音量,这就作为一个练习,在此就不再说明了。

    至 于其他的诸如触后键等与控制器类似的格式在此就不多说了。在这里有必要 提醒的是滑音。滑音的乐理范围是-8192~8191,但是在使用时参数是个正数, 比如要设置成 0,则应该是 0-(-8192)=8192,它才是参数。8192 的 7 位双字节 表示成“8192 mod 128=00H;8192 div 128=40H”。如果时间差是 00,则应表 示成“00 E6 00 40”

    最 后我们看看系统码。系统码的构成本来是“F0 厂家 ID 设备号码 格式代码 传送命令 具体参数 F7”,而在文件中,则不以开头的“F0”为系统码,而字节 数也仅记录剩余的系统码,比如 XG 的复位码是“F0 43 10 4C 00 00 7E 00 F7”, 则在文件中应写成“00 F0 08 43 10 4C 00 00 7E 00 F7”,其中第一个 00 是 时间差,F0 是系统码标志,08 是后面的字节数。有一点要注意的是,几个系统 码不可以写在一起,比如“00 F0 0D 43 10 4C 00 00 7E 00 F7 F0 AA BB CC F7”或“00 F0 0C 43 10 4C 00 00 7E 00 F7 AA BB CC F7”都是不好的写法。 如果存在以上系统码集,可以分成两个事件:“00 F0 08 43 10 4C 00 00 7E 0 0 F7 00 F0 04 AA BB CC F7”

    当然系统码可以写在任何音轨,不过一般我们会考虑把歌曲播放前发送的系统码 写在全局音轨中,并把时间差设成 00。

    作为一个参考,这里再附上一个 MIDI 样本。

    虽 然我们只讨论了同步多音轨的格式,其实对于其他两种,比如较常见的单音 轨格式,所有的事件只写在一个音轨中,即只要存在一个“MTrk”就足够了。而 相对 地,用于记录音轨数的两个字节也永远为“00 01”,连续事件如果出现的 通道不同,也必须重新指定通道(8x~Ex)。在此不详细讨论了。

    到目前为此,我们应该可以构造出任何 MIDI 音乐了,作为一些辅助性的参考, 可以查阅下一篇连载《MIDI 文件格式分析——附件篇》。另外,对于扩展名为. rmi 的格式,可以参阅下下篇连载《MIDI 文件格式分析——RMI 篇》。

    MIDI 文件格式分析——附件篇 该文档是前两编的补充,主要讲述以下内容: 音符十六进制的计算
    关于乐器选择

    RPN 和 NRPN
    在 MIDI 中,中央 C 是 C5,最低音是 C0,最高音是 G5,要计算任何 一个音符对应的十六进制,可以使用这个公式:
    假设音符是 NO,表示第 O 八度的音名 N,比如 G2 中,N 为 G,O 为 2, 则它的十进制为 O*12+N,N 的值为了简便起见,用下表给出:

    这样 G2 的十进制值为 2*12+7=31,十六进制为 1F。 若知道音符的十六进制,也可以很容易求出音符,比如 64(16)=100(1 0),
    而 100 div 12=8,100 mod 12=4,对应音符为 E8。写成公式就是: N=B mod 12;O=B div 12;(设 B 为表示音符的字节的十进制数)
    乐 器是 MIDI 中比较重要的因素,要选择所有的乐器不仅仅只是使用 Cx 号标志就能完成的,还必须结合 BankSelect(乐队选择),而 Ban kSelect 其实是由 0 号控制器和 32 号控制器完成的,它们的十六进 制代码分别是 00 和 20.比如要选择出 XG 标准中的 Slow Violin,它 在第 08H 个乐队中的第 28H 号乐器中,所以它的完整代码应为“00 B0 00 00 00 20 08 00 C0 28”。我们来分析它的构成:这里我们假 设时间差为 00,所有信息都发给通道 00,所以第一个 00 是时间差, B0 是打开控制器的标志,并指定发送到通道 00,接下来的 00 00, 是由控制器号 00 和控制器参数 00 构成的,它事实上是表示 0 号控制 器的参数为 0,即 BankSelect-MSB 的参数为 0,然后是下一个事件, 它 是“00 20 08”,即时间差是 00,使用 20H 号控制器,参数为 0 8H,即 BankSelect-LSB 的参数是 08H,这样就指定了 Bank(乐队)。 再下来就是 “00 C0 28”,就是所谓的 Patch Change 事件了,它的 时间差为 00,参数是 28H。这样就完成了标准的乐器选择。

    事实上,它是由三个事件共同完成的,如果某次选择乐器和上次的乐 器有共同的参数,可以不必重复使用相关的 X 作。

    在 本例中,您可能发现了一点,当连续使用同类 X 作时可以不必每 次指定 X 作种类,比如这里的连续再次使用控制器,所以第二个控制 器并没有使用 B0 作为标志,而 是直接使用控制器号码和它的参数。 这一点和音符是一样的。其实,如果连续使用 Patch Change 事件(我 是说如果),则也可不必每次都写 Cx,打开了一次就可以了;不过就 Patch Change 事件而言,连续地更换乐器的结果是仅最后一个有效 而已。

    在前面的文档中并没有提及 RPN 和 NRPN,其实它们是由四个连续的 控制器来实现的。我们假设要使用 RPN 事件的 Coarse Turning,它 的参数假设是 4096,则它的字节是“00 B0 65 00 00 64 02 00 06 20 00 26 00”,我们来分析这段字节:首先我们先看看 RPN 是由哪 四个控制器组成的——首先设置 RPN-MSB 和 RPN-LSB,分别对应的控 制器是 65H 和 64H,Coarse Turning 的 RPN 码是 2,所以 MSB 为 0, LSB 为 2;然后是设置 Data Entry MSB 和 Data Entry LSB,对应的 控制器是 06H 和 26H,而 4096 div 128=32,4096 mod 128=0,对应 的十六进制数分别是 20H 和 00H。因此就构成了上面的字节。而 NRP N 和 RPN 原理是一样的,只不过不用 RPN-MSB 和 RPN- LSB,而改用 N

    RPN-MSB 和 NRPN-LSB 而已,它们对应的十六进制数分别为 63H 和 62 H。 


    转载自:http://blog.sina.com.cn/s/blog_6f72ff900101f95b.html

    展开全文
  • 模块化库,用于使用Go读取和写入MIDI消息和MIDI文件。 注意:如果您正在Github上阅读此文件,请注意,该存储库已移至Gitlab(gitlab.com/gomidi/midi),并且这只是一面镜子。 Go版本:> = 1.14 操作系统/体系...
  • 纯vb代码播放资源文件里的MIDI文件,不调用控件、不调用dll。不用生成midi的临时文件。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 21,360
精华内容 8,544
关键字:

如何制作midi文件