YMF825 MIDI 音源モジュール(ペダル対応)

 練習を進めていて、今はポリフォニックの音源モジュールが売られていて、ArduinoにYMF825 MIDI音源モジュールを接続したものを作って使うのが良さそう(しかも安い)とわかった。PC内蔵音源だと練習していてどうもMIDI-USB変換のせいなのか、若干遅れがあるような気がして、それを改善したかった。しかもこれなら製作難易度がそれほどでもないかと。

 最初は大昔のようにシンセサイザーの様なものを作ろうかと調べたけれど、モノフォニックではピアノの練習には使えないし、、、(ちゃんと弾けるようになったらそれはそれでいつか作る予定だけれど)結構な時間がかかる。

 Arduino+YMF825 の記事はネットで検索したら結構あるんだけれど、主なものは掲載が数年前のためかlink切れで肝心のソースが見つからない。林檎朗さんの "Arduino YMF825board レガシー MIDI音源モジュール" というのが自分でも修正できそうなものであり、これを使わせてもらって、何とか思った動きに変更できた。改変したソースを公開してもよいと許諾をもらったので、ペダル対応したものを今回以下に記載することにした。

オリジナルからの変更点

①ソフトデバッグを容易にするために、MIDI入出力はSoftwareSerialとして、D2/D3に変更(D0/D1はUSB側につながっているのでシリアルモニタ使用可能)

②プログラムチェンジの音色は使っているキーボードA-33に合わせて16音に変更

③あとでシーケンサーなどをつなごうと、D4にclock outを追加 (HAGIWO/ハギヲさんの "900円で作るMIDI to CVモジュール-モジュラーシンセ自作" の回路及びソースを流用)

④ペダル対応としてMIDIのコントロールチェンジ:64 の追加(ちなみにハーフペダル等には対応していないので0/127の値以外は怪しいです)

 ペダルの動作はあっていると思うけれど、何せ本物のピアノを持っていなのでネットで調べた動作仕様を元に処理を追加している。これはおかしいという場合は指摘していただけると助かります。もちろん改変は自由ですので大元のMITライセンスにしたがって下さい。

以下の3種のスケッチをArduino IDEでコンパイルしてください。

1. ソースコード(midiinproc.ino)

/*
*      MIDI Running Status Proc.
*      
*  Apendix-2
*  http://amei.or.jp/midistandardcommittee/MIDIspcj.html
*  
*    fix  2017 9/14
*/
/*  2021/12/25 revised kurita  */

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

void midi_in_proc(unsigned char d)
{
 
 if((d & 0x80)){
   bit71(d);
   return;
 } else {
   bit70(d);
 }
}

// bit7=1 Status Byte proc

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

// Data Byte proc

void bit70(unsigned char d)
{
if(byt3flg){
  byt3flg=0;
  mbuff[(inpt+2)&0xFF]=d;
  inpt=inpt+3;
  return;
  }
//  else

if(runsts==0){  
   return; // do nothing
   }

 if(runsts < 0xC0){   // 80,90,B0
   goto proc2;
 }
 if (runsts<0xE0){    // fix 9/14 C0,D0
     goto proc3;
 }
 
 if(runsts < 0xF0){   // E0
   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)&0xFF]=d;
 // not increment. wait 3byt
 return;

proc3:  // 2-bytes Status
 mbuff[inpt]=runsts;
 mbuff[(inpt+1)&0xFF]=d;
 inpt = inpt+2;
 return;

}

2. ソースコード(ymf825cont.ino)

/*
* 
* from github 
  https://github.com/yamaha-webmusic/ymf825board

  
  RST_N- Pin9
  SS   - Pin10
  MOSI - Pin11
  MISO - Pin12
  SCK  - Pin13
*/

#include <SPI.h>
//0 :5V 1:3.3V
#define OUTPUT_power 0

unsigned char mastervol = (0x27 << 2); /* change 0x33 -> 0x27 */
//unsigned char mastervol = (0x3F << 2);

unsigned char vovol = (0x18 << 2);
unsigned char chvol = (0x1F << 2);

unsigned char modu = 0x00;

int pbendval = 0x200;

/*
* F-Numb Table C...B
*/
int fnumtable[12] = {
 357,     /* C */
 378,
 401,
 425,
 450,
 477,
 505,
 535,
 567,
 601,
 637,
 674
};

