MIDI演奏

  1. MIDI演奏


    1. MIDIとは

       MIDIは音楽演奏用のインターフェース規格で、シリアル接続でコントローラ、プレーヤ(音源)、鍵盤、を接続する規格です。ここでは、ノートオンコマンドを発生する簡単なコントローラを作成します。

    2. MIDIメッセージ

       midiのノートオンメッセージは、
       楽器の種類(音色)、音の高さ(音階)、音の強さ、
      を指定します。これを受けた音源は指定の音色、高さ、強さ、で音を出し始めます、
      音を終了するには、同じ音色、高さ、で強さ0のメッセージを送ります。
       具体的なメッセージの形式は
            0x9n,note,velocity
      です。0xは16進表記の意味です。n: はチャンネル番号で0..15がmidiのチャンネル1..16に対応します。midiチャンネルは楽器の音色に対応します。
      noteは音の高さでピアノ鍵盤の中央のド(c4)が60となります。半音を含めた鍵盤に通し番号をつけます。したがって、中央のレの音は62となります。velocity は音の強さを示し、0は無音、127をff(フォルテッシモ:最強)とします。

    3. 送信規則

       MIDIではこのメッセージの各バイトを、RS232Cと同じフォーマットでシリアル送信します。したがって、先頭に 0 のスタートビット、続けて 8ビット のメッセージバイト、最後に1ビットのストップビットを付加します。
       このシリアルデータを、ビット当たり32μSで送ります。したがって、1バイトは320μ秒で送ります。

    4. 送信ドライバ、レシーバ

       コネクタには5ピンDIN型コネクタを利用します。装置側はメス型で、ケーブルがオス型になります。電気的にはカレントループで送信側は、数mAのカレントループを構成します。0を送るには、4ピンから5ピンに数mAの電流を流せば良いのです。2ピンはケースグラウンドで、信号線のシールドを接続します。
       受信側では、4-5ピン間に光結合素子(フォトカプラ)を接続して信号を取り出します。したがって、ケーブルの信号線は2本のみです。



    5. MIDI音源

      本回路でMIDI演奏を行うには、MIDI音源が必要です。専用のMIDI音源を利用するか、MIDI演奏機能のあるPCにUSB-MIDI アダプタを付加します。

  2. 回路

    1. 回路

       MIDIの場合、電圧変換回路は不要です。MIDIコネクタに必要な信号端子は1本のみです。これにPICのPB5を利用します。PB5 を220オームの抵抗を通してMIDIコネクタの5ピンに接続します。また、MIDIコネクタの4ピンを抵抗を通して、電源(5V)に接続します。

    2. 回路図

      回路は、シリアル出力とMIDIコネクタの5ピンを接続し、MIDIコネクタの4ピンを5Vに接続するだけです。


  3. プログラム

    1. シリアル出力

       CSCCコンパイラは、#use RS232() でハードウエアでシリアル出力できない入出力端子を指定すると、ソフトウエアでシリアル送受信が可能になります(ただし、割り込みは利用できません)。MIDIのシリアル出力波形は、RS232Cと同じですから、RS232C(標準出力)に midi コマンドを送れば、MIDIプレーヤで演奏可能です。
      ここでは、以下のようにRS232Cを宣言します。
           #use RS232(BAUD=31250, xmit=PIN_B5, rcv=PIN_B2)
      31250はMIDIで規定の伝送速度です。
       int data[3]
      の3バイトにmidiコマンドを設定し、void SendData() で、MIDIコマンドを出力します。data[3]は次のように設定します。
       data[0] = 0x90; // 0x9n n=0..15チャンネル 
       data[1] = 60; // note 
       data[2] = 64; // velocity 0〜127
      これは、0x90はノートオン(発音)コマンドで、0チャンネル(GM音源ではピアノ音)に、ノート番号60(中央のド)を、強さ64で出力します。続けてノート音コマンドを出せば、音が重なって聞こえます。ここでは。ド、ミ、ソ の音を重ねます。0.5秒の休止後、強さ0のノートオンコマンドで発声を停止します。
       
    2. ソース

      //#include <16f88.h>
      #include <16f873A.h>
      
      //プログラミング:奥田
      
      #fuses HS, NOWDT, NOPROTECT, NOBROWNOUT, NODEBUG, NOLVP
      #use delay(CLOCK=20000000)
      #use RS232(BAUD=31250, xmit=PIN_B5, rcv=PIN_B2) // BAUD=312501 ⇒ 1バイトを320usで送信
      
      int data[3];
      
      void SendData();
      
      void main()
      {
              while(1)
              {
                      // ドの音
                      data[0] = 0x90;         // 0x9n n=0..15チャンネル
                      data[1] = 60;           // note
                      data[2] = 64;           // velocity 0〜127
                      SendData();
      
                      // レの音
                      data[0] = 0x90;         // 0x9n n=0..15チャンネル
                      data[1] = 64;           // note
                      data[2] = 64;           // velocity 0〜127
                      SendData();
      
                      // ミの音
                      data[0] = 0x90;         // 0x9n n=0..15チャンネル
                      data[1] = 67;           // note
                      data[2] = 64;           // velocity 0〜127
                      SendData();
      
                      delay_ms(500);
      
                      data[0] = 0x90;         // 0x9n n=0..15チャンネル
                      data[1] = 60;           // note
                      data[2] = 0;            // velocity 0〜127
                      SendData();
      
                      data[0] = 0x90;         // 0x9n n=0..15チャンネル
                      data[1] = 64;           // note
                      data[2] = 0;            // velocity 0〜127
                      SendData();
      
                      data[0] = 0x90;         // 0x9n n=0..15チャンネル
                      data[1] = 67;           // note
                      data[2] = 0;            // velocity 0〜127
                      SendData();
      
                      delay_ms(500);
              }
      }
      
      // データを送る
      void SendData()
      {
              int i;
              for(i=0; i<3; i++) putc(data[i]);
      }

  4. 発展

    1. 楽譜入力

       MIDIコマンドを配列に記録し、演奏してください。ただし、16F873Aではメモリ配列は最大で64バイト程度しか確保できません。
      二つの配列に分割すると、さらに同程度の配列が確保できます。

    2. MIDIコマンド

       チャンネル番号を変えると音色を変更できます。ベロシティや他のMIDIコマンドで演奏スタイルを変更してください。

    3. 外部メモリ

       外部メモリを追加すると、1曲の再生が可能です。