目次

Wwise SDK 2018.1.11
Wwise サウンドエンジン プラグインの作り方

Wwiseサウンドエンジン用にプラグインを開発すると可能性が広がりますが、状況が複雑になる場合もあります。 サンプルプラグイン セクションで提供されるサンプルと合わせて、以下のセクションにも目を通すことを強くお勧めします。提供されているサンプルはスタイルも構成も安定しているので、あなたの開発するプラグインの基礎として使えます。

Wwiseサウンドエンジン プラグインの概要

プラグインは、カスタムのDSPルーチンを、サウンドエンジンが実行する全体的な信号処理チェーンに挿入することを可能にします。このプラグインパラメータは、オーサリングツール、またはRTPCを通じてゲーム内のいずれかで制御できます (概念:リアルタイム パラメータコントロール (RTPC) を参照)。

各プラグインは二つのコンポーネントから成り立っています:

  • クロスプラットフォーム、または特定のプラットフォームに最適化して開発できる、サウンドエンジンに統合されたランタイムのコンポーネント。ゲームはこのプラグインと (Plug-in 静的登録 を参照) 、この実装に対するリンクを登録する必要があります。
  • オーサリングツールに統合された、ユーザーインターフェースコンポーネント。このコンポーネントは、Wwiseが読み込んだDLLにあります (Wwise プラグイン DLL の作成方法 を参照)。UIで設定したすべてのプラグインパラメータは、バンクに保存されるので、このコンポーネントはゲームで使用されません。パラメータを、RTPCを介してゲームで制御する場合には、必要な情報はまたバンクに保存されます。
Tip: ランタイムコンポーネントに共通の静的ライブラリを生成する。こうすることで、ランタイムコンポーネントはゲームとプラグインユーザーインターフェースの両方によりリンクされます (プラグイン ユーザーインターフェースはWwiseが読み込むDLLです)。

パラメータ ノード インターフェースは、サウンドエンジンのRTPCマネージャーもしくはWwiseオーサリングツールからの変更に反応し、実行中に現行のプラグインインスタンスパラメータを取得するよう、実装される必要があります。( パラメータ ノード インターフェースの実装 を参照してください。)

サウンドエンジンに統合できるプラグインには三つの種類があります:

プラグインとこれらに関連するパラメータはサウンドエンジンが、プラグインの仕組みを介して作成します。この仕組みは、新しいパラメータのインスタンスとプラグインのインスタンスを返す、静的な生成する関数の利用が必要になります。次のコードは、これがどのように行われるかを示しています。この生成関数はこのライブラリユーザーが見ることができる AK::PluginRegistration 静的インスタンスにパッケージされる必要があります。class/type 1つにつき、1つの AK::PluginRegistration クラスが必要です。

// Static parameter node creation function callback to be registered to the plug-in manager.
AK::IAkPluginParam * CreateMyPluginParams( AK::IAkPluginMemAlloc * in_pAllocator )
{
return AK_PLUGIN_NEW( in_pAllocator, CAkMyPluginParams() );
}
// Static plug-in creation function callback to be registered to the plug-in manager.
AK::IAkPlugin * CreateMyPlugin( AK::IAkPluginMemAlloc * in_pAllocator )
{
return AK_PLUGIN_NEW( in_pAllocator, CAkMyPlugin() );
}
//Static initializer object to automatically register the plug-in into the sound engine.
AK::PluginRegistration MyPluginRegistration(AkPluginTypeEffect, AKCOMPANYID_MYCOMPANY, EFFECTID_MYPLUGIN, CreateMyPlugin, CreateMyPluginParams);
Note: 作るプラグインの種類により、適切な AK::PluginRegistration 関数のAkPluginType 引数を設定します。たとえば、ソースプラグインのための AkPluginTypeSource、エフェクトプラグインのための AkPluginTypeEffect などです。AkPluginType 参照してください。
Note: Registration オブジェクトの命名は重要です。これは、AK_STATIC_LINK_PLUGIN(pluginname) マクロで、"Registration" を pluginname の後に連結します。以下 Plug-in 静的登録 を参照してください。

あなたがプラグイン提供者で、プラグインが他のベンダーのプラグインと同じIDにならないようにしたい場合には、support@audiokinetic.com までお問い合わせください。予約された会社IDを取得できます。

Plug-in 静的登録

