源插件用合成方的方式产生音频内容,并提供给输出缓冲区。这些合成方法包括物理建模、调制合成、采样合成等。可以按照本文档所述的方法实现 AK::IAkSourcePlugin 接口,来编写源插件。这里仅介绍 AK::IAkSourcePlugin 接口的特有函数。请参阅 如何创建 Wwise 声音引擎插件 了解与其他插件共用的接口组件的相关信息。请参阅随附的 Sine(正弦波)插件示例了解详情(示例 )。
此方法让源插件为数据处理做好准备,分配内存和设置初始条件。
此插件通过指针传递给内存分配器接口(AKIAkPluginMemAlloc)。您应该通过此接口来执行所有动态内存分配,并使用随附的内存分配宏(请参阅在音频插件中分配/取消分配内存 )。对于最常见的内存分配需求,即在初始化时分配内存和在终止时释放内存的情况下,插件将不需要保留指向分配器的指针。在终止时也会将此指针提供给插件。
AK::IAkSourcePluginContext 接口可以用于获取循环迭代次数等信息,或者有关源插件运行环境的其他信息。该接口还可以通过 AK::IAkPluginContextBase::GlobalContext() 访问全局上下文。
插件还接收指向其相关参数节点接口(AKIAkPluginParam)的指针。大多数插件希望保留对相关参数节点的引用,以便能够在运行时获取参数。请参阅参数节点与插件之间的通信。 了解更多详情。
所有这些接口将在插件的生命周期内有效,因此必要时在内部引用它们是安全的。
插件运行平台的原生音频格式作为 AK::IAkSourcePlugin::Init()
函数的参数传递。强烈建议插件以平台原生格式输出,以避免音频格式转换造成性能损失。如果源插件不适合以此格式输出,那么也可以输出 16 位带符号采样的交错声道信号。在多声道配置中,源插件还必须指定将输出交错还是非交错数据( AkAudioFormat::uInterleaveID)。默认的原生设置是
AK_NONINTERLEAVED。当输出非交错数据时,源插件应使用 AkAudioBuffer::GetChannel()
方法来访问每个声道的缓冲区。当输出交错数据时,应使用 AkAudioBuffer::GetInterleavedData()。在7
.1的情况下,源插件交错数据的声道顺序是 L-R-C-LFE-BL-BR-SL-SR。请参阅 访问使用 AkAudioBuffer 结构的数据 了解更多详情。
输入的声道掩码将默认使用单(仅中置扬声器)声道配置。您可以将此声道掩码更改为希望源插件输出的声道配置。以下代码示例中,声道掩码将改为立体声。在每次执行时收到的音频缓冲区将适配至初始化时插件指定的格式,并且在插件的整个生命周期内保持不变。因此对于稍后在初始化例程中进行处理所需的格式信息,也可以在缓冲区中安全存储。
AKRESULT CAkDCOffset::Init( AK::IAkPluginMemAlloc * in_pAllocator, // 内存分配接口。 AK::IAkSourcePluginContext * in_pSourcePluginContext, // 源插件上下文 AK::IAkPluginParam * in_pParams, // 效果器参数。 AkAudioFormat & io_rFormat // 支持的音频输出格式。 ) { // 保留指向相关参数节点的指针。 m_pParams = reinterpret_cast<CAkMyPluginParams*>( in_pParams ); // 进行辅助设置来处理循环,并可能更改合成持续时间 m_DurationHandler.Setup( m_pParams->fDuration, in_pSourceFXContext->GetNumLoops(), io_rFormat.uSampleRate ); // 在默认情况下,输出格式设置为单声道(输入)原生格式。更改为立体声输出。 io_rFormat.channelConfig.SetStandard(AK_SPEAKER_SETUP_STEREO); ... return AK_Success; }
|
Note: 每次效果器实例化时,都会调用 AK::IAkSourcePlugin::Init(),当声部开始播放或混音总线实例化时,就会实例化效果器。典型情况下,其他声音已经在播放,因此实例化需要在合理的时间段内进行。如果您需要初始化通用/全局数据结构,那么在注册插件库时就应该这样做。请参阅在插件中使用全局声音引擎回调 了解更多详情。 |
在初始化阶段之后,声音引擎调用此方法来确定声源的大致持续时间,以便在声音过渡期间处理交叉淡变。返回声源的预计持续时间,单位:毫秒。如果循环的迭代次数有限,则返回的持续时间将与总体持续时间相符,即播放声音的迭代次数将被考虑在内。当选择了无限循环或者声源的持续时间未知时,返回的持续时间应为零。注意,当选择了无限循环时,通过 AK::IAkSourcePluginContext::GetNumLoops() 获得的循环迭代次数总是为零。
// 获取声源的持续时间,单位:毫秒。 AkTimeMs CAkDCOffset::GetDuration( ) const { return m_DurationHandler.GetDuration() * 1000.f; }
|
Note: 如果使用了 RTPC 参数对插件的持续时间进行更改,交叉渐变的过渡时间可能不符合预期长度。 |
|
Note: 对于源插件,处理大多数耗时管理(包括循环)的最简单方法是使用 AkFXDurationHandler 服务,如正弦插件示例中所示(示例 )。 |
声音引擎在收到中断动作时将调用此方法。中断动作是一个流畅的停止操作。 插件可在此函数中实现一种流畅终止声音播放的方法。通常它仅停止循环,如果有释音将会播放释音。 如果此函数忽略或者处理了中断命令,须返回 AK_Success。 如果插件不能处理命令,则函数应返回 AK_Fail,这会让声源停止播放。
在当前循环迭代后停止播放 AKRESULT CAkDCOffset::StopLooping() { m_DurationHandler.SetLooping( 1 ); // 不再循环。 return AK_Success; }
|
Note: 此函数是可选的。如果不实现,声源将忽略中断命令并一直正常播放至结束。 |
调用此方法可以获取预估的振幅包络值(标准化值,位于 0 和 1 之间),该值将于源插件下次调用 Execute() 时生成。在 Wwise 的当前版本中,HDR 处理算法使用该方法来获取包络线的预估值,从而对比其更轻的声音进行相应衰减。此功能是可选的:在 HDR 总线下使用您的插件时,如果返回 1(默认值),则更轻声音的衰减值将保持恒定。
如果选择实现,请确保其返回标准化包络值,即您所知道的即将生成波形的峰值,或者对振幅包络和增益解耦,那么仅返回包络线的当前值即可。
此方法执行源插件音频信号处理算法,并填充指定的音频输出缓冲区(访问使用 AkAudioBuffer 结构的数据 )。进入函数时,输出缓冲区的 AkAudioBuffer::uValidFrames 字段将为零,即声道缓冲区中不含有效的音频采样帧。AkAudioBufferMaxFrames() 方法返回声源应填充的最大音频采样帧数。插件需确定要产生多少个输出采样帧,这可能取决于持续时间等参数值。在执行 DSP 后,源插件须通过设置音频缓冲区的 AkAudioBuffer::uValidFrames 字段,告诉音频管线已经生成了多少有效采样帧。
|
Note: 一般而言,算法应尽量完整填充缓冲区,以避免管线资源不足。 |
只要源插件将 AkAudioBuffer 结构的 eState 字段设置为 AK_DataReady,就会调用 Execute() 例程。返回 AK_NoMoreData 时,音频管线将终止且不再调用插件。 Wwise 的当前版本支持多达 6 声道输入的源插件(有关 5.1 设置,请参阅 声道顺序 )。
DC offset (DC偏置)插件的 Execute() 函数如下所示。请参阅 CAkSrcSine::Execute() 和各种乐音发生器 DSP 例程了解更多详情。
// 此示例中是一个简单应用,通过使用 RTPC 参数来输出稳定 DC 偏置信号。 void CAkDCOffset::Execute( AkAudioBuffer * io_pBuffer ) { // 在更改(如 RTPC 参数) 时设置新的持续时间; m_DurationHandler.SetDuration( m_pParams->fDuration ); // 确定执行期间需要多少采样帧,并根据当前状态设置 uValidFrames 和 eState m_DurationHandler.ProduceBuffer( io_pBuffer ); // 获取 RTPC DC 偏置参数 AkReal32 fDCOffset = m_pParams->GetDCOffset( ); // DC 偏置输出 DSP(支持任意数量的声道) for ( unsigned int i = 0; i < m_uNumChannels; ++i ) { AkSampleType * pBufOut = io_pBuffer->GetChannel(i); // AkSampleType 取决于平台(在软件平台上使用 AkReal32)。 AkUInt32 uFrameCount = io_pBuffer->uValidFrames; while ( uFrameCount-- ) { *pBufOut++ = AK_FLOAT_TO_SAMPLETYPE( fDCOffset ); // DC-offset 输出,会将标准浮点数转化为支持的格式。 } } }
当虚声部设置为“Play from elapsed time”时,将使用 AK::IAkSourcePlugin::TimeSkip() 替代 Execute(),来让源插件在必要时更新其内部状态(例如高级合成时间)。它可以用来模拟将要进行的处理,同时避免在执行插件时占用大量 CPU。根据要求的帧数,通过 io_uFrames 参数来调整调用 Execute() 将要产生的帧数,并根据此时是否存在音频输出来返回 AK_DataReady 或 AK_NoMoreData。
返回 AK_NotImplemented 将导致声部正常处理(就像不是虚声部一样),因此“Play from elapsed time”将不能起到节省 CPU 的作用。
// 此示例显示当虚声部设置为“Play from elapsed time”时应如何跳过某些帧的处理。 AKRESULT CAkDCOffset::TimeSkip( AkUInt32 &io_uFrames ) { AkUInt16 uValidFrames = (AkUInt16)io_uFrames; AkUInt16 uMaxFrames = (AkUInt16)io_uFrames; AKRESULT eResult = m_DurationHandler.ProduceBuffer( uMaxFrames, uValidFrames ); io_uFrames = uValidFrames; return eResult; } \
更多信息请参阅以下部分: Wwise 声音引擎插件概述 、效果器插件接口实现 、编写音频插件的 Wwise 设计工具部件