/*
* Block numb. on Center Octave C Note=60 
*/
int block=4;

void set_ss_pin(int val) {
   if(val ==HIGH) PORTB |= (4);
   else PORTB &= ~(4);
}

void set_rst_pin(int val) {
   if(val ==HIGH) PORTB |= (2);
   else PORTB &= ~(2);
}

void if_write(char addr,unsigned char* data,char num){
 char i;
 char snd;
   set_ss_pin(LOW);
   SPI.transfer(addr);
   for(i=0;i<num;i++){
     SPI.transfer(data[i]);    
   }
   set_ss_pin(HIGH);  
}

void if_s_write(char addr,unsigned char data){
 if_write(addr,&data,1);
}

unsigned char if_s_read(char addr){
 
   unsigned char rcv;
   
   set_ss_pin(LOW);    
   SPI.transfer(0x80|addr);
   rcv = SPI.transfer(0x00);
   set_ss_pin(HIGH);  
   return rcv;  
}

void init_825(void) {
  set_rst_pin(LOW);
  delay(1);
  set_rst_pin(HIGH);
  if_s_write( 0x1D, OUTPUT_power );
  if_s_write( 0x02, 0x0E );
  delay(1);
  if_s_write( 0x00, 0x01 );//CLKEN
  if_s_write( 0x01, 0x00 ); //AKRST
  if_s_write( 0x1A, 0xA3 );
  delay(1);
  if_s_write( 0x1A, 0x00 );
  delay(30);
  if_s_write( 0x02, 0x04 );//AP1,AP3
  delay(1);
  if_s_write( 0x02, 0x00 );
  //add
  if_s_write( 0x19,mastervol );//MASTER VOL
  if_s_write( 0x1B, 0x3F );//interpolation
  if_s_write( 0x14, 0x00 );//interpolation
  if_s_write( 0x03, 0x01 );//Analog Gain
  
  if_s_write( 0x08, 0xF6 );
  delay(21);
  if_s_write( 0x08, 0x00 );
  if_s_write( 0x09, 0xF8 );
  if_s_write( 0x0A, 0x00 );
  
  if_s_write( 0x17, 0x40 );//MS_S
  if_s_write( 0x18, 0x00 );
}

unsigned char tone_data[35] ={
   0x81,//header
   //T_ADR 0
/*  SquareLead */
/*  0x01,0x85,
   0x00,0x7F,0xF4,0xBB,0x00,0x10,0x40,
   0x00,0xAF,0xA0,0x0E,0x03,0x10,0x40,
   0x00,0x2F,0xF3,0x9B,0x00,0x20,0x41,
   0x00,0xAF,0xA0,0x0E,0x01,0x10,0x40, */
/*  GrandPiano */
   0x01,0x43,
   0x00,0x67,0xFF,0x9D,0x00,0x10,0x40,
   0x21,0x33,0xE2,0xA3,0x00,0x50,0x00,
   0x10,0x41,0xD3,0x88,0x01,0x10,0x00,
   0x21,0x62,0xD4,0x02,0x01,0x10,0x00,
   0x80,0x03,0x81,0x80,
 };

void set_tone(void){
 
  if_s_write( 0x08, 0xF6 );
  delay(1);
  if_s_write( 0x08, 0x00 );
 
  if_write( 0x07, &tone_data[0], 35 );//write to FIFO
}

/* 
*  Set Channel Vol. etc.
*/

void set_ch(void){
 char  i;
 unsigned char frac1,frac2;
 
 for(i=0;i<16;i++){
  if_s_write( 0x0B, i );// voice num
  if_s_write( 0x0F, 0x30 );// keyon = 0
  if_s_write( 0x10, chvol);// chvol
  if_s_write( 0x11, 0x00 );// XVB

  if_s_write( 0x12, 0x08 );// FRAC
  if_s_write( 0x13, 0x00 );// FRAC 

 }
}

/*
* Key On/Off Multi Voice
*/

void keyon(unsigned char fnumh, unsigned char fnuml,unsigned char vn,unsigned char vel){
//   if_s_write( 0x0B, 0x00 );//voice num
  if_s_write( 0x0B, vn );//voice num
//   if_s_write( 0x0C, 0x54 );//vovol
  if_s_write( 0x0C, vel << 2 );// velocity -> vovol
  if_s_write( 17, modu ); // modulate
  if_s_write( 0x0D, fnumh );//fnum
  if_s_write( 0x0E, fnuml );//fnum
  if_s_write( 0x0F, 0x40 );//keyon = 1  
}

void keyoff(unsigned char vn){
  if_s_write( 0x0B, vn );//voice num
  if_s_write( 0x0F, 0x00 );//keyon = 0

  
}
void ymf825setup() {
 // put your setup code here, to run once:
 pinMode(9,OUTPUT);
 pinMode(10,OUTPUT);
 set_ss_pin(HIGH);

 SPI.setBitOrder(MSBFIRST);
 SPI.setClockDivider(SPI_CLOCK_DIV8);
 SPI.setDataMode(SPI_MODE0);
 SPI.begin();

 init_825();
 set_tone();
 set_ch();
}

/*
*   Add Contorles
*/

void setmastervol(unsigned char v)
{
 v =( v/3 ) << 2; /* /2 -> /3 */
 if(v != mastervol){
   mastervol = v;
   if_s_write( 0x19,mastervol );//MASTER VOL
 }
}

void setmodulate(unsigned char m)
{
 int v;
 m =  m >> 4;
 if(m == modu)
 {return;}
   
 modu=m;
 for(v=0;v<16;v++){
    if_s_write( 0x0B, v );//voice num
    if_s_write( 17, m );  // modulate
 }
 
}

void alloff()
{
 int v;
 for(v=0;v<16;v++){
    if_s_write( 0x0B, v );//voice num
    if_s_write( 15, 0x30 );  // Keyoff,Mute,EG_RST
 }
 
}

/*
* Pitch Bend
*/

void setpbend(int bd)
{
  unsigned char frac1,frac2;
  int v;
 if(bd==pbendval)
 {return;}

 pbendval=bd;

 frac2 = (unsigned char)((bd<<1) & 0x00fe);
 frac1 = (unsigned char)(((bd<<2) & 0x1f00)>>8);
 
 digitalWrite(7, !digitalRead(7));  
 for(v=0;v<16;v++){
    if_s_write( 0x0B, v );//voice num
    if_s_write( 0x12, frac1 );// FRAC
    if_s_write( 0x13, frac2 );// FRAC 
 }
 
}

3. ソースコード(YMF825MIDImodule.ino)

  /*
*  YMF825 Legacy MIDI Module
*  2022/02/20 revised kurita for adding damper pedal
*
*    Ringoro
* 
*  2017/9/18
*  2017/9/25  
*    use case 
*    PROGMEM
*       9/29
*    CC 1,7,123
*       10/3
*    P.Bnend Table
*
*/

#include <avr/pgmspace.h>  // Flash memory library

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

byte clock_count = 0;
byte clock_max = 24;	//clock_max change by knob setting
int clock_rate = 0;	//knob CVin

byte cc64 =0 ; //damper pedal

#define KON   0x90
#define KOFF  0x80
#define CTRL  0xB0
#define PRG   0xC0	//tone change
#define BEND  0xE0
#define PRES  0xD0
#define AFT   0xA0
#define CLOCK 0xF8	//timing clock
#define ACTIVE 0xFE //active sensing

#define CC_MOD  1
#define CC_VOL  7
#define CC_DMP  64
#define CC_ALLOFF 123


extern int fnumtable[12];

#define C4  60

void noteon(int nt ,int vn,int vel)	// vn:voice number,vel:velocity
{
   int n,fn;
   unsigned char blk,fnl0,fnl,fnh;
//    char s[50];

   vel = vel  >>2;   // 7bit to 5bit
   n = nt % 12;
   blk = (unsigned char)(nt / 12) - 1; // fix 9/28
   fn = fnumtable[n];
   fnh =  fn & 0b01111111;
   fnl =  (fn & 0b001110000000) >> 4 | blk;
//    sprintf(s,"note= %2X  %2X",fnl,fnh);
//    Serial.println(s);
   keyon(fnl,fnh,vn,vel);   /* KEY-ON! */
}

void noteoff(int nt,int v)
{ 
   keyoff(v); 
}


/*
* Note OO/OFF Send 
*/

unsigned char keybuff[16]={0};
boolean hold[16]={false} ; /* for each voice nubmer */
unsigned char setpt=0;