オーディオプラグインの様々なインスタンスは、すべてPlug-in Managerが処理を行い、CompanyIDs ならびにPluginIDsの両方を使って、異なるプラグインクラスを認識します。プラグインは、ゲームで使用する前に、Plug-in Managerに登録する必要があります。登録処理で、PluginIDを引数として提供して、作成関数コールバックに結びつけます。

以下のサンプルコードは、ゲームがどのようにプラグインを登録するかを示しています。Audiokineticが提供するプラグインもまた、ゲームで使用する場合に登録する必要があります。

使い勝手を良くするために、すべてのプラグインは AK_STATIC_LINK_PLUGIN マクロのみを含むファクトリヘッダファイルが付いています。プラグイン管理を容易にするため、ファクトリヘッダには 「Factory」と連結するライブラリと同じように名前をつけてください。たとえば以下のコードは、MyPlugin.lib に関連す MyPluginFactory.h の内容です。

AK_STATIC_LINK_PLUGIN(MyPlugin); //This macro registers the plugin in the sound engine.

MyPlugin を使用しているゲームは、MyPluginFactory ファイルをインクルードして、MyPlugin.lib をリンクします。

#include <AK/Plugin/MyPluginFactory.h> // Factory headers forces linking of the plugin code through AK_STATIC_LINK_PLUGIN.
Note: 最後に_linkonceonlyが複数定義されているシンボルについてリンクエラーが出る場合には、複数の multiple CPP ファイルに含まれた Factory を含んでいることを意味します。これは、リンクユニット1つのつき1度だけ含むようにします(DLL、SO、DYLIB、EXE など)。

ダイナミックライブラリ

ゲームでプラグインを使用するには、静的ライブラリならびに動的ライブラリを介するという2つの方法があります。静的ライブラリの配布は必須です。動的ライブラリの配布はオプションですが、Wwise の Unity への統合には動的ライブラリを使用しているので、強く推奨します。しかし、Wwise Unreal インテグレーションは、スタティックライブラリを使用する必要があります。

ライブラリから動的ライブラリを作成するのは非常に簡単です。Audiokinetic はこれをすべてのオフェクトプラグインで行っているので、 \SDK\samples\DynamicLibraries フォルダーに多くの例を見つけることができます。要件は、

  • プロジェクトが構築した静的ライブラリにリンクしていること
  • AK_STATIC_LINK_PLUGIN への参照を直接、またはヘッダーファイルを介して1つ含むこと
  • お使いの動的ライブラリが、"g_pAKPluginList"シンボルを必ずエクスポートするようにします。ほとんどのプラットフォームは、エクスポート可能なように明示して定義しているので、自動的にエクスポートします。中には、明示したDEF ファイルが必要なプラットフォームもあります。DEFINE_PLUGIN_REGISTER_HOOK マクロを使用して、シンボルを定義します。
  • お使いの XML 宣言に従って、動的ライブラリに名前をつけてください。XMLで EngineDllName 属性を特定しなかった場合には、XML と同じ名前をつけます。 1つの DLL に複数のプラグインをグループ化することができることに留意してください。

つまり、静的ライブラリを動的ライブラリに変換するために必要なコードは、これだけです:

Unityでプラグインを実装するには、ライブラリのコピーを Wwise\Deployment\Plugins\[Platform]\DSP フォルダに置きます。そのフォルダのすべての DSP プラグインは、最適化された構成で、ゲームのリリースができる状態である必要があります。

Note: iOSでは、ビルドシステムが動的ライブラリの使用を阻止します。従って、Unity では、.a ファイルと対応する Factory.h ファイルの両方を実装する必要があります。他のプラットフォーム上での動的ライブラリと iOS 上の静的ライブラリの使用の間をリンクします。DLL 名は lib 名 (またはサブストリング) と同じ名前を "lib" プレフィックスなしでつけるようにしてください。 例:
  • Windows: MyPlugin.dll
  • iOS: libMyPlugin.a + MyPluginFactory.h
Note: Macでは、Wwise は dylib ファイルのみを読み込みます。しかし、Unity は DYLIB を有効な拡張子として認識しません。従って、ゲームを構築する際、これらのファイルをコピーならびに実装しません。この問題を回避するためには、ファイル自体が BUNDLEでなくても、拡張子を "BUNDLE"に変更します。 例:
  • Windows: MyPlugin.dll
  • Mac (非 Unity ゲーム): MyPlugin.dylib
  • Mac (Unity ゲーム): MyPlugin.bundle
