ADX2 Atom Craftの便利ショートカットパネルの作成、MIDIコントローラーやStream Deckからの操作


# ADX2とは
CRI ADX2は、ゲーム向け統合型サウンドミドルウェアです。ゲーム開発におけるサウンド演出の便利なライブラリと、その設定を行う専用ツールがセットになっています。
基礎知識や各エンジンの組み込み方については以下をご覧ください。

Unity: Unityのサウンド機能をADX2で強化する
https://qiita.com/Takaaki_Ichijo/items/16e6501fc07f5b3b3377

UE4: ADX2 for UE4の導入で、一歩上のサウンド表現を（導入編）
https://qiita.com/SigRem/items/4250925f6d66a4fd287a

## ロボット機能とは

ADX2に最近搭載された、処理の自動化機能です。
ADX2のワークフローでは音の設定を専用ツールAtom Craftの上で行いますが、その操作や各データの設定変更をpythonスクリプトで自動化できる機能です。

CRI Atom Craft ロボット とは
https://game.criware.jp/manual/adx2_tool/latest/criatom_tools_atomcraft_api.html

今回は起動しているAtom Craftに対して様々な入力を外部デバイスやスクリプトから行う拡張を作ります。

## スクリプトの実行方法

ロボット機能のスクリプトは、いくつかの実行方法があります。
- Atom Craft内のメニューから実行
- コマンドライン引数に渡して実行
- 起動中のAtom Craftにコマンドを送って実行

### Atom Craft内のメニューから実行

![ロボット機能.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19010/db396cd2-a7d6-71d4-3361-191646eb6d9d.png)

### コマンドライン引数に渡して実行

Atom Craftを起動していない状態で、スクリプトに記述された処理を実行します。

```
CriAtomCraftC.exe [プロジェクトファイル].atmcproject -script [スクリプトファイル].py -workunitall

```
### 起動中のAtom Craftにコマンドを送って実行

現在開いてるAtom Craftに対する操作も可能です。あらかじめAtom Craftで「スクリプトサーバー」を起動しておくことで、Atom Craftが外部Pythonスクリプトからの通信接続を待ち受けるようにします。

pythonスクリプトからは、cri.atomcraft.criatomcraft_api_lib経由で、現在開いているAtomCraftと通信接続を行うことで、pythonスクリプト経由でAtom Craftのパラメーターを変更できます。

![スクリプトサーバーの起動.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19010/aed23ff8-c8ae-69d2-03c8-d9dbb3990621.png)

接続を行うpythonスクリプトは次の通りです。

```acconnection.py
import sys
import cri.atomcraft.criatomcraft_api_lib as acconnect

def connect():
    # 初期化
    result = acconnect.initialize()
    if result != 0:
        print("initialize error")
        sys.exit()
    # 接続の実行
    result = acconnect.connect("127.0.0.1", 9000)
    if result != 0:
        print("connection failed")
        acconnect.finalize()
        sys.exit()

def disconnect():
    # 接続の終了
    acconnect.disconnect()
    # 終了処理
    acconnect.finalize()
    sys.exit()

```
サーバーアドレスはデフォルトで127.0.0.1:9000ですが、変更可能です。

# 外部ツール・デバイスからからAtom Craftを操作

ロボット機能を使って外部のツールまたはデバイスからAtom Craftを操作してみましょう。

## スクリプト例：選択キューのキューリミットフラグをオン

サンプルとして、選択中のキューのキューリミット（再生上限数）の設定を操作するスクリプトを用意しました。
操作前に先ほどの「acconnection.py」を使って接続し、操作後に切断します。
引数に"off"が付いていた場合は、逆にキューリミットをオフにします。

```set_cuelimit.py
# --Description:[ja]選択キューのキューリミット操作

import cri.atomcraft.project as acproject
import cri.atomcraft.criatomcraft_api_lib as acconnect
import acconnection

#引数取得
args = sys.argv
acconnection.connect()

# コマンドの送信
selected_cues = acproject.get_selected_objects("Cue")["data"]
if not selected_cues:
    acdebug.warning("Please select at least one Cue.")
    sys.exit()

for cue in selected_cues:
    value = "True"
    if(len(args) > 1 and args[1] == "off"):
        value = "False"
    acproject.set_value(cue, "CueLimitEnableFlag", value)

acconnection.disconnect()

```
set_valueには文字列でTrue,Falseを渡す点に注意してください。


