「まるでWwiseは表計算ソフト。」これは私たちUEチームがよく聞くコメントです。Wwiseはサウンドデザインをするためのツールですが、実際、エンジン部分を見るとWwiseプロジェクトは依然データです。しかも大量の。最近の現実として、ゲームは巨大であり、問題を事前に回避したければデータをうまくコントロールした方が良いというわけです。
幸い、Wwiseには大量のデータを操作するためのツールとして、 List View 、 Multi Editor 、 Batch Rename 、 Query Editor などが用意されています。
また、大量のデータを処理しやすくするために、Wwiseプロジェクトの中を整理する技やグッドプラクティスも色々とあります。例えばWork Unitの設定、命名規則の導入、タブ区切りファイルのオーディオファイルのインポート、カスタムプロパティの活用、バッチ操作で行う名前変更、色分けなどがあります。
さらに、データを探し出したいときは 検索 や Query Editor などがあります。ただ、これらのツールには限界があります。例えば、あなたのプロジェクトのランダムコンテナの中で、ループするサウンドが入っているのはどれ?あるEventが参照するオーディオソースはどれ ?
私たちは数年前、Wwiseプロジェクトをプログラマーが自動化、操作、そしてクエリできるプログラミングAPIとして、WAAPIを発表しました。ただ、WAAPIにはプログラミング言語が必要です。この能力はいまだ、主にプログラマーの手中にあって、残りのWwiseユーザーには手の届かない存在です。また、WAAPIスクリプトを実行できるようになるまで設定にも時間がかかります。
WAAPIのこちらの例はPythonで書かれ、あるEventが参照するすべてのコンバージョン後のファイルをプリントするものです。決して読みやすいものではありません。
from waapi import WaapiClient
import pprint
# connectする(デフォルトURL)
client = WaapiClient()
# 全ターゲットをreturnする
args = {
"from": {"path": ['\\Events\\Default Work Unit\\Play']},
"transform": [
{"select": ['children']}
]
}
options = {
"return": ['@Target']
}
result = client.call("ak.wwise.core.object.get", args, options=options)
pprint.pprint(result)
# ターゲットの全wemファイルをreturnする
args = {
"from": {"id": list(map(lambda x: x['@Target']['id'], result['return']))},
"transform": [
{"select": ['descendants']},
{"where": ['type:isIn', ['AudioFileSource']]}
]
}
options = {
"return": ['name', 'id','sound:convertedWemFilePath']
}
result = client.call("ak.wwise.core.object.get", args, options=options)
pprint.pprint(result)
# disconnectする
client.disconnect()
WAQLの導入
Wwise 2021.1 で初めてWAQLが取り入れられました。WAQLはWwise Authoring Query Languageの略で、「ワーケル」とよんでください。JIRAのユーザーは、JIRAデータベースをクエリする方法としてJQL(JIRA Query Language)をご存知かもしれません。またプログラマーの方は、C# LINQやSQLをご存知かもしれません。WAQLは、これらランゲージに似ているところがあります。Wwiseプロジェクトに対するクエリを、そのデータモデルを利用して行えるのです。要約すると、Wwiseオブジェクトや、そのプロパティにクエリをかけます。
WAQLは、自分のプロジェクトの中にあるデータを今までよりも自分でコントロールできるようにしたい、という私たちの計画の次の一歩にあたります。新たに学ばなくてはいけないランゲージではありますが、完全なプログラミング言語のPythonやJavascriptやC#を習うよりハードルがぐっと低いはずです。そしてWwise Authoringに入ったその状態のまま使用を開始できることが、さらに重要なポイントです。今回の記事の目標は、WAQLの基本を理解してもらうことです。実際に私たちは、記事を読み進めながらご自分のWwiseプロジェクトで試してみることをお勧めしています。これはWAQLのチュートリアルでもあり、導入のための概要でもあるのです。
ではまずシンプルなものから始めましょう。あなたのプロジェクトの中にある、ボリュームが0未満であるオブジェクトをすべて探し出します。そのためには、まず List View を開き、次を入力してください: $ where volume < 0
待った!何が起きているのか、考えます。まず、List Viewのサーチバーに入力したときに、普通はプロジェクト全体を対象にテキストサーチが実行されますが、今、最初に $ を入力したので、Wwiseは単純なサーチではなくWAQLクエリが開始されることを知ります。
次に where キーワードが、これから条件文が入力されることを示します。クエリを where で開始するとデフォルトで、条件がプロジェクト内の全オブジェクトに実行されます。最後に条件文を入力します。今回はWwiseオブジェクトのプロパティであるボリュームを、数字のゼロと比較するように指示します。この条件で、ボリュームがゼロ未満でないオブジェクトは外されます。
Wwiseのオブジェクトとプロパティ
ここで気になるのが、Wwiseのオブジェクトとプロパティについてです。Wwiseのオブジェクトとは、要はProject Explorerにあるすべての項目のことで、これに、様々なシステムの中で、隠れていたり見えたりするその他のオブジェクトも加わります。プロパティはオブジェクトの中で定義され、そこに値が格納されます。
Wwiseには多数のプロパティがあります。例えばこちらは、あるSoundオブジェクトで、Property EditorのGeneral Settingsタブにあるプロパティです:
プロパティには以下のようなものを1つ保存できます:
- 数値(整数値、実数値、ブール値、文字列)。例: Volume
- プロジェクト内のほかのオブジェクトへのリファレンス。例: OutputBusEffect0
- ローカルオブジェクトで、‘Custom’と言われるもの。例: Effect0
すべてのWwiseオブジェクトのすべてのプロパティを完全に記載したリストが ここ にあります。
また、ほとんどのオブジェクトにみられる、コアプロパティというものがいくつかあります。例えば‘name’、‘notes’、‘path’、‘id’などは、全Wwiseオブジェクトでアクセスできるコアプロパティで、‘volume’や‘outputbus’は特定の種類のオブジェクトに見られるプロパティです。コアプロパティは算出されることもあれば、オブジェクトと一緒に保存されることもあります。どの場合でも、WAQLではプロパティ名の大文字小文字を区別しません。
コアプロパティの詳細については こちら を参照にしてください。
条件を使い始める
すでに見た通り where 文は条件を定義します。この条件は、 where 文に提供された全オブジェクトに対して、判断されます。条件を定義するのはブール式、つまりtrueまたはfalseのどちらかになる文です。
以下は、いくつかの例です:
- $ where pitch = 1200
- $ where volume > -10 and volume < 0
- $ where IsLoopingEnabled or IsStreamingEnabled
- $ where (volume >= 0 and (lowpass > 0 or highpass > 0))
それでは where 条件を使って、ほかのシナリオも試してみてください。
以下の3つの文字列比較の演算子を使い、WAQLでテキストを検索し比較することもできます:
- $ where name = "Hello"
等号は、ある文字列全体を別の文字列と、大文字小文字を区別せず比較するときに使い、両者が全く同じ場合にtrueを返します。 - $ where notes : "hell"
コロン記号は、文字列の中の、ある単語の先頭を見つけるために使います。大文字小文字を区別しません。単語が見つかればtrueを返します。 - $ where outputbus = /^Music\d+$/
等号演算子は、正規表現にも使えます (ECMAScript style)。
オブジェクトとプロパティをつなげる
Wwiseオブジェクト上には、プロパティが2種類あります:
値を返すプロパティ:
- volume、pitch、lowpassなど: Wwiseでスライダーが設定されていることが多く、数値を保存します。オブジェクトの種類によって、これらは変わります。例えばSoundとRandom Containerではプロパティセットが同じではありません。
- name、notes、id、path: Wwiseオブジェクトシステムの中核をなす要素で、文字列の値を保存する場合が多いです。どのWwiseオブジェクトにもあります。
別のWwiseオブジェクトを返すプロパティ(リファレンスとも呼ばれます):
- outputbus、target、userauxsend0、effect0: これらは別のオブジェクトを指し、それはオブジェクトの種類によって変わります。例えばEventとSoundは、プロパティが同じではありません。
- parent: 親オブジェクトを指します。
オブジェクトと値を、 ドット 記号で組み合わせることができます。例えば:
- $ where parent.name = "Music"
親の名前が“Music”。 - $ where parent.parent.name = "Music"
祖父母の名前が“Music”。 - $ where parent.volume < 0
親のボリュームが0未満。 - $ where outputbus.parent.name = "Master Audio Bus"
アウトプットバスの親の名前が“Master Audio Bus”。 - $ where effect0.pluginname = "Wwise Compressor"
スロット0のエフェクトのプラグイン名が“Wwise Compressor”。
違うソースから始める
ここまで、プロジェクト全体のオブジェクトを対象にフィルターを適用してきました。さて、もっと狭いオブジェクト群の中から探したいような場合もあります。WAQLでは、クエリのソースを、このように設定することができます:
- 指定した種類のオブジェクトすべて
- プロジェクト内の1つまたは複数の、特定のオブジェクト
- レガシーのクエリオブジェクト(Query Editor)の結果
- 文字列検索クエリの結果
以下を試してみてください:
- $ from type sound
- $ from type audiofilesource
- $ from type randomsequencecontainer, switchcontainer, blendcontainer
種類を、直接 from 文で指定するのは、検索範囲を狭めるための非常に効率的な方法です。WAQLがイテレーションを指定したソースに限定します。最後のクエリは where キーワードを使ったフィルター検索で書くこともできます。ただしこのフィルターはEventやバスやサウンドなど、全プロジェクトオブジェクトを探さなければなりません。実行時間が遅くなります。
- $ where type = "randomsequencecontainer" or type = "switchcontainer" or type = "blendcontainer"
ほかの種類のオブジェクトでも試してみてください。 こちらを ご参照ください。
以下のように1つのオブジェクトから始めることが、非常に便利な場合もあります:
- $ from object "\Actor-Mixer Hierarchy\Default Work Unit"
- $ from object "{1514A4D8-1DA6-412A-A17E-75CA0C2149F3}"
- $ from object "Event:Play_Footstep_01"7
上記クエリは、 from object を排除することで、さらに短い形式で書くこともできます:
- $ "\Actor-Mixer Hierarchy\Default Work Unit"
- $ "{1514A4D8-1DA6-412A-A17E-75CA0C2149F3}"
- $ "Event:Play_Footstep_01"
また、複数のオブジェクトを指定することもできます。
- $ "\Actor-Mixer Hierarchy", "\Interactive Music Hierarchy"
- $ "{DE2B0843-131F-4E52-BC71-23C43A5324AB}", "{1514A4D8-1DA6-412A-A17E-75CA0C2149F3}"
- $ "Event:Play_Footstep_01", "Event:Play_Footstep_02", "Event:Play_Footstep_03"
以下も、スタート地点のソースが異なるクエリ例です:
- $ from search "foot walk"
- $ from search "hello" where type = "sound"
- $ from query "\Queries\Factory Queries\Audio Source\Audio Source - Format = Vorbis"
オブジェクトを選択する
ここまで、WAQLクエリのソースを from キーワードで指定する方法を習い、WAQLクエリを where キーワードで絞り込む方法を習いました。次にその結果を select キーワードでさらに展開させる方法を見ていきます。
オブジェクトを選択することで、最初の一連のオブジェクトからほかのオブジェクトを取得できます。WAQLクエリのある部分が、次の部分の元となり、つながっていくことを、常に頭に入れておいてください。
List Viewで、以下のクエリを入力してください:
- $ from object "\Actor-Mixer Hierarchy\Default Work Unit" select children
これはDefault Work Unitを見て、その直接の子をすべて返します。このクエリには2つの部分があり、それは from 文と、 select 文です。 from 文が、クエリの始まり、つまりソースを定義します。 select 文は、このソースから出てくる各オブジェクトに対して実行されます。
次のクエリは、オブジェクトの階層からそれぞれ異なる要素を選び出します:
- $ "\Actor-Mixer Hierarchy\Default Work Unit" select descendants
すべての子を、再帰的に返します。 - $ "\Actor-Mixer Hierarchy\Default Work Unit" select parent
直接の親を返します。
$ "\Actor-Mixer Hierarchy\Default Work Unit" select parent.parent
直接の祖父母を返します。 - $ "\Actor-Mixer Hierarchy\Default Work Unit" select ancestors
すべての親を再帰的に返します。 - $ "\Actor-Mixer Hierarchy\Default Work Unit" select parent, children
親と、その子の組み合わせを返します。 - $ "\Actor-Mixer Hierarchy\Default Work Unit" select this, parent, children
Default Work Unit自体と、その親と、子を組み合わせて返します。 - $ from type sound select parent
すべてのサウンドの、すべての親を返します。
select キーワードを使えば階層の子や親の間を移動することができるだけでなく、プロパティからオブジェクトを選択することもできます。
- $ from type sound select effect0
すべてのサウンドオブジェクトの、index 0にあるすべてのエフェクトを返します。 - $ from type sound select effect0, effect1, effect2, effect3
すべてのサウンドオブジェクト用に見つかった、すべてのエフェクトを返します。 - $ from type sound select outputbus
すべてのサウンドオブジェクトの、Output Busで見つかったすべてのバスを返します。 - $ from type sound select outputbus.parent
すべてのサウンドオブジェクトの、Output Busで見つかったバスの親を返します。
追加の演習問題:
- where 文を select 文のあとに追加してみます
- where 文を select 文の前に入れてみます
- select referencesto を使ってみます
複雑なクエリを解明する
次のクエリは、あるEventが参照するすべてのSoundオブジェクトを列挙するものです。このクエリでは、5つの文がつながっています。
- $ from type event select children select target select this, descendants where type = "sound"
クエリの各部分は、以下の通りです:
- $ from type event
まず、プロジェクトのすべてのEventを列挙します。 - $ from type event select children
次にEventオブジェクトからEventアクション(直接の子)を取得します。 - $ from type event select children select target
次に各アクションのターゲット(targetという名のリファレンス)を取得します。 - $ from type event select children select target select this, descendants
次に、ターゲット自体(キーワードthisを使用)と、その子孫を取得します。 - $ from type event select children select target select this, descendants where type = "sound"
最後に、サウンドオブジェクトだけを残します。
さて、次は?
これは氷山のほんの一角です。今はWAQLのバージョン1で、今後、さらに進化するのでご期待ください。既にアクセスしてクエリを行えるプロパティ数は450を超え、対象オブジェクトは60種類以上あります。クエリで組み合わせることのできる文の数に制限はなく、順序も自由なので、今でも可能性が無限大です。また、今回は触れていないキーワードもあります。
List View はWAQLの使い方を練習するのにもってこいの場所です。Query Editor を使ってWAQLクエリをプロジェクトに保存することもできます。
WAQLや、サポートされる機能について詳しく知りたい場合は、WAQLの リファレンス を参考にしてください。
もしWAAPIを使っていれば、WAQLを関数 ak.wwise.core.object.get の中で直接使うこともできます。あなたの仕事が 楽に なるはずです。
あなたがWAQLを使って何を達成したか、教えてください!
コメント