Note: Android では、libMyPlugin.so のように、ダイナミックライブラリの最初に「lib」をつける必要があります。

Allocating/De-allocating オーディオプラグインにおけるメモリ

すべての動的なメモリ割り当てを実行するか、提供されたメモリ割り当てインターフェースを介してオーディオプラグイン内の割り当て解除をする必要があります。これにより、プラグインが消費ならびに解放するすべてのメモリをMemory Managerが追跡、これを特定のメモリプールから割り当てし、そしてWwiseプロファイラーで表示します。

マクロは新規/削除演算子をオーバーロードするために提供され、提供されるメモリアロケータを使用してmalloc()/free() を呼び出します。これらのマクロは、IAkPluginMemAlloc.hに提供されています。

オブジェクトを割り当てるためには AK_PLUGIN_NEW() マクロを使用し、ポインターをメモリアロケータと希望するオブジェクトタイプに渡します。このマクロは、新規に割り当てたオブジェクトにポインターを返します。対応する AK_PLUGIN_DELETE() マクロを使用して、メモリを解放します。

配列を割り当てるには、AK_PLUGIN_ALLOC()を使用します。これは、Memory Managerから要求されたバイトでのサイズを得て、割り当てられたメモリアドレスにボイドポインターを返します。対応する AK_PLUGIN_FREE() マクロを使用して、割り当てたメモリを解放します。以下のサンプルコードでは、マクロの使い方を示しています。

// Allocate single CAkMyObject
CAkMykObject * pSingleObject = AK_PLUGIN_NEW( in_pAllocator, CAkMyObject );
// Release pSingleObject
AK_PLUGIN_DELETE( in_pAllocator, pSingleObject );
// Allocate an array of uNumSamples audio samples
AkSampleType * pData = static_cast<AkSampleType *>( AK_PLUGIN_ALLOC( in_pAllocator, sizeof(AkSampleType) * uNumSamples) );
// Free array of audio samples
AK_PLUGIN_FREE( in_pAllocator, pData );

パラメータ ノード インターフェースの実装

パラメータ ノードは主に、パラメータの読み出し、書き込みアクセスを中央に集めます。プラグイン パラメータ インターフェースは次のメソッドで成り立っています:

AK::IAkPluginParam::Clone()

このメソッドは、パラメータインスタンスの複製を作成し、必要な内部状態変数を調整して、新しいプラグインインスタンスと共に使用する準備をします。たとえば、イベントが新規再生インスタンスを作成すると、この状況が発生します。この関数は、AK_PLUGIN_NEW() マクロを使用して新規のパラメータ ノード インスタンスを返さなければなりません。多くの場合、構造体複製の呼び出しで十分です (以下のサンプルコードを参照)。パラメータ ノード内でメモリが割り当てられる場合には、ディープコピーを実施する必要があります。

// Creating a shared parameters duplicate.
AK::IAkPluginParam * CAkMyPluginParams::Clone( AK::IAkPluginMemAlloc * in_pAllocator )
{
return AK_PLUGIN_NEW( in_pAllocator, CAkMyPluginParams(*this) );
}

AK::IAkPluginParam::Init()

この関数は、提供されたパラメータブロックでパラメータを初期化します。提供されたパラメータブロックのサイズが0の場合 (つまり、プラグインがオーサリング ツール内で使用された場合)、AK::IAkPluginParam::Init() はデフォルト値を使ってパラメータ構造体を初期化します。

Tip: AK::IAkPluginParam::SetParamsBlock() を呼び出して、有効な場合パラメータブロックを初期化します。
// Parameter node initialization.
AKRESULT CAkMyPluginParams::Init( AK::IAkPluginMemAlloc * in_pAllocator, void * in_pParamsBlock, AkUInt32 in_ulBlockSize )
{
if ( in_ulBlockSize == 0)
{
// Init with default values if we got an invalid parameter block.
return AK_Success;
}
return SetParamsBlock( in_pParamsBlock, in_ulBlockSize );
}

AK::IAkPluginParam::SetParamsBlock()