int noteonsend(unsigned char nt,unsigned char vel)
{
//  char s[100];
 byte v;
 if (cc64> 64){  /* if damper pedal on */
  for(v=0;v<16;v++){
     if((keybuff[v]==nt)&&(hold[v]==true)){ /* when same key re-on */
       noteoff(nt,v); /* once noteoff */
       keybuff[v]=0;  /* the keybuff clear */
       hold[v]=false; /* the hold status clear */
     }
  }
 }
 for(v=0;v<16;v++){ /* at first time noteon */
     if(keybuff[setpt]==0){
       keybuff[setpt]=nt;
       hold[setpt]=false; /* when noteon ,the hold status clear */
       noteon(nt,setpt,vel);
       setpt = (setpt+1) & 0x0F;
       digitalWrite(7, !digitalRead(7));	/* for debug */
//        sprintf(s,"key%2s","on");
//        Serial.println(s); 
//        sprintf(s,"key= %2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d",keybuff[0],keybuff[1],keybuff[2],keybuff[3],keybuff[4],keybuff[5],keybuff[6],keybuff[7],keybuff[8],keybuff[9],keybuff[10],keybuff[11],keybuff[12],keybuff[13],keybuff[14],keybuff[15] );  /* for debug */
//        Serial.println(s); 
       return 1;
     } else {
        setpt = (setpt+1) & 0x0F;
     }
  }
  return 0;
}

int noteoffsend(unsigned char nt)
{
//   char s[100];
  byte  v;
  for(v=0;v<16;v++){
     if(keybuff[v]==nt){
      if(cc64<64){
       keybuff[v]=0;
       noteoff(nt,v);
      } else { hold[v]=true;}
//      sprintf(s,"key%3s","off");
//      Serial.println(s); 
//      sprintf(s,"key= %2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d",keybuff[0],keybuff[1],keybuff[2],keybuff[3],keybuff[4],keybuff[5],keybuff[6],keybuff[7],keybuff[8],keybuff[9],keybuff[10],keybuff[11],keybuff[12],keybuff[13],keybuff[14],keybuff[15] );  /* for debug */
//      Serial.println(s); 
//      sprintf(s,"hold= %2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d",hold[0],hold[1],hold[2],hold[3],hold[4],hold[5],hold[6],hold[7],hold[8],hold[9],hold[10],hold[11],hold[12],hold[13],hold[14],hold[15] );  /* for debug */
//      Serial.println(s); 
      return 1;
     }
  }
  return 0;
}

/*
* SET UP 
*/

#include <SoftwareSerial.h>
SoftwareSerial midiSerial(2, 3); // RX, TX

void setup() {

 ymf825setup();

/*  Serial.begin(31500); */
 Serial.begin(57600);      /* hard serial for serial monitor */
 midiSerial.begin(31250);  /* soft serial */

 runsts=0;
 byt3flg=0;
 inpt=0;
 outpt=0;
 pinMode(6, OUTPUT);	/* MIDI in */
 digitalWrite(6, HIGH);
 pinMode(7, OUTPUT);	/* note on/off */
 pinMode(4, OUTPUT);	/* clock out */
}

/*
* Main LOOP
*/

bool first=true;

void loop()
{
  unsigned char sts,b1,b2;
 if(first){
   testplay();
   first=false;
 }

/*
* When MIDI IN  ** change into loop **
*/

//  char s[50];          /* for debug */
 unsigned char  c;
 while (midiSerial.available() ) { 
   c = (char)midiSerial.read();
//  while (Serial.available() ) { 
//    c = (char)Serial.read();
   midi_in_proc(c); 
   
//    digitalWrite(6, !digitalRead(6));    /* for debug */
//    if((c != CLOCK )&&(c != ACTIVE )){  
//    sprintf(s,"midii= %2X",c);  /* for debug */
//    Serial.println(s);      /* for debug */
//    } 
 }

 //  clock_rate_check 
 clock_rate = analogRead(1);	//read knob voltage
 if (clock_rate < 256) {
	  clock_max = 24;	//slow
	}
	else if (clock_rate < 512 && clock_rate >= 256) {
		clock_max = 12;
	}
	else if (clock_rate < 768 && clock_rate >= 512) {
		clock_max = 6;
	}
	else if (clock_rate >= 768) {
		clock_max = 3;	//fast
	}
		
 // MIDI IN Buffer check
 if(inpt == outpt)
    return;

 sts=mbuff[outpt] & 0xFE; // MIDI ch. lower bit mask
 b1=mbuff[(outpt+1)&0xFF];
 b2=mbuff[(outpt+2)&0xFF];

 if(sts <= 0x7F){
     outpt++;
     return;
 }

//  each event

 switch(sts){
   case KON:
     if(b2==0){
       noteoffsend(b1);
     } else {
       noteonsend(b1,b2);
     }
     outpt=outpt+3;
     break;

   case KOFF:
     noteoffsend(b1);
     outpt=outpt+3;
     break;

    case CLOCK:
     clockout();  
     outpt++;
     break;
     
   case PRG:
     progchang(b1);
     outpt=outpt+2;
     break;
     
   case CTRL:
     ctrlchange(b1,b2);
     outpt=outpt+3;     	
     break;
     
   case BEND:
     ptchbend(b1,b2);
     outpt=outpt+3;
     break;
 
  defalut:
   outpt++;

 }
}


