ポートを列挙したら、次にポートを開きます。
但し、本気で仕掛け・挙動ともに複雑です。
このコードでも時々マーシャリングエラーが発生します。
// MIDI入力ポート public class MidiInPortHandle : IDisposable { public MidiInPortHandle(int portNum) // IDisposable 実装 public void Dispose() // ポートを閉じる public void Close() // MIDI受信 public event EventHandler<MidiInNativeEventArgs> MidiReceived; // ポートの名前 public string Name { get {} } }
MidiInPortHandle.cs
using System; namespace NextMIDI.MidiInPort { public class MidiInPortHandle : IDisposable { public MidiInPortHandle(int portNum) { name = MidiInApi.GetPortInformation(portNum).szPname; receiver = new MidiReceiver(portNum); receiver.MidiReceived += new EventHandler<MidiInNativeEventArgs>(MidiReceiver_MidiReceived); } string name = ""; MidiReceiver receiver; public event EventHandler<MidiInNativeEventArgs> MidiReceived; protected void OnMidiReceived(MidiInNativeEventArgs e) { if (MidiReceived != null) { MidiReceived(this, e); } } public void Dispose() { Close(); } public void Close() { if (receiver != null) { receiver.ClosePort(); receiver = null; } } private void MidiReceiver_MidiReceived(object sender, MidiInNativeEventArgs e) { OnMidiReceived(e); } public string Name { get { return name; } } } }
MidiReceiver.cs
using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Threading; using System.Windows.Forms; namespace NextMIDI.MidiInPort { internal class MidiReceiver : Control, IDisposable { internal MidiReceiver(int portNum) { isOpen = true; //----------// ポートハンドル作成 midiInOpen(ref systemHandle, portNum, this.Handle, 0, MidiInCallBackFlag.callBack_Window); //----------// バッファ作成 buffer = new MidiInBuffer(); buffer.SystemHandle = systemHandle; buffer.ResetHeader(); //----------// MIDI入力ポート起動 midiInStart(systemHandle); //----------// } public event EventHandler<MidiInNativeEventArgs> MidiReceived; protected void OnMidiReceived(MidiInNativeEventArgs e) { if (MidiReceived != null) { MidiReceived(this, e); } } uint systemHandle = 0; bool isOpen = false; MidiInBuffer buffer; void IDisposable.Dispose() { ClosePort(); base.Dispose(); } public void ClosePort() { InternalClose internalClose = new InternalClose(ClosePortInternal); this.Invoke(internalClose); } delegate void InternalClose(); private void ClosePortInternal() { if (isOpen) { isOpen = false; //----------// 入力を停止する midiInStop(systemHandle); //----------// 未処理のバッファをコールバック関数に返す /* while ((dataHeader.dwFlags & MidiHdrFlag.MHDR_DONE) == 0) { Thread.Sleep(1); } */ midiInReset(systemHandle); buffer.UnprepareHeader(); //----------// midiInClose(systemHandle); } } protected override void WndProc(ref Message m) { if (isOpen) { switch (m.Msg) { case 0x3C1: //MM_MIM_OPEN return; case 0x3C2: //MM_MIM_CLOSE return; case 0x3C3: //MM_MIM_DATA int receiveData = m.LParam.ToInt32(); Thread.CurrentThread.Priority = ThreadPriority.AboveNormal; switch (receiveData & 0xF0) { case 0x80: case 0x90: case 0xA0: case 0xB0: case 0xE0: OnMidiReceived(new MidiInNativeEventArgs(new byte[3] { Convert.ToByte(receiveData & 255), Convert.ToByte((receiveData & 65535) >> 8), Convert.ToByte((receiveData & ((2 << 24) - 1)) >> 16) })); break; case 0xC0: case 0xD0: OnMidiReceived(new MidiInNativeEventArgs(new byte[2] { Convert.ToByte(receiveData & 255), Convert.ToByte((receiveData & 65535) >> 8) })); break; } Thread.CurrentThread.Priority = ThreadPriority.Normal; return; case 0x3C4: //MM_MIM_LONGDATA Thread.CurrentThread.Priority = ThreadPriority.AboveNormal; byte[] receiveLongData = buffer.GetData(); buffer.ResetHeader(); OnMidiReceived(new MidiInNativeEventArgs(receiveLongData)); Thread.CurrentThread.Priority = ThreadPriority.Normal; return; case 0x3C5: //MM_MIM_ERROR return; case 0x3C6: //MM_MIM_LONGERROR return; case 0x3CC: //MOREDATA return; default: base.WndProc(ref m); return; } } else { base.WndProc(ref m); return; } } [DllImport("winmm.dll")] private static extern int midiInOpen(ref uint lphMidiIn, int uDeviceID, System.IntPtr dwCallback, int dwCallbackInstance, int dwFlags); [DllImport("winmm.dll")] private static extern int midiInClose(uint hMidiIn); [DllImport("winmm.dll")] private static extern int midiInStart(uint hMidiIn); [DllImport("winmm.dll")] private static extern int midiInStop(uint hMidiIn); [DllImport("winmm.dll")] private static extern int midiInReset(uint hMidiIn); } }
MidiInBuffer.cs
using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Threading; using NextMIDI.MidiPort; namespace NextMIDI.MidiInPort { internal class MidiInBuffer : IDisposable { internal MidiInBuffer() { dataHandle = GCHandle.Alloc(new byte[128], GCHandleType.Pinned); dataHeader.lpData = dataHandle.AddrOfPinnedObject(); dataHeader.dwBufferLength = 128; } GCHandle dataHandle = new GCHandle(); MidiHdr dataHeader = new MidiHdr(); uint systemHandle = 0; object lockTarget = new object(); internal void Clear() { lock (lockTarget) { dataHandle.Free(); } } public void Dispose() { Clear(); } internal void ResetHeader() { lock (lockTarget) { midiInPrepareHeader(systemHandle, ref dataHeader, Marshal.SizeOf(typeof(MidiHdr))); while ((dataHeader.dwFlags & MidiHdrFlag.MHDR_PREPARED) == 0) { Thread.Sleep(1); } midiInAddBuffer(systemHandle, ref dataHeader, Marshal.SizeOf(typeof(MidiHdr))); } } internal void UnprepareHeader() { lock (lockTarget) { if ((dataHeader.dwFlags & MidiHdrFlag.MHDR_PREPARED) == MidiHdrFlag.MHDR_PREPARED) { midiInUnprepareHeader(systemHandle, ref dataHeader, Marshal.SizeOf(typeof(MidiHdr))); } } } internal byte[] GetData() { lock (lockTarget) { if (!dataHandle.IsAllocated) { return null; } if (dataHeader.dwBufferLength < dataHeader.dwBytesRecorded) { throw new InvalidOperationException(); } byte[] data = (byte[])dataHandle.Target; int dataLength = (int)dataHeader.dwBytesRecorded; byte[] receiveBytes = new byte[dataLength]; for (int i = 0; i < dataLength; i++) { receiveBytes[i] = data[i]; } return receiveBytes; } } internal uint SystemHandle { get { return systemHandle; } set { lock (lockTarget) { systemHandle = value; } } } [DllImport("winmm.dll")] private static extern int midiInPrepareHeader(uint hMidiIn, ref MidiHdr lpMidiInHdr, int uSize); [DllImport("winmm.dll")] private static extern int midiInUnprepareHeader(uint hMidiIn, ref MidiHdr lpMidiInHdr, int uSize); [DllImport("winmm.dll")] private static extern int midiInAddBuffer(uint hMidiIn, ref MidiHdr lpMidiInHdr, int uSize); } }
MidiInCallBackFlag.cs
using System; namespace NextMIDI.MidiInPort { public class MidiInCallBackFlag { /// <summary> /// 第三引数がコントロールハンドルであることを示します。 /// </summary> public const int callBack_Window = 0x10000; } }
MidiInNativeEventArgs.cs
using System; namespace NextMIDI.MidiInPort { public class MidiInNativeEventArgs : EventArgs { public MidiInNativeEventArgs(byte[] data) { this.data = data; } byte[] data; public byte[] ReceiveData { get { return data; } } } }Top