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

  • 相关阅读:
    将在线图片转换成base64踩坑记录及静态资源跨域及缓存的处理
    MySQL大表拆分多个表的方式(横向拆分和纵向拆分)及如何解决跨表查询效率问题
    electron-vue项目打包踩坑指南
    如何在npm上发布vue插件
    MVC之前的那点事儿系列(9):MVC如何在Pipeline中接管请求的?
    MVC之前的那点事儿系列(8):UrlRouting的理解
    MVC之前的那点事儿系列(7):WebActivator的实现原理详解
    MVC之前的那点事儿系列(6):动态注册HttpModule
    MVC之前的那点事儿系列(5):Http Pipeline详细分析(下)
    MVC之前的那点事儿系列(4):Http Pipeline详细分析(上)
  • 原文地址:https://www.cnblogs.com/gxlxzys/p/2096497.html
Copyright © 2020-2023  润新知