あまり知られていない機能ですが、ReaWwiseはカスタムReaScriptsで使える生のWAAPI関数をREAPERに公開します。このブログ記事ではReaScript開発環境の中でWAAPIを使い、基本的なWwise関連の機能を実装する方法について考えます。
前提条件
WAAPIとLua
先にすすむ前に、WAAPI、Lua、ReaScriptの基本を理解しておくことが大切です。以下は勉強するためにおすすめのリソースです:
ReaWwise
WAAPIコマンドをReaScript内から実行するためには、 ReaWwiseをインストールする 必要があります。
はじめてみよう
ReaScript開発環境
ReaScript開発環境を使うためにはREAPERを開きます。REAPERメニューで Actions > Show action list を選択します。Actions ダイアログ右下の New action > New ReaScript をクリックします。この時点でファイルの保存を促すプロンプトが表示されます。ReaScriptファイルに名前を付け、 Save をクリックします。保存した後にReaScript開発環境が開きます。ここにコードを書いてゆきましょう。
Hello Wworld
-- Waapi Hello World.lua
if(reaper.AK_Waapi_Connect("127.0.0.1", 8080)) then
reaper.ShowConsoleMsg("Successfully connected to Wwise!")
reaper.AK_Waapi_Disconnect()
end
上記のコードスニペットでは、最初に AK_Waapi_Connect を呼び出しています。この関数がWAAPIとWwiseがやりとりをする IP と PORT を取り込みます。関数がブール値を返します。接続に成功した場合はtrueを、成功しなかった場合はfalseを返します。if文の終わりで AK_Waapi_Disconnect を呼び出して接続を終了させます。スクリプトの実行がうまくいくとREAPERコンソールの出力ウィンドウに以下のようなメッセージが出ます:
基本的な例(選択したオブジェクトの取得)
次の例はWwiseで選択中のオブジェクトのクエリに関するものです。
-- Get Selected Objects.lua
if(reaper.AK_Waapi_Connect("127.0.0.1", 8080)) then
local fieldsToReturn = reaper.AK_AkJson_Array()
reaper.AK_AkJson_Array_Add(fieldsToReturn, reaper.AK_AkVariant_String("path"))
local options = reaper.AK_AkJson_Map()
reaper.AK_AkJson_Map_Set(options, "return", fieldsToReturn)
local result = reaper.AK_Waapi_Call("ak.wwise.ui.getSelectedObjects",
reaper.AK_AkJson_Map(), options)
local status = reaper.AK_AkJson_GetStatus(result)
if(status) then
local objects = reaper.AK_AkJson_Map_Get(result, "objects")
local numObjects = reaper.AK_AkJson_Array_Size(objects)
for i=0, numObjects - 1 do
local item = reaper.AK_AkJson_Array_Get(objects, i)
local path = reaper.AK_AkJson_Map_Get(item, "path")
local pathStr = reaper.AK_AkVariant_GetString(path)
reaper.ShowConsoleMsg(pathStr .. "\n")
end
end
reaper.AK_AkJson_ClearAll()
reaper.AK_Waapi_Disconnect()
end
AkJson
JSONオブジェクトを作成しやすくするために、ReaWwiseがさまざまなヘルパー関数をエクスポートします。これらを使い、ReaScriptがスクリプターのニーズに基づいてダイナミックにJSONオブジェクトを作成します。
WAAPIを呼び出すためには 引数 、 オプション 、 コマンド文字列 の3つの要素が必要です。この例のコマンドストリングは ak.wwise.ui.getSelectedObjects です。WAAPIリファレンス にすべてのWAAPIコマンドの一覧があります。
WAAPIはこの特定コマンド用の引数として、空のマップを想定しています。私たちはオプションズマップを設定するだけです。
私たちが作成しようとしているオプションズマップは以下のようなものです:
{
"return": [
"path"
]
}
REAPERのLuaコンテキストとReaWwiseのバックエンドの間で渡すことができるのは、値タイプとポインタに限られているため、オプションズマップの作成はいくつかのステップに分かれます。
最初に、以下のように fieldsToReturn 配列を作成します。
local fieldsToReturn = reaper.AK_AkJson_Array()
fieldsToReturn 変数の中で返されるのが、ReaWwiseバックエンドの配列へのポインタです。このポインタを使い配列に対して操作を行うことができます。
次に、以下のように"path"文字列をfieldsToReturnの要素として追加します:
reaper.AK_AkJson_Array_Add(fieldsToReturn, reaper
.AK_AkVariant_String("path"))
最後に、以下のようにオプションズマップを作成し、キー"return"を持つ値としてfieldsToReturn配列を追加します:
local options = reaper.AK_AkJson_Map()
reaper.AK_AkJson_Map_Set(options, "return", fieldsToReturn)
WAAPIの呼び出し
必要なパラメータをすべて作成した後は、以下のようにWAAPIへの呼び出しの入力として使用します。
local result = reaper.AK_Waapi_Call("ak.wwise.ui.getSelectedObjects",
reaper.AK_AkJson_Map(), options)
結果を検証してWAAPIの呼び出しが成功したかどうかを確認します。複雑なデータ構造をReaWwiseバックエンドからLuaコンテキストに直接渡すことができないことを、忘れないでください。結果の変数がポインタです。
以下のようにステータスをクエリできます:
local status = reaper.AK_AkJson_GetStatus(result)
ステータスがtrueであれば、続けて以下のようにWAAPIの呼び出しで返された実際のデータをクエリします:
local objects = reaper.AK_AkJson_Map_Get(result, "objects")
local numObjects = reaper.AK_AkJson_Array_Size(objects)
次に、以下のようにnumObjectsの範囲でイテレーションを行い、必要なデータを抽出します:
for i=0, numObjects - 1 do
...
end
各オブジェクトがマップとして表されます。オブジェクトの特定の属性にアクセスするためには、ReaWwiseバックエンドが提供するヘルパー関数を使います。
オブジェクト配列から1つのオブジェクトを取得するためには、以下のようにオブジェクトポインタとインデックス値を使用します:
local item = reaper.AK_AkJson_Array_Get(objects, i)
変数 item は objects 配列にある1つのオブジェクトを表すマップオブジェクトへのポインタです。以下のように path 変数を抽出します:
local path = reaper.AK_AkJson_Map_Get(item, "path")
マップや配列値はvariantオブジェクトとして内部に保存されます。最終値を抽出するためには、値が何のデータを表しているのかを知る必要があります。今回は文字列を取得できることが分かっています。以下のヘルパー関数を使いvariantデータタイプから文字列を取得します:
local pathStr = reaper.AK_AkVariant_GetString(path)
変数 pathStr はスクリプトの残りの部分でこのまま使用できる通常のLua文字列です。このスクリプトは、pathStr をREAPERコンソールに出力するだけです。
reaper.ShowConsoleMsg(pathStr .. "\n")
ReaWwiseバックエンドは終始Luaコードで使用されているリファレンスタイプのオブジェクトを追跡する必要があるため、不要となった場合は以下のようにクリアすることが重要です:
reaper.AK_AkJson_ClearAll()
Advanced Example (Import)
次の例ではもう少し複雑なことを試みます。オーディオファイルをREAPERのレンダーディレクトリからWwiseに転送します。各オーディオファイルを、スクリプトでハードコードしたインポート先にサウンドSFXとしてインポートします。基盤として使用するWAAPIコマンドは ak.wwise.core.audio.import です。
この例のAPIに関連するコンセプトの大半は最初の例で説明済みのため、コードを1行ずつ説明することはしません。その代わりにコードの各セクションで何を行っているのかを大まかに説明します。
行3-13: WAAPIに接続し、importDestinationを設定し、レンダーディレクトリを判断します。今回のスクリプトではレンダーディレクトリがプロジェクトファイルの親ディレクトリと同じであることを前提としています。
行15-41: AK_Waapi_Call関数に入力として渡すAkJson構造をすべて構築します。
行44-70:レンダーディレクトリのイテレーションを進め、WAVファイルに遭遇した場合は、インポートするオーディオファイル一覧にそれを追加します。
行74-101: AK_WAAPI_Call関数を実行してREAPERコンソールに結果を表示します。エラーが発生した場合に結果からエラー情報を抽出するロジックも、これらの行に含まれています。
まとめ
この記事ではWAAPIをLua ReaScriptで直接使う例をいくつか見てきました。Wwiseへの基本的な接続から、Wwiseのクエリ、そしてオーディオファイルのインポートというかなり複雑な処理に至るまでをご紹介しました。私たちはこのAPIがみなさんのワークフローにとって有意義となることを願っています。みなさんがWAAPIをReaScriptsでどのように使いこなすのか、見るのを楽しみにしています。
コメント