このメソッドは、Wwiseでバンクを作成した際、AK::Wwise::IAudioPlugin::GetBankParameters()を介して保存したパラメータブロックを使用して、一度にすべてのプラグインパラメータを設定します。このパラメータは、Wwise同等のプラグインでバンクに書き込んだのと同じ形式で読み出しをします。データはパック形式なので、変数はあるターゲットプラットフォームで要求されるデータタイプと揃わないことがあることに注意してください。AkBankReadHelpers.hで提供されるREADBANKDATAヘルパーマクロを使用して、これらのプラットフォーム特定の問題を回避します。データはアプリケーションによって適切にバイトスワットされているので、プラグインパラメータのエンディアンの問題について心配することはありません。

// Read and parse parameter block.
AKRESULT CAkMyPluginParams::SetParamsBlock( void * in_pParamsBlock, AkUInt32 in_uBlockSize )
{
// Read data in the order it was put in the bank
AKRESULT eResult = AK_Success;
AkUInt8 * pParamsBlock = (AkUInt8 *)in_pParamsBlock;
m_fFloatParam1 = READBANKDATA( AkReal32, pParamsBlock, in_ulBlockSize );
m_bBoolParam2 = READBANKDATA( bool, pParamsBlock, in_ulBlockSize );
CHECKBANKDATASIZE( in_ulBlockSize, eResult );
return eResult;
}

AK::IAkPluginParam::SetParam()

このメソッドは、単一のパラメータを一度にアップデートします。これは、パラメータ値がプラグインUI、RTPC、またはその他のいずれかで変更された際に必ず呼び出します。アップデートするパラメータはAkPluginParamIDタイプの引数で特定され、Wwise XML プラグインデスクリプションファイルで定義されたAudioEnginePropertyIDに対応します。(詳細は、Wwiseプラグイン XML 記述ファイル を参照してくださ。)

Tip: XMLファイルで定義された各AudioEngineParameterIDと、AkPluginParamsIDタイプの定数変数にバインドすることを推奨します。
Note: RTPCパラメータをサポートするパラメータは、XMLファイルで特定したプロパティタイプが何であっても、タイプAkReal32を割り当てます。
// Parameters IDs for Wwise or RTPCs.
static const AkPluginParamID AK_MYFLOATPARAM1_ID = 0;
static const AkPluginParamID AK_MYBOOLPARAM2_ID = 1;
AKRESULT CAkMyPluginParams::SetParam( AkPluginParamID in_ParamID, void * in_pValue, AkUInt32 in_uParamSize )
{
// Set parameter value.
switch ( in_ParamID )
{
case AK_MYFLOATPARAM1_ID:
m_fFloatParam1.fParam2 = *(AkReal32*)( in_pValue );
break;
case AK_MYBOOLPARAM2_ID:
m_bBoolParam2 = *(bool*)( in_pValue ); // Parameter does not support RTPC
or ...
// Note RTPC parameters are always of type float regardless of property type in XML plugin description
m_bBoolParam2 = (*(AkReal32*)(in_pValue)) != 0;
break;
default:
}
return AK_Success;
}

AK::IAkPluginParam::Term()

このメソッドは、パラメータ ノードが停止された時、サウンドエンジンが呼び出します。使用したすべてのメモリリソースが解放され、パラメータ ノードのインスタンスは自ら消滅します。

// Shared parameters termination.
{
AK_PLUGIN_DELETE( in_pAllocator, this );
return AK_Success;
}

Communication Between Parameter Nodes and Plug-ins.

各プラグインは、パラメータ値を取得できるパラメータ ノードと関連し、これに従ってそのDSPを更新します。関連するパラメータ ノード インターフェースは、プラグインの初期化で受け渡され、プラグインが存続する限り有効のままになります。このプラグインは、DSP処理が要求する頻度で、パラメータ ノードから情報を問い合わせできます。プラグインとその関連するパラメータ ノードの間の一定方向のみの関係のため、パラメータ ノードが問い合わせるパラメータ値への応答は、作成者の判断に任されます (つまり、アクセサメソッドの使用)。

オーディオプラグインインターフェースの実装

