用Mido简单玩MIDI音乐——简介
Kelmory 2/21/2022 乐理MIDIPythonMido
这篇文章主要讨论如何通过 Mido 简单播放音乐以及一些基础的乐理知识
# MIDI
MIDI是一种音乐的数字乐器接口协议,通过音符的播放模拟演奏音乐。经过很多年的发展,MIDI已经有了一定的作曲承载能力。现在,通过MIDI也可以模拟很多有清晰曲谱的古典音乐,在Kaggle上也有了不少MIDI数据集。
# MIDO
Mido是python的一个MIDI包,提供统一的MIDI控制接口,最主要的方式是向MIDI文件中的不同音轨添加音符,或者打开接口后发送控制信息实时播放。Mido的API比较直观,使用也比较方便,足够覆盖大多数的使用情景。
# Mido的安装
首先放官网:
- 源代码:https://github.com/mido/mido
- 文档:https://mido.readthedocs.io/en/latest/index.html
Mido 需要 Python 2.7+ / 3.6+,安装很简单:
$ pip install mido
Mido本身并不直接控制MIDI的解析、播放,而是需要其他库控制,这些库被称为mido的后端,目前支持rtmidi、pygame等。默认情况下,使用rtmidi作为后端。安装也很简单:
$ pip install python-rtmidi
安装完成后我们就可以开始愉快的玩耍了。
# Midi的基础概念
要认识mido,就需要首先了解MIDI的一些标准。在查阅了一些MIDI标准的文件后,简单总结下 MIDI 1.1 的一些特性,以便理解mido的设计:
- MIDI是由一串字节组成,采用了变长记录的设计,用以平衡长短音符的占用;变长数据通过32bit记录数据块长度;每单位数据由大端法表示,即最高有效位在前。
- MIDI中数据组织的基本单位是块(chunk),分为header和track块;
- header块主要记录整个文件的元信息,包括长度、track块数量、格式(与音轨有关)、切分(division);
- 关于division的含义有两种表示,根据最高位区分:
- 表示一个音符的切分量,例如division为96表示四分音符用96 ticks,八分音符的时长即为48 ticks;
- 负数表示一秒的帧数,再表示每帧的tick数;
- 关于division的含义有两种表示,根据最高位区分:
- track块用于记录一个音轨中的所有事件,MIDI通过事件(event)控制音符的变化,如演奏某个音符或停止等;
- 每个event都带有一个自开始的offset时间和事件;
- 事件分为:MIDI事件,系统外事件(sysex)和元事件;
- 每个event都带有一个自开始的offset时间和事件;
- header块主要记录整个文件的元信息,包括长度、track块数量、格式(与音轨有关)、切分(division);
- MIDI使用序号对照音符,共128个音符,覆盖C-1到G9,已经超过了常见钢琴的88个音。
- MIDI有16个channel,可以理解为不同乐器的载体,通过调整channel的音色可以进行简单的配器。其中,channel 10用于记录打击乐。
# MIDI标准的信息表
MIDI音符对应表:
MIDI音色表:
PC# | Family | PC# | Family |
---|---|---|---|
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 |
41-48 | Strings | 105-112 | Ethnic |
49-56 | Ensemble | 113-120 | Percussive |
57-64 | Brass | 121-128 | Sound Effects |
# Mido基本概念
Mido通过名为Message
的对象控制midi后端,基本的原理是向后端的port或者文件发送MIDI事件,以控制实时的或是文件上的输出。在MIDI支持的事件集中,Mido仅有选择性的支持其中的一部分最常用的。
此处简单记录Message的效果,更多详细信息可以参考:
- Mido文档 - Message Types (opens new window)
- Mido文档 - 元信息事件 (opens new window)
- MIDI 1.1 标准 (opens new window)
Message名 | 参数/属性 | 备注 |
---|---|---|
note_off | channel note velocity | 释放某个音符 |
note_on | channel note velocity | 按下某个音符 |
polytouch | channel note value | 在按下音符后改变按下的压力 |
control_change | channel control value | 改变控制器 |
program_change | channel program | 改变音色 |
aftertouch | channel value | 将某条音轨上的所有音符的按压力度改变 |
pitchwheel | channel pitch | 改变某条音轨的变调 |
sysex | data | 用于MIDI系统外的信息传递 |
quarter_frame | frame_type frame_value | |
songpos | pos | 记录歌曲开始的MIDI节拍的位置 |
song_select | song | 选择播放的序列或歌曲 |
tune_request | 用于调整和弦 | |
clock | 用于同步音频的节拍 | |
start | 控制音符播放,clock会附带 | |
continue | 控制音符继续播放 | |
stop | 结束播放 | |
active_sensing | 可用于连接检测 | |
reset | 重置所有状态 |
# Next Step
有了以上的信息,我们就可以开始尝试各种通过程序控制的作曲方法了。