Wwise SDK 2024.1.0
|
Wwiseサウンドエンジン用にプラグインを開発すると可能性が広がりますが、状況が複雑になる場合もあります。 サンプルプラグイン セクションで提供されるサンプルと合わせて、以下のセクションにも目を通すことを強くお勧めします。提供されているサンプルはスタイルも構成も安定しているので、あなたの開発するプラグインの基礎として使えます。
プラグインは、カスタムのDSPルーチンを、サウンドエンジンが実行する全体的な信号処理チェーンに挿入することを可能にします。このプラグインパラメータは、オーサリングツール、またはRTPCを通じてゲーム内のいずれかで制御できます (リアルタイムパラメータコントロール(RTPC)を理解する を参照)。
各プラグインは二つのコンポーネントから成り立っています:
Tip: ランタイムコンポーネントに共通の静的ライブラリを生成する。こうすることで、ランタイムコンポーネントはゲームとプラグインユーザーインターフェースの両方によりリンクされます (プラグイン ユーザーインターフェースはWwiseが読み込むDLLです)。 |
パラメータ ノード インターフェースは、サウンドエンジンのRTPCマネージャーもしくはWwiseオーサリングツールからの変更に反応し、実行中に現行のプラグインインスタンスパラメータを取得するよう、実装される必要があります。( パラメータ ノード インターフェースの実装 を参照してください。)
サウンドエンジンに統合できるプラグインには三つの種類があります:
プラグインとこれらに関連するパラメータはサウンドエンジンが、プラグインの仕組みを介して作成します。この仕組みは、新しいパラメータのインスタンスとプラグインのインスタンスを返す、静的な生成する関数の利用が必要になります。次のコードは、これがどのように行われるかを示しています。この生成関数はこのライブラリユーザーが見ることができる AK::PluginRegistration 静的インスタンスにパッケージされる必要があります。class/type 1つにつき、1つの AK::PluginRegistration
クラスが必要です。
注釈: 作るプラグインの種類により、適切な AK::PluginRegistration 関数のAkPluginType 引数を設定します。たとえば、ソースプラグインのための AkPluginTypeSource、エフェクトプラグインのための AkPluginTypeEffect などです。 |
注釈: Registration オブジェクトの命名は重要です。これは、AK_STATIC_LINK_PLUGIN(pluginname) マクロで、"Registration" を pluginname の後に連結します。以下 Plug-in 静的登録 を参照してください。 |
あなたがプラグイン提供者で、プラグインが他のベンダーのプラグインと同じIDにならないようにしたい場合には、support@audiokinetic.com までお問い合わせください。予約された会社IDを取得できます。
オーディオプラグインの様々なインスタンスは、すべてPlug-in Managerが処理を行い、CompanyIDs ならびにPluginIDsの両方を使って、異なるプラグインクラスを認識します。プラグインは、ゲームで使用する前に、Plug-in Managerに登録する必要があります。登録処理で、PluginIDを引数として提供して、作成関数コールバックに結びつけます。
以下のサンプルコードは、ゲームがどのようにプラグインを登録するかを示しています。Audiokineticが提供するプラグインもまた、ゲームで使用する場合に登録する必要があります。
使い勝手を良くするために、すべてのプラグインは AK_STATIC_LINK_PLUGIN マクロのみを含むファクトリヘッダファイルが付いています。プラグイン管理を容易にするため、ファクトリヘッダには 「Factory」と連結するライブラリと同じように名前をつけてください。たとえば以下のコードは、MyPlugin.lib に関連す MyPluginFactory.h の内容です。
MyPlugin を使用しているゲームは、MyPluginFactory ファイルをインクルードして、MyPlugin.lib をリンクします。
注釈: 最後に_linkonceonlyが複数定義されているシンボルについてリンクエラーが出る場合には、複数の multiple CPP ファイルに含まれた Factory を含んでいることを意味します。これは、リンクユニット1つのつき1度だけ含むようにします(DLL、SO、DYLIB、EXE など)。 |
ゲームでプラグインを使用するには、静的ライブラリならびに動的ライブラリを介するという2つの方法があります。静的ライブラリの配布は必須です。動的ライブラリの配布はオプションですが、Wwise の Unity への統合には動的ライブラリを使用しているので、強く推奨します。しかし、Wwise Unreal インテグレーションは、静的ライブラリを使用する必要があります。
ライブラリから動的ライブラリを作成するのは非常に簡単です。Audiokinetic はこれをすべてのオフェクトプラグインで行っているので、 \SDK\samples\DynamicLibraries
フォルダーに多くの例を見つけることができます。要件は、
DEFINE_PLUGIN_REGISTER_HOOK
マクロを使用して、シンボルを定義します。EngineDllName
属性を特定しなかった場合には、XML と同じ名前をつけます。 1つの DLL に複数のプラグインをグループ化することができることに留意してください。つまり、静的ライブラリを動的ライブラリに変換するために必要なコードは、これだけです:
Unityでプラグインを実装するには、ライブラリのコピーを Wwise\Deployment\Plugins\[Platform]\DSP フォルダに置きます。そのフォルダのすべての DSP プラグインは、最適化された構成で、ゲームのリリースができる状態である必要があります。
注釈: iOSでは、ビルドシステムが動的ライブラリの使用を阻止します。従って、Unity では、.a ファイルと対応する Factory.h ファイルの両方を実装する必要があります。他のプラットフォーム上での動的ライブラリと iOS 上の静的ライブラリの使用の間をリンクします。DLL 名は lib 名 (またはサブストリング) と同じ名前を "lib" プレフィックスなしでつけるようにしてください。 例:
|
注釈: Macでは、Wwise は dylib ファイルのみを読み込みます。しかし、Unity は DYLIB を有効な拡張子として認識しません。従って、ゲームを構築する際、これらのファイルをコピーならびに実装しません。この問題を回避するためには、ファイル自体が BUNDLEでなくても、拡張子を "BUNDLE"に変更します。 例:
|
注釈: Android では、libMyPlugin.so のように、ダイナミックライブラリの最初に「lib」をつける必要があります。 |
Unlike statically linked plug-ins, dynamically linked plug-ins are loaded on demand. The Init bank contains a list of plug-in IDs that the project uses. When the Init bank is being loaded, the Sound Engine searches this list for unrecognized plug-in IDs. An attempt to load the dynamic library that contains the plug-in is made for each of these unrecognized plug-ins.
For the attempt to succeed, the plug-in library file must be placed in a location that the operating system's dynamic library loader searches. Library search paths vary from system to system. On several platforms, the directory containing the game executable is part of the library search paths.
Alternatively, set AkInitSettings::szPluginDLLPath
to the local system path that contains the plug-in library files. This path takes precedence over the operating system's library search paths. Refer to the IntegrationDemo sample code for the recommended AkInitSettings::szPluginDLLPath
setup method for various platforms.
注釈: When using a game engine integration, AkInitSettings::szPluginDLLPath is managed automatically. Plug-in library files are automatically copied to the appropriate directory when Wwise is integrated into the game engine project. If you are using Unity, refer to Integrating Wwise into a Unity Project. If you are using Unreal Engine, refer to Integrating Wwise into an Unreal Engine Project. |
すべての動的なメモリ割り当てを実行するか、提供されたメモリ割り当てインターフェースを介してオーディオプラグイン内の割り当て解除をする必要があります。これにより、プラグインが消費ならびに解放するすべてのメモリをMemory Managerが追跡、これを特定のメモリカテゴリでマークし、Wwiseプロファイラーで表示します。
マクロは新規/削除演算子をオーバーロードするために提供され、提供されるメモリアロケータを使用してmalloc()/free() を呼び出します。これらのマクロは、IAkPluginMemAlloc.hに提供されています。
オブジェクトを割り当てるためには AK_PLUGIN_NEW() マクロを使用し、ポインターをメモリアロケータと希望するオブジェクトタイプに渡します。このマクロは、新規に割り当てたオブジェクトにポインターを返します。対応する AK_PLUGIN_DELETE() マクロを使用して、メモリを解放します。
配列を割り当てるには、AK_PLUGIN_ALLOC()を使用します。これは、Memory Managerから要求されたバイトでのサイズを得て、割り当てられたメモリアドレスにボイドポインターを返します。対応する AK_PLUGIN_FREE() マクロを使用して、割り当てたメモリを解放します。以下のサンプルコードでは、マクロの使い方を示しています。
パラメータ ノードは主に、パラメータの読み出し、書き込みアクセスを中央に集めます。プラグイン パラメータ インターフェースは次のメソッドで成り立っています:
このメソッドは、パラメータインスタンスの複製を作成し、必要な内部状態変数を調整して、新しいプラグインインスタンスと共に使用する準備をします。たとえば、イベントが新規再生インスタンスを作成すると、この状況が発生します。この関数は、AK_PLUGIN_NEW() マクロを使用して新規のパラメータ ノード インスタンスを返さなければなりません。多くの場合、構造体複製の呼び出しで十分です (以下のサンプルコードを参照)。パラメータ ノード内でメモリが割り当てられる場合には、ディープコピーを実施する必要があります。
この関数は、提供されたパラメータブロックでパラメータを初期化します。提供されたパラメータブロックのサイズが0の場合 (つまり、プラグインがオーサリング ツール内で使用された場合)、AK::IAkPluginParam::Init() はデフォルト値を使ってパラメータ構造体を初期化します。
Tip: AK::IAkPluginParam::SetParamsBlock() を呼び出して、有効な場合パラメータブロックを初期化します。 |
このメソッドは、Wwiseでバンクを作成した際、AK::Wwise::Plugin::AudioPlugin::GetBankParameters() を介して保存したパラメータブロックを使用して、一度にすべてのプラグインパラメータを設定します。このパラメータは、Wwise同等のプラグインでバンクに書き込んだのと同じ形式で読み出しをします。データはパック形式なので、変数はあるターゲットプラットフォームで要求されるデータタイプと揃わないことがあることに注意してください。AkBankReadHelpers.hで提供されるREADBANKDATAヘルパーマクロを使用して、これらのプラットフォーム特定の問題を回避します。データはアプリケーションによって適切にバイトスワットされているので、プラグインパラメータのエンディアンの問題について心配することはありません。
このメソッドは、単一のパラメータを一度にアップデートします。これは、パラメータ値がプラグインUI、RTPC、またはその他のいずれかで変更された際に必ず呼び出します。アップデートするパラメータはAkPluginParamIDタイプの引数で特定され、Wwise XML プラグインデスクリプションファイルで定義されたAudioEnginePropertyIDに対応します。(詳細は、Wwiseプラグイン XML 記述ファイル を参照してくださ。)
Tip: XMLファイルで定義された各AudioEngineParameterIDと、AkPluginParamsIDタイプの定数変数にバインドすることを推奨します。 |
注釈: RTPCパラメータをサポートするパラメータは、XMLファイルで特定したプロパティタイプが何であっても、タイプAkReal32を割り当てます。 |
注釈: もし complex properties を使うのであれば、 AK::IAkPluginParam::SetParam の中の AK::IAkPluginParam::ALL_PLUGIN_DATA_ID と、 AK::Wwise::Plugin::CustomData::GetPluginData を扱う必要があります。 これは、プラグインが最初に再生される時に、少なくとも一度だけ使用されます。 |
このメソッドは、パラメータ ノードが停止された時、サウンドエンジンが呼び出します。使用したすべてのメモリリソースが解放され、パラメータ ノードのインスタンスは自ら消滅します。
各プラグインは、パラメータ値を取得できるパラメータ ノードと関連し、これに従ってそのDSPを更新します。関連するパラメータ ノード インターフェースは、プラグインの初期化で受け渡され、プラグインが存続する限り有効のままになります。このプラグインは、DSP処理が要求する頻度で、パラメータ ノードから情報を問い合わせできます。プラグインとその関連するパラメータ ノードの間の一定方向のみの関係のため、パラメータ ノードが問い合わせるパラメータ値への応答は、作成者の判断に任されます (つまり、アクセサメソッドの使用)。
オーディオプラグインを開発するには、エンジンのオーディオデータフローの中でプラグインが適切に機能できるため、特定の関数を実装する必要があります。ソースプラグインには、AK::IAkSourcePluginインターフェースから生成する必要があり、入力バッファと出力バッファを置き換えることのできるエフェクトには (つまり、アンオーダード アクセス、またはデータレートの変更の必要はありません)、 AK::IAkInPlaceEffectPluginから生成する必要があります。きちっと整理されていない実行が必要な他のエフェクトは、AK::IAkOutOfPlaceEffectPlugin インターフェースから生成する必要があります。
A plug-in life cycle always begins with a call to one of the AK::IAkAudioDeviceEffectPlugin::Init(), AK::IAkEffectPlugin::Init(), AK::IAkSinkPluginBase::Init() or AK::IAkSourcePlugin::Init() functions, immediately followed by a call to AK::IAkPlugin::Reset(). プラグインが多くのデータ出力を必要とする限り、AK::IAkPlugin::Execute() が新しいバッファと共に呼び出されます。プラグインがもう必要でない場合には、AK::IAkPlugin::Term() を呼び出します。
このメソッドは、プラグインが停止した時に呼び出します。AK::IAkPlugin::Term() は、プラグインが使用したすべてのメモリリソースを解放し、プラグインインスタンスを削除しなければなりません。
リセットメソッドは、プラグインの状態を初期化し、新しい無関係のオーディオコンテンツ用意する準備をします。サウンドエンジンパイプランは、初期化のすぐ後およびオブジェクトの状態がリセットを必要とする場合にいつでも、AK::IAkPlugin::Reset() を呼び出します。通常はすべてのメモリ割り当てが初期化の段階で実施されますが、ディレイラインと例のサンプルカウントはAK::IAkPlugin::Reset()でクリアする必要があります。
このプラグイン情報問い合わせの仕組みは、サウンドエンジンがプラグインについての情報を必要とする場合に使用します。AkPluginInfo 構造体に正しい情報を入力して、実装されているプラグインのタイプを説明 (たとえば、ソースまたはエフェクト)、そのバッファ使用のスキーム (たとえば、in placeなど)、および処理モード (たとえば、同期など)。
注釈: エフェクトプラグインは、すべてのプラットフォームで同期である必要があります。 // Effect info query from sound engine.
AKRESULT CAkMyPlugin::GetPluginInfo( AkPluginInfo & out_rPluginInfo )
{
out_rPluginInfo.bIsAsynchronous = false; // Synchronous plug-in.
return AK_Success;
}
|
オーディオ データ バッファは、AkAudioBuffer構造体へのポインターを介して、実行時にプラグインに渡されます。プラグインに渡されるすべてのオーディオ バッファは、固定の形式を使用します。ソフトウェアエッフェクトをサポートするプラットフォームでは、オーディオ バッファのチャンネルはインターリーブされておらず、すべてのサンプルは、48 kHzサンプルレートで実行される、(-1.f,1.f)レンジで正規化された32ビット浮動小数点です。
AkAudioBuffer構造体は、 インターリーブならびにデインターリーブされたデータの両方にアクセスする方法を提供します。各チャンネルバッファ (AkAudioBuffer::uValidFrames) で有効な、いくつかのサンプルフレームを特定するフィールドと、それらのバッファが含むことのできる最大数のサンプルフレーム (AkAudioBuffer::MaxFrames()が返す)を含みます。
AkAudioBuffer構造体はまた、データに存在するチャンネルを定義するバッファチャンネルマスクを含みます。チャンネル数が必要な場合には、AkAudioBuffer::NumChannels()を使用します。
プラグインは、AkAudioBuffer::GetInterleavedData()を介してインターリーブしたデータのバッファにアクセスできます。ソースプラグインのみがインターリーブされたデータにアクセス、出力できます。これを行うには、初期化の間にサウンドエンジンを正しく準備する必要があります (AK::IAkSourcePlugin::Init() を参照)。サウンドエンジンは、データを適切にネイティブのパイプライン形式に変換するために、処理したDSPをインスタンス化します。
Tip: ソースプラグインが既ににサウンドエンジンのネイティブ形式であるデータを出力した場合、より良いパフォーマンスが得られます。 |
プラグインは、AkAudioBuffer::GetChannel()を介して個々のデインターリーブされたチャンネルにアクセスします。データタイプは常に、サウンドエンジンのネイティブ形式 (AkSampleType) に一致します。次のコード例は、処理のためにデインターリーブされたチャンネルを取得する方法を示しています。
注意: プラグインは、各チャンネルのバッファがメモリで隣接しているのが当然とみなしてはなりません。 |
オーディオを処理するチャンネルは、Front Left、Front Right、Center、Rear Left、Rear Right、LFEの順に並べられています。. 低周波チャンネル(LIFE)は常に 最後に配置されるため(ソースプラグインを除く)、別々に処理することができます。なぜなら、多くのDSPプロセッサが必要とするからです。 プラグインは、 AkAudioBuffer::HasLFE()
と共にオーディオバッファにLFEチャンネルが存在する場合に、問い合わせできます。AkAudioBuffer::GetLFE()
を 呼び出すことで、直接LFEチャンネルにアクセスできます。次のコードは、LFEチャンネルを別に扱う2つの異なる方法を示しています。
LFEにないチャンネルに特定の処理と適用したい場合には、AkCommonDefs.h のチャンネルインデックス定義を使用する必要があります。 たとえば、5.x 構成のセンターチャンネルのみを処理したい場合には、次のようにします:
Tip: チャンネルインデックス定義は、設定が N.0 または N.1のいずれのからも独立していることに注意してください。これは、LFE チャンネルは、Souce プラグインを除いて、常に最後にあるからです (チャンネル設定がLFEでない場合には、AK_IDX_SETUP_N_LFE は使用しません)。 |
注釈: ソースプラグインのインタリーブされたデータの7.1チャンネルの場合、チャネルの順序はL-R-C-LFE-BL-BR-SL-SRです。 |
プラグインは、 AK::IAkGlobalPluginContext::RegisterGlobalCallback()
を使ってさまざまなグローバル サウンド エンジン コールバックを登録します。たとえば、プラグインのクラスは、プラグインインスタンスが認識するシングルトンを介して、オーディオフレームごとに1度呼び出す必要があるかもしれません。また、サウンドエンジンの利用中ずっと残っているデータ構造初期化のグローバルフックを使用するかもしれません。
これを行うには、デフォルトの AK_IMPLEMENT_PLUGIN_FACTORY マクロを独自の実装に置き換えて、AK::PluginRegistrationの "RegisterCallback"を活用します。以下のコードの一部では、MyRegisterCallback を呼び出した静的コールバックがこの目的で定義されており、AK::PluginRegistration object MyPluginRegistrationに引き渡されています。
注釈: AK_IMPLEMENT_PLUGIN_FACTORY マクロは、引数として引き渡されるプラグイン名に文字列を追加して、ファクトリ関数と AK::PluginRegistration オブジェクトを宣言しています。以下の例では、AK_IMPLEMENT_PLUGIN_FACTORY は同じ命名法に従って再実装しれています。お使いのプラグインでは、"MyPlugin" を実際の名前に置き換えます。さらに、 AK_IMPLEMENT_PLUGIN_FACTORY の妹マクロ AK_STATIC_LINK_PLUGIN はも同じ命名法に従っています。AK_IMPLEMENT_PLUGIN_FACTORY の命名法から逸脱するには、合わせて AK_STATIC_LINK_PLUGIN も実装する必要があります。 |
注意: 以下の例に示す通り、プラグイン登録コールバックの中で AK::IAkGlobalPluginContext::RegisterGlobalCallback() をコールしても良いのは、 AkGlobalCallbackLocation::AkGlobalCallbackLocation_Register を受信したときだけで、 AK::IAkGlobalPluginContext::UnregisterGlobalCallback() をコールしても良いのは、 AkGlobalCallbackLocation::AkGlobalCallbackLocation_Term を受信したときだけです。 具体的には、複数のプラグインの処理中にデッドロックが発生するのを防ぐため、この関数をプラグインインスタンス(例 in Init 、 Execute など)の中からコールしないでください。 |
詳細については、以下のセクションを参照してください: