誰でも使えるWAAPI パート2: wwise.core

ゲームオーディオ / Wwiseの使い方やツール

こんにちは。ヤン・ワン(別名シー・イェ)です。

パート1では、マインドマップを使いながらWAAPIの要点をまとめました。そして、開発環境を整えてPythonの短いスクリプトをいくつか書きました。さらに、WAAPIの力がどんなものかを、ひとまず体験しました。

パート2では、マインドマップにあるWAAPIのブランチ(branch)を探りたいと思います。APIの実用的なユースケースを交えながら、読みやすくシンプルな説明に努めます。

また、アクセスしやすいように、 GitHubにレポジトリを作成しておきました。このブログ連載に出てくるコードが全て入っています。

本題に入る前に、説明しておきたいことがいくつかあります:

  • APIのリストを作成した主な目的は、使用方法を明確にして、すぐに使って作業できるようにすることです。パート1の説明をもとに、あなたも自分のリストをつくってみることをお勧めします。
  • すでにパート1をお読みであれば、JSONシンタックスを読みやすくするためのフォーマットや、WAAPIの引数やreturn値の調べ方など、便利な使い方について分かったと思います。それでも、このブログを読むと同時にオンラインのドキュメントも確認すると良いでしょう。
  • 初心者にも分かりやすいように、各行にコメントを追加して細かく説明するようにしました。
  • 分からないことがあれば、まず調べてみてください。Wwiseの各種ドキュメントやGoogleサーチは想像以上にパワフルですよ。
  • WAAPIの機能は随時更新されるので、Wwiseの最新バージョンをインストールするようにしてください。もしエラーで “The procedure URI is unknown.” と出た場合は、そのAPIはWAAPIの現行バージョンでサポートされていないことを意味します。

目次:

TableOfContent_1



Wwise.coreの概要

1
WAAPIにとって不可欠なwwise.core APIですが、これは非常に強力です。wwise.coreとsoundengine以外の、残りのexecution APIは比較的シンプルです。今回は、wwise.coreに関するブログです。
上図マインドマップから、これらのAPIは主にWwiseで行うオーディオデザイン用であって、サウンドエンジンの設定ではないことが分かります。Wwiseを使った作業を最適化したいと思っている方には、お役に立つ内容だと思います。

WAAPIにとって不可欠なwwise.core APIですが、これは非常に強力です。wwise.coreとsoundengine以外の、残りのexecution APIは比較的シンプルです。今回は、wwise.coreに関するブログです。
上図マインドマップから、これらのAPIは主にWwiseで行うオーディオデザイン用であって、サウンドエンジンの設定ではないことが分かります。Wwiseを使った作業を最適化したいと思っている方には、お役に立つ内容だと思います。

注: 図中に取り消し線があれば、新しいAPIに変わったということです。

audio(AudioファイルをインポートしてWwiseオブジェクトを作成)

機能

audioというブランチの下にあるのが、importとimportTabDelimitedの2つのAPIです。その名の通り、アセットをインポートする時に使います。前者は、単純にオーディオファイルをインポートしてWwiseオブジェクトを作成するものです。後者を使うと、タブ区切りファイルに指定したルールに基づいてオーディオファイルをインポートし、特定の操作を実行できます。

importTabDelimitedは、事前に定義された情報をタブ区切りテキストファイルからインポートします。オーディオファイルのローカルディレクトリ、それらオブジェクトが入っている様々なWwise階層(コンテナ、Event、Output Bus)、プロパティ値への参照の仕方、Switchを使って子エレメントをアサインする方法などが、この情報に入っています。

テキストファイルは、Microsoft Excelなどの表計算アプリケーションで生成できます。最初の行で、各列のヘッダーが指定するプロパティを定義します。各列で、Wwiseプロジェクトで何を作成するのかを決めます。

使用方法

当然、アセットをインポートする上で一番大事なブランチがaudioがです。手作業で大量のファイルをインポートするときに、これらのAPIが、同じことを繰り返し行う手順を排除してくれます。適切な情報を指定しておけば、階層やプロパティやストリームなどを自動的に設定してくれます。

オーディオファイルのインポートにimportを使うときに、ファイル名でディレクトリやプロパティを指定する必要があります。そのために、ファイル名で示された保存先をマッピングするディクショナリを作成して、長いファイル名などによるエラーの可能性を減らすようにしてください。

