vMix(など)に対応したStreamDeck-likeな物理コントローラーを自作する
2018年: vMixのAPIとリファレンスを手sed目grepしてAPI URLを作ってた
2019年: URLを生成するやつを作った(vmix-utility)
2021年: StreamDeckネイティブプラグイン化を試みる(現在進行形...)
2024年(イマココ): 直接APIに物理コントローラーからアクセスしようと考える
まずは機能要件。
-
USBコントローラーとして機能するモードと、Ethernet経由で機能するモードが欲しいつまりHIDとEthernet(TCP/IP, DHCP)が必要- これ無理。というかUSB稼働は考えてもいいが、Goと相性が悪そうな分野なので捨てでも良いと判断
-
前者はStreamDeck(あくまでソフトウェアが本体)、後者はTriCasterやKairosのコンパネ(コントローラー側が本体)のようなイメージ- 前述したとおりなので、両者のアイデアを採用し、ハードウェア上で制御用ページを公開して弄れるようにする。
各モードはスイッチで切り替え可能両モードも共通してアプリから設定を変更するUSBモードはvMixなど外部ソフトウエアとの通信部分もアプリが行うEthernetモードは設定のみアプリが担当し、vMix APIとの通信は基盤で行えるようにする- コントローラーとして使う性質上、複数代の接続がありえる
- 起動は早いほうがいい(刺したら1分以内には使えるようになって欲しい)
- スタジオ使用なので安定性は必要
技術選定。
RaspberryPi4などのシリーズは、起動速度やOS周りがある為管理する対象が多くなってメンテナンス負荷が増えるのを嫌いたいので、要件的には悪くないが今回は外す。
更新: 以下に書いてあることを全部やると、RustやC++でいちからライブラリ群を自作する必要があってちょっとキツい。既存資産のGoを最大限使いまわせるアプローチを採用することにした。
TCPの対応、USB HID対応、ボタンやスイッチ搭載と将来的なLED搭載を考慮してRaspberryPi Pico, Arduino, M5stack, Armなどを候補に入れる。
コスパと拡張性を考えるとArm, Arduino、開発のしやすさを考えるとM5stackとなる。
更新: 何を言っているんだ。普通にラズパイだろ
目指すものがStreamDeckやTriCasterのコンパネのような拡張性が求められるシステムなので、Arm, Arduinoで考える。
また、(使いたいので)Rustで開発したい。これはただの欲。
プロジェクト名は、
Arduino + StreamDeck Or Arm + StreamDeck
RDeck としてみる。
R一文字にArduino, Arm, Rustを詰め込んだ。
どの言語で開発するにしろ、vMix TCP APIのクライアント実装が必要。
また、USBとRJ45、そしてそこそこ処理性能が高いCPUとメモリがいるかもしれない(XMLパーシングを行うならかなりいいのがいる)。
EthernetとUSB HIDが最初から乗ったArmか、Arduino Uno R4 MinimaにEthernet Shield2を載せるのとどちらが良いだろうか。
前者はコスパは程々だが、Arduinoベースだけあり文献は非常に多い。
後者はコスパは良いが、開発資料が少なく難しそうな気がする。悩ましい。
期間が空いてしまった。
取り急ぎMilk-V DuoとUSB/Ethernet拡張ボードを購入した。
64MBモデルでLinuxが動くようなので、C/C++やRustでガッツリIoTするより、Linux上のRustやGoで気軽に書いて楽を出来そう、かも。
必然的にUSBモードは捨てになりそうだけど。
また期間が開いた。
Rustなどを使ってMilkVやM5Stackに組み込み実装するのは骨が折れそうなので、Raspberry Pi上で走るLinuxに実装するアプローチに変更。
StreamDeck用のvMixプラグインが思ったより実装に難航しているので、モチベーションがこっちに移行してきた。
レポジトリを作成。
取り急ぎ、vMixにTCP APIで接続し、対応したLEDを光らせることに成功した。
input[入力] -> connector[制御判断] -> output[出力] というインターフェース分割を行うことで、各種部分がある程度共通で扱えるようにした。
例えば、BMD ATEMのタリー -> タリーライトの制御判断ロジック -> LED の場合、
- ATEMからタリーを受け取り、共通の「タリー入力情報」を作成し、次に渡す
- 受け取ったデータと設定を照合し、「タリーライト出力結果」を作成し、次に渡す
- 受け取ったデータをもとに、光る(又は彩度や色を変更する)
という共通化ができ、ATEMからTriCaster、再生中のみのタリー、タリーライトではなく文字出力、のようにそれぞれの部品の差し替えが実現できる。
問題は、これを稼働途中で行うので、各種APIやLEDへの接続をキャッシュし、ソフトウェア側で完全にコントロールしないといけないという点。
多対多の紐付けを、リトライ処理・非同期パフォーマンスなどを考慮したうえで実装する必要がある(つらい)。
複数のconnectorを実現したい場合、1connectorは1アクションと紐付いて複数インスタンス保持するのか、1connectorが複数アクションを管理するインスタンスとして振る舞いのか、かなり迷い
パフォーマンスとメンテナンス的な問題もある
割といい感じのものが出来てきた。
外部からの設定変更などをどう制御しようかと考えていたが、gobotの仕組みでHTTP APIがホスト出来るらしい。しかもフロントエンドまでついてくるらしい、イケている。
後は手すきの時にairを設定したりしたいな。
あと、gobotでピンのプルアップ/ダウン は設定出来ないような気がする。いちいちraspi-gpio
を叩いている(しかもピン番号ではなくGPIO番号なので読み替えが発生する) ので結構面倒。なんとかできないかなー
robot.AddCommand("stop", func(params map[string]interface{}) interface{} {
cancel()
return nil
})
こんな感じでコマンドを追加してあげると、UI上にも表れて扱えるようになるっぽい。
凄い便利だなーと思いつつ、フロントがすごいバグっぽい。デバッグ用途で良いけど実際にこれで人に渡したいとは思えないので、多分Ginあたりで自作することになるんだろうな...
取り急ぎ、airの設定とTaskfileを使ってちょっと楽を出来る様な仕組みくらいは作ろうかな
UI上で
- vMixやATEMなど接続先ソフトウェアの追加/変更/削除、ステータス確認
- GPIOピンアサインの変更(設定)
- determinerの動作の変更(タリーの条件など)
この辺りが出来たらかなりプロダクトして優秀なものが出来上がりそう。
気が早いけど、3DプリンターやGPIOの結線を簡易化・最適化して、小さい筐体に収まりある程度設定変更などが扱いやすいポータブルシステムになってくれたら最高。
結局ラズパイ4で開発しているけど、Gobotを使っているからうまく扱えばMilk-V Duoとかマルチプラットフォーム対応が出来そう。良いね。