C#+Midi 模拟各种乐器演奏

前段时间一时兴起,参考各种资料文档,各种程序代码。

连基本乐理知识都去了解了一些,弄清楚了什么是十二平均律,什么是半音、全音等等,终于弄出了这么个东东,如下图:


其功能就是输入“简谱”就能演奏出优美的旋律。

“连音”奏法一直没办法实现,是较为遗憾的一个事。

程序中的简谱也是有规则的:

  1. 以01234567为基本四分音符,每个音符用英文逗号分开,如:1,2,3,4等,0代表休止符。
  2. 在音符前输入:“+-#!” 加号表示此音升高八度,减号则降八度,井号升半音,叹号降半音。
  3. 在基本音符后加斜杠“/”表示此音时值减一半,半成8分音符,双斜杠则变成16分音符。
  4. 可在以上基础上再加入延音线“-”(减号),一个减号表示延长一倍时值,和简谱里用法一样。
  5. 还可在以上基础上再加入附点音符“.”(英文的句号),作用与简谱一样(允许双附点)。

================================

程序中主要使用的Windows API函数

View Code
/// <summary>
/// 复置midi输出
/// </summary>
/// <param name="handle"></param>
/// <returns></returns>
[DllImport("winmm.dll")]
protected static extern int midiOutReset(int handle);

/// <summary>
/// 向输出端口发送信息
/// </summary>
/// <param name="handle"></param>
/// <param name="message"></param>
/// <returns></returns>
[DllImport("winmm.dll")]
protected static extern int midiOutShortMsg(int handle, int message);
/// <summary>
/// 打开midi输出设备
/// </summary>
/// <param name="handle"></param>
/// <param name="deviceID"></param>
/// <param name="proc"></param>
/// <param name="instance"></param>
/// <param name="flags"></param>
/// <returns></returns>
[DllImport("winmm.dll")]
protected static extern int midiOutOpen(ref int handle, int deviceID,
MidiOutProc proc,
int instance, int flags);

/// <summary>
/// 关闭
/// </summary>
/// <param name="handle"></param>
/// <returns></returns>
[DllImport("winmm.dll")]
protected static extern int midiOutClose(int handle);

最核心的是向midi发送信息的部份,要了解发送指令的格式,请参考百度百科

当打开设备后就可以发送信息了,用的是上面的midiOutShortMsg函数,以下是经过封装的模拟键盘按下或抬起的函数

private void Send(int iStatus, int iChannel, int iData1, int iData2)
{
midiOutShortMsg(hndle, iStatus
| iChannel | (iData1 << 8) | (iData2 << 16));
}
/// <summary>
/// 键盘按下,默认为第一通道
/// </summary>
/// <param name="iData1"></param>
/// <param name="iData2"></param>
public void Note_On(int iData1, int iData2)
{
Note_On(
0, iData1, iData2);
}
public void Note_On(int iChannel, int iData1, int iData2)
{
Send(
0x90, iChannel, iData1, iData2);
}
public void Note_Off(int iData1, int iData2)
{
Note_Off(
0, iData1, iData2);
}
public void Note_Off(int iChannel, int iData1, int iData2)
{
Send(
0x80, iChannel, iData1, iData2);
}

注音看,0x90代表中的9代表键盘按下(开始发声),0代表第一通道,共16个通道,就是说可以有16个乐器同时演奏,iCannel是通道号,iData1是音符代号,0为最低音,127是最高音,钢琴的键盘中央C是60,iData2是音量或力度(我也不是很明白,一盘用100就行了)。这些信息在Send函数中进行运算、移位运算后,得到诸如0x92 48 96 的信息,表示通道3 开始弹奏C2

0x80就表示键盘抬起,作用就是停止发声,一般我们都是用0x90 + 音量为0来实现静音的(具体为什么,忘了,好像是这样的命令能有效减小mid文件的存储长度)

更多命令请百度或谷哥吧,现提供程序及源码下载。

简谱播放器下载

源代码下载(vs2010)

另外本程序引用一CodeProject中一个项目C# MIDI Toolkit部份Api声明的代码,此项目是一个键盘钢琴程序,运行界面如下:

