TouchDesigner Advent Calender 2024 の1日目の記事です!
Akai Pro APC40 MK2(以下、単に APC40 と呼びます)というMIDIコントローラーのLEDを、TouchDesignerから光らせてみて、MIDIコントローラーのLED制御について学ぶ記事です。
今回扱うライブラリやサンプルは、以下のGitHubリポジトリにて公開しています。
記事の目的
- APC40のLED制御を例として、TouchDesignerからMIDIコントローラーのLEDを操る方法を学ぶ
- TouchDesignerにおける、Pythonを使った自作モジュールの簡単な使い方について学ぶ
TouchDesignerでMIDIコントローラーのLEDを操る
LEDを制御することのメリット
MIDIコントローラーは、ボタンやパッド、ノブ、スライダーといった操作子の情報をMIDIイベントとして送信します。
加えて、LEDが付いているものでは、MIDIイベントを受信することでLEDの状態を更新できる場合が多いです。
この場合、コントローラーはユーザーからPCへ情報を伝えることにも使えるし、逆にPCからLEDを制御することで、情報をユーザーに伝えることもできます。
Ableton Liveなど特定のソフト向けに、LEDがソフトに反応して変化するプリセットなどを備えていることがありますが、このような仕組みを自分でも用意することができます。
TouchDesignerで映像送出、照明制御、VJなど、現場(たいてい暗い!)で操作するようなシステムを組んでいる場合、LEDの表示も適切に設定することによって、操作をわかりやすくし、ミスを減らすことに繋がります。
筆者は、TouchDesignerで組んだシステムを使ってVJを行っています。
以下のようにAPC40のLEDを活用しています。
一見してコントローラー起動時のレイアウトと変わらないように見えますが、VJシステムの各チャンネルの状態やテンポを反映していたり、映像のhueをコントロールするノブの下には処理結果の色が表示されたりと、双方向の制御を組んで活用しています。
LEDを制御する上で面倒なところ
多くのコントローラーでは、コントローラー上のそれぞれのLEDについて、対応するMIDIチャンネル、noteまたはCCのインデックスが割り当てられています。
定められたnoteまたはCCを、MIDIイベントとしてコントローラーに送信することで、LEDを操ることができます。
色も指定できる場合は、noteのvelocityで指定することが多いです。
APC40では、以下のプロトコルにその制御が定められています。
Akai APC40 Mk2 Communication Protocol – Akai Pro
ここでいうプロトコルとは、APC40が送信するMIDIイベントの形式や、受信した際のそれぞれの値に対する振る舞いを定めたものです。
例えば、APC40で40個並んでいる長方形のパッド(Clip Launch)の左上を赤色に光らせるなら、形式的には
{
"channel": 1,
"note_number": "0x20",
"velocity": 5
}
のように情報を準備して、これをMIDI noteとしてAPC40に送信することで実現できます。( 例1 )
これは直感的ではありません。
コントローラー上のLEDとMIDIチャンネル、note、CCとの対応を直接把握するのは難しいので、プロトコルを何度も確認することになります。
また色についても、velocityと対応する色との間ではっきりした規則がなく、プロトコルのリストから欲しい色を探すのも一苦労です。
APC40のようにグリッド状にパッドが並んでいるのであれば、Clip Launchの何行目何列目のLEDを何色に光らせる、といった具合で指定できたら扱いが楽になります。
つまり、形式的には
{
"type": "Clip Launch",
"row": 1,
"column": 1,
"color": "red"
}
のように指定できたら直感的です。( 例2 )
MIDI Out CHOPをPythonから制御する
MIDI Out CHOP と midioutCHOP Class を使えば、DATなどで用意したPythonのスクリプトを使ってMIDIイベントを送信することができます。
先ほどの 例1 に対応するコマンドであれば、
# MIDIイベントを送信するオペレーターを指定
midiout = op('midiout1')
# 点灯または点滅の種類を指定
channel = 1
# 制御するLEDの位置を指定
note = 0x20
# LEDの色を指定
velocity = 5
# MIDIイベントを送信(送信の仕様上、少し値に調整を加えています)
midiout.sendNoteOn(channel, note + 1, velocity / 127)
# Clip Launchの左上が赤色に点灯する
のようになります。
自作のモジュールでMIDIイベントの扱いを楽にする
元々あるこのクラスに加えて、本来は複雑なMIDIイベントの割り当てを、直感的に扱えるように変換してくれる自作のモジュールを用意します。
これらを使って、シンプルなコマンドによってLEDを操ることを試みます。
自作したクラスの集まりをモジュールにしたものが、サンプルリポジトリの/src/apc40mk2.py
です。
これを使えば、Clip Launchの左上を赤色に光らせるには、先ほどの 例2 のように、
# MIDIイベントを送信するオペレーターやデバイスのモードを指定
import apc40mk2
apc = apc40mk2.APC40MK2(op('midiout1'))
apc.mode.set_device_mode(mode=2)
# ここまで、個別LEDの色に直接関係ないので、あまり気にしなくても大丈夫です
# 制御するLEDの行を指定
row = 1
# 制御するLEDの列を指定
column = 1
# LEDの色を指定, 他にも`#ff0000`のような指定も可
color = "red"
# 点灯または点滅の種類を指定
led_type = 0
# MIDIイベントを送信
apc.led.set_clip_launch(row, column, color, led_type)
# Clip Launchの左上が赤色に点灯する
と書くことができます。
MIDIコントローラーの配置の様子に近い指定方法となっており、先ほどより見通しが良くなったかと思います。
自作モジュールのインポート方法
TouchDesignerでは、Pythonが実行されるDATと同じ階層に置かれているDATを、
import datName
の形でモジュールとしてインポートすることができます。
参考:MOD Class – Derivative
ここでは、apc40mk2.py
をネットワークエディターにドラック&ドロップすると作られるapc40mk2
というText DATに対して、同じ階層にあるDATからそれをモジュールとして読み込むようになっています。
一度読み込んでしまえば、あとは自分で用意したクラスでも使うことができます。
今回の場合は、まず
apc = apc40mk2.APC40MK2(op('midiout1'))
として、親クラスに引数の形で、MIDIイベント送信に使うMIDI Out CHOPを指定すると、各種コマンドを使えるようになります。
LEDの色指定についての工夫例
色の指定を行うvelocityについて、プロトコルに定められたような5
などのインデックスそのままではもちろん、'#FF0000'
のようなカラーコードや、"red"
のような色の一般名でも指定できるようになっています。
カラーコードについては、実際にはAPC40が出せるLEDの色の種類は高々128種類なので、指定されたカラーコードに最も近いインデックスを探してくれるようになっています。
わざわざプロトコルのカラーコード表と対峙しなくても、なんとなくこの辺りの色が出したい、という感じで指定できます。
具体的な実装としては、与えられたカラーコードと、実際に出せる色としてプロトコルに記載のあるカラーコードとのうち、ユークリッド距離(RGBの値それぞれの差の2乗和)が最も近いものを採用するだけの簡単なアルゴリズムになっています。
色の一般名については、
self.color_map = {
"black": 0, "dark gray": 1, "gray": 2, "white": 3, "red": 5,
"orange": 9, "yellow": 13, "green": 21, "cyan": 37, "blue": 45,
"purple": 49, "magenta": 53, "pink": 57
}
の13種類を指定できるようになっており、より簡易な運用ではこちらでも十分かと思います。
このような工夫が、自分でモジュールを用意するところの楽しく便利なところだと思います。
apc40mk2.py
の補足
apc40mk2.py
は、APC40MK2
という親のクラスと、パッドやボタンのLEDの制御を行うLEDController
、ノブの値と周りのリングLEDを制御するKnobController
、デバイスの動作モードを設定するDeviceModeController
の計3つの子のクラスに分かれています。
関数それぞれの細かい使い方については、モジュールに書いてあるDocStringを参照していただければと思います。
その際、APC40のプロトコルと見比べてみると、どのような処理をしているか分かりやすいかもしれません。
先ほどのled.set_clip_launch(row, column, color, led_type)
では、以下のようにしてMIDI noteのインデックスを指定しています。なお、一部簡略化して示しています。
def set_clip_launch(self, row, column, color, led_type):
self.midiout.sendNoteOn(led_type + 1, (5 - row) * 8 + column, color / 127)
応用
以上のような手法は、APC40以外のMIDIコントローラーであっても応用することができます。
使いたいコントローラーのMIDIプロトコルを見ながら、自分の使いやすい形でMIDIイベントを送信できるようなモジュールを用意し、実際の呼び出しはそのモジュールを通して行う、という流れは変わりません。
これだけで長くなるのでまた別の機会にと思いますが、他には、8x8のRGBカラーのLEDが配置されたNovationのパッド型コントローラー、Launchpadシリーズ用のモジュールを用意し、TouchDesigner上のTOPの8x8の映像と同じ色でパッドを光らせる、という応用を試したりもしました。
ぜひお手持ちのMIDIコントローラーでも試してみてください!
最後に
この記事について分からない点やご指摘があれば、ぜひ何らかの形で届けてくださると嬉しいです。
コメント、リプライ、DMなどお気軽にどうぞ!
残りの記事を読むのが楽しみです!
monoton(ものとん)について
音楽制作とVJ、ハードウェアを軸に、空間演出に取り組むテクニカルアーティストです。
楽曲リリース、TouchDesignerベースのVJシステム開発を自主制作として行いながら、リアル・バーチャルの双方でライブイベントや展示型作品を手がけています。
Twitter(X): @monoton_music