オペレーティングシステムには、ファイル名やパスの長さの制限があります。厳密には、Wwiseのファイル名は256文字以下とします。これ以上だとインポート操作が失敗する可能性があります。システムパスを考慮すると、ユーザーが使える文字数は通常、限られます。

その場合、importTabDelimitedを使って、具体的なルールが指定されているタブ区切りテキストファイルからオーディオファイルをインポートできます。実はこの処理を、さらに最適化できます。例えばサウンドデザイナーが、VBAでシンプルなアプリを構築してExcelでタブ区切りファイルを素早く生成したり、Pythonで複雑なGUIアプリを構築してこれらのファイルを直接作成したりできます。

audioSourcePeaks(ピーク値の取得)

機能

このブランチの下には、getMinMaxPeaksInRegionと、getMinMaxPeaksInTrimmedRegionの、2つのAPIがあります。ピーク値を取得し、特定情報を返すために使います。前者が、オーディオソースの指定された範囲のピーク値を取得します。後者が、オーディオソースのトリムされた範囲全体のピーク値を取得します。なお、ここで取得するのはMax Peakだけではなく、numPeaks引数によって指定されたMin/Max Peakのペアです。

getMinMaxPeaksInRegionには、timeFromと、timeToの2つの引数があります。これらで、オーディオソースの中でピークが必要な部分の開始時間と終了時間が決まります。getMinMaxPeaksInTrimmedRegionの場合は開始時間と終了時間を指定する必要がなく、SFXオブジェクトがトリムされたあとの値が検証されます。

どちらのAPIもbase-64でエンコードされた16-bit符号付き整数配列を返します。それをデコードして、指定のフォーマット(fmt)でパースして、dB値に変換します。

使用方法

私はWwiseプラグインの開発経験が浅いです。知っている限り、1つのオーディオソースから、それほどたくさんのMin/Max Peak値を取らなくてもいいはずです。ただ、もし必要であれば、これら2つのAPIを使って、各種チャンネルのグローバルなピーク値を計算できます。そのような値を、最大14294967295個も提供してくれます。

Object(オブジェクトの操作)

機能

Create、copy、delete、move(基本的なObject操作)最も基本的なobject操作を実行するのに、この4つのAPIを使います。object name、type、source path、target pathなどを定義する引数が入っています。

Createで、Wwise Objects Referenceドキュメントに記載されている膨大なオブジェクトを作成できます。一方、importやimportTabDelimitedでは、オーディオ関連のオブジェクトしか作成できません(コンテナ、Eventなど)。

createで作成できるのは、Sound SFXオブジェクト、Work Unit、コンテナ、さらにエフェクトやソースプラグインなどです。

setReference、setRandomizer、setAttenuationCurve、setName、setNotes、setProperty(オブジェクトプロパティの設定)

Createで設定できるオブジェクトプロパティは限られています(notesなど)。ほかのオブジェクトプロパティを設定するには、上記APIを使います。

setReferenceはオブジェクトのリファレンス値を設定します。例えば、Sound SFXオブジェクトのOutput Busへのリファレンスを設定できます。

そしてsetRandomizer、setAttenuationCurve、setName、setNotesは、それぞれの名前の通りの設定(set)を行います。

setProperty は、特定のプラットフォームのオブジェクトのプロパティ値を設定します。オブジェクトタイプ別に設定できるプロパティを詳しく知るには、Wwise Objects Referenceドキュメントを確認してください。

例えば、Mastering Suite内のプロパティを設定するには、GUIDやパスなど、場所が分かる情報を提供し、その"property"キー値を、変更したいプロパティ名に変更し、最後に、置き換える適切な値を指定するだけです。

get、getTypes、getPropertyInfo、getAttenuationCurve、getPropertyAndReferenceNames(オブジェクトプロパティの取得)

今のプロジェクトの情報が欲しいときは、上記APIが応えてくれます。Getはクエリに基づくAPIです。ID、名前、サイズ、パス、長さなどの情報を返してくれます。何かが欲しいときは、適切なクエリパラメータを設定すればいいのです。パート1でも触れた通り、両方の表(Arguments、Options)の引数を渡せば、あなたがOptions表で選択した内容に基づいたreturn結果が得られます。

では、この2つの違いは?

Arguments表にある2つの引数は、from、そしてtransformです。

  1. Fromが示すのは、あなたのクエリ用のデータソースです。オブジェクトを検索するために、名前、GUID、パス、タイプなどが使えます。また、サブ引数としてofTypeやsearchなどを指定して、オブジェクトの範囲にフィルタを適用することもできます。
  2. Transformは、選択したオブジェクトを変えるために使います。例えばfromを使ってRandom Containerを設定し、transformでselect parentを追加したとします。そうすると、親オブジェクトの方が代わりに選択されます。つまり、transformはfromを補助する重要な役割を担います。何から設定をしたのかによって、サーチ対象を親、子、またはリファレンスとすることができます。


