2010/09/18 - MIDIキーボード入力アプリができた

C#でMIDIキーボード入力をやってみる。midiInOpenにコールバックを登録しておけば,midiInStart/midiInStopでメッセージを受け取れる。

{
    [DllImport("winmm.dll")]
    public static extern uint midiOutOpen(
        ref IntPtr phmo,
        uint uDeviceID,
        IntPtr dwCallback,
        IntPtr dwInstance,
        uint fdwOpen);

    public delegate void CallBackDelegate(
        IntPtr hdrvr,
        uint uMsg,
        uint dwUser,
        uint dw1,
        uint dw2);
}

public class MIDIIn
{
    private Win32MIDI.CallBackDelegate _callback = null;

    public void Open()
    {
        _callback = new Win32MIDI.CallBackDelegate(CallBack);

        Win32MIDI.midiInOpen(
            ref _midiin,
            _mididevice,
            (IntPtr)Marshal.GetFunctionPointerForDelegate(_callback),
            (IntPtr)0,
            Win32MIDI.CALLBACK_FUNCTION);
    }

    private void CallBack(IntPtr hdrvr, uint uMsg, uint dwUser, uint dw1, uint dw2)
    {
        int state = (int)dw1 & 0xff;
        int data1 = (int)dw1 >> 8 & 0xff;
        int data2 = (int)dw1 >> 16 & 0xff;
    }
}

最初,C++で実装するときと同じようにCallBackをstaticメソッドにしていたのだが,インスタンスのメンバ変数を使いたくて,midiInOpenのdwInstanceにthisを渡すことを考えていた。でもthisをIntPtrに変換する方法というか変換していいのかを調べても何も情報は見つからない。最終的に「GetFunctionPointerForDelegateはthisポインタをうまいこと扱ってくれる」というような記述を見つけて,思いきってstaticを取ったらそのまま動いた。C++の発想だとstaticにしないと動かないのでメンバ関数をそのまま渡すというのは思いつきもしなかった。こんな感じで半日を無駄にしてしまった。

その後は順調に進んで,キーボード練習ソフトっぽいものはできあがった。そろそろもばもば(?)に投げてみよう。

コメントする