문제

원래 다음을 사용하여 작성된 오래된 메트로놈 응용 프로그램을 다시 작성하려고 합니다. 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 라이브러리이며 프로젝트를 시작하기 전에 광범위하게 검색했습니다.

미디닷넷 몇 분 만에 작업을 시작할 수 있었습니다. 가볍고 크기도 내 홈 프로젝트에 딱 맞습니다.다음에서도 이용 가능합니다. GitHub.(앞서 언급한 내용과 혼동하지 마세요. 미디.NET, 또한 유망해 보이지만 아직 한번도 시도해 본 적이 없습니다.)

물론 NAudio (위에서도 언급한)에는 수많은 기능이 있지만 원래 포스터처럼 몇 가지 메모를 재생하고 소스 코드를 빠르게 읽고 이해하고 싶었습니다.

나는 그것에 대해 많이 안다고 주장할 수는 없지만 그렇게 간단하지는 않다고 생각합니다. - 칼 프랭클린 DotNetRocks 명성은 꽤 많은 성과를 거두었습니다. 본 적이 있나요? 그의 DNRTV?

미디어 플레이어를 사용할 수 있습니다:

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

.NET에서 광범위한 MIDI 및 Wave 조작을 위해서는 손이 필요하다고 생각합니다. NAudio 솔루션입니다(다음을 통해서도 사용 가능) NuGet).

최근 추가된 내용은 미디.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();
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top