Options表には、returnと、platformの、2つの引数もあります。(注: これらの引数は、空欄のままにしておけます。)

1. Returnで、クエリが終わった後にどのような結果が出るのかを指定できます。空欄のままにすると、オブジェクトのGUIDと名前が返されます。
2. Platformはクエリ対象のプラットフォームを指定します。空欄のままにすると、デフォルトのプラットフォームに対してクエリを行います。

さて、getTypes、getPropertyInfo、getAttenuationCurve、getPropertyAndReferenceNamesが必要な理由は?

実は、これらのAPIは目的によって設計が異なるのです。getは、オブジェクトの一般的なプロパティを取得しようと、そのオブジェクトをクエリします。ほかの4つは、メタプロパティを取得します。getTypesは現在登録中の全てのオブジェクトのタイプを返し、getPropertyInfoはオブジェクトのプロパティの具体的な情報(設定値の範囲など)を返し、getAttenuationCurveは指定したオブジェクトのAttenuation Curve設定を返し、getPropertyAndReferenceNamesはオブジェクトのプロパティや現在のリファレンス名を返します。

使用方法

これらのAPIは、様々な状況で使えます。例えばオーディオファイルの変換後のサイズを取得したり、オブジェクトのプロパティやリファレンス名を取得したり、プロジェクトの全プラットフォームや使用中の全Output Busをクエリしたりできます。WwiseのQueriesタブに慣れていた方が簡単です。

GetInfo、log.get (プロジェクト情報やログの取得)

機能

この2つのAPIは、単純に特定の情報を取得するのに使用します。getInfoは、Wwiseのバージョン、プラットフォーム情報、WAAPIのバージョンなど、現在のプロジェクトに関するグローバル情報を返し、log.getは最新のログを返します。実際、Logsウィンドウのタブは、ここのチャネル引数にリンクしています。自分のアプリ内で動的にログを更新したい場合は、特定のサブスクリプション API が役に立ちます。(これについては後ほど説明。)例えばak.wwise.core.log.itemAdded。このAPIは、オブジェクトが追加されたときに情報を返します。

使用方法

必要に応じて、この2つのAPIを使います。例えば、log.getを使って、特定の操作を実行した後にログを毎回データベースに保存したり、よりカスタマイズされたフィードバックを得るために、細かい分析を実行したりできます。

Profiler(Profiler操作)

機能

startCapture、stopCapture (キャプチャのオン・オフ)

この2つのAPIは、引数を設定せずにProfiler Captureプロセスの開始と停止を行うためのものです。

getBusses、getCursorTime、getRTPCs、getVoiceContributions、getVoices (プロファイラーキャプチャーの具体的な時間の情報を取得)

getBusses、getRTPCs、そしてgetVoicesは、似ています。時間値を渡して、バスゲイン、RTPC ID、RTPC値、ボイスなどの特定情報を得るものです。

getCursorTimeは、指定されたプロファイラカーソルの現在の時間を、ミリ秒単位で返します。

getVoiceContributions は、ボイスのボリューム、ハイパス、ローパスなど、ドライパスに影響を与える全パラメータを返します。

なお、getBussesとgetVoicesは引数を2つ渡すことができ、2 番目の引数はクエリの範囲を定義します。

使用方法

手動制御や自動制御が可能なように、startCaptureとstopCaptureの機能を特定ツールに統合することができ、より複雑なキャプチャプロセスが可能になります。例えば、Unity WAAPIクライアントを使ってプロファイリング機能を追加し、キャプチャの開始と停止を制御すれば、詳しい分析をするためのプロファイリングデータを、必要に応じて取得することができます。

Project.save(プロジェクトの保存)

機能

このAPIは、現在のプロジェクトを保存するために使います。

使用方法

単にCtrl + Sの操作を置き換えるのではなく、パフォーマンスを犠牲にせず特定のトリガー条件に基づいてプロジェクトを自動的に保存します。例えば、一度に何万ものファイルをインポートするなど、バッチ処理を実行する場合に、100ファイルごと、あるいは10ファイルごとにでも、このAPIを呼び出すように設定すれば、潜在的なリスクを回避できます。

Remote(ゲームにリモート接続)