オーディオプラグインを開発するには、エンジンのオーディオデータフローの中でプラグインが適切に機能できるため、特定の関数を実装する必要があります。ソースプラグインには、AK::IAkSourcePluginインターフェースから生成する必要があり、入力バッファと出力バッファを置き換えることのできるエフェクトには (つまり、アンオーダード アクセス、またはデータレートの変更の必要はありません)、 AK::IAkInPlaceEffectPluginから生成する必要があります。きちっと整理されていない実行が必要な他のエフェクトは、AK::IAkOutOfPlaceEffectPlugin インターフェースから生成する必要があります。

プラグインのライフサイクルは、常にAK::IAkPlugin::Init() 関数の呼び出しから始まり、すぐその後にAK::IAkPlugin::Reset()の呼び出しに続きます。プラグインが多くのデータ出力を必要とする限り、AK::IAkPlugin::Execute() が新しいバッファと共に呼び出されます。プラグインがもう必要でない場合には、AK::IAkPlugin::Term() を呼び出します。

AK::IAkPlugin::Term()

このメソッドは、プラグインが停止した時に呼び出します。AK::IAkPlugin::Term() は、プラグインが使用したすべてのメモリリソースを解放し、プラグインインスタンスを削除しなければなりません。

{
if ( m_pMyDelayLine != NULL )
{
AK_PLUGIN_FREE( in_pAllocator, m_pMyDelayLine );
m_pMyDelayLine = NULL;
}
AK_PLUGIN_DELETE( in_pAllocator, this );
return AK_Success;
}

AK::IAkPlugin::Reset()

リセットメソッドは、プラグインの状態を初期化し、新しい無関係のオーディオコンテンツ用意する準備をします。サウンドエンジンパイプランは、初期化のすぐ後およびオブジェクトの状態がリセットを必要とする場合にいつでも、AK::IAkPlugin::Reset() を呼び出します。通常はすべてのメモリ割り当てが初期化の段階で実施されますが、ディレイラインと例のサンプルカウントはAK::IAkPlugin::Reset()でクリアする必要があります。

// Reset internal state of plug-in
{
// Reset delay line
if ( m_pMyDelayLine != NULL )
memset( m_pMyDelayLine, 0, m_uNumDelaySamples * sizeof(AkSampleType) );
return AK_Success;
}

AK::IAkPlugin::GetPluginInfo()

このプラグイン情報問い合わせの仕組みは、サウンドエンジンがプラグインについての情報を必要とする場合に使用します。AkPluginInfo 構造体に正しい情報を入力して、実装されているプラグインのタイプを説明 (たとえば、ソースまたはエフェクト)、そのバッファ使用のスキーム (たとえば、in placeなど)、および処理モード (たとえば、同期など)。

Note: エフェクトプラグインは、すべてのプラットフォームで同期である必要があります。

// Effect info query from sound engine.
AKRESULT CAkMyPlugin::GetPluginInfo( AkPluginInfo & out_rPluginInfo )
{
out_rPluginInfo.eType = AkPluginTypeSource; // Source plug-in.
out_rPluginInfo.bIsInPlace = true; // In-place plug-in.
out_rPluginInfo.bIsAsynchronous = false; // Synchronous plug-in.
return AK_Success;
}

AkAudioBuffer構造体を使用するデータにアクセスする

オーディオ データ バッファは、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) に一致します。次のコード例は、処理のためにデインターリーブされたチャンネルを取得する方法を示しています。

// Process all channels independently.
void CAkMyPlugin::Execute( AkAudioBuffer * io_pBuffer ) // Input/Output buffer (processing is done in place).
{
AkUInt32 uNumChannels = io_pBuffer->NumChannels();
for ( AkUInt32 uChan=0; uChan<uNumChannels; uChan++ )
{
AkSampleType * pChannel = io_pBuffer->GetChannel( uChan );
// Process data of pChannel...
}
}
Caution: プラグインは、各チャンネルのバッファがメモリで隣接しているのが当然とみなしてはなりません。

チェンネルの配列

オーディオを処理するチャンネルは、Front Left、Front Right、Center、Rear Left、Rear Right、LFEの順に並べられています。. 低周波チャンネル(LIFE)は常に 最後に配置されるため(ソースプラグインを除く)、別々に処理することができます。なぜなら、多くのDSPプロセッサが必要とするからです。 プラグインは、 AkAudioBuffer::HasLFE() と共にオーディオバッファにLFEチャンネルが存在する場合に、問い合わせできます。AkAudioBuffer::GetLFE() を 呼び出すことで、直接LFEチャンネルにアクセスできます。次のコードは、LFEチャンネルを別に扱う2つの異なる方法を示しています。