## 外部環境①Tkinterで便利ショートカットパネルを作成

標準のPythonのGUIライブラリTkinterを使って、簡単なGUIでAtom Craftの設定を変更するショートカットパネルを自作してみます。
先ほどのAtom Craftとの接続スクリプト、キューリミット設定スクリプトを組み合わせます。

```AtomCraftShortcutPanel.py
import sys
import tkinter as tk
import cri.atomcraft.debug as acdebug
import cri.atomcraft.project as acproject
import acconnection

def cuelimit():
    #引数取得
    args = sys.argv
    acconnection.connect()
    # コマンドの送信
    selected_cues = acproject.get_selected_objects("Cue")["data"]
    if not selected_cues:
        acdebug.warning("Please select at least one Cue.")
        sys.exit()

    for cue in selected_cues:
        value = "True"
        if(len(args) > 1 and args[1] == "off"):
            value = "False"
        acproject.set_value(cue, "CueLimitEnableFlag", value)
    acconnection.disconnect()

# ウィンドウの作成
root = tk.Tk()
# ウィンドウタイトル設定
root.title("Atom Craft Shortcut Panel")
# ウィンドウサイズ設定
root.geometry("200x300")
# 接続ボタンの作成
button_connect = tk.Button(root, text="Connect to Atom Script Server", command=acconnection.connect)
# キューリミットオンボタンの作成
button_cuelimit = tk.Button(root, text="Set Cue Limit To Selected Cue", command=cuelimit)
# ボタンの表示
button_connect.grid()
button_cuelimit.grid()

# ウィンドウを閉じたら切断
root.protocol("WM_DELETE_WINDOW", disconnect)
root.mainloop()
```

非常にシンプルですが、操作用のウィンドウができました。

![PythonによるAtomCraftショートカットパネル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19010/e5f9acef-f68a-6f60-8b9b-e989763c2fbe.png)

## MIDIコントローラーから操作

Atom Craftは元からMIDIコントローラーでの入力に対応していますが、スクリプトの直接起動はできません。
そこで、pygameを併用してMIDIコントローラーの入力をpythonスクリプト側で待ち受け、Atom Craftの操作します。

まずはpygameをインストールします。

```
python -m pip install pygame
```

MIDIのインプット入力待ち処理は次の通りです。

```midiinput.py
import pygame.midi as midi

trigger_id = 41
end_id = 45

midi.init()
input_id = midi.get_default_input_id()
midi_in = midi.Input(input_id)
loop = True
while loop:
    if midi_in.poll():
        midi_events = midi_in.read(10)
        state = midi_events[0][0]
        print ("midi_events:" + str(state))
        if state[1]==trigger_id and state[2]==127:
            cuelimit()
        if state[1]==end_id:
            loop = False

```

trigger_idとend_idには任意のmidiコントローラーの操作idを入れてください。
起動中は操作された要素がmidi_eventsログで流れるので、割り当てたいボタンを押せばidが何番なのかを確認できます。

## Stream Deckから操作

作成したpythonスクリプトset_cuelimit.pyは、液晶キーボードパネル「Stream Deck」からもAtom Craftを操作できます。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Stream DeckにAtom Craftのショートカットキー作るやつ、成功した！（ロボット機能経由）このあとQiita書きます <a href="https://t.co/AMVxj05LgJ">pic.twitter.com/AMVxj05LgJ</a></p>&mdash; ichijo (@Takaaki_Ichijo) <a href="https://twitter.com/Takaaki_Ichijo/status/1396020444898086919?ref_src=twsrc%5Etfw">May 22, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

Stream Deckの設定で「システム -> 開く」を選択し、「App/ファイル/」欄にpythonスクリプトの起動コマンドを入れます。 pyだとコマンドプロンプトが一瞬立ち上がるので、pywで非表示状態での実行を行います。

```
pyw [ロボット機能Pythonスクリプトのディレクトリ]set_cuelimit.py off

```

![StreamDeckSetting.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19010/7154bc17-505c-6421-ae30-03321e144596.png)

# ロボット機能で広がるAtom Craftショートカット作成
今回はシンプルなキュー操作をサンプルとしましたが、パラメーターを特定の値にセットするボタンや、より複雑な設定処理、一発ビルドボタンなど、いろいろと拡張可能です。
是非皆さんもプロジェクトに沿ってオレオレボタンやパネルを作ってみてください。