【Win 10 应用开发】MIDI 音乐合成——乐理篇
针对 MIDI 音乐的 API ,其实在 Win 8.1 的时候就出现。在UWP中采用了新的驱动模式,MIDI 消息传递更加高效。
首先得说明的是,UWP 的 MIDI 相关 API 不是针对 MIDI 文件的,而是针对 MIDI 设备的,所以它不具备保存 MIDI 文件的功能。当然,如果你想把 MIDI 消息存为音频文件,完全可以自己一个字节一个字节地写入。MIDI 文件分为两个数据块——头部和音轨。头部主要描述音轨类型(单轨或多轨),包含轨道数量,以及计时方式。
MIDI 有两种方式来描述音符时值:
1、Timing Clock:单个四分音符(常规是每四分音符为一拍)的“脉冲时钟数”(PPQ),时间单位Tick,一般为24的倍数。
2、帧率。这个跟视频有点像,比如24帧,30帧等。
计时方式用两个字节表示(16位),如果最高位为0,表示用Tick方式来描述,剩下的15位表示Tick值;如果最高位为1,则表示帧率。
比如,如果用Tick方式表示(常用),第16位必须为0,即 0111 1111 1111 1111。
MIDI 文件除头部外,剩下部分都是音轨数据。每个音轨由一系列事件组成。事件就是MIDI指令。MIDI 文件之所以体积小,是因为它不存储音频数据,只存储指令。比如 Note on 开始播放某个音符,Note off 停止播放某个音符。每个事件都由两段组成:
<delta time><event data>
Delta time 指事件的时间偏移量,它是相对于前一个事件而言的,当然,如果是轨道中的第一个事件(或者是元数据事件),delta time 可以是0。常用的是tick计时方式,比如,文件头中指定每个四分音符的时值为96,那么,假调事件A播放中音1(C),事件B停止播放中音1,如果这个中音1是四分音符,即时值为1拍,两个事件可这样排列:
<0><note on 60><96><note off 60>
60中音1的编码,这个老周后面会说,也就是B事件要在A事件后面,相隔时间为96,1拍。如果是八分音符呢,就是48(半拍)。
<0><note on 60><48><note off 60>
好了,关于 MIDI 文件的信息就说到这里,有兴趣的话,你可以到 midi.org 官方网站去查看相关的规范。老周写了一个读写 MIDI 文件的通用类,功能还未完尚,仅供参考。下载链接在这里。
=====================================================
下面咱们说正题。
UWP 中的 MIDI API 是用于与 MIDI 设备通信的。其实总的来说也就两种设备:输入/输出。输入设备一般来说也就是 MIDI 键盘了。这个我们一般人用不上,买一个的话也不便宜,起码要几百大洋。输出设备可以是专门的MIDI声卡,当然,我们一般的声卡也可以。普通声卡支持MIDI 的通用标准,缺点是音色不太真实。专业声卡再配上软音源就可以模拟出更多乐器的音色,而且质量也高。软音源也不便宜,买一套大概也要一千大洋。
本篇咱们先不说 API 怎么用,很简单,因为微软都封装好了的,直接发送 MIDI 消息就行了,或者从外接的 MIDI 键盘中接收 MIDI 消息。但是,前提是你得有一点乐理知识。要求不高,能看懂简谱的话,就可以了。
简谱头部
在简谱上,标题、副标题这些就不多说了,都能看明白的。在简谱头部,我们主要了解三个标记:
1、调号。比如我们看到许多简谱上会标注 1 = C,意思是中音1的发音是钢琴键盘上的【中央C】键(白键)。调号不理解也无所谓,其实不影响MIDI编程,我们就不需要弄得太复杂了,尤其是大调小调的区分,除非你对音乐有兴趣,可以研究研究。反正就是调越高声音越尖锐,调越低声音越柔和。所以小调一般很适合民歌。
2、拍号:常用的是 4/4,分子为4,表示每四拍为一小节;分母为4,表示一个四分音符为一拍。这是最常见的。比如这样:

前面部分是调号,紧跟着是拍号。
如果是,2/4,表明每两拍为一小节,四分音符为一拍。
3、节奏(节拍):表示每分钟多少拍(BPM)。常见的节奏为120。

表示一分钟 120 拍,所以,每拍的时长为 0.5 秒。
如果是60,表明一分钟60拍,即一秒一拍。

实际上,决定曲子速度的不是拍号,而是节奏。120 的曲子速度自然要比 60 的快。拍号只是确定每个音符的相对时值,标准是四分音符为1拍,那么八分音符就是半拍,十六分音符就是1/4拍,三十二分音符就是1/8拍了。总之都是二次方的,而且分的越小时值越短。
前面提到MIDI文件有 Tick 和帧率两种计时方式,其实计时方式也不会影响曲子的速度(时长),就好比2分钟长的视频,你把帧率从 30 帧改为 15 帧,但视频长度依然是 2 分钟,只是变得不太流畅而已。MIDI 中也一样,速度是由节拍映射(Tempo map)决定的。不同的是,我们简谱中用的是 BPM(每分钟多少拍),而MIDI中用的是微秒,比如,BPM=120,即0.5秒一拍,换算为微秒就是 500000了。
小节
上面咱们提到过,4/4表示每四分音符为一拍,每小节一拍。那小节是啥?在简谱上,用小节线(竖线)来划分小节。请看下面例子。

