使用C#播放MIDI声音的最佳方式

我正在尝试重建一个旧的节拍器应用程序,该应用程序最初使用C ++中的MFC编写,使用C#.NET编写。 我遇到的一个问题是播放用于表示节拍器“点击”的midi文件。

我在网上发现了一些关于在.NET中播放MIDI文章,但是大多数文章似乎依赖于有人拼凑在一起并提供的自定义库。 我并不反对使用这些,但我宁愿自己理解这是如何完成的,因为它似乎应该是一个非常微不足道的练习。

那么,我错过了什么吗? 或者在.NET应用程序中使用MIDI是否很困难?

我想你需要p / invoke到windows api才能从.net播放midi文件。

这个代码项目文章很好地解释了如何执行此操作: vb.net文章播放midi文件

要重写这个是c#,你需要mciSendString的以下import语句:

 [DllImport("winmm.dll")] static extern Int32 mciSendString(String command, StringBuilder buffer, Int32 bufferSize, IntPtr hwndCallback); 

希望这有帮助,祝你好运!

我目前正在开发一个C#MIDI应用程序,其他人都是对的 – 你需要使用p / invoke来实现这个目的。 我正在自己动手,因为它似乎更适合应用程序(我只需要一小部分MIDIfunction),但为了您的目的, C#MIDI工具包可能更适合。 它至少是我找到的最好的.NET MIDI库,我在开始项目之前进行了广泛的搜索。

midi-dot-net让我在几分钟内完成并运行 – 轻量级,适合我的家庭项目。 它也可以在GitHub上找到 。 (不要与前面提到的MIDI.NET混淆,后者看起来很有前景,我从来没有接触到它。)

当然, NAudio (上面也提到过)有很多function,但就像原版海报一样,我只想播放一些笔记并快速阅读和理解源代码。

我不能声称对它有太多的了解,但我认为这并不是那么简单 – DotNetRocks成名的Carl Franklin已经做了很多 – 你见过他的DNRTV吗?

您可以使用媒体播放器:

 using WMPLib; //... WindowsMediaPlayer wmp = new WindowsMediaPlayer(); wmp.URL = Path.Combine(Application.StartupPath ,"Resources/mymidi1.mid"); wmp.controls.play(); 

最近增加的是支持Midi Ports,Midi Files和SysEx的MIDI.NET。

System.Media。 SoundPlayer是播放WAV文件的一种简单方法。 WAV文件比MIDI有一些优势,其中之一就是你可以精确控制每个乐器的声音(而不是依赖于计算机的内置合成器)。

对于.NET中广泛的MIDI和Wave操作,我认为放下NAudio是解决方案(也可通过NuGet获得 )。

对不起这个问题现在有点旧了 ,但以下对我有用 (有点复制从Win32 – Midi循环使用MCISendString ):

 [DllImport("winmm.dll")] static extern Int32 mciSendString(String command, StringBuilder buffer, Int32 bufferSize, IntPtr hwndCallback); public static void playMidi(String fileName, String alias) { mciSendString("open " + fileName + " type sequencer alias " + alias, new StringBuilder(), 0, new IntPtr()); mciSendString("play " + alias, new StringBuilder(), 0, new IntPtr()); } public static void stopMidi(String alias) { mciSendString("stop " + alias, null, 0, new IntPtr()); mciSendString("close " + alias, null, 0, new IntPtr()); } 

这里给出了完整的命令字符串列表。 关于这个很酷的部分是除了音序器之外你可以使用不同的东西来播放不同的东西 ,例如waveaudio用于播放.wav文件。 我无法弄清楚如何让它玩.mp3虽然。

另请注意,stop和close命令必须在发送open和play命令的同一线程上发送,否则它们将无效并且文件将保持打开状态。 例如:

 [DllImport("winmm.dll")] static extern Int32 mciSendString(String command, StringBuilder buffer, Int32 bufferSize, IntPtr hwndCallback); public static Dictionary playingMidi = new Dictionary(); public static void PlayMidi(String fileName, String alias) { if (playingMidi.ContainsKey(alias)) throw new Exception("Midi with alias '" + alias + "' is already playing"); playingMidi.Add(alias, false); Thread stoppingThread = new Thread(() => { StartAndStopMidiWithDelay(fileName, alias); }); stoppingThread.Start(); } public static void StopMidiFromOtherThread(String alias) { if (!playingMidi.ContainsKey(alias)) return; playingMidi[alias] = true; } public static bool isPlaying(String alias) { return playingMidi.ContainsKey(alias); } private static void StartAndStopMidiWithDelay(String fileName, String alias) { mciSendString("open " + fileName + " type sequencer alias " + alias, null, 0, new IntPtr()); mciSendString("play " + alias, null, 0, new IntPtr()); StringBuilder result = new StringBuilder(100); mciSendString("set " + alias + " time format milliseconds", null, 0, new IntPtr()); mciSendString("status " + alias + " length", result, 100, new IntPtr()); int midiLengthInMilliseconds; Int32.TryParse(result.ToString(), out midiLengthInMilliseconds); Stopwatch timer = new Stopwatch(); timer.Start(); while(timer.ElapsedMilliseconds < midiLengthInMilliseconds && !playingMidi[alias]) { } timer.Stop(); StopMidi(alias); } private static void StopMidi(String alias) { if (!playingMidi.ContainsKey(alias)) throw new Exception("Midi with alias '" + alias + "' is already stopped"); // Execute calls to close and stop the player, on the same thread as the play and open calls mciSendString("stop " + alias, null, 0, new IntPtr()); mciSendString("close " + alias, null, 0, new IntPtr()); playingMidi.Remove(alias); }