リゼット(14新)推奨日記

旧はてなダイアリー(http://d.hatena.ne.jp/risette14/ )から移行しました。

M5StackでMIDIハーモナイザーを作る

経緯

ここ数年、定期的にバンド形式での音ゲー楽曲のコピー演奏を行っており、主にキーボードを弾いていますが、演奏の際に頭を悩ませがちなのが、打ち込み系楽曲を中心にときおり現れる、三度~六度2和音ハモりの速いフレーズの手弾きです。
音を機械的にn半音上下させるトランスポーズ機能ではキー・スケールに対して自然なハモりが得られませんが、手持ちのワークステーションシンセ(FANTOM-0やJUNO-DS)にはハーモナイザー機能がなく(むしろついてるシンセを知りたい)、1音ごとにトランスポーズした音をレイヤーする、サンプラーシーケンサーによる部分的な同期を使うなどの対策が求められますが、前者はレイヤーできるパート数の制限、後者はインテンポで進行しなければズレるためドラムに負担をかけてしまう、といった問題があります。
一方で、市販のハーモナイザー系エフェクター(手持ちはBOSS PS-6)は音の波形を処理するため、どうしてもやや(50ms程度)遅延が発生し、速いフレーズには向きません。
そこで、ワークステーションシンセ内のコントローラー部(鍵盤)からシンセサイザー部(音源)に送信されるMIDI信号に割り込んで新たな信号を付加すれば遅延なくハーモナイズできると考えました。DAWでできそうですが、鍵盤がすでに重い中でいちいちPCまで音楽スタジオに持ち込みたくないので、マイコンMIDIメッセージの勉強がてら、M5StackでMIDIハーモナイザー(あるいはインテリジェントピッチシフター)を開発することにしました。

用意したもの

シンセのMIDI OUT→M5StackのMIDI INおよびM5StackのMIDI OUT→シンセのMIDI INとなるようにMIDIケーブルを2本接続し、シンセから出力されたMIDIメッセージをM5Stackでハモり音に加工してシンセにループバックさせます。あとシンセのUSB MEMORY端子使って給電。
当初よくわからずラズパイでできるのかな…などとつぶやいていたところ、@GRNRGと@chloe_chatから大変実用的なアドバイスをいただきました。ありがとうございました。

完成形


タッチパネルによる送受信チャンネル設定、キー設定、和音1・2設定、ベロシティ比率設定、画面ロック機能を備えています。特に遅延なく、想定通りハーモナイズすることができるようになりました。

構築

環境構築

M5Stack Core2の公式サイトのドキュメントの手順通り、Arduino IDEおよびCore2用ボード、ライブラリの追加を行い、特に詰まる点はありませんでした。

コーディング

コーディングに関しては、C++は競プロの入門サイトで触りをやったぐらいで全然自信がありませんでしたが、GPT-4にMIDI送受信のサンプルコードを読み込ませつつ要件提示したところ、数秒で完成度6割程度のコードが出てきたので、手で書き換えつつさらにGPT-4と質疑やコードレビューを重ねることで数時間で完成形まで持っていくことができました。
公式ドキュメントの翻訳含め、生成AIのおかげで非常にスムーズに構築でき、個人開発には手放せないツールになるなと感じました。

MIDIモジュール

本体の裏蓋を開けてバッテリーソケットを外したところにモジュールを差し込むだけだったので、電子工作苦手な人間にも簡単でよかったです。Core2の場合はソルダジャンパを切り替えるよう記載されていましたが、GROVEポートは使用しない&ハンダ付けする能力がないことからそのままの設定で使用しました。
Core2用のサンプルスケッチは準備中とのことでしたが、CORE1用のサンプルスケッチを

#include <M5Stack.h>

から

#include <M5Core2.h>

に書き換えれば動作しました。
また、

CORE2+Arduinoで使う時の注意点
Serial2の入出力ピンが変更になった関係で、
MIDIライブラリの「MIDI.begin();」は使えません。
代わりに「Serial2.begin(31250, SERIAL_8N1, RXD2, TXD2);」
を入れてください。

と公式サイトに記載されていましたがこのままだと動かず、

Serial2.begin(31250, SERIAL_8N1, RX2, TX2);

としたところ動作しました。

以下は主な動作ロジックのメモです。素人コーディングなのでスケッチは個人的に連絡いただければ共有します…。

基本ロジック

受信チャンネル宛のMIDIメッセージを受信したら、以下のように変換して送信チャンネルに送信します。

ノートオン

設定したキー・スケールに従ってノートナンバー(音程)を変換し、設定比率に従ってベロシティを減らして送信します。

ノートオフ

設定したキー・スケールに従ってノートナンバー(音程)を変換し、送信します。

コントロールチェンジ

そのまま送信します。

その他

読み捨てます。

和音

スケール

メジャースケール(あるいはナチュラルマイナースケール)のみとし、ディスプレイには主調と対応する平行調を表示するようにしました。

和音

最大3和音化し、和音1、和音2それぞれについてOFF、-8th、-6th、-5th、-4th、-3rd、Root、+3rd、+4th、+5th、+6th、+8th、+10th、+12th、ORIGの各モードを切替可能としました。
ORIGは、原音に対し主音のみ-4th、他は-3rdに変換するモードです。

クロマティック音の扱い

BOSS PS-6の作りに合わせ、原音がクロマティック音の場合は、変換先にもクロマティック音があればクロマティック音を、なければ下側のダイアトニック音に寄せるようにしました。

ハマりポイント

  • Core2側のタッチパネルが、どこを触っても一瞬(0,0)を押したと認識するので、タッチの判定条件から(0,0)を除外する必要がありました。
  • ノートオン中に変換するキーや和音を設定変更すると、ノートオフ時の変換先がズレて音が止まらなくなるので、設定変更するたびにオール・ノート・オフメッセージを送信する必要がありました。

おわりに・今後の開発

マイコンMIDIへの苦手意識が少し払拭できてとてもよいチャレンジになりました。
現状、機器間でケーブル3本挿している状態なのが少し不格好なので、今後USB-MIDI化に取り組んでみたいと思います。