こんにちは。ヤン・ワン(別名シー・イェ)です。
私がWAAPI(Wwise Authoring API)に出会ったのは、去年の後半です。私はプロのプログラマーではないので、WAMPやJSONといった新しい概念に圧倒されそうになりました。ところが公式ドキュメント以外は、他の開発者が発信する動画や記事やプロジェクトなどは、ほとんどありませんでした。そこで、助けを求めてまわるかわりに、一人で解明していこうと思ったのです。そして、実に多くを学びました。
リーナス・トーバルズは、
オープンソースで、何かを本当にうまくやり遂げるには、大勢の人を巻き込まないといけないと私たちは強く感じている、と語っています。
アイディアとは、世に出てこそ価値がある、そうでしょう?そこで、オープンソースの精神を念頭に、このWAAPIガイドの連載をみんなと共有することを決めました。公式ドキュメントを補完する内容ですが、もっと読みやすく初心者向けにすることを心掛けました。
初心者向けといっても、一から始めてもらうわけではありません。逆にこれは、あなたがWAAPIの世界に踏み込んでいくときに、使いやすくしてくれるガイドです。私が使うツールはPythonなので、それを前提に話を進めます。もちろん、リモートコールするのにWAAPIが対応する他のプログラミング言語を使っても構いません(例えばC#でWAAPIをコール)。
この連載は、以下のような方が対象です:
1) 開発環境を設定したり、Python、Anaconda、pip、VS Code、PyCharmなどをインストールして使ったりすることができる方。
2) Pythonの基本的なシンタックスに慣れている方。
3) Wwiseの機能を全体的に理解している方。
4)Wwiseの既存ワークフローを積極的に最適化したい方。
5)「 マインドマップ」について知っている方。
目次:
なぜWAAPIを使うべきか?
- 1.1. Wwiseを使いながら、もっと効率的に作業できないかと悩んだことはありますか?
- 1.2. WAAPIの導入目的は?
- 1.3. 公式ドキュメントにある情報では不充分?
マインドマップを使ってWAAPIを効率的に習得
- 2.1. WAAPIの要点をまとめた「マインドマップ」
- 2.2. さらに分かりやすくするために、ナレッジベースにインポートする
この連載の書き方
WAAPIの基本
- 4.1. WAAPIとは?
- 4.2. WAAPIが対応するプログラミング言語や呼び出しのメソッド
プログラミング言語や呼び出しのメソッド
- 4.3. 開発環境の設定
Anacondaのインストール
Anacondaの設定と、pipを使ったWaapi-Clientパッケージの追加
VS Code開発環境の設定
WwiseでWAAPIの有効化
- 4.4. Execution APIとSubscription APIの違い
- 4.5. JSON、WAAPIのドキュメント
JSONとは?
ArgumentとResult(Execution API)
JSONの使い方は?
読みやすくなる、JSONシンタックスのフォーマットは?
Options、Publish(Subscription API)
- 4.6. Hello Wwise!
使用するAPIを決める
コード
Result
WAAPIユースケース
- 5.1. Execution API
引数なし
引数あり
- 5.2. Subscription API
- 次回は?
なぜWAAPIを使うべきか?
1.1. Wwiseを使いながら、もっと効率的に作業できないかと悩んだことはありますか?
- クリック操作やドラッグ&ドロップを減らせるのか?
- インポートした何百、何千というアセットの再生ルールを簡単に作成するには?
- Game SyncやEventやSoundBankを使うときのロジック接続を、自動化できる?
- DAWとWwiseの間で、ダイナミックなインタラクションを構築するには?
- インテグレーションパイプラインを常に最適化するために、CIシステムをリンクする方法は?
- その他
1.2. WAAPIを導入する目的は?
前述のような自問自答を1つでもしたことがあれば、WAAPIが良い解決策となります。Wwise 2017.1で導入された優秀な機能として、WAAPIは繰り返し作業を実行し、ワークフローを効率化してくれます。WAAPIを使って、プロジェクト情報を取得したり、オーディオファイルをインポートしたり、コンテナ階層を構築したり、Eventをポストしたり、Game Syncを設定したり、様々な種類の操作ができます。サウンドデザイナーにとってWAAPIは、Wwiseワークフローの最適化に欠かせないツールです。時間を大幅に節約できるので、その分クリエイティブな側面に注力できます。
業界でも、ゲームオーディオプログラマーやテクニカルサウンドデザイナーといった職種を設けていない企業が多いです。そのような会社に務めている方にとって、このブログはとても役立つかもしれません。ワークフローを効率化する一番の方法は、繰り返しのタスクの継続的な最適化です。迷ったり悩んだりしていないで、さっそく実際の使い方を見てみましょう。
1.3. 公式ドキュメントの情報では不充分?
私が知っているオーディオミドルウェアの中では、Wwiseのローカライズされた公式ドキュメントが最も充実しています。とはいえ、WAAPIの使い方を習うには、多少の技術的な知識が必要です。そこで私は、公式ドキュメントを補足する実用的なブログを連載で書こうと思いました。また、Audiokineticのブログには、WAAPIを取り上げた素晴らしい記事がいくつかあります。ぜひ読んでみてください。
マインドマップを使ってWAAPIを効率的に習得
2.1. WAAPIの要点をまとめた「マインドマップ」
大切な学習ツールとして、この8年、私はマインドマップに大きく影響を受けてきました。見れば分かる通り、WAAPIのAPIは種類が様々です。ドキュメントの中を検索して使い方を調べるには、時間がかかります。例えば、APIのクエリをするにはak.wwise.core.object.getを使うとは、分かりませんよね?
もっと良いやり方がないものか、考えました。そして、ひらめいたのです!マインドマップをつくる、ということです。マインドマップで、WAAPIの要点をまとめるには?では、ak.wwise.core.object.getを例に説明します。
- ひとまず、プレフィックスのakは忘れてください。残りの部分をwwise.core、object、getの3つに分けます。
- 次に、APIを機能ごとに分け、内容が分かるようにボックスで分類します。
Globalビュー
Localビュー
2.2.さらに分かりやすくするため、ナレッジベースにインポート
これで、WAAPIを習得できる基本的なロジックシステムができました。次に、さらに分かりやすくするため、この情報をMarginNote 3にインポートします。
MN3で表示
これでWAAPIの全体像がはっきり分かります。何より、APIを習得して利用するには、こちらの方が便利です。私はこれで理解できたので、あなたにも役に立つかもしれません。もちろん、自分に合った別のツールがあれば、それを使ってください。私が作成したマインドマップを全てここで見せようとは思いません。先ほどの方法で、自分のマインドマップを作ってみてください。それほど難しくないはずです。もし良ければ、私のものに手を加えてみてください。使うのがMarginNote 3でも、XMindでも、それ以外でも構いません。一番大事なのは、実際にやってみることです。
この連載の書き方
このように私は、WAAPIの要点をまとめてみました。では、このブログ連載をどのように書いたかについて説明します。WAAPI APIは、Execution (Functions) とSubscription (Topics) の2つのカテゴリーに分けられます。私はそれを軸に、ブログで連載を書きました。(注: ここでもakプレフィックスは入っていません)
これが、この連載のブログです:
- 概要
- wwise.core(主にExecution API)
- wwise.ui、wwise.debug、wwise.waapi
- soundengine
- wwise.core、wwise.debug、wwise.ui(Subscription API)
- Game EngineでWAAPIをコールする
- 例
WAAPIの基本
4.1.WAAPIとは?
WAAPI(Wwise Authoring API)は、Wwiseに不可欠のモジュールです。これらのAPIにコールすることで、マウスを使ったりキーボードに打ち込んだりすることなく、直接Wwiseに処理を実行するよう伝えられます。関係するのは、UI(ビュー、オプション、コマンド)、コア機能(オーディオファイルの素早い追加)、サウンドエンジン(RTPC値の設定、Eventのポストなど)といった処理です。WAAPIの詳しい情報はこちらです: https://www.audiokinetic.com/ja/library/edge/?source=SDK&id=waapi.html
4.2. WAAPIが対応するプログラミング言語や呼び出しのメソッド
プログラミング言語
WAAPIをコールするのに、C++、C#、JavaScript、Pythonなど様々言語を使えます。この2つ目以降の言語が、初心者にも比較的簡単に使えます。(Python 3.6+を推奨。)プラグイン内からWAAPIをコールする必要がなければ、C++を使う必要はありません。
コールメソッド
WAAPIでは、WAMP、HTTP POST、Wwiseプラグインの3つのメソッドで、APIコールを実行できます。ほとんどの場合、WAMPを使います。理由は、これだけがExecution APIとSubscription APIの両方に対応しているからです。ではWAMPとは何か?WebSocket経由の通信方式です。ネットワーク通信の原理についてあまり知らなければ、ネットワーク上で情報を移動させる手段と考えてください。これを使うには、IPアドレスとWAAPIに接続するポートが必要です。処理を実行するには、アプリケーションをWAMP経由でWwiseにつなげる必要があります。WAAPIでコールする方法について、詳しい情報はこちらです: https://www.audiokinetic.com/ja/library/edge/?source=SDK&id=waapi_gettingstarted.html
4.3. 開発環境の設定
開発環境については知っていると思うので、ここでは説明しません。興味があれば、以下のリンクにアクセスしてみてください。Condaには、WAAPIで必要なWaapi-Clientパッケージがないので、自分でインストールする必要があります。Anacondaが好きでなければ、代わりにpipを使うこともできます。好きであれば、公式のドキュメントに従って実行してください。最初にpipをインストールし、次にAnaconda内のpipを使ってパッケージを管理します。詳細については、以下のリンクをご覧ください。(上級者向け)conda skeleton pypiとcondaビルドコマンドを使って、パッケージをインストールできます。ただ、私は試したことがないので、お任せします。
Anacondaのインストール
https://segmentfault.com/a/1190000022797661
Anacondaの設定と、pipを使ったWaapi-Clientパッケージの追加
https://zhuanlan.zhihu.com/p/25198543
注: pipをインストールすれば、Python 3で直接pip install waapi-clientを実行できます。
VSCode開発環境の設定
https://zhuanlan.zhihu.com/p/30324113
WwiseでWAAPIを有効にする
https://www.audiokinetic.com/library/edge/?source=SDK&id=waapi_prepare.html
4.4. Execution APIとSubscription APIの違い
Execution APIが特定の処理を実行し、その後にSubscription APIがReturn値を取得します。Wwiseの公式ドキュメントでは、それぞれ「リモートコール」と「パブリッシュ&ポスト」と呼ばれています。Execution APIはその名通り、具体的な処理を実行する(execution)ときに使います。このAPIをコールすると、具体的な処理が実行されます。3つのメソッドのどれを使ってもExecution APIのコールを行えますが、HTTP POSTはベストではありません。
Subscription API:
Subscription APIコールを実行すると、あなたのアプリケーションはWwiseの反応を待ちます。例えば、オブジェクト作成アクションにサブスクライブしている場合は、そのアクションが実行されたあとに、return値を受け取ります。このようなコールを実行できるのはWAMPだけです。ほかの2つのメソッドでは、できません。
4.5. JSON、WAAPIのドキュメント
JSONとは?
プロのプログラマーでない人(例えば私)は、初めてWAAPIを使うときにJSONが何か分からず、不思議に思うかもしれません。JSON(JavaScript Object Notation)は、人間に読めるテキストを使ってデータオブジェクトを保存したり送信したりする、軽量のデータ交換フォーマットです。XMLについて知っている方は、JSONも多少分かる思います。JSONを知ることは重要です。なぜなら、WAAPIにリモートコールを行うときに、入力引数とreturn値の両方でこのフォーマットを使うからです。次に進む前に、JSONのことを説明します。分かりやすくするため、例をあげます。
ArgumentとResult(Execution API)
こちらはak.wwise.core.object.createのドキュメントですが、表が2つあります。
Arguments
Result
どちらにもName、Type、Descriptionの3つの列があります。関数で引数を渡してreturn値を取得できます。Arguments表にあるのが、関数を呼び出すときに渡す引数です。Result表にあるのが、終わった後にreturn値として返される結果です。前述の通り、全てがJSONフォーマットです。なお、アスタリスク(*)付きは必須の引数で、それ以外はオプションです。
Arguments表を見てみましょう。3つのタイプの引数があります:
- name *には、名前を定義する引数として文字列が1つ必要です。つまり、JSON用に名前を1つ、文字列として提供します。一方、parent *に4つの引数がある理由は?見ると、最初の引数はany of:です。つまり、そのあとに続く3つの引数のうち、どれかを選んでparentを定義すればいいのです。選択肢は、name、GUID、そしてpathです。
- notesにはアスタリスクが付いていません。必須引数ではないからです。つまり、ak.wwise.core.object.createを使うときに、必要に応じてnoteを渡すのかどうかを判断すれば良いのです。
- childrenは、少し分かりにくいです。今までの引数とは異なります。実は、ここで渡す引数に入れるためのアレイなのです。children[... ].type *と、children[... ].name *は、必須引数です。そこで、typeとnameのsub引数は、必ず入力します。
続いて、Result表を見てみましょう。ここで渡す引数さえ分かれば、どのようなreturn値が返されるのかを予想できるはずです。例えば、ak.wwise.core.object.createを使って、オブジェクトをいくつか作成したとします。当然、Wwiseはそれらのname、GUID、pathを、適宜返すべきです。そして、失敗すればエラーが報告されます。
JSONの使い方は?
前のセクションで、引数の内容や、それに対するreturn値について説明しました。今度は、これらの引数をどのように完成させれば、確実にWAAPIに届くのかを考えます。ak.wwise.core.object.createを例に、流れを説明します。
# ak.wwise.core.object.create の実行に必要なArgument
# ak.wwise.core.object.create を実行して args を渡した後に返されるResult
この例から分かるように、実はJSONはPythonのdictionaryのようなものです。違いは、JSONの引用符が必ず全て二重引用符なのに対し、JSONのブロックが必ず文字列のフォーマットとなることです。ただし、Python + WAAPIの環境下では、この2つのルールは厳しく確認されていないようです。PythonでJSONモジュールを使わなくても、フォーマットを変換できます。dictionaryフォーマットで記述しても機能します。
PythonとJSONを比較すると、データ構造の観点から相互関係が見えてきます。WAAPIを使うときに、これらのオブジェクトは欠かせません。求める結果を得るには、引数を必ずこのように設定する必要があります。
読みやすくなる、JSONシンタックスのフォーマットは?
WAAPIの引数に関するドキュメントはJSONで定義されていて、読みやすさに欠けます。WAAPIを使うときに引数を理解しやすくするには、JSONシンタックスのフォーマット化が必要です。
こちらはak.wwise.core.object.createの引数シンタックスです:
非常に読みにくいです。改善するには、JSON Editor( https://jsoneditoronline.org/ )のようなJSONフォーマットツールを使います。
フォーマットはさっきまで、めちゃくちゃでしたよね?すっかり見やすくなりました!
引数のシンタックスのフォーマットが整うと、required セクションにrequiredの引数があり、properties セクションにtypeやdescriptionがあるのが、はっきりと分かります。propertiesは、他に2つあります。localDefinitions は、実は前述のchildrenの定義です。patternProperties は、@propertyName経由でオブジェクトのプロパティを設定するときに可能なvalue typeです。
Result表も、使い方は同じです。次の図で、デフォルトのreturn値のname、children、idがはっきりと表示されています。JSONシンタックスのフォーマットを整えたので、引数もreturn値もかなり読みやすくなりました。WAAPI関数を呼び出すには、JSONフレームワーク内でrequiredの引数を変更してから、リモートコールを実行するだけです。JSONとPythonの相互関係を理解するには、まずは例を参考にしてみてください。Wwise Authoring APIのExamples Indexに記載されている全ての例に目を通すことをお勧めします。かなり短い例ばかりなので、このブログの説明を先に読んでおくと良いと思います。
では、実際のコンテキストにおける、これらの引数の使い方を考えます。こちらは公式ドキュメントにある例で、Sound SFXオブジェクトが2つ入ったRandom Containerの作成方法が書いてあります。
# 1. コード例にある引数
# parent GUID、type、name、プロパティ値
# childrenのtype、name
# 2. 実際のシナリオの引数
# JSONフォーマット引数をargsにアサイン
# リモートコールを実行。最初の引数がAPI name、次がJSON引数。
# 3. リモートコールの後のreturn値で、parent GUID、parent container name、children GUID、children nameなどを含む。
OptionsとPublish(Subscription API)
公式ドキュメントをよく見ると、Subscription APIの引数は少し違います。ArgumentsとResultではなく、OptionsとPublishという2つの表があります。Subscription APIは、トピックをパブリッシュする時に実行するコールバック関数に基づいています。Options表にある引数が、コールバック関数のreturn値のtypeを定義して無駄なクエリを防ぎます。一方、Publish表の引数は、Result表の引数の別の式だと考えてください。要は同じ情報をJSONフォーマットで返すのですが、パブリッシュするのは、サブスクライブしているトピックが変更されたときです。とはいえExecution APIの例外もあり、例えば ak.wwise.core.audio.importTabDelimited 、 ak.wwise.core.object.get 、 ak.wwise.core.profiler.getBusses 、 ak.wwise.core.profiler.getVoices などがそうです。これらには、Arguments表とOptions表の両方が記載されています。前者はクエリの範囲を指定します(必須)。後者はクエリの選択肢を示します(任意)。詳しくはパート2で説明します。
4.6. Hello Wwise!
ここまでは、基本的な話です。今度は、実際のシナリオでどう機能するのかを見てみましょう!“Hello Wwise!”を例に取り上げます。
使用するAPIを決める
当然、Hello WorldのようなシナリオではExecution APIを使います。ak.soundengine.postMsgMonitor が、適役です。
コード
理解しやすいように、コードに細かいnotesを追加しています。以下で確認できます。
# Pythonの例外を扱う “try…except…”文。例えば、WAAPI接続が失敗した時。
# Wwiseに接続するのに、デフォルトアドレスを使用。ポートは必要に応じて変更可能。
# WAAPI引数は、渡すものも、返されるものも、全てJSONフォーマット。プリントアウトメッセージ(Hello Wwise!)の定義にdictionaryを使用。
# ak.soundengine.postMsgMonitorにリモートコールをして、定義したばかりの引数を渡す
Result
スクリプトを実行する前に、Start Captureを忘れずにクリックしてください。そうしないと、Profilerがキャプチャ処理を開始しません。最後に、以下の情報が表示されます:
LogsのWAAPIタブで、WAMP接続が構築されたのが確認できます。
Profilerにプリントアウトメッセージ"Hello Wwise!”が表示されます。
WAAPIのユースケース
5.1.Execution APIs
引数なし
getInfo 関数で現在のプロジェクトの情報を取得
From waapi import WaapiClient, CannotConnectToWaapiException
引数あり
"Hello Wwise!"のセクションを参照。
5.2.Subscription APIs>
ak.wwise.core.object.nameChangedを使い、オブジェクトのnameが変更されたときにプロジェクト情報にサブスクライブし、その新name、旧name、そしてtypeを返します。
# Pythonの例外を扱う“try…except…else…”文
# コールバック関数としてon_name_changed()を使い、return値をdictionaryフォーマットで取得
# オブジェクトtypeを取得
# 旧nameを取得
# 新nameを取得
# フォーマット関数を使い情報をプリントアウトし、ユーザーに、type「XXX」のオブジェクトのnameが、「A」から「B」に変更されたことを、ユーザーに伝える。
# 必要に応じてWAMP接続を終了する
# 必要なトピックにサブスクライブし、コールバック関数で渡す。オブジェクトのnameが変更された時に、オブジェクトのtypeを返すには、typeを選択する
handler = client.subscribe("ak.wwise.core.object.nameChanged", on_name_changed, {"return": ["type"]})
# 情報をプリントアウトし、ak.wwise.core.object.nameChangedにサブスクライブしたことを、ユーザーに伝える。スクリプトを確認するためにオブジェクトのnameを変更することをユーザーに提案する
print("Subscribed 'ak.wwise.core.object.nameChanged', rename an object in Wwise")
これがreturn値です。プロジェクト情報が期待通りにプリントアウトされました。
•次回は?
パート2では、wwise.core のExecution APIを取り上げます。公式ドキュメントには多数の例が記載されています。すぐに取りかかれるように、私からは実際のユースケースをご紹介します。興味のある方は、お見逃しなく!
コメント