機能

Connect, disconnect(接続のオン・オフ切替)

これら2つのAPIを使って、リモートでゲームに接続したり、切断したりできます。その場合はホストIPとオプションのポートを提供する必要があります。だからこそ、下記のgetAvailableConsolesが必要です。様々なゲームエンジンに接続したい場合は、これを使って先に利用可能(available)なクライアントを取得できます。

getAvailableConsoles、getConnectionStatus(利用可能なコンソールの取得、接続ステータスの確認)

getAvailableConsolesは、Wwise AuthoringをSound Engineインスタンスに接続するために使える全てのコンソールを取得してから、エディタ名、IP、ポート、プラットフォームなどを返します。

getConnectionStatusで、現在の接続ステータスを確認できます。接続中のゲームエンジンだけが、自分のコンソール情報や接続ステータスを返します。

使用方法

接続・切断の機能は、『One Minute Wwise』で説明したようにゲームメニューに組み込むことができるので、ゲームで簡単に、接続や切断をクリックで操作できます。また、StreamDeckやMetagridのようなツールを使って、Pythonスクリプトを自動的にトリガーさせてリモート接続を有効化することができるので、手動操作に無駄に時間をかけずに済みます。

getAvailableConsolesとgetConnectionStatusを組み合わせて、Wwise Profilerのデータを自分のアプリに統合することができます(profilerに関するセクションを参照)。例えば、欲しい情報を自動的に取得したり、自分のアプリ内で現在の接続ステータスをユーザーに通知したりするだけでも、Wwise外のワークフローを改善できます。

Soundbank(SoundBankの生成と設定)

機能

Generateはその名の通り、SoundBankのリストを生成します。単純に全SoundBankを生成するだけでなく、特定のSoundBankやPlatformやLanguageをチェックしてから、Generate Selectedをクリックすることもできます。手作業で生成するのではなく、generateに任せることができます。

GetInclusionsは、SoundBankのinclusionリストを取得しますが、そこにはinclusionを追加するSoundBankのGUID、名前、またはパスが含まれます。

SetInclusionsは、SoundBankのinclusionリストに変更を加えます。SoundBankのinclusionリストで追加、削除、置き換えを行えます。

使用方法

SoundBankのinclusionリストを設定する前に、SoundBankを作成する必要があります。また、createを使ってSoundBankのオブジェクトや階層を作成できます。

まとめると、audioブランチのAPIはオーディオファイルをインポートしてオブジェクトを作成します。createブランチのAPIは階層やEventなどを作成して構築し、soundbankブランチのAPIはSoundBankを作成します。このワークフローを利用して、外部定義された構造ファイルを使い、アセット作成を自動化したり、soundbank経由でプロジェクトの内部構造をWwise外にあるアプリで確認したりできます。

SwitchContainer(Switch Containerの操作)

機能

前述の通り、createブランチのAPIでSwitch Containerなどのコンテナを作成できます。では、switchContainerは何のために必要か?

Switch ContainerがSwitch/State Groupにアサインされ、SwitchやStateにオブジェクトがアサインされていない限り、Switch Containerは機能しません。

アサインするのに使えるのが、switchContainerブランチのAPIです。

AddAssignmentは、Switch Containerの子をSwitchにアサインします。removeAssignmentは、Switch Containerの子とStateの間のアサインを、削除します。そのために必要なのは、Switch Container内のオブジェクトのGUIDと、Switch/State Group内のSwitchやStateのGUIDだけです。

GetAssignmentsは、Switch Containerの子とStateの間のアサインのリストを返します。

使用方法

switchContainerブランチのAPIは、作成したコンテナにSwitch要素をアサインすることで、自動化されたインポートのワークフローを補完してくれます。

Transport(Transport 制御)

機能

create、destroy、executeAction

createは、Wwiseオブジェクトのtransportオブジェクトを作成します。destroyは、transportオブジェクトを破壊します。createは、WwiseオブジェクトのGUIDの提供を必要とします。destroyは、transport objectのGUIDの提供を必要とします。

さて、transportオブジェクトとは?実は、既にWwiseを使った日常の作業で、この2つのアクションをいつも繰り返しているはずです。

例えば、Event Aを選択すると、Transport Controlでそれにフォーカスしたままになります。言い換えれば、Event A transportオブジェクトのできあがりです。Event Bを選択すると、EventAは破棄され、Event Bのtransportオブジェクトが作成されます。Transport ControlビューのPinアイコンをクリックすると、現在のtransportオブジェクトが維持され、ほかにtransportオブジェクトは作成されません。

