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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8763/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-07-31 17:20:04  来源:igfitidea点击:

Best way to play MIDI sounds using C#

提问by jerhinesmith

I'm trying to rebuild an old metronome application that was originally written using MFCin C++ to be written in .NETusing C#. One of the issues I'm running into is playing the midi files that are used to represent the metronome "clicks".

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

I've found a few articles online about playing MIDIin .NET, but most of them seem to rely on custom libraries that someone has cobbled together and made available. I'm not averse to using these, but I'd rather understand for myself how this is being done, since it seems like it shouldbe a mostly trivial exercise.

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

So, am I missing something? Or is it just difficult to use MIDI inside of a .NET application?

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

采纳答案by John Sibly

I think you'll need to p/invoke out to the windows api to be able to play midi files from .net.

我认为您需要调用/调用 windows api 才能从 .net 播放 midi 文件。

This codeproject article does a good job on explaining how to do this: vb.net article to play midi files

这篇 codeproject 文章很好地解释了如何执行此操作: vb.net 文章播放 midi 文件

To rewrite this is c# you'd need the following import statement for mciSendString:

要重写这是 c#,您需要以下 mciSendString 的导入语句:

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

Hope this helps - good luck!

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

回答by Whisk

I can't claim to know much about it, but I don't think it's that straightforward - Carl Franklin of DotNetRocksfame has done a fair bit with it - have you seen his DNRTV?

我不能声称对此了解很多,但我认为它没有那么简单——DotNetRocks名声中的卡尔富兰克林对此做了很多——你看过他的 DNRTV吗?

回答by Kjetil Limkj?r

I'm working on a C# MIDI application at the moment, and the others are right - you need to use p/invoke for this. I'm rolling my own as that seemed more appropriate for the application (I only need a small subset of MIDI functionality), but for your purposes the C# MIDI Toolkitmight be a better fit. It is at least the best .NET MIDI library I found, and I searched extensively before starting the project.

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

回答by MusiGenesis

System.Media.SoundPlayeris a good, simple way of playing WAV files. WAV files have some advantages over MIDI, one of them being that you can control precisely what each instrument sounds like (rather than relying on the computer's built-in synthesizer).

系统.媒体。SoundPlayer是一种播放 WAV 文件的好方法。WAV 文件比 MIDI 有一些优势,其中之一是您可以精确控制每种乐器的声音(而不是依赖计算机的内置合成器)。

回答by Carra

You can use the media player:

您可以使用媒体播放器:

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

回答by Shimmy Weitzhandler

For extensive MIDI and Wave manipulation in .NET, I think hands down NAudiois the solution (Also available via NuGet).

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

回答by obiwanjacobi

A recent addition is MIDI.NETthat supports Midi Ports, Midi Files and SysEx.

最近添加的是MIDI.NET,它支持 Midi 端口、Midi 文件和 SysEx。

回答by Phylliida

Sorry this question is a little old now, but the following worked for me (somewhat copied from Win32 - Midi looping with MCISendString):

对不起,这个问题现在有点老了,但以下对我有用(有点从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());
}

A full listing of command strings is given here. The cool part about this is you can just use different things besides sequencer to play different things, say waveaudio for playing .wav files. I can't figure out how to get it to play .mp3 though.

此处给出了命令字符串的完整列表。关于这个很酷的部分是你可以使用除了音序器之外的不同东西来播放不同的东西,比如用于播放 .wav 文件的 waveaudio。我不知道如何让它播放 .mp3。

Also, note that the stop and close command must be sent on the same thread that the open and play commands were sent on, otherwise they will have no effect and the file will remain open. For example:

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

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

public static Dictionary<String, bool> playingMidi = new Dictionary<String, bool>();

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);
}

回答by Paul Williams

midi-dot-netgot me up and running in minutes - lightweight and right-sized for my home project. It's also available on GitHub. (Not to be confused with the previously mentioned MIDI.NET, which also looks promising, I just never got around to it.)

midi-dot-net让我在几分钟内启动并运行 - 轻巧且适合我的家庭项目。它也可以在GitHub找到。(不要与前面提到的MIDI.NET混淆,它看起来也很有前途,我只是从来没有接触过它。)

Of course NAudio(also mentioned above) has tons of capability, but like the original poster I just wanted to play some notes and quickly read and understand the source code.

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

回答by Ronnie Overby

A new player emerges:

一个新玩家出现:

https://github.com/atsushieno/managed-midi

https://github.com/atsushieno/managed-midi

https://www.nuget.org/packages/managed-midi/

https://www.nuget.org/packages/managed-midi/

Not much in the way of documentation, but one focus of this library is cross platform support.

文档方式不多,但该库的重点之一是跨平台支持。