2021年4月10日土曜日

.net c#でmidiの受信をする (おーぷんMIDIぷろじぇくと)

 .net c#でmidiの送受信をする (おーぷんMIDIぷろじぇくと)

.net frameworkでmidiの送受信を行うには直接WindowsAPIを呼び出す必要があります。

ですが、かなり面倒になるので、今回はc++用のライブラリを使用してmidiの送受信を実現してみます。

この記事では自分用のメモでもあるため、詳しい説明をいれません。

当方プログラミング初心者のため間違いが多いと思います。

.net framework 4.7.2でうまく動くと思います。(まあ、別のバージョンでも動くでしょう)



MIDIメッセージ入出力用ライブラリ『MIDIIOライブラリ』(DLL)



まず、MIDIIOライブラリ バージョン1.2をダウンロードし、「MIDIIOLib1.2」→「Release」内にある「MIDIIO.dll」を実行ファイルと同ディレクトリに配置します。

今回は.net c#フォームアプリケーションでmidiの送受信を行いたいと思います。



下記のコードをnamespace内に記述します。コードの内容は「DllImport」で検索するといろいろ出てくると思います。

public class Open_midi_project
{
    //インストールされているMIDI入力デバイスの数を調べる。MIDI入力デバイスが何もインストールされていない場合0を返す。
    [DllImport("MIDIIO.dll")]
    public static extern int MIDIIn_GetDeviceNum();

    //MIDI入力デバイスの名前を調べる。lIndexには0以上、MIDIIn_GetDeviceNumで得られた値-1以下の値を指定すれば、正常にMIDI入力デバイスの名前を取得することができる。その他のインデックスを指定した場合、この関数は失敗し、0を返す。 なお、MIDI入力デバイスの名前は通常32文字以下(ヌル文字含む)であるので、バッファとしては32文字のTCHAR型配列を用意しておけば十分である。
    [DllImport("MIDIIO.dll")]
    public static extern int MIDIIn_GetDeviceName(int lIndexIntPtr pszDeviceNameint lLen);

    //MIDI入力デバイスを開く。
    [DllImport("MIDIIO.dll")]
    public static extern IntPtr MIDIIn_Open(string pszDeviceName);
    
    //MIDI入力デバイスを閉じる。
    [DllImport("MIDIIO.dll")]
    public static extern int MIDIIn_Close(IntPtr pMIDIIn);

    //現在使用しているMIDI入力デバイスを閉じ、新しいMIDI入力デバイスを開く。
    [DllImport("MIDIIO.dll")]
    public static extern IntPtr MIDIIn_Reopen(IntPtr pMIDIInstring pszDeviceName);

    //MIDI入力デバイスをリセットし、MIDI入力デバイスを開いた直後の状態に初期化する。
    [DllImport("MIDIIO.dll")]
    public static extern int MIDIIn_Reset(IntPtr pMIDIIn);

    //MIDIメッセージをひとつ取得し、実際に取得したMIDIメッセージのバイト数を返す。
    [DllImport("MIDIIO.dll")]
    public static extern int MIDIIn_GetMIDIMessage(IntPtr pMIDIInIntPtr pMessage,int lLen);


    //インストールされているMIDI出力デバイスの数を調べる。MIDI入力デバイスが何もインストールされていない場合0を返す。
    [DllImport("MIDIIO.dll")]
    public static extern int MIDIOut_GetDeviceNum();

    //MIDI出力デバイスの名前を調べる。lIndexには0以上、MIDIOut_GetDeviceNumで得られた値-1以下の値を指定すれば、正常にMIDI入力デバイスの名前を取得することができる。その他のインデックスを指定した場合、この関数は失敗し、0を返す。 なお、MIDI入力デバイスの名前は通常32文字以下(ヌル文字含む)であるので、バッファとしては32文字のTCHAR型配列を用意しておけば十分である。
    [DllImport("MIDIIO.dll")]
    public static extern int MIDIOut_GetDeviceName(int lIndexIntPtr pszDeviceNameint lLen);

    //MIDI出力デバイスを開く。
    [DllImport("MIDIIO.dll")]
    public static extern IntPtr MIDIOut_Open(string pszDeviceName);

    //MIDI出力デバイスを閉じる。
    [DllImport("MIDIIO.dll")]
    public static extern int MIDIOut_Close(IntPtr pMIDIOut);

    //現在使用しているMIDI出力デバイスを閉じ、新しいMIDI出力デバイスを開く。
    [DllImport("MIDIIO.dll")]
    public static extern IntPtr MIDIOut_Reopen(IntPtr pMIDIOutstring pszDeviceName);

    //MIDI出力デバイスをリセットし、MIDI出力デバイスを開いた直後の状態に初期化する。
    [DllImport("MIDIIO.dll")]
    public static extern int MIDIOut_Reset(IntPtr pMIDIOut);

    //MIDIメッセージをひとつ送信し、実際に送信したMIDIメッセージのバイト数を返す。
    [DllImport("MIDIIO.dll")]
    public static extern int MIDIOut_PutMIDIMessage(IntPtr pMIDIOutIntPtr pMessageint lLen);

}



これで.netでおーぷんMIDIぷろじぇくとのMIDIIOライブラリを使う準備が整いました。

「MIDIIOLib1.2」→「docs」内にある「MIDIIO.html」(MIDIIOライブラリ公式ガイドブック)とほぼ同じ使い方ができます。
上記コードではMIDIIOライブラリ内のすべての関数を記述していません。使いたい関数がある場合は個別に追加してください。



・MIDI IN コード例

コンソールにインストールされているMIDI入力デバイスの数を表示

//インストールされているMIDI入力デバイスの数を表示
Console.WriteLine("MIDIIn_GetDeviceNum:"+Open_midi_project.MIDIIn_GetDeviceNum());
 


