Pergunta

Estou tentando reconstruir um aplicativo metrônomo antigo que foi originalmente escrito usando MFC em C++ para ser escrito em .NET usando C#.Um dos problemas que estou enfrentando é a reprodução de arquivos midi usados ​​para representar os "cliques" do metrônomo.

Encontrei alguns artigos online sobre jogar MIDI no .NET, mas a maioria deles parece depender de bibliotecas personalizadas que alguém montou e disponibilizou.Não tenho aversão a usá-los, mas prefiro entender por mim mesmo como isso está sendo feito, pois parece deve ser um exercício principalmente trivial.

Então, estou faltando alguma coisa?Ou é apenas difícil usar MIDI dentro de um aplicativo .NET?

Foi útil?

Solução

Acho que você precisará invocar a API do Windows para poder reproduzir arquivos midi do .net.

Este artigo do codeproject explica bem como fazer isso:artigo vb.net para reproduzir arquivos midi

Para reescrever isso em c#, você precisaria da seguinte instrução de importação para mciSendString:

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

Espero que isso ajude - boa sorte!

Outras dicas

Estou trabalhando em um aplicativo C# MIDI no momento, e os outros estão certos - você precisa usar p/invoke para isso.Estou criando o meu próprio, pois parecia mais apropriado para o aplicativo (só preciso de um pequeno subconjunto de funcionalidades MIDI), mas para seus propósitos o Kit de ferramentas C# MIDI pode ser um ajuste melhor.É pelo menos a melhor biblioteca .NET MIDI que encontrei e pesquisei bastante antes de iniciar o projeto.

midi-ponto-net coloquei-me pronto para funcionar em minutos - leve e do tamanho certo para o meu projeto doméstico.Também está disponível em GitHub.(Não deve ser confundido com o mencionado anteriormente MIDI.NET, que também parece promissor, mas nunca tive tempo para isso.)

Claro NAudio (também mencionado acima) tem muitos recursos, mas como o autor da postagem original, eu só queria tocar algumas notas e ler e entender rapidamente o código-fonte.

Não posso afirmar que sei muito sobre isso, mas não acho que seja tão simples - Carl Franklin, da DotNetRocks a fama fez bastante com isso - você viu seu DNRTV?

Você pode usar o reprodutor de mídia:

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

Para manipulação extensiva de MIDI e Wave no .NET, acho que sem dúvida NAudio é a solução (também disponível via NuGet).

Uma adição recente é MIDI.NET que suporta portas Midi, arquivos Midi e SysEx.

Sistema.Mídia.Leitor de som é uma maneira boa e simples de reproduzir arquivos WAV.Os arquivos WAV têm algumas vantagens sobre o MIDI, uma delas é que você pode controlar com precisão o som de cada instrumento (em vez de depender do sintetizador integrado do computador).

Desculpe, esta pergunta é um pouco antiga agora, mas o seguinte funcionou para mim (um pouco copiado de Win32 - Loop Midi com 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());
}

Uma lista completa de strings de comando é fornecida aqui.A parte legal disso é que você pode usar coisas diferentes além do sequenciador para tocar coisas diferentes, digamos waveaudio para reproduzir arquivos .wav.Não consigo descobrir como fazê-lo reproduzir .mp3.

Além disso, observe que os comandos stop e close devem ser enviados no mesmo thread em que os comandos open e play foram enviados, caso contrário eles não terão efeito e o arquivo permanecerá aberto.Por exemplo:

[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 um novo jogador:

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

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

Não há muita documentação, mas um dos focos desta biblioteca é o suporte multiplataforma.

Acho muito melhor usar alguma biblioteca que tenha recursos avançados para reprodução de dados MIDI em vez de implementá-la por conta própria.Por exemplo, com SecoMolhadoMIDI para reproduzir arquivo MIDI via sintetizador padrão (Sintetizador Wavetable Microsoft GS):

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á o thread de chamada até que todo o arquivo seja reproduzido.Para controlar a reprodução de um arquivo MIDI, obtenha Playback objeto e usar seu Start/Stop métodos (mais detalhes no Reprodução artigo da biblioteca Wikipédia):

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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top