Лучший способ воспроизвести MIDI-звуки с помощью C #

Я пытаюсь восстановить старое приложение , метроном который был первоначально написан с использованием MFCв C ++ , который будет записан в .NETиспользовании C#. Одна из проблем, с которыми я сталкиваюсь, - это воспроизведение миди-файлов, которые используются для представления «щелчков» метронома.

Я нашел в Интернете несколько статей об игре MIDIв .NET, но большинство из них, кажется, полагаются на пользовательские библиотеки, которые кто-то собрал вместе и сделал доступными. Я не против их использования, но я бы лучше понял для себя, как это делается, поскольку кажется, что это должно быть в основном тривиальным упражнением.

Итак, я что-то упустил? Или просто сложно использовать MIDI внутри приложения .NET?

12.08.2008 12:34:07
11 ОТВЕТОВ
РЕШЕНИЕ

Я думаю, что вам нужно p / invoke для Windows API, чтобы иметь возможность проигрывать MIDI-файлы из .net.

Эта статья о проекте codeproject хорошо объясняет, как это сделать: статья vb.net для воспроизведения миди-файлов

Чтобы переписать это на c #, вам понадобится следующий оператор импорта для mciSendString:

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

Надеюсь это поможет. Удачи!

9
29.05.2014 19:42:21

Я не могу утверждать, что много знаю об этом, но я не думаю, что это так просто - Карл Франклин из DotNetRocks прославился этим - вы видели его DNRTV ?

1
12.08.2008 12:39:17

Сейчас я работаю над C # MIDI-приложением, а остальные правы - для этого нужно использовать p / invoke. Я использую свои собственные, поскольку это казалось более подходящим для приложения (мне нужен только небольшой набор функций MIDI), но для ваших целей лучше подойдет MIDI Toolkit C # . Это, по крайней мере, лучшая библиотека .NET MIDI, которую я нашел, и я много искал перед началом проекта.

11
12.08.2008 12:51:50
MIDI Toolkit Лесли, безусловно, является наиболее полным C # решением для воспроизведения и записи MIDI. Я использовал его для очень сложного проекта, и он работал хорошо.
andynormancx 19.12.2009 09:36:24

System.Media. SoundPlayer - это хороший, простой способ воспроизведения WAV-файлов. Файлы WAV имеют некоторые преимущества перед MIDI, одним из которых является то, что вы можете точно контролировать звучание каждого инструмента (вместо того, чтобы полагаться на встроенный синтезатор компьютера).

0
17.09.2008 01:55:06

Вы можете использовать медиаплеер:

using WMPLib;
//...
WindowsMediaPlayer wmp = new WindowsMediaPlayer();
wmp.URL = Path.Combine(Application.StartupPath ,"Resources/mymidi1.mid");
wmp.controls.play();
1
11.04.2011 18:31:20

Я думаю, что для обширных манипуляций с MIDI и Wave в .NET нужно использовать NAudio (также доступно через NuGet ).

1
8.05.2013 00:23:37

Недавним дополнением является MIDI.NET, который поддерживает порты Midi, Midi Files и SysEx.

1
30.09.2013 10:33:50

Извините, этот вопрос уже немного устарел , но у меня сработало следующее (несколько скопировано из Win32 - цикл Midi с 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());
}

Полный список командных строк приведен здесь . Крутая часть этого заключается в том, что вы можете просто использовать разные вещи помимо секвенсора для воспроизведения разных вещей , например waveaudio для воспроизведения файлов .wav. Я не могу понять, как заставить это играть .mp3 все же.

Также обратите внимание, что команды stop и close должны отправляться в том же потоке, в котором были отправлены команды open и play, иначе они не будут иметь никакого эффекта, и файл останется открытым. Например:

[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);
}
0
23.05.2017 11:53:27
используйте mciSendString ("open" + fileName + "alias" + alias, new StringBuilder (), 0, new IntPtr ()); вместо mciSendString ("open" + fileName + "псевдоним секвенсора типа" + псевдоним, new StringBuilder (), 0, new IntPtr ()); может воспроизводить файлы .mp3 (и еще несколько таких, как .wav, .wma и т. д.)
Silent Sojourner 20.06.2017 16:13:00

midi-dot-net заставил меня заработать за считанные минуты - легкий и подходящий для моего домашнего проекта. Это также доступно на GitHub . (Не путать с ранее упомянутым MIDI.NET , который также выглядит многообещающе, я просто никогда не удосужился .)

Конечно, NAudio (также упомянутый выше) имеет массу возможностей, но, как и оригинальный постер, я просто хотел сыграть несколько заметок и быстро прочитать и понять исходный код.

4
25.10.2015 19:26:00

Появляется новый игрок:

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

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

Документация не слишком сложна, но одной из целей этой библиотеки является межплатформенная поддержка.

0
15.12.2018 04:53:48

Я думаю, что гораздо лучше использовать библиотеку с расширенными функциями для воспроизведения MIDI-данных, а не реализовывать ее самостоятельно. Например, с DryWetMIDI (я его автор) для воспроизведения MIDI-файла через синтезатор по умолчанию ( Microsoft GS Wavetable Synth ):

using Melanchall.DryWetMidi.Devices;
using Melanchall.DryWetMidi.Core;

// ...

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

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

Playбудет блокировать вызывающий поток, пока весь файл не будет воспроизведен. Чтобы управлять воспроизведением MIDI-файла, получите Playbackобъект и используйте его Start/ Stopметоды (подробнее в статье о воспроизведении библиотеки 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();
1
23.11.2019 08:54:40