Pregunta

Estoy intentando reconstruir una antigua aplicación de metrónomo que se escribió originalmente usando MFC en C++ para ser escrito en .NET usando C#.Uno de los problemas con los que me encuentro es la reproducción de los archivos midi que se utilizan para representar los "clics" del metrónomo.

Encontré algunos artículos en línea sobre cómo jugar. MIDI en .NET, pero la mayoría de ellos parecen depender de bibliotecas personalizadas que alguien ha improvisado y puesto a disposición.No soy reacio a usarlos, pero prefiero entender por mí mismo cómo se hace, ya que parece que debería ser un ejercicio mayoritariamente trivial.

Entonces, ¿me estoy perdiendo algo?¿O simplemente es difícil utilizar MIDI dentro de una aplicación .NET?

¿Fue útil?

Solución

Creo que necesitarás p/invocar la API de Windows para poder reproducir archivos midi desde .net.

Este artículo de codeproject hace un buen trabajo al explicar cómo hacer esto:Artículo de vb.net para reproducir archivos midi

Para reescribir esto en C#, necesitaría la siguiente declaración de importación para mciSendString:

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

¡Espero que esto ayude, buena suerte!

Otros consejos

Estoy trabajando en una aplicación MIDI C# en este momento y los demás tienen razón: necesitas usar p/invoke para esto.Estoy preparando el mío propio porque me pareció más apropiado para la aplicación (sólo necesito un pequeño subconjunto de funcionalidad MIDI), pero para sus propósitos, el Kit de herramientas MIDI de C# podría ser una mejor opción.Es al menos la mejor biblioteca .NET MIDI que encontré y busqué exhaustivamente antes de comenzar el proyecto.

red-punto-midi Me puso en funcionamiento en minutos: liviano y del tamaño adecuado para el proyecto de mi hogar.También está disponible en GitHub.(No debe confundirse con el mencionado anteriormente MIDI.NET, que también parece prometedor, pero nunca lo logré).

Por supuesto NAudio (también mencionado anteriormente) tiene toneladas de capacidades, pero al igual que el póster original, solo quería tocar algunas notas y leer y comprender rápidamente el código fuente.

No puedo afirmar saber mucho al respecto, pero no creo que sea tan sencillo - Carl Franklin de DotNetRocas La fama ha acabado bastante con esto. ¿Has visto? su DNRTV?

Puedes utilizar el reproductor multimedia:

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

Para una manipulación extensa de MIDI y Wave en .NET, creo que sin lugar a dudas NAudio es la solución (También disponible a través de NuGet).

Una adición reciente es MIDI.NET que soporta puertos Midi, archivos Midi y SysEx.

Sistema.Medios.Reproductor de sonido es una forma buena y sencilla de reproducir archivos WAV.Los archivos WAV tienen algunas ventajas sobre MIDI, una de ellas es que puedes controlar con precisión cómo suena cada instrumento (en lugar de depender del sintetizador integrado de la computadora).

Lo siento, esta pregunta es un poco antigua ahora, pero lo siguiente funcionó para mí (algo copiado de Win32: bucle midi con 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());
}

Se proporciona una lista completa de cadenas de comandos. aquí.Lo bueno de esto es que puedes usar diferentes cosas además del secuenciador para jugar. cosas diferentes, digamos waveaudio para reproducir archivos .wav.Sin embargo, no sé cómo hacer que reproduzca .mp3.

Además, tenga en cuenta que el comando detener y cerrar debe enviarse en el mismo hilo en el que se enviaron los comandos abrir y reproducir; de lo contrario, no tendrán ningún efecto y el archivo permanecerá abierto.Por ejemplo:

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

Surge un nuevo jugador:

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

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

No hay mucha documentación, pero un enfoque de esta biblioteca es el soporte multiplataforma.

Creo que es mucho mejor usar alguna biblioteca que tenga funciones avanzadas para la reproducción de datos MIDI en lugar de implementarla usted mismo.Por ejemplo, con SecoHúmedoMIDI para reproducir archivos MIDI a través del sintetizador predeterminado (Sintetizador Microsoft GS Wavetable):

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 bloqueará el hilo de llamada hasta que se reproduzca todo el archivo.Para controlar la reproducción de un archivo MIDI, obtenga Playback objeto y utilizar su Start/Stop métodos (más detalles en el Reproducción artículo de la biblioteca 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();
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top