そういえば、送信ばっかりで受信を試したことがなかったので、試してみました。これ。
M5StickC(ESP32)にWindows10からBLE-MIDIでリアルタイム数値送信をしてみる
なるほど、いい感じです。これまで送信しか試してなかったのは、MIDIコントローラーを作るということしか考えてなかったからでした。以前、試していたのはこれ。
これをもとにフットスイッチをつくったりしていたのです( M5Stack_BLE-MIDI-Footswitch )。
受信ができればさらに用途が広がりそうです。というわけで、次に作ろうと考えたのは、送受信するやつ。当然です。
前に作ったコードから、ボタンまわりとMIDIデータ送信部分を抜き出し、最初のリンクにあるコードに付け加えてみました。しかし、これが動かない。受信はできるけど、送信はできないまま。
そんなこんなで、最初のリンクのコードと2つめのリンクのコードを見比べてみます。足りなそうなのを加えてみます(ほぼわかってない)。出来上がったのが、以下のコード。ボタンを押せば、MIDIノートを送信します(NOTE ON / NOTE OFF)。
#include <M5StickC.h>
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
//add
#include <BLE2902.h>
#define MIDI_SERVICE_UUID "03b80e5a-ede8-4b33-a751-6ce34ec4c700"
#define MIDI_CHARACTERISTIC_UUID "7772e5db-3868-4112-a1a9-f2669d106bf3"
#define DEVIVE_NAME "M5StickC"
BLEServer *pServer;
BLEAdvertising *pAdvertising;
BLECharacteristic *pCharacteristic;
int pos = 0;
char midi[5];
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
M5.Lcd.setTextSize(1);
M5.Lcd.setCursor(10, 0);
M5.Lcd.printf("BLE MIDI Connected. ");
};
void onDisconnect(BLEServer* pServer) {
M5.Lcd.setTextSize(1);
M5.Lcd.setCursor(10, 0);
M5.Lcd.printf("BLE MIDI Disconnect.");
}
};
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string rxValue = pCharacteristic->getValue();
pos = 0;
if (rxValue.length() > 0) {
for (int i = 0; i < rxValue.length(); i++)
{
Serial.printf("%02x", rxValue[i]);
midi[pos] = rxValue[i];
pos++;
if (pos == 5)
{
M5.Lcd.setTextColor(WHITE, BLACK); // add
M5.Lcd.setTextSize(3);
M5.Lcd.setCursor(10, 30);
M5.Lcd.printf("%02x %02x %02x", midi[2], midi[3], midi[4]);
pos = 0;
}
}
Serial.println();
}
}
};
// add
const int buttonON = LOW;
const int buttonOFF = HIGH;
///// Button
const uint8_t buttonPins[5] = {37, 39, 0, 26 }; //A, B, PIN 36除く (26/36/0)
boolean buttonFlags[5];
uint8_t buttonNote[5] = {60, 64, 67, 71, 72};
uint8_t buttonCC[5] = {79, 80, 81, 82, 83};
void noteOn(uint8_t channel, uint8_t pitch, uint8_t velocity) {
uint8_t midiPacket[] = {0x80, 0x80, (uint8_t)(0x90 | channel), pitch, velocity };
pCharacteristic->setValue(midiPacket, 5); // packet, length in bytes
pCharacteristic->notify();
}
void noteOff(uint8_t channel, uint8_t pitch, uint8_t velocity) {
uint8_t midiPacket[] = {0x80, 0x80, (uint8_t)(0x80 | channel), pitch, velocity };
pCharacteristic->setValue(midiPacket, 5); // packet, length in bytes)
pCharacteristic->notify();
}
void setup() {
M5.begin();
M5.Lcd.setRotation(3);
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setTextColor(WHITE, BLACK);
M5.Lcd.setTextSize(1);
M5.Lcd.setCursor(10, 0);
M5.Lcd.printf("BLE MIDI Disconnect.");
// add
pinMode(M5_BUTTON_HOME, INPUT);
pinMode(M5_BUTTON_RST, INPUT);
BLEDevice::init(DEVIVE_NAME);
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
BLEService *pService = pServer->createService(BLEUUID(MIDI_SERVICE_UUID));
pCharacteristic = pService->createCharacteristic(
BLEUUID(MIDI_CHARACTERISTIC_UUID),
BLECharacteristic::PROPERTY_READ |
// BLECharacteristic::PROPERTY_WRITE |
BLECharacteristic::PROPERTY_NOTIFY |
BLECharacteristic::PROPERTY_WRITE_NR
);
pCharacteristic->setCallbacks(new MyCallbacks());
// add
pCharacteristic->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);
pCharacteristic->addDescriptor(new BLE2902());
pService->start();
// add
BLESecurity *pSecurity = new BLESecurity();
pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_BOND);
pSecurity->setCapability(ESP_IO_CAP_NONE);
pSecurity->setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);
BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
oAdvertisementData.setFlags(0x04);
oAdvertisementData.setCompleteServices(BLEUUID(MIDI_SERVICE_UUID));
oAdvertisementData.setName(DEVIVE_NAME);
pAdvertising = pServer->getAdvertising();
pAdvertising->setAdvertisementData(oAdvertisementData);
pAdvertising->start();
}
void loop() {
//add
for (int i = 0; i < 2; i++) {
int buttonValue = digitalRead(buttonPins[i]);
buttonValue = digitalRead(buttonPins[i]);
if (buttonValue == buttonON && buttonFlags[i] == false) {
// noteOn
noteOn(0, buttonNote[i], 127);
M5.Lcd.setTextSize(2);
M5.Lcd.setTextColor(WHITE);
M5.Lcd.fillRect(36 + i * 74 , 60 -1, 34, 16 +1, RED);
M5.Lcd.setCursor(4 + i * 74 , 60);
M5.Lcd.printf("%2d On", buttonPins[i]);
delay(60); //
buttonFlags[i] = true;
} //if
if (buttonValue == buttonOFF && buttonFlags[i] == true) {
// noteOff
noteOff(0, buttonNote[i], 127);
M5.Lcd.setTextSize(2);
M5.Lcd.fillRect( 36 + i * 74, 60 -1, 34, 16 +1, BLUE);
M5.Lcd.setCursor(40 + i * 74, 60);
M5.Lcd.printf("Off", buttonPins[i]);
delay(60); //
M5.Lcd.fillRect(0 + i * 74, 60 -1, 78, 16 +1, BLACK);
buttonFlags[i] = false;
} // if
delay(8); //
} //for
delay(1);
}
もとはM5Stack用に作ったやつなので、余計なコードも残ってますが、M5StickCで動くはずです。ペアリングがうまくいったりいかなかったりするので、M5StickCの電源入れたり切ったりします(これもわかってない)。理屈も押さえずなんとなくでやってるので、おかしなところがあったら教えていただけるとありがたいです。
あと、アイキャッチのM5StickCの写真ですが、モバイル版のPhotoshopでテキトーなフィルターを使ったらわけがわからなくなりました。特に意味はないです。
WindowsでのBLE-MIDI通信を双方向で行いたい場合は、MIDIberryの最新エディションMIDIberryMがオススメです。
っていうか、CakewalkがDAWで唯一、ネイティブにBLE-MIDI対応してるんで、ほんとはそれがオススメ。まだ、モノによってはちょっと怪しいことがありますけど。
コメント