バージョン

menu_open
Wwise SDK 2023.1.2
Sound Engine Effectプラグインの作成

Effect Plug-inインターフェースを実装する

エフェクトプラグインは、入力オーディオデータとして供給された既存サウンドにDSPアルゴリズムを適用します。エフェクトプラグインの記述は、AK::IAkInPlaceEffectPlugin または AK::IAkOutOfPlaceEffectPlugin インターフェースのいずれかを実装することより構成されています。ここでは、これらのインターフェースに固有の関数のみがカバーされています。他のプラグインタイプと共有されるインターフェースコンポーネント(AK::IAkPlugin インターフェース)に関する情報については、Sound Engineプラグインの作成 を参照してください。詳細は、提供のAkDelay プラグインを参照してください( サンプル )。

AK::IAkEffectPlugin::Init()

このメソッドは、データ処理のためにエフェクトプラグインを準備し、メモリを割り当て、初期条件を設定します。

The plug-in is passed in a pointer to a memory allocator interface (AK::IAkPluginMemAlloc). We recommend that you allocate all dynamic memory through this interface using the provided memory allocation macros (refer to Allocating/De-allocating オーディオプラグインにおけるメモリ) so that Wwise can track the memory, and so that any underlying memory hooks in the game engine can use it. For the most common memory allocation needs, specifically allocation at initialization and release at termination, the plug-in does not need to retain a pointer to the allocator. It is also provided to the plug-in on termination.

The AK::IAkEffectPluginContext interface can access the global context through AK::IAkPluginContextBase::GlobalContext().

The plug-in also receives a pointer to its associated parameter node interface (AK::IAkPluginParam). Most plug-ins keep a reference to the associated parameter node to be able to retrieve parameters at runtime. 詳細は、 Communication Between Parameter Nodes and Plug-ins. を参照してください。

All of these interfaces remain valid throughout the plug-in's lifespan so it is safe to keep an internal reference to them when necessary.

Effect plug-ins also receive the input/output audio format (which stays the same during the lifespan of the plug-in) to be able to allocate memory and set up processing for a given channel configuration.

注釈: AK::IAkEffectPlugin::Init() is called every time the effect is instantiated, which happens when a voice starts playing or a mixing bus is instantiated. Because other sounds are typically playing already, this must occur within a reasonable amount of time. If you need to initialize large common/global data structures, do so when registering the plug-in library. 詳細は、プラグインからグローバル サウンド エンジン コールバックを使用する を参照してください。

AK::IAkPluginEffect::Execute()

エフェクトプラグインは、次の2つのインターフェースのいずれかを実装することもできます:AK::IAkInPlaceEffectPlugin または AK::IAkOutOfPlaceEffectPlugin 。一般的には、(入力および出力データの両方に対して同じオーディオバッファを使用する)インプレース効果を、ほとんどのエフェクトに対して使用する必要があります。ただし、データフローの変化(たとえば、タイムストレッチ効果など)がある場合には、アウトオブプレースインターフェースを代わりに実装する必要があります。

注意: 異なる入力/出力チャンネル構成のアウトオブプレース効果を、マスターミキサー階層に挿入することができます。しかし、ミキシングバスにレートが変化するエフェクトをかけることはできません。異なる入力/出力バッファ長のエフェクトは、アクターミキサー階層にのみ挿入することができます (ソースエフェクトとして)。

IAkInPlaceEffectPlugin::Execute

このメソッドは、プラグインの信号処理アルゴリズムを指定されたオーディオバッファに対してインプレースで実行します(詳細は、AkAudioBuffer構造体を使用するデータにアクセスする を参照してください)。この構造体は、入力サンプルがいくつ有効かに関する情報(AkAudioBuffer::uValidFrames)およびバッファが収容可能な最大オーディオサンプルフレーム数に関する情報(AkAudioBuffer::MaxFrames() メソッド)をプラグインに提供します。AkAudioBuffer::eState 構造体メンバは、最後の実行であるか(AK_NoMoreData)否か(AK_DataReady)をプラグインに通知します。

AK::IAkInPlaceEffectPlugin::TimeSkip() は、バーチャルボイスが経過時間から再生された時にプラグインが必要に応じてその内部状態を更新し続けることができるように、Execute() に置換されます。

IAkOutOfPlaceEffectPlugin::Execute

