YMF825のテストプログラム

#1 パソコンキーボードを鍵盤にみたててYMF825を鳴らす

というスケッチを書いて見たのですが、実物が無いので音出せません。何か間違いあるかもしません。はい。(後から試しました音出ました)
ymf825board_sample1.inoを参考に書きました。

~~~書いていて気が付いたのですが、YMF825のマニュアルのF-Numberのレジスタビット並びがサンプルプログラムと異なってますねえ。マニュアルでは Fnumbの上位3ビットはレジスタの bit3-bit5 に並ぶ様に記載されていますがこの通りにビットシフトするとサンプルスケッチの値と食い違います。。。~~~と思ったらビットの勘定間違えてました。マニュアル通りです。

（月末にYMF825boardが手に入ったら試してみます。でも大分人気な様で本当に入手できるかあやしいですが。。
実物持っている人は試してみて欲しいです。）

キー配列はパソコンキーボードの小文字cが中央の「ド」です。この「ド」のノートをMIDIキーコードの中央ド(=60)に割当ててオクターブと12音を割り出してFM音源のFnumber,Blockを計算します。やや回りくどいですが、後々MIDI音源モジュールみたいなものを作るためにこういうやり方にしました。
スペースでノートオフしますが、このスケッチではYMF825へ同じボイスをOFFせずにノートONを送れることもできるのですがその場合なにが何が起こるのでしょう。。。普通に考えればレガート奏法になると思いますが。

```YFM825KBD.ino

/*
 *  YMF825 PC KDB Play
 * 
 *    2017/8/12
 *
 
   RST_N- Pin9
   SS   - Pin10
   MOSI - Pin11
   MISO - Pin12
   SCK  - Pin13
 
  PC KBD Layout

   s    f g   j k l
  z x  c v b n m , . /
  
 */
struct kbdnote{
  char key;
  char note;
} pcbkbd[16] = {
  {'z',-3},
  {'s',-2},
  {'x',-1},
  {'c', 0},
  {'f', 1},
  {'v', 2},
  {'g', 3},
  {'b', 4},
  {'n', 5},
  {'j', 6},
  {'m', 7},
  {'k', 8},
  {',', 9},
  {'l',10},
  {'.',11},
  {'/',12}
};
/*
 * F-Numb Table C...B
 */
int fnumtable[] = {
  357,     /* C */
  378,
  401,
  425,
  450,
  477,
  505,
  535,
  567,
  601,
  637,
  674
};

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

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

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, 0x20 );//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 );
}

void set_tone(void){
  unsigned char tone_data[35] ={
    0x81,//header
    //T_ADR 0
    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,
    0x80,0x03,0x81,0x80,
  };
  
   if_s_write( 0x08, 0xF6 );
   delay(1);
   if_s_write( 0x08, 0x00 );
  
   if_write( 0x07, &tone_data[0], 35 );//write to FIFO
}

void set_ch(void){
   if_s_write( 0x0F, 0x30 );// keyon = 0
   if_s_write( 0x10, 0x71 );// chvol
   if_s_write( 0x11, 0x00 );// XVB
   if_s_write( 0x12, 0x08 );// FRAC
   if_s_write( 0x13, 0x00 );// FRAC  
}

void keyon(unsigned char fnumh, unsigned char fnuml){
   if_s_write( 0x0B, 0x00 );//voice num
   if_s_write( 0x0C, 0x54 );//vovol
   if_s_write( 0x0D, fnumh );//fnum
   if_s_write( 0x0E, fnuml );//fnum
   if_s_write( 0x0F, 0x40 );//keyon = 1  
}

void keyoff(void){
   if_s_write( 0x0F, 0x00 );//keyon = 0
}

#define C4  60

void noteon(int nt)
{
    int n,fn;
    unsigned char blk,fnl0,fnl,fnh;
    char s[50];
    n = nt % 12;
    blk = (unsigned char)(nt / 12) - 1;
    fn = fnumtable[n];
    fnh =  fn & 0b01111111;
    fnl =  (fn & 0b001110000000) >> 4 | blk;
    sprintf(s,"note= %2X  %2X",fnl,fnh);
    Serial.println(s);
    keyon(fnl,fnh);   /* KEY-ON! */
}

/*
 * Note Check & Key ON
 */
int notecheck(char c)
{
    int i,rtn=0;
    for(i=0;i<16;i++){
      if(pcbkbd[i].key==c){
        noteon(pcbkbd[i].note + C4);
        rtn =  1;   /* Note Match */
      }
    }

  return rtn ; 
}


void setup() {
  // 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();

  Serial.begin(9600); 
}

void loop()
{
  char c;
  if (Serial.available() == 0)
    return;
  c = Serial.read();

  if(notecheck(c))
    return;

  if(c==' ')  /* Space Key = OFF */
   { keyoff(); Serial.println("Key OFF");}


}

void _loop() {
  // put your main code here, to run repeatedly:
  keyon(0x14,0x65);
  delay(500);
  keyoff();
  delay(200);
  keyon(0x1c,0x11);
  delay(500);
  keyoff();
  delay(200);
  keyon(0x1c,0x42);
  delay(500);
  keyoff();
  delay(200);
  keyon(0x1c,0x5d);
  delay(500);
  keyoff();
  delay(200);
  keyon(0x24,0x17);
  delay(500);
  keyoff();
  delay(200);
}
```