/*
* Test Play
*  C E G 'C
*/

char notes[]={60,60,67,67,69,69,67,00,65,65,64,64,62,62,60};

void testplay() {
 int i;
 int d;

 for(i=0;i<sizeof(notes);i++){
   if (notes[i] != 0) {
     noteon(notes[i],0,90);
     delay(200);
     noteoff(notes[i],0);
     delay(50);
   } else {
     delay(250);
   }
 }

}


/*
* Tone Parameters
* 
*/

// const  unsigned char   program[4][30]={

const  unsigned char PROGMEM   program[16][30]={

{
/*
GrandPiano(1)
*/  
0x01,0x43,
0x00,0x67,0xFF,0x9D,0x00,0x10,0x40,
0x21,0x33,0xE2,0xA3,0x00,0x50,0x00,
0x10,0x41,0xD3,0x88,0x01,0x10,0x00,
0x21,0x62,0xD4,0x02,0x01,0x10,0x00
},
{
/*
Vibes(2)
*/  
0x01,0x45,
0x20,0x44,0xC2,0x5C,0x41,0x70,0x00,
0x21,0x59,0xD6,0x1E,0x51,0x40,0x00,
0x21,0x34,0xC2,0x78,0x51,0x80,0x00,
0x30,0x42,0xDF,0x1C,0x31,0x10,0x00
},
{
/*
ChurchOrgan(3)
*/
0x01,0x47,
0x00,0x5F,0x90,0x4E,0x00,0x30,0x00,
0x00,0x27,0xB2,0x74,0x00,0x70,0x00,
0x00,0x5F,0x80,0x12,0x00,0x10,0x00,
0x00,0x57,0x80,0x12,0x00,0x00,0x28
},
{
/*
NylonGuiter(4)
*/  
0x01,0x85,
0x11,0x41,0xE8,0x55,0x00,0x10,0x06,
0x30,0x73,0xFF,0x00,0x01,0x10,0x00,
0x51,0x55,0xB4,0x38,0x00,0x30,0x00,
0x40,0x94,0xDF,0x36,0x03,0x10,0x00
},
{
/*
PickBass(5)
*/  
0x01,0x43,
0x21,0x37,0xF1,0x4E,0x44,0x10,0x05,
0x41,0x6B,0xC7,0x54,0x44,0x70,0x00,
0x21,0x69,0xF2,0x5E,0x44,0x20,0x00,
0x61,0x82,0xB6,0x00,0x44,0x10,0x00
},
{
/*
Violin(6)
*/  
0x01,0x85,
0x03,0x30,0x60,0x26,0x00,0x10,0x0A,
0x02,0x76,0x61,0x0C,0x13,0x10,0x00,
0x73,0x76,0xE0,0x21,0x10,0x10,0x32,
0x72,0x77,0x6F,0x0E,0x03,0x10,0x00
},
{
/*
Strings(7)
*/  
0x01,0x85,
0x02,0x28,0x91,0x6C,0x10,0x16,0x00,
0x02,0x5F,0x70,0x1C,0x03,0x13,0x00,
0x03,0x2B,0x90,0x50,0x10,0x13,0x20,
0x02,0x4F,0x60,0x01,0x13,0x17,0x00
},
{
/*
mu.trampet(8)
*/  
0x01,0x45,
0x02,0x09,0x70,0x43,0x00,0x12,0x40,
0x02,0x7E,0x90,0x06,0x01,0x17,0x00,
0x02,0x29,0x61,0x5A,0x30,0x16,0x04,
0x02,0x7E,0xA0,0x06,0x01,0x13,0x40
},
{
/*
TenorSax(9)
*/  
0x01,0x45,
0x01,0x03,0x70,0x16,0x44,0x10,0x0B,
0x00,0x92,0x70,0x3C,0x43,0x10,0x40,
0x01,0x03,0x70,0x22,0x44,0x10,0x48,
0x00,0x92,0x70,0x36,0x43,0x10,0x00
},
{
/*
Flute(10)
*/  
0x01,0x45,
0x00,0x1A,0xD1,0x1C,0x10,0x30,0x07,
0x00,0xB8,0x73,0x94,0x01,0x30,0x00,
0x00,0x98,0xE0,0x9C,0x31,0x10,0x07,
0x00,0xA5,0x60,0x04,0x11,0x10,0x80
},
{
/*
SquareLead(11)
*/  
0x01,0x85,
0x00,0x7F,0xF4,0xB8,0x00,0x10,0x40,
0x00,0xAF,0xA0,0x0E,0x03,0x10,0x40,
0x00,0x2F,0xF3,0x9B,0x10,0x20,0x41,
0x00,0xAF,0xA0,0x0E,0x01,0x10,0x40
},
{
/*
NewAgePd(12)
*/  
0x01,0x45,
0x31,0x3F,0xF0,0x98,0x44,0x70,0x0D,
0x40,0x47,0xF0,0x2E,0x44,0x50,0x00,
0x00,0x11,0x60,0x62,0x03,0x17,0x0E,
0x00,0x51,0x81,0x02,0x03,0x10,0x00
},
{
/*
Ice Rain(13)
*/  
0x01,0x85,
0x02,0x33,0x63,0x4A,0x10,0x30,0x03,
0x02,0x42,0x40,0x25,0x01,0x30,0x00,
0x02,0x33,0x63,0x40,0x00,0x10,0x85,
0x02,0x41,0x41,0x0E,0x03,0x10,0x00
},
{
/*
Siter(14)
*/  
0x01,0x85,
0x23,0x13,0xD1,0x28,0x00,0x10,0x20,
0x33,0x53,0xDE,0x02,0x03,0x30,0x00,
0x42,0x27,0xF1,0x3C,0x01,0x60,0x08,
0x82,0x87,0xFE,0x02,0x03,0x10,0x08
},
{
/*
SteelDrums(15)
*/  
0x01,0x45,
0x91,0x9A,0xF2,0x86,0x44,0x51,0x05,
0x71,0x7A,0xF2,0x00,0x44,0x23,0x00,
0xA0,0x8A,0xF2,0x70,0x44,0xA3,0x00,
0x70,0x7A,0xF2,0x00,0x44,0x20,0x00
},
{
/*
Rain(16)
*/ 
/* 
0x01,0x85,
0x33,0x37,0x3A,0x56,0x55,0x50,0x00,
0x73,0x76,0x53,0x01,0x55,0xA0,0x00,
0x33,0x37,0x3A,0x56,0x55,0x50,0x00,
0x43,0x46,0x53,0x01,0x75,0xA7,0x00
}
*/
/*
TnkBell(16)
*/
0x01,0x45,
0x30,0x46,0xF5,0x41,0x44,0xE0,0x03,
0x70,0x66,0xCE,0x2E,0x44,0x20,0x00,
0x20,0x26,0xC5,0x78,0x44,0x77,0x08,
0x40,0x55,0xFD,0x04,0x54,0x60,0x00,
}
};

