はじめに
M5StackとMIDI音源、MIDIコントローラを使って、パソコン無しでシンセサイザーのライブパフォーマンスができる機材を作りました。グルーヴボックスと呼ばれているものに近いと思います。文章の説明だとわかりにくいかと思いますので、よろしければ次の動画をご覧ください。
作ろうと思った動機
去年(2020年)の夏ごろM5Stackを買って、いろいろ忙しくて年末まで放置してたのですが、年末に少しいじってみたらハマリました。これは面白いです! Arduinoのときはメモリの少なさと、基盤むき出しということの敷居の高さがあったのですが、M5Stackはその辺りが使いやすくなっていて、昔のホビーパソコンの世界に近いものを感じました。
Arduinoを使っていた頃からMIDIコントローラのようなものは作りたいと思っていたのですが、Githubのサンプルをいろいろ持ってきて、3日ほどでMIDIファイルを演奏させることができました。これに気をよくして、ライブパフォーマンスなどでも使えるような機能をいろいろ盛り込んだのが本作となります。作ったのは音源を操作するプレイヤーなので、別途MIDI音源が必要なのですが、今回は学研のポケットミク(NSX-39)を使いました。コンパクトであること、USBケーブル一本で接続できる利便性、また安価で入手も容易かと思います。もちろん、これでなくてもMIDI接続できる音源ならば、なんでも接続できます。
機能
- SMF(標準MIDIファイル)を再生します。再生するファイルは一覧表示で選択できます。(SMF自体はあらかじめパソコンのDAWなどで作っておきます)
- 各チャンネルごとにソロ、ミュート設定ができます。
- 特定のチャンネルに対してmidiコントローラのツマミやフェーダーを使って、リアルタイムに音色を変化させることができます。いわゆる、演奏中にツマミをグリグリすると音色がどんどん変わっていく機能です。
- ループ再生機能。本来のSMFにはない機能なのですが、独自の仕様拡張を行い、ループ再生ができるようにしました。演奏中に複数のループを切り替えることもできます。Aメロを好きな回数だけ繰り替えしたら、サビを演奏し、間奏から再びAメロに戻る、といった演奏ができます。
- LEDメトロノーム:補足的な機能ですが、コントローラのLEDがメトロノームのようにテンポ通りに点滅します。
- FTP機能:これも補足機能です。MIDIファイルはM5StackのSDカードに入ってますが、ファイルの入れ替えをWi-FiのFTPでおこなうことができます。M5StakからSDカードを取り出してパソコンにセットして、ファイルを入れ替え、またM5Stackに戻す、というのは結構な手間なので、それを省くための機能です。
ハードウェア構成
M5Stackに、純正のUSBモジュール(SKU:M020)を取り付け、USBハブを介して、MIDIコントローラ(KORG nanoKONTROL2)とMIDI音源(学研 NSX-39 ポケットミク)を繋げます。機能的な都合によりコントローラはnanoKONTROL2に限定されますが、MIDI音源のほうはどんな音源にも対応できます。
再生するMIDIファイルはSDカードに格納します。曲の再生前にファイルを一気に読み込むので、SDカードの転送速度が速くなくても大丈夫です。
電子工作というほどのものではありませんが、ギタリストが使うエフェクターボードのようにボードに固定しました。ボードに使ったのはA5のバインダー(紙ばさみ)です。下敷きとか鉄板など、強度などいろいろ検討した結果、このバインダーにしました(本当はツヤの無い素材にしたかったのですが、見つかりませんでした)。写真のようにビニールテープで止めてあるだけなので、いつでも元のバインダーに戻せます。
プログラム
プログラム全体は長いので(ライブラリを除いた総行数約6500行)、主な機能の一部であるMIDIメッセージバッファとループ演奏の仕組みのみ説明します。
MIDIファイルはSMF(Standard midi file)という標準仕様があり、それを演奏するライブラリ(Arduino Standard MIDI File (SMF) Player)を使用しました。もともとはUSB-MIDI用ではなく、レガシーMIDIケーブル接続用のライブラリでしたが、USB-MIDI用に改造した上、ループ演奏機能なども追加しました。
MIDI 1.0は古い規格で31.25kbpsと非常に低速です。そのままUSBでMIDIデータを送受信した場合、あまり通信量のないMIDIコントローラなどでは大丈夫ですが、1曲のオケまるごとのような大きなデータを扱う場合、機器によってはUSBの速度に耐えられず、受信側が動かなくなってしまうようです。特に今回使ったポケットミクはその辺りに弱いようで、パソコン上のDAWソフトからの通信でもおかしくなってしまうことが多かったです。当初はこの辺りがとても不安定で、ウェイトを入れてもうまくいったりいかなかったりでした。結局、単純にウェイトを入れるだけではダメで、データを一度バッファリングして、MIDIの通信速度である31.25kbpsをオーバーしないように順番にデータを送り出してやるようにすると、かなり安定しました。ただ、今でも稀にデータ消失があるようで、今後はタイマ割り込みでの実装なども考えています。帯域制御というそうなのですが、曲データの他にMIDIコントローラからMIDI音源へのデータ送信もあるので、道路の交通整理のように一筋縄ではいかないようです。
MIDIメッセージバッファは次のようにリングバッファを用いたFIFOバッファになっています。
MIDIメッセージバッファ(NTFIFOBUF.HPP)
#ifndef _NTFIFOBUF_HPP
#define _NTFIFOBUF_HPP
#include <string.h>
#define BUF_SIZE 100
// 通常MIDIメッセージバイト数(32bitアライン)
#define DATA_SIZE 4
// SysEx MIDIメッセージバイト数(32bitアライン)
#define EXDATA_SIZE 24
// FIFO MIDIメッセージBufクラス
class NTFIFOBuf {
private:
uint8_t array[BUF_SIZE][EXDATA_SIZE];
int front = 0, data_num = 0;
public:
uint8_t push(uint8_t *data)
{
if (data_num == BUF_SIZE) //full
return false;
memcpy(array[(front + data_num) % BUF_SIZE], data, DATA_SIZE);
data_num++;
return true;
}
// SysEx MIDIメッセージ用
uint8_t pushex(uint8_t *data)
{
if (data_num == BUF_SIZE) //full
return false;
memcpy(array[(front + data_num) % BUF_SIZE], data, EXDATA_SIZE);
data_num++;
return true;
}
uint8_t pop(uint8_t *data)
{
if (data_num == 0) //empty
return false;
memcpy(data, array[front], EXDATA_SIZE);
data_num--;
front = (front + 1) % BUF_SIZE;
return true;
}
};
#endif // _NTFIFOBUF_HPP
ループ再生はMIDIのメタイベント(テキスト)により、ループ開始と終了のタイミングで「セクション番号」を打っておきます。DAW上で譜面データを作成するときにテキストを記載できるので、「#Section 1」「#Section 2」などと打っておくと、それがループポイントになります。MIDIファイルを開いた際、最初に全ての「セクション番号」を読み込むので、演奏時は先のセクションにも移動できます。これは、本来のSMFにはない独自仕様です。実装の都合上、音が鳴るすべてのトラック(チャンネル)にセクション番号を打つ必要があります。
終わりに
今後ですが、別のコントローラを使うことも考えてますし、シンセ部分をラズベリーパイなどに置き換えるのも楽しいかなと思っています。でも、まずは所有しているMIDI音源をちゃんと使うところから始めるつもりです。
謝辞
以下のライブラリを使用させていただきました。ありがとうございます。
Arduino Standard MIDI File (SMF) Player (by Marco Colli)
FTP Serveur for ESP8266 (by Jean-Michel Gallego / David Paiva)
LovyanGFX (by lovyan03)


-
natto21
さんが
2021/02/26
に
編集
をしました。
(メッセージ: 初版)
-
natto21
さんが
2021/02/27
に
編集
をしました。
-
natto21
さんが
2021/02/27
に
編集
をしました。
-
natto21
さんが
2021/02/28
に
編集
をしました。
ログインしてコメントを投稿する