7

我为我的生日买了一个 MIDI 键盘。我找到了一个程序(MidiPiano),它从 MIDI 输入中获取信号并将其转换为音乐,但我更愿意自己编写一个。

我在哪里可以找到执行此类任务的文档?MIDI 协议有据可查,但 MIDI 端口却没有。

我检查了 CodeProject 中的两个项目(Project MIDI 和 C# MIDI Toolkit),但花了很多时间都没有接近我的目标。

对项目的引用会很好,但请仅使用 C#。

4

6 回答 6

7

您需要包装http://msdn.microsoft.com/en-us/library/dd757277(VS.85).aspx中列出的所有所需功能

如果您只是使用短消息,这并不太难,如果您想做 SysEx 或输出流,事情会变得有点复杂。

基本输入端口所需要做的就是获取有效的输入 ID (InputCount -1),将有效的 ID 传递给 Open,启动输入,通过委托接收消息...停止输入,然后最后关闭它。这是一个非常粗略的示例,说明如何实现这一点 - 您需要进行一些检查并注意端口在关闭之前没有被收集,并且关闭的回调已经发生,否则您将冻结您的系统!

祝你好运!

命名空间 MIDI
{
    公共类输入端口
    {
        私有 NativeMethods.MidiInProc midiInProc;
        私有 IntPtr 句柄;

        公共输入端口()
        {
            midiInProc = new NativeMethods.MidiInProc(MidiProc);
            句柄 = IntPtr.Zero;
        }

        公共静态 int InputCount
        {
            获取 { 返回 NativeMethods.midiInGetNumDevs(); }
        }

        公共布尔关闭()
        {
            布尔结果 = NativeMethods.midiInClose(handle)
                == NativeMethods.MMSYSERR_NOERROR;
            句柄 = IntPtr.Zero;
            返回结果;
        }

        公共布尔打开(int id)
        {
            返回 NativeMethods.midiInOpen(
                出手柄,
                ID,
                midiInProc,
                IntPtr. 零,
                NativeMethods.CALLBACK_FUNCTION)
                    == NativeMethods.MMSYSERR_NOERROR;
        }

        公共布尔开始()
        {
            返回 NativeMethods.midiInStart(句柄)
                == NativeMethods.MMSYSERR_NOERROR;
        }

        公共布尔停止()
        {
            返回 NativeMethods.midiInStop(句柄)
                == NativeMethods.MMSYSERR_NOERROR;
        }

        私人无效MidiProc(IntPtr hMidiIn,
            诠释 wMsg,
            IntPtr dwInstance,
            int dwParam1,
            int dwParam2)
        {
            // 在这里接收消息
        }
    }

    内部静态类 NativeMethods
    {
        内部常量 int MMSYSERR_NOERROR = 0;
        内部常量 int CALLBACK_FUNCTION = 0x00030000;

        内部委托无效 MidiInProc(
            IntPtr hMidiIn,
            诠释 wMsg,
            IntPtr dwInstance,
            int dwParam1,
            int dwParam2);

        [DLLImport("winmm.dll")]
        内部静态外部 int midiInGetNumDevs();

        [DLLImport("winmm.dll")]
        内部静态外部 int midiInClose(
            IntPtr hMidiIn);

        [DLLImport("winmm.dll")]
        内部静态外部 int midiInOpen(
            出 IntPtr lphMidiIn,
            int uDeviceID,
            MidiInProc dwCallback,
            IntPtr dwCallbackInstance,
            int dwFlags);

        [DLLImport("winmm.dll")]
        内部静态外部 int midiInStart(
            IntPtr hMidiIn);

        [DLLImport("winmm.dll")]
        内部静态外部 int midiInStop(
            IntPtr hMidiIn);
    }
}
于 2010-01-02T21:00:49.693 回答
2

我也找不到太多,但就像 Josh 说的,Carl 确实在 MIDI 方面做了很多工作,所以也许给他发一封电子邮件……他甚至可以回复,但他通常是 VB.Net 人,所以除非有人将他的东西移植到 C#?

对于其他一些看起来很有希望的参考资料......

如果您正在寻找纯 C# 解决方案……请查看Alvas.Audio。对于您的要求,它看起来确实有点高端,但可能会有所帮助。

也可能是项目midi

于 2010-01-02T16:15:48.363 回答
2

我只是在 c# midi 通信系统的开发过程中。Sanford 的 midi 工具包很好,但 Leslie 的实现有很多改进,这使得代码的可读性降低。我的代码尽可能简单。如果你愿意,可以加入我。几天后,我发布了完全工作的 MIDI 监视器。看看http://puremidi.codeplex.com/

于 2011-03-18T22:15:53.453 回答
1

使用 C# Midi Toolkit 从键盘接收 midi 信息(连接到声卡的 midi 输入端口)。要创建音频(音乐或音调),您需要生成连续的数字音频数据流。您可以从 C# Synth Toolkit(与 midi 工具包的作者相同)开始编写您自己的合成器。

但您也可以下载免费(开源)音序器程序(例如 Audacity)并使用 VST 乐器插件为您完成这项工作。网络上有很多免费的插件。

于 2010-02-18T08:35:39.957 回答
0

我已经通过编写 Python 脚本以在 MIDI 键盘上每次出现音符 ON/OFF 时传输 UDP 数据包的方式解决了这个问题。

使用 C#/.NET 在 Unity3D 中接收 TCP/IP/UDP 上的 MIDI

这样,平台特定的 MIDI 内容就被包装了,我可以编写与平台无关的 C# 代码来获取 UDP 数据包。

于 2014-02-21T11:49:51.293 回答
0

使用DryWetMIDI,您可以使用以下代码从 MIDI 端口获取事件:

namespace InputDeviceExample
{
    class Program
    {
        private static IInputDevice _inputDevice;

        static void Main(string[] args)
        {
            _inputDevice = InputDevice.GetByName("Some MIDI device");
            _inputDevice.EventReceived += OnEventReceived;
            _inputDevice.StartEventsListening();

            Console.WriteLine("Input device is listening for events. Press any key to exit...");
            Console.ReadKey();

            (_inputDevice as IDisposable)?.Dispose();
        }

        private static void OnEventReceived(object sender, MidiEventReceivedEventArgs e)
        {
            var midiDevice = (MidiDevice)sender;
            Console.WriteLine($"Event received from '{midiDevice.Name}' at {DateTime.Now}: {e.Event}");
        }
    }
}

您可以在库文档的设备部分找到更多信息。

于 2020-08-21T15:58:20.590 回答