void CAkMyPlugin::Execute( AkAudioBuffer * io_pBuffer ) // Input/Output buffer (processing is done in place).
{
// Get LFE channel with GetLFE().
AkSampleType * pLFE = io_pBuffer->GetLFE();
if ( pLFE )
{
// Process data of pLFE...
}
または、
// Get LFE channel with GetChannel().
if ( io_pBuffer->HasLFE() )
{
AkSampleType * pLFE = io_pBuffer->GetChannel( io_pBuffer->NumChannels() - 1 );
// Process data of pLFE...
}
}

LFEにないチャンネルに特定の処理と適用したい場合には、AkCommonDefs.h のチャンネルインデックス定義を使用する必要があります。 たとえば、5.x 構成のセンターチャンネルのみを処理したい場合には、次のようにします:

// Process only the center channel of a 5.x configuration.
void CAkMyPlugin::Execute( AkAudioBuffer * io_pBuffer ) // Input/Output buffer (processing is done in place).
{
// Query for specific channel configuration.
if ( io_pBuffer->GetChannelMask() == AK_SPEAKER_SETUP_5 || io_pBuffer->GetChannelMask() == AK_SPEAKER_SETUP_5POINT1 )
{
// Access channel using the index defined for the appropriate configuration.
AkSampleType * pCenter = io_pBuffer->GetChannel( AK_IDX_SETUP_5_CENTER );
// Process data of pCenter...
}
}
Tip: チャンネルインデックス定義は、設定が N.0 または N.1のいずれのからも独立していることに注意してください。これは、LFE チャンネルは、Souce プラグインを除いて、常に最後にあるからです (チャンネル設定がLFEでない場合には、AK_IDX_SETUP_N_LFE は使用しません)。
Note: ソースプラグインのインタリーブされたデータの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に引き渡されています。

Note: 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 も実装する必要があります。
// A global callback for initializing and terminating MyPluginManager (AkGlobalCallbackFunc).
static void MyRegisterCallback(
AK::IAkGlobalPluginContext * in_pContext, ///< Engine context.
AkGlobalCallbackLocation in_eLocation, ///< Location where this callback is fired.
void * in_pCookie ///< User cookie passed to AK::SoundEngine::RegisterGlobalCallback().
)
{
if (in_eLocation == AkGlobalCallbackLocation_Register)
{
// Registration time: called when sound engine is initialized, or when dynamic plugin lib is loaded.
// Create our singleton. サウンドエンジンの利用全般に及ぶ必要のある割り当てを行うために、グローバルコンテキストが提供するアロケータを使用します。
MyPluginManager * pMyPluginManager = AK_PLUGIN_NEW(in_pContext->GetAllocator(), MyPluginManager);
if (pMyPluginManager)
{
// Succeeded. "Term" コールバックに登録して、マネージャを終了します。
AKRESULT eResult = in_pContext->RegisterGlobalCallback(MyRegisterCallback, AkGlobalCallbackLocation_Term, pMyPluginManager);
// Handle registration failure.
if (eResult != AK_Success)
{
// ...
}
}
}
else if (in_eLocation == AkGlobalCallbackLocation_Term)
{
// Termination time: called when sound engine is terminated.
// The cookie is our instance of MyPluginManager, as was registered above.
AKASSERT(in_pCookie);
// Destroy it.
AK_PLUGIN_DELETE(in_pContext->GetAllocator(), (MyPluginManager*)in_pCookie);
}
}
// Replace AK_IMPLEMENT_PLUGIN_FACTORY(MyPlugin, AkPluginTypeEffect, MY_COMPANY_ID, MY_PLUGIN_ID)
// Here, "MyPlugin" should be replaced by the name of your plugin.
AK::IAkPlugin* CreateMyPlugin(AK::IAkPluginMemAlloc * in_pAllocator);
AK::IAkPluginParam * CreateMyPluginParams(AK::IAkPluginMemAlloc * in_pAllocator);
AK::PluginRegistration MyPluginRegistration(AkPluginTypeEffect, MY_COMPANY_ID, MY_PLUGIN_ID, CreateMyPlugin, CreateMyPluginParams, MyRegisterCallback, NULL);

詳細については、以下のセクションを参照してください: