$23 YAMAHA PCM piano module-DIY Eurorack Modular Synthesizer
Seeeduino xiao(arduino)とNSX-39を使ってモジュラーシンセサイザー のPCMピアノモジュールを自作したので、その備忘録。
背景
自作モジュラーシンセの41作品目。
モジュラーシンセには多くの音源モジュールがある。FMやAM、倍音加算やウェーブテーブルなど種類豊富だ。しかしアコースティックなPCM音源のモジュールは種類が極めて少ない。
一方で、モジュラーシンセの代表的な音楽ジャンルのアンビエントでは、ピアノやギターといったアコースティック楽器が多く用いられる。
モジュラーシンセでアコースティック楽器の音を鳴らすべく、DIYを企画した。
モジュラーシンセでPCM音源を鳴らすなんて邪道だが、それが許されるのがDIYの世界だとおもってる。
制作物のスペック
ユーロラック規格 3U 12HPサイズ+α
電源:100mA ( at 5V )
YAMAHA NSX-1 ICベース
基板はGakken NSX-39(ポケットミク)を使用。
2音色(2ch)、ステレオ出力。
音色は12種類、エフェクト12種類+リバーブ+コーラス。
CV入力はV/octでクオンタイズしている。
可変パラメータ
・カットオフ周波数
・ボリューム(CH1とCH2の音量調整用)
・サスティンタイム(レベルではない、ゲート入力からのNOTE ON時間)
・リリースタイム
・オクターブ
・リバーブレート
・コーラスレート
・追加FXレート
・アーティキュレーション 周期(3拍、4拍、6拍)
・アーティキュレーション ベロシティ 8種類
・アーティキュレーション サスティンタイム 8種類
・V/octキャリブレーション
プッシュスイッチで音色と追加FXを切り替える。
設定はマイコンに保存可能。
12種類のFX、音色リストは以下の通り
YAMAHAのPCM ICなので、音が非常に良い。
アーティキュレーションというパラメータは人間的な演奏に近づけるための独自のパラメータだ。
同じベロシティ、同じサスティンタイムで演奏すると、機械的に感じてしまう。その対策として、一定の周期で抑揚を付けることで人間的な表現力を再現している。
製作費
総額約2500円
---------------------------------
Seeeduino xiao 580円
NSX-39基板 1000円
フロントパネル 150円
オペアンプ MPC6232 50円
USBケーブル(micro - type C) 500円
3.5mm ステレオプラグ 70円
他(汎用部品は下記リンク先参照)
NSX-39基板は1300円で買ったポケットミクから分解して手に入れた。
印刷鍵盤を300円、基板を1000円と見積もっている。
ハードウェア
コントローラーはSeeeduino xiaoを使用した。NSX-39とはUSB接続が必要なのだが、Seeeduino xiaoのMCU"SAMD21"は、これ単体でUSB hostとして動作するからだ。
Arduino UNOとUSB hostシールドの組み合わせでもNSX-39を動作させることは出来る。開発初期はこの組み合わせだったが、サイズとコストを下げるため、Seeeduino xiaoを採用した。
Seeeduino xiaoとNSX-39基板はUSBケーブルで接続される。NSX-39の音声出力はフロントパネルに接続される。かなり無茶のある基板構造だ。NSX-39基板はテープで絶縁処理して、モジュラーシンセのケースの中に格納する。
こういう無茶な構造のモジュールが作れるのも、自作の醍醐味だ。
NSX-39基板の取り出しは非常に簡単。ポケットミクの箱を分解して、ネジと数か所のリード線を切断すれば簡単に取り出せる。
ソフトウェア
USB host
Seeeduino XiaoでNSX-39を動かすライブラリが公開されているので、それをベースに開発を進めた。雑な説明にはなるが、リンク先のeVY1とはNSX-39の互換基板の様なものだ。
MIDI周り
可変抵抗やCV/GATEからの信号をUSB経由でNSX-39基板に送信する。送信内容はMIDIに準拠しているため、MIDI信号の内容について理解する必要がある。NSX-39のMIDI信号については下記のリンクが非常に詳しく解説している。
また、YAMAHAのデータシートからもMIDI信号の内容を読み取ることが出来る。とはいえ、制御のほとんどはGM音源のMIDIに準拠しているので、sys exを使わない限りデータシートを読む必要はない。
例えば、音を鳴らしたいときは「鍵盤を押す(NOTE ON)」処理をUSB経由でNSX-39基板に送ってやればよい。MIDI CH1のノートON、音の高さ、ベロシティの強さをバッファに一時保存して、それを一度に送信する。
void noteOn(uint8_t note)
{
uint8_t buf[3];
buf[0] = 0x91;// note on
buf[1] = note; // note
buf[2] = 0x7f; // Velocity
Midi.SendData(buf);
}
宣伝:オープンソースプロジェクトの支援をお願いします
DIYモジュラーシンセのオープンソースプロジェクトを継続するために、patreonというサービスでパトロンを募集しています。
コーヒー一杯の支援をいただけると嬉しいです。
また、パトロン限定のコンテンツも配信しています。
ソースコード
粗末だが公開する。悪い点があれば指摘を貰えると嬉しい。
前述の通り、USB hostはライブラリを使用しているので、ライセンスについてはそちらに準拠してほしい。
#include <FlashAsEEPROM.h>//flash memory use as eeprom
#include <usbh_midi.h>
#include <usbhub.h>
#if (USB_VID==0x2341 && defined(ARDUINO_SAMD_ZERO)) || (USB_VID==0x2a03 && defined(ARDUINO_SAM_ZERO))
#define SerialDebug SERIAL_PORT_MONITOR
#else
#define SerialDebug Serial1
#endif
float AD_CH1 = 0;
float AD_CH2 = 0;
float AD_CH1_calb = 1.04;//reduce resistance error
float AD_CH2_calb = 1.04;//reduce resistance error
int cmp1 = 0;
int cmp2 = 0;
byte search_qnt = 0;
int cmp12 = 0;
int cmp22 = 0;
byte search_qnt2 = 0;
int old_POT1, old_POT2, old_POT3, old_POT4, POT1, POT2, POT3, POT4, toggle1, toggle2, old_toggle1, old_toggle2;
byte cutoff1 = 127; //cutoff freq
byte sus1 = 10; // sis1 * 10msec , sustain time
byte rel1 = 100; //Release time
byte rev1 = 64; //Reverb wet
byte oct1 = 2; //octave
byte cho1 = 70;//chorus
byte vol1 = 127;//volume
byte pan1 = 63;//LR pan
byte calb1 = 0; //AD error calibration
byte FX_wet1 = 10; //FX wet
byte FX_select1 = 0; //FX
byte art_cnt1 = 0; //count up when trig in
byte art_freq1 = 0;//
byte art_vel1 = 0; //velocity table select
byte art_sus1 = 0; //velocity table select
byte art_sustime1 = 0;
byte cutoff2 = 127; //cutoff freq
byte sus2 = 10; // sis1 * 10msec , sustain time
byte rel2 = 100; //Release time
byte rev2 = 64; //Reverb wet
byte oct2 = 2; //octave
byte cho2 = 70;//chorus
byte vol2 = 127;//volume
byte pan2 = 63;//LR pan
byte calb2 = 0; //AD error calibration
byte FX_wet2 = 100; //FX wet
byte FX_select2 = 0; //FX
byte art_cnt2 = 0; //count up when trig in
byte art_freq2 = 0;//
byte art_vel2 = 0; //velocity table select
byte FX_MSB[12] = {
1, 18, 17, 68, 66, 65, 5, 7, 20, 75, 74, 74
};
byte FX_LSB[12] = {
7, 0, 0, 16, 2, 7, 16, 0, 0, 19, 8, 0
};
//Reverb Hall L 1 7
//Reverb CANYON reverb 18 0
//Reverb Tunnel 17 0
//Chorus SYMPHONIC 68 16
//Chorus CELESTE2 66 2
//Chorus FB Chorus 65 7
//Delay DELAY LCR 5 16
//Delay ECHO 7 0
//Delay Karaoke 20 0
//Distortion ST Dist soft 75 19
//Distortion ST Over drive 74 8
//Distortion Over drive 74 0
byte mode = 0; //change POT assing
byte old_mode = 0;
byte select_ch = 1; //1=CH1 setting ,2=CH2 setting
byte old_select_ch = 1;
byte initial = 1; //1 = before initial setting , 0 = initital setting done
byte select_bank1 = 0;
byte select_bank2 = 0;
byte bank1[12] = {//Instrument bank
0,4,8,12,17,26,60,78,81,98,108,114
};
//00 Acoustic Pino
//04 Electric Piano
//08 Celesta
//12 Marimba
//17 Percussive Organ
//26 Electric Guitar (jazz)
//60 French horn
//78 Whistle
//81 Lead 2 (sawtooth)
//98 FX 3 (crystal)
//108 Kalimba
//114 Steel Drums
int note1 = 0; //CH1 quantized note
int note2 = 0; //CH2 quantized note
int gate_delay1 = 0;
int gate_delay_timer1 = 0;
int gate_delay2 = 0;
int gate_delay_timer2 = 0;
long timer = 0;
int cv_qnt[62] = {
0, 9, 26, 43, 60, 77, 94, 111, 128, 145, 162, 179, 196, 213, 230, 247, 264, 281, 298, 315, 332, 349, 366, 383, 400, 417, 434, 451, 468, 485, 502, 519, 536, 553, 570, 587, 604, 621, 638, 655, 672, 689, 706, 723, 740, 757, 774, 791, 808, 825, 842, 859, 876, 893, 910, 927, 944, 961, 978, 995, 1012, 1024
};//input quantize
byte art_vel3[8][3] = {//Velocity type
{0, 0, 0},
{0, 40, 40},
{40, 40, 0},
{0, 20, 40},
{20, 0, 40},
{0, 40, 0},
{40, 0, 0},
{0, 0, 40}
};
byte art_sus3[8][3] = {//Sustin type
{0, 0, 0},
{0, 40, 40},
{40, 40, 0},
{0, 20, 40},
{20, 0, 40},
{0, 40, 0},
{40, 0, 0},
{0, 0, 40}
};
byte art_vel4[8][4] = {//Velocity type
{0, 0, 0, 0},
{40, 40, 40, 0},
{0, 40, 40, 40},
{0, 40, 20, 40},
{40, 0, 20, 0},
{20, 20, 0, 40},
{20, 0, 20, 0},
{20, 40, 40, 0}
};
byte art_sus4[8][4] = {//Sustin type
{0, 0, 0, 0},
{40, 40, 40, 0},
{0, 40, 40, 40},
{0, 40, 20, 40},
{40, 0, 20, 0},
{20, 20, 0, 40},
{20, 0, 20, 0},
{20, 40, 40, 0}
};
byte art_vel6[8][6] = {//Velocity type
{0, 0, 0, 0, 0, 0},
{40, 0, 20, 0, 20, 20},
{40, 40, 40, 0, 20, 20},
{0, 40, 20, 0, 20, 40},
{0, 40, 0, 20, 0, 40},
{20, 40, 40, 20, 0, 40},
{20, 0, 20, 40, 40, 20},
{20, 20, 0, 0, 20, 40}
};
byte art_sus6[8][6] = {//Sustin type
{0, 0, 0, 0, 0, 0},
{40, 0, 20, 0, 20, 20},
{40, 40, 40, 0, 20, 20},
{0, 40, 20, 0, 20, 40},
{0, 40, 0, 20, 0, 40},
{20, 40, 40, 20, 0, 40},
{20, 0, 20, 40, 40, 20},
{20, 20, 0, 0, 20, 40}
};
USBHost UsbH;
USBH_MIDI Midi(&UsbH);
uint16_t pid, vid;
bool note_on1 = 0;
int note_on_timer1 = 100;
bool old_note_on1 = 0;
bool note_off1 = 0; //0=note_off , 1 = note_on
bool note_on2 = 0;
int note_on_timer2 = 100;
bool old_note_on2 = 0;
bool note_off2 = 0; //0=note_off , 1 = note_on
void setup()
{
analogReadResolution(12);
pinMode(0, INPUT); //toggle2 , mode select , push sw
pinMode(1, INPUT); //toggle1 , ch select
pinMode(2, INPUT); //pot1
pinMode(3, INPUT); //CV1
pinMode(4, INPUT); //pot2
pinMode(5, INPUT_PULLDOWN); //gate1
pinMode(7, INPUT_PULLDOWN); //gate2
pinMode(8, INPUT); //pot3
pinMode(9, INPUT); //CV2
pinMode(10, INPUT); //pot4
pinMode(12, OUTPUT); //debug LED
pinMode(13, OUTPUT); //debug LED
timer = millis();
vid = pid = 0;
SerialDebug.begin(115200);
if (UsbH.Init()) {
SerialDebug.println("USB host did not start");
while (1); //halt
}
delay( 4000 );//wait NSX-39 setup
}
void loop()
{
UsbH.Task();
if ( Midi ) {//Initial setting midi data send
if (initial == 1) {
initial_setting();
initial = 0;
}
old_mode = mode;
old_select_ch = select_ch;
old_toggle2 = toggle2;
//--------------------analog read POT---------------------------
if (timer + 50 <= millis()) {//Read at 50 msec intervals to reduce the processing load.
POT1 = analogRead(2) / 32;//0-127
POT2 = analogRead(4) / 32;//0-127
POT3 = analogRead(8) / 32;//0-127
POT4 = analogRead(10) / 32;//0-127
if (select_ch == 1) {//CH1 setting
if (mode == 0) {
if (abs(old_POT1 - POT1) > 10) {//old_POT for Disables POT reading at the moment of switching.
cutoff1 = POT1;
}
if (abs(old_POT2 - POT2) > 10) {
vol1 = POT2;
}
if (abs(old_POT3 - POT3) > 10) {
sus1 = POT3;
}
if (abs(old_POT4 - POT4) > 10) {
rel1 = POT4;
}
}
else if (mode == 1) {
if (abs(old_POT1 - POT1) > 10) {
if (POT1 / 32 == 0) {
art_freq1 = 0; //0times
}
else if (POT1 / 32 == 1) {
art_freq1 = 3; //0times
}
else if (POT1 / 32 == 2) {
art_freq1 = 4; //0times
}
else if (POT1 / 32 == 3) {
art_freq1 = 6; //0times
}
}
if (abs(old_POT2 - POT2) > 10) {
art_vel1 = POT2 / 16;
}
if (abs(old_POT3 - POT3) > 10) {
art_sus1 = POT2 / 16;
}
if (abs(old_POT4 - POT4) > 10) {
calb1 = POT4;
}
}
else if (mode == 2) {
if (abs(old_POT1 - POT1) > 10) {
oct1 = POT1 / 32;
}
if (abs(old_POT2 - POT2) > 10) {
rev1 = POT2;
}
if (abs(old_POT3 - POT3) > 10) {
cho1 = POT3;
}
if (abs(old_POT4 - POT4) > 10) {
FX_wet1 = POT4;
}
}
}
else if (select_ch == 2) {//CH2 setting
if (mode == 0) {
if (abs(old_POT1 - POT1) > 10) {
cutoff2 = POT1;
}
if (abs(old_POT2 - POT2) > 10) {
vol2 = POT2;
}
if (abs(old_POT3 - POT3) > 10) {
sus2 = POT3;
}
if (abs(old_POT4 - POT4) > 10) {
rel2 = POT4;
}
}
else if (mode == 1) {
if (abs(old_POT1 - POT1) > 10) {
if (POT1 / 32 == 0) {
art_freq2 = 0; //0times
}
else if (POT1 / 32 == 1) {
art_freq2 = 3; //0times
}
else if (POT1 / 32 == 2) {
art_freq2 = 4; //0times
}
else if (POT1 / 32 == 3) {
art_freq2 = 6; //0times
}
}
if (abs(old_POT2 - POT2) > 10) {
art_vel2 = POT2 / 16;
}
if (abs(old_POT4 - POT4) > 10) {
calb2 = POT4;
}
}
else if (mode == 2) {
if (abs(old_POT1 - POT1) > 10) {
oct2 = POT1 / 32;
}
if (abs(old_POT2 - POT2) > 10) {
rev2 = POT2;
}
if (abs(old_POT3 - POT3) > 10) {
cho2 = POT3;
}
if (abs(old_POT4 - POT4) > 10) {
FX_wet2 = POT4;
}
}
}
timer = millis();
param_set();
};
//--------------------analog read SW---------------------------
toggle2 = analogRead(1);//select CH or push SW
toggle1 = analogRead(0);
if (old_toggle2 > 1023 && toggle2 <= 1023) {//push sw on
if (mode == 0) {
if (select_ch == 1) {
select_bank1++;
if (select_bank1 >= 12) {
select_bank1 = 0;
}
uint8_t buf[2];
buf[0] = 0xC1;//program change
buf[1] = bank1[select_bank1]; // program number
Midi.SendData(buf);
delay(1);
}
else if (select_ch == 2) {
select_bank2++;
if (select_bank2 >= 12) {
select_bank2 = 0;
}
uint8_t buf[2];
buf[0] = 0xC2;//program change
buf[1] = bank1[select_bank2]; // program number
Midi.SendData(buf);
delay(1);
}
}
else if (mode == 2) {
FX_select1++;//change effect fx
if (FX_select1 >= 12) {
FX_select1 = 0;
}
uint8_t buf1[10];//send fx midi data
buf1[0] = 0xF0;
buf1[1] = 0x43;
buf1[2] = 0x10;
buf1[3] = 0x4C;
buf1[4] = 0x02;
buf1[5] = 0x01;
buf1[6] = 0x40;
buf1[7] = FX_MSB[FX_select1];
buf1[8] = FX_LSB[FX_select1];
buf1[9] = 0xF7;
Midi.SendData(buf1);
delay(1);
}
else if (mode == 1) {
save();//save flash mem
delay(1000);
}
}
else if (toggle2 > 4095 / 3 && toggle2 <= 4095 * 2 / 3) {
select_ch = 1;
}
else if (toggle2 > 4095 * 2 / 3) {
select_ch = 2;
}
if (toggle1 <= 4095 / 3) {
mode = 1;
}
else if (toggle1 > 4095 / 3 && toggle1 <= 4095 * 2 / 3) {
mode = 0;
}
else if (toggle1 > 4095 * 2 / 3) {
mode = 2;
}
if (old_mode != mode || old_select_ch != select_ch) {
old_POT1 = POT1;//old_POT for Disables POT reading at the moment of switching.
old_POT2 = POT2;
old_POT3 = POT3;
old_POT4 = POT4;
}
//---------------------analog read quantize---------------------
if (gate_delay1 == 1 && gate_delay_timer1 + 5 <= millis()) {//delay 5msec for adc latency
AD_CH1 = analogRead(3) / 4 * (AD_CH1_calb + 0.0016 * calb1); //12bit to 10bit
gate_delay1 = 2;//note on flug
for ( search_qnt = 0; search_qnt <= 61 ; search_qnt++ ) {// quantize
if ( AD_CH1 >= cv_qnt[search_qnt] && AD_CH1 < cv_qnt[search_qnt + 1]) {
cmp1 = AD_CH1 - cv_qnt[search_qnt];
cmp2 = cv_qnt[search_qnt + 1] - AD_CH1;
break;
}
}
if (cmp1 >= cmp2) {//quantize
note1 = search_qnt + 1;
}
else if (cmp2 > cmp1) {//quantize
note1 = search_qnt;
}
}
if (gate_delay2 == 1 && gate_delay_timer2 + 5 <= millis()) {//delay 5msec for adc latency
AD_CH2 = analogRead(9) / 4 * (AD_CH2_calb + 0.0016 * calb2); //12bit to 10bit
gate_delay2 = 2;//note on flug
for ( search_qnt2 = 0; search_qnt2 <= 61 ; search_qnt2++ ) {// quantize
if ( AD_CH2 >= cv_qnt[search_qnt2] && AD_CH2 < cv_qnt[search_qnt2 + 1]) {
cmp12 = AD_CH2 - cv_qnt[search_qnt2];
cmp22 = cv_qnt[search_qnt2 + 1] - AD_CH2;
break;
}
}
if (cmp12 >= cmp22) {//quantize
note2 = search_qnt2 + 1;
}
else if (cmp22 > cmp12) {//quantize
note2 = search_qnt2;
}
}
//---------------------trigger---------------------
old_note_on1 = note_on1;
old_note_on2 = note_on2;
note_on1 = digitalRead(5);
note_on2 = digitalRead(7);
if (note_on1 == 1 && old_note_on1 == 0) {
digitalWrite(12, LOW); //seeeduino xiao led on
gate_delay1 = 1;//Timer count until CV stabilizes.
gate_delay_timer1 = millis();//Timer count until CV stabilizes.
art_cnt1++;//Articulation count up
if (art_cnt1 > art_freq1) { //when count max
art_cnt1 = 1;//Articulation reset
}
if (art_freq1 == 0) {
art_sustime1 = 0;
}
else if (art_freq1 == 3) {
art_sustime1 = art_sus3[art_sus1][art_cnt1];
}
else if (art_freq1 == 4) {
art_sustime1 = art_sus4[art_sus1][art_cnt1];
}
else if (art_freq1 == 6) {
art_sustime1 = art_sus6[art_sus1][art_cnt1];
}
}
if (note_on2 == 1 && old_note_on2 == 0) {
digitalWrite(11, LOW); //seeeduino xiao led on
gate_delay2 = 1;
gate_delay_timer2 = millis();
art_cnt2++;
if (art_cnt2 > art_freq2) { //when count max
art_cnt2 = 1;
}
}
if (note_on_timer1 + 100 + sus1 * 7 + art_sustime1 * sus1 / 4 <= millis() && note_off1 == 1) {
digitalWrite(12, HIGH); //seeeduino xiao led off
noteOff(note1 + 40);
note_off1 = 0;
}
if (note_on_timer2 + 100 + sus2 * 7 <= millis() && note_off2 == 1) {
digitalWrite(11, HIGH); //seeeduino xiao led off
noteOff2(note2 + 40);
note_off2 = 0;
}
if (gate_delay1 == 2) { //finish pitch adc
noteOn(note1 + 24);
note_on_timer1 = millis();
note_off1 = 1;
gate_delay1 = 0;
}
if (gate_delay2 == 2) { //finish pitch adc
noteOn2(note2 + 24);
note_on_timer2 = millis();
note_off2 = 1;
gate_delay2 = 0;
}
}
}
void noteOn(uint8_t note)//note on
{
uint8_t buf[3];
buf[0] = 0x91;// note on
buf[1] = note + oct1 * 12; // note
if (art_freq1 == 0) {
buf[2] = 0x7f; // Velocity
}
else if (art_freq1 == 3) {
buf[2] = 127 - art_vel3[art_vel1][art_cnt1]; // Velocity
}
else if (art_freq1 == 4) {
buf[2] = 127 - art_vel4[art_vel1][art_cnt1]; // Velocity
}
else if (art_freq1 == 6) {
buf[2] = 127 - art_vel6[art_vel1][art_cnt1]; // Velocity
}
Midi.SendData(buf);
}
void noteOff(uint8_t note)//note off
{
uint8_t buf[3];
buf[0] = 0xB1;//control change
buf[1] = 123;//all note off
buf[2] = 0x00;
Midi.SendData(buf);
}
void noteOn2(uint8_t note)//note on
{
uint8_t buf[3];
buf[0] = 0x92;// note on
buf[1] = note + oct2 * 12; // note
if (art_freq2 == 0) {
buf[2] = 0x7f; // Velocity
}
else if (art_freq2 == 3) {
buf[2] = 127 - art_vel3[art_vel2][art_cnt2]; // Velocity
}
else if (art_freq2 == 4) {
buf[2] = 127 - art_vel4[art_vel2][art_cnt2]; // Velocity
}
else if (art_freq2 == 6) {
buf[2] = 127 - art_vel6[art_vel2][art_cnt2]; // Velocity
}
Midi.SendData(buf);
}
void noteOff2(uint8_t note)//note off
{
uint8_t buf[3];
buf[0] = 0xB2;//control change
buf[1] = 123;//all note off
buf[2] = 0x00;
Midi.SendData(buf);
}
void param_set() {
uint8_t buf[3];
if (select_ch == 1) {
if (mode == 0) {
buf[0] = 0xB1;//control change
buf[1] = 74; // Cf
buf[2] = cutoff1;
Midi.SendData(buf);
delay(1);
buf[0] = 0xB1;//control change
buf[1] = 07; // volume
buf[2] = vol1; //
Midi.SendData(buf);
delay(1);
buf[0] = 0xB1;//control change
buf[1] = 72; // release
buf[2] = rel1; //
Midi.SendData(buf);
delay(1);
}
else if (mode == 2) {
buf[0] = 0xB1;//control change
buf[1] = 91; // rev
buf[2] = rev1; //
Midi.SendData(buf);
delay(1);
buf[0] = 0xB1;//control change
buf[1] = 93; // chorus wet
buf[2] = cho1; //
Midi.SendData(buf);
delay(1);
buf[0] = 0xB1;//control change
buf[1] = 0x5E; // FX wet
buf[2] = FX_wet1; //
Midi.SendData(buf);
delay(1);
}
}
else if (select_ch == 2) {
if (mode == 0) {
buf[0] = 0xB2;//control change
buf[1] = 74; // Cf
buf[2] = cutoff2;
Midi.SendData(buf);
delay(1);
buf[0] = 0xB2;//control change
buf[1] = 07; // volume
buf[2] = vol2; //
Midi.SendData(buf);
delay(1);
buf[0] = 0xB2;//control change
buf[1] = 72; // release
buf[2] = rel2; //
Midi.SendData(buf);
delay(1);
}
else if (mode == 2) {
buf[0] = 0xB2;//control change
buf[1] = 91; // rev
buf[2] = rev2; //
Midi.SendData(buf);
delay(1);
buf[0] = 0xB2;//control change
buf[1] = 93; // chorus wet
buf[2] = cho2; //
Midi.SendData(buf);
delay(1);
buf[0] = 0xB2;//control change
buf[1] = 0x5E; // FX wet
buf[2] = FX_wet2; //
Midi.SendData(buf);
delay(1);
}
}
}
void initial_setting() {
if (EEPROM.isValid() == 1) { //already writed eeprom
cutoff1 = EEPROM.read(1);
sus1 = EEPROM.read(2);
rel1 = EEPROM.read(3);
rev1 = EEPROM.read(4);
oct1 = EEPROM.read(5);
cho1 = EEPROM.read(6);
vol1 = EEPROM.read(7);
calb1 = EEPROM.read(8);
FX_wet1 = EEPROM.read(9);
FX_select1 = EEPROM.read(10);
select_bank1 = EEPROM.read(11);
cutoff2 = EEPROM.read(12);
sus2 = EEPROM.read(13);
rel2 = EEPROM.read(14);
rev2 = EEPROM.read(15);
oct2 = EEPROM.read(16);
cho2 = EEPROM.read(17);
vol2 = EEPROM.read(18);
calb2 = EEPROM.read(19);
FX_wet2 = EEPROM.read(20);
FX_select2 = EEPROM.read(21);
select_bank2 = EEPROM.read(22);
}
else if ( EEPROM.isValid() == 0) { //no eeprom data , setting any number to eeprom
cutoff1 = 20;
sus1 = 20;
rel1 = 80;
rev1 = 100;
oct1 = 3;
cho1 = 63;
vol1 = 127;
calb1 = 50;
FX_wet1 = 30;
FX_select1 = 0;
select_bank1 = 3;
cutoff2 = 20;
sus2 = 20;
rel2 = 80;
rev2 = 100;
oct2 = 3;
cho2 = 63;
vol2 = 127;
calb2 = 80;
FX_wet2 = 30;
FX_select2 = 0;
select_bank2 = 0;
}
delay(10);
uint8_t buf1[9];//system effect_FX setting
buf1[0] = 0xF0;
buf1[1] = 0x43;
buf1[2] = 0x10;
buf1[3] = 0x4C;
buf1[4] = 0x02;
buf1[5] = 0x01;
buf1[6] = 0x5A;
buf1[7] = 0x01;
buf1[8] = 0xF7;
Midi.SendData(buf1);
delay(2);
buf1[0] = 0xF0;//FX return
buf1[1] = 0x43;
buf1[2] = 0x10;
buf1[3] = 0x4C;
buf1[4] = 0x02;
buf1[5] = 0x01;
buf1[6] = 0x56;
buf1[7] = 0x7F;
buf1[8] = 0xF7;
Midi.SendData(buf1);
delay(2);
uint8_t buf[3];
buf[0] = 0xB1;//control change
buf[1] = 74; // Cf
buf[2] = cutoff1; //
Midi.SendData(buf);
delay(1);
buf[0] = 0xB1;//control change
buf[1] = 07; // volume
buf[2] = vol1; //
Midi.SendData(buf);
delay(1);
buf[0] = 0xB1;//control change
buf[1] = 72; // release
buf[2] = rel1; //
Midi.SendData(buf);
delay(1);
buf[0] = 0xB1;//control change
buf[1] = 91; // rev
buf[2] = rev1; //
Midi.SendData(buf);
delay(1);
buf[0] = 0xB1;//control change
buf[1] = 93; // chorus wet
buf[2] = cho1; //
Midi.SendData(buf);
delay(1);
buf[0] = 0xB1;//control change
buf[1] = 0x5E; // FX wet
buf[2] = FX_wet1; //
Midi.SendData(buf);
delay(1);
buf[0] = 0xB2;//control change
buf[1] = 74; // Cf
buf[2] = cutoff2; //
Midi.SendData(buf);
delay(1);
buf[0] = 0xB2;//control change
buf[1] = 07; // volume
buf[2] = vol2; //
Midi.SendData(buf);
delay(1);
buf[0] = 0xB2;//control change
buf[1] = 72; // release
buf[2] = rel2; //
Midi.SendData(buf);
delay(1);
buf[0] = 0xB2;//control change
buf[1] = 91; // rev
buf[2] = rev2; //
Midi.SendData(buf);
delay(1);
buf[0] = 0xB2;//control change
buf[1] = 93; // chorus wet
buf[2] = cho2; //
Midi.SendData(buf);
delay(1);
buf[0] = 0xB2;//control change
buf[1] = 0x5E; // FX wet
buf[2] = FX_wet2; //
Midi.SendData(buf);
delay(1);
uint8_t buf2[10];
buf2[0] = 0xF0;
buf2[1] = 0x43;
buf2[2] = 0x10;
buf2[3] = 0x4C;
buf2[4] = 0x02;
buf2[5] = 0x01;
buf2[6] = 0x40;
buf2[7] = FX_MSB[FX_select1];
buf2[8] = FX_LSB[FX_select1];
buf2[9] = 0xF7;
Midi.SendData(buf2);
delay(1);
uint8_t buf3[2];
buf3[0] = 0xC1;//program change
buf3[1] = bank1[select_bank1]; // program number
Midi.SendData(buf3);
buf3[0] = 0xC2;//program change
buf3[1] = bank1[select_bank2]; // program number
Midi.SendData(buf3);
}
void save() {
EEPROM.write(1, cutoff1);
EEPROM.write(2, sus1);
EEPROM.write(3, rel1);
EEPROM.write(4, rev1);
EEPROM.write(5, oct1);
EEPROM.write(6, cho1);
EEPROM.write(7, vol1);
EEPROM.write(8, calb1);
EEPROM.write(9, FX_wet1);
EEPROM.write(10, FX_select1);
EEPROM.write(11, select_bank1);
EEPROM.commit();
delay(100);
}
#つくってみた
この記事が気に入ったらサポートをしてみませんか?