Question

Je suis en train de reconstruire un vieux métronome application qui a été écrit à l'origine en utilisant MFC en C++ pour être écrit dans .NET à l'aide de C#.L'une des questions que je suis en cours d'exécution dans est de jouer les fichiers midi qui sont utilisés pour représenter le métronome "clics".

J'ai trouvé quelques articles en ligne sur la lecture MIDI dans .NET, mais la plupart d'entre eux semblent s'appuyer sur des bibliothèques personnalisées que quelqu'un a monté et mis à disposition.Je ne suis pas opposé à l'utilisation de ceux-ci, mais je préfère comprendre pour moi-même comment c'est fait, puisqu'il semble qu'il devrait être à majorité simple.

Alors, suis-je raté quelque chose?Ou est-ce juste difficile à utiliser MIDI à l'intérieur d'un .NET application?

Était-ce utile?

La solution

Je pense que vous aurez besoin de p/invoke à l'api windows pour être en mesure de jouer des fichiers midi de .net.

Cette codeproject article fait un bon travail en expliquant comment faire:vb.net article à lire les fichiers midi

Réécrire c'est le c#, vous auriez besoin de l'instruction d'importation suivante pour mciSendString:

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

Espérons que cela aide - bonne chance!

Autres conseils

Je suis en train de travailler sur un C# application MIDI à l'heure actuelle, et les autres sont de droite, vous devez utiliser p/invoke pour cela.Je continue mes propres comme cela semblait plus appropriée pour l'application (j'ai seulement besoin d'un petit sous-ensemble de la fonctionnalité MIDI), mais pour les fins de la C# MIDI Toolkit peut-être un meilleur ajustement.Au moins, c'est le meilleur .NET la bibliothèque MIDI, j'ai trouvé, et j'ai beaucoup cherché avant de commencer le projet.

midi-dot-net je me levai et en quelques minutes - léger et de taille idéale pour mon projet de maison.Il est également disponible sur GitHub.(À ne pas confondre avec le mentionné précédemment MIDI.NET, qui aussi a l'air prometteur, je n'ai jamais eu autour d'elle.)

Bien sûr NAudio (également mentionnée ci-dessus) a des tonnes de capacité, mais comme le posteur d'origine, je voulais juste jouer quelques notes et de rapidement lire et comprendre le code source.

Je ne peux pas prétendre savoir beaucoup à ce sujet, mais je ne pense pas que c'est simple - Carl Franklin de DotNetRocks la renommée a fait un peu juste avec elle - avez-vous vu son DNRTV?

Vous pouvez utiliser le lecteur windows media:

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

Pour la vaste MIDI et Wave manipulation .NET, je pense que les mains vers le bas NAudio la solution est (Également disponible via NuGet).

Un ajout récent est MIDI.NET qui prend en charge les Ports Midi de, Midi de Fichiers et de SysEx.

Système.Médias.SoundPlayer est un bon, simple façon de jouer des fichiers WAV.WAV fichiers ont certains avantages par rapport à MIDI, l'un d'eux étant que vous pouvez contrôler précisément ce que chaque instrument sonne comme (plutôt que de s'appuyer sur l'ordinateur, synthétiseur intégré).

Désolé, cette question est un peu vieux maintenant, mais la suite a fonctionné pour moi (un peu copié à partir de Win32 - Midi en boucle avec 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());
}

Une liste complète des chaînes de commande est donné ici.La partie la plus cool à ce sujet est que vous pouvez simplement utiliser des choses différentes en plus de séquenceur à jouer différentes choses, dire waveaudio pour jouer .les fichiers wav.Je ne peux pas comprendre comment le faire jouer .mp3 si.

Notez également que l'arrêt et la commande de fermeture doivent être envoyés sur le même thread que de l'ouvrir et de lire les commandes ont été envoyées sur, sinon, ils n'auraient aucun effet et le fichier reste ouvert.Par exemple:

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

Un nouveau joueur s'en dégage:

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

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

Pas beaucoup de documentation, mais un des objectifs de cette bibliothèque est de la croix-plate-forme de soutien.

Je pense que c'est beaucoup mieux d'utiliser une bibliothèque qui dispose de fonctionnalités avancées pour les données MIDI de lecture au lieu de la mettre en œuvre par votre propre.Par exemple, avec DryWetMIDI pour jouer un fichier MIDI par défaut de synthèse (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 va bloquer le thread appelant jusqu'à ce que tout le fichier lu.Pour contrôler la lecture d'un fichier MIDI, obtenir Playback objet et l'utilisation de son Start/Stop méthodes (plus de détails dans la La lecture l'article de la bibliothèque 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();
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top