版本

menu_open
Wwise SDK 2022.1.17
示例:开发低通滤波器插件

本主题提供了详尽的社区插件开发示例。在本例中,我们会开发低通滤波器插件。

创建新的工程

首先,需要使用 wp.py 工具创建新的插件工程。有关 new 参数的更多详细信息,请参阅 创建音频插件 章节。

目标为 Windows 上的设计工具平台。为此,我们来调用 premake

现在创建好了用于构建声音引擎和设计工具 (WwisePlugin) 部分的解决方案。

接下来,便可构建自研插件并确认是否能在 Wwise 中加载。

实现滤波处理效果

现在,我们想添加一些处理效果来进一步增强插件的功能。在此,我们使用以下公式来实现简单的一阶低通滤波效果:

y[n] = x[n] + (y[n-1] - x[n]) * coeff

其中 coeff 浮点值介于 0 ~ 1 之间。

首先,我们在 SoundEnginePlugin/LowpassFX.h 中创建一组变量来保存滤波器的数据。

变量 m_coeff 为滤波器系数。该浮点值将用于所有声道。矢量 m_previousOutput 将保存所有声道的上一输出值,以供计算滤波器的后续数值。

要想实现滤波效果,只需初始化系数变量,依据声道数调节矢量的大小,然后使用上述公式处理每一样本。

SoundEnginePlugin/LowpassFX.cpp 中:

使用 RTPC 参数来控制滤波器的频率

目前的滤波器比较简单,因为无法与之进行交互。下面我们来将 RTPC 参数与滤波器的频率绑定,以便实时更改其数值。为了允许插件使用 RTPC 参数,我们需要实施以下四项更改。

首先,必须在 WwisePlugin/Lowpass.xml 中添加其定义。插件模板中已经有了名为 PlaceHolder 的参数框架。 我们来使用其定义 Frequency 参数。在 WwisePlugin/Lowpass.xml 中,将占位属性替换为以下内容:

其次,需要更新 SoundEnginePlugin 文件夹中的 LowpassFXParams.hLowpassFXParams.cpp 来反映属性更改。

LowpassFXParams.h 中,更新 LowpassRTPCParams 结构中的参数 ID 和参数名称。

同时更新 LowpassFXParams.cpp

再次,在 WwisePlugin 文件夹中,需要更新 Lowpass::GetBankParameters 函数,以将 Frequency 参数写入到 SoundBank 中:

最后,在处理循环中,还要使用以下公式来依据当前频率计算滤波器的系数:

coeff = exp(-2 * pi * f / sr)

我们需要检索当前采样率。

加入一些数学符号。

计算滤波器系数:

插入参数值

通常,每个缓冲区大小更新一次处理参数是不够的(缓冲区大小等于声道缓冲区中的采样数,一般介于 64 ~ 2048 之间)。尤其是在此参数会影响处理的频率或增益的情况下,数值更新太慢会导致输出声音中出现拉链噪声或噼啪噪声。

对此,只需在整个缓冲区当中以线性方式插入数值即可。下面我们来针对频率参数执行此操作。

在计算一帧新的音频样本之前(即在 LowpassFX.cpp 中的 Execute 函数最上面),我们要检查频率参数是否发生了更改。 为此,可直接查询 LowpassFXParams 类中的 AkFXParameterChangeHandler 对象。若频率发生了更改,则计算 ramp 的变量:

备注: AkAudioBuffer 对象的成员变量 uValidFrames 代表缓冲区中每个声道所含的有效采样数。

在获取该数据后,只需每帧将 coeffBegin 增大 coeffStep 即可。我们需要针对输入/输出缓冲区的每个声道执行此操作。

现在我们构建了一个能够实现简单的低通滤波效果并实时控制截止频率的基础功能插件。接下来,我们说说设计方面的一些问题。

封装处理逻辑

现在,所有的信号处理逻辑都写在了插件主类内。这种设计模式存在很多弊端:

  • 插件主类会显得很臃肿,等到添加新的处理功能来构建较为复杂的效果时,情况会更加糟糕。
  • 很难在需要时将该滤波器用于其他插件。对这种基础处理组件来说更是如此。
  • 不符合单一职责原则。

下面我们来重构代码以将滤波处理封装到其自身的类中。首先,依据以下定义在 SoundEnginePlugin 文件夹中创建 FirstOrderLowpass.h 文件:

接着,在 FirstOrderLowpass.cpp 文件中添加实现代码:

然后,直接在插件主类中创建一组 FirstOrderLowpass 对象(每个声道一个),然后通过调用 Setup 函数来使用它们。

AkSampleType * GetChannel(AkUInt32 in_uIndex)
Definition: AkCommonDefs.h:565
uint16_t AkUInt16
Unsigned 16-bit integer
Audiokinetic namespace
Interface used to write data during sound bank generation.
AkForceInline AkUInt32 NumChannels() const
Get the number of channels.
Definition: AkCommonDefs.h:481
AKRESULT
Standard function call result.
Definition: AkTypes.h:199
AKSOUNDENGINE_API AKRESULT Init(const AkCommSettings &in_settings)
bool WriteReal32(float in_value)
Writes a 32-bit, single-precision floating point value.
float AkReal32
32-bit floating point
AkUInt16 uValidFrames
Number of valid sample frames in the audio buffer
Definition: AkCommonDefs.h:646
#define READBANKDATA(_Type, _Ptr, _Size)
Read and return bank data of a given type, incrementing running pointer and decrementing block size f...
uint32_t AkUInt32
Unsigned 32-bit integer
AkInt16 AkPluginParamID
Source or effect plug-in parameter ID
Definition: AkTypes.h:134
AkForceInline AkUInt32 GetNumChannels() const
Definition: AkCommonDefs.h:74
Defines the parameters of an audio buffer format.
Definition: AkCommonDefs.h:62
AkUInt32 uSampleRate
Number of samples per second
Definition: AkCommonDefs.h:63
#define AK_RESTRICT
Refers to the __restrict compilation flag available on some platforms
Definition: AkTypes.h:45

此页面对您是否有帮助?

需要技术支持?

仍有疑问?或者问题?需要更多信息?欢迎联系我们,我们可以提供帮助!

查看我们的“技术支持”页面

介绍一下自己的项目。我们会竭力为您提供帮助。

来注册自己的项目,我们帮您快速入门,不带任何附加条件!

开始 Wwise 之旅