上面例子中有两个小节,按照拍号的规定,每小节必须是四拍,第一个3是两拍,第二个3是两拍,加起来正好是四拍。所以后面紧跟一条竖线,这根线就是小节线。第二个小节中,中音5是一拍,中音2是一拍,紧接着的中音3、1下面都有一横线,是八分音符,各半拍,加起来正好一拍;最后的低音6是一拍,合起来也是四拍。
再看一个例子。

注意看拍号,2/4表示每四分音符为一拍,但每小节是两拍。比如第一小节,中音1、中音2都是四分音符,各一拍,共两拍,所以构成一个小节。
音符
我们刚刚在简谱上看到的1234567,就是音符,当然这是简谱上的表示法,这种表示法,容易识别。在五线谱中,音符是用“蝌蚪文”来表示的,不容易分别,也不好懂。
顺便说说唱名和音名。这两个东西,很多时候都会搞混。所谓唱名,就是你用嘴巴唱出来的时候发的声,就是
dol re mi fa sol la xi
对应的音符就是 1 2 3 4 5 6 7。这个应该不难,小学生都懂。
音名就是钢琴键盘上那些字母,与唱名对应的是 C D E F G A B。
中国很多乐器(尤其是吹管类)的基本音域都在 1 2 3 5 6 这几个音上,那是因为我们古代的定音方式为“宫,商,角,徽,羽”,有的说是“宫,商,角,徴,羽”,对应的大约是1 2 3 5 6,古人是用“三分损益”法计算音阶的。因此,许多民乐都没有 4 这个音(3和4的音程是半音),比如,巴乌就是个典型。 笛子和洞箫虽然有 4 这个音(放开全部音孔,八孔箫要按住半音孔),但发声相对较弱。其实,像巴乌(葫芦丝)这些乐器也可以通过接中音5以下的音孔来调节出 4 的音,但也是比较弱的。
十二平均律
音阶划分方式很多,比如中国古代有“五度相生”法,五度指纯五度,这个很复杂,老周也说不清楚,不过,我可以总结出一句不太靠谱的话——纯五度的总音程为 3.5 个全音(三个全音,一个半音)。
其他的计算方式不多讲,因为 MIDI 的音阶用的是十二平均律,这是世界普及的,琴键上用的也是十二平均律。其实,十二平均律是中国人发明的,在明朝的时候就出现了,只是当时乐器生产工艺限制,没有人愿意接受这种方式,结果让西方人抢了头功。
十二平均律是以每【半音】来划分的,因此,它可以包含12个音:
1、1#、2、2#、3、4、4#、5、5#、6、6#、7
对应的音名为
C、C#、D、D#、E、F、F#、G、G#、A、A#、B
其中,3和4之间的音程是半音,前一八度的7与后一八度的1之间的音程是半音,其余为全音,比如1和2之间是全音,所以,在1和2之半加一个 1#,表示在1的基础上升半音,因此,1# 和 2b 是同一个位置,1升半音就是 1#,2 降半音是 2b。
文字是说不清楚的,看看这个图你就懂了。

不管白键还是黑键,两个键之间的音程都是半音,你会看到,3 和 4 之间没有黑键,因为 3 和 4 之间的音程就是半音。故 12345 就是所谓的纯五度,因为它们的总音程就是 3.5 个全音。
再看一张更大的图。

