LoginSignup
1
0

MIDI input処理テスト

Last updated at Posted at 2017-08-16

#1 MIDI入力の処理

レガシーなMIDI音源モジュールを作るための下ごしらえとしてArduino用MIDIの入力処理プログラムを書いてみます。動作のためにMIDIインターフェスが必要ですがインターフェースはスイッチサイエンスのMIDIシールドキットを使いました。

このスケッチは2年ほど前に書いたものでMIDIライブラリは使っていません。MIDI規格書にありますMIDI-IN ランニングステータス処理のアルゴリズムをそのままインプリメントしました。今の処システムエクルクルーシブ等は処理せずに捨てる様になっています。

MIDISheld.jpg

入力されたMIDIメッセージのランニングステータスを個々のフルMIDIメッセージに展開してmidi-in のバッファ mbuff[]へ格納します。mbuffから順繰りにデータを読込んで行って個々のメッセージの処理が出来る様になるはず、です。

この例では確認のためにKeyOnメッセージでLEDオン、KeyOffでLEDオフするようにしました。MIDI-INタイミングでのLED点滅もしてみたのですがアクティブセンシングが頻繁に来るので点滅タイミングは間引きするようにしています。

ちょとあやしいところは、mbuff[]は256バイトのリングバッファで、読出し・格納ポインタとして unsigned char の変数 inpt,outptを使っています。が、outpt=255 の時に a = mbuff[outpt+1] とした場合 a にmbuff[0] が入ってくれるか mbuff[256] が入ってしまうか、、、DOS時代にはこれで問題無く処理してくれましたがもしかしたらバグってるかもしれません。その辺ご注意下さい。

MIDI-LED.ino
/* -------------------------------

      MIDI IN LED Blink

      Ringoro
      
      2015/5/12
      2017/8/16

--------------------------------- */

unsigned char runsts=0;
unsigned char byt3flg=0;
unsigned char inpt=0;
unsigned char outpt=0;
unsigned char mbuff[256];
unsigned char laston;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(31250);
  runsts=0;
  byt3flg=0;
  inpt=0;
  outpt=0;
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
//  digitalWrite(6,HIGH);  // LED LOW Active 
//  digitalWrite(7,HIGH); 
}

void bit71(char);   // Bit7 = 1 proc. 
void bit70(char);   // Bit7 = 0 proc.

/*
 *      MIDI Running Status Proc.
 *      
 *  Apendix-2
 *  http://amei.or.jp/midistandardcommittee/MIDIspcj.html
 *  
 *    
 */
void midi_in_proc(char d)
{
  
  if((d & 0x80)){
    bit71(d);
    return;
  } else {
    bit70(d);
  }
}

// bit7=1 Status Byte proc

void bit71(char d)
{
  if(d>=0xF8){ // do nothing
   return;
  }
  runsts = d;
  byt3flg=0;
  if(d == 0xF6){  // data push
    mbuff[inpt++]=d;
  }
  else {
    // not increment pt 
  }
}

// Data Byte proc

void bit70(char d)
{
 if(byt3flg){
   byt3flg=0;
   mbuff[inpt+2]=d;
   inpt=inpt+3;
   return;
   }
 //  else
 
 if(runsts==0){  
   return; // do nothing
 }
  if(runsts < 0xC0){
    goto proc2;
  }
  if (runsts<0xE9){
      goto proc3;
  }
  
  if(runsts < 0xF0){
    goto proc2;
  }
  
  if(runsts==0xF2){ // song position pt
    runsts=0;
    goto proc2;
  }
  
  if(runsts==0xF3 || runsts == 0xF1){
    runsts = 0;  // 2bytes Status
    goto proc3;
  }
  // else do nothing
  // !! SysExc not proceed. !!
  runsts=0;
  return;
  
  
proc2:  // byt 2 of 3-Bytes data proc
  byt3flg=1;
  mbuff[inpt]=runsts;
  mbuff[inpt+1]=d;
  // not increment. wait 3byt
  return;

proc3:  // 2-bytes Status
  mbuff[inpt]=runsts;
  mbuff[inpt+1]=d;
  inpt = inpt+2;
  return;
  
}

void loop() {
  // MIDI IN Buffer check
  if(inpt == outpt)
     return;

  if(mbuff[outpt] <= 0x7F){
      outpt++;
      return;
  }
   
  if((mbuff[outpt]  & 0xF0)==0x90){
    outpt = outpt+2;
    if(mbuff[outpt] == 0){
         digitalWrite(7, HIGH);  // KeyOFF
         outpt=outpt+1;
         return;
    } else { 
      digitalWrite(7, LOW);     // KeyON
      outpt = outpt+1;
      return;
      }
    }
    if((mbuff[outpt]  & 0xF0)==0x80){
      digitalWrite(7,HIGH);        // KeyOFF
      outpt = outpt+3;
      return;
    }

   // else...
  outpt++;

}

/*
 * When MIDI IN
 */

void serialEvent() {
  static int c;
  while (Serial.available()) {
//   digitalWrite(6, LOW);
    // get the new byte:
    char c = (char)Serial.read();
    midi_in_proc(c);
  }
  if (c++ & 0x04){
     digitalWrite(6, !digitalRead(6));
  }
}

1
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0