ツマミがたくさんあるMIDIコントローラーが欲しいけれど、Federfoxのは高いし、密かに狙っていたBASTL INSTRUMENTSの60Knobsは製造中止してしまった。
MIDIコンDIYについて調べてみたらArduinoを使えばそんなに難しくなさそうなので、自作することに。こちらの動画を参考にして5ツマミMIDIコンを作ってから、40ツマミMIDIコンを作った。
ちょっとした覚え書き。
𓃌𓃌𓃌𓃌𓃌𓃌𓃌𓃌𓃌𓃌 ←40ツマミ
使用材料
- Arduino UNO (Arduino LeonardoやArduino Megaを使ったほうが良かったかも)
- Muxシールド II
- 単芯ケーブル
- 可変抵抗器&ツマミ
- A4収納ボックス
- ピンヘッダ
使用道具
𓃌𓃌𓃌𓃌𓃌𓃌𓃌𓃌𓃌𓃌
ケースの準備
試作というのもあってケースにはあんまりこだわりはなく、適当なA4の収納ボックスを使った。秋葉原にあるエスエス無線に行くと色々なケースが売ってるみたい。次作るときには行ってみよう。
ケース作りはほとんどこちらの動画と同じ要領で。ドリルビットは竹用だとプラスチックにヒビが入らない。つるんと穴が開けれて気持ちがよい𓃑
穴開け箇所を鉛筆で下書きしたけど、ドリルで穴開ける時に下書きからどうしてもずれてしまい、穴をちょっと大きくしないと固定できなかった。(可変抵抗器は7mmでぴったりだが8mmに、可変抵抗器にある小さいフックは2mmでぴったりだけど3mmにした)下穴用ドリルで下穴あけておけばよかったかも。


可変抵抗とArduinoをケースに固定
こちらの動画だと、配線を先にしてから可変抵抗器をケースにつけてるけど、ケースに可変抵抗器を固定してから配線することにした。その方が後の半田付けが楽かと思い。

ArduinoにMuxつける
Arduino UNOのI/Oにピンヘッダ刺してMux シールドⅡを接続する。Arduino UNOだとI/Oが6つしかないけどMuxを使うと最大48に増やせる。これでたくさんのツマミが付けられる。(デザインを考慮してツマミは48じゃなくて40にした)
(Arduino Megaを使えばマルチプレクサ要らなかったかも)
+5VとGNDのコードを半田付け
可変抵抗に+5VとGNDのコードを半田付けする。赤が+5Vで黒がGND。地道な作業。


GNDも同じように繋げて、+5VとGNDをMuxにも繋げる。(どこから繋げてもいいみたいだけど、一番近い29番の可変抵抗器から繋げた)
可変抵抗上下逆に付けちゃってるので後でArduinoのプログラムで調整する。
信号線を半田付け
Mux シールドⅡのユーザーガイドに推奨するコネクターが載ってたけど、時間がなかったのでMuxに直接半田付けした。(時間がなかったっていうのは、2,3日後のライブに使いたかったから…)時間あったらコネクターとピン配列変換ケーブルを使った方がよいと思う。順番間違えちゃった時に抜き差しするだけなので楽なのと、半田劣化による接続不良のリスクが減るので。
何度も間違えて半田付けし直して大変だった。。可変抵抗に信号線半田付けしてから、Muxに刺して裏返して一気に半田付けするといいみたい。テスターを使って可変抵抗の各端子の抵抗が0に近いのを確認。(0に近いと正しく接続されてるってことらしい)

Arduinoのpin 8を解放する
ここからはユーザーガイド見ながらの作業。Muxシールドの48 I/Oを使用するにはArduinoのpin8っていうのを解放しないといけないらしいので、Mux裏側のSJ1のパッド間のトレースをカットする(下図赤)
またシールドを全部入力で使用するのにSJ5の中央と左のパッドの間にはんだを置く(下図黄色)