Soundcaster Sessionは、実際はtransportオブジェクトを集めたものなのです。

executeActionは、あるtransportオブジェクトに対するアクションを実行します。可能性のあるアクション値は5つあり、それはplay、stop、pause、playStop、playDirectlyです。

getList, getState

getListは全transportオブジェクトのリストを返します。destroyで破壊されない限り、全てのトランスポートオブジェクトを見ることができます。

getStateは、transportオブジェクトのステートを取得します。executeActionでアクションを実行した後、このAPIでステートのクエリを行えます。

使用方法

transportブランチのAPIで、Wwise外にあるアプリの再生行動を定義できます。外部アプリとは、あなたのインテグレーションツールでも構いません。そこでWwiseプロジェクトのサウンドのプレビューを確認したり、Wwiseの外でSoundcaster Sessionを再現したりすることもできます。

undo (Undo)

機能

もしReaScriptをよく知っていれば、beginGroupとendGroupを、Undo_BeginBlock() とUndo_EndBlock() として考えることができます。beginGroupは、undoグループを開始させます。endGroupは、最後のundoグループを終了させます。beginGroupは繰り返し使えます。

cancelGroupは、最後のundoグループをキャンセルします。

使用方法

undoグループを使うと、一連のアクションを一度にまとめてキャンセルできます。論理上は、アクションのredoにも使えます。ただしWAAPIは、今のところundoにしか対応していません。今は、Wwise APIの今後のアップデートを待つことにしましょう。undoブランチのAPIのおかげで、Wwise外のアクションをキャンセルできる可能性が追加されました。

まとめ

習ったことは、練習しないと忘れてしまうものです。そこで、パート1の説明に基づいて、ご自分なりのリストをつくることを提案します。

WAAPIを活用できるように、実践すること:
1) マインドマップの有無にかかわらず、WAAPIの要点を自分でまとめてみます。
2) オープンに考えて、自分のオーディオデザインやインテグレーションワークフローで、どこが問題なのかを洗い出します。
3) 基本的なロジックを把握し、どのAPIを使うべきかを判断します。
4) 自分のアイディアを実現させるための、コードを書きます。

ユースケース

実際のWAAPIのユースケースを見てみましょう。これらのユースケースでは、本質的な機能の実装に焦点を当てています。ここでは、インタラクティブなデザインやGUIは、最大の関心事ではありません。これらのコードを参考にしながら、必要に応じて自分でコードを書いてください。私はここで、できるだけ多くのwwise.core APIを対象にしました。カバーできていないものは、是非ともこれから研究してみてください。

バグが報告された場合は、コードを再確認すれば問題を特定できるはずです。

シンプルにするために、私は各APIを関数にカプセル化しました。必要に応じて、Execution APIのセクション(パート1)で説明したサンプルコードを、変更してみてください。

MacOSでは、Wwiseのディレクトリ構造がWindowsと異なります。MacOSユーザーは、ファイルパスに気を付けてください。(Wwise Launcherで、PROJECTS > RECENT PROJECTS > show more >> を開きます。)

1. Sound SFXオブジェクトをインポートし、階層を構築し、プロパティを設定し、Eventを作成し、アクションタイプを設定します。次にSoundBankを作成し、新しく作成したEventを追加し、そのSoundBankを生成します。

Wwiseに素早くオーディオファイルをインポートし、適切な階層やEventも作成することで、オーディオインテグレーションの効率が大幅に改善されます。以下の例で、通常だと引数のファイルパス、プロパティ、階層などは手作業で入れていくものです。実は、このような繰り返しのタスクは、WAAPIで実行することもできるのです。

オーディオアセットをWwiseプロジェクトに素早くインポートするために、一定の命名規則や、データベースとのやり取りや、正規表現を有効活用して、まずメタデータを準備し、その後にお好みのプログラミング言語を使ってフォーマットされたファイルを、WAAPIインポートに必要なJSON引数に変換することができます。

APIの選択
1) ファイルのインポート:import
2) プロパティの設定: setProperty
3) Eventの作成、サウンドの追加、SoundBankの作成: create
4) inclusionの設定とSoundBankの生成:setInclusions、generate

コードを書く

