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

<p>I've found a few articles online about playing <code>MIDI</code> in .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 <em>should</em> be a mostly trivial exercise.</p>

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

[{'answer_id': 8773, 'author': 'Whisk', 'author_id': 908, 'author_profile': 'https://Stackoverflow.com/users/908', 'pm_score': 1, 'selected': False, 'text': '<p>I can\'t claim to know much about it, but I don\'t think it\'s that straightforward - Carl Franklin of <a href="http://www.dotnetrocks.com/" rel="nofollow noreferrer">DotNetRocks</a> fame has done a fair bit with it - have you seen <a href="http://dnrtv.com/default.aspx?showID=110" rel="nofollow noreferrer" title="DNR TV">his DNRTV</a>?</p>\n'}, {'answer_id': 8777, 'author': 'John Sibly', 'author_id': 1078, 'author_profile': 'https://Stackoverflow.com/users/1078', 'pm_score': 4, 'selected': True, 'text': '<p>I think you\'ll need to p/invoke out to the windows api to be able to play midi files from .net.</p>\n\n<p>This codeproject article does a good job on explaining how to do this:\n<a href="http://www.codeproject.com/KB/audio-video/vbnetSoundClass.aspx" rel="nofollow noreferrer">vb.net article to play midi files</a></p>\n\n<p>To rewrite this is c# you\'d need the following import statement for mciSendString:</p>\n\n<pre><code>[DllImport("winmm.dll")] \nstatic extern Int32 mciSendString(String command, StringBuilder buffer, \n                                  Int32 bufferSize, IntPtr hwndCallback);\n</code></pre>\n\n<p>Hope this helps - good luck!</p>\n'}, {'answer_id': 8779, 'author': 'Kjetil Limkjær', 'author_id': 991, 'author_profile': 'https://Stackoverflow.com/users/991', 'pm_score': 4, 'selected': False, 'text': '<p>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 <A href="http://www.codeproject.com/KB/audio-video/MIDIToolkit.aspx" rel="noreferrer">C# MIDI Toolkit</A> might be a better fit. It is at least the best .NET MIDI library I found, and I searched extensively before starting the project.</p>\n'}, {'answer_id': 79116, 'author': 'MusiGenesis', 'author_id': 14606, 'author_profile': 'https://Stackoverflow.com/users/14606', 'pm_score': -1, 'selected': False, 'text': "<p>System.Media.<strong>SoundPlayer</strong> is 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).</p>\n"}, {'answer_id': 5625772, 'author': 'Carra', 'author_id': 21679, 'author_profile': 'https://Stackoverflow.com/users/21679', 'pm_score': 1, 'selected': False, 'text': '<p>You can use the media player:</p>\n\n<pre><code>using WMPLib;\n//...\nWindowsMediaPlayer wmp = new WindowsMediaPlayer();\nwmp.URL = Path.Combine(Application.StartupPath ,"Resources/mymidi1.mid");\nwmp.controls.play();\n</code></pre>\n'}, {'answer_id': 16430739, 'author': 'Shimmy Weitzhandler', 'author_id': 75500, 'author_profile': 'https://Stackoverflow.com/users/75500', 'pm_score': 1, 'selected': False, 'text': '<p>For extensive MIDI and Wave manipulation in .NET, I think hands down <a href="http://naudio.codeplex.com" rel="nofollow">NAudio</a> is the solution (Also available via <a href="https://nuget.org/packages/NAudio" rel="nofollow">NuGet</a>).</p>\n'}, {'answer_id': 19092009, 'author': 'obiwanjacobi', 'author_id': 178897, 'author_profile': 'https://Stackoverflow.com/users/178897', 'pm_score': 1, 'selected': False, 'text': '<p>A recent addition is <a href="http://midinet.codeplex.com" rel="nofollow">MIDI.NET</a> that supports Midi Ports, Midi Files and SysEx.</p>\n'}, {'answer_id': 22976812, 'author': 'Phylliida', 'author_id': 2924421, 'author_profile': 'https://Stackoverflow.com/users/2924421', 'pm_score': 1, 'selected': False, 'text': '<p>Sorry this question is a little old now, but the following worked for me (somewhat copied from <a href="https://stackoverflow.com/questions/16829520/win32-midi-looping-with-mcisendstring">Win32 - Midi looping with MCISendString</a>):</p>\n\n<pre><code>[DllImport("winmm.dll")]\nstatic extern Int32 mciSendString(String command, StringBuilder buffer, Int32 bufferSize, IntPtr hwndCallback);\n\npublic static void playMidi(String fileName, String alias)\n{\n  mciSendString("open " + fileName + " type sequencer alias " + alias, new StringBuilder(), 0, new IntPtr());\n  mciSendString("play " + alias, new StringBuilder(), 0, new IntPtr());\n}\n\npublic static void stopMidi(String alias)\n{\n  mciSendString("stop " + alias, null, 0, new IntPtr());\n  mciSendString("close " + alias, null, 0, new IntPtr());\n}\n</code></pre>\n\n<p>A full listing of command strings is given <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/dd743572(v=vs.85).aspx" rel="nofollow noreferrer">here</a>. The cool part about this is you can just use different things besides sequencer to play <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/dd743638(v=vs.85).aspx" rel="nofollow noreferrer">different things</a>, say waveaudio for playing .wav files. I can\'t figure out how to get it to play .mp3 though.</p>\n\n<p>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:</p>\n\n<pre><code>[DllImport("winmm.dll")]\nstatic extern Int32 mciSendString(String command, StringBuilder buffer,\n                                    Int32 bufferSize, IntPtr hwndCallback);\n\npublic static Dictionary&lt;String, bool&gt; playingMidi = new Dictionary&lt;String, bool&gt;();\n\npublic static void PlayMidi(String fileName, String alias)\n{\n    if (playingMidi.ContainsKey(alias))\n        throw new Exception("Midi with alias \'" + alias + "\' is already playing");\n\n    playingMidi.Add(alias, false);\n\n    Thread stoppingThread = new Thread(() =&gt; { StartAndStopMidiWithDelay(fileName, alias); });\n    stoppingThread.Start();\n}\n\npublic static void StopMidiFromOtherThread(String alias)\n{\n    if (!playingMidi.ContainsKey(alias))\n        return;\n\n    playingMidi[alias] = true;\n}\n\npublic static bool isPlaying(String alias)\n{\n    return playingMidi.ContainsKey(alias);\n}\n\nprivate static void StartAndStopMidiWithDelay(String fileName, String alias)\n{\n    mciSendString("open " + fileName + " type sequencer alias " + alias, null, 0, new IntPtr());\n    mciSendString("play " + alias, null, 0, new IntPtr());\n\n    StringBuilder result = new StringBuilder(100);\n    mciSendString("set " + alias + " time format milliseconds", null, 0, new IntPtr());\n    mciSendString("status " + alias + " length", result, 100, new IntPtr());\n\n    int midiLengthInMilliseconds;\n    Int32.TryParse(result.ToString(), out midiLengthInMilliseconds);\n\n    Stopwatch timer = new Stopwatch();\n    timer.Start();\n\n    while(timer.ElapsedMilliseconds &lt; midiLengthInMilliseconds &amp;&amp; !playingMidi[alias])\n    {\n\n    }\n\n    timer.Stop();\n\n    StopMidi(alias);\n}\n\nprivate static void StopMidi(String alias)\n{\n    if (!playingMidi.ContainsKey(alias))\n        throw new Exception("Midi with alias \'" + alias + "\' is already stopped");\n\n    // Execute calls to close and stop the player, on the same thread as the play and open calls\n    mciSendString("stop " + alias, null, 0, new IntPtr());\n    mciSendString("close " + alias, null, 0, new IntPtr());\n\n    playingMidi.Remove(alias);\n}\n</code></pre>\n'}, {'answer_id': 33334058, 'author': 'Paul Williams', 'author_id': 420400, 'author_profile': 'https://Stackoverflow.com/users/420400', 'pm_score': 2, 'selected': False, 'text': '<p><a href="https://code.google.com/p/midi-dot-net/" rel="nofollow">midi-dot-net</a> got me up and running in minutes - lightweight and right-sized for my home project.  It\'s also available on <a href="https://github.com/jstnryan/midi-dot-net" rel="nofollow">GitHub</a>.  (Not to be confused with the previously mentioned <a href="http://midinet.codeplex.com/" rel="nofollow">MIDI.NET</a>, which also looks promising, I just never got around to it.)</p>\n\n<p>Of course <a href="https://github.com/naudio/NAudio" rel="nofollow">NAudio</a> (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.</p>\n'}, {'answer_id': 53789640, 'author': 'Ronnie Overby', 'author_id': 64334, 'author_profile': 'https://Stackoverflow.com/users/64334', 'pm_score': 1, 'selected': False, 'text': '<p>A new player emerges:</p>\n\n<p><a href="https://github.com/atsushieno/managed-midi" rel="nofollow noreferrer">https://github.com/atsushieno/managed-midi</a></p>\n\n<p><a href="https://www.nuget.org/packages/managed-midi/" rel="nofollow noreferrer">https://www.nuget.org/packages/managed-midi/</a></p>\n\n<p>Not much in the way of documentation, but one focus of this library is cross platform support.</p>\n'}, {'answer_id': 54442916, 'author': 'Maxim', 'author_id': 2975589, 'author_profile': 'https://Stackoverflow.com/users/2975589', 'pm_score': 2, 'selected': False, 'text': '<p>I think it\'s much better to use some library that which has advanced features for MIDI data playback instead of implementing it by your own. For example, with <a href="https://github.com/melanchall/drywetmidi" rel="nofollow noreferrer">DryWetMIDI</a> (I\'m the author of it) to play MIDI file via default synthesizer (<em>Microsoft GS Wavetable Synth</em>):</p>\n<pre><code>using Melanchall.DryWetMidi.Devices;\nusing Melanchall.DryWetMidi.Core;\n\n// ...\n\nvar midiFile = MidiFile.Read(&quot;Greatest song ever.mid&quot;);\n\nusing (var outputDevice = OutputDevice.GetByName(&quot;Microsoft GS Wavetable Synth&quot;))\n{\n    midiFile.Play(outputDevice);\n}\n</code></pre>\n<p><code>Play</code> will block the calling thread until entire file played. To control playback of a MIDI file, obtain <code>Playback</code> object and use its <code>Start</code>/<code>Stop</code> methods (more details in the <a href="https://melanchall.github.io/drywetmidi/articles/playback/Overview.html" rel="nofollow noreferrer">Playback</a> article of the <a href="https://melanchall.github.io/drywetmidi" rel="nofollow noreferrer">library docs</a>):</p>\n<pre><code>var playback = midiFile.GetPlayback(outputDevice);\n\n// You can even loop playback and speed it up\nplayback.Loop = true;\nplayback.Speed = 2.0;\n\nplayback.Start();\n\n// ...\n\nplayback.Stop();\n\n// ...\n\nplayback.Dispose();\noutputDevice.Dispose();\n</code></pre>\n'}]
['https://Stackoverflow.com/questions/8763', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/1108/']