#M5Pianoについて
先日記事を投稿しました。
https://qiita.com/siroitori0413/items/9e0cb11495a8bbfeffd8
#MIDIキーボード化
M5Stack+M5PianoをMIDIキーボード化することに成功したので記載しておきます。
当方MIDIについては初心者ですのでおかしな表記あればご指摘ください。
◆使用したソフト類
- loopMIDI :仮想MIDIポート
https://www.tobias-erichsen.de/software/loopmidi.html - The Hairless MIDI<->Serial Bridge :仮想MIDIとシリアルポートをつなぐ役割
https://projectgus.github.io/hairless-midiserial/ - Music Studio Producer(MSP) :音楽制作ソフト
http://forest.watch.impress.co.jp/library/software/msproducer/
#プログラム(M5Stack)
キーボードがタッチされたときと手が離されたときそれぞれに、MIDIに信号を送信します。
MIDI.sendNoteOn(note, velocity, channel)
MIDI.sendNoteOff(note, velocity, channel)
#include <MIDI.h>
#include <M5Stack.h>
#include <Wire.h>
#include <FastLED.h>
// #include <Adafruit_NeoPixel.h>
#define LED_PIN 2
#define NUM_LEDS_PER_STRIP 29
CRGB Leds[NUM_LEDS_PER_STRIP];
// Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
#define LF 0x0A //New Line
#define CR 0x0D //Carriage return
#define SP 0x20 //Spcae
#define Sensitivity_PWM1 0x00 //ch2,ch1
#define Sensitivity_PWM2 0x01 //ch4,ch3
#define Sensitivity_PWM3 0x02 //ch6,ch5
#define Sensitivity_PWM4 0x03 //ch21,ch7
#define Sensitivity_PWM5 0x04 //ch9,ch8
#define Sensitivity_PWM6 0x05 //ch11,ch10
#define Sensitivity_PWM7 0x06 //ch13,ch12
#define Sensitivity_PWM8 0x07 //ch15,ch14
#define Sensitivity_PWM9 0x08 //ch17,ch16
#define Sensitivity_PWM10 0x09 //ch19,ch18
#define Sensitivity_PWM11 0x0A //ch20
#define GTRL1 0x0B
#define GTRL2 0x0C
#define Cal_CTRL 0x0D
#define Port_CTRL1 0x0E
#define Port_CTRL2 0x0F
#define Port_CTRL3 0x10
#define Port_CTRL4 0x11
#define Port_CTRL5 0x12
#define Port_CTRL6 0x13
#define Cal_HOLD1 0x14
#define Cal_HOLD2 0x15
#define Cal_HOLD3 0x16
#define Err_CTRL 0x17
#define Output1 0x20
#define Output2 0x21
#define Output3 0x22
#define Ref_wr_H 0x23
#define Ref_wr_L 0x24
#define Ref_wr_CH1 0x25
#define Ref_wr_CH2 0x26
#define Ref_wr_CH3 0x27
#define Sen_RD_CTRL 0x28
#define Sensitivity_RD 0x29
#define Rd_CH1 0x30
#define Rd_CH2 0x31
#define Rd_CH3 0x32
#define Sen_H 0x33
#define Sen_L 0x34
#define Ref_H 0x35
#define Ref_L 0x36
#define Rd_CH1 0x37
#define Rd_CH2 0x38
#define Rd_CH3 0x39
#define TS20_SLAVE_GND 0x6A //0xD4<<1 //ADD Pin = GND
#define TS20_SLAVE_VDD 0x7A //0xF4<<1 //ADD Pin = VDD
void Init_TS20(void); //Initialize TS20
#define RESET_PIN 7 //Reset pin
#define EN_PIN 6 //I2C Enable Pin
#define Set_Bit(val, bitn) (val |=(1<<(bitn)))
#define Clr_Bit(val, bitn) (val&=~(1<<(bitn)))
#define Get_Bit(val, bitn) (val &(1<<(bitn)) )
MIDI_CREATE_DEFAULT_INSTANCE();
byte key[4];
// #define pRed pixels.Color(5,0,0)
// #define pBlack pixels.Color(0,0,0)
boolean notePressed[25];
void setup() {
M5.begin();
Wire.begin(26, 5); // join i2c bus (address optional for master)
MIDI.begin(1); // MIDI BEGIN!
Serial.begin(115200); // start serial for output (Spped)
delay(100); //wait for 100[msec]
Init_TS20(); //Initialize TS20
delay(100); //wait for 100[msec]
key[0] = 0;
key[1] = 0;
key[2] = 0;
key[3] = 0;
// 一番最初に光る緑の電源LED
pinMode(2, OUTPUT);
digitalWrite(2, HIGH);
delay(500);
digitalWrite(2, LOW); // これが点いているとランプの位置がずれるのでOFFっておく
// キーボードの上のLED
FastLED.addLeds<NEOPIXEL, LED_PIN>(Leds, NUM_LEDS_PER_STRIP);
FastLED.setBrightness(10);
// pixels.begin();
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setCursor(1, 10);
M5.Lcd.setTextColor(TFT_YELLOW, TFT_BLACK);
M5.Lcd.setTextSize(3);
M5.Lcd.printf("M5PIANO");
for (int i = 0; i < 29; i++)
{
Leds[i] = CRGB::Red;
// pixels.setPixelColor(i, pRed);
delay(20);
FastLED.show();
}
delay(1000);
for (int i = 0; i < 29; i++)
{
Leds[i] = CRGB::Black;
// FastLED.setPixelColor(i, pBlack);
delay(10);
FastLED.show();
}
ledcSetup(TONE_PIN_CHANNEL, 0, 10);
ledcAttachPin(SPEAKER_PIN, TONE_PIN_CHANNEL);
}
// キーのタッチ判定処理:LED・音
void refresh(int ledNo, int data, byte b, int keyCnt, int setValue) {
if ((data & b) == b) {
Leds[ledNo] = CRGB::Blue;
if (notePressed[setValue-36] == false) {
notePressed[setValue-36] = true;
MIDI.sendNoteOn(setValue, 127, 1);
}
} else {
if (notePressed[setValue-36] == true) {
notePressed[setValue-36] = false;
MIDI.sendNoteOff(setValue, 127, 1);
}
Leds[ledNo] = CRGB::Black;
Clr_Bit(key[keyCnt], setValue);
}
}
void loop() {
int data0, data1, data2, data3, data4, data5;
delay(5);
Wire.beginTransmission(TS20_SLAVE_GND); // sned ic slave address
Wire.write(byte(Output1)); // sends register address
Wire.endTransmission(); // stop transmitting
Wire.requestFrom(TS20_SLAVE_GND, 3); // key data read (3 byte)
data0 = Wire.read();
data1 = Wire.read();
data2 = Wire.read();
Wire.beginTransmission(TS20_SLAVE_VDD); // sned ic slave address
Wire.write(byte(Output1)); // sends register address
Wire.endTransmission(); // stop transmitting
Wire.requestFrom(TS20_SLAVE_VDD, 3); // key data read (3 byte)
data3 = Wire.read();
data4 = Wire.read();
data5 = Wire.read();
M5.Lcd.setCursor(1, 50);
M5.Lcd.printf("%d,%d,%d,%d,%d,%d ", data0, data1, data2, data3, data4, data5);
for (int i = 0; i < 29; i++)
{
Leds[i] = CRGB::Black;
// pixels.setPixelColor(i, pBlack);
}
// キータッチ判定、LED/音
refresh(0, data0, 0x10, 0, 36);
refresh(1, data0, 0x20, 0, 37);
refresh(2, data0, 0x40, 0, 38);
refresh(3, data1, 0x01, 0, 39);
refresh(4, data1, 0x02, 0, 40);
refresh(6, data2, 0x04, 0, 41);
refresh(7, data2, 0x08, 0, 42);
refresh(8, data2, 0x10, 0, 43);
refresh(9, data0, 0x01, 1, 44);
refresh(10, data0, 0x02, 1, 45);
refresh(11, data0, 0x04, 1, 46);
refresh(12, data0, 0x08, 1, 47);
refresh(14, data3, 0x10, 1, 48);
refresh(15, data3, 0x20, 1, 49); //
refresh(16, data3, 0x40, 1, 50);
refresh(17, data4, 0x01, 1, 51); //
refresh(18, data4, 0x02, 2, 52);
refresh(20, data5, 0x02, 2, 53);
refresh(21, data5, 0x04, 2, 54); //
refresh(22, data5, 0x08, 2, 55);
refresh(23, data5, 0x10, 2, 56); //
refresh(24, data3, 0x01, 2, 57);
refresh(25, data3, 0x02, 2, 58); //
refresh(26, data3, 0x04, 2, 59);
refresh(28, data3, 0x08, 3, 60);
FastLED.show();
M5.update();
}
void Init_TS20(void)
{
//------------------ Software Reset Enable (Set)----------------------
Wire.beginTransmission(TS20_SLAVE_GND); // send ic slave address
Wire.write(byte(GTRL2)); // sends register address
Wire.write(byte(0x1A)); // sends register data
Wire.endTransmission(); // stop transmitting
//----------------- Port Control ------------------------------------
Wire.beginTransmission(TS20_SLAVE_GND); // send ic slave address
Wire.write(byte(Port_CTRL1)); // sends register address
Wire.write(byte(0x00)); // sends register data
Wire.endTransmission(); // stop transmitting
Wire.beginTransmission(TS20_SLAVE_GND); // send ic slave address
Wire.write(byte(Port_CTRL2)); // sends register address
Wire.write(byte(0x00)); // sends register data
Wire.endTransmission(); // stop transmitting
Wire.beginTransmission(TS20_SLAVE_GND); // send ic slave address
Wire.write(byte(Port_CTRL3)); // sends register address
Wire.write(byte(0x00)); // sends register data
Wire.endTransmission(); // stop transmitting
Wire.beginTransmission(TS20_SLAVE_GND); // send ic slave address
Wire.write(byte(Port_CTRL4)); // sends register address
Wire.write(byte(0x00)); // sends register data
Wire.endTransmission(); // stop transmitting
Wire.beginTransmission(TS20_SLAVE_GND); // send ic slave address
Wire.write(byte(Port_CTRL5)); // sends register address
Wire.write(byte(0x00)); // sends register data
Wire.endTransmission(); // stop transmitting
Wire.beginTransmission(TS20_SLAVE_GND); // send ic slave address
Wire.write(byte(Port_CTRL6)); // sends register address
Wire.write(byte(0x00)); // sends register data
Wire.endTransmission(); // stop transmitting
//--------------- Sensitivty control,(threshold level)-----------
Wire.beginTransmission(TS20_SLAVE_GND); // send ic slave address
Wire.write(byte(Sensitivity_PWM1)); // sends register address
Wire.write(byte(0x55)); // sends register data
Wire.endTransmission(); // stop transmitting
Wire.beginTransmission(TS20_SLAVE_GND); // send ic slave address
Wire.write(byte(Sensitivity_PWM2)); // sends register address
Wire.write(byte(0x55)); // sends register data
Wire.endTransmission(); // stop transmitting
Wire.beginTransmission(TS20_SLAVE_GND); // send ic slave address
Wire.write(byte(Sensitivity_PWM3)); // sends register address
Wire.write(byte(0x55)); // sends register data
Wire.endTransmission(); // stop transmitting
Wire.beginTransmission(TS20_SLAVE_GND); // send ic slave address
Wire.write(byte(Sensitivity_PWM4)); // sends register address
Wire.write(byte(0xF5)); // sends register data
Wire.endTransmission(); // stop transmitting
Wire.beginTransmission(TS20_SLAVE_GND); // send ic slave address
Wire.write(byte(Sensitivity_PWM5)); // sends register address
Wire.write(byte(0x55)); // sends register data
Wire.endTransmission(); // stop transmitting
Wire.beginTransmission(TS20_SLAVE_GND); // send ic slave address
Wire.write(byte(Sensitivity_PWM6)); // sends register address
Wire.write(byte(0x55)); // sends register data
Wire.endTransmission(); // stop transmitting
Wire.beginTransmission(TS20_SLAVE_GND); // send ic slave address
Wire.write(byte(Sensitivity_PWM7)); // sends register address
Wire.write(byte(0x55)); // sends register data
Wire.endTransmission(); // stop transmitting
Wire.beginTransmission(TS20_SLAVE_GND); // send ic slave address
Wire.write(byte(Sensitivity_PWM8)); // sends register address
Wire.write(byte(0x55)); // sends register data
Wire.endTransmission(); // stop transmitting
Wire.beginTransmission(TS20_SLAVE_GND); /// send ic slave address
Wire.write(byte(Sensitivity_PWM9)); // sends register address
Wire.write(byte(0x55)); // sends register data
Wire.endTransmission(); // stop transmitting
Wire.beginTransmission(TS20_SLAVE_GND); // send ic slave address
Wire.write(byte(Sensitivity_PWM10)); // sends register address
Wire.write(byte(0x55)); // sends register data
Wire.endTransmission(); // stop transmitting
Wire.beginTransmission(TS20_SLAVE_GND); // sned ic slave address
Wire.write(byte(Sensitivity_PWM11)); // sends register address
Wire.write(byte(0x55)); // sends register data
Wire.endTransmission(); // stop transmitting
Wire.beginTransmission(TS20_SLAVE_GND); // send ic slave address
Wire.write(byte(GTRL1)); // sends register address
Wire.write(byte(0x4B)); // sends register data
Wire.endTransmission(); // stop transmitting
//------------------ Calibration On ---------------------------
Wire.beginTransmission(TS20_SLAVE_GND); // send ic slave address
Wire.write(byte(Cal_HOLD1)); // sends register address
Wire.write(byte(0x00)); // sends register data
Wire.endTransmission(); // stop transmitting
Wire.beginTransmission(TS20_SLAVE_GND); // send ic slave address
Wire.write(byte(Cal_HOLD2)); // sends register address
Wire.write(byte(0x00)); // sends register data
Wire.endTransmission(); // stop transmitting
Wire.beginTransmission(TS20_SLAVE_GND); // send ic slave address
Wire.write(byte(Cal_HOLD3)); // sends register address
Wire.write(byte(0x00)); // sends register data
Wire.endTransmission(); // stop transmitting
Wire.beginTransmission(TS20_SLAVE_GND); // send ic slave address
Wire.write(byte(Err_CTRL)); // sends register address
Wire.write(byte(0x0D)); // sends register data
Wire.endTransmission(); // stop transmitting
Wire.beginTransmission(TS20_SLAVE_GND); // send ic slave address
Wire.write(byte(Cal_CTRL)); // sends register address
Wire.write(byte(0xFA)); // sends register data
Wire.endTransmission(); // stop transmitting
//------------------ Software Reset Disable (Clear) -----------------------
Wire.beginTransmission(TS20_SLAVE_GND); // send ic slave address
Wire.write(byte(GTRL2)); // sends register address
Wire.write(byte(0x12)); // sends register data
Wire.endTransmission(); // stop transmitting
}
#動かし方
① M5StackとM5Pianoを接続しプログラムを書き込んだ後、M5StackとPCをUSBケーブルでつなぐ
② loopMIDIを起動して適当な名前を付けて追加
③ Hairless MIDIを開き、左上の「Serial<->MIDI Bridge On」のチェックを外してから、
・Serial Port にはM5StackがUSB接続されているCOMポートを選択
・MIDI Out には②でつけた名前を選択
④ M5Pianoの鍵盤を数回たたきながら③の「Serial<->MIDI Bridge On」のチェックをONにする
※こちらの環境のみかもしれませんがなぜかこうすることでチェックが入れられました。すんなりチェックが入るならそれでOKです。
これでMIDIキーボードとして接続が出来ました。
M5Pianoの鍵盤をたたくことでPCで音を鳴らしたり編集したりすることができます。
#注意
MIDIキーボードとして接続した後M5tackのプログラムをArduino IDEから再度書き込むときは接続しているポートをMIDI用でつかんだままになっているのでいったん接続を解除(Hairless MIDIの「Serial<->MIDI Bridge On」のチェックOFF)しましょう。