还有还在一个网站找到了一些VB写的钢琴键盘,也很有参考价值。

posted @ 2011-07-02 22:11 缤纷 阅读(1763) 评论(22) 编辑 收藏

 回复 引用 查看   
#1楼 2011-07-02 22:25 雪之无痕      
有点意思
 回复 引用 查看   
#2楼[楼主] 2011-07-02 22:29 缤纷      
@雪之无痕
呵呵,我喜欢做一些有意思的东西。

 回复 引用 查看   
#3楼 2011-07-02 22:33 乱世虾      
呵呵,志同道合,我前一阵子也一直想了解一下C#做midi,找了sourceforge上的MidiSheetMusic源码来看~
 回复 引用 查看   
#4楼 2011-07-02 22:53 ゞ追忆o0ゞ      
楼主太牛了,声音好好听,如果可以界面像VB写的那个程序的话就更牛了,一边弹一边生成楼主记录音符的那种格式,写完最好还可以录音,哈哈。
 回复 引用 查看   
#5楼[楼主] 2011-07-02 23:02 缤纷      
@ゞ追忆o0ゞ
呵呵,需要怎样的功能,以后你们就自己弄了,我代码都传上来了。

 回复 引用 查看   
#6楼 2011-07-02 23:06 拾玄      
支持多声部吗?
 回复 引用 查看   
#7楼 2011-07-02 23:07 拾玄      
呵呵,先支持一下
 回复 引用 查看   
#8楼[楼主] 2011-07-02 23:07 缤纷      
@拾玄
不支持

 回复 引用 查看   
#9楼 2011-07-02 23:18 拾玄      
如果,能读写midi格式文件就便好玩了。
不过那个也要支持多声部。

 回复 引用 查看   
#10楼[楼主] 2011-07-02 23:32 缤纷      
引用拾玄:
如果,能读写midi格式文件就便好玩了。
不过那个也要支持多声部。

这个 C# MIDI Toolkit 支持的,可以打开mid文件,你有兴趣可以下载代码看看。

 回复 引用 查看   
#11楼 2011-07-02 23:39 Create Chen      
前一阵子也想做一个弹钢琴的玩意的, 但没找到比较好的声音素材,呵呵
 回复 引用 查看   
#12楼 2011-07-02 23:41 拾玄      
引用缤纷:
引用拾玄:
如果,能读写midi格式文件就便好玩了。
不过那个也要支持多声部。

这个 C# MIDI Toolkit 支持的,可以打开mid文件,你有兴趣可以下载代码看看。

先谢了,我去看看:)

 回复 引用 查看   
#13楼 2011-07-03 00:18 技术拓荒者      
这个都行,哈哈
 回复 引用 查看   
#14楼 2011-07-03 00:20 技术拓荒者      
厉害,小子
 回复 引用 查看   
#15楼 2011-07-03 07:42 大石头      
推荐++

那么多人说好,都没接个++推荐的

 回复 引用 查看   
#16楼 2011-07-03 09:45 落叶潇潇雨      
很棒!!!
 回复 引用 查看   
#17楼 2011-07-03 12:09 独孤残云      
好有趣啊~
坚决支持 ^ ^

 回复 引用 查看   
#18楼 2011-07-03 13:15 renyu      
真好听,非常好,就是不知道弄这个曲谱
 回复 引用 查看   
#19楼[楼主] 2011-07-03 13:57 缤纷      
引用renyu:真好听,非常好,就是不知道弄这个曲谱

要懂简谱才行的。

 回复 引用 查看   
#20楼 2011-07-03 23:28 reavics      
有意思,顶!
 回复 引用 查看   
#21楼 2012-02-21 13:57 凌_晨      
博主!小弟求助。我有一个测试程序需要实现。有一台midi电子琴,usb接到电脑上,然后按各个按键,需要在测试程序中看到是哪个键按下了,而且力度(音量)有多大。如何实现啊?C#与usb通讯如何实现呢?哪个midi琴没有额外的驱动,直接接到电脑上就行了的。
 回复 引用 查看   
#22楼[楼主] 2012-02-21 16:18 缤纷      
@凌_晨
这个USB通信,我也不清楚呀。