문제
원래 다음을 사용하여 작성된 오래된 메트로놈 응용 프로그램을 다시 작성하려고 합니다. MFC
C++로 작성하려면 .NET
사용하여 C#
.제가 겪고 있는 문제 중 하나는 메트로놈 "클릭"을 나타내는 데 사용되는 미디 파일을 재생하는 것입니다.
온라인에서 게임에 관한 몇 가지 기사를 찾았습니다. MIDI
.NET에 있지만 대부분은 누군가가 함께 엮어 제공한 사용자 정의 라이브러리에 의존하는 것 같습니다.나는 이것을 사용하는 것을 싫어하지는 않지만 이것이 어떻게 수행되는지 스스로 이해하고 싶습니다. ~해야 한다 대부분 사소한 운동이 될 것입니다.
그럼 내가 뭔가를 놓치고 있는 걸까?아니면 .NET 애플리케이션 내에서 MIDI를 사용하는 것이 어렵습니까?
해결책
.net에서 미디 파일을 재생할 수 있으려면 Windows API를 p/invoke해야 할 것 같습니다.
이 코드 프로젝트 기사는 이를 수행하는 방법을 잘 설명합니다.미디 파일을 재생하는 vb.net 기사
이것을 C#으로 다시 작성하려면 mciSendString에 대해 다음 import 문이 필요합니다.
[DllImport("winmm.dll")]
static extern Int32 mciSendString(String command, StringBuilder buffer,
Int32 bufferSize, IntPtr hwndCallback);
도움이 되었기를 바랍니다. 행운을 빕니다!
다른 팁
저는 현재 C# MIDI 애플리케이션을 작업 중인데 다른 것들도 맞습니다. 이를 위해서는 p/invoke를 사용해야 합니다.나는 그것이 응용 프로그램에 더 적합해 보였기 때문에 내 자신을 굴리고 있습니다(나는 MIDI 기능의 작은 하위 집합만 필요합니다). 그러나 귀하의 목적에 따라 C# MIDI 툴킷 더 잘 맞을 수도 있습니다.적어도 내가 찾은 최고의 .NET MIDI 라이브러리이며 프로젝트를 시작하기 전에 광범위하게 검색했습니다.
나는 그것에 대해 많이 안다고 주장할 수는 없지만 그렇게 간단하지는 않다고 생각합니다. - 칼 프랭클린 DotNetRocks 명성은 꽤 많은 성과를 거두었습니다. 본 적이 있나요? 그의 DNRTV?
미디어 플레이어를 사용할 수 있습니다:
using WMPLib;
//...
WindowsMediaPlayer wmp = new WindowsMediaPlayer();
wmp.URL = Path.Combine(Application.StartupPath ,"Resources/mymidi1.mid");
wmp.controls.play();
최근 추가된 내용은 미디.NET Midi 포트, Midi 파일 및 SysEx를 지원합니다.
시스템.미디어.사운드플레이어 WAV 파일을 재생하는 간단하고 좋은 방법입니다.WAV 파일은 MIDI에 비해 몇 가지 장점이 있는데, 그 중 하나는 컴퓨터에 내장된 신디사이저에 의존하지 않고 각 악기의 소리를 정확하게 제어할 수 있다는 것입니다.
죄송합니다. 이 질문은 조금 오래되었지만 다음은 저에게 효과적이었습니다. Win32 - 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());
}
명령 문자열의 전체 목록이 제공됩니다. 여기.이것의 멋진 부분은 시퀀서 외에 다른 것을 사용하여 연주할 수 있다는 것입니다. 다른 것들, .wav 파일을 재생하려면 waveaudio를 말하세요.하지만 .mp3를 재생하는 방법을 알 수 없습니다.
또한 중지 및 닫기 명령은 열기 및 재생 명령이 전송된 동일한 스레드에서 전송되어야 합니다. 그렇지 않으면 아무런 효과가 없으며 파일은 열린 상태로 유지됩니다.예를 들어:
[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);
}
새로운 플레이어가 등장합니다:
https://github.com/atsushieno/managed-midi
https://www.nuget.org/packages/managed-midi/
문서화 방식은 많지 않지만 이 라이브러리의 초점 중 하나는 크로스 플랫폼 지원입니다.
저는 직접 구현하는 것보다 MIDI 데이터 재생을 위한 고급 기능을 갖춘 일부 라이브러리를 사용하는 것이 훨씬 낫다고 생각합니다.예를 들어, DryWetMIDI 기본 신디사이저를 통해 MIDI 파일을 재생하려면(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
전체 파일이 재생될 때까지 호출 스레드를 차단합니다.MIDI 파일의 재생을 제어하려면 Playback
개체를 사용하고 Start
/Stop
방법(자세한 내용은 재생 도서관의 기사 위키):
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();