WAQL(Wwise Authoring Query Language)のリリースからすでに数年が経ちました。最初のバージョンからはあまり大きな変化がありませんでした。導入以来、最も注目すべき変更点はWwise 2022.1で行われた Project Explorerの検索へのWAQLの統合でした。そして2023.1のリリースに当たり、このクエリ言語をいかに次のレベルに進化させたかをご紹介したいと思います。
WAQLについてご存知のない方は、こちらのブログがおすすめです: https://blog.audiokinetic.com/ja/introducing-waql/
詳細に入る前にWwise Authoring 2023.1で私たちが内部でどのような改善を行ったかをまとめてみます。ここ数年、私たちはWwise Authoringの最も古いデータモデルの一部を、私たちが「ジェネリックなオブジェクトモデル」と呼ぶものに変換してきました。Wwiseのすべてのオブジェクトを同じ方法で処理できるようにすることが基本的な考え方です。例えばどのオブジェクトもボリュームのようなプロパティがあったり、出力バスなど別のオブジェクトを参照したりします。こうすることでジェネリック(一般的)なことはすべて、専用の関数をつくらずにWAQLやWAAPIに公開することができます。例えばWAAPIにはsetVolume関数がありません。ボリュームを設定するためにはak.wwise.core.object.setPropertyまたはak.wwise.core.object.setを呼び出し、"volume"をプロパティ名として渡します。
オブジェクトモデルに追加した比較的新しいことの1つに、オブジェクトリストという概念があります。オブジェクトリストでは、可変数のオブジェクトやオブジェクトへの参照を、どのオブジェクトの中にも保存することができます。例えばActor-Mixer Hierarchyの各オブジェクトにRTPCオブジェクトのリストが付くようになり、エフェクトスロットのリストも付きました。RTPCオブジェクトやエフェクトをボリュームと同様にak.wwise.core.object.set
で設定することができます。
エフェクトやWAQLについてもう少し話を続けます。スロット0にEQが設定されているオブジェクトをすべて検索したい場合、2022.1以前は以下のようにしました:
$ where effect0.pluginname : "EQ"
これで最初のエフェクトのプラグイン名に"EQ"が含まれる、プロジェクト内のすべてのオブジェクトが返されます。ところがエフェクトスロットを限定しない場合は、以下のようにすっきりしなくなります:
$ where effect0.pluginname : "EQ" or effect1.pluginname : "EQ" or effect2.pluginname : "EQ" or effect3.pluginname : "EQ"
2023.1ではこれらの4つの固定されたエフェクトスロットを削除し、オブジェクトリストに変えました。WAQLでオブジェクトリストにあるエフェクトにクエリをかけるのは、どうすればよいと思いますか?これを可能にするために、WAQLにオブジェクトリストの正式な対応を追加する必要がありました。
リスト関数の概要
WAQLでは、where 文、 select文、またはreturn式の中で使用できるアクセサタイプはいくつかあります。以下はタイプのリストです:
アクセサタイプ |
戻り値 |
例 |
Property |
Variant型(integer, float, boolean. string)。 |
Volume, Pitch, IsLoopingEnabled |
Reference |
Wwise Object |
Output Bus, User Aux Send 0, Attenuation |
Object List(NEW!) |
Wwiseオブジェクトの配列 |
RTPC, エフェクト, 子, 子孫 |
JSONオブジェクト |
key-valueを持つJSONオブジェクト。 |
duration.max, duration.min, loudness.integrated |
オブジェクトリストがWAQLでネイティブにサポートされるようになったことで、いくつかの使い方があります。リストに関連して追加されたことの1つに、リストのすべてのアイテムを一括処理する関数の概念があります。
まず最初にcount()関数です。count()関数はリストのアイテム数を返します。この数値をほかの数値と比較することができます。例えば:
$ where effects.count() > 0
これはすばらしいことで、count()関数は引数として任意の条件を設定することもできます。つまり特定条件を満たすアイテム数を数えることができるのです。早速エフェクトリストのEQのあるオブジェクトを探してみます。
$ where effects.count(effect.pluginname : "eq") > 0
このクエリをany()関数で書くことも可能で、条件を満たすアイテムを1つ見つけた時にすぐにtrueを返すため、より効率的です。
$ where effects.any(effect.pluginname : "eq")
以下がリストで使用することのできる関数です:
関数 |
概要 |
例 |
count |
指定条件を満たすリストのアイテム数を返し、それ以外の場合はfalseを返します。条件文は任意です。 |
$ where children.count() > 3 |
any |
条件を満たすアイテムが見つかった場合はtrueを返し、それ以外の場合はfalseを返します。空の場合はfalseを返します。条件文は任意です。 |
$ where rtpc.any() |
all |
リストのすべてのアイテムが指定条件を満たす場合はtrueを返し、それ以外の場合はfalseを返します。空の場合はfalseを返します。条件文は必須です。 |
$ where children.all(type = "Sound") |
first |
指定条件を満たす最初のアイテムを返します。条件文は任意です。 |
$ where effects.first(effect.pluginname :"EQ") != null |
last |
指定条件を満たす最後のアイテムを返します。条件文は任意です。 |
$ where effects.last(effect.pluginname :"EQ") != null |
take |
指定した数のアイテムを抽出し、それらを新たなリストとして返します。 |
$ select children.take(2) |
skip |
指定した数のアイテムを飛ばし、残りを新たなリストとして返します。 |
$ select effects.skip(1) |
at |
リストの指定インデックスにあるアイテムを返します。 |
$ select effects.at(0) |
where |
指定条件に一致するアイテムを新たなリストとして返します。 |
$ select effects.where(effect.pluginname :"EQ") |
エフェクトについて
エフェクトについて少し詳しく説明します。2023.1においてサウンドエンジン側のエフェクトの上限が4個から255個に増えました。一方、Wwise Authoring側では制限がありません(どこかの時点でメモリなどのシステムリソースによる制限は出てきますが)。そこでエフェクトをリストとして格納します。以下はSoundオブジェクトに対するエフェクトのデータモデルを示すUML図です。
EffectSlotという新しいオブジェクトタイプもここで導入しています。EffectSlotは小さなオブジェクトであり、BypassおよびRenderプロパティを格納するほか、ShareSetまたはCustomエフェクトを参照するEffectも格納します。
SoundオブジェクトはEffectSlotオブジェクトのリストを格納するほか、そのサウンドに対するすべてのエフェクトを一括して迂回するBypassEffectsプロパティも格納します。
実はプロジェクト内のすべてのEffectSlotオブジェクトのクエリを以下で行うことができます:
$ from type effectslot
より強力なReturn式
WAAPIと共にWAQLを使うことで、Return式を使って返されたオブジェクトに対して、特定データのクエリを行うことができます。例えば、以下はプロジェクト内すべてのSoundオブジェクトを返すWAQLクエリですが:
$ from type sound
以下のreturn式のJSON配列と共に用いると:
["name", "volume"]
その結果、下表がJSONフォーマットで返されます:
name |
volume |
Silence |
0 |
Ambient_Day_Element_01_01 |
0 |
Ambient_Day_Element_01_02 |
0 |
waterdrop_05 |
-4 |
Ambient_Water_River |
-20 |
さてここで、これらのサウンドのRTPCを取得したいと仮定します。すでにWwise 2022.1でも可能であった、以下の式を使うことができます:
["name", "volume", "rtpc"]
ただしrtpc列として、各行につき以下のようなものが返されます:
[
{
"id": "{1D1905C4-18F9-4506-AD8B-A0CDEC396F4D}"
}
]
これはJSONオブジェクトの配列で、各オブジェクトにRTPC項目のIDが含まれます。この情報はGUIDがすでに分かっている場合、またはGUIDを確認する追加のクエリを行う場合にしか役に立ちません。WAQLはWwiseオブジェクトを返す時に、デフォルトでオブジェクトのIDと名前を返します。今回のケースではRTPCオブジェクトに名前がないため、IDだけが返されます。
ここで例えば、RTPCが付属するプロパティ名と、RTPCを駆動するコントロールインプットの名前を知りたいとします。2023.1には合成によって新しいJSONオブジェクトを返すことができる、以下のような新たな構文があります:
["name", "volume", "rtpc.{controlinput, propertyname}"]
最後の列について、以下のようなものが返されます:
[
{
"controlinput": {
"id": "{CEC3FD56-5B7C-44AF-B635-5C3A0C36825E}",
"name": "Distance_to_Camera"
},
"propertyname": "Volume"
}
]
ここでもデフォルトのidおよびnameの両方が、ControlInputリファレンスのために返されているのが分かります。もしコントロールインプットのIDが不要であれば、以下のような式の配列を使うことができます:
["name", "volume", "rtpc.{controlinput.name, propertyname}"]
その結果、よりコンパクトで要点を簡潔にまとめた次のものが得られます:
[
{
"controlinput.name": "Distance_to_Camera",
"propertyname": "Volume"
}
]
ここで問題となるのはこの列を入手するために必要なコードが、JSONオブジェクトのキーとしてReturn式を使用することで、これは非常に冗長であることです。例えば私たちが求めている1行目のRTPCフィールドにアクセスするためには、こちらのPythonコードが必要となります:
myRTPCs = results[0]['rtpc.{controlinput.name, propertyname}']
この問題を軽減するために、キーワードasを用いたエイリアスの概念を導入して、式の名前を変更できるようにします:
["name", "volume", "rtpc.{controlinput.name, propertyname} as rtpcs"]
コードを短縮することができ、以下のようになります:
myRTPCs = results[0]['rtpcs']
リストのコンカチネーション
最後にご紹介したいのはリストのコンカチネーションです。例として、まずプロジェクトのすべてのイベントを取得します:
$ from type event
そして次に各イベントに関係するそれぞれのオリジナルWAVファイルを取得する、魔法のような以下の式を使います:
["name as event", "children.target.[this, descendants].where(type=\"Sound\").originalRelativeFilePath as originals"]
結果は:
イベント |
オリジナル |
Ambient_Region_PineForest |
[ |
Ambient_River |
[ |
ここで何が起きているのか分かりますか?たくさんのコンセプトが一緒になっています。式を分解すると以下のようになります:
children |
イベントの子、つまりアクションのリストを返します。 |
.target |
各アクションについて、そのアクションのtargetオブジェクトを選択します。これは通常、Actor-Mixer Hierarchy内のオブジェクトを指します。 |
.[this, descendants] |
ターゲットごとに、ターゲット自体(this)とその子孫(descendants)を連結した新しい配列を構築して選択します。 |
.where(type=\"Sound\") |
オブジェクトにフィルターを適用し、Soundオブジェクトだけを残します。なおJSON値の中にあるため、ダブルクォーテーションをエスケープしていることに注意してください。 |
.originalRelativeFilePath |
各サウンドについて、Originalsフォルダに対する元のWAVファイルパスを選択します。 |
その他のリスト
せっかくリストの話をしてきましたので、「WAQLで使用できるリスト」をまとめました:
特化されたリスト:
- 多くのオブジェクトのエフェクト(NEW!)
- 多くのオブジェクトのRTPC
- ランダムおよびシーケンスコンテナのプレイリスト(NEW!)
- オーディオファイルソースのマーカー(NEW!)
- Actor-Mixer HierarchyオブジェクトのMetadata
- ミュージックスイッチコンテナのエントリー、引数(NEW!)
- ダイアログイベントのエントリー、引数(NEW!)
- ミュージックオブジェクトのスティンガー
- ミュージックセグメントのキュー
- ミュージックトラックのシーケンス
- ミュージックシーケンスのクリップ(つまりサブトラック)
一般的なリスト
- children
- ancestors
- descendants
- referencesTo
終わりに
大変な情報量であったと思います。詳しく学びながら遊んでみたいと思う方は、これらの新機能に対応するように更新されたWAQL Playground(https://github.com/ak-brodrigue/waql-playground)を使ってみてください。Wwise 2023.1をダウンロードし、ご自分のプロジェクトをここで試すことができます。理解してご自分のものにするためには、これが一番の方法です。
WAQLは自分のデータをコントロールし、可視性を高めるという考えに基づいています。新機能はこの信念をさらに発展させるものです。
WAQLをProject Explorerの検索、List Viewの検索、Schematic View、Toolbarの検索などで直接使えるほか、Query Editor内で使用できることも忘れないでください。
またWAQLリファレンス(https://www.audiokinetic.com/en/library/edge/?source=SDK&id=waql_reference.html)やWwiseオブジェクトリファレンス(https://www.audiokinetic.com/en/library/edge/?source=SDK&id=wobjects_index.html)も、WAQLやオブジェクトモデルの隠れた魅力を引き出してくれる便利な情報源です。
コメント