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;
}
*/
※本物のピアノでペダル仕様は確認してあっていた、良かった。
この記事が気に入ったらサポートをしてみませんか?