Arduino, ESP32-S3-N8R2を購入しました、N8R2は8MByte Flash、2MByte PSRAMを搭載しています。 N16R8もあります。こちらは16MByte Flash、8MByte PSRAMを搭載しています。 N16R8は価格も高いので、N8R2(800円くらいでした)を選びました。
ESP32-S3は他のArduinoとは違って、2つのスイッチと2つのUSB TypeCのコネクタがついています。
Arduino IDEのボードマネージャで、esp32をインストールします。
Boardとして”ESP32S3 Dev Module"を選びます。 IDEを使ってスケッチをESP32に書き込むにはUSBと書かれたType Cコネクタを使います。 ESP32を接続して電源を入れた後、BOOTボタンを押したまま、RST(Reset)ボタンを押します。 これで、Aeduino IDEからESP32がCOMポートとして見えます。

他にも数々の設定項目が表示されます。私は以下の3箇所を変更しました。 特に、USBからスケッチを書き込むためには、"USB CDC On Boot:"Enabled"に設定します。

LinuxでArduino IDEを使っている時、私の場合、スケッチ書き込み時に、Permission denided 'dev/ttyACM0' とエラーが表示されました。この場合、以下のコマンドでグループを確認します。この場合、dialoutというグループでした。
> ls -l /dev/ttyACM* crw-rw---- 1 root dialout 166, 0 6月 2 16:01 /dev/ttyACM0
現在、ユーザーが所属しているグループを確認します。dialoutが含まれていませんでした。
> groups bear adm cdrom sudo dip plugdev lpadmin sambashare
グループにdialoutを加えます。これで書き込めるようになります。
> sudo usermod -aG dialout $USER
ESP32-S3はTinyUSBというライブラリを使って、USB MIDIに対応しています。 Arduino IDEのESP32-S3で使われるTinyUSB は、通常は別途ライブラリとしてインストールするものではなく、 ESP32 Arduino Core に含まれています。
USB MIDIをインストールします。
次のようなスケッチで確認することができます。
#include "USB.h"
#include "USBMIDI.h"
USBMIDI MIDI;
void setup() {
USB.begin();
}
void loop() {
MIDI.noteOn(60, 127, 1);
delay(500);
MIDI.noteOff(60, 0, 1);
delay(500);
}
ESP32-S3はBluetoothに対応してみます。ライブラリを見てみるとそのものずばりのESP32 BLE MIDIがありましたのでインストールしました。
インストールするとき以下のダイアログが表示され、関連するモジュールNimBLE-Arduinoがインストールされます。
インストール後、Exampleにある01-Basic-Midi-Deviceをコンパイルしてみます。
以下のようなエラーになりました。
In file included from /Users/user/Documents/Arduino/libraries/ESP32-BLE-MIDI/src/BLEMidi.h:4,
from /private/var/folders/f0/57_0lcld44v9vkth22lzqq_40000gp/T/.arduinoIDE-unsaved202655-1371-1j7ua4h.7afg/01-Basic-Midi-Device/01-Basic-Midi-Device.ino:2:
/Users/user/Documents/Arduino/libraries/ESP32-BLE-MIDI/src/utility/BLEMidiServer.h:18:10: error: 'void BLEMidiServerClass::onConnect(NimBLEServer*)' marked 'override', but does not override
18 | void onConnect(BLEServer* pServer) override;
| ^~~~~~~~~
/Users/user/Documents/Arduino/libraries/ESP32-BLE-MIDI/src/utility/BLEMidiServer.h:19:10: error: 'void BLEMidiServerClass::onDisconnect(NimBLEServer*)' marked 'override', but does not override
19 | void onDisconnect(BLEServer* pServer) override;
| ^~~~~~~~~~~~
exit status 1
Compilation error: exit status 1
このエラーを調べてみると、NimBLE-Arduinoのバージョンが新しいことが原因とのこと、 現在インストールされていたのは最新のバージョンで2.5.0でした。これを、REMOVEし、1.4.3をインストールします。
この状態でコンパイルすると、コンパイルは通ります。スケッチをESP32-S3へ書き込み動作させます。 Serial Monitorを見ていると以下のようなエラーが出てBLE MIDIのデバイスとして認識できません。
000062 A6 : 0x00000000 A7 : 0x3fcebc25 A8 : btdm: bss start 0x3fcef180, len 36 btdm: data start 0x3fcef174, data start rom 0x40057350, len 12 MAGIC fadebead VERSION 0001000b Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.
このエラーを解消するために、ESP32 Coreのバージョンをダウンします。今日現在インストールされていたのは3.3.8でした。 3.2.0へバージョンダウンします。
これでコンパイルが通り、ESP32-S3へインストール、RESETスイッチを押すとBluetooth MIDI デバイスとして認識できます。
上でインストールしたESP32-S3デバイスをMacで認識させます。Audio MIDI設定を起動します。

