SAM2695のNRPNの深掘り
SAM2695でNRPNするとき、特殊なコントロールチェンジに対応しているようだが、midoでは送信できないような気がする
(同等なメッセージを通常のNRPNで送信できる)
需要はないだろうし、同等なメッセージがNRPNで送信できるので、それほど困っていないが、探求心から詳細を調べてみた(完全に自己満足のポエム記事である)
以下のつづき
SAM2695は、NRPNを使って、CutoffやResonanceの設定ができる
NRPNは、雑に解説すると、1つの項目を設定するのに3回のコントロールチェンジを必要とする
以下のような命令(Cutoffの周波数を最大の0x7Fにする設定)
[0xb0, 0x63, 0x01]
[0xb0, 0x62, 0x20]
[0xb0, 0x06, 0x7F]
しかしながら、M5Stackのuiflow MicroPythonライブラリの実装では、
以下のように、1回のコントロールチェンジのデータを送信している
(以下、本記事では特殊CCと呼ぶことにする)
SAM2695は、これを許容しているようで、CutoffやResonanceが効いていることを実際に音を聞いて確認した
[0xb0, 0x63, 0x01, 0x62, 0x20, 0x06, 0x7F]
しかし、SAM2695のデータシートには、3回のコントロールチェンジをする旨が書かれている気がする
コードを読み間違えている、理解が間違っているかもしれない、と思い、
念のため、Windows側からもMIDIメッセージを送信して、サクッと確認して終わりにしようと思った
そのちょっとした興味本位のせいで、膨大な時間を消費することになってしまったのであった
midoで特殊CCを送信したい
Windowsのmidoを使って、特殊CCを送信しようと思った
しかしながら、mido.Message.from_bytes()関数を使って、3バイト以上のコントロールチェンジメッセージを作ると、
msg = mido.Message.from_bytes([0xb0, 0x63, 0x01, 0x62, 0x20, 0x06, 0x00]) # cutoff frequency
コントロールチェンジのメッセージサイズと異なるという以下のエラーが出る(3バイトである必要がある)
site-packages\mido\messages\decode.py", line 52, in _decode_data_bytes
raise ValueError(
ValueError: wrong number of bytes for control_change message
しかたないので、コントロールチェンジの長さチェックしている条件判定において、
and spec['type'] != 'control_change': などの条件を付与して
コントロールチェンジのときだけ、バリデーションを回避してみる
これで特殊CCが送信できるといいのだが…
midoが扱うのはMessage型
midoでデータを送信するとき、Message型のデータを指定する必要がある
例え、バリデーションを回避しても、
mido.Message.from_bytes()関数で、「bytes型」でMIDIメッセージを作成した場合、「Message型」に変換される
そうすると、コントロールチェンジは必ず3バイトに強制的に変換されてしまう
特殊CCは、3バイトの通常のコントロールチェンジに変換されてしまう
後半が欠落する
不正なデータが作られないようにする、親切設計なのだが、
今回のケースでは仇となってしまっている
bytes型で送信するメソッドを作ってみる
port.send()するとき(MIDIメッセージを送信するとき)、送信するデータは「Message型」である必要があるが、
「bytes型」で送信するメソッドを作ってみる
def send(self, bytes):
"""Send bytes on the port."""
with self._send_lock:
self._rt.send_message(bytes)
今度は、python-rtmidi側のバリデーションでエラーが出る
File "_rtmidi.pyx", line 1103, in _rtmidi.MidiOut.send_messageValueError: 'message' longer than 3 bytes but does not start with 0xF0.
このエラーを出している、python-rtmidi側だと思われる
以下のGitHubのURLの部分にはそれらしいコードがあるが、
Cythonなので、ビルドしないといけないと思われる
(Cythonの知識はゼロなので、わかっていない)
RtMidiで試すことに
方向性を変えて、RtMidiライブラリを使って、C++で実装してみる
何も問題なく、特殊CCが送信できて、Cutoff、Resonanceを確認できた
RtMidiOut *midiout = 0;
unsigned char message[32];
// RtMidiOut constructor procedures are omitted because it isn't main topic.
// :
//
// Reset
message[0] = 0xFF;
midiout->sendMessage(message, 1);
SLEEP(100);
// Note On: 144, 64, 90
message[0] = 144;
message[1] = 60;
message[2] = 90;
midiout->sendMessage(message, 3);
SLEEP(3000);
// Note Off: 128, 64, 0
message[0] = 128;
message[1] = 60;
message[2] = 0;
midiout->sendMessage(message, 3);
// CC: cutoff (NRPN for SAM2695)
message[0] = 0xb0;
message[1] = 0x63;
message[2] = 0x01;
message[3] = 0x62;
message[4] = 0x20;
message[5] = 0x06;
message[6] = 0x7f;
midiout->sendMessage(message, 7);
// CC: resonance (NRPN for SAM2695)
message[0] = 0xb0;
message[1] = 0x63;
message[2] = 0x01;
message[3] = 0x62;
message[4] = 0x21;
message[5] = 0x06;
message[6] = 0x7f;
midiout->sendMessage(message, 7);
// Note On: 144, 64, 90
message[0] = 144;
message[1] = 60;
message[2] = 90;
midiout->sendMessage(message, 3);
SLEEP(3000);
// Note Off: 128, 64, 0
message[0] = 128;
message[1] = 60;
message[2] = 0;
midiout->sendMessage(message, 3);
まとめ
SAM2695では、特殊CCで、NRPNを送信することができる(3つのメッセージが1つになるので実装が楽になる)
midoでは、特殊CCは、送信できないと思われる
どこかに回避用の策が用意されているかも
midoにおいても、通常のNRPN(3回のコントロールチェンジ)を使えば、SAM2695のCutoffなどを変更できる
最後に
かなり無意味な調査に膨大な時間を使ってしまったが
調査技術、情報の整理技術が向上したといいかせる
不便なので、python-rtmidiのビルドして、midoで特殊CCを送信できるようにしたい(が、時間が足りなすぎる)
python-rtmidiのビルドもしてみた