/*
*   Prog change 
*/
extern unsigned char tone_data[35];
void progchang(unsigned char p)
{
 int i;
//  p = p & 0x3;
 byte j;
 byte k=0;
 byte patch[16]={0,11,18,24,33,40,49,59,68,75,80,94,96,104,114,122};
 for (j=0;j<16;j++){
   if (patch[j]==p){
     k=j;
     break;
   }
 }

 for(i=0;i<30;i++){
   tone_data[i+1]=pgm_read_byte_near(&(program[k][0])+i);
//    tone_data[i+1]=program[p][i];
 }
 set_tone();
 
}

/*
* Control Change
*/
void ctrlchange(unsigned char b1,unsigned char b2)
{
//  char s[100];          /* for debug */
 switch(b1){
   case CC_VOL:  // 7
     setmastervol(b2);
     break;
  case CC_MOD:   // 1
     setmodulate(b2);
     break;

  case CC_DMP:  // 64
     byte v;
     v=0 ;
     cc64=b2;
     if (b2<64){
       while (v<16){
        if(hold[v]==true){
          noteoff(keybuff[v],v);
//        sprintf(s,"damper%3s","key");
//        Serial.println(s); 
//        sprintf(s,"key= %2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d",keybuff[0],keybuff[1],keybuff[2],keybuff[3],keybuff[4],keybuff[5],keybuff[6],keybuff[7],keybuff[8],keybuff[9],keybuff[10],keybuff[11],keybuff[12],keybuff[13],keybuff[14],keybuff[15] );  /* for debug */
//        Serial.println(s); 
//        sprintf(s,"hold= %2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d,%2d",hold[0],hold[1],hold[2],hold[3],hold[4],hold[5],hold[6],hold[7],hold[8],hold[9],hold[10],hold[11],hold[12],hold[13],hold[14],hold[15] );  /* for debug */
//        Serial.println(s); 
          keybuff[v]=0;
          hold[v]=false;
         }
         v++;
       }
      }
      if (cc64==127){digitalWrite(6, LOW);} else {digitalWrite(6, HIGH);} /* for debug */ 
      break;

  case CC_ALLOFF:  // 123(0x7B)
     alloff();
     break;

  default:
   break;
   
 }
 
}

