Frage

Ich versuche, eine alte Metronomanwendung neu zu erstellen, die ursprünglich mit geschrieben wurde MFC in C++ geschrieben werden .NET verwenden C#.Eines der Probleme, auf die ich stoße, ist das Abspielen der Midi-Dateien, die zur Darstellung der Metronom-„Klicks“ verwendet werden.

Ich habe online ein paar Artikel über das Spielen gefunden MIDI in .NET, aber die meisten von ihnen scheinen auf benutzerdefinierten Bibliotheken zu basieren, die jemand zusammengeschustert und verfügbar gemacht hat.Ich bin nicht abgeneigt, diese zu verwenden, aber ich möchte lieber selbst verstehen, wie das gemacht wird, da es so aussieht sollen eine meist triviale Übung sein.

Also, übersehe ich etwas?Oder ist es einfach schwierig, MIDI innerhalb einer .NET-Anwendung zu verwenden?

War es hilfreich?

Lösung

Ich denke, Sie müssen einen p/invoke-Aufruf an die Windows-API durchführen, um Midi-Dateien von .net abspielen zu können.

Dieser Codeprojekt-Artikel erklärt gut, wie das geht:vb.net-Artikel zum Abspielen von Midi-Dateien

Um dies in c# umzuschreiben, benötigen Sie die folgende Importanweisung für mciSendString:

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

Hoffe das hilft – viel Glück!

Andere Tipps

Ich arbeite gerade an einer C#-MIDI-Anwendung, und die anderen haben Recht – Sie müssen dafür p/invoke verwenden.Ich drehe mein eigenes, da es für die Anwendung besser geeignet schien (ich benötige nur einen kleinen Teil der MIDI-Funktionalität), aber für Ihre Zwecke ist das besser C#-MIDI-Toolkit passt vielleicht besser.Es ist zumindest die beste .NET-MIDI-Bibliothek, die ich gefunden habe, und ich habe vor Beginn des Projekts ausführlich gesucht.

Midi-Dot-Net Ich war in wenigen Minuten einsatzbereit – leicht und in der richtigen Größe für mein Heimprojekt.Es ist auch verfügbar auf GitHub.(Nicht zu verwechseln mit den zuvor genannten MIDI.NET, was auch vielversprechend aussieht, ich bin einfach nie dazu gekommen.)

Natürlich NAudio (ebenfalls oben erwähnt) bietet jede Menge Möglichkeiten, aber wie beim Originalposter wollte ich nur ein paar Noten spielen und schnell den Quellcode lesen und verstehen.

Ich kann nicht behaupten, viel darüber zu wissen, aber ich glaube nicht, dass es so einfach ist – Carl Franklin von DotNetRocks Der Ruhm hat einiges dazu beigetragen – haben Sie gesehen? sein DNRTV?

Sie können den Mediaplayer verwenden:

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

Für umfangreiche MIDI- und Wave-Manipulationen in .NET denke ich zweifellos NAudio ist die Lösung (Auch verfügbar über NuGet).

Eine neue Ergänzung ist MIDI.NET das Midi-Ports, Midi-Dateien und SysEx unterstützt.

System.Medien.SoundPlayer ist eine gute und einfache Möglichkeit, WAV-Dateien abzuspielen.WAV-Dateien haben gegenüber MIDI einige Vorteile. Einer davon besteht darin, dass Sie genau steuern können, wie jedes Instrument klingt (anstatt sich auf den integrierten Synthesizer des Computers zu verlassen).

Tut mir leid, diese Frage ist jetzt etwas alt, aber das Folgende hat bei mir funktioniert (etwas kopiert von Win32 – Midi-Looping mit 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());
}

Es wird eine vollständige Liste der Befehlszeichenfolgen angegeben Hier.Das Coole daran ist, dass man neben dem Sequenzer auch andere Dinge zum Spielen verwenden kann verschiedene Dinge, sagen wir waveaudio zum Abspielen von .wav-Dateien.Ich kann jedoch nicht herausfinden, wie ich es dazu bringen kann, .mp3 abzuspielen.

Beachten Sie außerdem, dass die Stopp- und Schließbefehle im selben Thread gesendet werden müssen, in dem die Öffnungs- und Wiedergabebefehle gesendet wurden, da sie sonst keine Wirkung haben und die Datei geöffnet bleibt.Zum Beispiel:

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

Ein neuer Spieler taucht auf:

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

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

Es gibt nicht viel Dokumentation, aber ein Schwerpunkt dieser Bibliothek liegt auf der plattformübergreifenden Unterstützung.

Ich denke, es ist viel besser, eine Bibliothek zu verwenden, die über erweiterte Funktionen für die MIDI-Datenwiedergabe verfügt, als sie selbst zu implementieren.Zum Beispiel mit DryWetMIDI um MIDI-Dateien über den Standard-Synthesizer abzuspielen (Microsoft GS Wavetable Synth):

using Melanchall.DryWetMidi.Devices;
using Melanchall.DryWetMidi.Smf;

// ...

var midiFile = MidiFile.Read("Greatest song ever.mid");

using (var outputDevice = OutputDevice.GetByName("Microsoft GS Wavetable Synth"))
{
    midiFile.Play(outputDevice);
}

Play blockiert den aufrufenden Thread, bis die gesamte Datei abgespielt wird.Um die Wiedergabe einer MIDI-Datei zu steuern, erhalten Sie Playback Objekt und verwenden Sie es Start/Stop Methoden (weitere Details in der Wiedergabe Artikel der Bibliothek Wiki):

var playback = midiFile.GetPlayback(outputDevice);

// You can even loop playback and speed it up
playback.Loop = true;
playback.Speed = 2.0;

playback.Start();

// ...

playback.Stop();

// ...

playback.Dispose();
outputDevice.Dispose();
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top