2016-11-03 11 views
0

그래서 저는 midiOutShortMsg()를 사용하여 C#에서 단일 음표를 연주하려고합니다. 문제는 사운드가 재생되지 않는다는 것입니다. 내가 노트를 연주하는 것으로 알아 낸 한 가지 방법은 i = 0에서 10000까지의 for 루프에 midiOutShortMsg()를 삽입하는 것입니다.하지만 API가 작동하는 방법은 그렇게 생각하지 않습니다.C# midioutshortmsg no sound

나중에 프로젝트에서 MIDI를 Kinect 프로젝트에 구현하고 for 루프를 사용하여 Kinect의 실시간 피드백을 지연시킵니다. 그래서 for 루프 메서드는 no-go이다.

다음은 메모를 재생할 때 사용하는 코드입니다. for 루프를 주석 처리하면 소리가 재생되지 않습니다. 어떤 도움을 주시면 감사하겠습니다.

using System; 
using System.Runtime.InteropServices; 
using System.Text; 

namespace MIDITest 
{ 

    [StructLayout(LayoutKind.Sequential)] 
    public struct MidiOutCaps 
    { 
     public UInt16 wMid; 
     public UInt16 wPid; 
     public UInt32 vDriverVersion; 

     [MarshalAs(UnmanagedType.ByValTStr, 
      SizeConst = 32)] 
     public String szPname; 

     public UInt16 wTechnology; 
     public UInt16 wVoices; 
     public UInt16 wNotes; 
     public UInt16 wChannelMask; 
     public UInt32 dwSupport; 
    } 

class Program 
    { 
     // MCI INterface 
     [DllImport("winmm.dll")] 
     private static extern long mciSendString(string command, 
      StringBuilder returnValue, int returnLength, 
      IntPtr winHandle); 

     // Midi API 
     [DllImport("winmm.dll")] 
     private static extern int midiOutGetNumDevs(); 

     [DllImport("winmm.dll")] 
     private static extern int midiOutGetDevCaps(Int32 uDeviceID, 
      ref MidiOutCaps lpMidiOutCaps, UInt32 cbMidiOutCaps); 

     [DllImport("winmm.dll")] 
     private static extern int midiOutOpen(ref int handle, 
      int deviceID, MidiCallBack proc, int instance, int flags); 

     [DllImport("winmm.dll")] 
     private static extern int midiOutShortMsg(int handle, 
      int message); 

     [DllImport("winmm.dll")] 
     private static extern int midiOutClose(int handle); 

     private delegate void MidiCallBack(int handle, int msg, 
      int instance, int param1, int param2); 

     static void Main() 
     { 
      int handle = 0; 

      var numDevs = midiOutGetNumDevs(); 
      Console.WriteLine("You have {0} midi output devices", numDevs); 
      MidiOutCaps myCaps = new MidiOutCaps(); 
      var res = midiOutGetDevCaps(0, ref myCaps, 
        (UInt32)Marshal.SizeOf(myCaps)); 

      res = midiOutOpen(ref handle, 0, null, 0, 0); 

      byte[] data = new byte[4]; 

      data[0] = 0x90; 
      data[1] = 50; 
      data[2] = 111; 
      uint msg = BitConverter.ToUInt32(data, 0); 

      for (int i = 0; i < 10000; i++) 
      { 
       // both hard coding the message and creating it with byte doesn't work 
       //res = midiOutShortMsg(handle, 0x007F4A90); 
       res = midiOutShortMsg(handle, (int)msg); 
      } 
      res = midiOutClose(handle); 
      Console.ReadLine(); 
     } 
    } 
} 
+1

이 방법이 잘못되었다고 생각합니다. 이를 위해 기존의 MIDI 라이브러리를 사용하십시오. 나는 [naudio] (https://github.com/naudio/NAudio)를 존경합니다. 이미 잘 테스트되어야하는 MIDI IO 용 관리 랩퍼가 포함되어 있습니다. 왜 당신은 바이트 순서에 대해 걱정하고, 미디 래퍼 작성에 엄청난 시간을 낭비하지 않고 그것을 사용하지 않습니까? 그것은 당신에게 시간을 절약하고 상자에서 보편적 인 응용 프로그램을 지원합니다. 너는 너의 프로젝트에 그것을 (nuget 할 수있다) (https://www.nuget.org/packages/NAudio/) 쉽게. – spender

+0

안녕하세요, 귀하의 회신을 보내 주셔서 감사합니다! 저는 하루 종일 naudio에서 일해 왔지만, 하나의 노트를 연주 할 때도 System.Threading.Thread.Sleep()을 사용해야한다는 것을 알게되었습니다. 그리고 단일 음표를 연주하면 전체 프로그램이 중단되고 소리가 들리지 않는 동일한 문제가 발생합니다. 어떤 대안을 알게됩니까? – Shinsuke

답변

0

midiOutShortMsg는 음이 재생 시간을 가졌다 전에 midiOutClose가 호출되는 것을 의미하는 코드의 실행을 중지하지 않기 때문입니다. 이 문제를 극복하기

한 가지 방법은 추가하는 것 Sleep : length는 재생이 끝날 때까지 참고 걸리는 밀리 시간이

res = midiOutShortMsg(handle, (int)msg); 

if (res == 0) // Check success code 
{ 
    System.Threading.Thread.Sleep(length); 
} 

res = midiOutClose(handle); 

.

그러나 이것은 거의 권장되지 않습니다.

+1

MIDI로 일반 창 타이머를 사용하면 음악적으로 가장 문맹한 사람조차도 알아볼 수있을 정도로 타이밍이 너무 흐려집니다. – spender

+0

Bassie! 불행히도 System.Threading.Thread.Sleep()에서는 Kinect가 기본적으로 단일 스레드이므로 프로그램 전체가 중지됩니다. 나는 멀티 스레딩을 찾고 있지만 kinect는 초당 30 프레임으로 업데이트됩니다. 나는 실수로 스레드의 미친 양을 만들고 싶지 않고 다른 해결 방법을 알고 있는지 궁금해하고 있습니다! – Shinsuke

+0

@Shinsuke 문제 없음 - 응용 프로그램에서 소리가 출력되는지 확인할 수 있으며 소리가 더 이상 재생되지 않을 때까지 'midiOutClose'를 호출하지 마십시오. – Bassie