# 1. ファイルのインポートと階層の構築
def file_import(file_path):
# ファイルをインポートする際の引数を定義します。import にはファイルパス
# と、オブジェクトタイプが定義されている保存先のパスが含まれます。
# 音声以外のSound SFXオブジェクトの場合、 importLanguageはSFXに設定し
# 音声以外のサウンドSFXオブジェクトの場合、 importLanguageはSFXに設定し、
# importOperation は useExisting に設定します。もし必要なコンテナが
# 既に存在すれば直接置き換えられ、なければ新規に作成します。
    args_import = {
        "importOperation""useExisting",
        "default": {
            "importLanguage""SFX"
        },
        "imports": [
            {
                "audioFile": file_path,
                "objectPath""\\Actor-Mixer Hierarchy\\Default Work Unit\\<Sequence Container>Test 0\\<Sound SFX>My SFX 0"
            }
        ]
    }
# return値の引数を定義します。この場合は
# GUIDとオブジェクト名を含むWindowsのみの情報を返します。
    opts = {
       "platform""Windows",
        "return": [
            "id""name"
        ]
    }
    return client.call("ak.wwise.core.audio.import", args_import, options=opts)

# 2. プロパティの設定
def set_property(object_guid):
# 変更したいオブジェクトのGUIDをターゲットオブジェクトに設定します。
# Volumeプロパティが変更されます。 対象プラットフォームはMacに設定します。
    #値が10に変更されます。 
    args_property = {
        "object": object_guid,
        "property""Volume",
        "platform""Windows",
        "value"10
    }
    client.call("ak.wwise.core.object.setProperty", args_property)