void clockout() {
	clock_count ++;
	if (clock_count > clock_max) {
		clock_count = 0;
	}
	if (clock_count == 1) {
		digitalWrite(4, HIGH);
	}
	else if (clock_count != 1) {  
		digitalWrite(4, LOW);
	}
}

/*
* Pitch Bend
* 
*  conver to REG #18,19   256...512...1023
*  by Table
*  
*/
int ptchbend(unsigned char b1,unsigned char b2)
{
PROGMEM static const unsigned short tPitTbl[256] = {
 256,257,259,260,262,263,264,266,267,269,270,272,273,275,276,278,
 279,281,282,284,285,287,288,290,292,293,295,296,298,300,301,303,
 304,306,308,309,311,313,314,316,318,320,321,323,325,327,328,330,
 332,334,336,337,339,341,343,345,347,349,350,352,354,356,358,360,
 362,364,366,368,370,372,374,376,378,380,382,384,386,388,391,393,
 395,397,399,401,403,406,408,410,412,415,417,419,421,424,426,428,
 431,433,435,438,440,442,445,447,450,452,454,457,459,462,464,467,
 470,472,475,477,480,482,485,488,490,493,496,498,501,504,506,509,
 512,515,518,520,523,526,529,532,535,538,540,543,546,549,552,555,
 558,561,564,567,571,574,577,580,583,586,589,593,596,599,602,606,
 609,612,616,619,622,626,629,632,636,639,643,646,650,653,657,660,
 664,668,671,675,679,682,686,690,693,697,701,705,709,712,716,720,
 724,728,732,736,740,744,748,752,756,760,764,769,773,777,781,785,
 790,794,798,803,807,811,816,820,825,829,834,838,843,847,852,856,
 861,866,870,875,880,885,890,894,899,904,909,914,919,924,929,934,
 939,944,949,954,960,965,970,975,981,986,991,997,1002,1007,1013,1023 };

 extern int pbendval;
 int k,bd,bv;
 bv = b2*128 + b1;
 k = bv / 64;

 bd = pgm_read_word_near(tPitTbl + k);

 setpbend(bd);
 return bd;  
}

/*
* pitch Bend   unused...
* 
*  conver to REG #18,19   256...512...1023
*  
*/
/*
int _ptchbend(unsigned char b1,unsigned char b2)
{
 extern int pbendval;
 long   dlt,bv,bd;

 bv = b2*128 + b1;
 dlt = bv-8192;

 if (dlt==0){
   bd = 512;
   }
 if (dlt > 0){
   bd = 512 * (dlt+8192)/8192;
 }

 if (dlt < 0){
   dlt = 0 - dlt;
   bd = 512L * 8192L /(8192+dlt);
 }
 setpbend((int)bd);
 return (int)bd;  
}

*/

※本物のピアノでペダル仕様は確認してあっていた、良かった。



この記事が気に入ったらサポートをしてみませんか?