Wwise SDK 2022.1.18
|
This topic provides an example of Community plug-in development from start to finish. In this case, we will develop a lowpass filter plug-in.
First, we need to create a new plug-in project with wp.py tools. See Creating Audio Plug-ins for more details about new
arguments.
We will target the Authoring platform on Windows, so let's call premake:
Solutions have been created for building the SoundEngine and the Authoring (WwisePlugin) parts.
We can now build our plug-in and confirm that it loads in Wwise.
Now, we want to add some processing to make our plug-in a little bit more useful. We will implement a simple first order lowpass filter, using this equation:
y[n] = x[n] + (y[n-1] - x[n]) * coeff
where coeff
is a floating-point value between 0 and 1.
First, let's create a couple of variables in SoundEnginePlugin/LowpassFX.h
to hold our filter's data.
The variable m_coeff
is our filter coefficient as a floating-point value, it will be used for all sound channels. The vector m_previousOutput
will hold the last output value of all channels, mandatory to compute the next values of the filter.
To implement the filtering effect, all we have to do is to initialize the coefficient variable, adjust the size of the vector according to the number of channels and then process every sample with the previous formula.
In SoundEnginePlugin/LowpassFX.cpp
:
At this point, our filter is pretty boring because there is no way to interact with it. The next step is to bind an RTPC parameter to the filter's frequency so that we can change its value in real time. There are four changes to make to allow our plug-in to use an RTPC parameter.
First, we must add its definition in WwisePlugin/Lowpass.xml
. There is already a parameter skeleton, named "PlaceHolder", in the plug-in template. We will use it to define a "Frequency" parameter. In WwisePlugin/Lowpass.xml
, replace the placeholder property with this:
Second, we need to update LowpassFXParams.h
and LowpassFXParams.cpp
in the SoundEnginePlugin folder to reflect our property changes.
In LowpassFXParams.h
, update the parameter IDs and the name of the parameter in the LowpassRTPCParams
structure.
Update LowpassFXParams.cpp
as well:
Third, in the WwisePlugin
folder, we need to update the Lowpass::GetBankParameters
function to write the "Frequency" parameter in the bank:
Finally, in our processing loop, we want to use the current frequency to compute the filter's coefficient with this formula:
coeff = exp(-2 * pi * f / sr)
We need to retrieve the current sampling rate,
include some math symbols:
and compute the filter coefficient:
It is often not enough to update a processing parameter once per buffer size (the number of samples in an audio buffer channel, usually between 64 and 2048). Especially if this parameter affects the frequency or the gain of the processing; updating the value too slowly can produce zipper noise or clicks in the output sound.
A simple solution to this problem is to linearly interpolate the value over the whole buffer. Here is how we can do this for our frequency parameter.
Just before computing a new frame of audio samples, i.e., at the top of the Execute
function in LowpassFX.cpp
, we will check if the frequency parameter has changed. To do so, we just ask the AkFXParameterChangeHandler
object in the LowpassFXParams
class. If the frequency has changed, we compute the variables of the ramp:
Note: The member variable uValidFrames of the AkAudioBuffer object represents the number of valid samples per channel contained in the buffer. |
With this data, all we have to do is to increase coeffBegin
by coeffStep
for each sample of the frame. We need to do this for each channel of the in/out buffer.
Now that we have a basic functional plug-in implementing a simple lowpass filter with real-time control over the cutoff frequency, let's talk about design concerns.
At this point, all our signal processing logic is written inside the plug-in main class. This is not a good design pattern for many reasons:
Let's refactor our code to encapsulate the filter processing in its own class. Create a file FirstOrderLowpass.h
in the SoundEnginePlugin
folder with this defintion:
And add the implementation in a file called FirstOrderLowpass.cpp:
Then, all we have to do in our main plug-in class is to create a vector of FirstOrderLowpass
objects (one per audio channel), call their Setup
function and start using them.
Questions? Problems? Need more info? Contact us, and we can help!
Visit our Support pageRegister your project and we'll help you get started with no strings attached!
Get started with Wwise