# 3. Sound SFXオブジェクトのEventを作成し、再生動作を定義します
def set_event():
    # Eventを作成し、再生動作を定義します
    args_new_event = {
# 保存先パス、タイプ、Event名、
        # 名前のコンフリクトにどう対応するのか、を定義します
        "parent""\\Events\\Default Work Unit",
        "type""Event",
        "name""Play_SFX",
        "onNameConflict""merge",
        "children": [
            {
# 再生時の動作を定義します。nameは空欄のままです。@ActionType is 
                # 1に設定 (つまりPlay)。@Targetは、再生するサウンドオブジェクトに設定します
                "name""",
                "type""Action",
                "@ActionType"1,
                "@Target""\\Actor-Mixer Hierarchy\\Default Work Unit\\Test 0\\My SFX 0"
            }
        ]
    }
    return client.call("ak.wwise.core.object.create", args_new_event{)

# 4. SoundBankを作成し、そこにEventを追加します。
def set_soundbank():
# SoundBanks フォルダの下の Default Work Unit に SoundBank を作成します
    args_new_event = {
        "parent""\\SoundBanks\\Default Work Unit",
        "type""SoundBank",
        "name""Just_a_Bank",
        "onNameConflict""replace"
    }
# return値を取得します
    soundbank_info = client.call("ak.wwise.core.object.create", args_create_soundbank)

# 作成したサウンドバンクにイベントを追加します
    args_set_inclusion = {
        "soundbank""\\SoundBanks\\Default Work Unit\\Just_a_Bank",
        "operation""add",
        "inclusions": [
            {
# Just_a_Bank SoundBankにPlay_SFX Eventを追加し、その時にフィルタを使い
# return値を指定します。
                "object""\\Events\\Default Work Unit\\Play_SFX",
                "filter": [
                    "events",
                    "structures",
                    "media"
                ]
            }
        ]
    }

    return client.call("ak.wwise.core.soundbank.setInclusions", args_set_inclusion)

# 5. サウンドバンクの生成
def generate_soundbank():
# 生成するSoundBankを指定します。writeToDiskをTrueに設定します。
    args_generate_soundbank = {
        "soundbanks": [
            {
                "name""Ambient"
            }
        ],
        "writeToDisk"True
    }

    return client.call("ak.wwise.core.soundbank.generate", args_generate_soundbank)

2. 現在のプロジェクトのグローバル情報と、Sound SFXのサイズとSoundBankのパスを取得します。

APIの選択

  • グローバル情報の取得: getInfo
  • 変換されたサウンド SFX オブジェクトのサイズを取得する: get
  • SoundBankのパスを取得する: get

コードを書く

# 1. グローバル情報の取得
def get_global_info():
# getInfo でプロジェクト情報を取得します
    return client.call("ak.wwise.core.getInfo")

# 2. Sound SFXのサイズを取得する
def get_sfx_and_event_size(sound_sfx_guid):
# 引数にオブジェクトのGUIDを設定します。
    args = {
        "from": {
            "id": [
                sound_sfx_guid
            ]
        }
    }
# return値を設定します: オブジェクト名と変換後のサイズ
    opts = {
        "return": [
            "name""totalSize"
        ]
    }
    return client.call("ak.wwise.core.object.get", args, options=opts)

# 3. SoundBankのサイズを取得する
def get_soundbank_size(soundbank_guid):
    # 前のユースケースと同じ
    args = {
        "from": {
            "id": [
                soundbank_guid
            ]
        }
    }
    # プラットフォームをWindowsに設定します。 return値 (i.e. SoundBankパス)を設定します
    opts = {
        "platform" : "Windows",
        "return": [
            "soundbank:bnkFilePath"
        ]
    }
    # os.path.getsize() を使いSoundBankサイズを取得し、単位をMBに変換します。
# 注意: Macユーザーの場合は、パスの値をさらに処理する必要があります。
    path =  client.call("ak.wwise.core.object.get", args, options=opts)['return'][0]
    size = os.path.getsize(path) / (1024 ** 2)
    return size

3. Soundcaster Sessionを再作成し、再生動作を制御します。

Soundcasterには主に2つの目的があります。 1. 再利用のためにtransportオブジェクトのグループを保存すること(Soundcaster Session)。 2. 再生中のGame Sync、オブジェクトのプロパティ、M/Sなどを制御すること。

ここでは、Soundcaster Sessionの再現方法を考えます。

注:WAAPIのtransportオブジェクトは、Wwiseプロジェクトで保存できません。Soundcaster Sessionの機能を実装するには、セッションごとにGUIDを保存して、次回そのtransportオブジェクトを再作成できるようにします。

APIの選択

  • Transportの制御: transport

コードを書く

# 1. transportオブジェクトを作成します(Xはカスタマイズされた番号)。transportオブジェクトのGUIDは
# 作成後に返されます。シンプルにするために、Wwiseオブジェクト名と
# transportオブジェクトのGUIDを同じディクショナリに入れました。
from waapi import WaapiClient, CannotConnectToWaapiException

def transportX(object_guid):
    try:
        with WaapiClient() as client:
# 引数にtransportオブジェクトのGUIDを設定します。
            transport_args = {
                "object": object_guid
            }

# transportオブジェクトのIDをディクショナリフォーマットで返します。
# 例えば、{'transport'.12}
            result_transport_id = client.call("ak.wwise.core.transport.create", transport_args)

# id を object_guid に設定します。ak.wwise.core.object.getを使ってWwiseの
            # オブジェクト名を取得します。Wwiseオブジェクト名を使って
            # transportオブジェクトを作成できるはずです。
            args = {
                "from": {
                    "id": [
                        object_guid
                    ]
                }
            }

            opts = {
                "return": [
                    "name"
                ]
            }

# リモートコールをかけます。Wwiseオブジェクト名をディクショナリフォーマットで返します。
            # 例えば {'name’: 'MyObjectName'}
            result_dict_name = client.call("ak.wwise.core.object.get", args, options=opts)['return'][0]

# Wwiseオブジェクトの名前とtransportオブジェクトのIDをマージします。すると
            # ディクショナリフォーマットのTransport Sessionを取得します。
# 例えば、{'name': 'MyObjectName', 'transport'.1234}
            return result_dict_name.update(result_transport_id)

    except CannotConnectToWaapiException:
        print("Could not connect to Waapi: Is Wwise running and Wwise Authoring API enabled?" )

# 複数のtransportオブジェクトを取得したら、それらの情報をリストに入れます。すると
# シンプルなSoundcaster Sessionを取得できます。
# env_session = [{'name': 'MyObjectName1', 'transport': 1234}, 
# {'name': 'MyObjectName2', 'transport': 12345}]

# 2. Transport SessionからtransportオブジェクトのIDを取得します。

def get_transport_args(env_session, object_name, play_state):
    # セッションリスト (env_session)を確認します。transport_dictディクショナリを
    # 提示されたオブジェクト名(object_name)用のものを取得します。 
    for i in env_session:
        if i['name'] == object_name:
            transport_dict = i

# transport_dictからtransportオブジェクトのIDを取得します。必要な引数を
    # 渡します。
    transport_id = {'transport': transport_dict[transport]}
    args = {"action": play_state}
    return args.update(transport_id)

# 3. セッションリスト、オブジェクト名、再生動作を渡します。リモートコールを 
# executeActionに対してして、再生動作を制御します。
from waapi import WaapiClient, CannotConnectToWaapiException

try:
    with WaapiClient() as client:
        args = get_transport_args(env_session, object_name, play_state)
        client.call("ak.wwise.core.transport.executeAction", args)

except CannotConnectToWaapiException:
    print("Could not connect to Waapi: Is Wwise running and Wwise Authoring API enabled?" )

4. Profilerデータをキャプチャしてレポートを作成します。

APIの選択

  • キャプチャのオン・オフ: startCapture, stopCapture
  • データの取得: getBusses、getCursorTime、getRTPCs、getVoiceContributions、getVoices

コードを書く

# 1. プロファイラデータのキャプチャを開始します。start timeを返します。
def start_capture():
    return client.call("ak.wwise.core.profiler.startCapture")

# 2. キャプチャを停止します。stop timeを返します。
def stop_capture():
    return client.call("ak.wwise.core.profiler.startCapture")

# 3. キャプチャしたデータから情報を取得します。cursor_time 
# 値は、必ずstart_capture() と stop_capture() の間とします。
def capture_log_query(cursor_time):
# time pointを設定します
    args_times = {
        "time": cursor_time
    }

# 現在のボイスの名前とステート(フィジカルまたはバーチャル)を取得し
    # 相対的なゲームオブジェクト名とIDを取得します
    opts_get_voices = {
        "return": [
            "objectName""isVirtual""gameObjectName""gameObjectID"
        ]
    }

# アクティブバスを取得します
    opts_get_busses = {
        "return": [
            "objectName"
        ]
    }

# アクティブRTPCのIDと値を取得します
    log_rtpcs = client.call("ak.wwise.core.profiler.getRTPCs", args_times)["return"]
    # 上記説明を確認します
    log_voices = client.call("ak.wwise.core.profiler.getVoices", args_times, options=opts_get_voices)["return"]
    log_busses = client.call("ak.wwise.core.profiler.getBusses", args_times, options=opts_get_busses)["return"]

次回は?

パート3では、wwise.ui、wwise.waapi、wwise.debug、soundengineなど、残りのExecution APIを取り上げます。

トーマス・ワン(汪洋)

フリーランスオーディオ / ゲームサウンドデザイナー

トーマス・ワン(汪洋)

フリーランスオーディオ / ゲームサウンドデザイナー

現在、テクニカルオーディオリサーチを専門とし、ゲームオーディオワークフローの最適化、ミドルウェアのインテグレーション、オーディオプログラミングなどを手がける。

 @zcyh_147

コメント

Replyを残す

メールアドレスが公開されることはありません。

ほかの記事

Monument Valley 2の美しいサウンドの制作現場: トッド・ベイカー氏インタビュー

このインタビューは、 A Sound Effectに最初に掲載されました。 Monument Valley 2でUstwo...

10.4.2018 - 作者 アン・ソフィー・モンジョウ(ANNE-SOPHIE MONGEAU)

WAAPIをよりシンプルに

この記事を読み終える頃には、Wwise Authoring API (WAAPI) を使ったことがない方々も興味がわいてくるはずです。...

24.7.2018 - 作者 アダム・T・クロフト(ADAM T. CROFT)

Total War: WARHAMMER 2: 音楽構成を決め、音楽システムを活用するまで

Total Warシリーズのビデオゲームを知らない読者のために説明すると、Total...

2.7.2019 - 作者 _CREATIVE ASSEMBLY_

理想の仕事: ゲームオーディオにおける「倫理的な雇用」という考え方

3.9.2019 - 作者 ゴードン・マクグラデリー(Gordon McGladdery)

アンビソニックスで、ダイナミックなアンビエンスを実現

アンビソニックスを回転...

16.6.2020 - 作者 ルイス・ハビエル・ブッフォーニ(Louis-Xavier Buffoni)

WwiseでMidiのマジックを使う 『New Super Lucky's Tale』のFoxberry Timer

親愛なるWwiseユーザーの皆さん、こんにちは。

8.2.2021 - 作者 アーロン・ブラウン(AARON BROWN)

ほかの記事

Monument Valley 2の美しいサウンドの制作現場: トッド・ベイカー氏インタビュー

このインタビューは、 A Sound Effectに最初に掲載されました。 Monument Valley 2でUstwo...

WAAPIをよりシンプルに

この記事を読み終える頃には、Wwise Authoring API (WAAPI) を使ったことがない方々も興味がわいてくるはずです。...

Total War: WARHAMMER 2: 音楽構成を決め、音楽システムを活用するまで

Total Warシリーズのビデオゲームを知らない読者のために説明すると、Total...