このメソッドは、アウトオブプレース アルゴリズム用のプラグインの信号処理を実行します。AkAudioBuffer 構造体は、入力バッファ用に1つ、出力バッファ用に1つ、全部で2つ使用されます。パイプラインは、現在のエフェクトの状態を判断するために出力オーディオバッファで eState を使用します。エフェクトは、入力バッファを全て消費した場合(そして後により多くのデータで実行を続けて行くために AK_DataNeeded を返す場合)、または全出力バッファが充填された時に AK_DataReady を出力した場合にのみに返されます。エフェクトが内部状態のフラッシュを完了するまで(AK_NoMoreData が返される必要のある時点まで)、AK_DataReady により受信される AK_NoMoreData を変更することにより、エフェクトテールをアウトオブプレースエフェクトに実装することも可能です。

入力バッファは、完全に消費されるまでパイプラインにより解放されることはありません。従って、最後の Execute() コールが中断されたところでデータの読み取りを開始するために in_uInOffset オフセットパラメータを使用することが重要です。以下のサンプルはこれを実現する方法を示しています。

void CAkSimpleUpsampler::Execute(
AkAudioBuffer * io_pInBuffer,
AkUInt32 in_uInOffset,
AkAudioBuffer * io_pOutBuffer )
{
assert( io_pInBuffer->NumChannels() == io_pOutBuffer->NumChannels() );
const AkUInt32 uNumChannels = io_pInBuffer->NumChannels();
AkUInt32 uFramesConsumed; // Track how much data is consumed from input buffer
AkUInt32 uFramesProduced; // Track how much data is produced to output buffer
for ( AkUInt32 i = 0; i < uNumChannels; i++ )
{
AkReal32 * AK_RESTRICT pInBuf = (AkReal32 * AK_RESTRICT) io_pInBuffer->GetChannel( i ) + in_uInOffset;
AkReal32 * AK_RESTRICT pfOutBuf = (AkReal32 * AK_RESTRICT) io_pOutBuffer->GetChannel( i ) + io_pOutBuffer->uValidFrames;
uFramesConsumed = 0; // Reset for every channel
uFramesProduced = 0;
while ( (uFramesConsumed < io_pInBuffer->uValidFrames) && (uFramesProduced < io_pOutBuffer->MaxFrames()) )
{
// Do some processing that consumes input and produces output at different rate (e.g. time-stretch or resampling)
*pfOutBuf++ = *pInBuf;
*pfOutBuf++ = *pInBuf++;
uFramesConsumed++;
uFramesProduced += 2;
}
}
// Update AkAudioBuffer structure to continue processing
io_pInBuffer->uValidFrames -= uFramesConsumed;
io_pOutBuffer->uValidFrames += uFramesProduced;
if ( io_pInBuffer->eState == AK_NoMoreData && io_pInBuffer->uValidFrames == 0 )
io_pOutBuffer->eState = AK_NoMoreData; // Input entirely consumed and nothing more to output, the effect is done
else if ( io_pOutBuffer->uValidFrames == io_pOutBuffer->MaxFrames() )
io_pOutBuffer->eState = AK_DataReady; // A complete audio buffer is ready
else
io_pOutBuffer->eState = AK_DataNeeded; // We need more data to continue processing
}

AK::IAkOutOfPlaceEffectPlugin::TimeSkip() は、バーチャルボイスが経過時間から再生された時にプラグインが必要に応じてその内部状態を更新し続けることができるように、Execute() に置換されます。従って、この関数は、指定数の出力フレームを生成するのに通常どのぐらいの入力サンプルが消費されるかをパイプラインに知らせる役割を担います。

Implementing エフェクトプラグイン テール

エフェクトの一部(特にディレイラインを持つエフェクト)は、入力が正常に減衰の再生を終了した後に出力される必要のある内部状態を持っています。エフェクトAPI は、有効な入力データがなくても実行を継続することを可能にします。AkAudioBuffer 構造体の eState フラグが AK_NoMoreData になると、パイプラインは、現在の実行後に有効な入力サンプルフレームをプラグインに供給しなくなります。その後、プラグインは、入力信号が終了した後にディレイラインを空にできるよう、新しい(後続の)フレームをバッファ内に(MaxFrames() が返す値まで)自由に書き込むことができるようになります。オーディオパイプラインには、適切に uValidFrames フィールドを更新することによって出力されたフレーム数を常に知らせる必要があります。エフェクトテールのフラッシュを完了するためにプラグイン Execute() 関数が再び呼び出される必要がある場合には、eState メンバが AK_DataReady に設定されなければなりません。エフェクトが、eState フィールドに AK_NoMoreData を設定した場合には、パイプラインはプラグイン Execute() の呼び出しのみを停止します。