这样你就看到规律了,一个八度的键排序是这样的:
黑 黑 黑 黑 黑 ……
-------------------------------------------------------------------------------------------------------------------
白 白 白 白 白 白 白 ……
故而,3和4之间是两个白键,7和1之间是两个白键,因为它们的音程都是半音。
将其替换为十二个音符,就是:
1# 2# 4# 5# 6# ……
-------------------------------------------------------------------------------
1 2 3 4 5 6 7 ……
介绍完音符,咱们还要了解音符的时值,所谓时值,就是音符的相对时间长度。
按照时值不同,可以分为以下几种:
1、全音符。标准情况下是四拍,表示方法为 X - - -。
2、二分音符。标准情况下是二拍,表示方法 X -。
3、四分音符。一拍,表示方法 X。
4、八分音符。半拍,表示方法
。
5、十六分音符。四分之一拍,表示方式
。
6、三十二分音符。八分之一拍,表示方式
。
……
后面就不再分了,时值太短了,你也唱不出来。
当然,也有比较特殊的,比如,三拍时值的音符,也可以表示为 X - -。
好了,只要有了上面这些基本知识,就可以开始 MIDI 编程了。下一篇老周就说说如何向声卡发送 MIDI 消息。本篇就扯到这儿了。
【Win 10 应用开发】MIDI 音乐合成——乐理篇的更多相关文章
- 【Win 10 应用开发】MIDI 音乐合成——音符消息篇
在上一篇中,老周介绍了一些乐理知识,有了那些常识后,进行 MIDI 编程就简单得多了.尽管微软已经把 API 封装好,用起来也很简单,但是,如果你没有相应的音乐知识基础,你是无法进行 MIDI 编程的 ...
- 【Win 10 应用开发】启动远程设备上的应用
这个功能必须在“红石-1”(build 14393)以上的系统版中才能使用,运行在一台设备上的应用,可以通过URI来启动另一台设备上的应用.激活远程应用需要以下前提: 系统必须是build 14393 ...
- 【Win 10 应用开发】导入.pfx证书
这个功能其实并不常用,一般开发较少涉及到证书,不过,简单了解一下还是有必要的. 先来说说制作测试证书的方法,这里老周讲两种方法,可以生成用于测试的.pfx文件. 产生证书,大家都知道有个makecer ...
- 【Win 10应用开发】Adaptive磁贴模板的XML文档结构
在若干天之前,老周给大家讲了Adaptive Toast通知的XML模板,所以相应地,今天老周给大家介绍一下Adaptive磁贴的新XML模板. 同样道理,你依旧可以使用8.1时候的磁贴模板,在win ...
- 【Win 10 应用开发】RTM版的UAP项目解剖
Windows 10 发布后,其实SDK也偷偷地在VS的自定义安装列表中出现了,今天开发人员中心也更新了下载.正式版的SDK在API结构上和以前预览的时候是一样的,只是版本变成10240罢了,所以大家 ...
- 【Win 10应用开发】认识一下UAP项目
Windows 10 SDK预览版需要10030以上版本号的Win 10预览版系统才能使用.之前我安装的9926的系统,然后安装VS 2015 CTP 6,再装Win 10 SDK,但是在新建项目后, ...
- 【Win 10 应用开发】在代码中加载文本资源
记得前一次,老周给大伙,不,小伙伴们介绍了如何填写 .resw 文件,并且在 XAML 中使用 x:Uid 标记来加载.也顺便给大伙儿分析了运行时是如何解析 .resw 文件的. 本来说好了,后续老周 ...
- 【Win 10应用开发】延迟共享
延迟共享是啥呢,这么说吧,就是在应用程序打开共享面板选择共享目标时,不会设置要共享的数据,而是等到共享目标请求数据时,才会发送数据,而且,延迟操作可以在后台进行. 这样说似乎过于抽象,最好的诠释方法, ...
- 【Win 10 应用开发】Toast通知激活应用——前台&后台
老周最近热衷于讲故事,接下来还是讲故事时间. 有人问我:你上大学的时候,有加入过学生会吗?读大学有没有必要加入学生会? 哎哟,这怎么回答呢,从短期来说,加入学生会有点用,至少可以娱乐一下,运气好的话, ...
随机推荐
- CREATE DATABASE RoomReservation
要从我的模型开始构建我的RoomReservation数据库对象,我将创建表对象. 要在SQL Server中创建表,我需要使用CREATE TABLE语句. 使用CREATE TABLE语句,我将能 ...
- 获取 修改 CSS 样式
内联(style里的)样式 element.style.color element.style.getPropertyValue("color") 非内联样式 window.g ...
- PTA 数据结构 银行业务队列简单模拟
仅供参考,请勿粘贴 设某银行有A.B两个业务窗口,且处理业务的速度不一样,其中A窗口处理速度是B窗口的2倍 -- 即当A窗口每处理完2个顾客时,B窗口处理完1个顾客.给定到达银行的顾客序列,请按业务完 ...
- linux系统下解决getch()输入数值不回显示
在linux系统下开发C 程序却会遇到系统不支持conio.h头文件,无法使用getch()不回显函数.下面就演示如何构建函数实现数值输入不回显. #include <stdio.h> # ...
- C# 取Visio模型信息的简易方法
最近的一个项目,要求导出Visio图纸,因为是建筑类的,所以,需要设置墙壁,门,房间等信息的参数. 拿墙壁为例,选中墙壁模型,右键属性,会弹出以下对话框. 需要设置墙长.墙壁厚度等一些列信息. 现在C ...
- 阿里云centos配置postfix
1. 为了防止垃圾邮件,先到域名控制面板设置好. MX A 记录及TXT记录 其中TXT记录如下 @ spf1 a mx ~all 意思就是使用spf1协议,允许a记录和MX记录对应的IP,不允许 ...
- Adobe Audio 分轨录音教程(需要KX,Live机架)
一.需要的硬件和软件 1. 创新5.1声卡或7.1声卡: 2. 已安装KX驱动和Live机架,经过测试安装后需要重启电脑才能生效. 3. 已安装Adobe Audition 3.0 二.测试环境 WI ...
- 学python+django去北京找工作,靠谱吗?
有些朋友说,自己的学习能力还可以.倾向于python加框架,如django,python本来就会一些.不太了解北京公司的情况,想知道现学的python+django在北京找到工作有多少可能性. 要想知 ...
- DataSetToJson 扩展方法
001 using System; 002 using System.Collections.Generic; 003 using System.Linq; 004 using System.Text ...
- 【python】__new__和__init__区别
原文:http://blog.csdn.net/cnmilan/article/details/8849680 __new__:创建对象时调用,返回当前对象的一个实例__init__:创建完对象后调用 ...