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配列のデータ送信される



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











2021年4月7日水曜日

KS-3181の使い方

 KS-3181の使い方

秋月のお楽しみ袋に入っていた謎のIC「TAXAN KS-3181」を解析して使えるようにしてみました。








ピン数が64pinと多めなのですが、ダイ画像を見るとそこまで複雑な回路ではないとわかります。


解析の手順は、以前解析を行った「KY-3201P SGC」と同じなので省略します。

・ロジック

総当たり戦法でピンの解析をした結果、8ビット × 4 出力のラッチICということが分かりました。
8ビットでデータを入力して、2ビットで出力先を選択します。
そのほかにもちょこっと回路が付属していました。
また、一部不明なピン(内部にシフトレジスタがあるかも)がありました。



詳しく知りたい方は以下の回路を眺めてみてください。
ピン名はこちらで適当に付けました。

※KS-3181の内部回路がこれで合っているとは限りませんのでご注意ください。
使用の際は要検証をお願いします。この内容によって発生した損害は、いかなる理由であっても当方は責任を負いません。


回路図には含まれていませんが~CLRピン以外の入力ピンはKS-3181内部でプルアップされています。

ピンB0~B7にデータをセットして、~CSをH→Lにしたときに出力フリップフロップへストローブされます。


メインの使い道は、マイコン等のポート出力の追加としてでしょうか。
LEDキューブや大型のLED電光掲示板とか作れそうです。
ただ、ICのパッケージがSDIP64のため、普段電子工作で使うような2.54mmピッチ基板やブレッドボードに刺さりません。そこさえなんとかなれば、わりと有用なICであると思います。



・使用例

ArduinoでLED32個を点灯させてみました。

回路図





サンプルプログラム
//KS-3181_テストプログラム
void setup()
{
  //KS-3181のB0~B7をArduinoのピン0~7へ接続
  //KS-3181の~CS(3つのうち一つ、残り2つはGND)をArduinoのピン11へ接続
  //KS-3181のSEL_0,SEL_1をArduinoのピン8,9へ接続
  //KS-3181のMODE_0,MODE_1をGNDへ接続
  //KS-3181のCS,CLRをVCC(5V)へ接続
  //謎シフトレジスタIN_A,IN_BをGNDへ接続

  //データピン設定
  for(int pin_setup = 0;pin_setup < 8;pin_setup++){
    pinMode(pin_setup, OUTPUT);//D0~D7
    digitalWrite(pin_setup0); 
  }

  //チップセレクトピン設定
  pinMode(11, OUTPUT);//cs
  digitalWrite(110); 

  //ポートセレクトピン設定
  pinMode(8, OUTPUT);//sel_0
  pinMode(9, OUTPUT);//sel_1
  digitalWrite(80);
  digitalWrite(90);
}

void loop(){
  unsigned long data = 0;//4x8ビット点灯データ
  int dp = 0;//テスト点灯用
  int dp_c= 32;//テスト点灯用
  
  while (1)
  {
    ////////////////////////テスト点灯////////////////////////
    data = (long)1<<dp;
    data |= (long)0xFFFFFFFF<<dp_c;
    dp++;
    if(dp >= dp_c){
      dp = 0;
      dp_c--;
      
    }
    if(dp_c <= 0){
      dp_c = 32;
    }
    delay(10);
    ////////////////////////////////////////////////

    //出力
    for (int ps = 0ps < 4ps++)
    {
      digitalWrite(8ps & 1);//ポートセレクト
      digitalWrite(9, (ps >> 1) & 1);//ポートセレクト

      for (int pin_data = 0pin_data < 8pin_data++)
      {
        digitalWrite(pin_data, (data >> (pin_data + 8 * ps)) & 1);
      }
      digitalWrite(111);//チップセレクト_ラッチ
      delayMicroseconds(1);
      digitalWrite(110);
    }

  }


}















2021年4月3日土曜日

真空管付属データシート集

 真空管付属データシート集

箱入り真空管に入っていたデータシートや回路図を載せます。
画像サイズが大きめなので読み込みに時間がかかるかもしれません。


・日立 5EA8

テレビ用中増幅率3極・シャープカットオフ5極管

5EA8はテレビ受像機用3極、5極管で5極部は中間周波数増幅の最終段に、3極部は映像検波または同期分離などに適しています。





・ナショナル 7DJ8

カスコード型増巾器用真空管

ナショナル7DJ8はテレビのカスコード型増巾器用として特に設計された最新の高性能な双3極管でヒーター電流が0.3Aでありますからナショナル・テレビ用ワールドシリーズ真空管を使用したトランスレス。テレビセットのチューナー用真空管として最適であります。又7DJ8は雑音レベル及入力コンダクタンスが低く従って高利得を得ることができます。





・ナショナル 12AT7

TV用鋼増幅率槽3極管

12AT7 / ECC81 はテレビ受像機又はFM受信機等の超高周波帯に於ける高周波増幅(グリッド接地型,カソード接地型,プッシュプル型)及び周波数変換に使用される9ピンの高増幅率双3極管である。ヒーターにはセンタータップが出ているから,ヒーター電圧6.3V又は12.6Vの何れでも使用できる。又ヒーターが共通である以外は各ユニットは各々無関係であるから独立して使用する事が可能である。



ナショナルワールドシリーズ
14"トランスレス・テレビジョン受像機配線図(例)





・東芝 6AR5 Hi-Fi用

電力増幅用5極管

6AR5Hi-Fiは7ピンミニチュア形の電力増幅用5極管であります。シングルで3.4W、プッシュプルで7~8Wの出力が得られますので小形Hi-Fiアンプ、小型ホームラジオの電力増幅用に適しております。特性は6F6GTと同様で42類似品種であります。また、プッシュプル増幅には特性の揃ったペアチューブのご使用をおすすめいたします。



回路例





・ナショナル ラジオ用6.3VMTシリーズ

6BE6 , 6BA6 , 6AV6 , 6AR5 , 6X4 ,6BD6



ナショナル6.3VMTシリーズ使用
標準5球スーパー配線図(例)



おわり