テールを処理する最も簡単な方法は、SDK で提供の AkFXTailHandler サービスクラスを使用することです。プラグイン用のクラスメンバとして保持されている AkFXTailHandler のインスタンスで、インプレースエフェクト内でする必要のあることは、AkFXTailHandler::HandleTail() を呼び出して、これに AkAudioBuffer といったん出力が終了した時に出力するオーディオサンプル総数(パラメータに基づいて実行ごとに変更される場合あり)を渡すことのみです。詳細は、AkDelay プラグインソースコードを参照してください( サンプル )。

注釈: Effectプラグインの実行に関する重要な注意事項

  • Wwiseでプラグインが使用される場合、パラメータが RTPC をサポートするかどうかに関わらず、パラメータの変更はパラメータノードまで送信されます。これにより、Wwise 使用の必要に応じて、プラグインは非 RTPC 値の実行時の値の変更をサポートすることができます。プラグインがこれをサポートしないようにするには、初期化時にパラメータ値のコピーを作成し、プラグインの存続期間を通じてこれらの値が変化しないようにする必要があります。
  • プラグインはいくつかのチャンネル構成を処理する必要があり(バス上に挿入出来る場合は、少なくともモノラル、ステレオ、5.1)、そうでない場合は初期化時に AK_UnsupportedChannelConfig を返さなければなりません。

バイパス

プラグインは、UI、イベント、RTPC など様々なメカニズムを通じて Wwise やゲーム内でバイパスすることができます。このような場合、プラグイン Execute() ルーチンは呼び出されません。プラグインが unbypass 上で再開し実行関数が再び呼び出されると、プラグインはその処理を再始動します。エフェクトが最終的にバイパスされない場合、新たなスタートのためにディレイラインや他の状態情報をクリアすることができるように、プラグインの Reset() 関数がバイパス上に呼び出されます。詳細は、AK::IAkPlugin::Reset() を参照してください。

注意: 実行時のバイパスやバイパス解除は、プラグインや処理されているサウンドマテリアルによっては、信号の不連続を引き起こす場合があります。

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

Sound Engineにおけるモニタリング

モニタリングとは、オーディオプラグインの状態を再生中に観察するプロセスのことです。

Authoringアプリケーションをコミュニケーションモジュール経由で接続すると、Sound Engineプラグインインスタンスが、自分のステートを任意のデータバッファとして提供し、プラグインのAuthoring側に渡すことができます。 このデータは、例えば実行プロセスから計算したパフォーマンス測定であったり、様々な処理ステージにおけるメータリング用の信号レベルであったりします。

このセクションは、Sound Engine側のモニタリングに関するものです。 受信側やデシリアライズ処理の詳細は Authoringにおけるモニタリング を参照してください。

モニタリングデータの送信

送信を行うのは、プラグインのSound Engine部分です。その流れの各段階を、以下に示します:

  • シリアライズ: モニタリングデータは、任意のサイズのバッファとして提供されるため、プラグインのSound Engine部分が送信予定のデータをシリアライズして、それを、対するAuthoring側で受信してからデシリアライズする必要があります。シリアライズはプラグイン作成側が実装を担うため、Wwiseにはデータが不透明のままです。 プラットフォームに関わらず標準サイズのあるタイプを必ず使うようにして、例えば long というサイズは、 64-bitプラットフォームの一部では4バイト(LLP64)を採用し、ほかでは8バイト(LP64)を採用するので、注意してください。また、アライメント要件の異なるプラットフォームでは、パッケージングストラテジによって struct レイアウトが異なることがあるので、注意してください。カスタムのパッキングアライメントを指定するには、 pack pragmaを使います。
  • 送信: モニタリングデータをバッファにシリアライズできた時点で、Sound Engineプラグインは、プラグインのコンテキストインスタンスで提供される関数 AK::IAkPluginContextBase::PostMonitorData() を使い、プロファイラのコミュニケーションチャンネルでデータを送信します。この関数は、 Execute 関数内でコールしてください。
注釈: モニタリングデータは非同期で送信するので、 AK::IAkPluginContextBase::PostMonitorData() が、Sound Engineプラグインの提供するバッファをコピーします。つまり、バッファを安心してスタックにアロケーションできるほか、 PostMonitorData がコールされたあとは解放できます。

