Я пытаюсь восстановить старое приложение , метроном который был первоначально написан с использованием MFC
в C ++ , который будет записан в .NET
использовании C#
. Одна из проблем, с которыми я сталкиваюсь, - это воспроизведение миди-файлов, которые используются для представления «щелчков» метронома.
Я нашел в Интернете несколько статей об игре MIDI
в .NET, но большинство из них, кажется, полагаются на пользовательские библиотеки, которые кто-то собрал вместе и сделал доступными. Я не против их использования, но я бы лучше понял для себя, как это делается, поскольку кажется, что это должно быть в основном тривиальным упражнением.
Итак, я что-то упустил? Или просто сложно использовать MIDI внутри приложения .NET?
Я думаю, что вам нужно 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);
Надеюсь это поможет. Удачи!
Я не могу утверждать, что много знаю об этом, но я не думаю, что это так просто - Карл Франклин из DotNetRocks прославился этим - вы видели его DNRTV ?
Сейчас я работаю над C # MIDI-приложением, а остальные правы - для этого нужно использовать p / invoke. Я использую свои собственные, поскольку это казалось более подходящим для приложения (мне нужен только небольшой набор функций MIDI), но для ваших целей лучше подойдет MIDI Toolkit C # . Это, по крайней мере, лучшая библиотека .NET MIDI, которую я нашел, и я много искал перед началом проекта.
System.Media. SoundPlayer - это хороший, простой способ воспроизведения WAV-файлов. Файлы WAV имеют некоторые преимущества перед MIDI, одним из которых является то, что вы можете точно контролировать звучание каждого инструмента (вместо того, чтобы полагаться на встроенный синтезатор компьютера).
Вы можете использовать медиаплеер:
using WMPLib;
//...
WindowsMediaPlayer wmp = new WindowsMediaPlayer();
wmp.URL = Path.Combine(Application.StartupPath ,"Resources/mymidi1.mid");
wmp.controls.play();
Я думаю, что для обширных манипуляций с MIDI и Wave в .NET нужно использовать NAudio (также доступно через NuGet ).
Недавним дополнением является MIDI.NET, который поддерживает порты Midi, Midi Files и SysEx.
Извините, этот вопрос уже немного устарел , но у меня сработало следующее (несколько скопировано из 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);
}
midi-dot-net заставил меня заработать за считанные минуты - легкий и подходящий для моего домашнего проекта. Это также доступно на GitHub . (Не путать с ранее упомянутым MIDI.NET , который также выглядит многообещающе, я просто никогда не удосужился .)
Конечно, NAudio (также упомянутый выше) имеет массу возможностей, но, как и оригинальный постер, я просто хотел сыграть несколько заметок и быстро прочитать и понять исходный код.
Появляется новый игрок:
https://github.com/atsushieno/managed-midi
https://www.nuget.org/packages/managed-midi/
Документация не слишком сложна, но одной из целей этой библиотеки является межплатформенная поддержка.
Я думаю, что гораздо лучше использовать библиотеку с расширенными функциями для воспроизведения 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();