Лучший способ воспроизведения MIDI-звуков с использованием С#
Я пытаюсь перестроить старое приложение метронома, которое изначально было написано с помощью MFC
в С++, которое должно быть записано в .NET
с помощью C#
. Одна из проблем, с которыми я сталкиваюсь, - это играть в midi файлы, которые используются для представления "кликов" метронома.
Я нашел несколько статей в Интернете о воспроизведении MIDI
в .NET, но большинство из них, похоже, полагаются на пользовательские библиотеки, которые кто-то собрал вместе и сделал доступными. Я не прочь использовать их, но я бы лучше понял, как это делается, поскольку кажется, что это должно быть в основном тривиальным упражнением.
Итак, я что-то упускаю? Или просто сложно использовать MIDI внутри приложения .NET?
Ответы
Ответ 1
Я думаю, вам нужно будет p/invoke в windows api, чтобы иметь возможность воспроизводить MIDI файлы из .net.
В этой статье кодекса хорошо написано, как это сделать:
статья vb.net для воспроизведения midi файлов
Чтобы переписать это С#, вам понадобится следующий оператор import для mciSendString:
[DllImport("winmm.dll")]
static extern Int32 mciSendString(String command, StringBuilder buffer,
Int32 bufferSize, IntPtr hwndCallback);
Надеюсь, это поможет - удачи!
Ответ 2
В настоящий момент я работаю над С# MIDI-приложением, а остальные правы - вам нужно использовать p/invoke для этого. Я катаюсь самостоятельно, поскольку это кажется более подходящим для приложения (мне нужен только небольшой набор функций MIDI), но для ваших целей С# MIDI Toolkit может быть лучше подходит. Это, по крайней мере, лучшая библиотека .NET MIDI, которую я нашел, и я искал экстенсивно, прежде чем запускать проект.
Ответ 3
midi-dot-net запустил меня за несколько минут - легкий и правильный размер для моего домашнего проекта. Он также доступен на GitHub. (Не путать с ранее упомянутым MIDI.NET, который также выглядит многообещающим, я просто никогда не обходил его.)
Конечно NAudio (также упоминалось выше) имеет массу возможностей, но, как и оригинальный плакат, я просто хотел сыграть несколько заметок и быстро прочитать и понять исходный код.
Ответ 4
Я не могу утверждать, что много знаю об этом, но я не думаю, что это просто - Карл Франклин из DotNetRocks слава сделала с ним честную битву - вы видели его DNRTV?
Ответ 5
Вы можете использовать медиаплеер:
using WMPLib;
//...
WindowsMediaPlayer wmp = new WindowsMediaPlayer();
wmp.URL = Path.Combine(Application.StartupPath ,"Resources/mymidi1.mid");
wmp.controls.play();
Ответ 6
Для обширных манипуляций с MIDI и Wave в .NET я думаю, что руки NAudio - это решение (также доступно через NuGet).
Ответ 7
Недавнее дополнение MIDI.NET, которое поддерживает Midi Ports, Midi Files и SysEx.
Ответ 8
System.Media. SoundPlayer - это хороший, простой способ воспроизведения файлов WAV. WAV файлы имеют некоторые преимущества по сравнению с MIDI, одним из которых является то, что вы можете точно контролировать, что такое инструмент (вместо того, чтобы полагаться на встроенный синтезатор компьютера).
Ответ 9
Извините, этот вопрос немного устарел, но для меня это работало (несколько скопировано из Win32 - Midi looping с 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);
}
Ответ 10
Появляется новый игрок:
https://github.com/atsushieno/managed-midi
https://www.nuget.org/packages/managed-midi/
Документация не слишком сложна, но одной из целей этой библиотеки является межплатформенная поддержка.
Ответ 11
Я думаю, что гораздо лучше использовать библиотеку с расширенными функциями для воспроизведения MIDI-данных, а не реализовывать ее самостоятельно. Например, с помощью DryWetMIDI для воспроизведения MIDI файла через синтезатор по умолчанию (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
заблокирует вызывающий поток, пока весь файл не будет воспроизведен. Чтобы управлять воспроизведением MIDI файла, получите объект Playback
и используйте его методы Start
/Stop
(подробнее см. Статью Playback библиотеки 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();