モニタリングデータを常に送信できるわけではなく、モニタリングデータを使えるのは、Wwise Authoringアプリケーションがプロファイリング中のときだけです。Authoringがプロファイリング中でないときや、単純にゲームをプロファイリングすることが不可能なときなどに、データの準備や送信を行うのは無駄です。このような不要なコストを避けるには、2つの方法があります:

  • ランタイムのチェック: プラグインのコンテキストが提供する関数 AK::IAkPluginContextBase::CanPostMonitorData() は、プロファイリングがアクティブでないときや、モニタリングデータをポストすることに対応していない場合に、falseを返します。この関数を使い、モニタリングに対応するかどうかを、 AK::IAkPluginContextBase::PostMonitorData() をコールする前に必ずチェックしてください。
  • コンパイル時のチェック: リリースビルドでは、一般的にコミュニケーションモジュールを初期化しないので、プロファイリングは不可能です。コンパイル処理から、モニタリングデータの準備と送信に関する部分のコードを削除するには、 AK_OPTIMIZED に対してプリプロセッサチェックを行います。AK_OPTIMIZED は、Wwise Plug-in開発ツールの wp.py を使うと、デフォルトでリリースビルドに定義されます。

モニタリングデータのシリアライズと送信の方法が、以下のコード例から分かります:

void MyPlugin::Execute( AkAudioBuffer * io_pBuffer )
{
const AkUInt32 uNumChannels = io_pBuffer->NumChannels();
// Algorithm tracks signal peaks for all uNumChannels channels inside the following array
float fChannelPeaks[MAX_NUM_CHANNELS];
...
#ifndef AK_OPTIMIZED // Compile-time check
if ( m_pContext->CanPostMonitorData() ) // Runtime check, m_pContext is cached from MyPlugin::Init()
{
// == Serialization
// Compute the buffer size and allocate a buffer
unsigned int uMonitorDataSize = sizeof(AkUInt32) * uNumChannels*sizeof(float);
char * pMonitorData = (char *) AkAlloca( uMonitorDataSize );
// Fill the monitoring data buffer
*((AkUInt32 *) pMonitorData ) = uNumChannels;
memcpy( pMonitorData + sizeof(AkUInt32), fChannelPeaks, uNumChannels*sizeof(float) );
// == Sending
m_pContext->PostMonitorData( pMonitorData, uMonitorDataSize );
// If the buffer was allocated using \c AK::IAkPluginMemAlloc, free it here
// When using AkAlloca, nothing to do: the memory is freed automatically when the function returns
}
#endif
...
}

オブジェクトプロセッサは、各オブジェクトがそれぞれ所有する個々のオーディオ信号のアレイを、 Execute 関数内で意図的に扱うオーディオプラグインから派生しています。 Execute は、 AkAudioBuffer インスタンスを1つずつ受け取らずに、 1つのオブジェクトに対して1つの AkAudioBuffer インスタンスがある一覧表を、 Ak3DAudioObjects wrapperオブジェクトとして受信します。

1つのオブジェクトプロセッサプラグインが、複数のオーディオバッファのアレイを処理するので、このプラグインが送信するモニタリングデータには、処理される全てのオブジェクトに関連するモニタリングデータの、アグリゲーションを入れる必要があります。一番簡単なのは、オブジェクトの数を送信し、各シグナルに関係するモニタリングデータを、アレイとしてシリアライズする方法です。

オブジェクトプロセッサの詳細は、 Sound Engine Object Processorプラグインの作成 を参照してください。

AkSampleType * GetChannel(AkUInt32 in_uIndex)
Definition: AkCommonDefs.h:575
@ AK_DataReady
The provider has available data.
Definition: AkTypes.h:241
AkForceInline AkUInt32 NumChannels() const
Get the number of channels.
Definition: AkCommonDefs.h:491
@ AK_NoMoreData
No more data is available from the source.
Definition: AkTypes.h:226
float AkReal32
32-bit floating point
AKRESULT eState
Execution status
Definition: AkCommonDefs.h:650
AkUInt16 uValidFrames
Number of valid sample frames in the audio buffer
Definition: AkCommonDefs.h:656
#define AkAlloca(_size_)
Stack allocations.
@ AK_DataNeeded
The consumer needs more.
Definition: AkTypes.h:239
uint32_t AkUInt32
Unsigned 32-bit integer
#define AK_RESTRICT
Refers to the __restrict compilation flag available on some platforms
Definition: AkTypes.h:45
AkForceInline AkUInt16 MaxFrames() const
Definition: AkCommonDefs.h:643

このページはお役に立ちましたか?

サポートは必要ですか?

ご質問や問題、ご不明点はございますか?お気軽にお問い合わせください。

サポートページをご確認ください

あなたのプロジェクトについて教えてください。ご不明な点はありませんか。

プロジェクトを登録していただくことで、ご利用開始のサポートをいたします。

Wwiseからはじめよう