デバイスID  "num" のMIDI入力デバイスの名前を表示

//デバイスID  "num" のMIDI入力デバイスの名前を表示
IntPtr openmidi_in_dev_name = new IntPtr();
openmidi_in_dev_name = Marshal.AllocHGlobal(32); //32バイトのメモリ確保
Open_midi_project.MIDIIn_GetDeviceName(numopenmidi_in_dev_name32);
Console.WriteLine("DeviceName:" + Marshal.PtrToStringAnsi(openmidi_in_dev_name));
Marshal.FreeHGlobal(openmidi_in_dev_name); //メモリ解放



コンボボックス"midi_in_comboBox"にmidi入力デバイスを列挙する
※フォーム内にmidi_in_comboBoxが必要です。

//コンボボックス"midi_in_comboBox"にmidi入力デバイスを列挙する
midi_in_comboBox.Items.Clear();
midi_in_comboBox.Items.Add("選択してください");
for (int openmidi_device_id=0;openmidi_device_idOpen_midi_project.MIDIIn_GetDeviceNum(); openmidi_device_id++)
{
    IntPtr openmidi_in_dev_name = new IntPtr();
    openmidi_in_dev_name = Marshal.AllocHGlobal(32); //32バイトのメモリ確保
    Open_midi_project.MIDIIn_GetDeviceName(openmidi_device_idopenmidi_in_dev_name32);
    midi_in_comboBox.Items.Add(Marshal.PtrToStringAnsi(openmidi_in_dev_name));
    Marshal.FreeHGlobal(openmidi_in_dev_name); //メモリ解放
}



コンボボックス"midi_in_comboBox.Text"のMIDI入力ポートを開くor閉じる

//コンボボックス"midi_in_comboBox.Text"のMIDI入力ポートを開くor閉じる
IntPtr openmidi_in_hd = new IntPtr();
openmidi_in_hd = Open_midi_project.MIDIIn_Open(midi_in_comboBox.Text);//開く
Open_midi_project.MIDIIn_Close(openmidi_in_hd);//閉じる



MIDIメッセージ受け取り(逐次読み出しが必要)

//MIDIメッセージ受け取り
IntPtr openmidi_rx_buf = new IntPtr();
byte[] openmidi_in_data = new byte[256];

int openmidi_rx_buf_size = Open_midi_project.MIDIIn_GetMIDIMessage(openmidi_in_hdopenmidi_rx_buf,256);//受信バッファに溜まっているバイト数取得

Marshal.Copy(openmidi_rx_bufopenmidi_in_data0openmidi_rx_buf_size);
//openmidi_in_data配列に受信データが格納される






・MIDI OUT コード例


コンソールにインストールされているMIDI出力デバイスの数を表示

//インストールされているMIDI出力デバイスの数を表示
Console.WriteLine("MIDIOut_GetDeviceNum:" + Open_midi_project.MIDIOut_GetDeviceNum());



デバイスID  "num" のMIDI出力デバイスの名前を表示

//デバイスID  "num" のMIDI出力デバイスの名前を表示
IntPtr openmidi_out_dev_name = new IntPtr();
openmidi_out_dev_name = Marshal.AllocHGlobal(32); //32バイトのメモリ確保
Open_midi_project.MIDIOut_GetDeviceName(numopenmidi_out_dev_name32);
Console.WriteLine("DeviceName:" + Marshal.PtrToStringAnsi(openmidi_out_dev_name));
Marshal.FreeHGlobal(openmidi_out_dev_name); //メモリ解放



コンボボックス"midi_out_comboBox"にmidi出力デバイスを列挙する
※フォーム内にmidi_out_comboBoxが必要です。

//コンボボックス"midi_out_comboBox"にmidi出力デバイスを列挙する
midi_out_comboBox.Items.Clear();
midi_out_comboBox.Items.Add("選択してください");
for (int openmidi_device_id=0;openmidi_device_idOpen_midi_project.MIDIOut_GetDeviceNum(); openmidi_device_id++)
{
    IntPtr openmidi_out_dev_name = new IntPtr();
    openmidi_out_dev_name = Marshal.AllocHGlobal(32); //32バイトのメモリ確保
    Open_midi_project.MIDIOut_GetDeviceName(openmidi_device_idopenmidi_out_dev_name32);
    midi_out_comboBox.Items.Add(Marshal.PtrToStringAnsi(openmidi_out_dev_name));
    Marshal.FreeHGlobal(openmidi_out_dev_name); //メモリ解放
}



コンボボックス"midi_out_comboBox.Text"のMIDI出力ポートを開くor閉じる

//コンボボックス"midi_out_comboBox.Text"のMIDI出力ポートを開くor閉じる
IntPtr openmidi_out_hd = new IntPtr();
openmidi_out_hd = Open_midi_project.MIDIOut_Open(midi_out_comboBox.Text);//開く
Open_midi_project.MIDIOut_Close(openmidi_out_hd);//閉じる



MIDIメッセージ送信

//MIDIメッセージ送信
IntPtr openmidi_tx_buf = new IntPtr();
byte[] openmidi_out_data = new byte[256];
int byte_size_midi = 3;//送信するデータサイズ
byte[0]=0x90;
byte[1]=0x64;
byte[2]=0x7F;//ch1,vel:127,note:100ノートオン

Marshal.Copy(openmidi_out_data0openmidi_tx_bufbyte_size_midi);
Open_midi_project.MIDIOut_PutMIDIMessage(openmidi_out_hdopenmidi_tx_bufbyte_size_midi);
//openmidi_out_data配列のデータ送信される



各関数の使い方はこんな感じです。











0 件のコメント:

コメントを投稿