arduinoスケッチのサンプルを少し改造して、シリアル入力で演奏できるように改造しました。
arduinoコンソールで演奏、有線シリアル通信での演奏、BluetoothモジュールをつければAndroidやiPhoneからSPPで無線再生できると思います。
本サンプルは下記2つをシリアルで行うことが出来ます。
①歌詞の指定(PA)
②音符の演奏(MML)
動画はarduinoコンソールで演奏した例
■使用の前に
・arduinoとeVY1shieldソフトウェアシリアルを使用します。
eYV1shieldのJP2を2-3に変更してください。
・(ハードウェアの)シリアル通信でコマンド入力します。
本サンプルでは9600bpsで改行コードは[LFのみ]です
■歌詞指定
#のあとに発声(Phonetic symbols)を入力します
アイウエオの5音例 ⇒ #a,i,M,e,o
歌詞指定については、YMW820(NSX-1) MIDI仕様書:日本語eVocaloid™Phonetic Alphabet(PA)を参照の事
Yamaha-WebMusic GitHubPage(現時点では一番下のSpecにあります)
http://yamaha-webmusic.github.io/nsx1-apps/manual/
PDF直リンク
http://yamaha-webmusic.github.io/nsx1-apps/specs/ANMW820A-001-10-j.pdf
■音符再生
再生はMMLで指定します。
ド:C レ:D ミ:E ファ:F ソ:G ラ:A シ:B で指定します。
半音や付点・オクターブ変更など何も出来ません。
音長は全て500msで固定になっています
ドレミファソの例 ⇒ CDEFG
先に歌詞指定をしてから、音符再生すると歌います。
基本的に元のかえるの歌サンプルそのままです。
#include <avr/pgmspace.h>
#include <SoftwareSerial.h>
#define CHANNEL 0 //(0:eVocaloid 1-15:MIDI(9:drum) )
/*
* 注意:
* SoftwareSerial使用の為eYV1shieldのJP2を2-3に変更する事
*/
int led = 13;
//SW-Serial: eVY1 shield
SoftwareSerial swSerial(2, 3);
void setup() {
// initialize the digital pin as an output.
pinMode(led, OUTPUT);
// Set MIDI baud rate:
swSerial.begin(31250);
// HW-Serial: console
Serial.begin(9600);
//delay(1000);
}
char recv_buf[32]; // 受信用バッファ32bytes
char *p_buf=recv_buf;//受信バッファポインタ(初期値recv_buf先頭アドレス)
void loop(){
//シリアル受信処理
while(Serial.available()>0){
*p_buf = Serial.read();//1byte読み込みバッファに書き込み
if(*p_buf=='\n'){
*p_buf='\0';// \0:null(文字列終端)で改行を上書き
receive_data(recv_buf);//受信データ処理
p_buf=recv_buf;//受信バッファポインタ初期値化
}else{
p_buf++;
}
}
}
//serialコマンドデータ受信
void receive_data(char *recvdata) {
if(strlen(recvdata)!=0){
if(*recvdata=='#'){
//歌詞設定
lylic_send(recvdata);
}else{
//mml再生
play_mml(recvdata);
}
}
}
//mml再生
void play_mml(char *recvdata) {
int key = 0x3c; //C
int wait =500;
int oct = 0;
char mml[256];
strcpy(mml,recvdata);
int mml_len = strlen(mml) / sizeof(mml[0]);
Serial.print("mml:[");
Serial.print(mml);
Serial.println("]");
for(int i = 0;i< mml_len ;i++){ char c = mml[i]; if(c >= 'a' && c <='z') c-= 0x20; if((c>='A' && c<='Z')||c=='<'||c=='>'){
//key send
if(i!=0){
Short_Message((byte)(0x90 | CHANNEL),key,0x7f);//note on
delay(wait);
Short_Message((byte)(0x80 | CHANNEL),key,0x7f);//note off
}
key= 0x3c;
switch(c) {
case 'C': break;
case 'D': key+=2; break;
case 'E': key+=4; break;
case 'F': key+=5; break;
case 'G': key+=7; break;
case 'A': key+=9; break;
case 'B': key+=11; break;
default: break;
}
}
}
Short_Message((byte)(0x90 | CHANNEL),key,0x7f);
delay(wait);
Short_Message((byte)(0x80 | CHANNEL),key,0x7f);//note off
}
void Short_Message(int cmd, int d1, int d2) {
swSerial.write((byte)cmd);
swSerial.write((byte)d1);
swSerial.write((byte)d2);
}
//lylic send
void lylic_send(char *str){
//Phonetic symbols hedaer f04379090050は固定
swSerial.write((byte)0xF0);
swSerial.write((byte)0x43);
swSerial.write((byte)0x79);
swSerial.write((byte)0x09);
swSerial.write((byte)0x00);
swSerial.write((byte)0x50);
swSerial.write((byte)0x10);//10:replace 11:append
Serial.print("lylic:[");
for(int i=1;i<strlen(str)+1;i++){
swSerial.write(*(str+i));
Serial.print(*(str+i));
}
Serial.println("]");
//footer
swSerial.write((byte)0x00);//end of list
swSerial.write((byte)0xF7);
}
■その他
・歌詞(発音)指定について、
元サンプルには文字→発音の変換テーブルが付いていましたが、50音の単音、濁音、半濁音のみで、
仕様書と比較するとテーブルが全て用意されている訳ではなく、自由度が低くなるのでローレベルで指定するようにしました。
(たとえばシェとかがないです)
スペースで区切ると1つの音符に対して、連続発音で指定できました
“a i”で”あい”のような。
元々ボカロっている人じゃないので少し難しいです。
・CHANNELで0をdefineしてますが、MIDIのチャネルをあらわしています。
0が特別にeVocaloidに割り当てられていて、その他チャネルが普通のMIDIのようです。
1~8,10~15にするとピアノの音がなります。(0以外の場合歌詞指定は不要です)
音色変更機能は未実装ですのでピアノから変更できません。
9にするとドラムセットです。
・一部ちゃんと音が出ない発音がありますので、本サンプルを信用しないでください(^^;
バグだと思うのですが解析する時間がとれず・・・
・元のサンプルでNOTE ON音鳴らした後、NOTE OFFしてない等気に食わない部分は微修正してます
MMLについては、これしか出来ないのに不満爆発なので過去に作ったやつを移植したいです。
いつかMMLで楽器+eVocaloid同時演奏もしたいですね。