ウィンドウメニューから「MIDIスタジオを表示」を選択。ウィンドウ上部のBluetoothマークをクリックします。

装置名に「Basic MIDI Device」が表示されますので、これをクリックし「接続」ボタンを押します。

MIDI Monitorを立ち上げるとノートメッセージを確認することができます。

上でインストールしたESP32 BLE MIDIのAPIをExampleを見て羅列してみました。
| 接続 | |
| BLEMidiServer.begin("Device Name") | Setupで使用。MIDI Serverをスタートする。"Device Name"がクライアントから見える。 |
| BLEMidiServer.isConnected() | 接続していればTrue |
| 送信 | |
| BLEMidiServer.noteOn(uint8_t channel, uint8_t note, uint8_t velocity); | Note On Messageを送信 |
| BLEMidiServer.noteOff(uint8_t channel, uint8_t note, uint8_t velocity); | Note Off Messageを送信 |
| BLEMidiServer.afterTouchPoly(uint8_t channel, uint8_t note, uint8_t pressure); | Poliphonic After Touchを送信 |
| BLEMidiServer.controlChange(uint8_t channel, uint8_t controller, uint8_t value) | Control Changeを送信 |
| BLEMidiServer.programChange(uint8_t channel, uint8_t program) | Program Changeを送信 |
| BLEMidiServer.afterTouch(uint8_t channel, uint8_t pressure) | Channel After Touchを送信 |
| BLEMidiServer.pitchBend(uint8_t channel, uint8_t lsb, uint8_t msb) | Pitch Bendを送信 |
| 受信 | |
| BLEMidiServer.setNoteOnCallback(onNoteOn) | void onNoteOn(uint8_t channel, uint8_t note, uint8_t velocity, uint16_t timestamp) |
| LEMidiServer.setNoteOffCallback(onNoteOff) | void onNoteOff(uint8_t channel, uint8_t note, uint8_t velocity, uint16_t timestamp) |
| BLEMidiServer.setAfterTouchPolyCallback(onAfterTouchPoly) | void onAfterTouchPoly(uint8_t channel, uint8_t note, uint8_t pressure, uint16_t timestamp) |
| BLEMidiServer.setControlChangeCallback(onControlChange) | void onControlChange(uint8_t channel, uint8_t controller, uint8_t value, uint16_t timestamp) |
| BLEMidiServer.setProgramChangeCallback(onProgramChange) | void onProgramChange(uint8_t channel, uint8_t program, uint16_t timestamp) |
| BLEMidiServer.setAfterTouchCallback(onAfterTouch) | void onAfterTouch(uint8_t channel, uint8_t pressure, uint16_t timestamp) |
| BLEMidiServer.setPitchBendCallback(onPitchbend) | void onPitchbend(uint8_t channel, uint16_t value, uint16_t timestamp) |
(注)pitchBendはコンパイルエラーが出ます
/Users/user/Documents/Arduino/Basic_Midi_Device/Basic_Midi_Device.ino: In function 'void loop()':
/Users/user/Documents/Arduino/Basic_Midi_Device/Basic_Midi_Device.ino:26:30: error: call of overloaded 'pitchBend(int, int, int)' is ambiguous
26 | BLEMidiServer.pitchBend(7,123,34);
| ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~
In file included from /Users/user/Documents/Arduino/libraries/ESP32-BLE-MIDI/src/utility/BLEMidiBase.h:6,
from /Users/user/Documents/Arduino/libraries/ESP32-BLE-MIDI/src/utility/BLEMidiServer.h:4,
from /Users/user/Documents/Arduino/libraries/ESP32-BLE-MIDI/src/BLEMidi.h:4,
from /Users/user/Documents/Arduino/Basic_Midi_Device/Basic_Midi_Device.ino:2:
/Users/user/Documents/Arduino/libraries/ESP32-BLE-MIDI/src/utility/Midi.h:16:10: note: candidate: 'void Midi::pitchBend(uint8_t, uint8_t, uint8_t)'
16 | void pitchBend(uint8_t channel, uint8_t lsb, uint8_t msb);
| ^~~~~~~~~
/Users/user/Documents/Arduino/libraries/ESP32-BLE-MIDI/src/utility/Midi.h:28:10: note: candidate: 'void Midi::pitchBend(uint8_t, float, float)'
28 | void pitchBend(uint8_t channel, float semitones, float range = 4);
| ^~~~~~~~~
exit status 1
Compilation error: call of overloaded 'pitchBend(int, int, int)' is ambiguous
void Midi::pitchBend(uint8_t, uint8_t, uint8_t) という関数が2つあることが問題です。 これを解決するには、Arduino/libraries/ESP32-BLE-MIDI/src/utility/Midi.hと Arduino/libraries/ESP32-BLE-MIDI/src/utility/Midi.cppに記載の関数名を書き換えます。
Midi.h/Midi.cpp (修正前)void pitchBend(uint8_t channel, float semitones, float range = 4); (修正後)void pitchBendTones(uint8_t channel, float semitones, float range = 4);
SP32-BLE-MIDIをいくつか修正しました。修正点は以下の通りです。リポジトリを https://github.com/mikatahara/MH-ESP32-BLE-MIDIにおきました。
Pitch Bendは14ビット(0 - 0x3FFFの16384段階)のデータを送信することができます。 このデータをPBと書くことにします。
semitones=2.0の時、integerValue=0x4000となってしまい、送信されるメッセージが 0x0000となってしまうため、 以下のように一部修正しました。
void Midi::pitchBendTones(uint8_t channel, float semitones, float range)
{
if(semitones < -range/2 || semitones > range/2)
return;
uint16_t integerValue = semitones * 16384 / range + 8192;
if(integerValue==0x4000) integerValue=0x3FFF;
pitchBend(channel, integerValue);
}
System Exclusiveメッセージを送信する関数をBLEMidiServerに追加しました。
/** Send System Exclusive */ void sendSysEx(uint8_t *sysex, uint16_t sizeofsysex);
使い方のサンプルは以下の通りです。
#include <Arduino.h>
#include <BLEMidi.h>
uint8_t midiMessage[] = {
0xF0, //sysex
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
0xF7 //end of sysex
};
void setup() {
BLEMidiServer.begin("Basic MIDI device");
}
void loop() {
if (BLEMidiServer.isConnected()) {
BLEMidiServer.sendSysEx(midiMessage, sizeof(midiMessage));
}
delay(1000);
}
ESP32 BLE MIDIには、MIDI Machine Control(MMC)のメッセージを送信するためのAPIが 付属しています。(対応している製品があれば…ですが。)
MIDIマシンコントロールは、MIDI仕様のサブセットであり、 マルチトラックレコーダーなどの録音機器を制御するための特定のコマンドを提供します。 MMCメッセージは、標準のMIDIケーブルを介して送信でき、再生、早送り、巻き戻し、停止、一時停止、 録音などの機能をリモートで制御できます。 MIDIマシンコントロールはシステムエクスクルーシブメッセージで送信します。
| void mmcPlay(void); | void mmcDeferredPlay(void); | void mmcPause(void); | void mmcStop(void); |
| void mmcRecordStrobe(void); | void mmcRecordPause(void); | void mmcRecordExit(void); | void mmcEject(void); |
| vvoid mmcChase(void); | void mmcReset(void); | void mmcFastForward(void); | void mmcRewind(void); |
メッセージが送信できませんでしたので、一部ライブラリを修正しました。
Midi.h/Midi.cpp void Midi::sendMMC(mmc_t command) (修正前)sendMessage(midiMessage, sizeof(midiMessage)); (修正後)sendSysEx(midiMessage,sizeof(midiMessage));