Arduino IDEでの作業
ここからはパソコン使っての作業。Arduino IDEをインストールする。
ユーザーガイドからMuxShield.zipをダウンロードし、Arduino IDE立ち上げてツールバーからSketch>Include Library>Add .ZIP LibraryでMuxShield.zipをインストールする。
またArduinoでMIDI通信を扱うためにArduino MIDI Libraryを上記と同じようにインストールする。
MuxShiledライブラリのサンプルMuxShieldAnalogInとMIDI LibraryのサンプルBasic_IOを掛け合わせて、いい感じになるようにChat GPTにプログラムを書いてもらう。(プログラムはこの記事の最後に載せる)
ArduinoをPCに接続し、Arduino IDEでArduinoが挿さってるポートを選び、Chat GPTに書いてもらったプログラムをArduinoにアップロードする。
仮想MIDIバスの作成
Macのアプリケーション>ユーティリティ>Audio MIDI設定で仮想MIDIバスを作成する。
ツールバーからウィンドウ>MIDIスタジオを表示、アイコン[IAC ドライバ]をダブルクリックして、[装置はオンライン]のチェックボックスにチェックを入れると有効になる。MIDI入力と出力はそれぞれ1。
(私のMIDIスタジオではIACドライバが他のMIDIコンに埋もれてて「あれ、どこ?」ってなった)

シリアル通信からMIDI通信へ変換
Arduino UNOはシリアル通信のため、Serial Midi Bridgeなどのツールを使用してMIDI通信ができるようにする。
Serial Midi Bridgeはアプリだと正常に動作しなかったので、ターミナルでPythonファイルを実行した。

(今調べてみたらファームウェアの書き換えをすればArduino UNOをMIDIデバイスにできるみたい。こうすればいちいちシリアル↔︎MIDI変換ツール使う必要なさそう。)
(Arduino LeonardoやArduino Micro、Arduino Pro Microを使えばデフォルトでMIDI通信を送受信できるみたいなので変換ツールやファームウェの書き換えは不要みたい。参考動画)
Ableton Liveでマッピング
Ableton Liveを立ち上げて、メニューのファイル>設定>Link, Tempo & MIDIでコントロールサーフェスをNone、入力と出力をIAC Driver (Bus1)にし、トラックとリモートにチェックを入れる。
あとは好きなようにマッピング。40ツマミあるとたくさんのエフェクターのパラメータにマッピングできる。

Arduinoスケッチ
Mux ShieldライブラリのサンプルMuxShieldAnalogInとMIDI LibraryのサンプルBasic_IOを参考にChat GPTにプログラムを書いてもらって、使いながら不具合があるたびに問題解決するように修正してもらった。
可変抵抗逆につけちゃったので、0-1023が1023-0になるようにしてもらったのと、ツマミを一番左まで回してもMIDIの方は2%くらい残っちゃったので、980以上になったら1023になるようにした(逆だから紛らわしい…)。
あとちょっと遅れがあったのでconst float alpha = 0.2; で変化を滑らかにしたのと、delay(10); を消した。Serial.beginはさっきの変換ツールのbaudrateと同じ115200にする必要あり。あとはよくわかりません。
最終的にこんな感じ。
#include <MIDI.h>
#include <MuxShield.h>
MIDI_CREATE_DEFAULT_INSTANCE();
MuxShield muxShield;
const int numKnobs = 40;
int lastValues[numKnobs] = {0};
float smoothedValues[numKnobs] = {0};
const float alpha = 0.2; // Adjust the response speed
void setup() {
for (int i = 0; i < numKnobs; i++) {
lastValues[i] = -1;
smoothedValues[i] = 0;
}
for (int i = 0; i < numKnobs; i++) {
muxShield.setMode((i / 16) + 1, ANALOG_IN);
}
MIDI.begin(MIDI_CHANNEL_OMNI);
Serial.begin(115200);
}
void loop() {
for (int i = 0; i < numKnobs; i++) {
int reading = muxShield.analogReadMS((i / 16) + 1, i % 16);
smoothedValues[i] = alpha * reading + (1 - alpha) * smoothedValues[i];
// Adjusted the threshold for the high-value dead zone
if ((int)smoothedValues[i] > 980) {
smoothedValues[i] = 1023; // Force value to 1023 if above 980
}
int midiValue = map((int)smoothedValues[i], 0, 1023, 127, 0); // Regular map range
if (abs(midiValue - lastValues[i]) > 5) {
sendMIDIControlChange(i, midiValue, 1);
lastValues[i] = midiValue;
}
}
// delay(10); // Optional delay adjustment or removal
}
void sendMIDIControlChange(int controlNumber, int value, int channel) {
MIDI.sendControlChange(controlNumber, value, channel);
}