惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

I
Intezer
V
Vulnerabilities – Threatpost
Google Online Security Blog
Google Online Security Blog
T
The Exploit Database - CXSecurity.com
C
CXSECURITY Database RSS Feed - CXSecurity.com
AWS News Blog
AWS News Blog
G
GRAHAM CLULEY
P
Privacy & Cybersecurity Law Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
C
Cybersecurity and Infrastructure Security Agency CISA
N
News | PayPal Newsroom
T
Tenable Blog
Spread Privacy
Spread Privacy
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
S
Secure Thoughts
P
Privacy International News Feed
IT之家
IT之家
Project Zero
Project Zero
T
The Blog of Author Tim Ferriss
Engineering at Meta
Engineering at Meta
大猫的无限游戏
大猫的无限游戏
博客园_首页
GbyAI
GbyAI
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
量子位
雷峰网
雷峰网
Apple Machine Learning Research
Apple Machine Learning Research
Hacker News: Ask HN
Hacker News: Ask HN
Google DeepMind News
Google DeepMind News
MongoDB | Blog
MongoDB | Blog
N
Netflix TechBlog - Medium
Martin Fowler
Martin Fowler
NISL@THU
NISL@THU
I
InfoQ
D
DataBreaches.Net
有赞技术团队
有赞技术团队
K
Kaspersky official blog
Security Latest
Security Latest
The Register - Security
The Register - Security
Hugging Face - Blog
Hugging Face - Blog
S
Security @ Cisco Blogs
P
Proofpoint News Feed
M
MIT News - Artificial intelligence
H
Hackread – Cybersecurity News, Data Breaches, AI and More
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
AI
AI
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
P
Proofpoint News Feed
Security Archives - TechRepublic
Security Archives - TechRepublic
N
News and Events Feed by Topic

博客园 - 缤纷夏日

文件分割合并DOS版 安装vs2017后,RDLC 报表定义具有无法升级的无效目标命名空间 frp+TeamViewer 完美解决TeamViewer5分钟商业提醒 TortoiseGit版本库中某个文件显示问号或叹号的问题解决办法 vs2012调试时,抛出异常的等待时间很慢,原来是QQ电脑管家搞的鬼。 wordpress4.4+版本自动生成一个768w像素缩略图的解决办法 vs2012 与 win7 不兼容的问题 c#+Winform实现自定义的“复制、粘贴”右键快捷菜单,多个控件共享使用一个右键菜单。 自制《要塞:十字军东征》无限金钱修改器 ms Sql 数据库出现 “提供的统计信息流已损坏”的解决办法。 如何让DataGridView根据数据“0”或“1”等值显示为“是”或“否”(复选框的使用) DataGridView 显示和隐藏DataGridViewButtonCell按钮的办法 文件隐藏助手,将一个压缩文件隐藏到图片中 如何让DataGridview控件自动滚动到指定的行或列 为Winform程序中DataGridView控件增加自动显示行号功能 在Excel Vba程序中自制进度条,显示实时进度信息 Winform中的DataGridView控件内容自动保存 地下城守护者2 无限魔法修改器 缤纷影视系统3.0源码开放
C#+Midi 模拟各种乐器演奏
缤纷夏日 · 2011-07-02 · via 博客园 - 缤纷夏日

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

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


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

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

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

  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写的钢琴键盘,也很有参考价值。